[armedbear-cvs] r12968 - trunk/abcl/src/org/armedbear/lisp

Erik Huelsmann ehuelsmann at common-lisp.net
Sat Oct 9 22:59:02 UTC 2010


Author: ehuelsmann
Date: Sat Oct  9 18:59:01 2010
New Revision: 12968

Log:
Factor out getEntry from get() and put().

Also, declare the 'buckets' field volatile and decide
not to use read-locking in some cases.

Modified:
   trunk/abcl/src/org/armedbear/lisp/HashTable.java

Modified: trunk/abcl/src/org/armedbear/lisp/HashTable.java
==============================================================================
--- trunk/abcl/src/org/armedbear/lisp/HashTable.java	(original)
+++ trunk/abcl/src/org/armedbear/lisp/HashTable.java	Sat Oct  9 18:59:01 2010
@@ -33,6 +33,7 @@
  */
 package org.armedbear.lisp;
 
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 import static org.armedbear.lisp.Lisp.*;
 
@@ -45,7 +46,10 @@
     // of elements exceeds the threshold, the implementation calls rehash().
     protected int threshold;
     // Array containing the actual key-value mappings.
-    protected HashEntry[] buckets;
+    
+    @SuppressWarnings("VolatileArrayField")
+    protected volatile HashEntry[] buckets;
+    
     // The number of key-value pairs.
     protected int count;
     private int mask;
@@ -137,9 +141,11 @@
 
     @Override
     public LispObject getParts() {
+        // No need to take out a read lock, for the same reason as MAPHASH
+        HashEntry[] b = buckets;
         LispObject parts = NIL;
-        for (int i = 0; i < buckets.length; i++) {
-            HashEntry e = buckets[i];
+        for (int i = 0; i < b.length; i++) {
+            HashEntry e = b[i];
             while (e != null) {
                 parts = parts.push(new Cons("KEY [bucket " + i + "]", e.key));
                 parts = parts.push(new Cons("VALUE", e.value));
@@ -226,18 +232,23 @@
         return comparator.getTest();
     }
 
+    protected HashEntry getEntry(LispObject key) {
+        int index = comparator.hash(key) & mask;
+        HashEntry e = buckets[index];
+        while (e != null) {
+            if (comparator.keysEqual(key, e.key)) {
+                return e;
+            }
+            e = e.next;
+        }
+        return null;
+    }
+
     public LispObject get(LispObject key) {
         lock.readLock().lock();
         try {
-            int index = comparator.hash(key) & mask;
-            HashEntry e = buckets[index];
-            while (e != null) {
-                if (comparator.keysEqual(key, e.key)) {
-                    return e.value;
-                }
-                e = e.next;
-            }
-            return null;
+            HashEntry e = getEntry(key);
+            return (e == null) ? null : e.value;
         } finally {
             lock.readLock().unlock();
         }
@@ -246,20 +257,18 @@
     public void put(LispObject key, LispObject value) {
         lock.writeLock().lock();
         try {
-            int index = comparator.hash(key) & mask;
-            for (HashEntry e = buckets[index]; e != null; e = e.next) {
-                if (comparator.keysEqual(key, e.key)) {
-                    e.value = value;
-                    return;
+            HashEntry e = getEntry(key);
+            if (e == null) {
+                e.value = value;
+            } else {
+                // Not found. We need to add a new entry.
+                if (++count > threshold) {
+                    rehash();
                 }
+
+                int index = comparator.hash(key) & mask;
+                buckets[index] = new HashEntry(key, value, buckets[index]);
             }
-            // Not found. We need to add a new entry.
-            if (++count > threshold) {
-                rehash();
-                // Need a new hash value to suit the bigger table.
-                index = comparator.hash(key) & mask;
-            }
-            buckets[index] = new HashEntry(key, value, buckets[index]);
         } finally {
             lock.writeLock().unlock();
         }
@@ -315,9 +324,11 @@
 
     // Returns a list of (key . value) pairs.
     public LispObject ENTRIES() {
+        // No need to take out a read lock, for the same reason as MAPHASH
+        HashEntry[] b = buckets;
         LispObject list = NIL;
-        for (int i = buckets.length; i-- > 0;) {
-            HashEntry e = buckets[i];
+        for (int i = b.length; i-- > 0;) {
+            HashEntry e = b[i];
             while (e != null) {
                 list = new Cons(new Cons(e.key, e.value), list);
                 e = e.next;
@@ -327,8 +338,13 @@
     }
 
     public LispObject MAPHASH(LispObject function) {
-        for (int i = buckets.length; i-- > 0;) {
-            HashEntry e = buckets[i];
+        // Don't take out a read lock: it can't be upgraded to a write
+        // lock, which would block the scenario where put() is called to
+        // set the value of the current entry
+
+        HashEntry[] b = buckets;
+        for (int i = b.length; i-- > 0;) {
+            HashEntry e = b[i];
             while (e != null) {
                 function.execute(e.key, e.value);
                 e = e.next;




More information about the armedbear-cvs mailing list