[jbosscache-commits] JBoss Cache SVN: r6385 - in core/trunk/src/main/java/org/jboss/cache: util/concurrent and 1 other directory.

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Wed Jul 23 16:41:03 EDT 2008


Author: manik.surtani at jboss.com
Date: 2008-07-23 16:41:02 -0400 (Wed, 23 Jul 2008)
New Revision: 6385

Added:
   core/trunk/src/main/java/org/jboss/cache/util/concurrent/SelfInitializingConcurrentHashMap.java
Modified:
   core/trunk/src/main/java/org/jboss/cache/PessimisticUnversionedNode.java
   core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java
Log:
lazy initialization of child map

Modified: core/trunk/src/main/java/org/jboss/cache/PessimisticUnversionedNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/PessimisticUnversionedNode.java	2008-07-23 16:15:03 UTC (rev 6384)
+++ core/trunk/src/main/java/org/jboss/cache/PessimisticUnversionedNode.java	2008-07-23 20:41:02 UTC (rev 6385)
@@ -86,6 +86,7 @@
    {
       PessimisticUnversionedNode<K, V> n = new PessimisticUnversionedNode<K, V>(fqn.getLastElement(), fqn, data, cache);
       copyInternals(n);
+      n.children = children;
       n.lockStrategyFactory = lockStrategyFactory;
       return n;
    }
@@ -100,7 +101,7 @@
       {
          synchronized (this)
          {
-            children().put(child.getFqn().getLastElement(), child);
+            children.put(child.getFqn().getLastElement(), child);
          }
       }
       else
@@ -116,7 +117,7 @@
          throw new IllegalArgumentException("null child name");
       }
 
