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