From 405555278dbe6e44653c6b35c04209572376afa7 Mon Sep 17 00:00:00 2001
From: hns <hannesw@gmail.com>
Date: Fri, 9 Mar 2001 16:05:31 +0000
Subject: [PATCH] Implemented caching of null nodes in getNode (Node, String,
 Relation). A singleton nullNode is used to cache Node objects in the
 application cache if they don't exist.

---
 src/helma/objectmodel/db/NodeManager.java | 28 +++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/src/helma/objectmodel/db/NodeManager.java b/src/helma/objectmodel/db/NodeManager.java
index eb11405f..5d32ae2b 100644
--- a/src/helma/objectmodel/db/NodeManager.java
+++ b/src/helma/objectmodel/db/NodeManager.java
@@ -38,6 +38,9 @@ public final class NodeManager {
     // a wrapper that catches some Exceptions while accessing this NM
     public final WrappedNodeManager safe;
 
+    // an instance of Node that's used to cache null values
+    private Node nullNode;
+
     public NodeManager (Application app, String dbHome, Properties props) throws DbException {
 	this.app = app;
 	int cacheSize = Integer.parseInt (props.getProperty ("cachesize", "1000"));
@@ -47,6 +50,7 @@ public final class NodeManager {
 	app.logEvent ("set up node cache ("+cacheSize+")");
 
 	safe = new WrappedNodeManager (this);
+	nullNode = new Node ("nullNode", "nullNode", null, safe);
 
 	// get the initial id generator value
 	String idb = props.getProperty ("idBaseValue");
@@ -222,15 +226,35 @@ public final class NodeManager {
 	            // check if node is already in cache with primary key
 	            Node oldnode = (Node) cache.put (primKey, node);
 	            // no need to check for oldnode != node because we fetched a new node from db
-	            if (oldnode != null && oldnode.getState () != Node.INVALID) {
+	            if (oldnode != null && oldnode != nullNode && oldnode.getState () != Node.INVALID) {
 	                cache.put (primKey, oldnode);
 	                if (!keyIsPrimary)
 	                    cache.put (key, oldnode);
 	                node = oldnode;
-	            } else if (!keyIsPrimary) // cache node with secondary key
+	            } else if (!keyIsPrimary) {
+	                // cache node with secondary key
 	                cache.put (key, node);
+	            }
 	        } // synchronized
+	    } else {
+	        // node fetched from db is null, cache result using nullNode
+	        synchronized (cache) {
+	            Node oldnode = (Node) cache.put (key, nullNode);
+	            // for the rare case that some other thread created the node in the meantime
+	            if (oldnode != null && oldnode != nullNode && oldnode.getState () != Node.INVALID) {
+	                Key primKey = oldnode.getKey ();
+	                boolean keyIsPrimary = primKey.equals (key);
+	                cache.put (oldnode.getKey (), oldnode);
+	                if (!keyIsPrimary)
+	                    cache.put (key, oldnode);
+	                node = oldnode;
+	            } else {
+	                return null;
+	            }
+	        }
 	    }
+	} else if (node == nullNode) {
+	    return null;
 	} else {
 	    // update primary key in cache to keep it from being flushed, see above
 	    if (!rel.usesPrimaryKey ()) {