-      child = (NodeSPI<K, V>) children().get(childName);
+      child = (NodeSPI<K, V>) children.get(childName);
       InvocationContext ctx = cache.getInvocationContext();
       if (createIfNotExists && child == null)
       {
@@ -132,7 +133,7 @@
          {
             // check again to see if the child exists
             // after acquiring exclusive lock
-            child = (NodeSPI<K, V>) children().get(childName);
+            child = (NodeSPI<K, V>) children.get(childName);
             if (child == null)
             {
                if (notify) cache.getNotifier().notifyNodeCreated(childFqn, true, ctx);

Modified: core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java	2008-07-23 16:15:03 UTC (rev 6384)
+++ core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java	2008-07-23 20:41:02 UTC (rev 6385)
@@ -17,6 +17,7 @@
 import org.jboss.cache.optimistic.DataVersion;
 import org.jboss.cache.transaction.GlobalTransaction;
 import org.jboss.cache.util.ImmutableSetCopy;
+import org.jboss.cache.util.concurrent.SelfInitializingConcurrentHashMap;
 
 import java.util.Collections;
 import java.util.HashMap;
@@ -24,7 +25,6 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
 
 /**
  * Basic data node class.  Throws {@link UnsupportedOperationException} for version-specific methods like {@link #getVersion()} and
@@ -82,7 +82,15 @@
       setLockForChildInsertRemove(lockForChildInsertRemove);
       this.fqn = fqn;
       // if this is a root node, create the child map.
-      if (fqn.isRoot()) children = new ConcurrentHashMap<Object, Node<K, V>>(64, .5f, 16);
+      if (fqn.isRoot())
+      {
+         children = new ConcurrentHashMap<Object, Node<K, V>>(64, .5f, 16);
+      }
+      else
+      {
+         // this always needs to be initialized.  The actual cost of the ConcurrentHashMap, however, is deferred.
+         children = new SelfInitializingConcurrentHashMap<Object, Node<K, V>>();
+      }
    }
 
    public UnversionedNode(Fqn fqn, CacheSPI<K, V> cache, boolean lockForChildInsertRemove, Map<K, V> data)
@@ -130,21 +138,6 @@
       return cache.peek(fqn.getParent(), true);
    }
 
-   protected final ConcurrentMap<Object, Node<K, V>> children()
-   {
-      if (children == null) initChildMap();
-      return children;
-   }
-
-   private synchronized void initChildMap()
-   {
-      if (children == null)
-      {
-         // Fewer segments to save memory
-         children = new ConcurrentHashMap<Object, Node<K, V>>(4, .75f, 4);
-      }
-   }
-
    // does not need to be synchronized since this will only be accessed by a single thread in MVCC thanks to the write lock.
    private void initDataMap()
    {
@@ -202,14 +195,14 @@
          throw new IllegalArgumentException("null child name");
       }
 
-      child = (NodeSPI<K, V>) children().get(childName);
+      child = (NodeSPI<K, V>) children.get(childName);
       InvocationContext ctx = cache.getInvocationContext();
       if (createIfNotExists && child == null)
       {
          Fqn childFqn = Fqn.fromRelativeElements(fqn, childName);
          NodeSPI<K, V> newChild = nodeFactory.createNode(childFqn, delegate);
 
-         child = (NodeSPI<K, V>) children().putIfAbsent(childName, newChild);
+         child = (NodeSPI<K, V>) children.putIfAbsent(childName, newChild);
 
          if (child == null)
          {
@@ -349,7 +342,7 @@
       Fqn childFqn = child.getFqn();
       if (childFqn.isDirectChildOf(fqn))
       {
-         children().put(childFqn.getLastElement(), child);
+         children.put(childFqn.getLastElement(), child);
       }
       else
       {
@@ -449,7 +442,7 @@
          this.children = null;
       else
       {
-         this.children().clear();
+         this.children.clear();
          this.children.putAll(children);
       }
    }
@@ -500,7 +493,7 @@
    {
       if (childName != null)
       {
-         children().put(childName, n);
+         children.put(childName, n);
       }
    }
 
@@ -632,7 +625,7 @@
       if (trace) log.trace("Marking node " + getFqn() + " as " + (valid ? "" : "in") + "valid");
       if (recursive)
       {
-         for (Node<K, V> child : children().values())
+         for (Node<K, V> child : children.values())
          {
             ((NodeSPI<K, V>) child).setValid(valid, recursive);
          }
@@ -661,7 +654,7 @@
    protected void copyInternals(UnversionedNode n)
    {
       // direct reference to child map
-      n.children = children();
+      n.children = children;
       n.commandsFactory = commandsFactory;
       n.delegate = delegate;
       n.nodeFactory = nodeFactory;

Added: core/trunk/src/main/java/org/jboss/cache/util/concurrent/SelfInitializingConcurrentHashMap.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/util/concurrent/SelfInitializingConcurrentHashMap.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/util/concurrent/SelfInitializingConcurrentHashMap.java	2008-07-23 20:41:02 UTC (rev 6385)
@@ -0,0 +1,192 @@
+package org.jboss.cache.util.concurrent;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * Primarily used to hold child maps for nodes.  Underlying CHM is null initially, and once threads start
+ * writing to this map, the CHM is initialized.
+ *
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @since 3.0
+ */
+public class SelfInitializingConcurrentHashMap<K, V> implements ConcurrentMap<K, V>
+{
+   private volatile ConcurrentMap<K, V> delegate;
+//   private int initialCapacity = -1, concurrencyLevel = -1;
+//   private float loadFactor = -1;
+
+   /**
+    * Creates a new delegate map and will use a default constructor to initialize the {@link java.util.concurrent.ConcurrentMap}
+    * it will eventually delegate to.
+    */
+   public SelfInitializingConcurrentHashMap()
+   {
+
+   }
+
+   /**
+    * Creates a new delegate map and will use the params passed in to initialize the {@link java.util.concurrent.ConcurrentMap}
+    * it will eventually delegate to.
+    *
+    * @param initialCapacity  the initial capacity. The implementation
+    *                         performs internal sizing to accommodate this many elements.
+    * @param loadFactor       the load factor threshold, used to control resizing.
+    *                         Resizing may be performed when the average number of elements per
+    *                         bin exceeds this threshold.
+    * @param concurrencyLevel the estimated number of concurrently
+    *                         updating threads. The implementation performs internal sizing
+    *                         to try to accommodate this many threads.
+    * @throws IllegalArgumentException if the initial capacity is
+    *                                  negative or the load factor or concurrencyLevel are
+    *                                  nonpositive.
+    */
+//   public SelfInitializingConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel)
+//   {
+//      this.initialCapacity = initialCapacity;
+//      this.loadFactor = loadFactor;
+//      this.concurrencyLevel = concurrencyLevel;
+//   }
+
+   // -------------- initialization methods and helpers ----------------------
+   private ConcurrentMap<K, V> getDelegate()
+   {
+      if (delegate == null) init();
+      return delegate;
+   }
+
+   private synchronized void init()
+   {
+      // Reminiscent of DCL but the delegate here is volatile so construction reordering should not affect.
+      if (delegate == null)
+      {
+         delegate = new ConcurrentHashMap<K, V>(4, 0.75f, 4);
+         // hard-coded for node child maps for now
+
+//         if (initialCapacity == -1 || concurrencyLevel == -1 || loadFactor == -1)
+//         {
+//            delegate = new ConcurrentHashMap<K, V>();
+//         }
+//         else
+//         {
+//            delegate = new ConcurrentHashMap<K, V>(initialCapacity, loadFactor, concurrencyLevel);
+//         }
+      }
+   }
+
+   // -------------- Public API methods that will trigger initialization ----------------------
+
+   public final V put(K key, V value)
+   {
+      return getDelegate().put(key, value);
+   }
+
+   public final V remove(Object key)
+   {
+      return getDelegate().remove(key);
+   }
+
+   public final void putAll(Map<? extends K, ? extends V> m)
+   {
+      getDelegate().putAll(m);
+   }
+
+   public final V putIfAbsent(K key, V value)
+   {
+      return getDelegate().putIfAbsent(key, value);
+   }
+
+   public final boolean replace(K key, V oldValue, V newValue)
+   {
+      return getDelegate().replace(key, oldValue, newValue);
+   }
+
+   public final V replace(K key, V value)
+   {
+      return getDelegate().replace(key, value);
+   }
+
+   // -------------- Public API methods that won't trigger initialization ----------------------
+
+   public final boolean remove(Object key, Object value)
+   {
+      return delegate != null && delegate.remove(key, value);
+   }
+
+   public final int size()
+   {
+      return delegate == null ? 0 : delegate.size();
+   }
+
+   public final boolean isEmpty()
+   {
+      return delegate == null || delegate.isEmpty();
+   }
+
+   public final boolean containsKey(Object key)
+   {
+      return delegate != null && delegate.containsKey(key);
+   }
+
+   public final boolean containsValue(Object value)
+   {
+      return delegate != null && delegate.containsValue(value);
+   }
+
+   public final V get(Object key)
+   {
+      return delegate == null ? null : delegate.get(key);
+   }
+
+   public final void clear()
+   {
+      if (delegate != null) delegate.clear();
+   }
+
+   public final Set<K> keySet()
+   {
+      if (delegate == null) return Collections.emptySet();
+      return delegate.keySet();
+   }
+
+   public final Collection<V> values()
+   {
+      if (delegate == null) return Collections.emptySet();
+      return delegate.values();
+   }
+
+   public final Set<Entry<K, V>> entrySet()
+   {
+      if (delegate == null) return Collections.emptySet();
+      return delegate.entrySet();
+   }
+
+   @Override
+   public String toString()
+   {
+      return "SelfInitializingConcurrentHashMap{" +
+            "delegate=" + delegate +
+            '}';
+   }
+
+   @Override
+   public boolean equals(Object o)
+   {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+      SelfInitializingConcurrentHashMap that = (SelfInitializingConcurrentHashMap) o;
+      return !(delegate != null ? !delegate.equals(that.delegate) : that.delegate != null);
+   }
+
+   @Override
+   public int hashCode()
+   {
+      int result;
+      result = (delegate != null ? delegate.hashCode() : 0);
+      return result;
+   }
+}




More information about the jbosscache-commits mailing list