Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: echopoint/util/collections/ConcurrentReaderHashMap.java


1   /* 
2    * This file is part of the Echo Point Project.  This project is a collection
3    * of Components that have extended the Echo Web Application Framework.
4    *
5    * EchoPoint is free software; you can redistribute it and/or modify
6    * it under the terms of the GNU Lesser General Public License as published by
7    * the Free Software Foundation; either version 2 of the License, or
8    * (at your option) any later version.
9    *
10   * EchoPoint is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU Lesser General Public License for more details.
14   *
15   * You should have received a copy of the GNU Lesser General Public License
16   * along with Echo Point; if not, write to the Free Software
17   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   */
19  
20  /*
21   * This file was made part of the EchoPoint framework on 13/02/04.  It is
22   * included under Doug Lea's explicit public domain licencing as stated
23   * "All classes are released to the public domain and may be used for any 
24   * purpose whatsoever without permission or acknowledgment. 
25   * Portions of the CopyOnWriteArrayList and ConcurrentReaderHashMap classes are 
26   * adapted from Sun JDK source code. These are copyright of 
27   * Sun Microsystems, Inc, and are used with their kind 
28   * permission as described in the their licence 
29   * 
30   * http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/sun-u.c.license.pdf
31   */
32   
33  /*
34    File: ConcurrentReaderHashMap
35  
36    Written by Doug Lea. Adapted and released, under explicit
37    permission, from JDK1.2 HashMap.java and Hashtable.java which
38    carries the following copyright:
39  
40       * Copyright 1997 by Sun Microsystems, Inc.,
41       * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
42       * All rights reserved.
43       *
44       * This software is the confidential and proprietary information
45       * of Sun Microsystems, Inc. ("Confidential Information").  You
46       * shall not disclose such Confidential Information and shall use
47       * it only in accordance with the terms of the license agreement
48       * you entered into with Sun.
49  
50    History:
51    Date       Who                What
52    28oct1999  dl               Created
53    14dec1999  dl               jmm snapshot
54    19apr2000  dl               use barrierLock
55    12jan2001  dl               public release
56    17nov2001  dl               Minor tunings
57    20may2002  dl               BarrierLock can now be serialized.
58    09dec2002  dl               Fix interference checks.
59  */
60  
61  package echopoint.util.collections;
62  
63  import java.io.IOException;
64  import java.io.Serializable;
65  import java.util.AbstractCollection;
66  import java.util.AbstractMap;
67  import java.util.AbstractSet;
68  import java.util.Collection;
69  import java.util.Enumeration;
70  import java.util.Iterator;
71  import java.util.Map;
72  import java.util.NoSuchElementException;
73  import java.util.Set;
74  
75  /**
76   * A version of Hashtable that supports mostly-concurrent reading, but
77   * exclusive writing.  Because reads are not limited to periods
78   * without writes, a concurrent reader policy is weaker than a classic
79   * reader/writer policy, but is generally faster and allows more
80   * concurrency. This class is a good choice especially for tables that
81   * are mainly created by one thread during the start-up phase of a
82   * program, and from then on, are mainly read (with perhaps occasional
83   * additions or removals) in many threads.  If you also need concurrency
84   * among writes, consider instead using ConcurrentHashMap.
85   * <p>
86   *
87   * Successful retrievals using get(key) and containsKey(key) usually
88   * run without locking. Unsuccessful ones (i.e., when the key is not
89   * present) do involve brief synchronization (locking).  Also, the
90   * size and isEmpty methods are always synchronized.
91   *
92   * <p> Because retrieval operations can ordinarily overlap with
93   * writing operations (i.e., put, remove, and their derivatives),
94   * retrievals can only be guaranteed to return the results of the most
95   * recently <em>completed</em> operations holding upon their
96   * onset. Retrieval operations may or may not return results
97   * reflecting in-progress writing operations.  However, the retrieval
98   * operations do always return consistent results -- either those
99   * holding before any single modification or after it, but never a
100  * nonsense result.  For aggregate operations such as putAll and
101  * clear, concurrent reads may reflect insertion or removal of only
102  * some entries. In those rare contexts in which you use a hash table
103  * to synchronize operations across threads (for example, to prevent
104  * reads until after clears), you should either encase operations
105  * in synchronized blocks, or instead use java.util.Hashtable.
106  *
107  * <p>
108  *
109  * This class also supports optional guaranteed
110  * exclusive reads, simply by surrounding a call within a synchronized
111  * block, as in <br> 
112  * <code>ConcurrentReaderHashMap t; ... Object v; <br>
113  * synchronized(t) { v = t.get(k); } </code> <br>
114  *
115  * But this is not usually necessary in practice. For
116  * example, it is generally inefficient to write:
117  *
118  * <blockquote><pre>
119  *   ConcurrentReaderHashMap t; ...            // Inefficient version
120  *   Object key; ...
121  *   Object value; ...
122  *   synchronized(t) { 
123  *     if (!t.containsKey(key))
124  *       t.put(key, value);
125  *       // other code if not previously present
126  *     }
127  *     else {
128  *       // other code if it was previously present
129  *     }
130  *   }
131  *</pre></blockquote>
132  * Instead, if the values are intended to be the same in each case, just take advantage of the fact that put returns
133  * null if the key was not previously present:
134  * <blockquote><pre>
135  *   ConcurrentReaderHashMap t; ...                // Use this instead
136  *   Object key; ...
137  *   Object value; ...
138  *   Object oldValue = t.put(key, value);
139  *   if (oldValue == null) {
140  *     // other code if not previously present
141  *   }
142  *   else {
143  *     // other code if it was previously present
144  *   }
145  *</pre></blockquote>
146  * <p>
147  *
148  * Iterators and Enumerations (i.e., those returned by
149  * keySet().iterator(), entrySet().iterator(), values().iterator(),
150  * keys(), and elements()) return elements reflecting the state of the
151  * hash table at some point at or since the creation of the
152  * iterator/enumeration.  They will return at most one instance of
153  * each element (via next()/nextElement()), but might or might not
154  * reflect puts and removes that have been processed since they were
155  * created.  They do <em>not</em> throw ConcurrentModificationException.
156  * However, these iterators are designed to be used by only one
157  * thread at a time. Sharing an iterator across multiple threads may
158  * lead to unpredictable results if the table is being concurrently
159  * modified.  Again, you can ensure interference-free iteration by
160  * enclosing the iteration in a synchronized block.  <p>
161  *
162  * This class may be used as a direct replacement for any use of
163  * java.util.Hashtable that does not depend on readers being blocked
164  * during updates. Like Hashtable but unlike java.util.HashMap,
165  * this class does NOT allow <tt>null</tt> to be used as a key or
166  * value.  This class is also typically faster than ConcurrentHashMap
167  * when there is usually only one thread updating the table, but 
168  * possibly many retrieving values from it.
169  * <p>
170  *
171  * Implementation note: A slightly faster implementation of
172  * this class will be possible once planned Java Memory Model
173  * revisions are in place.
174  *
175  * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
176 
177  **/
178 
179 public class ConcurrentReaderHashMap extends AbstractMap implements Map, Cloneable, Serializable {
180 
181   /*
182     The basic strategy is an optimistic-style scheme based on
183     the guarantee that the hash table and its lists are always
184     kept in a consistent enough state to be read without locking:
185   
186     * Read operations first proceed without locking, by traversing the
187        apparently correct list of the apparently correct bin. If an
188        entry is found, but not invalidated (value field null), it is
189        returned. If not found, operations must recheck (after a memory
190        barrier) to make sure they are using both the right list and
191        the right table (which can change under resizes). If
192        invalidated, reads must acquire main update lock to wait out
193        the update, and then re-traverse.
194   
195     * All list additions are at the front of each bin, making it easy
196        to check changes, and also fast to traverse.  Entry next
197        pointers are never assigned. Remove() builds new nodes when
198        necessary to preserve this.
199   
200     * Remove() (also clear()) invalidates removed nodes to alert read
201        operations that they must wait out the full modifications.
202   
203   */
204 
205   /** A Serializable class for barrier lock **/
206   protected static class BarrierLock implements java.io.Serializable {
207   }
208 
209   /**
210    * Lock used only for its memory effects.
211    **/
212   protected final BarrierLock barrierLock = new BarrierLock();
213 
214   /**
215    * field written to only to guarantee lock ordering.
216    **/
217 
218   protected transient Object lastWrite;
219 
220   /**
221    * Force a memory synchronization that will cause
222    * all readers to see table. Call only when already
223    * holding main synch lock.
224    **/
225   protected final void recordModification(Object x) {
226     synchronized (barrierLock) {
227       lastWrite = x;
228     }
229   }
230 
231   /**
232    * Get ref to table; the reference and the cells it
233    * accesses will be at least as fresh as from last
234    * use of barrierLock
235    **/
236   protected final Entry[] getTableForReading() {
237     synchronized (barrierLock) {
238       return table;
239     }
240   }
241 
242   /**
243    * The default initial number of table slots for this table (32).
244    * Used when not otherwise specified in constructor.
245    **/
246   public static int DEFAULT_INITIAL_CAPACITY = 32;
247 
248   /**
249    * The minimum capacity, used if a lower value is implicitly specified
250    * by either of the constructors with arguments.  
251    * MUST be a power of two.
252    */
253   private static final int MINIMUM_CAPACITY = 4;
254 
255   /**
256    * The maximum capacity, used if a higher value is implicitly specified
257    * by either of the constructors with arguments.
258    * MUST be a power of two <= 1<<30.
259    */
260   private static final int MAXIMUM_CAPACITY = 1 << 30;
261 
262   /**
263    * The default load factor for this table (1.0).
264    * Used when not otherwise specified in constructor.
265    **/
266 
267   public static final float DEFAULT_LOAD_FACTOR = 0.75f;
268 
269   /**
270    * The hash table data.
271    */
272   protected transient Entry[] table;
273 
274   /**
275    * The total number of mappings in the hash table.
276    */
277   protected transient int count;
278 
279   /**
280    * The table is rehashed when its size exceeds this threshold.  (The
281    * value of this field is always (int)(capacity * loadFactor).)
282    *
283    * @serial
284    */
285   protected int threshold;
286 
287   /**
288    * The load factor for the hash table.
289    *
290    * @serial
291    */
292   protected float loadFactor;
293 
294   /**
295    * Returns the appropriate capacity (power of two) for the specified 
296    * initial capacity argument.
297    */
298   private int p2capacity(int initialCapacity) {
299     int cap = initialCapacity;
300 
301     // Compute the appropriate capacity
302     int result;
303     if (cap > MAXIMUM_CAPACITY || cap < 0) {
304       result = MAXIMUM_CAPACITY;
305     } else {
306       result = MINIMUM_CAPACITY;
307       while (result < cap)
308         result <<= 1;
309     }
310     return result;
311   }
312 
313   /**
314    * Return hash code for Object x. Since we are using power-of-two
315    * tables, it is worth the effort to improve hashcode via
316    * the same multiplicative scheme as used in IdentityHashMap.
317    */
318   private static int hash(Object x) {
319     int h = x.hashCode();
320     // Multiply by 127 (quickly, via shifts), and mix in some high
321     // bits to help guard against bunching of codes that are
322     // consecutive or equally spaced.
323     return ((h << 7) - h + (h >>> 9) + (h >>> 17));
324   }
325 
326   /** 
327    * Check for equality of non-null references x and y. 
328    **/
329   protected boolean eq(Object x, Object y) {
330     return x == y || x.equals(y);
331   }
332 
333   /**
334    * Constructs a new, empty map with the specified initial 
335    * capacity and the specified load factor. 
336    *
337    * @param initialCapacity the initial capacity
338    *  The actual initial capacity is rounded to the nearest power of two.
339    * @param loadFactor  the load factor of the ConcurrentReaderHashMap
340    * @throws IllegalArgumentException  if the initial maximum number 
341    *               of elements is less
342    *               than zero, or if the load factor is nonpositive.
343    */
344 
345   public ConcurrentReaderHashMap(int initialCapacity, float loadFactor) {
346     if (loadFactor <= 0)
347       throw new IllegalArgumentException("Illegal Load factor: " + loadFactor);
348     this.loadFactor = loadFactor;
349 
350     int cap = p2capacity(initialCapacity);
351 
352     table = new Entry[cap];
353     threshold = (int) (cap * loadFactor);
354   }
355 
356   /**
357    * Constructs a new, empty map with the specified initial 
358    * capacity and default load factor.
359    *
360    * @param   initialCapacity   the initial capacity of the 
361    *                            ConcurrentReaderHashMap.
362    * @throws    IllegalArgumentException if the initial maximum number 
363    *              of elements is less
364    *              than zero.
365    */
366 
367   public ConcurrentReaderHashMap(int initialCapacity) {
368     this(initialCapacity, DEFAULT_LOAD_FACTOR);
369   }
370 
371   /**
372    * Constructs a new, empty map with a default initial capacity
373    * and load factor.
374    */
375 
376   public ConcurrentReaderHashMap() {
377     this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
378   }
379 
380   /**
381    * Constructs a new map with the same mappings as the given map.  The
382    * map is created with a capacity of twice the number of mappings in
383    * the given map or 16 (whichever is greater), and a default load factor.
384    */
385 
386   public ConcurrentReaderHashMap(Map t) {
387     this(Math.max((int) (t.size() / DEFAULT_LOAD_FACTOR) + 1, 16), DEFAULT_LOAD_FACTOR);
388     putAll(t);
389   }
390 
391   /**
392    * Returns the number of key-value mappings in this map.
393    *
394    * @return the number of key-value mappings in this map.
395    */
396 
397   public synchronized int size() {
398     return count;
399   }
400 
401   /**
402    * Returns <tt>true</tt> if this map contains no key-value mappings.
403    *
404    * @return <tt>true</tt> if this map contains no key-value mappings.
405    */
406 
407   public synchronized boolean isEmpty() {
408     return count == 0;
409   }
410 
411   /**
412    * Returns the value to which the specified key is mapped in this table.
413    *
414    * @param   key   a key in the table.
415    * @return  the value to which the key is mapped in this table;
416    *          <code>null</code> if the key is not mapped to any value in
417    *          this table.
418    * @exception  NullPointerException  if the key is
419    *               <code>null</code>.
420    * @see     #put(Object, Object)
421    */
422 
423   public Object get(Object key) {
424 
425     // throw null pointer exception if key null
426     int hash = hash(key);
427 
428     /* 
429        Start off at the apparently correct bin.  If entry is found, we
430        need to check after a barrier anyway.  If not found, we need a
431        barrier to check if we are actually in right bin. So either
432        way, we encounter only one barrier unless we need to retry.
433        And we only need to fully synchronize if there have been
434        concurrent modifications.
435     */
436 
437     Entry[] tab = table;
438     int index = hash & (tab.length - 1);
439     Entry first = tab[index];
440     Entry e = first;
441 
442     for (;;) {
443       if (e == null) {
444 
445         // If key apparently not there, check to
446         // make sure this was a valid read
447 
448         Entry[] reread = getTableForReading();
449         if (tab == reread && first == tab[index])
450           return null;
451         else {
452           // Wrong list -- must restart traversal at new first
453           tab = reread;
454           e = first = tab[index = hash & (tab.length - 1)];
455         }
456 
457       } else if (e.hash == hash && eq(key, e.key)) {
458         Object value = e.value;
459         if (value != null)
460           return value;
461 
462         // Entry was invalidated during deletion. But it could
463         // have been re-inserted, so we must retraverse.
464         // To avoid useless contention, get lock to wait out modifications
465         // before retraversing.
466 
467         synchronized (this) {
468           tab = table;
469         }
470         e = first = tab[index = hash & (tab.length - 1)];
471 
472       } else
473         e = e.next;
474     }
475   }
476 
477   /**
478    * Tests if the specified object is a key in this table.
479    * 
480    * @param   key   possible key.
481    * @return  <code>true</code> if and only if the specified object 
482    *          is a key in this table, as determined by the 
483    *          <tt>equals</tt> method; <code>false</code> otherwise.
484    * @exception  NullPointerException  if the key is
485    *               <code>null</code>.
486    * @see     #contains(Object)
487    */
488 
489   public boolean containsKey(Object key) {
490     return get(key) != null;
491   }
492 
493   /**
494    * Maps the specified <code>key</code> to the specified 
495    * <code>value</code> in this table. Neither the key nor the 
496    * value can be <code>null</code>. <p>
497    *
498    * The value can be retrieved by calling the <code>get</code> method 
499    * with a key that is equal to the original key. 
500    *
501    * @param      key     the table key.
502    * @param      value   the value.
503    * @return     the previous value of the specified key in this table,
504    *             or <code>null</code> if it did not have one.
505    * @exception  NullPointerException  if the key or value is
506    *               <code>null</code>.
507    * @see     Object#equals(Object)
508    * @see     #get(Object)
509    */
510 
511   public Object put(Object key, Object value) {
512     if (value == null)
513       throw new NullPointerException();
514 
515     int hash = hash(key);
516     Entry[] tab = table;
517     int index = hash & (tab.length - 1);
518     Entry first = tab[index];
519     Entry e;
520 
521     for (e = first; e != null; e = e.next)
522       if (e.hash == hash && eq(key, e.key))
523         break;
524 
525     synchronized (this) {
526       if (tab == table) {
527         if (e == null) {
528           //  make sure we are adding to correct list
529           if (first == tab[index]) {
530             //  Add to front of list
531             Entry newEntry = new Entry(hash, key, value, first);
532             tab[index] = newEntry;
533             if (++count >= threshold)
534               rehash();
535             else
536               recordModification(newEntry);
537             return null;
538           }
539         } else {
540           Object oldValue = e.value;
541           if (first == tab[index] && oldValue != null) {
542             e.value = value;
543             return oldValue;
544           }
545         }
546       }
547 
548       // retry if wrong list or lost race against concurrent remove
549       return sput(key, value, hash);
550     }
551   }
552 
553   /**
554    * Continuation of put(), called only when synch lock is
555    * held and interference has been detected.
556    **/
557   protected Object sput(Object key, Object value, int hash) {
558 
559     Entry[] tab = table;
560     int index = hash & (tab.length - 1);
561     Entry first = tab[index];
562     Entry e = first;
563 
564     for (;;) {
565       if (e == null) {
566         Entry newEntry = new Entry(hash, key, value, first);
567         tab[index] = newEntry;
568         if (++count >= threshold)
569           rehash();
570         else
571           recordModification(newEntry);
572         return null;
573       } else if (e.hash == hash && eq(key, e.key)) {
574         Object oldValue = e.value;
575         e.value = value;
576         return oldValue;
577       } else
578         e = e.next;
579     }
580   }
581 
582   /**
583    * Rehashes the contents of this map into a new table
584    * with a larger capacity. This method is called automatically when the
585    * number of keys in this map exceeds its capacity and load factor.
586    */
587   protected void rehash() {
588     Entry[] oldTable = table;
589     int oldCapacity = oldTable.length;
590     if (oldCapacity >= MAXIMUM_CAPACITY) {
591       threshold = Integer.MAX_VALUE; // avoid retriggering
592       return;
593     }
594 
595     int newCapacity = oldCapacity << 1;
596     int mask = newCapacity - 1;
597     threshold = (int) (newCapacity * loadFactor);
598 
599     Entry[] newTable = new Entry[newCapacity];
600     /*
601      * Reclassify nodes in each list to new Map.  Because we are
602      * using power-of-two expansion, the elements from each bin
603      * must either stay at same index, or move to
604      * oldCapacity+index. We also eliminate unnecessary node
605      * creation by catching cases where old nodes can be reused
606      * because their next fields won't change. Statistically, at
607      * the default threshhold, only about one-sixth of them need
608      * cloning. (The nodes they replace will be garbage
609      * collectable as soon as they are no longer referenced by any
610      * reader thread that may be in the midst of traversing table
611      * right now.)
612      */
613 
614     for (int i = 0; i < oldCapacity; i++) {
615       // We need to guarantee that any existing reads of old Map can
616       //  proceed. So we cannot yet null out each bin.  
617       Entry e = oldTable[i];
618 
619       if (e != null) {
620         int idx = e.hash & mask;
621         Entry next = e.next;
622 
623         //  Single node on list
624         if (next == null)
625           newTable[idx] = e;
626 
627         else {
628           // Reuse trailing consecutive sequence of all same bit
629           Entry lastRun = e;
630           int lastIdx = idx;
631           for (Entry last = next; last != null; last = last.next) {
632             int k = last.hash & mask;
633             if (k != lastIdx) {
634               lastIdx = k;
635               lastRun = last;
636             }
637           }
638           newTable[lastIdx] = lastRun;
639 
640           // Clone all remaining nodes
641           for (Entry p = e; p != lastRun; p = p.next) {
642             int k = p.hash & mask;
643             newTable[k] = new Entry(p.hash, p.key, p.value, newTable[k]);
644           }
645         }
646       }
647     }
648 
649     table = newTable;
650     recordModification(newTable);
651   }
652 
653   /**
654    * Removes the key (and its corresponding value) from this 
655    * table. This method does nothing if the key is not in the table.
656    *
657    * @param   key   the key that needs to be removed.
658    * @return  the value to which the key had been mapped in this table,
659    *          or <code>null</code> if the key did not have a mapping.
660    * @exception  NullPointerException  if the key is
661    *               <code>null</code>.
662    */
663 
664   public Object remove(Object key) {
665     /*
666       Find the entry, then 
667         1. Set value field to null, to force get() to retry
668         2. Rebuild the list without this entry.
669            All entries following removed node can stay in list, but
670            all preceeding ones need to be cloned.  Traversals rely
671            on this strategy to ensure that elements will not be
672           repeated during iteration.
673     */
674 
675     int hash = hash(key);
676     Entry[] tab = table;
677     int index = hash & (tab.length - 1);
678     Entry first = tab[index];
679     Entry e = first;
680 
681     for (e = first; e != null; e = e.next)
682       if (e.hash == hash && eq(key, e.key))
683         break;
684 
685     synchronized (this) {
686       if (tab == table) {
687         if (e == null) {
688           if (first == tab[index])
689             return null;
690         } else {
691           Object oldValue = e.value;
692           if (first == tab[index] && oldValue != null) {
693             e.value = null;
694             count--;
695 
696             Entry head = e.next;
697             for (Entry p = first; p != e; p = p.next)
698               head = new Entry(p.hash, p.key, p.value, head);
699 
700             tab[index] = head;
701             recordModification(head);
702             return oldValue;
703           }
704         }
705       }
706 
707       // Wrong list or interference
708       return sremove(key, hash);
709     }
710   }
711 
712   /**
713    * Continuation of remove(), called only when synch lock is
714    * held and interference has been detected.
715    **/
716 
717   protected Object sremove(Object key, int hash) {
718     Entry[] tab = table;
719     int index = hash & (tab.length - 1);
720     Entry first = tab[index];
721 
722     for (Entry e = first; e != null; e = e.next) {
723       if (e.hash == hash && eq(key, e.key)) {
724         Object oldValue = e.value;
725         e.value = null;
726         count--;
727         Entry head = e.next;
728         for (Entry p = first; p != e; p = p.next)
729           head = new Entry(p.hash, p.key, p.value, head);
730 
731         tab[index] = head;
732         recordModification(head);
733         return oldValue;
734       }
735     }
736     return null;
737   }
738 
739   /**
740    * Returns <tt>true</tt> if this map maps one or more keys to the
741    * specified value. Note: This method requires a full internal
742    * traversal of the hash table, and so is much slower than
743    * method <tt>containsKey</tt>.
744    *
745    * @param value value whose presence in this map is to be tested.
746    * @return <tt>true</tt> if this map maps one or more keys to the
747    * specified value.  
748    * @exception  NullPointerException  if the value is <code>null</code>.
749    */
750 
751   public boolean containsValue(Object value) {
752     if (value == null)
753       throw new NullPointerException();
754 
755     Entry tab[] = getTableForReading();
756 
757     for (int i = 0; i < tab.length; ++i) {
758       for (Entry e = tab[i]; e != null; e = e.next)
759         if (value.equals(e.value))
760           return true;
761     }
762 
763     return false;
764   }
765 
766   /**
767    * Tests if some key maps into the specified value in this table.
768    * This operation is more expensive than the <code>containsKey</code>
769    * method.<p>
770    *
771    * Note that this method is identical in functionality to containsValue,
772    * (which is part of the Map interface in the collections framework).
773    * 
774    * @param      value   a value to search for.
775    * @return     <code>true</code> if and only if some key maps to the
776    *             <code>value</code> argument in this table as 
777    *             determined by the <tt>equals</tt> method;
778    *             <code>false</code> otherwise.
779    * @exception  NullPointerException  if the value is <code>null</code>.
780    * @see        #containsKey(Object)
781    * @see        #containsValue(Object)
782    * @see     Map
783    */
784 
785   public boolean contains(Object value) {
786     return containsValue(value);
787   }
788 
789   /**
790    * Copies all of the mappings from the specified map to this one.
791    * 
792    * These mappings replace any mappings that this map had for any of the
793    * keys currently in the specified Map.
794    *
795    * @param t Mappings to be stored in this map.
796    */
797 
798   public synchronized void putAll(Map t) {
799     int n = t.size();
800     if (n == 0)
801       return;
802 
803     // Expand enough to hold at least n elements without resizing.
804     // We can only resize table by factor of two at a time.
805     // It is faster to rehash with fewer elements, so do it now.
806     while (n >= threshold)
807       rehash();
808 
809     for (Iterator it = t.entrySet().iterator(); it.hasNext();) {
810       Map.Entry entry = (Map.Entry) it.next();
811       Object key = entry.getKey();
812       Object value = entry.getValue();
813       put(key, value);
814     }
815   }
816 
817   /**
818    * Removes all mappings from this map.
819    */
820   public synchronized void clear() {
821     Entry tab[] = table;
822     for (int i = 0; i < tab.length; ++i) {
823 
824       // must invalidate all to force concurrent get's to wait and then retry
825       for (Entry e = tab[i]; e != null; e = e.next)
826         e.value = null;
827 
828       tab[i] = null;
829     }
830     count = 0;
831     recordModification(tab);
832   }
833 
834   /**
835    * Returns a shallow copy of this 
836    * <tt>ConcurrentReaderHashMap</tt> instance: the keys and
837    * values themselves are not cloned.
838    *
839    * @return a shallow copy of this map.
840    */
841 
842   public synchronized Object clone() {
843     try {
844       ConcurrentReaderHashMap t = (ConcurrentReaderHashMap) super.clone();
845 
846       t.keySet = null;
847       t.entrySet = null;
848       t.values = null;
849 
850       Entry[] tab = table;
851       t.table = new Entry[tab.length];
852       Entry[] ttab = t.table;
853 
854       for (int i = 0; i < tab.length; ++i) {
855         Entry first = null;
856         for (Entry e = tab[i]; e != null; e = e.next)
857           first = new Entry(e.hash, e.key, e.value, first);
858         ttab[i] = first;
859       }
860 
861       return t;
862     } catch (CloneNotSupportedException e) {
863       // this shouldn't happen, since we are Cloneable
864       throw new InternalError();
865     }
866   }
867 
868   // Views
869 
870   protected transient Set keySet = null;
871   protected transient Set entrySet = null;
872   protected transient Collection values = null;
873 
874   /**
875    * Returns a set view of the keys contained in this map.  The set is
876    * backed by the map, so changes to the map are reflected in the set, and
877    * vice-versa.  The set supports element removal, which removes the
878    * corresponding mapping from this map, via the <tt>Iterator.remove</tt>,
879    * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and
880    * <tt>clear</tt> operations.  It does not support the <tt>add</tt> or
881    * <tt>addAll</tt> operations.
882    *
883    * @return a set view of the keys contained in this map.
884    */
885 
886   public Set keySet() {
887     Set ks = keySet;
888     return (ks != null) ? ks : (keySet = new KeySet());
889   }
890 
891   private class KeySet extends AbstractSet {
892     public Iterator iterator() {
893       return new KeyIterator();
894     }
895     public int size() {
896       return ConcurrentReaderHashMap.this.size();
897     }
898     public boolean contains(Object o) {
899       return ConcurrentReaderHashMap.this.containsKey(o);
900     }
901     public boolean remove(Object o) {
902       return ConcurrentReaderHashMap.this.remove(o) != null;
903     }
904     public void clear() {
905       ConcurrentReaderHashMap.this.clear();
906     }
907   }
908 
909   /**
910    * Returns a collection view of the values contained in this map.  The
911    * collection is backed by the map, so changes to the map are reflected in
912    * the collection, and vice-versa.  The collection supports element
913    * removal, which removes the corresponding mapping from this map, via the
914    * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
915    * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
916    * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
917    *
918    * @return a collection view of the values contained in this map.
919    */
920 
921   public Collection values() {
922     Collection vs = values;
923     return (vs != null) ? vs : (values = new Values());
924   }
925 
926   private class Values extends AbstractCollection {
927     public Iterator iterator() {
928       return new ValueIterator();
929     }
930     public int size() {
931       return ConcurrentReaderHashMap.this.size();
932     }
933     public boolean contains(Object o) {
934       return ConcurrentReaderHashMap.this.containsValue(o);
935     }
936     public void clear() {
937       ConcurrentReaderHashMap.this.clear();
938     }
939   }
940 
941   /**
942    * Returns a collection view of the mappings contained in this map.  Each
943    * element in the returned collection is a <tt>Map.Entry</tt>.  The
944    * collection is backed by the map, so changes to the map are reflected in
945    * the collection, and vice-versa.  The collection supports element
946    * removal, which removes the corresponding mapping from the map, via the
947    * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
948    * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
949    * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
950    *
951    * @return a collection view of the mappings contained in this map.
952    */
953 
954   public Set entrySet() {
955     Set es = entrySet;
956     return (es != null) ? es : (entrySet = new EntrySet());
957   }
958 
959   private class EntrySet extends AbstractSet {
960     public Iterator iterator() {
961       return new HashIterator();
962     }
963     public boolean contains(Object o) {
964       if (!(o instanceof Map.Entry))
965         return false;
966       Map.Entry entry = (Map.Entry) o;
967       Object v = ConcurrentReaderHashMap.this.get(entry.getKey());
968       return v != null && v.equals(entry.getValue());
969     }
970     public boolean remove(Object o) {
971       if (!(o instanceof Map.Entry))
972         return false;
973       return ConcurrentReaderHashMap.this.findAndRemoveEntry((Map.Entry) o);
974     }
975     public int size() {
976       return ConcurrentReaderHashMap.this.size();
977     }
978     public void clear() {
979       ConcurrentReaderHashMap.this.clear();
980     }
981   }
982 
983   /**
984    * Helper method for entrySet.remove
985    **/
986   protected synchronized boolean findAndRemoveEntry(Map.Entry entry) {
987     Object key = entry.getKey();
988     Object v = get(key);
989     if (v != null && v.equals(entry.getValue())) {
990       remove(key);
991       return true;
992     } else
993       return false;
994   }
995 
996   /**
997    * Returns an enumeration of the keys in this table.
998    *
999    * @return  an enumeration of the keys in this table.
1000   * @see     Enumeration
1001   * @see     #elements()
1002   * @see  #keySet()
1003   * @see  Map
1004   */
1005  public Enumeration keys() {
1006    return new KeyIterator();
1007  }
1008
1009  /**
1010   * Returns an enumeration of the values in this table.
1011   * Use the Enumeration methods on the returned object to fetch the elements
1012   * sequentially.
1013   *
1014   * @return  an enumeration of the values in this table.
1015   * @see     java.util.Enumeration
1016   * @see     #keys()
1017   * @see  #values()
1018   * @see  Map
1019   */
1020
1021  public Enumeration elements() {
1022    return new ValueIterator();
1023  }
1024
1025  /**
1026   * ConcurrentReaderHashMap collision list entry.
1027   */
1028
1029  protected static class Entry implements Map.Entry {
1030
1031    /* 
1032       The use of volatile for value field ensures that
1033       we can detect status changes without synchronization.
1034       The other fields are never changed, and are
1035       marked as final. 
1036    */
1037
1038    protected final int hash;
1039    protected final Object key;
1040    protected final Entry next;
1041    protected volatile Object value;
1042
1043    Entry(int hash, Object key, Object value, Entry next) {
1044      this.hash = hash;
1045      this.key = key;
1046      this.next = next;
1047      this.value = value;
1048    }
1049
1050    // Map.Entry Ops 
1051
1052    public Object getKey() {
1053      return key;
1054    }
1055
1056    /**
1057     * Get the value.  Note: In an entrySet or entrySet.iterator,
1058     * unless the set or iterator is used under synchronization of the
1059     * table as a whole (or you can otherwise guarantee lack of
1060     * concurrent modification), <tt>getValue</tt> <em>might</em>
1061     * return null, reflecting the fact that the entry has been
1062     * concurrently removed. However, there are no assurances that
1063     * concurrent removals will be reflected using this method.
1064     * 
1065     * @return     the current value, or null if the entry has been 
1066     * detectably removed.
1067     **/
1068    public Object getValue() {
1069      return value;
1070    }
1071
1072    /**
1073     * Set the value of this entry.  Note: In an entrySet or
1074     * entrySet.iterator), unless the set or iterator is used under
1075     * synchronization of the table as a whole (or you can otherwise
1076     * guarantee lack of concurrent modification), <tt>setValue</tt>
1077     * is not strictly guaranteed to actually replace the value field
1078     * obtained via the <tt>get</tt> operation of the underlying hash
1079     * table in multithreaded applications.  If iterator-wide
1080     * synchronization is not used, and any other concurrent
1081     * <tt>put</tt> or <tt>remove</tt> operations occur, sometimes
1082     * even to <em>other</em> entries, then this change is not
1083     * guaranteed to be reflected in the hash table. (It might, or it
1084     * might not. There are no assurances either way.)
1085     *
1086     * @param      value   the new value.
1087     * @return     the previous value, or null if entry has been detectably
1088     * removed.
1089     * @exception  NullPointerException  if the value is <code>null</code>.
1090     * 
1091     **/
1092
1093    public Object setValue(Object value) {
1094      if (value == null)
1095        throw new NullPointerException();
1096      Object oldValue = this.value;
1097      this.value = value;
1098      return oldValue;
1099    }
1100
1101    public boolean equals(Object o) {
1102      if (!(o instanceof Map.Entry))
1103        return false;
1104      Map.Entry e = (Map.Entry) o;
1105      return (key.equals(e.getKey()) && value.equals(e.getValue()));
1106    }
1107
1108    public int hashCode() {
1109      return key.hashCode() ^ value.hashCode();
1110    }
1111
1112    public String toString() {
1113      return key + "=" + value;
1114    }
1115
1116  }
1117
1118  protected class HashIterator implements Iterator, Enumeration {
1119    protected final Entry[] tab; // snapshot of table
1120    protected int index; // current slot 
1121    protected Entry entry = null; // current node of slot
1122    protected Object currentKey; // key for current node
1123    protected Object currentValue; // value for current node
1124    protected Entry lastReturned = null; // last node returned by next
1125
1126    protected HashIterator() {
1127      tab = ConcurrentReaderHashMap.this.getTableForReading();
1128      index = tab.length - 1;
1129    }
1130
1131    public boolean hasMoreElements() {
1132      return hasNext();
1133    }
1134    public Object nextElement() {
1135      return next();
1136    }
1137
1138    public boolean hasNext() {
1139
1140      /*
1141        currentkey and currentValue are set here to ensure that next()
1142        returns normally if hasNext() returns true. This avoids
1143        surprises especially when final element is removed during
1144        traversal -- instead, we just ignore the removal during
1145        current traversal.  
1146      */
1147
1148      for (;;) {
1149        if (entry != null) {
1150          Object v = entry.value;
1151          if (v != null) {
1152            currentKey = entry.key;
1153            currentValue = v;
1154            return true;
1155          } else
1156            entry = entry.next;
1157        }
1158
1159        while (entry == null && index >= 0)
1160          entry = tab[index--];
1161
1162        if (entry == null) {
1163          currentKey = currentValue = null;
1164          return false;
1165        }
1166      }
1167    }
1168
1169    protected Object returnValueOfNext() {
1170      return entry;
1171    }
1172
1173    public Object next() {
1174      if (currentKey == null && !hasNext())
1175        throw new NoSuchElementException();
1176
1177      Object result = returnValueOfNext();
1178      lastReturned = entry;
1179      currentKey = currentValue = null;
1180      entry = entry.next;
1181      return result;
1182    }
1183
1184    public void remove() {
1185      if (lastReturned == null)
1186        throw new IllegalStateException();
1187      ConcurrentReaderHashMap.this.remove(lastReturned.key);
1188      lastReturned = null;
1189    }
1190
1191  }
1192
1193  protected class KeyIterator extends HashIterator {
1194    protected Object returnValueOfNext() {
1195      return currentKey;
1196    }
1197  }
1198
1199  protected class ValueIterator extends HashIterator {
1200    protected Object returnValueOfNext() {
1201      return currentValue;
1202    }
1203  }
1204
1205  /**
1206   * Save the state of the <tt>ConcurrentReaderHashMap</tt> 
1207   * instance to a stream (i.e.,
1208   * serialize it).
1209   *
1210   * @serialData The <i>capacity</i> of the 
1211   * ConcurrentReaderHashMap (the length of the
1212   * bucket array) is emitted (int), followed  by the
1213   * <i>size</i> of the ConcurrentReaderHashMap (the number of key-value
1214   * mappings), followed by the key (Object) and value (Object)
1215   * for each key-value mapping represented by the ConcurrentReaderHashMap
1216   * The key-value mappings are emitted in no particular order.
1217   */
1218
1219  private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException {
1220    // Write out the threshold, loadfactor, and any hidden stuff
1221    s.defaultWriteObject();
1222
1223    // Write out number of buckets
1224    s.writeInt(table.length);
1225
1226    // Write out size (number of Mappings)
1227    s.writeInt(count);
1228
1229    // Write out keys and values (alternating)
1230    for (int index = table.length - 1; index >= 0; index--) {
1231      Entry entry = table[index];
1232
1233      while (entry != null) {
1234        s.writeObject(entry.key);
1235        s.writeObject(entry.value);
1236        entry = entry.next;
1237      }
1238    }
1239  }
1240
1241  /**
1242   * Reconstitute the <tt>ConcurrentReaderHashMap</tt> 
1243   * instance from a stream (i.e.,
1244   * deserialize it).
1245   */
1246  private synchronized void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {
1247    // Read in the threshold, loadfactor, and any hidden stuff
1248    s.defaultReadObject();
1249
1250    // Read in number of buckets and allocate the bucket array;
1251    int numBuckets = s.readInt();
1252    table = new Entry[numBuckets];
1253
1254    // Read in size (number of Mappings)
1255    int size = s.readInt();
1256
1257    // Read the keys and values, and put the mappings in the table
1258    for (int i = 0; i < size; i++) {
1259      Object key = s.readObject();
1260      Object value = s.readObject();
1261      put(key, value);
1262    }
1263  }
1264
1265  /** 
1266   * Return the number of slots in this table 
1267   **/
1268
1269  public synchronized int capacity() {
1270    return table.length;
1271  }
1272
1273  /** 
1274   * Return the load factor 
1275   **/
1276  public float loadFactor() {
1277    return loadFactor;
1278  }
1279}