You are viewing a plain text version of this content. The canonical link for it is here.
Posted to slide-dev@jakarta.apache.org by st...@apache.org on 2004/08/18 15:13:52 UTC

cvs commit: jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/state ItemStateCache.java ItemStateProvider.java TicketItemStateManager.java TransientItemStateManager.java

stefan      2004/08/18 06:13:52

  Modified:    proposals/jcrri/src/org/apache/slide/jcr/core/state
                        ItemStateCache.java ItemStateProvider.java
                        TicketItemStateManager.java
                        TransientItemStateManager.java
  Log:
  #0000 fixed performance issues when saving on root
  
  Revision  Changes    Path
  1.10      +10 -1     jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/state/ItemStateCache.java
  
  Index: ItemStateCache.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/state/ItemStateCache.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- ItemStateCache.java	2 Aug 2004 16:22:22 -0000	1.9
  +++ ItemStateCache.java	18 Aug 2004 13:13:52 -0000	1.10
  @@ -129,6 +129,15 @@
       }
   
       /**
  +     * Returns the number of entries in the cache.
  +     *
  +     * @return number of entries in the cache.
  +     */
  +    protected int size() {
  +	return cache.size();
  +    }
  +
  +    /**
        * Returns an iterator of the keys (i.e. <code>ItemId</code> objects)
        * of the cached entries.
        *
  
  
  
  1.7       +3 -1      jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/state/ItemStateProvider.java
  
  Index: ItemStateProvider.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/state/ItemStateProvider.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- ItemStateProvider.java	2 Aug 2004 16:22:22 -0000	1.6
  +++ ItemStateProvider.java	18 Aug 2004 13:13:52 -0000	1.7
  @@ -17,6 +17,8 @@
   
   import org.apache.slide.jcr.core.ItemId;
   
  +import java.util.Iterator;
  +
   /**
    * The <code>ItemStateProvider</code> interface...
    *
  
  
  
  1.7       +237 -30   jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/state/TicketItemStateManager.java
  
  Index: TicketItemStateManager.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/state/TicketItemStateManager.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- TicketItemStateManager.java	2 Aug 2004 16:22:22 -0000	1.6
  +++ TicketItemStateManager.java	18 Aug 2004 13:13:52 -0000	1.7
  @@ -1,6 +1,6 @@
   /*
    * Copyright 2002-2004 The Apache Software Foundation.
  - *
  +   *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
  @@ -20,10 +20,7 @@
   
   import javax.jcr.RepositoryException;
   import java.io.PrintStream;
  -import java.util.ArrayList;
  -import java.util.Collections;
  -import java.util.Iterator;
  -import java.util.List;
  +import java.util.*;
   
   /**
    * <code>TicketItemStateManager</code> ...
  @@ -55,31 +52,44 @@
   	hierMgr = new HierarchyManagerImpl(rootNodeUUID, this, nsResolver);
       }
   
  -    static synchronized void collectDescendantItemStates(ItemId id, HierarchyManager hierMgr, ItemStateProvider provider, List descendents) {
  +    private synchronized void collectDescendantItemStates(ItemId id, List descendents) {
  +	// XXX very inefficient implementation, especially if # of transient states
  +	// is relatively small compared to the total # of persistent states
  +	if (descendents.size() == transientStateMgr.getEntriesCount()) {
  +	    return;
  +	}
   	try {
   	    if (id.denotesNode()) {
   		NodeId parentId = (NodeId) id;
   		ItemId[] childIds = hierMgr.listChildren(parentId);
   		for (int i = 0; i < childIds.length; i++) {
   		    ItemId childId = childIds[i];
  -		    if (provider.hasItemState(childId)) {
  -			descendents.add(provider.getItemState(childId));
  +		    if (transientStateMgr.hasItemState(childId)) {
  +			ItemState state = transientStateMgr.getItemState(childId);
  +			if (!descendents.contains(state)) {
  +			    descendents.add(state);
  +			}
  +		    }
  +		    if (childId.denotesNode()) {
  +			// recurse
  +			collectDescendantItemStates(childId, descendents);
   		    }
  -		    // recurse
  -		    collectDescendantItemStates(childId, hierMgr, provider, descendents);
   		}
   		// also add transient child nodes that have been unlinked from
   		// the specified parent node but are not orphaned yet (i.e.
   		// they are still linked to at least one other parent node)
  -		if (provider.hasItemState(parentId)) {
  -		    NodeState parentState = (NodeState) provider.getItemState(parentId);
  +		if (transientStateMgr.hasItemState(parentId)) {
  +		    NodeState parentState = (NodeState) transientStateMgr.getItemState(parentId);
   		    Iterator iter = parentState.getRemovedChildNodeEntries().iterator();
   		    while (iter.hasNext()) {
   			// removed child nodes
   			NodeState.ChildNodeEntry cne = (NodeState.ChildNodeEntry) iter.next();
   			NodeId removedChildId = new NodeId(cne.getUUID());
  -			if (provider.hasItemState(removedChildId)) {
  -			    descendents.add(provider.getItemState(removedChildId));
  +			if (transientStateMgr.hasItemState(removedChildId)) {
  +			    ItemState state = transientStateMgr.getItemState(removedChildId);
  +			    if (!descendents.contains(state)) {
  +				descendents.add(state);
  +			    }
   			}
   		    }
   		}
  @@ -91,7 +101,12 @@
   	}
       }
   
  -    static synchronized void collectDescendantItemStatesInAttic(ItemId id, HierarchyManager hierMgr, ItemStateProvider provider, List descendents) {
  +    private synchronized void collectDescendantItemStatesInAttic(ItemId id, List descendents) {
  +	// XXX very inefficient implementation, especially if # of transient states
  +	// is relatively small compared to the total # of persistent states
  +	if (descendents.size() == transientStateMgr.getEntriesInAtticCount()) {
  +	    return;
  +	}
   	try {
   	    if (id.denotesNode()) {
   		NodeId parentId = (NodeId) id;
  @@ -101,26 +116,27 @@
   		for (int i = 0; i < childIds.length; i++) {
   		    ItemId childId = childIds[i];
   		    // check attic
  -		    if (provider.hasItemStateInAttic(childId)) {
  +		    if (transientStateMgr.hasItemStateInAttic(childId)) {
   			// found on attic, add to descendents list
  -			descendents.add(provider.getItemStateInAttic(childId));
  +			ItemState state = transientStateMgr.getItemStateInAttic(childId);
  +			if (!descendents.contains(state)) {
  +			    descendents.add(state);
  +			}
  +		    }
  +		    if (childId.denotesNode()) {
  +			// recurse
  +			collectDescendantItemStatesInAttic(childId, descendents);
   		    }
  -		    // recurse
  -		    collectDescendantItemStatesInAttic(childId, hierMgr, provider, descendents);
   		}
   
  -		// traverse existing children (because parentId might denote
  -		// a node that was marked removed)
  +		// traverse existing children (because they might have zombie children)
   		childIds = hierMgr.listChildren(parentId);
   		for (int i = 0; i < childIds.length; i++) {
   		    ItemId childId = childIds[i];
  -		    // check attic
  -		    if (provider.hasItemStateInAttic(childId)) {
  -			// found on attic, add to descendents list
  -			descendents.add(provider.getItemStateInAttic(childId));
  +		    if (childId.denotesNode()) {
  +			// recurse
  +			collectDescendantItemStatesInAttic(childId, descendents);
   		    }
  -		    // recurse
  -		    collectDescendantItemStatesInAttic(childId, hierMgr, provider, descendents);
   		}
   	    }
   	} catch (ItemStateException ise) {
  @@ -234,9 +250,104 @@
        */
       public Iterator getDescendantTransientItemStates(ItemId parentId) {
   	// @todo need a more efficient way to find descendents in cache (e.g. using hierarchical index)
  +	if (!transientStateMgr.hasAnyItemStates()) {
  +	    return Collections.EMPTY_LIST.iterator();
  +	}
  +	// collection of descendant transient states:
  +	// the path serves as key and sort criteria
  +	TreeMap descendants = new TreeMap(new PathComparator());
  +	try {
  +	    Path[] parentPaths = hierMgr.getAllPaths(parentId);
  +	    /**
  +	     * walk through list of transient states and check if
  +	     * they are descendants of the specified parent
  +	     */
  +	    Iterator iter = transientStateMgr.getEntries();
  +	    while (iter.hasNext()) {
  +		ItemState state = (ItemState) iter.next();
  +		ItemId id = state.getId();
  +		Path[] paths = hierMgr.getAllPaths(id);
  +		boolean isDescendant = false;
  +		/**
  +		 * check if any of the paths to the transient state
  +		 * is a descendant of any of the specified parentId's paths
  +		 */
  +		for (int i = 0; i < paths.length; i++) {
  +		    Path p0 = paths[i];	// path to transient state
  +		    // walk through array of the specified parentId's paths
  +		    for (int j = 0; j < parentPaths.length; j++) {
  +			Path p1 = parentPaths[j]; // path to specified parentId
  +			if (p0.isDescendantOf(p1)) {
  +			    // this is a descendant, add it to the list and
  +			    // continue with next transient state
  +			    descendants.put(p0, state);
  +                            isDescendant = true;
  +			    break;
  +			}
  +		    }
  +		    if (isDescendant) {
  +			break;
  +		    }
  +		}
  +		if (!isDescendant && id.denotesNode()) {
  +		    /**
  +		     * finally check if transient state has been unlinked
  +		     * from a parent node (but is not orphaned yet, i.e. is
  +		     * still linked to at least one other parent node);
  +		     * if that's the case, check if that parent is a
  +		     * descendant of/identical with any of the specified
  +		     * parentId's paths.
  +		     */
  +		    NodeState nodeState = (NodeState) state;
  +		    Iterator iterUUIDs = nodeState.getRemovedParentUUIDs().iterator();
  +		    while (iterUUIDs.hasNext()) {
  +			/**
  +			 * check if any of the paths to the removed parent
  +			 * is a descendant of/identical with any of the
  +			 * specified parentId's paths.
  +			 */
  +			Path[] pa = hierMgr.getAllPaths(new NodeId((String) iterUUIDs.next()));
  +			for (int k = 0; k < pa.length; k++) {
  +			    Path p0 = pa[k];	// path to removed parent
  +			    // walk through array of the specified parentId's paths
  +			    for (int j = 0; j < parentPaths.length; j++) {
  +				Path p1 = parentPaths[j]; // path to specified parentId
  +				if (p0.equals(p1) || p0.isDescendantOf(p1)) {
  +				    // this is a descendant, add it to the list and
  +				    // continue with next transient state
  +
  +				    // FIXME need to create dummy path in order
  +				    // to avoid conflicts
  +				    Path.PathBuilder pb = new Path.PathBuilder(p0.getElements());
  +				    pb.addFirst(NamespaceRegistryImpl.NS_DEFAULT_URI, Integer.toString(new Random().nextInt()));
  +				    descendants.put(pb.getPath(), state);
  +				    isDescendant = true;
  +				    break;
  +				}
  +			    }
  +			    if (isDescendant) {
  +				break;
  +			    }
  +			}
  +			if (isDescendant) {
  +			    break;
  +			}
  +		    }
  +		}
  +		// continue with next transient state
  +	    }
  +	} catch (MalformedPathException mpe) {
  +	    log.warn("inconsistent hierarchy state", mpe);
  +	} catch (RepositoryException re) {
  +	    log.warn("inconsistent hierarchy state", re);
  +	}
  +
  +	return descendants.values().iterator();
  +/*
   	ArrayList descendents = new ArrayList();
  -	collectDescendantItemStates(parentId, hierMgr, transientStateMgr, descendents);
  +	collectDescendantItemStates(parentId, descendents);
   	return Collections.unmodifiableList(descendents).iterator();
  +*/
       }
   
       /**
  @@ -249,9 +360,59 @@
        */
       public Iterator getDescendantTransientItemStatesInAttic(ItemId parentId) {
   	// @todo need a more efficient way to find descendents in attic (e.g. using hierarchical index)
  +	if (!transientStateMgr.hasAnyItemStatesInAttic()) {
  +	    return Collections.EMPTY_LIST.iterator();
  +	}
  +	// collection of descendant transient states in attic:
  +	// the path serves as key and sort criteria
  +	TreeMap descendants = new TreeMap(new PathComparator());
  +	try {
  +	    Path[] parentPaths = hierMgr.getAllPaths(parentId, true);
  +	    /**
  +	     * walk through list of transient states in attic and check if
  +	     * they are descendants of the specified parent
  +	     */
  +	    Iterator iter = transientStateMgr.getEntriesInAttic();
  +	    while (iter.hasNext()) {
  +		ItemState state = (ItemState) iter.next();
  +		ItemId id = state.getId();
  +		Path[] paths = hierMgr.getAllPaths(id, true);
  +		boolean isDescendant = false;
  +		/**
  +		 * check if any of the paths to the transient state
  +		 * is a descendant of any of the specified parentId's paths
  +		 */
  +		for (int i = 0; i < paths.length; i++) {
  +		    Path p0 = paths[i];	// path to transient state in attic
  +		    // walk through array of the specified parentId's paths
  +		    for (int j = 0; j < parentPaths.length; j++) {
  +			Path p1 = parentPaths[j]; // path to specified parentId
  +			if (p0.isDescendantOf(p1)) {
  +			    // this is a descendant, add it to the list and
  +			    // continue with next transient state
  +			    descendants.put(p0, state);
  +                            isDescendant = true;
  +			    break;
  +			}
  +		    }
  +		    if (isDescendant) {
  +			break;
  +		    }
  +		}
  +		// continue with next transient state
  +	    }
  +	} catch (MalformedPathException mpe) {
  +	    log.warn("inconsistent hierarchy state", mpe);
  +	} catch (RepositoryException re) {
  +	    log.warn("inconsistent hierarchy state", re);
  +	}
  +
  +	return descendants.values().iterator();
  +/*
   	ArrayList descendents = new ArrayList();
  -	collectDescendantItemStatesInAttic(parentId, hierMgr, transientStateMgr, descendents);
  +	collectDescendantItemStatesInAttic(parentId, descendents);
   	return Collections.unmodifiableList(descendents).iterator();
  +*/
       }
   
       //------< methods for creating & discarding transient ItemState instances >
  @@ -373,5 +534,51 @@
       public PersistentPropertyState createPersistentPropertyState(String parentUUID, QName propName)
   	    throws ItemStateException {
   	return persistentStateMgr.createPropertyState(parentUUID, propName);
  +    }
  +
  +    //--------------------------------------------------------< inner classes >
  +    /**
  +     * Comparator used to sort canonical <code>Path</code> objects
  +     * hierarchically (in depth-first tree traversal order).
  +     */
  +    static class PathComparator implements Comparator {
  +	/**
  +	 *
  +	 * @param o1
  +	 * @param o2
  +	 * @return
  +	 */
  +	public int compare(Object o1, Object o2) {
  +	    Path p1 = (Path) o1;
  +	    Path p2 = (Path) o2;
  +	    if (p1.equals(p2)) {
  +		return 0;
  +	    }
  +	    try {
  +		if (p1.isAncestorOf(p2)) {
  +		    return -1;
  +		} else if (p1.isDescendantOf(p2)) {
  +		    return 1;
  +		}
  +	    } catch (MalformedPathException mpe) {
  +		log.warn("unable to compare non-canonical (i.e. relative) paths", mpe);
  +	    }
  +	    // the 2 paths are not on the same graph;
  +	    // do string comparison of individual path elements
  +	    Path.PathElement[] pea1 = p1.getElements();
  +	    Path.PathElement[] pea2 = p2.getElements();
  +	    for (int i = 0; i < pea1.length; i++) {
  +		if (i >= pea2.length) {
  +		    return 1;
  +		}
  +		String s1 = pea1[i].toString();
  +		String s2 = pea2[i].toString();
  +		int result = s1.compareTo(s2);
  +		if (result != 0) {
  +		    return result;
  +		}
  +	    }
  +	    return 0;
  +	}
       }
   }
  
  
  
  1.13      +39 -2     jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/state/TransientItemStateManager.java
  
  Index: TransientItemStateManager.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/state/TransientItemStateManager.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- TransientItemStateManager.java	2 Aug 2004 16:22:22 -0000	1.12
  +++ TransientItemStateManager.java	18 Aug 2004 13:13:52 -0000	1.13
  @@ -154,12 +154,49 @@
   	}
       }
   
  -    //----------< more methods for listing and retrieving ItemState instances >
  +    //------------------< methods for listing & querying state of cache/attic >
       /**
        * @return
        */
       boolean hasAnyItemStates() {
   	return !isEmpty();
  +    }
  +
  +    /**
  +     * @return
  +     */
  +    boolean hasAnyItemStatesInAttic() {
  +	return !attic.isEmpty();
  +    }
  +
  +    /**
  +     * @return
  +     */
  +    int getEntriesCount() {
  +	return size();
  +    }
  +
  +    /**
  +     * @return
  +     */
  +    int getEntriesInAtticCount() {
  +	return attic.size();
  +    }
  +
  +    /**
  +     *
  +     * @return
  +     */
  +    Iterator getEntries() {
  +	return entries();
  +    }
  +
  +    /**
  +     *
  +     * @return
  +     */ 
  +    Iterator getEntriesInAttic() {
  +	return attic.entries();
       }
   
       //----------------< methods for creating & discarding ItemState instances >
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: slide-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: slide-dev-help@jakarta.apache.org