getNode functions now use a local Key object in Transactor
This commit is contained in:
parent
c805f1fd6b
commit
335931bddb
4 changed files with 60 additions and 35 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue