[jboss-svn-commits] JBoss Common SVN: r4045 - jboss-logmanager/trunk/src/main/java/org/jboss/logmanager.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Thu Feb 18 20:14:51 EST 2010


Author: david.lloyd at jboss.com
Date: 2010-02-18 20:14:50 -0500 (Thu, 18 Feb 2010)
New Revision: 4045

Added:
   jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/CopyOnWriteWeakMap.java
   jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/FastCopyHashMap.java
Modified:
   jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/LoggerNode.java
Log:
Use new CopyOnWriteWeakMap for LoggerNodes to reference their children to keep memory consumption down without sacrificing lookup performance

Added: jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/CopyOnWriteWeakMap.java
===================================================================
--- jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/CopyOnWriteWeakMap.java	                        (rev 0)
+++ jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/CopyOnWriteWeakMap.java	2010-02-19 01:14:50 UTC (rev 4045)
@@ -0,0 +1,254 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2010, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.logmanager;
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.AbstractMap;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+
+final class CopyOnWriteWeakMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> {
+
+    private final Queue<K, V> queue = new Queue<K, V>();
+
+    private static final FastCopyHashMap EMPTY = new FastCopyHashMap(32, 0.25f);
+
+    @SuppressWarnings({ "unchecked" })
+    private FastCopyHashMap<K, Node<K, V>> empty() { return (FastCopyHashMap<K, Node<K, V>>) EMPTY; }
+
+    private volatile FastCopyHashMap<K, Node<K, V>> map = empty();
+
+    private FastCopyHashMap<K, Node<K, V>> cleanCopyForRemove() {
+        assert Thread.holdsLock(this);
+        final Map<K, Node<K, V>> oldMap = map;
+        final Queue<K, V> queue = this.queue;
+        if (oldMap.isEmpty()) {
+            queue.clear();
+            return empty();
+        }
+        final FastCopyHashMap<K, Node<K, V>> newMap = new FastCopyHashMap<K, Node<K, V>>(oldMap);
+        Node<K, V> ref;
+        while ((ref = queue.poll()) != null) {
+            final Object key = ref.getKey();
+            if (newMap.get(key) == ref) {
+                newMap.remove(key);
+                if (newMap.isEmpty()) {
+                    queue.clear();
+                    return empty();
+                }
+            }
+        }
+        return newMap;
+    }
+
+    private FastCopyHashMap<K, Node<K, V>> cleanCopyForMod() {
+        assert Thread.holdsLock(this);
+        final Map<K, Node<K, V>> oldMap = map;
+        final Queue<K, V> queue = this.queue;
+        if (oldMap.isEmpty()) {
+            queue.clear();
+            return empty().clone();
+        }
+        final FastCopyHashMap<K, Node<K, V>> newMap = new FastCopyHashMap<K, Node<K, V>>(oldMap);
+        Node<K, V> ref;
+        while ((ref = queue.poll()) != null) {
+            final Object key = ref.getKey();
+            if (newMap.get(key) == ref) {
+                newMap.remove(key);
+                if (newMap.isEmpty()) {
+                    queue.clear();
+                    return empty().clone();
+                }
+            }
+        }
+        return newMap;
+    }
+
+    public V putIfAbsent(final K key, final V value) {
+        if (key == null) {
+            throw new IllegalArgumentException("key is null");
+        }
+        if (value == null) {
+            throw new IllegalArgumentException("value is null");
+        }
+        synchronized (this) {
+            final Node<K, V> oldNode = map.get(key);
+            if (oldNode != null) {
+                final V val = oldNode.get();
+                if (val != null) return val;
+            }
+            final FastCopyHashMap<K, Node<K, V>> newMap = cleanCopyForMod();
+            newMap.put(key, new Node<K,V>(key, value, queue));
+            map = newMap;
+            return null;
+        }
+    }
+
+    public boolean remove(final Object key, final Object value) {
+        synchronized (this) {
+            final Node<K, V> oldNode = map.get(key);
+            final V existing = oldNode.get();
+            if (existing != null && existing.equals(value)) {
+                final FastCopyHashMap<K, Node<K, V>> newMap = cleanCopyForRemove();
+                newMap.remove(key);
+                map = newMap;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean replace(final K key, final V oldValue, final V newValue) {
+        if (newValue == null) {
+            throw new IllegalArgumentException("newValue is null");
+        }
+        if (oldValue == null) {
+            return false;
+        }
+        synchronized (this) {
+            final Node<K, V> oldNode = map.get(key);
+            final V existing = oldNode.get();
+            if (existing != null && existing.equals(oldValue)) {
+                final FastCopyHashMap<K, Node<K, V>> newMap = cleanCopyForMod();
+                map.put(key, new Node<K, V>(key, newValue, queue));
+                map = newMap;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public V replace(final K key, final V value) {
+        if (value == null) {
+            throw new IllegalArgumentException("value is null");
+        }
+        synchronized (this) {
+            final Node<K, V> oldNode = map.get(key);
+            final V existing = oldNode.get();
+            if (existing != null) {
+                final FastCopyHashMap<K, Node<K, V>> newMap = cleanCopyForMod();
+                map.put(key, new Node<K, V>(key, value, queue));
+                map = newMap;
+            }
+            return existing;
+        }
+    }
+
+    public int size() {
+        return map.size();
+    }
+
+    public boolean isEmpty() {
+        return map.isEmpty();
+    }
+
+    public boolean containsKey(final Object key) {
+        return map.containsKey(key);
+    }
+
+    public boolean containsValue(final Object value) {
+        if (value == null) return false;
+        for (Node<K, V> node : map.values()) {
+            if (value.equals(node.get())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public V get(final Object key) {
+        final Node<K, V> node = map.get(key);
+        return node == null ? null : node.get();
+    }
+
+    public V put(final K key, final V value) {
+        if (key == null) {
+            throw new IllegalArgumentException("key is null");
+        }
+        if (value == null) {
+            throw new IllegalArgumentException("value is null");
+        }
+        synchronized (this) {
+            final FastCopyHashMap<K, Node<K, V>> newMap = cleanCopyForMod();
+            final Node<K, V> old = newMap.put(key, new Node<K, V>(key, value, queue));
+            map = newMap;
+            return old == null ? null : old.get();
+        }
+    }
+
+    public V remove(final Object key) {
+        if (key == null) return null;
+        synchronized (this) {
+            final FastCopyHashMap<K, Node<K, V>> newMap = cleanCopyForRemove();
+            final Node<K, V> old = newMap.remove(key);
+            map = newMap;
+            return old == null ? null : old.get();
+        }
+    }
+
+    public void clear() {
+        synchronized (this) {
+            map = empty();
+        }
+    }
+
+    public Set<Entry<K, V>> entrySet() {
+        final FastCopyHashMap<K, Node<K, V>> snapshot = map;
+        final Map<K, V> copyMap = new HashMap<K, V>();
+        for (Node<K, V> node : snapshot.values()) {
+            final V value = node.get();
+            if (value == null) continue;
+            final K key = node.getKey();
+            copyMap.put(key, value);
+        }
+        return Collections.unmodifiableMap(copyMap).entrySet();
+    }
+
+    private static final class Node<K, V> extends WeakReference<V> {
+        private final K key;
+
+        Node(final K key, final V value, final ReferenceQueue<? super V> queue) {
+            super(value, queue);
+            this.key = key;
+        }
+
+        K getKey() {
+            return key;
+        }
+    }
+
+    private static final class Queue<K, V> extends ReferenceQueue<V> {
+
+        public Node<K, V> poll() {
+            return (Node<K, V>) super.poll();
+        }
+
+        void clear() {
+            while (poll() != null);
+        }
+    }
+}

Added: jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/FastCopyHashMap.java
===================================================================
--- jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/FastCopyHashMap.java	                        (rev 0)
+++ jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/FastCopyHashMap.java	2010-02-19 01:14:50 UTC (rev 4045)
@@ -0,0 +1,855 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.logmanager;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.AbstractCollection;
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+/**
+ * A HashMap that is optimized for fast shallow copies. If the copy-ctor is
+ * passed another FastCopyHashMap, or clone is called on this map, the shallow
+ * copy can be performed using little more than a single array copy. In order to
+ * accomplish this, immutable objects must be used internally, so update
+ * operations result in slightly more object churn than <code>HashMap</code>.
+ *
+ * Note: It is very important to use a smaller load factor than you normally
+ * would for HashMap, since the implementation is open-addressed with linear
+ * probing. With a 50% load-factor a get is expected to return in only 2 probes.
+ * However, a 90% load-factor is expected to return in around 50 probes.
+ *
+ * @author Jason T. Greene
+ */
+class FastCopyHashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, Cloneable, Serializable
+{
+   /**
+    * Marks null keys.
+    */
+   private static final Object NULL = new Object();
+
+   /**
+    * Serialization ID
+    */
+   private static final long serialVersionUID = 10929568968762L;
+
+   /**
+    * Same default as HashMap, must be a power of 2
+    */
+   private static final int DEFAULT_CAPACITY = 8;
+
+   /**
+    * MAX_INT - 1
+    */
+   private static final int MAXIMUM_CAPACITY = 1 << 30;
+
+   /**
+    * 67%, just like IdentityHashMap
+    */
+   private static final float DEFAULT_LOAD_FACTOR = 0.67f;
+
+   /**
+    * The open-addressed table
+    */
+   private transient Entry<K, V>[] table;
+
+   /**
+    * The current number of key-value pairs
+    */
+   private transient int size;
+
+   /**
+    * The next resize
+    */
+   private transient int threshold;
+
+   /**
+    * The user defined load factor which defines when to resize
+    */
+   private final float loadFactor;
+
+   /**
+    * Counter used to detect changes made outside of an iterator
+    */
+   private transient int modCount;
+
+   // Cached views
+   private transient KeySet keySet;
+   private transient Values values;
+   private transient EntrySet entrySet;
+
+   public FastCopyHashMap(int initialCapacity, float loadFactor)
+   {
+      if (initialCapacity < 0)
+         throw new IllegalArgumentException("Can not have a negative size table!");
+
+      if (initialCapacity > MAXIMUM_CAPACITY)
+         initialCapacity = MAXIMUM_CAPACITY;
+
+      if (!(loadFactor > 0F && loadFactor <= 1F))
+         throw new IllegalArgumentException("Load factor must be greater than 0 and less than or equal to 1");
+
+      this.loadFactor = loadFactor;
+      init(initialCapacity, loadFactor);
+   }
+
+   @SuppressWarnings("unchecked")
+   public FastCopyHashMap(Map<? extends K, ? extends V> map)
+   {
+      if (map instanceof FastCopyHashMap)
+      {
+         FastCopyHashMap<? extends K, ? extends V> fast = (FastCopyHashMap<? extends K, ? extends V>) map;
+         this.table = (Entry<K, V>[]) fast.table.clone();
+         this.loadFactor = fast.loadFactor;
+         this.size = fast.size;
+         this.threshold = fast.threshold;
+      }
+      else
+      {
+         this.loadFactor = DEFAULT_LOAD_FACTOR;
+         init(map.size(), this.loadFactor);
+         putAll(map);
+      }
+   }
+
+   @SuppressWarnings("unchecked")
+   private void init(int initialCapacity, float loadFactor)
+   {
+      int c = 1;
+      for (; c < initialCapacity; c <<= 1) ;
+      threshold = (int) (c * loadFactor);
+
+      // Include the load factor when sizing the table for the first time
+      if (initialCapacity > threshold && c < MAXIMUM_CAPACITY)
+      {
+         c <<= 1;
+         threshold = (int) (c * loadFactor);
+      }
+
+      this.table = (Entry<K, V>[]) new Entry[c];
+   }
+
+   public FastCopyHashMap(int initialCapacity)
+   {
+      this(initialCapacity, DEFAULT_LOAD_FACTOR);
+   }
+
+   public FastCopyHashMap()
+   {
+      this(DEFAULT_CAPACITY);
+   }
+
+   // The normal bit spreader...
+   private static final int hash(Object key)
+   {
+      int h = key.hashCode();
+      h ^= (h >>> 20) ^ (h >>> 12);
+      return h ^ (h >>> 7) ^ (h >>> 4);
+   }
+
+   @SuppressWarnings("unchecked")
+   private static final <K> K maskNull(K key)
+   {
+      return key == null ? (K) NULL : key;
+   }
+
+   private static final <K> K unmaskNull(K key)
+   {
+      return key == NULL ? null : key;
+   }
+
+   private int nextIndex(int index, int length)
+   {
+      index = (index >= length - 1) ? 0 : index + 1;
+      return index;
+   }
+
+   private static final boolean eq(Object o1, Object o2)
+   {
+      return o1 == o2 || (o1 != null && o1.equals(o2));
+   }
+
+   private static final int index(int hashCode, int length)
+   {
+      return hashCode & (length - 1);
+   }
+
+   public int size()
+   {
+      return size;
+   }
+
+   public boolean isEmpty()
+   {
+      return size == 0;
+   }
+
+   public V get(Object key)
+   {
+      key = maskNull(key);
+
+      int hash = hash(key);
+      int length = table.length;
+      int index = index(hash, length);
+
+      for (int start = index; ;)
+      {
+         Entry<K, V> e = table[index];
+         if (e == null)
+            return null;
+
+         if (e.hash == hash && eq(key, e.key))
+            return e.value;
+
+         index = nextIndex(index, length);
+         if (index == start) // Full table
+            return null;
+      }
+   }
+
+   public boolean containsKey(Object key)
+   {
+      key = maskNull(key);
+
+      int hash = hash(key);
+      int length = table.length;
+      int index = index(hash, length);
+
+      for (int start = index; ;)
+      {
+         Entry<K, V> e = table[index];
+         if (e == null)
+            return false;
+
+         if (e.hash == hash && eq(key, e.key))
+            return true;
+
+         index = nextIndex(index, length);
+         if (index == start) // Full table
+            return false;
+      }
+   }
+
+   public boolean containsValue(Object value)
+   {
+      for (Entry<K, V> e : table)
+         if (e != null && eq(value, e.value))
+            return true;
+
+      return false;
+   }
+
+   public V put(K key, V value)
+   {
+      key = maskNull(key);
+
+      Entry<K, V>[] table = this.table;
+      int hash = hash(key);
+      int length = table.length;
+      int index = index(hash, length);
+
+      for (int start = index; ;)
+      {
+         Entry<K, V> e = table[index];
+         if (e == null)
+            break;
+
+         if (e.hash == hash && eq(key, e.key))
+         {
+            table[index] = new Entry<K, V>(e.key, e.hash, value);
+            return e.value;
+         }
+
+         index = nextIndex(index, length);
+         if (index == start)
+            throw new IllegalStateException("Table is full!");
+      }
+
+      modCount++;
+      table[index] = new Entry<K, V>(key, hash, value);
+      if (++size >= threshold)
+         resize(length);
+
+      return null;
+   }
+
+
+   @SuppressWarnings("unchecked")
+   private void resize(int from)
+   {
+      int newLength = from << 1;
+
+      // Can't get any bigger
+      if (newLength > MAXIMUM_CAPACITY || newLength <= from)
+         return;
+
+      Entry<K, V>[] newTable = new Entry[newLength];
+      Entry<K, V>[] old = table;
+
+      for (Entry<K, V> e : old)
+      {
+         if (e == null)
+            continue;
+
+         int index = index(e.hash, newLength);
+         while (newTable[index] != null)
+            index = nextIndex(index, newLength);
+
+         newTable[index] = e;
+      }
+
+      threshold = (int) (loadFactor * newLength);
+      table = newTable;
+   }
+
+   public void putAll(Map<? extends K, ? extends V> map)
+   {
+      int size = map.size();
+      if (size == 0)
+         return;
+
+      if (size > threshold)
+      {
+         if (size > MAXIMUM_CAPACITY)
+            size = MAXIMUM_CAPACITY;
+
+         int length = table.length;
+         for (; length < size; length <<= 1) ;
+
+         resize(length);
+      }
+
+      for (Map.Entry<? extends K, ? extends V> e : map.entrySet())
+         put(e.getKey(), e.getValue());
+   }
+
+   public V remove(Object key)
+   {
+      key = maskNull(key);
+
+      Entry<K, V>[] table = this.table;
+      int length = table.length;
+      int hash = hash(key);
+      int start = index(hash, length);
+
+      for (int index = start; ;)
+      {
+         Entry<K, V> e = table[index];
+         if (e == null)
+            return null;
+
+         if (e.hash == hash && eq(key, e.key))
+         {
+            table[index] = null;
+            relocate(index);
+            modCount++;
+            size--;
+            return e.value;
+         }
+
+         index = nextIndex(index, length);
+         if (index == start)
+            return null;
+      }
+
+
+   }
+
+   private void relocate(int start)
+   {
+      Entry<K, V>[] table = this.table;
+      int length = table.length;
+      int current = nextIndex(start, length);
+
+      for (; ;)
+      {
+         Entry<K, V> e = table[current];
+         if (e == null)
+            return;
+
+         // A Doug Lea variant of Knuth's Section 6.4 Algorithm R.
+         // This provides a non-recursive method of relocating
+         // entries to their optimal positions once a gap is created.
+         int prefer = index(e.hash, length);
+         if ((current < prefer && (prefer <= start || start <= current))
+               || (prefer <= start && start <= current))
+         {
+            table[start] = e;
+            table[current] = null;
+            start = current;
+         }
+
+         current = nextIndex(current, length);
+      }
+   }
+
+   public void clear()
+   {
+      modCount++;
+      Entry<K, V>[] table = this.table;
+      for (int i = 0; i < table.length; i++)
+         table[i] = null;
+
+      size = 0;
+   }
+
+   @SuppressWarnings("unchecked")
+   public FastCopyHashMap<K, V> clone()
+   {
+      try
+      {
+         FastCopyHashMap<K, V> clone = (FastCopyHashMap<K, V>) super.clone();
+         clone.table = table.clone();
+         clone.entrySet = null;
+         clone.values = null;
+         clone.keySet = null;
+         return clone;
+      }
+      catch (CloneNotSupportedException e)
+      {
+         // should never happen
+         throw new IllegalStateException(e);
+      }
+   }
+
+   public void printDebugStats()
+   {
+      int optimal = 0;
+      int total = 0;
+      int totalSkew = 0;
+      int maxSkew = 0;
+      for (int i = 0; i < table.length; i++)
+      {
+         Entry<K, V> e = table[i];
+         if (e != null)
+         {
+
+            total++;
+            int target = index(e.hash, table.length);
+            if (i == target)
+               optimal++;
+            else
+            {
+               int skew = Math.abs(i - target);
+               if (skew > maxSkew) maxSkew = skew;
+               totalSkew += skew;
+            }
+
+         }
+      }
+
+      System.out.println(" Size:            " + size);
+      System.out.println(" Real Size:       " + total);
+      System.out.println(" Optimal:         " + optimal + " (" + (float) optimal * 100 / total + "%)");
+      System.out.println(" Average Distnce: " + ((float) totalSkew / (total - optimal)));
+      System.out.println(" Max Distance:    " + maxSkew);
+   }
+
+   public Set<Map.Entry<K, V>> entrySet()
+   {
+      if (entrySet == null)
+         entrySet = new EntrySet();
+
+      return entrySet;
+   }
+
+   public Set<K> keySet()
+   {
+      if (keySet == null)
+         keySet = new KeySet();
+
+      return keySet;
+   }
+
+   public Collection<V> values()
+   {
+      if (values == null)
+         values = new Values();
+
+      return values;
+   }
+
+   @SuppressWarnings("unchecked")
+   private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException
+   {
+      s.defaultReadObject();
+
+      int size = s.readInt();
+
+      init(size, loadFactor);
+
+      for (int i = 0; i < size; i++)
+      {
+         K key = (K) s.readObject();
+         V value = (V) s.readObject();
+         putForCreate(key, value);
+      }
+
+      this.size = size;
+   }
+
+   @SuppressWarnings("unchecked")
+   private void putForCreate(K key, V value)
+   {
+      key = maskNull(key);
+
+      Entry<K, V>[] table = this.table;
+      int hash = hash(key);
+      int length = table.length;
+      int index = index(hash, length);
+
+      Entry<K, V> e = table[index];
+      while (e != null)
+      {
+         index = nextIndex(index, length);
+         e = table[index];
+      }
+
+      table[index] = new Entry<K, V>(key, hash, value);
+   }
+
+   private void writeObject(java.io.ObjectOutputStream s) throws IOException
+   {
+      s.defaultWriteObject();
+      s.writeInt(size);
+
+      for (Entry<K, V> e : table)
+      {
+         if (e != null)
+         {
+            s.writeObject(unmaskNull(e.key));
+            s.writeObject(e.value);
+         }
+      }
+   }
+
+   private static final class Entry<K, V>
+   {
+      final K key;
+      final int hash;
+      final V value;
+
+      Entry(K key, int hash, V value)
+      {
+         this.key = key;
+         this.hash = hash;
+         this.value = value;
+      }
+   }
+
+   private abstract class FasyCopyHashMapIterator<E> implements Iterator<E>
+   {
+      private int next = 0;
+      private int expectedCount = modCount;
+      private int current = -1;
+      private boolean hasNext;
+      Entry<K, V> table[] = FastCopyHashMap.this.table;
+
+      public boolean hasNext()
+      {
+         if (hasNext == true)
+            return true;
+
+         Entry<K, V> table[] = this.table;
+         for (int i = next; i < table.length; i++)
+         {
+            if (table[i] != null)
+            {
+               next = i;
+               return hasNext = true;
+            }
+         }
+
+         next = table.length;
+         return false;
+      }
+
+      protected Entry<K, V> nextEntry()
+      {
+         if (modCount != expectedCount)
+            throw new ConcurrentModificationException();
+
+         if (!hasNext && !hasNext())
+            throw new NoSuchElementException();
+
+         current = next++;
+         hasNext = false;
+
+         return table[current];
+      }
+
+      @SuppressWarnings("unchecked")
+      public void remove()
+      {
+         if (modCount != expectedCount)
+            throw new ConcurrentModificationException();
+
+         int current = this.current;
+         int delete = current;
+
+         if (current == -1)
+            throw new IllegalStateException();
+
+         // Invalidate current (prevents multiple remove)
+         this.current = -1;
+
+         // Start were we relocate
+         next = delete;
+
+         Entry<K, V>[] table = this.table;
+         if (table != FastCopyHashMap.this.table)
+         {
+            FastCopyHashMap.this.remove(table[delete].key);
+            table[delete] = null;
+            expectedCount = modCount;
+            return;
+         }
+
+
+         int length = table.length;
+         int i = delete;
+
+         table[delete] = null;
+         size--;
+
+         for (; ;)
+         {
+            i = nextIndex(i, length);
+            Entry<K, V> e = table[i];
+            if (e == null)
+               break;
+
+            int prefer = index(e.hash, length);
+            if ((i < prefer && (prefer <= delete || delete <= i))
+                  || (prefer <= delete && delete <= i))
+            {
+               // Snapshot the unseen portion of the table if we have
+               // to relocate an entry that was already seen by this iterator
+               if (i < current && current <= delete && table == FastCopyHashMap.this.table)
+               {
+                  int remaining = length - current;
+                  Entry<K, V>[] newTable = (Entry<K, V>[]) new Entry[remaining];
+                  System.arraycopy(table, current, newTable, 0, remaining);
+
+                  // Replace iterator's table.
+                  // Leave table local var pointing to the real table
+                  this.table = newTable;
+                  next = 0;
+               }
+
+               // Do the swap on the real table
+               table[delete] = e;
+               table[i] = null;
+               delete = i;
+            }
+         }
+      }
+   }
+
+
+   private class KeyIterator extends FasyCopyHashMapIterator<K>
+   {
+      public K next()
+      {
+         return unmaskNull(nextEntry().key);
+      }
+   }
+
+   private class ValueIterator extends FasyCopyHashMapIterator<V>
+   {
+      public V next()
+      {
+         return nextEntry().value;
+      }
+   }
+
+   private class EntryIterator extends FasyCopyHashMapIterator<Map.Entry<K, V>>
+   {
+      private class WriteThroughEntry extends SimpleEntry<K, V>
+      {
+         WriteThroughEntry(K key, V value)
+         {
+            super(key, value);
+         }
+
+         public V setValue(V value)
+         {
+            if (table != FastCopyHashMap.this.table)
+               FastCopyHashMap.this.put(getKey(), value);
+
+            return super.setValue(value);
+         }
+      }
+
+      public Map.Entry<K, V> next()
+      {
+         Entry<K, V> e = nextEntry();
+         return new WriteThroughEntry(unmaskNull(e.key), e.value);
+      }
+
+   }
+
+   private class KeySet extends AbstractSet<K>
+   {
+      public Iterator<K> iterator()
+      {
+         return new KeyIterator();
+      }
+
+      public void clear()
+      {
+         FastCopyHashMap.this.clear();
+      }
+
+      public boolean contains(Object o)
+      {
+         return containsKey(o);
+      }
+
+      public boolean remove(Object o)
+      {
+         int size = size();
+         FastCopyHashMap.this.remove(o);
+         return size() < size;
+      }
+
+      public int size()
+      {
+         return FastCopyHashMap.this.size();
+      }
+   }
+
+   private class Values extends AbstractCollection<V>
+   {
+      public Iterator<V> iterator()
+      {
+         return new ValueIterator();
+      }
+
+      public void clear()
+      {
+         FastCopyHashMap.this.clear();
+      }
+
+      public int size()
+      {
+         return FastCopyHashMap.this.size();
+      }
+   }
+
+   private class EntrySet extends AbstractSet<Map.Entry<K, V>>
+   {
+      public Iterator<Map.Entry<K, V>> iterator()
+      {
+         return new EntryIterator();
+      }
+
+      public boolean contains(Object o)
+      {
+         if (!(o instanceof Map.Entry))
+            return false;
+
+         Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
+         Object value = get(entry.getKey());
+         return eq(entry.getValue(), value);
+      }
+
+      public void clear()
+      {
+         FastCopyHashMap.this.clear();
+      }
+
+      public boolean isEmpty()
+      {
+         return FastCopyHashMap.this.isEmpty();
+      }
+
+      public int size()
+      {
+         return FastCopyHashMap.this.size();
+      }
+   }
+
+   protected static class SimpleEntry<K, V> implements Map.Entry<K, V>
+   {
+      private K key;
+      private V value;
+
+      SimpleEntry(K key, V value)
+      {
+         this.key = key;
+         this.value = value;
+      }
+
+      SimpleEntry(Map.Entry<K, V> entry)
+      {
+         this.key = entry.getKey();
+         this.value = entry.getValue();
+      }
+
+      public K getKey()
+      {
+         return key;
+      }
+
+      public V getValue()
+      {
+         return value;
+      }
+
+      public V setValue(V value)
+      {
+         V old = this.value;
+         this.value = value;
+         return old;
+      }
+
+      public boolean equals(Object o)
+      {
+         if (this == o)
+            return true;
+
+         if (!(o instanceof Map.Entry))
+            return false;
+         Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;
+         return eq(key, e.getKey()) && eq(value, e.getValue());
+      }
+
+      public int hashCode()
+      {
+         return (key == null ? 0 : hash(key)) ^
+                (value == null ? 0 : hash(value));
+      }
+
+      public String toString()
+      {
+         return getKey() + "=" + getValue();
+      }
+   }
+}

Modified: jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/LoggerNode.java
===================================================================
--- jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/LoggerNode.java	2010-02-18 19:03:35 UTC (rev 4044)
+++ jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/LoggerNode.java	2010-02-19 01:14:50 UTC (rev 4045)
@@ -28,8 +28,6 @@
 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import static org.jboss.logmanager.ConcurrentReferenceHashMap.ReferenceType.STRONG;
-import static org.jboss.logmanager.ConcurrentReferenceHashMap.ReferenceType.WEAK;
 
 /**
  * A node in the tree of logger names.  Maintains weak references to children and a strong reference to its parent.
@@ -62,7 +60,7 @@
     /**
      * The map of names to child nodes.  The child node references are weak.
      */
-    private final ConcurrentMap<String, LoggerNode> children = new ConcurrentReferenceHashMap<String, LoggerNode>(8, STRONG, WEAK);
+    private final ConcurrentMap<String, LoggerNode> children = new CopyOnWriteWeakMap<String, LoggerNode>();
 
     /**
      * Construct a new root instance.



More information about the jboss-svn-commits mailing list