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) { public Key (DbMapping dbmap, String id) {
this.type = dbmap == null ? "" : dbmap.typename; this.type = dbmap == null ? "" : dbmap.typename;
this.id = id; this.id = id;
hash = this.id.hashCode (); hash = id.hashCode ();
} }
public Key (String type, String id) { public Key (String type, String id) {
@ -33,36 +33,46 @@ public final class Key implements Serializable {
} }
public boolean equals (Object what) { public boolean equals (Object what) {
if (what == this) try {
return true; Key k = (Key) what;
if (what == null || !(what instanceof Key)) return (id == k.id || id.equals (k.id)) && (type == k.type || type.equals (k.type));
} catch (Exception x) {
return false; 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 () { public int hashCode () {
return hash; 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 * 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 * 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. * a key that can't be mistaken for a relational db key.
*/ */
public Key getVirtualKey (String sid) { 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) { public String getVirtualID (String sid) {
String ptype = pmap == null ? "" : pmap.typename; return makeVirtualID (type, id, sid);
return ptype+"/"+pid + "*h~v*" + 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; return ptype+"/"+pid + "*h~v*" + sid;
} }

View file

@ -123,7 +123,7 @@ public class Node implements INode, Serializable {
setParent (home); setParent (home);
// this.dbmap = null; // this.dbmap = null;
// generate a key for the virtual node that can't be mistaken for a JDBC-URL // 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.name = propname;
this.anonymous = false; this.anonymous = false;
if (prototype == null) if (prototype == null)

View file

@ -42,7 +42,8 @@ public final class NodeManager {
public NodeManager (Application app, String dbHome, Properties props) throws DbException { public NodeManager (Application app, String dbHome, Properties props) throws DbException {
this.app = app; this.app = app;
int cacheSize = Integer.parseInt (props.getProperty ("cachesize", "1000")); 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+")"); IServer.getLogger().log ("set up node cache ("+cacheSize+")");
safe = new WrappedNodeManager (this); safe = new WrappedNodeManager (this);
@ -139,11 +140,11 @@ public final class NodeManager {
if (kstr == null) if (kstr == null)
return null; return null;
Key key = new Key (dbmap, kstr);
Transactor tx = (Transactor) Thread.currentThread (); Transactor tx = (Transactor) Thread.currentThread ();
// tx.timer.beginEvent ("getNode "+kstr); // tx.timer.beginEvent ("getNode "+kstr);
Key key = tx.key;
key.recycle (dbmap, kstr);
// See if Transactor has already come across this node // See if Transactor has already come across this node
Node node = tx.getVisitedNode (key); Node node = tx.getVisitedNode (key);
@ -169,10 +170,12 @@ public final class NodeManager {
} }
} // synchronized } // synchronized
} }
} else {
// cache hit
} }
if (node != null) if (node != null)
tx.visitCleanNode (node.getKey (), node); tx.visitCleanNode (key.duplicate(), node);
// tx.timer.endEvent ("getNode "+kstr); // tx.timer.endEvent ("getNode "+kstr);
return node; return node;
@ -183,21 +186,23 @@ public final class NodeManager {
if (kstr == null) if (kstr == null)
return 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 (); Transactor tx = (Transactor) Thread.currentThread ();
// tx.timer.beginEvent ("getNode "+kstr); // 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 // See if Transactor has already come across this node
Node node = tx.getVisitedNode (key); Node node = tx.getVisitedNode (key);
if (node != null && node.getState() != Node.INVALID) { if (node != null && node.getState() != Node.INVALID) {
// System.err.println ("CACHE HIT THREAD 2");
// tx.timer.endEvent ("getNode "+kstr); // tx.timer.endEvent ("getNode "+kstr);
// if we didn't fetch the node via its primary key, refresh the primary key in the cache. // 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 // 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); Node oldnode = (Node) cache.put (node.getKey (), node);
if (oldnode != null && oldnode.getState () != Node.INVALID) { if (oldnode != null && oldnode.getState () != Node.INVALID) {
cache.put (node.getKey (), oldnode); cache.put (node.getKey (), oldnode);
cache.put (key, oldnode); cache.put (key.duplicate(), oldnode);
node = oldnode; node = oldnode;
} }
} }
@ -218,38 +223,44 @@ public final class NodeManager {
node = (Node) cache.get (key); node = (Node) cache.get (key);
if (node == null || node.getState() == Node.INVALID) { 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 // The requested node isn't in the shared cache. Synchronize with key to make sure only one
// version is fetched from the database. // version is fetched from the database.
node = getNodeByRelation (db, tx.txn, home, kstr, rel); node = getNodeByRelation (db, tx.txn, home, kstr, rel);
if (node != null) { if (node != null) {
Key primKey = node.getKey (); Key primKey = node.getKey ();
boolean keyIsPrimary = primKey.equals (key);
synchronized (cache) { synchronized (cache) {
// check if node is already in cache with primary key
Node oldnode = (Node) cache.put (primKey, node); Node oldnode = (Node) cache.put (primKey, node);
if (oldnode != null && oldnode.getState () != Node.INVALID) { if (oldnode != null && oldnode.getState () != Node.INVALID) {
cache.put (primKey, oldnode); cache.put (primKey, oldnode);
cache.put (key, oldnode); if (!keyIsPrimary)
cache.put (key.duplicate(), oldnode);
node = oldnode; node = oldnode;
} } else if (!keyIsPrimary) // cache node with secondary key
cache.put (key.duplicate(), node);
} // synchronized } // synchronized
} }
} } else {
// System.err.println ("CACHE HIT 2");
if (node != null) {
// update primary key in cache, see above // update primary key in cache, see above
if (!rel.usesPrimaryKey ()) { if (!rel.usesPrimaryKey ()) {
synchronized (cache) { synchronized (cache) {
Node oldnode = (Node) cache.put (node.getKey (), node); Node oldnode = (Node) cache.put (node.getKey (), node);
if (oldnode != null && oldnode.getState () != Node.INVALID) { if (oldnode != null && oldnode.getState () != Node.INVALID) {
cache.put (node.getKey (), oldnode); cache.put (node.getKey (), oldnode);
cache.put (key, oldnode); cache.put (key.duplicate(), oldnode);
node = oldnode; node = oldnode;
} }
} }
} }
tx.visitCleanNode (node.getKey (), node);
} }
if (node != null)
tx.visitCleanNode (key.duplicate(), node);
// tx.timer.endEvent ("getNode "+kstr); // tx.timer.endEvent ("getNode "+kstr);
return node; return node;
} }

View file

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