• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.collect;
18 
19 import com.google.common.annotations.GwtCompatible;
20 import com.google.common.annotations.GwtIncompatible;
21 import com.google.common.base.FinalizableReferenceQueue;
22 import com.google.common.base.FinalizableSoftReference;
23 import com.google.common.base.FinalizableWeakReference;
24 import com.google.common.base.Function;
25 import com.google.common.collect.CustomConcurrentHashMap.ComputingStrategy;
26 import com.google.common.collect.CustomConcurrentHashMap.Internals;
27 
28 import java.io.IOException;
29 import java.io.ObjectInputStream;
30 import java.io.ObjectOutputStream;
31 import java.io.Serializable;
32 import java.lang.ref.SoftReference;
33 import java.lang.ref.WeakReference;
34 import java.lang.reflect.Field;
35 import java.util.Map;
36 import java.util.TimerTask;
37 import java.util.concurrent.ConcurrentHashMap;
38 import java.util.concurrent.ConcurrentMap;
39 import java.util.concurrent.TimeUnit;
40 
41 /**
42  * A {@link ConcurrentMap} builder, providing any combination of these
43  * features: {@linkplain SoftReference soft} or {@linkplain WeakReference
44  * weak} keys, soft or weak values, timed expiration, and on-demand
45  * computation of values. Usage example: <pre> {@code
46  *
47  *   ConcurrentMap<Key, Graph> graphs = new MapMaker()
48  *       .concurrencyLevel(32)
49  *       .softKeys()
50  *       .weakValues()
51  *       .expiration(30, TimeUnit.MINUTES)
52  *       .makeComputingMap(
53  *           new Function<Key, Graph>() {
54  *             public Graph apply(Key key) {
55  *               return createExpensiveGraph(key);
56  *             }
57  *           });}</pre>
58  *
59  * These features are all optional; {@code new MapMaker().makeMap()}
60  * returns a valid concurrent map that behaves exactly like a
61  * {@link ConcurrentHashMap}.
62  *
63  * The returned map is implemented as a hash table with similar performance
64  * characteristics to {@link ConcurrentHashMap}. It supports all optional
65  * operations of the {@code ConcurrentMap} interface. It does not permit
66  * null keys or values. It is serializable; however, serializing a map that
67  * uses soft or weak references can give unpredictable results.
68  *
69  * <p><b>Note:</b> by default, the returned map uses equality comparisons
70  * (the {@link Object#equals(Object) equals} method) to determine equality
71  * for keys or values. However, if {@link #weakKeys()} or {@link
72  * #softKeys()} was specified, the map uses identity ({@code ==})
73  * comparisons instead for keys. Likewise, if {@link #weakValues()} or
74  * {@link #softValues()} was specified, the map uses identity comparisons
75  * for values.
76  *
77  * <p>The returned map has <i>weakly consistent iteration</i>: an iterator
78  * over one of the map's view collections may reflect some, all or none of
79  * the changes made to the map after the iterator was created.
80  *
81  * <p>An entry whose key or value is reclaimed by the garbage collector
82  * immediately disappears from the map. (If the default settings of strong
83  * keys and strong values are used, this will never happen.) The client can
84  * never observe a partially-reclaimed entry. Any {@link java.util.Map.Entry}
85  * instance retrieved from the map's {@linkplain Map#entrySet() entry set}
86  * is snapshot of that entry's state at the time of retrieval.
87  *
88  * <p>{@code new MapMaker().weakKeys().makeMap()} can almost always be
89  * used as a drop-in replacement for {@link java.util.WeakHashMap}, adding
90  * concurrency, asynchronous cleanup, identity-based equality for keys, and
91  * great flexibility.
92  *
93  * @author Bob Lee
94  * @author Kevin Bourrillion
95  * @since 2010.01.04 <b>stable</b> (imported from Google Collections Library)
96  */
97 @GwtCompatible(emulated = true)
98 public final class MapMaker {
99   private Strength keyStrength = Strength.STRONG;
100   private Strength valueStrength = Strength.STRONG;
101   private long expirationNanos = 0;
102   private boolean useCustomMap;
103   private final CustomConcurrentHashMap.Builder builder
104       = new CustomConcurrentHashMap.Builder();
105 
106   /**
107    * Constructs a new {@code MapMaker} instance with default settings,
108    * including strong keys, strong values, and no automatic expiration.
109    */
MapMaker()110   public MapMaker() {}
111 
112   /**
113    * Sets a custom initial capacity (defaults to 16). Resizing this or
114    * any other kind of hash table is a relatively slow operation, so,
115    * when possible, it is a good idea to provide estimates of expected
116    * table sizes.
117    *
118    * @throws IllegalArgumentException if {@code initialCapacity} is
119    *   negative
120    * @throws IllegalStateException if an initial capacity was already set
121    */
initialCapacity(int initialCapacity)122   public MapMaker initialCapacity(int initialCapacity) {
123     builder.initialCapacity(initialCapacity);
124     return this;
125   }
126 
127   /**
128    * Guides the allowed concurrency among update operations. Used as a
129    * hint for internal sizing. The table is internally partitioned to try
130    * to permit the indicated number of concurrent updates without
131    * contention.  Because placement in hash tables is essentially random,
132    * the actual concurrency will vary. Ideally, you should choose a value
133    * to accommodate as many threads as will ever concurrently modify the
134    * table. Using a significantly higher value than you need can waste
135    * space and time, and a significantly lower value can lead to thread
136    * contention. But overestimates and underestimates within an order of
137    * magnitude do not usually have much noticeable impact. A value of one
138    * is appropriate when it is known that only one thread will modify and
139    * all others will only read. Defaults to 16.
140    *
141    * @throws IllegalArgumentException if {@code concurrencyLevel} is
142    *     nonpositive
143    * @throws IllegalStateException if a concurrency level was already set
144    */
145   @GwtIncompatible("java.util.concurrent.ConcurrentHashMap concurrencyLevel")
concurrencyLevel(int concurrencyLevel)146   public MapMaker concurrencyLevel(int concurrencyLevel) {
147     builder.concurrencyLevel(concurrencyLevel);
148     return this;
149   }
150 
151   /**
152    * Specifies that each key (not value) stored in the map should be
153    * wrapped in a {@link WeakReference} (by default, strong references
154    * are used).
155    *
156    * <p><b>Note:</b> the map will use identity ({@code ==}) comparison
157    * to determine equality of weak keys, which may not behave as you expect.
158    * For example, storing a key in the map and then attempting a lookup
159    * using a different but {@link Object#equals(Object) equals}-equivalent
160    * key will always fail.
161    *
162    * @throws IllegalStateException if the key strength was already set
163    * @see WeakReference
164    */
165   @GwtIncompatible("java.lang.ref.WeakReference")
weakKeys()166   public MapMaker weakKeys() {
167     return setKeyStrength(Strength.WEAK);
168   }
169 
170   /**
171    * Specifies that each key (not value) stored in the map should be
172    * wrapped in a {@link SoftReference} (by default, strong references
173    * are used).
174    *
175    * <p><b>Note:</b> the map will use identity ({@code ==}) comparison
176    * to determine equality of soft keys, which may not behave as you expect.
177    * For example, storing a key in the map and then attempting a lookup
178    * using a different but {@link Object#equals(Object) equals}-equivalent
179    * key will always fail.
180    *
181    * @throws IllegalStateException if the key strength was already set
182    * @see SoftReference
183    */
184   @GwtIncompatible("java.lang.ref.SoftReference")
softKeys()185   public MapMaker softKeys() {
186     return setKeyStrength(Strength.SOFT);
187   }
188 
setKeyStrength(Strength strength)189   private MapMaker setKeyStrength(Strength strength) {
190     if (keyStrength != Strength.STRONG) {
191       throw new IllegalStateException("Key strength was already set to "
192           + keyStrength + ".");
193     }
194     keyStrength = strength;
195     useCustomMap = true;
196     return this;
197   }
198 
199   /**
200    * Specifies that each value (not key) stored in the map should be
201    * wrapped in a {@link WeakReference} (by default, strong references
202    * are used).
203    *
204    * <p>Weak values will be garbage collected once they are weakly
205    * reachable. This makes them a poor candidate for caching; consider
206    * {@link #softValues()} instead.
207    *
208    * <p><b>Note:</b> the map will use identity ({@code ==}) comparison
209    * to determine equality of weak values. This will notably impact
210    * the behavior of {@link Map#containsValue(Object) containsValue},
211    * {@link ConcurrentMap#remove(Object, Object) remove(Object, Object)},
212    * and {@link ConcurrentMap#replace(Object, Object, Object) replace(K, V, V)}.
213    *
214    * @throws IllegalStateException if the key strength was already set
215    * @see WeakReference
216    */
217   @GwtIncompatible("java.lang.ref.WeakReference")
weakValues()218   public MapMaker weakValues() {
219     return setValueStrength(Strength.WEAK);
220   }
221 
222   /**
223    * Specifies that each value (not key) stored in the map should be
224    * wrapped in a {@link SoftReference} (by default, strong references
225    * are used).
226    *
227    * <p>Soft values will be garbage collected in response to memory
228    * demand, and in a least-recently-used manner. This makes them a
229    * good candidate for caching.
230    *
231    * <p><b>Note:</b> the map will use identity ({@code ==}) comparison
232    * to determine equality of soft values. This will notably impact
233    * the behavior of {@link Map#containsValue(Object) containsValue},
234    * {@link ConcurrentMap#remove(Object, Object) remove(Object, Object)},
235    * and {@link ConcurrentMap#replace(Object, Object, Object) replace(K, V, V)}.
236    *
237    * @throws IllegalStateException if the value strength was already set
238    * @see SoftReference
239    */
240   @GwtIncompatible("java.lang.ref.SoftReference")
softValues()241   public MapMaker softValues() {
242     return setValueStrength(Strength.SOFT);
243   }
244 
setValueStrength(Strength strength)245   private MapMaker setValueStrength(Strength strength) {
246     if (valueStrength != Strength.STRONG) {
247       throw new IllegalStateException("Value strength was already set to "
248           + valueStrength + ".");
249     }
250     valueStrength = strength;
251     useCustomMap = true;
252     return this;
253   }
254 
255   /**
256    * Specifies that each entry should be automatically removed from the
257    * map once a fixed duration has passed since the entry's creation.
258    *
259    * @param duration the length of time after an entry is created that it
260    *     should be automatically removed
261    * @param unit the unit that {@code duration} is expressed in
262    * @throws IllegalArgumentException if {@code duration} is not positive
263    * @throws IllegalStateException if the expiration time was already set
264    */
expiration(long duration, TimeUnit unit)265   public MapMaker expiration(long duration, TimeUnit unit) {
266     if (expirationNanos != 0) {
267       throw new IllegalStateException("expiration time of "
268           + expirationNanos + " ns was already set");
269     }
270     if (duration <= 0) {
271       throw new IllegalArgumentException("invalid duration: " + duration);
272     }
273     this.expirationNanos = unit.toNanos(duration);
274     useCustomMap = true;
275     return this;
276   }
277 
278   /**
279    * Builds the final map, without on-demand computation of values. This method
280    * does not alter the state of this {@code MapMaker} instance, so it can be
281    * invoked again to create multiple independent maps.
282    *
283    * @param <K> the type of keys to be stored in the returned map
284    * @param <V> the type of values to be stored in the returned map
285    * @return a concurrent map having the requested features
286    */
makeMap()287   public <K, V> ConcurrentMap<K, V> makeMap() {
288     return useCustomMap
289         ? new StrategyImpl<K, V>(this).map
290         : new ConcurrentHashMap<K, V>(builder.getInitialCapacity(),
291             0.75f, builder.getConcurrencyLevel());
292   }
293 
294   /**
295    * Builds a map that supports atomic, on-demand computation of values. {@link
296    * Map#get} either returns an already-computed value for the given key,
297    * atomically computes it using the supplied function, or, if another thread
298    * is currently computing the value for this key, simply waits for that thread
299    * to finish and returns its computed value. Note that the function may be
300    * executed concurrently by multiple threads, but only for distinct keys.
301    *
302    * <p>If an entry's value has not finished computing yet, query methods
303    * besides {@code get} return immediately as if an entry doesn't exist. In
304    * other words, an entry isn't externally visible until the value's
305    * computation completes.
306    *
307    * <p>{@link Map#get} on the returned map will never return {@code null}. It
308    * may throw:
309    *
310    * <ul>
311    * <li>{@link NullPointerException} if the key is null or the computing
312    *     function returns null
313    * <li>{@link ComputationException} if an exception was thrown by the
314    *     computing function. If that exception is already of type {@link
315    *     ComputationException}, it is propagated directly; otherwise it is
316    *     wrapped.
317    * </ul>
318    *
319    * <p><b>Note:</b> Callers of {@code get} <i>must</i> ensure that the key
320    * argument is of type {@code K}. The {@code get} method accepts {@code
321    * Object}, so the key type is not checked at compile time. Passing an object
322    * of a type other than {@code K} can result in that object being unsafely
323    * passed to the computing function as type {@code K}, and unsafely stored in
324    * the map.
325    *
326    * <p>If {@link Map#put} is called before a computation completes, other
327    * threads waiting on the computation will wake up and return the stored
328    * value. When the computation completes, its new result will overwrite the
329    * value that was put in the map manually.
330    *
331    * <p>This method does not alter the state of this {@code MapMaker} instance,
332    * so it can be invoked again to create multiple independent maps.
333    */
makeComputingMap( Function<? super K, ? extends V> computingFunction)334   public <K, V> ConcurrentMap<K, V> makeComputingMap(
335       Function<? super K, ? extends V> computingFunction) {
336     return new StrategyImpl<K, V>(this, computingFunction).map;
337   }
338 
339   // Remainder of this file is private implementation details
340 
341   private enum Strength {
342     WEAK {
equal(Object a, Object b)343       @Override boolean equal(Object a, Object b) {
344         return a == b;
345       }
hash(Object o)346       @Override int hash(Object o) {
347         return System.identityHashCode(o);
348       }
referenceValue( ReferenceEntry<K, V> entry, V value)349       @Override <K, V> ValueReference<K, V> referenceValue(
350           ReferenceEntry<K, V> entry, V value) {
351         return new WeakValueReference<K, V>(value, entry);
352       }
newEntry( Internals<K, V, ReferenceEntry<K, V>> internals, K key, int hash, ReferenceEntry<K, V> next)353       @Override <K, V> ReferenceEntry<K, V> newEntry(
354           Internals<K, V, ReferenceEntry<K, V>> internals, K key,
355           int hash, ReferenceEntry<K, V> next) {
356         return (next == null)
357             ? new WeakEntry<K, V>(internals, key, hash)
358             : new LinkedWeakEntry<K, V>(internals, key, hash, next);
359       }
copyEntry( K key, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext)360       @Override <K, V> ReferenceEntry<K, V> copyEntry(
361           K key, ReferenceEntry<K, V> original,
362           ReferenceEntry<K, V> newNext) {
363         WeakEntry<K, V> from = (WeakEntry<K, V>) original;
364         return (newNext == null)
365             ? new WeakEntry<K, V>(from.internals, key, from.hash)
366             : new LinkedWeakEntry<K, V>(
367                 from.internals, key, from.hash, newNext);
368       }
369     },
370 
371     SOFT {
equal(Object a, Object b)372       @Override boolean equal(Object a, Object b) {
373         return a == b;
374       }
hash(Object o)375       @Override int hash(Object o) {
376         return System.identityHashCode(o);
377       }
referenceValue( ReferenceEntry<K, V> entry, V value)378       @Override <K, V> ValueReference<K, V> referenceValue(
379           ReferenceEntry<K, V> entry, V value) {
380         return new SoftValueReference<K, V>(value, entry);
381       }
newEntry( Internals<K, V, ReferenceEntry<K, V>> internals, K key, int hash, ReferenceEntry<K, V> next)382       @Override <K, V> ReferenceEntry<K, V> newEntry(
383           Internals<K, V, ReferenceEntry<K, V>> internals, K key,
384           int hash, ReferenceEntry<K, V> next) {
385         return (next == null)
386             ? new SoftEntry<K, V>(internals, key, hash)
387             : new LinkedSoftEntry<K, V>(internals, key, hash, next);
388       }
copyEntry( K key, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext)389       @Override <K, V> ReferenceEntry<K, V> copyEntry(
390           K key, ReferenceEntry<K, V> original,
391           ReferenceEntry<K, V> newNext) {
392         SoftEntry<K, V> from = (SoftEntry<K, V>) original;
393         return (newNext == null)
394             ? new SoftEntry<K, V>(from.internals, key, from.hash)
395             : new LinkedSoftEntry<K, V>(
396                 from.internals, key, from.hash, newNext);
397       }
398     },
399 
400     STRONG {
equal(Object a, Object b)401       @Override boolean equal(Object a, Object b) {
402         return a.equals(b);
403       }
hash(Object o)404       @Override int hash(Object o) {
405         return o.hashCode();
406       }
referenceValue( ReferenceEntry<K, V> entry, V value)407       @Override <K, V> ValueReference<K, V> referenceValue(
408           ReferenceEntry<K, V> entry, V value) {
409         return new StrongValueReference<K, V>(value);
410       }
newEntry( Internals<K, V, ReferenceEntry<K, V>> internals, K key, int hash, ReferenceEntry<K, V> next)411       @Override <K, V> ReferenceEntry<K, V> newEntry(
412           Internals<K, V, ReferenceEntry<K, V>> internals, K key,
413           int hash, ReferenceEntry<K, V> next) {
414         return (next == null)
415             ? new StrongEntry<K, V>(internals, key, hash)
416             : new LinkedStrongEntry<K, V>(
417                 internals, key, hash, next);
418       }
copyEntry( K key, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext)419       @Override <K, V> ReferenceEntry<K, V> copyEntry(
420           K key, ReferenceEntry<K, V> original,
421           ReferenceEntry<K, V> newNext) {
422         StrongEntry<K, V> from = (StrongEntry<K, V>) original;
423         return (newNext == null)
424             ? new StrongEntry<K, V>(from.internals, key, from.hash)
425             : new LinkedStrongEntry<K, V>(
426                 from.internals, key, from.hash, newNext);
427       }
428     };
429 
430     /**
431      * Determines if two keys or values are equal according to this
432      * strength strategy.
433      */
equal(Object a, Object b)434     abstract boolean equal(Object a, Object b);
435 
436     /**
437      * Hashes a key according to this strategy.
438      */
hash(Object o)439     abstract int hash(Object o);
440 
441     /**
442      * Creates a reference for the given value according to this value
443      * strength.
444      */
referenceValue( ReferenceEntry<K, V> entry, V value)445     abstract <K, V> ValueReference<K, V> referenceValue(
446         ReferenceEntry<K, V> entry, V value);
447 
448     /**
449      * Creates a new entry based on the current key strength.
450      */
newEntry( Internals<K, V, ReferenceEntry<K, V>> internals, K key, int hash, ReferenceEntry<K, V> next)451     abstract <K, V> ReferenceEntry<K, V> newEntry(
452         Internals<K, V, ReferenceEntry<K, V>> internals, K key,
453         int hash, ReferenceEntry<K, V> next);
454 
455     /**
456      * Creates a new entry and copies the value and other state from an
457      * existing entry.
458      */
copyEntry(K key, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext)459     abstract <K, V> ReferenceEntry<K, V> copyEntry(K key,
460         ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext);
461   }
462 
463   private static class StrategyImpl<K, V> implements Serializable,
464       ComputingStrategy<K, V, ReferenceEntry<K, V>> {
465     final Strength keyStrength;
466     final Strength valueStrength;
467     final ConcurrentMap<K, V> map;
468     final long expirationNanos;
469     Internals<K, V, ReferenceEntry<K, V>> internals;
470 
StrategyImpl(MapMaker maker)471     StrategyImpl(MapMaker maker) {
472       this.keyStrength = maker.keyStrength;
473       this.valueStrength = maker.valueStrength;
474       this.expirationNanos = maker.expirationNanos;
475 
476       map = maker.builder.buildMap(this);
477     }
478 
StrategyImpl( MapMaker maker, Function<? super K, ? extends V> computer)479     StrategyImpl(
480         MapMaker maker, Function<? super K, ? extends V> computer) {
481       this.keyStrength = maker.keyStrength;
482       this.valueStrength = maker.valueStrength;
483       this.expirationNanos = maker.expirationNanos;
484 
485       map = maker.builder.buildComputingMap(this, computer);
486     }
487 
setValue(ReferenceEntry<K, V> entry, V value)488     public void setValue(ReferenceEntry<K, V> entry, V value) {
489       setValueReference(
490           entry, valueStrength.referenceValue(entry, value));
491       if (expirationNanos > 0) {
492         scheduleRemoval(entry.getKey(), value);
493       }
494     }
495 
scheduleRemoval(K key, V value)496     void scheduleRemoval(K key, V value) {
497       /*
498        * TODO: Keep weak reference to map, too. Build a priority
499        * queue out of the entries themselves instead of creating a
500        * task per entry. Then, we could have one recurring task per
501        * map (which would clean the entire map and then reschedule
502        * itself depending upon when the next expiration comes). We
503        * also want to avoid removing an entry prematurely if the
504        * entry was set to the same value again.
505        */
506       final WeakReference<K> keyReference = new WeakReference<K>(key);
507       final WeakReference<V> valueReference = new WeakReference<V>(value);
508       ExpirationTimer.instance.schedule(
509           new TimerTask() {
510             @Override public void run() {
511               K key = keyReference.get();
512               if (key != null) {
513                 // Remove if the value is still the same.
514                 map.remove(key, valueReference.get());
515               }
516             }
517           }, TimeUnit.NANOSECONDS.toMillis(expirationNanos));
518     }
519 
equalKeys(K a, Object b)520     public boolean equalKeys(K a, Object b) {
521       return keyStrength.equal(a, b);
522     }
523 
equalValues(V a, Object b)524     public boolean equalValues(V a, Object b) {
525       return valueStrength.equal(a, b);
526     }
527 
hashKey(Object key)528     public int hashKey(Object key) {
529       return keyStrength.hash(key);
530     }
531 
getKey(ReferenceEntry<K, V> entry)532     public K getKey(ReferenceEntry<K, V> entry) {
533       return entry.getKey();
534     }
535 
getHash(ReferenceEntry<K, V> entry)536     public int getHash(ReferenceEntry<K, V> entry) {
537       return entry.getHash();
538     }
539 
newEntry( K key, int hash, ReferenceEntry<K, V> next)540     public ReferenceEntry<K, V> newEntry(
541         K key, int hash, ReferenceEntry<K, V> next) {
542       return keyStrength.newEntry(internals, key, hash, next);
543     }
544 
copyEntry(K key, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext)545     public ReferenceEntry<K, V> copyEntry(K key,
546         ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
547       ValueReference<K, V> valueReference = original.getValueReference();
548       if (valueReference == COMPUTING) {
549         ReferenceEntry<K, V> newEntry
550             = newEntry(key, original.getHash(), newNext);
551         newEntry.setValueReference(
552             new FutureValueReference(original, newEntry));
553         return newEntry;
554       } else {
555         ReferenceEntry<K, V> newEntry
556             = newEntry(key, original.getHash(), newNext);
557         newEntry.setValueReference(valueReference.copyFor(newEntry));
558         return newEntry;
559       }
560     }
561 
562     /**
563      * Waits for a computation to complete. Returns the result of the
564      * computation or null if none was available.
565      */
waitForValue(ReferenceEntry<K, V> entry)566     public V waitForValue(ReferenceEntry<K, V> entry)
567         throws InterruptedException {
568       ValueReference<K, V> valueReference = entry.getValueReference();
569       if (valueReference == COMPUTING) {
570         synchronized (entry) {
571           while ((valueReference = entry.getValueReference())
572               == COMPUTING) {
573             entry.wait();
574           }
575         }
576       }
577       return valueReference.waitForValue();
578     }
579 
580     /**
581      * Used by CustomConcurrentHashMap to retrieve values. Returns null
582      * instead of blocking or throwing an exception.
583      */
getValue(ReferenceEntry<K, V> entry)584     public V getValue(ReferenceEntry<K, V> entry) {
585       ValueReference<K, V> valueReference = entry.getValueReference();
586       return valueReference.get();
587     }
588 
compute(K key, final ReferenceEntry<K, V> entry, Function<? super K, ? extends V> computer)589     public V compute(K key, final ReferenceEntry<K, V> entry,
590         Function<? super K, ? extends V> computer) {
591       V value;
592       try {
593         value = computer.apply(key);
594       } catch (ComputationException e) {
595         // if computer has thrown a computation exception, propagate rather
596         // than wrap
597         setValueReference(entry,
598             new ComputationExceptionReference<K, V>(e.getCause()));
599         throw e;
600       } catch (Throwable t) {
601         setValueReference(
602           entry, new ComputationExceptionReference<K, V>(t));
603         throw new ComputationException(t);
604       }
605 
606       if (value == null) {
607         String message
608             = computer + " returned null for key " + key + ".";
609         setValueReference(
610             entry, new NullOutputExceptionReference<K, V>(message));
611         throw new NullOutputException(message);
612       } else {
613         setValue(entry, value);
614       }
615       return value;
616     }
617 
618     /**
619      * Sets the value reference on an entry and notifies waiting
620      * threads.
621      */
setValueReference(ReferenceEntry<K, V> entry, ValueReference<K, V> valueReference)622     void setValueReference(ReferenceEntry<K, V> entry,
623         ValueReference<K, V> valueReference) {
624       boolean notifyOthers = (entry.getValueReference() == COMPUTING);
625       entry.setValueReference(valueReference);
626       if (notifyOthers) {
627         synchronized (entry) {
628           entry.notifyAll();
629         }
630       }
631     }
632 
633     /**
634      * Points to an old entry where a value is being computed. Used to
635      * support non-blocking copying of entries during table expansion,
636      * removals, etc.
637      */
638     private class FutureValueReference implements ValueReference<K, V> {
639       final ReferenceEntry<K, V> original;
640       final ReferenceEntry<K, V> newEntry;
641 
FutureValueReference( ReferenceEntry<K, V> original, ReferenceEntry<K, V> newEntry)642       FutureValueReference(
643           ReferenceEntry<K, V> original, ReferenceEntry<K, V> newEntry) {
644         this.original = original;
645         this.newEntry = newEntry;
646       }
647 
get()648       public V get() {
649         boolean success = false;
650         try {
651           V value = original.getValueReference().get();
652           success = true;
653           return value;
654         } finally {
655           if (!success) {
656             removeEntry();
657           }
658         }
659       }
660 
copyFor(ReferenceEntry<K, V> entry)661       public ValueReference<K, V> copyFor(ReferenceEntry<K, V> entry) {
662         return new FutureValueReference(original, entry);
663       }
664 
waitForValue()665       public V waitForValue() throws InterruptedException {
666         boolean success = false;
667         try {
668           // assert that key != null
669           V value = StrategyImpl.this.waitForValue(original);
670           success = true;
671           return value;
672         } finally {
673           if (!success) {
674             removeEntry();
675           }
676         }
677       }
678 
679       /**
680        * Removes the entry in the event of an exception. Ideally,
681        * we'd clean up as soon as the computation completes, but we
682        * can't do that without keeping a reference to this entry from
683        * the original.
684        */
removeEntry()685       void removeEntry() {
686         internals.removeEntry(newEntry);
687       }
688     }
689 
getNext( ReferenceEntry<K, V> entry)690     public ReferenceEntry<K, V> getNext(
691         ReferenceEntry<K, V> entry) {
692       return entry.getNext();
693     }
694 
setInternals( Internals<K, V, ReferenceEntry<K, V>> internals)695     public void setInternals(
696         Internals<K, V, ReferenceEntry<K, V>> internals) {
697       this.internals = internals;
698     }
699 
700     private static final long serialVersionUID = 0;
701 
writeObject(ObjectOutputStream out)702     private void writeObject(ObjectOutputStream out)
703         throws IOException {
704       // Custom serialization code ensures that the key and value
705       // strengths are written before the map. We'll need them to
706       // deserialize the map entries.
707       out.writeObject(keyStrength);
708       out.writeObject(valueStrength);
709       out.writeLong(expirationNanos);
710 
711       // TODO: It is possible for the strategy to try to use the map
712       // or internals during deserialization, for example, if an
713       // entry gets reclaimed. We could detect this case and queue up
714       // removals to be flushed after we deserialize the map.
715       out.writeObject(internals);
716       out.writeObject(map);
717     }
718 
719     /**
720      * Fields used during deserialization. We use a nested class so we
721      * don't load them until we need them. We need to use reflection to
722      * set final fields outside of the constructor.
723      */
724     private static class Fields {
725       static final Field keyStrength = findField("keyStrength");
726       static final Field valueStrength = findField("valueStrength");
727       static final Field expirationNanos = findField("expirationNanos");
728       static final Field internals = findField("internals");
729       static final Field map = findField("map");
730 
findField(String name)731       static Field findField(String name) {
732         try {
733           Field f = StrategyImpl.class.getDeclaredField(name);
734           f.setAccessible(true);
735           return f;
736         } catch (NoSuchFieldException e) {
737           throw new AssertionError(e);
738         }
739       }
740     }
741 
readObject(ObjectInputStream in)742     private void readObject(ObjectInputStream in)
743         throws IOException, ClassNotFoundException {
744       try {
745         Fields.keyStrength.set(this, in.readObject());
746         Fields.valueStrength.set(this, in.readObject());
747         Fields.expirationNanos.set(this, in.readLong());
748         Fields.internals.set(this, in.readObject());
749         Fields.map.set(this, in.readObject());
750       } catch (IllegalAccessException e) {
751         throw new AssertionError(e);
752       }
753     }
754   }
755 
756   /** A reference to a value. */
757   private interface ValueReference<K, V> {
758     /**
759      * Gets the value. Does not block or throw exceptions.
760      */
get()761     V get();
762 
763     /** Creates a copy of this reference for the given entry. */
copyFor(ReferenceEntry<K, V> entry)764     ValueReference<K, V> copyFor(ReferenceEntry<K, V> entry);
765 
766     /**
767      * Waits for a value that may still be computing. Unlike get(),
768      * this method can block (in the case of FutureValueReference) or
769      * throw an exception.
770      */
waitForValue()771     V waitForValue() throws InterruptedException;
772   }
773 
774   private static final ValueReference<Object, Object> COMPUTING
775       = new ValueReference<Object, Object>() {
776     public Object get() {
777       return null;
778     }
779     public ValueReference<Object, Object> copyFor(
780         ReferenceEntry<Object, Object> entry) {
781       throw new AssertionError();
782     }
783     public Object waitForValue() {
784       throw new AssertionError();
785     }
786   };
787 
788   /**
789    * Singleton placeholder that indicates a value is being computed.
790    */
791   @SuppressWarnings("unchecked")
792   // Safe because impl never uses a parameter or returns any non-null value
computing()793   private static <K, V> ValueReference<K, V> computing() {
794     return (ValueReference<K, V>) COMPUTING;
795   }
796 
797   /** Used to provide null output exceptions to other threads. */
798   private static class NullOutputExceptionReference<K, V>
799       implements ValueReference<K, V> {
800     final String message;
NullOutputExceptionReference(String message)801     NullOutputExceptionReference(String message) {
802       this.message = message;
803     }
get()804     public V get() {
805       return null;
806     }
copyFor( ReferenceEntry<K, V> entry)807     public ValueReference<K, V> copyFor(
808         ReferenceEntry<K, V> entry) {
809       return this;
810     }
waitForValue()811     public V waitForValue() {
812       throw new NullOutputException(message);
813     }
814   }
815 
816   /** Used to provide computation exceptions to other threads. */
817   private static class ComputationExceptionReference<K, V>
818       implements ValueReference<K, V> {
819     final Throwable t;
ComputationExceptionReference(Throwable t)820     ComputationExceptionReference(Throwable t) {
821       this.t = t;
822     }
get()823     public V get() {
824       return null;
825     }
copyFor( ReferenceEntry<K, V> entry)826     public ValueReference<K, V> copyFor(
827         ReferenceEntry<K, V> entry) {
828       return this;
829     }
waitForValue()830     public V waitForValue() {
831       throw new AsynchronousComputationException(t);
832     }
833   }
834 
835   /** Wrapper class ensures that queue isn't created until it's used. */
836   private static class QueueHolder {
837     static final FinalizableReferenceQueue queue
838         = new FinalizableReferenceQueue();
839   }
840 
841   /**
842    * An entry in a reference map.
843    */
844   private interface ReferenceEntry<K, V> {
845     /**
846      * Gets the value reference from this entry.
847      */
getValueReference()848     ValueReference<K, V> getValueReference();
849 
850     /**
851      * Sets the value reference for this entry.
852      *
853      * @param valueReference
854      */
setValueReference(ValueReference<K, V> valueReference)855     void setValueReference(ValueReference<K, V> valueReference);
856 
857     /**
858      * Removes this entry from the map if its value reference hasn't
859      * changed.  Used to clean up after values. The value reference can
860      * just call this method on the entry so it doesn't have to keep
861      * its own reference to the map.
862      */
valueReclaimed()863     void valueReclaimed();
864 
865     /** Gets the next entry in the chain. */
getNext()866     ReferenceEntry<K, V> getNext();
867 
868     /** Gets the entry's hash. */
getHash()869     int getHash();
870 
871     /** Gets the key for this entry. */
getKey()872     public K getKey();
873   }
874 
875   /**
876    * Used for strongly-referenced keys.
877    */
878   private static class StrongEntry<K, V> implements ReferenceEntry<K, V> {
879     final K key;
880 
StrongEntry(Internals<K, V, ReferenceEntry<K, V>> internals, K key, int hash)881     StrongEntry(Internals<K, V, ReferenceEntry<K, V>> internals, K key,
882         int hash) {
883       this.internals = internals;
884       this.key = key;
885       this.hash = hash;
886     }
887 
getKey()888     public K getKey() {
889       return this.key;
890     }
891 
892     // The code below is exactly the same for each entry type.
893 
894     final Internals<K, V, ReferenceEntry<K, V>> internals;
895     final int hash;
896     volatile ValueReference<K, V> valueReference = computing();
897 
getValueReference()898     public ValueReference<K, V> getValueReference() {
899       return valueReference;
900     }
setValueReference( ValueReference<K, V> valueReference)901     public void setValueReference(
902         ValueReference<K, V> valueReference) {
903       this.valueReference = valueReference;
904     }
valueReclaimed()905     public void valueReclaimed() {
906       internals.removeEntry(this, null);
907     }
getNext()908     public ReferenceEntry<K, V> getNext() {
909       return null;
910     }
getHash()911     public int getHash() {
912       return hash;
913     }
914   }
915 
916   private static class LinkedStrongEntry<K, V> extends StrongEntry<K, V> {
917 
LinkedStrongEntry(Internals<K, V, ReferenceEntry<K, V>> internals, K key, int hash, ReferenceEntry<K, V> next)918     LinkedStrongEntry(Internals<K, V, ReferenceEntry<K, V>> internals,
919         K key, int hash, ReferenceEntry<K, V> next) {
920       super(internals, key, hash);
921       this.next = next;
922     }
923 
924     final ReferenceEntry<K, V> next;
925 
getNext()926     @Override public ReferenceEntry<K, V> getNext() {
927       return next;
928     }
929   }
930 
931   /**
932    * Used for softly-referenced keys.
933    */
934   private static class SoftEntry<K, V> extends FinalizableSoftReference<K>
935       implements ReferenceEntry<K, V> {
SoftEntry(Internals<K, V, ReferenceEntry<K, V>> internals, K key, int hash)936     SoftEntry(Internals<K, V, ReferenceEntry<K, V>> internals, K key,
937         int hash) {
938       super(key, QueueHolder.queue);
939       this.internals = internals;
940       this.hash = hash;
941     }
942 
getKey()943     public K getKey() {
944       return get();
945     }
946 
finalizeReferent()947     public void finalizeReferent() {
948       internals.removeEntry(this);
949     }
950 
951     // The code below is exactly the same for each entry type.
952 
953     final Internals<K, V, ReferenceEntry<K, V>> internals;
954     final int hash;
955     volatile ValueReference<K, V> valueReference = computing();
956 
getValueReference()957     public ValueReference<K, V> getValueReference() {
958       return valueReference;
959     }
setValueReference( ValueReference<K, V> valueReference)960     public void setValueReference(
961         ValueReference<K, V> valueReference) {
962       this.valueReference = valueReference;
963     }
valueReclaimed()964     public void valueReclaimed() {
965       internals.removeEntry(this, null);
966     }
getNext()967     public ReferenceEntry<K, V> getNext() {
968       return null;
969     }
getHash()970     public int getHash() {
971       return hash;
972     }
973   }
974 
975   private static class LinkedSoftEntry<K, V> extends SoftEntry<K, V> {
LinkedSoftEntry(Internals<K, V, ReferenceEntry<K, V>> internals, K key, int hash, ReferenceEntry<K, V> next)976     LinkedSoftEntry(Internals<K, V, ReferenceEntry<K, V>> internals,
977         K key, int hash, ReferenceEntry<K, V> next) {
978       super(internals, key, hash);
979       this.next = next;
980     }
981 
982     final ReferenceEntry<K, V> next;
983 
getNext()984     @Override public ReferenceEntry<K, V> getNext() {
985       return next;
986     }
987   }
988 
989   /**
990    * Used for weakly-referenced keys.
991    */
992   private static class WeakEntry<K, V> extends FinalizableWeakReference<K>
993       implements ReferenceEntry<K, V> {
WeakEntry(Internals<K, V, ReferenceEntry<K, V>> internals, K key, int hash)994     WeakEntry(Internals<K, V, ReferenceEntry<K, V>> internals, K key,
995         int hash) {
996       super(key, QueueHolder.queue);
997       this.internals = internals;
998       this.hash = hash;
999     }
1000 
getKey()1001     public K getKey() {
1002       return get();
1003     }
1004 
finalizeReferent()1005     public void finalizeReferent() {
1006       internals.removeEntry(this);
1007     }
1008 
1009     // The code below is exactly the same for each entry type.
1010 
1011     final Internals<K, V, ReferenceEntry<K, V>> internals;
1012     final int hash;
1013     volatile ValueReference<K, V> valueReference = computing();
1014 
getValueReference()1015     public ValueReference<K, V> getValueReference() {
1016       return valueReference;
1017     }
setValueReference( ValueReference<K, V> valueReference)1018     public void setValueReference(
1019         ValueReference<K, V> valueReference) {
1020       this.valueReference = valueReference;
1021     }
valueReclaimed()1022     public void valueReclaimed() {
1023       internals.removeEntry(this, null);
1024     }
getNext()1025     public ReferenceEntry<K, V> getNext() {
1026       return null;
1027     }
getHash()1028     public int getHash() {
1029       return hash;
1030     }
1031   }
1032 
1033   private static class LinkedWeakEntry<K, V> extends WeakEntry<K, V> {
LinkedWeakEntry(Internals<K, V, ReferenceEntry<K, V>> internals, K key, int hash, ReferenceEntry<K, V> next)1034     LinkedWeakEntry(Internals<K, V, ReferenceEntry<K, V>> internals,
1035         K key, int hash, ReferenceEntry<K, V> next) {
1036       super(internals, key, hash);
1037       this.next = next;
1038     }
1039 
1040     final ReferenceEntry<K, V> next;
1041 
getNext()1042     @Override public ReferenceEntry<K, V> getNext() {
1043       return next;
1044     }
1045   }
1046 
1047   /** References a weak value. */
1048   private static class WeakValueReference<K, V>
1049       extends FinalizableWeakReference<V>
1050       implements ValueReference<K, V> {
1051     final ReferenceEntry<K, V> entry;
1052 
WeakValueReference(V referent, ReferenceEntry<K, V> entry)1053     WeakValueReference(V referent, ReferenceEntry<K, V> entry) {
1054       super(referent, QueueHolder.queue);
1055       this.entry = entry;
1056     }
1057 
finalizeReferent()1058     public void finalizeReferent() {
1059       entry.valueReclaimed();
1060     }
1061 
copyFor( ReferenceEntry<K, V> entry)1062     public ValueReference<K, V> copyFor(
1063         ReferenceEntry<K, V> entry) {
1064       return new WeakValueReference<K, V>(get(), entry);
1065     }
1066 
waitForValue()1067     public V waitForValue() {
1068       return get();
1069     }
1070   }
1071 
1072   /** References a soft value. */
1073   private static class SoftValueReference<K, V>
1074       extends FinalizableSoftReference<V>
1075       implements ValueReference<K, V> {
1076     final ReferenceEntry<K, V> entry;
1077 
SoftValueReference(V referent, ReferenceEntry<K, V> entry)1078     SoftValueReference(V referent, ReferenceEntry<K, V> entry) {
1079       super(referent, QueueHolder.queue);
1080       this.entry = entry;
1081     }
1082 
finalizeReferent()1083     public void finalizeReferent() {
1084       entry.valueReclaimed();
1085     }
1086 
copyFor( ReferenceEntry<K, V> entry)1087     public ValueReference<K, V> copyFor(
1088         ReferenceEntry<K, V> entry) {
1089       return new SoftValueReference<K, V>(get(), entry);
1090     }
1091 
waitForValue()1092     public V waitForValue() {
1093       return get();
1094     }
1095   }
1096 
1097   /** References a strong value. */
1098   private static class StrongValueReference<K, V>
1099       implements ValueReference<K, V> {
1100     final V referent;
1101 
StrongValueReference(V referent)1102     StrongValueReference(V referent) {
1103       this.referent = referent;
1104     }
1105 
get()1106     public V get() {
1107       return referent;
1108     }
1109 
copyFor( ReferenceEntry<K, V> entry)1110     public ValueReference<K, V> copyFor(
1111         ReferenceEntry<K, V> entry) {
1112       return this;
1113     }
1114 
waitForValue()1115     public V waitForValue() {
1116       return get();
1117     }
1118   }
1119 }
1120