Return-Path: Delivered-To: apmail-jackrabbit-commits-archive@www.apache.org Received: (qmail 68050 invoked from network); 24 Apr 2008 12:48:43 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 24 Apr 2008 12:48:43 -0000 Received: (qmail 27490 invoked by uid 500); 24 Apr 2008 12:48:45 -0000 Delivered-To: apmail-jackrabbit-commits-archive@jackrabbit.apache.org Received: (qmail 27456 invoked by uid 500); 24 Apr 2008 12:48:45 -0000 Mailing-List: contact commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@jackrabbit.apache.org Delivered-To: mailing list commits@jackrabbit.apache.org Received: (qmail 27445 invoked by uid 99); 24 Apr 2008 12:48:45 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 24 Apr 2008 05:48:45 -0700 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 24 Apr 2008 12:47:59 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id DAC2C1A9832; Thu, 24 Apr 2008 05:48:18 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r651246 - /jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java Date: Thu, 24 Apr 2008 12:48:17 -0000 To: commits@jackrabbit.apache.org From: dpfister@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20080424124818.DAC2C1A9832@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: dpfister Date: Thu Apr 24 05:48:12 2008 New Revision: 651246 URL: http://svn.apache.org/viewvc?rev=651246&view=rev Log: JCR-1104 - JSR 283 support - shareble nodes (work in progress) - add consistency check to CachingHierarchyManager Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java?rev=651246&r1=651245&r2=651246&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java Thu Apr 24 05:48:12 2008 @@ -88,6 +88,11 @@ private LRUEntry tail; /** + * Flag indicating whether consistency checking is enabled. + */ + private boolean consistencyCheckEnabled; + + /** * Create a new instance of this class. * * @param rootNodeId root node id @@ -101,6 +106,16 @@ upperLimit = DEFAULT_UPPER_LIMIT; } + /** + * Enable or disable consistency checks in this instance. + * + * @param enable true to enable consistency checks; + * false to disable + */ + public void enableConsistencyChecks(boolean enable) { + this.consistencyCheckEnabled = enable; + } + //-------------------------------------------------< base class overrides > /** @@ -305,7 +320,7 @@ if (cne == null) { // Item does not exist, remove evict(child, true); - return; + continue; } LRUEntry childEntry = (LRUEntry) child.get(); @@ -315,6 +330,7 @@ } } } + checkConsistency(); } } @@ -350,6 +366,7 @@ try { Path path = PathFactoryImpl.getInstance().create(getPath(state.getNodeId()), name, index, true); nodeAdded(state, path, id); + checkConsistency(); } catch (PathNotFoundException e) { log.warn("Unable to get path of node " + state.getNodeId() + ", event ignored."); @@ -424,6 +441,7 @@ parents[i].setChildren(newChildrenOrder); } } + checkConsistency(); } } @@ -437,6 +455,7 @@ try { Path path = PathFactoryImpl.getInstance().create(getPath(state.getNodeId()), name, index, true); nodeRemoved(state, path, id); + checkConsistency(); } catch (PathNotFoundException e) { log.warn("Unable to get path of node " + state.getNodeId() + ", event ignored."); @@ -539,6 +558,8 @@ entry.addElement(element); } element.set(entry); + + checkConsistency(); } } @@ -605,6 +626,7 @@ evict(elements[i], shift); } } + checkConsistency(); } } @@ -641,36 +663,35 @@ private void nodeAdded(NodeState state, Path path, NodeId id) throws PathNotFoundException, ItemStateException { - synchronized (cacheMonitor) { - PathMap.Element element = null; + // assert: synchronized (cacheMonitor) + PathMap.Element element = null; - LRUEntry entry = (LRUEntry) idCache.get(id); - if (entry != null) { - // child node already cached: this can have the following - // reasons: - // 1) node was moved, cached path is outdated - // 2) node was cloned, cached path is still valid - NodeState child = null; - if (hasItemState(id)) { - child = (NodeState) getItemState(id); - } - if (child == null || !child.isShareable()) { - PathMap.Element[] elements = entry.getElements(); - element = elements[0]; - for (int i = 0; i < elements.length; i++) { - elements[i].remove(); - } - } - } - PathMap.Element parent = pathCache.map(path.getAncestor(1), true); - if (parent != null) { - parent.insert(path.getNameElement()); + LRUEntry entry = (LRUEntry) idCache.get(id); + if (entry != null) { + // child node already cached: this can have the following + // reasons: + // 1) node was moved, cached path is outdated + // 2) node was cloned, cached path is still valid + NodeState child = null; + if (hasItemState(id)) { + child = (NodeState) getItemState(id); } - if (element != null) { - // store remembered element at new position - pathCache.put(path, element); + if (child == null || !child.isShareable()) { + PathMap.Element[] elements = entry.getElements(); + element = elements[0]; + for (int i = 0; i < elements.length; i++) { + elements[i].remove(); + } } } + PathMap.Element parent = pathCache.map(path.getAncestor(1), true); + if (parent != null) { + parent.insert(path.getNameElement()); + } + if (element != null) { + // store remembered element at new position + pathCache.put(path, element); + } } /** @@ -685,37 +706,36 @@ private void nodeRemoved(NodeState state, Path path, NodeId id) throws PathNotFoundException, ItemStateException { - synchronized (cacheMonitor) { - PathMap.Element parent = pathCache.map(path.getAncestor(1), true); - if (parent == null) { + // assert: synchronized (cacheMonitor) + PathMap.Element parent = pathCache.map(path.getAncestor(1), true); + if (parent == null) { + return; + } + PathMap.Element element = parent.getDescendant(PathFactoryImpl.getInstance().create( + new Path.Element[] { path.getNameElement() }), true); + if (element != null) { + // with SNS, this might evict a child that is NOT the one + // having id, check first whether item has + // the id passed as argument + LRUEntry entry = (LRUEntry) element.get(); + if (entry != null && !entry.getId().equals(id)) { return; } - PathMap.Element element = parent.getDescendant(PathFactoryImpl.getInstance().create( - new Path.Element[] { path.getNameElement() }), true); - if (element != null) { - // with SNS, this might evict a child that is NOT the one - // having id, check first whether item has - // the id passed as argument - LRUEntry entry = (LRUEntry) element.get(); - if (entry != null && !entry.getId().equals(id)) { - return; - } - // if item is shareable, remove this path only, otherwise - // every path this item has been mapped to - NodeState child = null; - if (hasItemState(id)) { - child = (NodeState) getItemState(id); - } - if (child == null || !child.isShareable()) { - evictAll(id, true); - } else { - evict(element, true); - } + // if item is shareable, remove this path only, otherwise + // every path this item has been mapped to + NodeState child = null; + if (hasItemState(id)) { + child = (NodeState) getItemState(id); + } + if (child == null || !child.isShareable()) { + evictAll(id, true); } else { - // element itself is not cached, but removal might cause SNS - // index shifting - parent.remove(path.getNameElement()); + evict(element, true); } + } else { + // element itself is not cached, but removal might cause SNS + // index shifting + parent.remove(path.getNameElement()); } } @@ -744,6 +764,63 @@ ps.println(line.toString()); } }, true); + } + } + + /** + * Check consistency. + */ + private void checkConsistency() throws IllegalStateException { + // assert: synchronized (cacheMonitor) + if (!consistencyCheckEnabled) { + return; + } + + int elementsInCache = 0; + + Iterator iter = idCache.values().iterator(); + while (iter.hasNext()) { + LRUEntry entry = (LRUEntry) iter.next(); + elementsInCache += entry.getElements().length; + } + + class PathMapElementCounter implements PathMap.ElementVisitor { + int count; + public void elementVisited(PathMap.Element element) { + LRUEntry mappedEntry = (LRUEntry) element.get(); + LRUEntry cachedEntry = (LRUEntry) idCache.get(mappedEntry.getId()); + if (cachedEntry == null) { + String msg = "Path element (" + element + + " ) cached in path map, associated id (" + + mappedEntry.getId() + ") isn't."; + throw new IllegalStateException(msg); + } + if (cachedEntry != mappedEntry) { + String msg = "LRUEntry associated with element (" + element + + " ) in path map is not equal to cached LRUEntry (" + + cachedEntry.getId() + ")."; + throw new IllegalStateException(msg); + } + PathMap.Element[] elements = cachedEntry.getElements(); + for (int i = 0; i < elements.length; i++) { + if (elements[i] == element) { + count++; + return; + } + } + String msg = "Element (" + element + + ") cached in path map, but not in associated LRUEntry (" + + cachedEntry.getId() + ")."; + throw new IllegalStateException(msg); + } + } + + PathMapElementCounter counter = new PathMapElementCounter(); + pathCache.traverse(counter, false); + if (counter.count != elementsInCache) { + String msg = "PathMap element and cached element count don't match (" + + counter.count + " != " + elementsInCache + ")"; + throw new IllegalStateException(msg); } }