getNode functions now use a local Key object in Transactor

This commit is contained in:
hns 2001-01-18 18:10:49 +00:00
parent c805f1fd6b
commit 335931bddb
4 changed files with 60 additions and 35 deletions

View file

@ -23,7 +23,7 @@ public final class Key implements Serializable {
public Key (DbMapping dbmap, String id) {
this.type = dbmap == null ? "" : dbmap.typename;
this.id = id;
hash = this.id.hashCode ();
hash = id.hashCode ();
}
public Key (String type, String id) {
@ -33,36 +33,46 @@ public final class Key implements Serializable {
}
public boolean equals (Object what) {
if (what == this)
return true;
if (what == null || !(what instanceof Key))
try {
Key k = (Key) what;
return (id == k.id || id.equals (k.id)) && (type == k.type || type.equals (k.type));
} catch (Exception x) {
return false;
Key other = (Key) what;
if (type == null)
return (id.equals (other.id) && other.type == null);
else
return (id.equals (other.id) && type.equals (other.type));
}
}
public int hashCode () {
return hash;
}
public void recycle (DbMapping dbmap, String id) {
this.type = dbmap == null ? "" : dbmap.typename;
this.id = id;
hash = id.hashCode ();
}
public Key duplicate () {
return new Key (type, id);
}
/**
* Get the Key for a virtual node contained by this node, that is, a node that does
* not represent a record in the database. The main objective here is to generate
* a key that can't be mistaken for a relational db key.
*/
public Key getVirtualKey (String sid) {
return new Key ("", getVirtualID (type, id, sid));
return new Key ("", makeVirtualID (type, id, sid));
}
public static String getVirtualID (DbMapping pmap, String pid, String sid) {
String ptype = pmap == null ? "" : pmap.typename;
return ptype+"/"+pid + "*h~v*" + sid;
public String getVirtualID (String sid) {
return makeVirtualID (type, id, sid);
}
public static String getVirtualID (String ptype, String pid, String sid) {
public static String makeVirtualID (DbMapping pmap, String pid, String sid) {
return makeVirtualID (pmap == null ? "" : pmap.typename, pid, sid);
}
public static String makeVirtualID (String ptype, String pid, String sid) {
return ptype+"/"+pid + "*h~v*" + sid;
}

View file

@ -123,7 +123,7 @@ public class Node implements INode, Serializable {
setParent (home);
// this.dbmap = null;
// generate a key for the virtual node that can't be mistaken for a JDBC-URL
this.id = Key.getVirtualID (parentmap, parentID, propname);
this.id = Key.makeVirtualID (parentmap, parentID, propname);
this.name = propname;
this.anonymous = false;
if (prototype == null)

View file

@ -42,7 +42,8 @@ public final class NodeManager {
public NodeManager (Application app, String dbHome, Properties props) throws DbException {
this.app = app;
int cacheSize = Integer.parseInt (props.getProperty ("cachesize", "1000"));
cache = new CacheMap (cacheSize, 0.8f);
// Make actual cache size bigger, since we use it only up to the threshold
cache = new CacheMap ((int) Math.ceil (cacheSize/0.75f), 0.75f);
IServer.getLogger().log ("set up node cache ("+cacheSize+")");
safe = new WrappedNodeManager (this);
@ -139,11 +140,11 @@ public final class NodeManager {
if (kstr == null)
return null;
Key key = new Key (dbmap, kstr);
Transactor tx = (Transactor) Thread.currentThread ();
// tx.timer.beginEvent ("getNode "+kstr);
Key key = tx.key;
key.recycle (dbmap, kstr);
// See if Transactor has already come across this node
Node node = tx.getVisitedNode (key);
@ -169,10 +170,12 @@ public final class NodeManager {
}
} // synchronized
}
} else {
// cache hit
}
if (node != null)
tx.visitCleanNode (node.getKey (), node);
tx.visitCleanNode (key.duplicate(), node);
// tx.timer.endEvent ("getNode "+kstr);
return node;
@ -183,21 +186,23 @@ public final class NodeManager {
if (kstr == null)
return null;
Key key;
// If what we want is a virtual node create a "synthetic" key
if (rel.virtual /*&& home.getState() != INode.VIRTUAL */ || rel.groupby != null)
key = home.getKey ().getVirtualKey (kstr);
// if a key for a node from within the DB
else
key = new Key (rel.other, rel.getKeyID (home, kstr));
Transactor tx = (Transactor) Thread.currentThread ();
// tx.timer.beginEvent ("getNode "+kstr);
Key key = tx.key;
// If what we want is a virtual node create a "synthetic" key
if (rel.virtual /*&& home.getState() != INode.VIRTUAL */ || rel.groupby != null)
key.recycle (null, home.getKey ().getVirtualID (kstr));
// if a key for a node from within the DB
else
key.recycle (rel.other, rel.getKeyID (home, kstr));
// See if Transactor has already come across this node
Node node = tx.getVisitedNode (key);
if (node != null && node.getState() != Node.INVALID) {
// System.err.println ("CACHE HIT THREAD 2");
// tx.timer.endEvent ("getNode "+kstr);
// if we didn't fetch the node via its primary key, refresh the primary key in the cache.
// otherwise we risk cache corroption (duplicate node creation) if the node is fetched by its primary key
@ -206,7 +211,7 @@ public final class NodeManager {
Node oldnode = (Node) cache.put (node.getKey (), node);
if (oldnode != null && oldnode.getState () != Node.INVALID) {
cache.put (node.getKey (), oldnode);
cache.put (key, oldnode);
cache.put (key.duplicate(), oldnode);
node = oldnode;
}
}
@ -218,38 +223,44 @@ public final class NodeManager {
node = (Node) cache.get (key);
if (node == null || node.getState() == Node.INVALID) {
// System.err.println ("CACHE MISS 2");
// The requested node isn't in the shared cache. Synchronize with key to make sure only one
// version is fetched from the database.
node = getNodeByRelation (db, tx.txn, home, kstr, rel);
if (node != null) {
Key primKey = node.getKey ();
boolean keyIsPrimary = primKey.equals (key);
synchronized (cache) {
// check if node is already in cache with primary key
Node oldnode = (Node) cache.put (primKey, node);
if (oldnode != null && oldnode.getState () != Node.INVALID) {
cache.put (primKey, oldnode);
cache.put (key, oldnode);
if (!keyIsPrimary)
cache.put (key.duplicate(), oldnode);
node = oldnode;
}
} else if (!keyIsPrimary) // cache node with secondary key
cache.put (key.duplicate(), node);
} // synchronized
}
}
if (node != null) {
} else {
// System.err.println ("CACHE HIT 2");
// update primary key in cache, see above
if (!rel.usesPrimaryKey ()) {
synchronized (cache) {
Node oldnode = (Node) cache.put (node.getKey (), node);
if (oldnode != null && oldnode.getState () != Node.INVALID) {
cache.put (node.getKey (), oldnode);
cache.put (key, oldnode);
cache.put (key.duplicate(), oldnode);
node = oldnode;
}
}
}
tx.visitCleanNode (node.getKey (), node);
}
if (node != null)
tx.visitCleanNode (key.duplicate(), node);
// tx.timer.endEvent ("getNode "+kstr);
return node;
}

View file

@ -28,6 +28,9 @@ public class Transactor extends Thread {
private volatile boolean active;
private volatile boolean killed;
// the transactor reuses a key object to avoid unnecessary object creation
protected Key key;
// Transaction for the embedded database
protected DbTxn txn;
// Transactions for SQL data sources
@ -49,6 +52,7 @@ public class Transactor extends Thread {
active = false;
killed = false;
timer = new Timer();
key = new Key ("", "");
}
public void visitNode (Node node) {