aa
NonBlockingHashMap.java
Go to the documentation of this file.
1 package com.cliffc.aa.util;
2 
3 import sun.misc.Unsafe;
4 
5 import java.io.IOException;
6 import java.io.Serializable;
7 import java.lang.reflect.Field;
8 import java.util.*;
9 import java.util.concurrent.ConcurrentMap;
10 import java.util.concurrent.atomic.AtomicLongFieldUpdater;
11 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
12 
13 /*
14  * Written by Cliff Click and released to the public domain, as explained at
15  * http://creativecommons.org/licenses/publicdomain
16  */
17 
73 public class NonBlockingHashMap<TypeK, TypeV>
74  extends AbstractMap<TypeK, TypeV>
75  implements ConcurrentMap<TypeK, TypeV>, Cloneable, Serializable {
76 
77  private static final long serialVersionUID = 1234123412341234123L;
78 
79  private static final int REPROBE_LIMIT=10; // Too many reprobes then force a table-resize
80 
81  // --- Bits to allow Unsafe access to arrays
82  private static final Unsafe _unsafe = UtilUnsafe.getUnsafe();
83  private static final int _Obase = _unsafe.arrayBaseOffset(Object[].class);
84  private static final int _Oscale = _unsafe.arrayIndexScale(Object[].class);
85  private static final int _Olog = _Oscale==4?2:(_Oscale==8?3:9999);
86  private static long rawIndex(final Object[] ary, final int idx) {
87  assert idx >= 0 && idx < ary.length;
88  // Note the long-math requirement, to handle arrays of more than 2^31 bytes
89  // - or 2^28 - or about 268M - 8-byte pointer elements.
90  return _Obase + ((long)idx << _Olog);
91  }
92 
93  // --- Setup to use Unsafe
94  private static final long _kvs_offset;
95  static { // <clinit>
96  Field f = null;
97  try { f = NonBlockingHashMap.class.getDeclaredField("_kvs"); }
98  catch( java.lang.NoSuchFieldException e ) { throw new RuntimeException(e); }
99  _kvs_offset = _unsafe.objectFieldOffset(f);
100  }
101  private boolean CAS_kvs( final Object[] oldkvs, final Object[] newkvs ) {
102  return _unsafe.compareAndSwapObject(this, _kvs_offset, oldkvs, newkvs );
103  }
104 
105  // --- Adding a 'prime' bit onto Values via wrapping with a junk wrapper class
106  private static final class Prime {
107  final Object _V;
108  Prime( Object V ) { _V = V; }
109  static Object unbox( Object V ) { return V instanceof Prime ? ((Prime)V)._V : V; }
110  }
111 
112  // --- hash ----------------------------------------------------------------
113  // Helper function to spread lousy hashCodes
114  private static int hash( final Object key) {
115  int h = key.hashCode(); // The real hashCode call
116  h ^= (h>>>20) ^ (h>>>12);
117  h ^= (h>>> 7) ^ (h>>> 4);
118  return h;
119  }
120 
121 
122 
123  // --- The Hash Table --------------------
124  // Slot 0 is always used for a 'CHM' entry below to hold the interesting
125  // bits of the hash table. Slot 1 holds full hashes as an array of ints.
126  // Slots {2,3}, {4,5}, etc hold {Key,Value} pairs. The entire hash table
127  // can be atomically replaced by CASing the _kvs field.
128  //
129  // Why is CHM buried inside the _kvs Object array, instead of the other way
130  // around? The CHM info is used during resize events and updates, but not
131  // during standard 'get' operations. I assume 'get' is much more frequent
132  // than 'put'. 'get' can skip the extra indirection of skipping through the
133  // CHM to reach the _kvs array.
134  private transient Object[] _kvs;
135  private static final CHM chm (Object[] kvs) { return (CHM )kvs[0]; }
136  private static final int[] hashes(Object[] kvs) { return (int[])kvs[1]; }
137  // Number of K,V pairs in the table
138  private static final int len(Object[] kvs) { return (kvs.length-2)>>1; }
139 
140  // Time since last resize
141  private transient long _last_resize_milli;
142 
143  // --- Minimum table size ----------------
144  // Pick size 8 K/V pairs, which turns into (8*2+2)*4+12 = 84 bytes on a
145  // standard 32-bit HotSpot, and (8*2+2)*8+12 = 156 bytes on 64-bit Azul.
146  private static final int MIN_SIZE_LOG=3; //
147  private static final int MIN_SIZE=(1<<MIN_SIZE_LOG); // Must be power of 2
148 
149  // --- Sentinels -------------------------
150  // No-Match-Old - putIfMatch does updates only if it matches the old value,
151  // and NO_MATCH_OLD basically counts as a wildcard match.
152  private static final Object NO_MATCH_OLD = new Object(); // Sentinel
153  // Match-Any-not-null - putIfMatch does updates only if it find a real old
154  // value.
155  private static final Object MATCH_ANY = new Object(); // Sentinel
156  // This K/V pair has been deleted (but the Key slot is forever claimed).
157  // The same Key can be reinserted with a new value later.
158  public static final Object TOMBSTONE = new Object();
159  // Prime'd or box'd version of TOMBSTONE. This K/V pair was deleted, then a
160  // table resize started. The K/V pair has been marked so that no new
161  // updates can happen to the old table (and since the K/V pair was deleted
162  // nothing was copied to the new table).
163  private static final Prime TOMBPRIME = new Prime(TOMBSTONE);
164 
165  // --- key,val -------------------------------------------------------------
166  // Access K,V for a given idx
167  //
168  // Note that these are static, so that the caller is forced to read the _kvs
169  // field only once, and share that read across all key/val calls - lest the
170  // _kvs field move out from under us and back-to-back key & val calls refer
171  // to different _kvs arrays.
172  private static final Object key(Object[] kvs,int idx) { return kvs[(idx<<1)+2]; }
173  private static final Object val(Object[] kvs,int idx) { return kvs[(idx<<1)+3]; }
174  private static final boolean CAS_key( Object[] kvs, int idx, Object old, Object key ) {
175  return _unsafe.compareAndSwapObject( kvs, rawIndex(kvs,(idx<<1)+2), old, key );
176  }
177  private static final boolean CAS_val( Object[] kvs, int idx, Object old, Object val ) {
178  return _unsafe.compareAndSwapObject( kvs, rawIndex(kvs,(idx<<1)+3), old, val );
179  }
180 
181 
182  // --- dump ----------------------------------------------------------------
184  public final void print() {
185  System.out.println("=========");
186  print2(_kvs);
187  System.out.println("=========");
188  }
189  // print the entire state of the table
190  private final void print( Object[] kvs ) {
191  for( int i=0; i<len(kvs); i++ ) {
192  Object K = key(kvs,i);
193  if( K != null ) {
194  String KS = (K == TOMBSTONE) ? "XXX" : K.toString();
195  Object V = val(kvs,i);
196  Object U = Prime.unbox(V);
197  String p = (V==U) ? "" : "prime_";
198  String US = (U == TOMBSTONE) ? "tombstone" : U.toString();
199  System.out.println(""+i+" ("+KS+","+p+US+")");
200  }
201  }
202  Object[] newkvs = chm(kvs)._newkvs; // New table, if any
203  if( newkvs != null ) {
204  System.out.println("----");
205  print(newkvs);
206  }
207  }
208  // print only the live values, broken down by the table they are in
209  private final void print2( Object[] kvs) {
210  for( int i=0; i<len(kvs); i++ ) {
211  Object key = key(kvs,i);
212  Object val = val(kvs,i);
213  Object U = Prime.unbox(val);
214  if( key != null && key != TOMBSTONE && // key is sane
215  val != null && U != TOMBSTONE ) { // val is sane
216  String p = (val==U) ? "" : "prime_";
217  System.out.println(""+i+" ("+key+","+p+val+")");
218  }
219  }
220  Object[] newkvs = chm(kvs)._newkvs; // New table, if any
221  if( newkvs != null ) {
222  System.out.println("----");
223  print2(newkvs);
224  }
225  }
226 
227  // Count of reprobes
234  public long reprobes() { long r = _reprobes.get(); _reprobes = new ConcurrentAutoTable(); return r; }
235 
236 
237  // --- reprobe_limit -----------------------------------------------------
238  // Heuristic to decide if we have reprobed toooo many times. Running over
239  // the reprobe limit on a 'get' call acts as a 'miss'; on a 'put' call it
240  // can trigger a table resize. Several places must have exact agreement on
241  // what the reprobe_limit is, so we share it here.
242  private static final int reprobe_limit( int len ) {
243  return REPROBE_LIMIT + (len>>4);
244  }
245 
246  // --- NonBlockingHashMap --------------------------------------------------
247  // Constructors
248 
251  public NonBlockingHashMap( ) { this(MIN_SIZE); }
252 
258  public NonBlockingHashMap( final int initial_sz ) { initialize(initial_sz); }
259  private final void initialize( int initial_sz ) {
260  if( initial_sz < 0 ) throw new IllegalArgumentException();
261  int i; // Convert to next largest power-of-2
262  if( initial_sz > 1024*1024 ) initial_sz = 1024*1024;
263  for( i=MIN_SIZE_LOG; (1<<i) < (initial_sz<<2); i++ ) ;
264  // Double size for K,V pairs, add 1 for CHM and 1 for hashes
265  _kvs = new Object[((1<<i)<<1)+2];
266  _kvs[0] = new CHM(new ConcurrentAutoTable()); // CHM in slot 0
267  _kvs[1] = new int[1<<i]; // Matching hash entries
268  _last_resize_milli = System.currentTimeMillis();
269  }
270  // Version for subclassed readObject calls, to be called after the defaultReadObject
271  protected final void initialize() { initialize(MIN_SIZE); }
272 
273  // --- wrappers ------------------------------------------------------------
274 
277  @Override
278  public int size ( ) { return chm(_kvs).size(); }
281  @Override
282  public boolean isEmpty ( ) { return size() == 0; }
283 
287  @Override
288  public boolean containsKey( Object key ) { return get(key) != null; }
289 
298  public boolean contains ( Object val ) { return containsValue(val); }
299 
309  @Override
310  public TypeV put ( TypeK key, TypeV val ) { return putIfMatch( key, val, NO_MATCH_OLD); }
311 
318  public TypeV putIfAbsent( TypeK key, TypeV val ) { return putIfMatch( key, val, TOMBSTONE ); }
319 
325  @Override
326  public TypeV remove ( Object key ) { return putIfMatch( key,TOMBSTONE, NO_MATCH_OLD); }
327 
331  public boolean remove ( Object key,Object val ) { return putIfMatch( key,TOMBSTONE, val ) == val; }
332 
336  public TypeV replace ( TypeK key, TypeV val ) { return putIfMatch( key, val,MATCH_ANY ); }
337 
341  public boolean replace ( TypeK key, TypeV oldValue, TypeV newValue ) {
342  return putIfMatch( key, newValue, oldValue ) == oldValue;
343  }
344 
345 
346  // Atomically replace newVal for oldVal, returning the value that existed
347  // there before. If oldVal is the returned value, then newVal was inserted,
348  // otherwise not. A null oldVal means the key does not exist (only insert if
349  // missing); a null newVal means to remove the key.
350  @SuppressWarnings("unchecked")
351  public final TypeV putIfMatchAllowNull( Object key, Object newVal, Object oldVal ) {
352  if( oldVal == null ) oldVal = TOMBSTONE;
353  if( newVal == null ) newVal = TOMBSTONE;
354  final TypeV res = (TypeV)putIfMatch( this, _kvs, key, newVal, oldVal );
355  assert !(res instanceof Prime);
356  //assert res != null;
357  return res == TOMBSTONE ? null : res;
358  }
359 
360  @SuppressWarnings("unchecked")
361  private final TypeV putIfMatch( Object key, Object newVal, Object oldVal ) {
362  if (oldVal == null || newVal == null) throw new NullPointerException();
363  final Object res = putIfMatch( this, _kvs, key, newVal, oldVal );
364  assert !(res instanceof Prime);
365  assert res != null;
366  return res == TOMBSTONE ? null : (TypeV)res;
367  }
368 
369 
373  @Override
374  public void putAll(Map<? extends TypeK, ? extends TypeV> m) {
375  for (Map.Entry<? extends TypeK, ? extends TypeV> e : m.entrySet())
376  put(e.getKey(), e.getValue());
377  }
378 
380  @Override
381  public void clear() { // Smack a new empty table down
382  Object[] newkvs = new NonBlockingHashMap(MIN_SIZE)._kvs;
383  while( !CAS_kvs(_kvs,newkvs) ) // Spin until the clear works
384  ;
385  }
386 
393  @Override
394  public boolean containsValue( final Object val ) {
395  if( val == null ) throw new NullPointerException();
396  for( TypeV V : values() )
397  if( V == val || V.equals(val) )
398  return true;
399  return false;
400  }
401 
402  // This function is supposed to do something for Hashtable, and the JCK
403  // tests hang until it gets called... by somebody ... for some reason,
404  // any reason....
405  protected void rehash() {
406  }
407 
415  @SuppressWarnings("unchecked")
416  @Override
417  public Object clone() {
418  try {
419  // Must clone, to get the class right; NBHM might have been
420  // extended so it would be wrong to just make a new NBHM.
422  // But I don't have an atomic clone operation - the underlying _kvs
423  // structure is undergoing rapid change. If I just clone the _kvs
424  // field, the CHM in _kvs[0] won't be in sync.
425  //
426  // Wipe out the cloned array (it was shallow anyways).
427  t.clear();
428  // Now copy sanely
429  for( TypeK K : keySet() ) {
430  final TypeV V = get(K); // Do an official 'get'
431  t.put(K,V);
432  }
433  return t;
434  } catch (CloneNotSupportedException e) {
435  // this shouldn't happen, since we are Cloneable
436  throw new InternalError();
437  }
438  }
439 
452  @Override
453  public String toString() {
454  Iterator<Entry<TypeK,TypeV>> i = entrySet().iterator();
455  if( !i.hasNext())
456  return "{}";
457 
458  StringBuilder sb = new StringBuilder();
459  sb.append('{');
460  for (;;) {
461  Entry<TypeK,TypeV> e = i.next();
462  TypeK key = e.getKey();
463  TypeV value = e.getValue();
464  sb.append(key == this ? "(this Map)" : key);
465  sb.append('=');
466  sb.append(value == this ? "(this Map)" : value);
467  if( !i.hasNext())
468  return sb.append('}').toString();
469  sb.append(", ");
470  }
471  }
472 
473  // Get *any* valid Key. Useful for making worklists out of a hashtable - the
474  // hashtable can remove dup work. Repeated calls probably return the same
475  // Key, so only useful if keys are removed after calling.
476  @SuppressWarnings("unchecked")
477  public TypeK getKey() { return (TypeK)_getKey(_kvs); }
478  private static Object _getKey(Object[] kvs) {
479  for( int i=0; i<len(kvs); i++ ) {
480  Object key = key(kvs,i);
481  Object val = val(kvs,i);
482  Object U = Prime.unbox(val);
483  if( key != null && key != TOMBSTONE && // key is sane
484  val != null && U != TOMBSTONE ) // val is sane
485  return key;
486  }
487  Object[] newkvs = chm(kvs)._newkvs; // New table, if any
488  return newkvs == null ? null : _getKey(newkvs);
489  }
490 
491  // --- keyeq ---------------------------------------------------------------
492  // Check for key equality. Try direct pointer compare first, then see if
493  // the hashes are unequal (fast negative test) and finally do the full-on
494  // 'equals' v-call.
495  private static boolean keyeq( Object K, Object key, int[] hashes, int hash, int fullhash ) {
496  return
497  K==key || // Either keys match exactly OR
498  // hash exists and matches? hash can be zero during the install of a
499  // new key/value pair.
500  ((hashes[hash] == 0 || hashes[hash] == fullhash) &&
501  // Do not call the users' "equals()" call with a Tombstone, as this can
502  // surprise poorly written "equals()" calls that throw exceptions
503  // instead of simply returning false.
504  K != TOMBSTONE && // Do not call users' equals call with a Tombstone
505  // Do the match the hard way - with the users' key being the loop-
506  // invariant "this" pointer. I could have flipped the order of
507  // operands (since equals is commutative), but I'm making mega-morphic
508  // v-calls in a reprobing loop and nailing down the 'this' argument
509  // gives both the JIT and the hardware a chance to prefetch the call target.
510  key.equals(K)); // Finally do the hard match
511  }
512 
513  // --- get -----------------------------------------------------------------
521  // Never returns a Prime nor a Tombstone.
522  @SuppressWarnings("unchecked")
523  @Override
524  public TypeV get( Object key ) {
525  final Object V = get_impl(this,_kvs,key);
526  assert !(V instanceof Prime); // Never return a Prime
527  assert V != TOMBSTONE;
528  return (TypeV)V;
529  }
530 
531  private static Object get_impl( final NonBlockingHashMap topmap, final Object[] kvs, final Object key ) {
532  final int fullhash= hash (key); // throws NullPointerException if key is null
533  final int len = len (kvs); // Count of key/value pairs, reads kvs.length
534  final CHM chm = chm (kvs); // The CHM, for a volatile read below; reads slot 0 of kvs
535  final int[] hashes=hashes(kvs); // The memoized hashes; reads slot 1 of kvs
536 
537  int idx = fullhash & (len-1); // First key hash
538 
539  // Main spin/reprobe loop, looking for a Key hit
540  int reprobe_cnt=0;
541  while( true ) {
542  // Probe table. Each read of 'val' probably misses in cache in a big
543  // table; hopefully the read of 'key' then hits in cache.
544  final Object K = key(kvs,idx); // Get key before volatile read, could be null
545  final Object V = val(kvs,idx); // Get value before volatile read, could be null or Tombstone or Prime
546  if( K == null ) return null; // A clear miss
547 
548  // We need a volatile-read here to preserve happens-before semantics on
549  // newly inserted Keys. If the Key body was written just before inserting
550  // into the table a Key-compare here might read the uninitialized Key body.
551  // Annoyingly this means we have to volatile-read before EACH key compare.
552  // .
553  // We also need a volatile-read between reading a newly inserted Value
554  // and returning the Value (so the user might end up reading the stale
555  // Value contents). Same problem as with keys - and the one volatile
556  // read covers both.
557  final Object[] newkvs = chm._newkvs; // VOLATILE READ before key compare
558 
559  // Key-compare
560  if( keyeq(K,key,hashes,idx,fullhash) ) {
561  // Key hit! Check for no table-copy-in-progress
562  if( !(V instanceof Prime) ) // No copy?
563  return (V == TOMBSTONE) ? null : V; // Return the value
564  // Key hit - but slot is (possibly partially) copied to the new table.
565  // Finish the copy & retry in the new table.
566  return get_impl(topmap,chm.copy_slot_and_check(topmap,kvs,idx,key),key); // Retry in the new table
567  }
568  // get and put must have the same key lookup logic! But only 'put'
569  // needs to force a table-resize for a too-long key-reprobe sequence.
570  // Check for too-many-reprobes on get - and flip to the new table.
571  if( ++reprobe_cnt >= reprobe_limit(len) || // too many probes
572  K == TOMBSTONE ) // found a TOMBSTONE key, means no more keys in this table
573  return newkvs == null ? null : get_impl(topmap,topmap.help_copy(newkvs),key); // Retry in the new table
574 
575  idx = (idx+1)&(len-1); // Reprobe by 1! (could now prefetch)
576  }
577  }
578 
579  // --- getk -----------------------------------------------------------------
583  // Never returns a Prime nor a Tombstone.
584  @SuppressWarnings("unchecked")
585  public TypeK getk( TypeK key ) {
586  return (TypeK)getk_impl(this,_kvs,key);
587  }
588 
589  private static final Object getk_impl( final NonBlockingHashMap topmap, final Object[] kvs, final Object key ) {
590  final int fullhash= hash (key); // throws NullPointerException if key is null
591  final int len = len (kvs); // Count of key/value pairs, reads kvs.length
592  final CHM chm = chm (kvs); // The CHM, for a volatile read below; reads slot 0 of kvs
593  final int[] hashes=hashes(kvs); // The memoized hashes; reads slot 1 of kvs
594 
595  int idx = fullhash & (len-1); // First key hash
596 
597  // Main spin/reprobe loop, looking for a Key hit
598  int reprobe_cnt=0;
599  while( true ) {
600  // Probe table.
601  final Object K = key(kvs,idx); // Get key before volatile read, could be null
602  if( K == null ) return null; // A clear miss
603 
604  // We need a volatile-read here to preserve happens-before semantics on
605  // newly inserted Keys. If the Key body was written just before inserting
606  // into the table a Key-compare here might read the uninitialized Key body.
607  // Annoyingly this means we have to volatile-read before EACH key compare.
608  // .
609  // We also need a volatile-read between reading a newly inserted Value
610  // and returning the Value (so the user might end up reading the stale
611  // Value contents). Same problem as with keys - and the one volatile
612  // read covers both.
613  final Object[] newkvs = chm._newkvs; // VOLATILE READ before key compare
614 
615  // Key-compare
616  if( keyeq(K,key,hashes,idx,fullhash) )
617  return K; // Return existing Key!
618 
619  // get and put must have the same key lookup logic! But only 'put'
620  // needs to force a table-resize for a too-long key-reprobe sequence.
621  // Check for too-many-reprobes on get - and flip to the new table.
622  if( ++reprobe_cnt >= reprobe_limit(len) || // too many probes
623  K == TOMBSTONE ) { // found a TOMBSTONE key, means no more keys in this table
624  return newkvs == null ? null : getk_impl(topmap,topmap.help_copy(newkvs),key); // Retry in the new table
625  }
626 
627  idx = (idx+1)&(len-1); // Reprobe by 1! (could now prefetch)
628  }
629  }
630 
631  // --- putIfMatch ---------------------------------------------------------
632  // Put, Remove, PutIfAbsent, etc. Return the old value. If the returned
633  // value is equal to expVal (or expVal is NO_MATCH_OLD) then the put can be
634  // assumed to work (although might have been immediately overwritten). Only
635  // the path through copy_slot passes in an expected value of null, and
636  // putIfMatch only returns a null if passed in an expected null.
637  static volatile int DUMMY_VOLATILE;
638  private static final Object putIfMatch( final NonBlockingHashMap topmap, final Object[] kvs, final Object key, final Object putval, final Object expVal ) {
639  assert putval != null;
640  assert !(putval instanceof Prime);
641  assert !(expVal instanceof Prime);
642  final int fullhash = hash (key); // throws NullPointerException if key null
643  final int len = len (kvs); // Count of key/value pairs, reads kvs.length
644  final CHM chm = chm (kvs); // Reads kvs[0]
645  final int[] hashes = hashes(kvs); // Reads kvs[1], read before kvs[0]
646  int idx = fullhash & (len-1);
647 
648  // ---
649  // Key-Claim stanza: spin till we can claim a Key (or force a resizing).
650  int reprobe_cnt=0;
651  Object K=null, V=null;
652  Object[] newkvs=null;
653  while( true ) { // Spin till we get a Key slot
654  V = val(kvs,idx); // Get old value (before volatile read below!)
655  K = key(kvs,idx); // Get current key
656  if( K == null ) { // Slot is free?
657  // Found an empty Key slot - which means this Key has never been in
658  // this table. No need to put a Tombstone - the Key is not here!
659  if( putval == TOMBSTONE ) return putval; // Not-now & never-been in this table
660  if( expVal == MATCH_ANY ) return null; // Will not match, even after K inserts
661  // Claim the null key-slot
662  if( CAS_key(kvs,idx, null, key ) ) { // Claim slot for Key
663  chm._slots.add(1); // Raise key-slots-used count
664  hashes[idx] = fullhash; // Memoize fullhash
665  break; // Got it!
666  }
667  // CAS to claim the key-slot failed.
668  //
669  // This re-read of the Key points out an annoying short-coming of Java
670  // CAS. Most hardware CAS's report back the existing value - so that
671  // if you fail you have a *witness* - the value which caused the CAS to
672  // fail. The Java API turns this into a boolean destroying the
673  // witness. Re-reading does not recover the witness because another
674  // thread can write over the memory after the CAS. Hence we can be in
675  // the unfortunate situation of having a CAS fail *for cause* but
676  // having that cause removed by a later store. This turns a
677  // non-spurious-failure CAS (such as Azul has) into one that can
678  // apparently spuriously fail - and we avoid apparent spurious failure
679  // by not allowing Keys to ever change.
680 
681  // Volatile read, to force loads of K to retry despite JIT, otherwise
682  // it is legal to e.g. haul the load of "K = key(kvs,idx);" outside of
683  // this loop (since failed CAS ops have no memory ordering semantics).
684  int dummy = DUMMY_VOLATILE;
685  continue;
686  }
687  // Key slot was not null, there exists a Key here
688 
689  // We need a volatile-read here to preserve happens-before semantics on
690  // newly inserted Keys. If the Key body was written just before inserting
691  // into the table a Key-compare here might read the uninitialized Key body.
692  // Annoyingly this means we have to volatile-read before EACH key compare.
693  newkvs = chm._newkvs; // VOLATILE READ before key compare
694 
695  if( keyeq(K,key,hashes,idx,fullhash) )
696  break; // Got it!
697 
698  // get and put must have the same key lookup logic! Lest 'get' give
699  // up looking too soon.
700  //topmap._reprobes.add(1);
701  if( ++reprobe_cnt >= reprobe_limit(len) || // too many probes or
702  K == TOMBSTONE ) { // found a TOMBSTONE key, means no more keys
703  // We simply must have a new table to do a 'put'. At this point a
704  // 'get' will also go to the new table (if any). We do not need
705  // to claim a key slot (indeed, we cannot find a free one to claim!).
706  newkvs = chm.resize(topmap,kvs);
707  if( expVal != null ) topmap.help_copy(newkvs); // help along an existing copy
708  return putIfMatch(topmap,newkvs,key,putval,expVal);
709  }
710 
711  idx = (idx+1)&(len-1); // Reprobe!
712  } // End of spinning till we get a Key slot
713 
714  // ---
715  // Found the proper Key slot, now update the matching Value slot. We
716  // never put a null, so Value slots monotonically move from null to
717  // not-null (deleted Values use Tombstone). Thus if 'V' is null we
718  // fail this fast cutout and fall into the check for table-full.
719  if( putval == V ) return V; // Fast cutout for no-change
720 
721  // See if we want to move to a new table (to avoid high average re-probe
722  // counts). We only check on the initial set of a Value from null to
723  // not-null (i.e., once per key-insert). Of course we got a 'free' check
724  // of newkvs once per key-compare (not really free, but paid-for by the
725  // time we get here).
726  if( newkvs == null && // New table-copy already spotted?
727  // Once per fresh key-insert check the hard way
728  ((V == null && chm.tableFull(reprobe_cnt,len)) ||
729  // Or we found a Prime, but the JMM allowed reordering such that we
730  // did not spot the new table (very rare race here: the writing
731  // thread did a CAS of _newkvs then a store of a Prime. This thread
732  // reads the Prime, then reads _newkvs - but the read of Prime was so
733  // delayed (or the read of _newkvs was so accelerated) that they
734  // swapped and we still read a null _newkvs. The resize call below
735  // will do a CAS on _newkvs forcing the read.
736  V instanceof Prime) )
737  newkvs = chm.resize(topmap,kvs); // Force the new table copy to start
738  // See if we are moving to a new table.
739  // If so, copy our slot and retry in the new table.
740  if( newkvs != null )
741  return putIfMatch(topmap,chm.copy_slot_and_check(topmap,kvs,idx,expVal),key,putval,expVal);
742 
743  // ---
744  // We are finally prepared to update the existing table
745  assert !(V instanceof Prime);
746 
747  // Must match old, and we do not? Then bail out now. Note that either V
748  // or expVal might be TOMBSTONE. Also V can be null, if we've never
749  // inserted a value before. expVal can be null if we are called from
750  // copy_slot.
751 
752  if( expVal != NO_MATCH_OLD && // Do we care about expected-Value at all?
753  V != expVal && // No instant match already?
754  (expVal != MATCH_ANY || V == TOMBSTONE || V == null) &&
755  !(V==null && expVal == TOMBSTONE) && // Match on null/TOMBSTONE combo
756  (expVal == null || !expVal.equals(V)) ) // Expensive equals check at the last
757  return V; // Do not update!
758 
759  // Actually change the Value in the Key,Value pair
760  if( CAS_val(kvs, idx, V, putval ) ) {
761  // CAS succeeded - we did the update!
762  // Both normal put's and table-copy calls putIfMatch, but table-copy
763  // does not (effectively) increase the number of live k/v pairs.
764  if( expVal != null ) {
765  // Adjust sizes - a striped counter
766  if( (V == null || V == TOMBSTONE) && putval != TOMBSTONE ) chm._size.add( 1);
767  if( !(V == null || V == TOMBSTONE) && putval == TOMBSTONE ) chm._size.add(-1);
768  }
769  } else { // Else CAS failed
770  V = val(kvs,idx); // Get new value
771  // If a Prime'd value got installed, we need to re-run the put on the
772  // new table. Otherwise we lost the CAS to another racing put.
773  // Simply retry from the start.
774  if( V instanceof Prime )
775  return putIfMatch(topmap,chm.copy_slot_and_check(topmap,kvs,idx,expVal),key,putval,expVal);
776  }
777  // Win or lose the CAS, we are done. If we won then we know the update
778  // happened as expected. If we lost, it means "we won but another thread
779  // immediately stomped our update with no chance of a reader reading".
780  return (V==null && expVal!=null) ? TOMBSTONE : V;
781  }
782 
783  // --- help_copy ---------------------------------------------------------
784  // Help along an existing resize operation. This is just a fast cut-out
785  // wrapper, to encourage inlining for the fast no-copy-in-progress case. We
786  // always help the top-most table copy, even if there are nested table
787  // copies in progress.
788  private final Object[] help_copy( Object[] helper ) {
789  // Read the top-level KVS only once. We'll try to help this copy along,
790  // even if it gets promoted out from under us (i.e., the copy completes
791  // and another KVS becomes the top-level copy).
792  Object[] topkvs = _kvs;
793  CHM topchm = chm(topkvs);
794  if( topchm._newkvs == null ) return helper; // No copy in-progress
795  topchm.help_copy_impl(this,topkvs,false);
796  return helper;
797  }
798 
799 
800  // --- CHM -----------------------------------------------------------------
801  // The control structure for the NonBlockingHashMap
802  private static final class CHM<TypeK,TypeV> {
803  // Size in active K,V pairs
804  private final ConcurrentAutoTable _size;
805  public int size () { return (int)_size.get(); }
806 
807  // ---
808  // These next 2 fields are used in the resizing heuristics, to judge when
809  // it is time to resize or copy the table. Slots is a count of used-up
810  // key slots, and when it nears a large fraction of the table we probably
811  // end up reprobing too much. Last-resize-milli is the time since the
812  // last resize; if we are running back-to-back resizes without growing
813  // (because there are only a few live keys but many slots full of dead
814  // keys) then we need a larger table to cut down on the churn.
815 
816  // Count of used slots, to tell when table is full of dead unusable slots
818  public int slots() { return (int)_slots.get(); }
819 
820  // ---
821  // New mappings, used during resizing.
822  // The 'new KVs' array - created during a resize operation. This
823  // represents the new table being copied from the old one. It's the
824  // volatile variable that is read as we cross from one table to the next,
825  // to get the required memory orderings. It monotonically transits from
826  // null to set (once).
827  volatile Object[] _newkvs;
828  private final AtomicReferenceFieldUpdater<CHM,Object[]> _newkvsUpdater =
829  AtomicReferenceFieldUpdater.newUpdater(CHM.class,Object[].class, "_newkvs");
830  // Set the _next field if we can.
831  boolean CAS_newkvs( Object[] newkvs ) {
832  while( _newkvs == null )
833  if( _newkvsUpdater.compareAndSet(this,null,newkvs) )
834  return true;
835  return false;
836  }
837 
838  // Sometimes many threads race to create a new very large table. Only 1
839  // wins the race, but the losers all allocate a junk large table with
840  // hefty allocation costs. Attempt to control the overkill here by
841  // throttling attempts to create a new table. I cannot really block here
842  // (lest I lose the non-blocking property) but late-arriving threads can
843  // give the initial resizing thread a little time to allocate the initial
844  // new table. The Right Long Term Fix here is to use array-lets and
845  // incrementally create the new very large array. In C I'd make the array
846  // with malloc (which would mmap under the hood) which would only eat
847  // virtual-address and not real memory - and after Somebody wins then we
848  // could in parallel initialize the array. Java does not allow
849  // un-initialized array creation (especially of ref arrays!).
850  volatile long _resizers; // count of threads attempting an initial resize
851  private static final AtomicLongFieldUpdater<CHM> _resizerUpdater =
852  AtomicLongFieldUpdater.newUpdater(CHM.class, "_resizers");
853 
854  // ---
855  // Simple constructor
857  _size = size;
859  }
860 
861  // --- tableFull ---------------------------------------------------------
862  // Heuristic to decide if this table is too full, and we should start a
863  // new table. Note that if a 'get' call has reprobed too many times and
864  // decided the table must be full, then always the estimate_sum must be
865  // high and we must report the table is full. If we do not, then we might
866  // end up deciding that the table is not full and inserting into the
867  // current table, while a 'get' has decided the same key cannot be in this
868  // table because of too many reprobes. The invariant is:
869  // slots.estimate_sum >= max_reprobe_cnt >= reprobe_limit(len)
870  private final boolean tableFull( int reprobe_cnt, int len ) {
871  return
872  // Do the cheap check first: we allow some number of reprobes always
873  reprobe_cnt >= REPROBE_LIMIT &&
874  (reprobe_cnt >= reprobe_limit(len) ||
875  // More expensive check: see if the table is > 1/2 full.
876  _slots.estimate_get() >= (len>>1));
877  }
878 
879  // --- resize ------------------------------------------------------------
880  // Resizing after too many probes. "How Big???" heuristics are here.
881  // Callers will (not this routine) will 'help_copy' any in-progress copy.
882  // Since this routine has a fast cutout for copy-already-started, callers
883  // MUST 'help_copy' lest we have a path which forever runs through
884  // 'resize' only to discover a copy-in-progress which never progresses.
885  private final Object[] resize( NonBlockingHashMap topmap, Object[] kvs) {
886  assert chm(kvs) == this;
887 
888  // Check for resize already in progress, probably triggered by another thread
889  Object[] newkvs = _newkvs; // VOLATILE READ
890  if( newkvs != null ) // See if resize is already in progress
891  return newkvs; // Use the new table already
892 
893  // No copy in-progress, so start one. First up: compute new table size.
894  int oldlen = len(kvs); // Old count of K,V pairs allowed
895  int sz = size(); // Get current table count of active K,V pairs
896  int newsz = sz; // First size estimate
897 
898  // Heuristic to determine new size. We expect plenty of dead-slots-with-keys
899  // and we need some decent padding to avoid endless reprobing.
900  if( sz >= (oldlen>>2) ) { // If we are >25% full of keys then...
901  newsz = oldlen<<1; // Double size, so new table will be between 12.5% and 25% full
902  // For tables less than 1M entries, if >50% full of keys then...
903  // For tables more than 1M entries, if >75% full of keys then...
904  if( 4L*sz >= ((oldlen>>20)!=0?3L:2L)*oldlen )
905  newsz = oldlen<<2; // Double double size, so new table will be between %12.5 (18.75%) and 25% (25%)
906  }
907  // This heuristic in the next 2 lines leads to a much denser table
908  // with a higher reprobe rate
909  //if( sz >= (oldlen>>1) ) // If we are >50% full of keys then...
910  // newsz = oldlen<<1; // Double size
911 
912  // Last (re)size operation was very recent? Then double again; slows
913  // down resize operations for tables subject to a high key churn rate.
914  long tm = System.currentTimeMillis();
915  long q=0;
916  if( newsz <= oldlen && // New table would shrink or hold steady?
917  (tm <= topmap._last_resize_milli+10000 || // Recent resize (less than 10 sec ago)
918  (q=_slots.estimate_get()) >= (sz<<1)) ) // 1/2 of keys are dead?
919  newsz = oldlen<<1; // Double the existing size
920 
921  // Do not shrink, ever
922  if( newsz < oldlen ) newsz = oldlen;
923 
924  // Convert to power-of-2
925  int log2;
926  for( log2=MIN_SIZE_LOG; (1<<log2) < newsz; log2++ ) ; // Compute log2 of size
927  long len = ((1L << log2) << 1) + 2;
928  // prevent integer overflow - limit of 2^31 elements in a Java array
929  // so here, 2^30 + 2 is the largest number of elements in the hash table
930  if ((int)len!=len) {
931  log2 = 30;
932  len = (1L << log2) + 2;
933  if (sz > ((len >> 2) + (len >> 1))) throw new RuntimeException("Table is full.");
934  }
935 
936  // Now limit the number of threads actually allocating memory to a
937  // handful - lest we have 750 threads all trying to allocate a giant
938  // resized array.
939  long r = _resizers;
940  while( !_resizerUpdater.compareAndSet(this,r,r+1) )
941  r = _resizers;
942  // Size calculation: 2 words (K+V) per table entry, plus a handful. We
943  // guess at 64-bit pointers; 32-bit pointers screws up the size calc by
944  // 2x but does not screw up the heuristic very much.
945  long megs = ((((1L<<log2)<<1)+8)<<3/*word to bytes*/)>>20/*megs*/;
946  if( r >= 2 && megs > 0 ) { // Already 2 guys trying; wait and see
947  newkvs = _newkvs; // Between dorking around, another thread did it
948  if( newkvs != null ) // See if resize is already in progress
949  return newkvs; // Use the new table already
950  // TODO - use a wait with timeout, so we'll wakeup as soon as the new table
951  // is ready, or after the timeout in any case.
952  //synchronized( this ) { wait(8*megs); } // Timeout - we always wakeup
953  // For now, sleep a tad and see if the 2 guys already trying to make
954  // the table actually get around to making it happen.
955  try { Thread.sleep(megs); } catch( Exception e ) { }
956  }
957  // Last check, since the 'new' below is expensive and there is a chance
958  // that another thread slipped in a new thread while we ran the heuristic.
959  newkvs = _newkvs;
960  if( newkvs != null ) // See if resize is already in progress
961  return newkvs; // Use the new table already
962 
963  // Double size for K,V pairs, add 1 for CHM
964  newkvs = new Object[(int)len]; // This can get expensive for big arrays
965  newkvs[0] = new CHM(_size); // CHM in slot 0
966  newkvs[1] = new int[1<<log2]; // hashes in slot 1
967 
968  // Another check after the slow allocation
969  if( _newkvs != null ) // See if resize is already in progress
970  return _newkvs; // Use the new table already
971 
972  // The new table must be CAS'd in so only 1 winner amongst duplicate
973  // racing resizing threads. Extra CHM's will be GC'd.
974  if( CAS_newkvs( newkvs ) ) { // NOW a resize-is-in-progress!
975  //notifyAll(); // Wake up any sleepers
976  //long nano = System.nanoTime();
977  //System.out.println(" "+nano+" Resize from "+oldlen+" to "+(1<<log2)+" and had "+(_resizers-1)+" extras" );
978  //if( System.out != null ) System.out.print("["+log2);
979  topmap.rehash(); // Call for Hashtable's benefit
980  } else // CAS failed?
981  newkvs = _newkvs; // Reread new table
982  return newkvs;
983  }
984 
985 
986  // The next part of the table to copy. It monotonically transits from zero
987  // to _kvs.length. Visitors to the table can claim 'work chunks' by
988  // CAS'ing this field up, then copying the indicated indices from the old
989  // table to the new table. Workers are not required to finish any chunk;
990  // the counter simply wraps and work is copied duplicately until somebody
991  // somewhere completes the count.
992  volatile long _copyIdx = 0;
993  static private final AtomicLongFieldUpdater<CHM> _copyIdxUpdater =
994  AtomicLongFieldUpdater.newUpdater(CHM.class, "_copyIdx");
995 
996  // Work-done reporting. Used to efficiently signal when we can move to
997  // the new table. From 0 to len(oldkvs) refers to copying from the old
998  // table to the new.
999  volatile long _copyDone= 0;
1000  static private final AtomicLongFieldUpdater<CHM> _copyDoneUpdater =
1001  AtomicLongFieldUpdater.newUpdater(CHM.class, "_copyDone");
1002 
1003  // --- help_copy_impl ----------------------------------------------------
1004  // Help along an existing resize operation. We hope its the top-level
1005  // copy (it was when we started) but this CHM might have been promoted out
1006  // of the top position.
1007  private final void help_copy_impl( NonBlockingHashMap topmap, Object[] oldkvs, boolean copy_all ) {
1008  assert chm(oldkvs) == this;
1009  Object[] newkvs = _newkvs;
1010  assert newkvs != null; // Already checked by caller
1011  int oldlen = len(oldkvs); // Total amount to copy
1012  final int MIN_COPY_WORK = Math.min(oldlen,1024); // Limit per-thread work
1013 
1014  // ---
1015  int panic_start = -1;
1016  int copyidx=-9999; // Fool javac to think it's initialized
1017  while( _copyDone < oldlen ) { // Still needing to copy?
1018  // Carve out a chunk of work. The counter wraps around so every
1019  // thread eventually tries to copy every slot repeatedly.
1020 
1021  // We "panic" if we have tried TWICE to copy every slot - and it still
1022  // has not happened. i.e., twice some thread somewhere claimed they
1023  // would copy 'slot X' (by bumping _copyIdx) but they never claimed to
1024  // have finished (by bumping _copyDone). Our choices become limited:
1025  // we can wait for the work-claimers to finish (and become a blocking
1026  // algorithm) or do the copy work ourselves. Tiny tables with huge
1027  // thread counts trying to copy the table often 'panic'.
1028  if( panic_start == -1 ) { // No panic?
1029  copyidx = (int)_copyIdx;
1030  while( !_copyIdxUpdater.compareAndSet(this,copyidx,copyidx+MIN_COPY_WORK) )
1031  copyidx = (int)_copyIdx; // Re-read
1032  if( !(copyidx < (oldlen<<1)) ) // Panic!
1033  panic_start = copyidx; // Record where we started to panic-copy
1034  }
1035 
1036  // We now know what to copy. Try to copy.
1037  int workdone = 0;
1038  for( int i=0; i<MIN_COPY_WORK; i++ )
1039  if( copy_slot(topmap,(copyidx+i)&(oldlen-1),oldkvs,newkvs) ) // Made an oldtable slot go dead?
1040  workdone++; // Yes!
1041  if( workdone > 0 ) // Report work-done occasionally
1042  copy_check_and_promote( topmap, oldkvs, workdone );// See if we can promote
1043 
1044  copyidx += MIN_COPY_WORK;
1045  // Uncomment these next 2 lines to turn on incremental table-copy.
1046  // Otherwise this thread continues to copy until it is all done.
1047  if( !copy_all && panic_start == -1 ) // No panic?
1048  return; // Then done copying after doing MIN_COPY_WORK
1049  }
1050  // Extra promotion check, in case another thread finished all copying
1051  // then got stalled before promoting.
1052  copy_check_and_promote( topmap, oldkvs, 0 );// See if we can promote
1053  }
1054 
1055  // --- copy_slot_and_check -----------------------------------------------
1056  // Copy slot 'idx' from the old table to the new table. If this thread
1057  // confirmed the copy, update the counters and check for promotion.
1058  //
1059  // Returns the result of reading the volatile _newkvs, mostly as a
1060  // convenience to callers. We come here with 1-shot copy requests
1061  // typically because the caller has found a Prime, and has not yet read
1062  // the _newkvs volatile - which must have changed from null-to-not-null
1063  // before any Prime appears. So the caller needs to read the _newkvs
1064  // field to retry his operation in the new table, but probably has not
1065  // read it yet.
1066  private final Object[] copy_slot_and_check( NonBlockingHashMap topmap, Object[] oldkvs, int idx, Object should_help ) {
1067  assert chm(oldkvs) == this;
1068  Object[] newkvs = _newkvs; // VOLATILE READ
1069  // We're only here because the caller saw a Prime, which implies a
1070  // table-copy is in progress.
1071  assert newkvs != null;
1072  if( copy_slot(topmap,idx,oldkvs,_newkvs) ) // Copy the desired slot
1073  copy_check_and_promote(topmap, oldkvs, 1); // Record the slot copied
1074  // Generically help along any copy (except if called recursively from a helper)
1075  return (should_help == null) ? newkvs : topmap.help_copy(newkvs);
1076  }
1077 
1078  // --- copy_check_and_promote --------------------------------------------
1079  private final void copy_check_and_promote( NonBlockingHashMap topmap, Object[] oldkvs, int workdone ) {
1080  assert chm(oldkvs) == this;
1081  int oldlen = len(oldkvs);
1082  // We made a slot unusable and so did some of the needed copy work
1083  long copyDone = _copyDone;
1084  assert (copyDone+workdone) <= oldlen;
1085  if( workdone > 0 ) {
1086  while( !_copyDoneUpdater.compareAndSet(this,copyDone,copyDone+workdone) ) {
1087  copyDone = _copyDone; // Reload, retry
1088  assert (copyDone+workdone) <= oldlen;
1089  }
1090  //if( (10*copyDone/oldlen) != (10*(copyDone+workdone)/oldlen) )
1091  //System.out.print(" "+(copyDone+workdone)*100/oldlen+"%"+"_"+(_copyIdx*100/oldlen)+"%");
1092  }
1093 
1094  // Check for copy being ALL done, and promote. Note that we might have
1095  // nested in-progress copies and manage to finish a nested copy before
1096  // finishing the top-level copy. We only promote top-level copies.
1097  if( copyDone+workdone == oldlen && // Ready to promote this table?
1098  topmap._kvs == oldkvs && // Looking at the top-level table?
1099  // Attempt to promote
1100  topmap.CAS_kvs(oldkvs,_newkvs) ) {
1101  topmap._last_resize_milli = System.currentTimeMillis(); // Record resize time for next check
1102  //long nano = System.nanoTime();
1103  //System.out.println(" "+nano+" Promote table to "+len(_newkvs));
1104  //if( System.out != null ) System.out.print("]");
1105  }
1106  }
1107 
1108  // --- copy_slot ---------------------------------------------------------
1109  // Copy one K/V pair from oldkvs[i] to newkvs. Returns true if we can
1110  // confirm that the new table guaranteed has a value for this old-table
1111  // slot. We need an accurate confirmed-copy count so that we know when we
1112  // can promote (if we promote the new table too soon, other threads may
1113  // 'miss' on values not-yet-copied from the old table). We don't allow
1114  // any direct updates on the new table, unless they first happened to the
1115  // old table - so that any transition in the new table from null to
1116  // not-null must have been from a copy_slot (or other old-table overwrite)
1117  // and not from a thread directly writing in the new table. Thus we can
1118  // count null-to-not-null transitions in the new table.
1119  private boolean copy_slot( NonBlockingHashMap topmap, int idx, Object[] oldkvs, Object[] newkvs ) {
1120  // Blindly set the key slot from null to TOMBSTONE, to eagerly stop
1121  // fresh put's from inserting new values in the old table when the old
1122  // table is mid-resize. We don't need to act on the results here,
1123  // because our correctness stems from box'ing the Value field. Slamming
1124  // the Key field is a minor speed optimization.
1125  Object key;
1126  while( (key=key(oldkvs,idx)) == null )
1127  CAS_key(oldkvs,idx, null, TOMBSTONE);
1128 
1129  // ---
1130  // Prevent new values from appearing in the old table.
1131  // Box what we see in the old table, to prevent further updates.
1132  Object oldval = val(oldkvs,idx); // Read OLD table
1133  while( !(oldval instanceof Prime) ) {
1134  final Prime box = (oldval == null || oldval == TOMBSTONE) ? TOMBPRIME : new Prime(oldval);
1135  if( CAS_val(oldkvs,idx,oldval,box) ) { // CAS down a box'd version of oldval
1136  // If we made the Value slot hold a TOMBPRIME, then we both
1137  // prevented further updates here but also the (absent)
1138  // oldval is vacuously available in the new table. We
1139  // return with true here: any thread looking for a value for
1140  // this key can correctly go straight to the new table and
1141  // skip looking in the old table.
1142  if( box == TOMBPRIME )
1143  return true;
1144  // Otherwise we boxed something, but it still needs to be
1145  // copied into the new table.
1146  oldval = box; // Record updated oldval
1147  break; // Break loop; oldval is now boxed by us
1148  }
1149  oldval = val(oldkvs,idx); // Else try, try again
1150  }
1151  if( oldval == TOMBPRIME ) return false; // Copy already complete here!
1152 
1153  // ---
1154  // Copy the value into the new table, but only if we overwrite a null.
1155  // If another value is already in the new table, then somebody else
1156  // wrote something there and that write is happens-after any value that
1157  // appears in the old table. If putIfMatch does not find a null in the
1158  // new table - somebody else should have recorded the null-not_null
1159  // transition in this copy.
1160  Object old_unboxed = ((Prime)oldval)._V;
1161  assert old_unboxed != TOMBSTONE;
1162  putIfMatch(topmap, newkvs, key, old_unboxed, null);
1163 
1164  // ---
1165  // Finally, now that any old value is exposed in the new table, we can
1166  // forever hide the old-table value by slapping a TOMBPRIME down. This
1167  // will stop other threads from uselessly attempting to copy this slot
1168  // (i.e., it's a speed optimization not a correctness issue).
1169  while( oldval != TOMBPRIME && !CAS_val(oldkvs,idx,oldval,TOMBPRIME) )
1170  oldval = val(oldkvs,idx);
1171 
1172  return true;
1173  } // end copy_slot
1174  } // End of CHM
1175 
1176 
1177  // --- Snapshot ------------------------------------------------------------
1178  // The main class for iterating over the NBHM. It "snapshots" a clean
1179  // view of the K/V array.
1180  private class SnapshotV implements Iterator<TypeV>, Enumeration<TypeV> {
1181  final Object[] _sskvs;
1182  public SnapshotV() {
1183  while( true ) { // Verify no table-copy-in-progress
1184  Object[] topkvs = _kvs;
1185  CHM topchm = chm(topkvs);
1186  if( topchm._newkvs == null ) { // No table-copy-in-progress
1187  // The "linearization point" for the iteration. Every key in this
1188  // table will be visited, but keys added later might be skipped or
1189  // even be added to a following table (also not iterated over).
1190  _sskvs = topkvs;
1191  break;
1192  }
1193  // Table copy in-progress - so we cannot get a clean iteration. We
1194  // must help finish the table copy before we can start iterating.
1195  topchm.help_copy_impl(NonBlockingHashMap.this,topkvs,true);
1196  }
1197  // Warm-up the iterator
1198  next();
1199  }
1200  int length() { return len(_sskvs); }
1201  Object key(int idx) { return NonBlockingHashMap.key(_sskvs,idx); }
1202  Object val(int idx) { return NonBlockingHashMap.val(_sskvs,idx); }
1203  private int _idx; // Varies from 0-keys.length
1204  private Object _nextK, _prevK; // Last 2 keys found
1205  private TypeV _nextV, _prevV; // Last 2 values found
1206  public boolean hasNext() { return _nextV != null; }
1207  @SuppressWarnings("unchecked")
1208  public TypeV next() {
1209  // 'next' actually knows what the next value will be - it had to
1210  // figure that out last go-around lest 'hasNext' report true and
1211  // some other thread deleted the last value. Instead, 'next'
1212  // spends all its effort finding the key that comes after the
1213  // 'next' key.
1214  if( _idx != 0 && _nextV == null ) throw new NoSuchElementException();
1215  _prevK = _nextK; // This will become the previous key
1216  _prevV = _nextV; // This will become the previous value
1217  _nextV = null; // We have no more next-key
1218  Object nV;
1219  // Attempt to set <_nextK,_nextV> to the next K,V pair.
1220  // _nextV is the trigger: stop searching when it is != null
1221  while( _idx<length() ) { // Scan array
1222  _nextK = key(_idx++); // Get a key that definitely is in the set (for the moment!)
1223  if( _nextK != null && // Found something?
1224  _nextK != TOMBSTONE && // Key is not TOMBSTONE
1225  // Keys can be deleted and not TOMBSTONE, and after deletion had
1226  // their innards gutted... so you cannot use them to compute their
1227  // own hash or 'get' a Value. So get the paired Value directly.
1228  (nV=val(_idx-1)) != null && // Get value
1229  nV != TOMBSTONE ) // Value is not TOMBSTONE
1230  { _nextV = (TypeV)nV; break; } // Got it! _nextK/_nextV is a valid Key/Value
1231  } // Else keep scanning
1232  return _prevV; // Return current value.
1233  }
1234  public void remove() {
1235  if( _prevV == null ) throw new IllegalStateException();
1237  _prevV = null;
1238  }
1239 
1240  public TypeV nextElement() { return next(); }
1241  public boolean hasMoreElements() { return hasNext(); }
1242  }
1243  public Object[] raw_array() { return new SnapshotV()._sskvs; }
1244 
1248  public Enumeration<TypeV> elements() { return new SnapshotV(); }
1249 
1250  // --- values --------------------------------------------------------------
1264  @Override
1265  public Collection<TypeV> values() {
1266  return new AbstractCollection<TypeV>() {
1267  @Override public void clear ( ) { NonBlockingHashMap.this.clear ( ); }
1268  @Override public int size ( ) { return NonBlockingHashMap.this.size ( ); }
1269  @Override public boolean contains( Object v ) { return NonBlockingHashMap.this.containsValue(v); }
1270  @Override public Iterator<TypeV> iterator() { return new SnapshotV(); }
1271  };
1272  }
1273 
1274  // --- keySet --------------------------------------------------------------
1275  @SuppressWarnings("unchecked")
1276  private class SnapshotK implements Iterator<TypeK>, Enumeration<TypeK> {
1278  public SnapshotK() { _ss = new SnapshotV(); }
1279  public void remove() { _ss.remove(); }
1280  public TypeK next() { _ss.next(); return (TypeK)_ss._prevK; }
1281  public boolean hasNext() { return _ss.hasNext(); }
1282  public TypeK nextElement() { return next(); }
1283  public boolean hasMoreElements() { return hasNext(); }
1284  }
1285 
1289  public Enumeration<TypeK> keys() { return new SnapshotK(); }
1290 
1304  @Override
1305  public Set<TypeK> keySet() {
1306  return new AbstractSet<TypeK> () {
1307  @Override public void clear ( ) { NonBlockingHashMap.this.clear ( ); }
1308  @Override public int size ( ) { return NonBlockingHashMap.this.size ( ); }
1309  @Override public boolean contains( Object k ) { return NonBlockingHashMap.this.containsKey(k); }
1310  @Override public boolean remove ( Object k ) { return NonBlockingHashMap.this.remove (k) != null; }
1311  @Override public Iterator<TypeK> iterator() { return new SnapshotK(); }
1312  };
1313  }
1314 
1315 
1316  // --- entrySet ------------------------------------------------------------
1317  // Warning: Each call to 'next' in this iterator constructs a new NBHMEntry.
1318  private class NBHMEntry extends AbstractEntry<TypeK,TypeV> {
1319  NBHMEntry( final TypeK k, final TypeV v ) { super(k,v); }
1320  public TypeV setValue(final TypeV val) {
1321  if( val == null ) throw new NullPointerException();
1322  _val = val;
1323  return put(_key, val);
1324  }
1325  }
1326 
1327  @SuppressWarnings("unchecked")
1328  private class SnapshotE implements Iterator<Map.Entry<TypeK,TypeV>> {
1330  public SnapshotE() { _ss = new SnapshotV(); }
1331  public void remove() { _ss.remove(); }
1332  public Map.Entry<TypeK,TypeV> next() { _ss.next(); return new NBHMEntry((TypeK)_ss._prevK,_ss._prevV); }
1333  public boolean hasNext() { return _ss.hasNext(); }
1334  }
1335 
1357  @Override
1358  public Set<Map.Entry<TypeK,TypeV>> entrySet() {
1359  return new AbstractSet<Map.Entry<TypeK,TypeV>>() {
1360  @Override public void clear ( ) { NonBlockingHashMap.this.clear( ); }
1361  @Override public int size ( ) { return NonBlockingHashMap.this.size ( ); }
1362  @Override public boolean remove( final Object o ) {
1363  if( !(o instanceof Map.Entry)) return false;
1364  final Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1365  return NonBlockingHashMap.this.remove(e.getKey(), e.getValue());
1366  }
1367  @Override public boolean contains(final Object o) {
1368  if( !(o instanceof Map.Entry)) return false;
1369  final Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1370  TypeV v = get(e.getKey());
1371  return v.equals(e.getValue());
1372  }
1373  @Override public Iterator<Map.Entry<TypeK,TypeV>> iterator() { return new SnapshotE(); }
1374  };
1375  }
1376 
1377  // --- writeObject -------------------------------------------------------
1378  // Write a NBHM to a stream
1379  private void writeObject(java.io.ObjectOutputStream s) throws IOException {
1380  s.defaultWriteObject(); // Nothing to write
1381  for( Object K : keySet() ) {
1382  final Object V = get(K); // Do an official 'get'
1383  s.writeObject(K); // Write the <TypeK,TypeV> pair
1384  s.writeObject(V);
1385  }
1386  s.writeObject(null); // Sentinel to indicate end-of-data
1387  s.writeObject(null);
1388  }
1389 
1390  // --- readObject --------------------------------------------------------
1391  // Read a CHM from a stream
1392  @SuppressWarnings("unchecked")
1393  private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {
1394  s.defaultReadObject(); // Read nothing
1396  for(;;) {
1397  final TypeK K = (TypeK) s.readObject();
1398  final TypeV V = (TypeV) s.readObject();
1399  if( K == null ) break;
1400  put(K,V); // Insert with an offical put
1401  }
1402  }
1403 
1404 } // End NonBlockingHashMap class
com.cliffc.aa.util.NonBlockingHashMap._Oscale
static final int _Oscale
Definition: NonBlockingHashMap.java:84
com.cliffc.aa.util.NonBlockingHashMap.rehash
void rehash()
Definition: NonBlockingHashMap.java:405
com.cliffc.aa.util.NonBlockingHashMap.val
static final Object val(Object[] kvs, int idx)
Definition: NonBlockingHashMap.java:173
com.cliffc.aa.util.NonBlockingHashMap.reprobes
long reprobes()
Get and clear the current count of reprobes.
Definition: NonBlockingHashMap.java:234
com.cliffc.aa.util.NonBlockingHashMap.getk
TypeK getk(TypeK key)
Returns the Key to which the specified key is mapped, or.
Definition: NonBlockingHashMap.java:585
com.cliffc.aa.util.NonBlockingHashMap.writeObject
void writeObject(java.io.ObjectOutputStream s)
Definition: NonBlockingHashMap.java:1379
com.cliffc.aa.util.NonBlockingHashMap.SnapshotV._sskvs
final Object[] _sskvs
Definition: NonBlockingHashMap.java:1181
com.cliffc.aa.util.NonBlockingHashMap.serialVersionUID
static final long serialVersionUID
Definition: NonBlockingHashMap.java:77
com.cliffc.aa.util.NonBlockingHashMap._unsafe
static final Unsafe _unsafe
Definition: NonBlockingHashMap.java:82
com.cliffc.aa.util.NonBlockingHashMap._getKey
static Object _getKey(Object[] kvs)
Definition: NonBlockingHashMap.java:478
com.cliffc.aa.util.NonBlockingHashMap
A lock-free alternate implementation of java.util.concurrent.ConcurrentHashMap with better scaling pr...
Definition: NonBlockingHashMap.java:75
com.cliffc.aa.util.NonBlockingHashMap.replace
TypeV replace(TypeK key, TypeV val)
Atomically do a put(key,val) if-and-only-if the key is mapped to some value already.
Definition: NonBlockingHashMap.java:336
com.cliffc.aa.util.NonBlockingHashMap.CHM.slots
int slots()
Definition: NonBlockingHashMap.java:818
com.cliffc.aa.util.NonBlockingHashMap.putIfMatchAllowNull
final TypeV putIfMatchAllowNull(Object key, Object newVal, Object oldVal)
Definition: NonBlockingHashMap.java:351
com.cliffc.aa.util.NonBlockingHashMap.Prime._V
final Object _V
Definition: NonBlockingHashMap.java:107
com.cliffc.aa.util.NonBlockingHashMap.keyeq
static boolean keyeq(Object K, Object key, int[] hashes, int hash, int fullhash)
Definition: NonBlockingHashMap.java:495
com.cliffc.aa.util.NonBlockingHashMap.Prime.unbox
static Object unbox(Object V)
Definition: NonBlockingHashMap.java:109
com.cliffc.aa.util.NonBlockingHashMap.SnapshotK
Definition: NonBlockingHashMap.java:1276
com.cliffc.aa.util.NonBlockingHashMap.CHM._newkvsUpdater
final AtomicReferenceFieldUpdater< CHM, Object[]> _newkvsUpdater
Definition: NonBlockingHashMap.java:828
com.cliffc.aa.util.NonBlockingHashMap.CHM.CAS_newkvs
boolean CAS_newkvs(Object[] newkvs)
Definition: NonBlockingHashMap.java:831
com.cliffc.aa.util.NonBlockingHashMap.contains
boolean contains(Object val)
Legacy method testing if some key maps into the specified value in this table.
Definition: NonBlockingHashMap.java:298
com.cliffc.aa.util.NonBlockingHashMap.CHM.tableFull
final boolean tableFull(int reprobe_cnt, int len)
Definition: NonBlockingHashMap.java:870
com.cliffc.aa.util.NonBlockingHashMap.NonBlockingHashMap
NonBlockingHashMap(final int initial_sz)
Create a new NonBlockingHashMap with initial room for the given number of elements,...
Definition: NonBlockingHashMap.java:258
com.cliffc.aa.util.ConcurrentAutoTable
An auto-resizing table of.
Definition: ConcurrentAutoTable.java:19
com.cliffc.aa.util.UtilUnsafe.getUnsafe
static Unsafe getUnsafe()
Fetch the Unsafe.
Definition: UtilUnsafe.java:19
com.cliffc.aa.util.NonBlockingHashMap.CHM
Definition: NonBlockingHashMap.java:802
com.cliffc.aa.util.NonBlockingHashMap.CHM.copy_check_and_promote
final void copy_check_and_promote(NonBlockingHashMap topmap, Object[] oldkvs, int workdone)
Definition: NonBlockingHashMap.java:1079
com.cliffc.aa.util.NonBlockingHashMap.CHM._resizerUpdater
static final AtomicLongFieldUpdater< CHM > _resizerUpdater
Definition: NonBlockingHashMap.java:851
com.cliffc.aa.util.UtilUnsafe
Simple class to obtain access to the Unsafe object.
Definition: UtilUnsafe.java:15
com.cliffc.aa.util.NonBlockingHashMap.CHM.size
int size()
Definition: NonBlockingHashMap.java:805
com.cliffc.aa.util.NonBlockingHashMap.len
static final int len(Object[] kvs)
Definition: NonBlockingHashMap.java:138
com.cliffc.aa.util.NonBlockingHashMap.values
Collection< TypeV > values()
Returns a Collection view of the values contained in this map.
Definition: NonBlockingHashMap.java:1265
com.cliffc.aa.util.NonBlockingHashMap.SnapshotV.SnapshotV
SnapshotV()
Definition: NonBlockingHashMap.java:1182
com.cliffc.aa.util.NonBlockingHashMap.replace
boolean replace(TypeK key, TypeV oldValue, TypeV newValue)
Atomically do a put(key,newValue) if-and-only-if the key is mapped a value which is equals to oldValu...
Definition: NonBlockingHashMap.java:341
com.cliffc.aa.util.NonBlockingHashMap.SnapshotK.next
TypeK next()
Definition: NonBlockingHashMap.java:1280
com.cliffc.aa.util.NonBlockingHashMap.CHM._copyIdxUpdater
static final AtomicLongFieldUpdater< CHM > _copyIdxUpdater
Definition: NonBlockingHashMap.java:993
com.cliffc.aa.util.ConcurrentAutoTable.add
void add(long x)
Add the given value to current counter value.
Definition: ConcurrentAutoTable.java:30
com.cliffc.aa.util.NonBlockingHashMap.CAS_kvs
boolean CAS_kvs(final Object[] oldkvs, final Object[] newkvs)
Definition: NonBlockingHashMap.java:101
com.cliffc.aa.util.NonBlockingHashMap.toString
String toString()
Returns a string representation of this map.
Definition: NonBlockingHashMap.java:453
com.cliffc.aa.util.NonBlockingHashMap.SnapshotV.remove
void remove()
Definition: NonBlockingHashMap.java:1234
com.cliffc.aa.util.NonBlockingHashMap.NonBlockingHashMap
NonBlockingHashMap()
Create a new NonBlockingHashMap with default minimum size (currently set to 8 K/V pairs or roughly 84...
Definition: NonBlockingHashMap.java:251
com.cliffc.aa.util.NonBlockingHashMap.SnapshotV.next
TypeV next()
Definition: NonBlockingHashMap.java:1208
com.cliffc.aa.util.NonBlockingHashMap._Olog
static final int _Olog
Definition: NonBlockingHashMap.java:85
com.cliffc.aa.util.NonBlockingHashMap.CHM.help_copy_impl
final void help_copy_impl(NonBlockingHashMap topmap, Object[] oldkvs, boolean copy_all)
Definition: NonBlockingHashMap.java:1007
com.cliffc.aa.util.NonBlockingHashMap.SnapshotE.next
Map.Entry< TypeK, TypeV > next()
Definition: NonBlockingHashMap.java:1332
com.cliffc.aa.util.NonBlockingHashMap.SnapshotK._ss
final SnapshotV _ss
Definition: NonBlockingHashMap.java:1277
com.cliffc.aa.util.NonBlockingHashMap.TOMBPRIME
static final Prime TOMBPRIME
Definition: NonBlockingHashMap.java:163
AbstractMap
com.cliffc.aa.util.NonBlockingHashMap.SnapshotV._nextK
Object _nextK
Definition: NonBlockingHashMap.java:1204
com.cliffc.aa.util.NonBlockingHashMap.reprobe_limit
static final int reprobe_limit(int len)
Definition: NonBlockingHashMap.java:242
com.cliffc.aa.util.NonBlockingHashMap.SnapshotK.nextElement
TypeK nextElement()
Definition: NonBlockingHashMap.java:1282
com.cliffc.aa.util.NonBlockingHashMap.rawIndex
static long rawIndex(final Object[] ary, final int idx)
Definition: NonBlockingHashMap.java:86
com.cliffc.aa.util.NonBlockingHashMap.SnapshotV._idx
int _idx
Definition: NonBlockingHashMap.java:1203
com.cliffc.aa.util.NonBlockingHashMap.CHM.CHM
CHM(ConcurrentAutoTable size)
Definition: NonBlockingHashMap.java:856
com.cliffc.aa.util.NonBlockingHashMap.remove
TypeV remove(Object key)
Removes the key (and its corresponding value) from this map.
Definition: NonBlockingHashMap.java:326
com.cliffc.aa.util.NonBlockingHashMap.DUMMY_VOLATILE
static volatile int DUMMY_VOLATILE
Definition: NonBlockingHashMap.java:637
com.cliffc.aa.util.NonBlockingHashMap.SnapshotE.SnapshotE
SnapshotE()
Definition: NonBlockingHashMap.java:1330
com.cliffc.aa.util.NonBlockingHashMap.SnapshotV.nextElement
TypeV nextElement()
Definition: NonBlockingHashMap.java:1240
com.cliffc.aa.util.NonBlockingHashMap.SnapshotE
Definition: NonBlockingHashMap.java:1328
com.cliffc.aa.util.NonBlockingHashMap.entrySet
Set< Map.Entry< TypeK, TypeV > > entrySet()
Returns a Set view of the mappings contained in this map.
Definition: NonBlockingHashMap.java:1358
com.cliffc.aa.util.NonBlockingHashMap.SnapshotV._prevV
TypeV _prevV
Definition: NonBlockingHashMap.java:1205
com.cliffc.aa.util.NonBlockingHashMap.key
static final Object key(Object[] kvs, int idx)
Definition: NonBlockingHashMap.java:172
com.cliffc.aa.util.NonBlockingHashMap.SnapshotE._ss
final SnapshotV _ss
Definition: NonBlockingHashMap.java:1329
com.cliffc.aa.util.NonBlockingHashMap.isEmpty
boolean isEmpty()
Returns size() == 0.
Definition: NonBlockingHashMap.java:282
com.cliffc.aa.util.NonBlockingHashMap.print
final void print()
Verbose printout of table internals, useful for debugging.
Definition: NonBlockingHashMap.java:184
com.cliffc.aa.util.NonBlockingHashMap.SnapshotV._nextV
TypeV _nextV
Definition: NonBlockingHashMap.java:1205
com.cliffc.aa.util.NonBlockingHashMap.NBHMEntry.NBHMEntry
NBHMEntry(final TypeK k, final TypeV v)
Definition: NonBlockingHashMap.java:1319
com.cliffc.aa.util.NonBlockingHashMap.putIfMatch
static final Object putIfMatch(final NonBlockingHashMap topmap, final Object[] kvs, final Object key, final Object putval, final Object expVal)
Definition: NonBlockingHashMap.java:638
com.cliffc.aa.util.NonBlockingHashMap.putIfAbsent
TypeV putIfAbsent(TypeK key, TypeV val)
Atomically, do a put if-and-only-if the key is not mapped.
Definition: NonBlockingHashMap.java:318
com.cliffc.aa.util.NonBlockingHashMap.CHM.resize
final Object[] resize(NonBlockingHashMap topmap, Object[] kvs)
Definition: NonBlockingHashMap.java:885
com.cliffc.aa.util.NonBlockingHashMap.CHM._size
final ConcurrentAutoTable _size
Definition: NonBlockingHashMap.java:804
com.cliffc.aa.util.NonBlockingHashMap.SnapshotV._prevK
Object _prevK
Definition: NonBlockingHashMap.java:1204
com.cliffc.aa.util.NonBlockingHashMap.MIN_SIZE_LOG
static final int MIN_SIZE_LOG
Definition: NonBlockingHashMap.java:146
com.cliffc.aa.util.NonBlockingHashMap.putAll
void putAll(Map<? extends TypeK, ? extends TypeV > m)
Copies all of the mappings from the specified map to this one, replacing any existing mappings.
Definition: NonBlockingHashMap.java:374
com.cliffc.aa.util.NonBlockingHashMap.TOMBSTONE
static final Object TOMBSTONE
Definition: NonBlockingHashMap.java:158
com.cliffc.aa.util.NonBlockingHashMap.REPROBE_LIMIT
static final int REPROBE_LIMIT
Definition: NonBlockingHashMap.java:79
com.cliffc.aa.util.NonBlockingHashMap.containsValue
boolean containsValue(final Object val)
Returns true if this Map maps one or more keys to the specified value.
Definition: NonBlockingHashMap.java:394
com.cliffc.aa.util.NonBlockingHashMap._kvs
transient Object[] _kvs
Definition: NonBlockingHashMap.java:134
com.cliffc.aa.util.NonBlockingHashMap.NO_MATCH_OLD
static final Object NO_MATCH_OLD
Definition: NonBlockingHashMap.java:152
com.cliffc.aa.util.AbstractEntry
A simple implementation of java.util.Map.Entry.
Definition: AbstractEntry.java:15
com.cliffc.aa.util.NonBlockingHashMap.initialize
final void initialize(int initial_sz)
Definition: NonBlockingHashMap.java:259
com.cliffc.aa.util.NonBlockingHashMap.keySet
Set< TypeK > keySet()
Returns a Set view of the keys contained in this map.
Definition: NonBlockingHashMap.java:1305
com.cliffc.aa.util.NonBlockingHashMap.SnapshotK.hasNext
boolean hasNext()
Definition: NonBlockingHashMap.java:1281
com.cliffc.aa.util.NonBlockingHashMap.put
TypeV put(TypeK key, TypeV val)
Maps the specified key to the specified value in the table.
Definition: NonBlockingHashMap.java:310
com.cliffc.aa.util.NonBlockingHashMap.SnapshotV.hasMoreElements
boolean hasMoreElements()
Definition: NonBlockingHashMap.java:1241
com.cliffc.aa.util.NonBlockingHashMap.SnapshotV.val
Object val(int idx)
Definition: NonBlockingHashMap.java:1202
com.cliffc.aa.util.NonBlockingHashMap.CHM._resizers
volatile long _resizers
Definition: NonBlockingHashMap.java:850
com.cliffc.aa.util.NonBlockingHashMap.CHM.copy_slot
boolean copy_slot(NonBlockingHashMap topmap, int idx, Object[] oldkvs, Object[] newkvs)
Definition: NonBlockingHashMap.java:1119
com.cliffc.aa.util.NonBlockingHashMap.getKey
TypeK getKey()
Definition: NonBlockingHashMap.java:477
com.cliffc.aa.util.NonBlockingHashMap.CHM.copy_slot_and_check
final Object[] copy_slot_and_check(NonBlockingHashMap topmap, Object[] oldkvs, int idx, Object should_help)
Definition: NonBlockingHashMap.java:1066
com.cliffc.aa.util.NonBlockingHashMap._last_resize_milli
transient long _last_resize_milli
Definition: NonBlockingHashMap.java:141
com.cliffc.aa.util.NonBlockingHashMap.Prime.Prime
Prime(Object V)
Definition: NonBlockingHashMap.java:108
com.cliffc.aa.util.NonBlockingHashMap.putIfMatch
final TypeV putIfMatch(Object key, Object newVal, Object oldVal)
Definition: NonBlockingHashMap.java:361
com.cliffc.aa.util.NonBlockingHashMap._kvs_offset
static final long _kvs_offset
Definition: NonBlockingHashMap.java:94
com.cliffc.aa.util.NonBlockingHashMap._reprobes
transient ConcurrentAutoTable _reprobes
Definition: NonBlockingHashMap.java:228
com.cliffc.aa.util.NonBlockingHashMap.SnapshotV
Definition: NonBlockingHashMap.java:1180
com.cliffc.aa.util.NonBlockingHashMap.containsKey
boolean containsKey(Object key)
Tests if the key in the table using the equals method.
Definition: NonBlockingHashMap.java:288
com.cliffc.aa.util.ConcurrentAutoTable.estimate_get
long estimate_get()
A cheaper get.
Definition: ConcurrentAutoTable.java:60
com.cliffc.aa.util.NonBlockingHashMap.CHM._copyDone
volatile long _copyDone
Definition: NonBlockingHashMap.java:999
com.cliffc.aa.util.NonBlockingHashMap.keys
Enumeration< TypeK > keys()
Returns an enumeration of the keys in this table.
Definition: NonBlockingHashMap.java:1289
com.cliffc.aa.util.NonBlockingHashMap.SnapshotV.length
int length()
Definition: NonBlockingHashMap.java:1200
com.cliffc.aa.util.NonBlockingHashMap.SnapshotV.hasNext
boolean hasNext()
Definition: NonBlockingHashMap.java:1206
com.cliffc.aa.util.NonBlockingHashMap.initialize
final void initialize()
Definition: NonBlockingHashMap.java:271
com.cliffc.aa.util.NonBlockingHashMap.CHM._slots
final ConcurrentAutoTable _slots
Definition: NonBlockingHashMap.java:817
Cloneable
com.cliffc.aa.util.NonBlockingHashMap.NBHMEntry.setValue
TypeV setValue(final TypeV val)
Definition: NonBlockingHashMap.java:1320
com.cliffc.aa.util.NonBlockingHashMap.clear
void clear()
Removes all of the mappings from this map.
Definition: NonBlockingHashMap.java:381
com.cliffc.aa.util.NonBlockingHashMap.CHM._copyIdx
volatile long _copyIdx
Definition: NonBlockingHashMap.java:992
com.cliffc.aa.util.NonBlockingHashMap._Obase
static final int _Obase
Definition: NonBlockingHashMap.java:83
com.cliffc.aa.util.NonBlockingHashMap.hashes
static final int[] hashes(Object[] kvs)
Definition: NonBlockingHashMap.java:136
com.cliffc.aa.util.AbstractEntry._val
TypeV _val
Strongly typed value.
Definition: AbstractEntry.java:19
com.cliffc.aa.util.NonBlockingHashMap.print
final void print(Object[] kvs)
Definition: NonBlockingHashMap.java:190
com.cliffc.aa.util.NonBlockingHashMap.Prime
Definition: NonBlockingHashMap.java:106
com.cliffc.aa.util.AbstractEntry._key
final TypeK _key
Strongly typed key.
Definition: AbstractEntry.java:17
com.cliffc.aa.util.NonBlockingHashMap.CHM._copyDoneUpdater
static final AtomicLongFieldUpdater< CHM > _copyDoneUpdater
Definition: NonBlockingHashMap.java:1000
com.cliffc.aa.util.NonBlockingHashMap.size
int size()
Returns the number of key-value mappings in this map.
Definition: NonBlockingHashMap.java:278
com.cliffc.aa.util.NonBlockingHashMap.get_impl
static Object get_impl(final NonBlockingHashMap topmap, final Object[] kvs, final Object key)
Definition: NonBlockingHashMap.java:531
Enumeration
com.cliffc.aa.util.NonBlockingHashMap.SnapshotV.key
Object key(int idx)
Definition: NonBlockingHashMap.java:1201
com.cliffc.aa.util.NonBlockingHashMap.SnapshotK.hasMoreElements
boolean hasMoreElements()
Definition: NonBlockingHashMap.java:1283
com.cliffc.aa.util.NonBlockingHashMap.help_copy
final Object[] help_copy(Object[] helper)
Definition: NonBlockingHashMap.java:788
com.cliffc.aa.util.NonBlockingHashMap.CAS_val
static final boolean CAS_val(Object[] kvs, int idx, Object old, Object val)
Definition: NonBlockingHashMap.java:177
com.cliffc.aa.util.NonBlockingHashMap.raw_array
Object[] raw_array()
Definition: NonBlockingHashMap.java:1243
com.cliffc.aa.util.NonBlockingHashMap.chm
static final CHM chm(Object[] kvs)
Definition: NonBlockingHashMap.java:135
com.cliffc.aa.util.NonBlockingHashMap.clone
Object clone()
Creates a shallow copy of this hashtable.
Definition: NonBlockingHashMap.java:417
com.cliffc.aa.util.NonBlockingHashMap.hash
static int hash(final Object key)
Definition: NonBlockingHashMap.java:114
com.cliffc.aa.util.NonBlockingHashMap.CAS_key
static final boolean CAS_key(Object[] kvs, int idx, Object old, Object key)
Definition: NonBlockingHashMap.java:174
com.cliffc.aa.util.ConcurrentAutoTable.get
long get()
Current value of the counter.
Definition: ConcurrentAutoTable.java:50
com.cliffc.aa.util.NonBlockingHashMap.print2
final void print2(Object[] kvs)
Definition: NonBlockingHashMap.java:209
com.cliffc.aa.util.NonBlockingHashMap.elements
Enumeration< TypeV > elements()
Returns an enumeration of the values in this table.
Definition: NonBlockingHashMap.java:1248
com.cliffc.aa.util.NonBlockingHashMap.readObject
void readObject(java.io.ObjectInputStream s)
Definition: NonBlockingHashMap.java:1393
com.cliffc.aa.util.NonBlockingHashMap.SnapshotK.SnapshotK
SnapshotK()
Definition: NonBlockingHashMap.java:1278
com.cliffc.aa.util.NonBlockingHashMap.SnapshotE.hasNext
boolean hasNext()
Definition: NonBlockingHashMap.java:1333
com.cliffc.aa.util.NonBlockingHashMap.CHM._newkvs
volatile Object[] _newkvs
Definition: NonBlockingHashMap.java:827
com.cliffc.aa.util.NonBlockingHashMap.MIN_SIZE
static final int MIN_SIZE
Definition: NonBlockingHashMap.java:147
com.cliffc.aa.util.NonBlockingHashMap.NBHMEntry
Definition: NonBlockingHashMap.java:1318
com.cliffc.aa.util.NonBlockingHashMap.MATCH_ANY
static final Object MATCH_ANY
Definition: NonBlockingHashMap.java:155
com.cliffc.aa.util.NonBlockingHashMap.getk_impl
static final Object getk_impl(final NonBlockingHashMap topmap, final Object[] kvs, final Object key)
Definition: NonBlockingHashMap.java:589