001 /* 002 * Copyright (C) 2009 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package com.google.common.cache; 018 019 import static com.google.common.base.Objects.firstNonNull; 020 import static com.google.common.base.Preconditions.checkArgument; 021 import static com.google.common.base.Preconditions.checkNotNull; 022 import static com.google.common.base.Preconditions.checkState; 023 024 import com.google.common.annotations.Beta; 025 import com.google.common.base.Ascii; 026 import com.google.common.base.Equivalence; 027 import com.google.common.base.Equivalences; 028 import com.google.common.base.Objects; 029 import com.google.common.base.Supplier; 030 import com.google.common.base.Suppliers; 031 import com.google.common.base.Ticker; 032 import com.google.common.cache.AbstractCache.SimpleStatsCounter; 033 import com.google.common.cache.AbstractCache.StatsCounter; 034 import com.google.common.cache.CustomConcurrentHashMap.Strength; 035 import com.google.common.collect.ForwardingConcurrentMap; 036 import com.google.common.util.concurrent.ExecutionError; 037 import com.google.common.util.concurrent.UncheckedExecutionException; 038 039 import java.io.Serializable; 040 import java.lang.ref.SoftReference; 041 import java.lang.ref.WeakReference; 042 import java.util.AbstractMap; 043 import java.util.Collections; 044 import java.util.ConcurrentModificationException; 045 import java.util.Map; 046 import java.util.Set; 047 import java.util.concurrent.ConcurrentHashMap; 048 import java.util.concurrent.ConcurrentMap; 049 import java.util.concurrent.ExecutionException; 050 import java.util.concurrent.TimeUnit; 051 052 import javax.annotation.CheckReturnValue; 053 import javax.annotation.Nullable; 054 055 /** 056 * <p>A builder of {@link Cache} instances having any combination of the following features: 057 * 058 * <ul> 059 * <li>least-recently-used eviction when a maximum size is exceeded 060 * <li>time-based expiration of entries, measured since last access or last write 061 * <li>keys automatically wrapped in {@linkplain WeakReference weak} references 062 * <li>values automatically wrapped in {@linkplain WeakReference weak} or 063 * {@linkplain SoftReference soft} references 064 * <li>notification of evicted (or otherwise removed) entries 065 * </ul> 066 * 067 * <p>Usage example: <pre> {@code 068 * 069 * Cache<Key, Graph> graphs = CacheBuilder.newBuilder() 070 * .concurrencyLevel(4) 071 * .weakKeys() 072 * .maximumSize(10000) 073 * .expireAfterWrite(10, TimeUnit.MINUTES) 074 * .build( 075 * new CacheLoader<Key, Graph>() { 076 * public Graph load(Key key) throws AnyException { 077 * return createExpensiveGraph(key); 078 * } 079 * });}</pre> 080 * 081 * 082 * These features are all optional. 083 * 084 * <p>The returned cache is implemented as a hash table with similar performance characteristics to 085 * {@link ConcurrentHashMap}. It implements the optional operations {@link Cache#invalidate}, 086 * {@link Cache#invalidateAll}, {@link Cache#size}, {@link Cache#stats}, and {@link Cache#asMap}, 087 * with the following qualifications: 088 * 089 * <ul> 090 * <li>The {@code invalidateAll} method will invalidate all cached entries prior to returning, and 091 * removal notifications will be issued for all invalidated entries. 092 * <li>The {@code asMap} view supports removal operations, but no other modifications. 093 * <li>The {@code asMap} view (and its collection views) have <i>weakly consistent iterators</i>. 094 * This means that they are safe for concurrent use, but if other threads modify the cache after 095 * the iterator is created, it is undefined which of these changes, if any, are reflected in 096 * that iterator. These iterators never throw {@link ConcurrentModificationException}. 097 * </ul> 098 * 099 * <p><b>Note:</b> by default, the returned cache uses equality comparisons (the 100 * {@link Object#equals equals} method) to determine equality for keys or values. However, if 101 * {@link #weakKeys} was specified, the cache uses identity ({@code ==}) 102 * comparisons instead for keys. Likewise, if {@link #weakValues} or {@link #softValues} was 103 * specified, the cache uses identity comparisons for values. 104 * 105 * <p>If soft or weak references were requested, it is possible for a key or value present in the 106 * the cache to be reclaimed by the garbage collector. If this happens, the entry automatically 107 * disappears from the cache. A partially-reclaimed entry is never exposed to the user. 108 * 109 * <p>Certain cache configurations will result in the accrual of periodic maintenance tasks which 110 * will be performed during write operations, or during occasional read operations in the absense of 111 * writes. The {@link Cache#cleanUp} method of the returned cache will also perform maintenance, but 112 * calling it should not be necessary with a high throughput cache. Only caches built with 113 * {@linkplain CacheBuilder#removalListener removalListener}, 114 * {@linkplain CacheBuilder#expireAfterWrite expireAfterWrite}, 115 * {@linkplain CacheBuilder#expireAfterAccess expireAfterAccess}, 116 * {@linkplain CacheBuilder#weakKeys weakKeys}, {@linkplain CacheBuilder#weakValues weakValues}, 117 * or {@linkplain CacheBuilder#softValues softValues} perform periodic maintenance. 118 * 119 * <p>The caches produced by {@code CacheBuilder} are serializable, and the deserialized caches 120 * retain all the configuration properties of the original cache. Note that the serialized form does 121 * <i>not</i> include cache contents, but only configuration. 122 * 123 * @param <K> the base key type for all caches created by this builder 124 * @param <V> the base value type for all caches created by this builder 125 * @author Charles Fry 126 * @author Kevin Bourrillion 127 * @since 10.0 128 */ 129 @Beta 130 public final class CacheBuilder<K, V> { 131 private static final int DEFAULT_INITIAL_CAPACITY = 16; 132 private static final int DEFAULT_CONCURRENCY_LEVEL = 4; 133 private static final int DEFAULT_EXPIRATION_NANOS = 0; 134 135 static final Supplier<? extends StatsCounter> DEFAULT_STATS_COUNTER = Suppliers.ofInstance( 136 new StatsCounter() { 137 @Override 138 public void recordHit() {} 139 140 @Override 141 public void recordLoadSuccess(long loadTime) {} 142 143 @Override 144 public void recordLoadException(long loadTime) {} 145 146 @Override 147 public void recordConcurrentMiss() {} 148 149 @Override 150 public void recordEviction() {} 151 152 @Override 153 public CacheStats snapshot() { 154 return EMPTY_STATS; 155 } 156 }); 157 static final CacheStats EMPTY_STATS = new CacheStats(0, 0, 0, 0, 0, 0); 158 159 static final Supplier<SimpleStatsCounter> CACHE_STATS_COUNTER = 160 new Supplier<SimpleStatsCounter>() { 161 @Override 162 public SimpleStatsCounter get() { 163 return new SimpleStatsCounter(); 164 } 165 }; 166 167 enum NullListener implements RemovalListener<Object, Object> { 168 INSTANCE; 169 170 @Override 171 public void onRemoval(RemovalNotification<Object, Object> notification) {} 172 } 173 174 static final int UNSET_INT = -1; 175 176 int initialCapacity = UNSET_INT; 177 int concurrencyLevel = UNSET_INT; 178 int maximumSize = UNSET_INT; 179 180 Strength keyStrength; 181 Strength valueStrength; 182 183 long expireAfterWriteNanos = UNSET_INT; 184 long expireAfterAccessNanos = UNSET_INT; 185 186 RemovalCause nullRemovalCause; 187 188 Equivalence<Object> keyEquivalence; 189 Equivalence<Object> valueEquivalence; 190 191 RemovalListener<? super K, ? super V> removalListener; 192 193 Ticker ticker; 194 195 // TODO(fry): make constructor private and update tests to use newBuilder 196 CacheBuilder() {} 197 198 /** 199 * Constructs a new {@code CacheBuilder} instance with default settings, including strong keys, 200 * strong values, and no automatic eviction of any kind. 201 */ 202 public static CacheBuilder<Object, Object> newBuilder() { 203 return new CacheBuilder<Object, Object>(); 204 } 205 206 private boolean useNullCache() { 207 return (nullRemovalCause == null); 208 } 209 210 /** 211 * Sets a custom {@code Equivalence} strategy for comparing keys. 212 * 213 * <p>By default, the cache uses {@link Equivalences#identity} to determine key equality when 214 * {@link #weakKeys} is specified, and {@link Equivalences#equals()} otherwise. 215 */ 216 CacheBuilder<K, V> keyEquivalence(Equivalence<Object> equivalence) { 217 checkState(keyEquivalence == null, "key equivalence was already set to %s", keyEquivalence); 218 keyEquivalence = checkNotNull(equivalence); 219 return this; 220 } 221 222 Equivalence<Object> getKeyEquivalence() { 223 return firstNonNull(keyEquivalence, getKeyStrength().defaultEquivalence()); 224 } 225 226 /** 227 * Sets a custom {@code Equivalence} strategy for comparing values. 228 * 229 * <p>By default, the cache uses {@link Equivalences#identity} to determine value equality when 230 * {@link #weakValues} or {@link #softValues} is specified, and {@link Equivalences#equals()} 231 * otherwise. 232 */ 233 CacheBuilder<K, V> valueEquivalence(Equivalence<Object> equivalence) { 234 checkState(valueEquivalence == null, 235 "value equivalence was already set to %s", valueEquivalence); 236 this.valueEquivalence = checkNotNull(equivalence); 237 return this; 238 } 239 240 Equivalence<Object> getValueEquivalence() { 241 return firstNonNull(valueEquivalence, getValueStrength().defaultEquivalence()); 242 } 243 244 /** 245 * Sets the minimum total size for the internal hash tables. For example, if the initial capacity 246 * is {@code 60}, and the concurrency level is {@code 8}, then eight segments are created, each 247 * having a hash table of size eight. Providing a large enough estimate at construction time 248 * avoids the need for expensive resizing operations later, but setting this value unnecessarily 249 * high wastes memory. 250 * 251 * @throws IllegalArgumentException if {@code initialCapacity} is negative 252 * @throws IllegalStateException if an initial capacity was already set 253 */ 254 public CacheBuilder<K, V> initialCapacity(int initialCapacity) { 255 checkState(this.initialCapacity == UNSET_INT, "initial capacity was already set to %s", 256 this.initialCapacity); 257 checkArgument(initialCapacity >= 0); 258 this.initialCapacity = initialCapacity; 259 return this; 260 } 261 262 int getInitialCapacity() { 263 return (initialCapacity == UNSET_INT) ? DEFAULT_INITIAL_CAPACITY : initialCapacity; 264 } 265 266 /** 267 * Guides the allowed concurrency among update operations. Used as a hint for internal sizing. The 268 * table is internally partitioned to try to permit the indicated number of concurrent updates 269 * without contention. Because assignment of entries to these partitions is not necessarily 270 * uniform, the actual concurrency observed may vary. Ideally, you should choose a value to 271 * accommodate as many threads as will ever concurrently modify the table. Using a significantly 272 * higher value than you need can waste space and time, and a significantly lower value can lead 273 * to thread contention. But overestimates and underestimates within an order of magnitude do not 274 * usually have much noticeable impact. A value of one permits only one thread to modify the cache 275 * at a time, but since read operations can proceed concurrently, this still yields higher 276 * concurrency than full synchronization. Defaults to 4. 277 * 278 * <p><b>Note:</b>The default may change in the future. If you care about this value, you should 279 * always choose it explicitly. 280 * 281 * @throws IllegalArgumentException if {@code concurrencyLevel} is nonpositive 282 * @throws IllegalStateException if a concurrency level was already set 283 */ 284 public CacheBuilder<K, V> concurrencyLevel(int concurrencyLevel) { 285 checkState(this.concurrencyLevel == UNSET_INT, "concurrency level was already set to %s", 286 this.concurrencyLevel); 287 checkArgument(concurrencyLevel > 0); 288 this.concurrencyLevel = concurrencyLevel; 289 return this; 290 } 291 292 int getConcurrencyLevel() { 293 return (concurrencyLevel == UNSET_INT) ? DEFAULT_CONCURRENCY_LEVEL : concurrencyLevel; 294 } 295 296 /** 297 * Specifies the maximum number of entries the cache may contain. Note that the cache <b>may evict 298 * an entry before this limit is exceeded</b>. As the cache size grows close to the maximum, the 299 * cache evicts entries that are less likely to be used again. For example, the cache may evict an 300 * entry because it hasn't been used recently or very often. 301 * 302 * <p>When {@code size} is zero, elements will be evicted immediately after being loaded into the 303 * cache. This has the same effect as invoking {@link #expireAfterWrite 304 * expireAfterWrite}{@code (0, unit)} or {@link #expireAfterAccess expireAfterAccess}{@code (0, 305 * unit)}. It can be useful in testing, or to disable caching temporarily without a code change. 306 * 307 * @param size the maximum size of the cache 308 * @throws IllegalArgumentException if {@code size} is negative 309 * @throws IllegalStateException if a maximum size was already set 310 */ 311 public CacheBuilder<K, V> maximumSize(int size) { 312 checkState(this.maximumSize == UNSET_INT, "maximum size was already set to %s", 313 this.maximumSize); 314 checkArgument(size >= 0, "maximum size must not be negative"); 315 this.maximumSize = size; 316 if (maximumSize == 0) { 317 // SIZE trumps EXPIRED 318 this.nullRemovalCause = RemovalCause.SIZE; 319 } 320 return this; 321 } 322 323 /** 324 * Specifies that each key (not value) stored in the cache should be strongly referenced. 325 * 326 * @throws IllegalStateException if the key strength was already set 327 */ 328 CacheBuilder<K, V> strongKeys() { 329 return setKeyStrength(Strength.STRONG); 330 } 331 332 /** 333 * Specifies that each key (not value) stored in the cache should be wrapped in a {@link 334 * WeakReference} (by default, strong references are used). 335 * 336 * <p><b>Warning:</b> when this method is used, the resulting cache will use identity ({@code ==}) 337 * comparison to determine equality of keys. 338 * 339 * <p>Entries with keys that have been garbage collected may be counted by {@link Cache#size}, but 340 * will never be visible to read or write operations. Entries with garbage collected keys are 341 * cleaned up as part of the routine maintenance described in the class javadoc. 342 * 343 * @throws IllegalStateException if the key strength was already set 344 */ 345 public CacheBuilder<K, V> weakKeys() { 346 return setKeyStrength(Strength.WEAK); 347 } 348 349 CacheBuilder<K, V> setKeyStrength(Strength strength) { 350 checkState(keyStrength == null, "Key strength was already set to %s", keyStrength); 351 keyStrength = checkNotNull(strength); 352 return this; 353 } 354 355 Strength getKeyStrength() { 356 return firstNonNull(keyStrength, Strength.STRONG); 357 } 358 359 /** 360 * Specifies that each value (not key) stored in the cache should be strongly referenced. 361 * 362 * @throws IllegalStateException if the value strength was already set 363 */ 364 CacheBuilder<K, V> strongValues() { 365 return setValueStrength(Strength.STRONG); 366 } 367 368 /** 369 * Specifies that each value (not key) stored in the cache should be wrapped in a 370 * {@link WeakReference} (by default, strong references are used). 371 * 372 * <p>Weak values will be garbage collected once they are weakly reachable. This makes them a poor 373 * candidate for caching; consider {@link #softValues} instead. 374 * 375 * <p><b>Note:</b> when this method is used, the resulting cache will use identity ({@code ==}) 376 * comparison to determine equality of values. 377 * 378 * <p>Entries with values that have been garbage collected may be counted by {@link Cache#size}, 379 * but will never be visible to read or write operations. Entries with garbage collected keys are 380 * cleaned up as part of the routine maintenance described in the class javadoc. 381 * 382 * @throws IllegalStateException if the value strength was already set 383 */ 384 public CacheBuilder<K, V> weakValues() { 385 return setValueStrength(Strength.WEAK); 386 } 387 388 /** 389 * Specifies that each value (not key) stored in the cache should be wrapped in a 390 * {@link SoftReference} (by default, strong references are used). Softly-referenced objects will 391 * be garbage-collected in a <i>globally</i> least-recently-used manner, in response to memory 392 * demand. 393 * 394 * <p><b>Warning:</b> in most circumstances it is better to set a per-cache {@linkplain 395 * #maximumSize maximum size} instead of using soft references. You should only use this method if 396 * you are well familiar with the practical consequences of soft references. 397 * 398 * <p><b>Note:</b> when this method is used, the resulting cache will use identity ({@code ==}) 399 * comparison to determine equality of values. 400 * 401 * <p>Entries with values that have been garbage collected may be counted by {@link Cache#size}, 402 * but will never be visible to read or write operations. Entries with garbage collected values 403 * are cleaned up as part of the routine maintenance described in the class javadoc. 404 * 405 * @throws IllegalStateException if the value strength was already set 406 */ 407 public CacheBuilder<K, V> softValues() { 408 return setValueStrength(Strength.SOFT); 409 } 410 411 CacheBuilder<K, V> setValueStrength(Strength strength) { 412 checkState(valueStrength == null, "Value strength was already set to %s", valueStrength); 413 valueStrength = checkNotNull(strength); 414 return this; 415 } 416 417 Strength getValueStrength() { 418 return firstNonNull(valueStrength, Strength.STRONG); 419 } 420 421 /** 422 * Specifies that each entry should be automatically removed from the cache once a fixed duration 423 * has elapsed after the entry's creation, or the most recent replacement of its value. 424 * 425 * <p>When {@code duration} is zero, elements will be evicted immediately after being loaded into 426 * the cache. This has the same effect as invoking {@link #maximumSize maximumSize}{@code (0)}. It 427 * can be useful in testing, or to disable caching temporarily without a code change. 428 * 429 * <p>Expired entries may be counted by {@link Cache#size}, but will never be visible to read or 430 * write operations. Expired entries are cleaned up as part of the routine maintenance described 431 * in the class javadoc. 432 * 433 * @param duration the length of time after an entry is created that it should be automatically 434 * removed 435 * @param unit the unit that {@code duration} is expressed in 436 * @throws IllegalArgumentException if {@code duration} is negative 437 * @throws IllegalStateException if the time to live or time to idle was already set 438 */ 439 public CacheBuilder<K, V> expireAfterWrite(long duration, TimeUnit unit) { 440 checkExpiration(duration, unit); 441 this.expireAfterWriteNanos = unit.toNanos(duration); 442 if (duration == 0 && this.nullRemovalCause == null) { 443 // SIZE trumps EXPIRED 444 this.nullRemovalCause = RemovalCause.EXPIRED; 445 } 446 return this; 447 } 448 449 private void checkExpiration(long duration, TimeUnit unit) { 450 checkState(expireAfterWriteNanos == UNSET_INT, "expireAfterWrite was already set to %s ns", 451 expireAfterWriteNanos); 452 checkState(expireAfterAccessNanos == UNSET_INT, "expireAfterAccess was already set to %s ns", 453 expireAfterAccessNanos); 454 checkArgument(duration >= 0, "duration cannot be negative: %s %s", duration, unit); 455 } 456 457 long getExpireAfterWriteNanos() { 458 return (expireAfterWriteNanos == UNSET_INT) ? DEFAULT_EXPIRATION_NANOS : expireAfterWriteNanos; 459 } 460 461 /** 462 * Specifies that each entry should be automatically removed from the cache once a fixed duration 463 * has elapsed after the entry's creation, or last access. Access time is reset by 464 * {@link Cache#get} and {@link Cache#getUnchecked}, but not by operations on the view returned by 465 * {@link Cache#asMap}. 466 * 467 * <p>When {@code duration} is zero, elements will be evicted immediately after being loaded into 468 * the cache. This has the same effect as invoking {@link #maximumSize maximumSize}{@code (0)}. It 469 * can be useful in testing, or to disable caching temporarily without a code change. 470 * 471 * <p>Expired entries may be counted by {@link Cache#size}, but will never be visible to read or 472 * write operations. Expired entries are cleaned up as part of the routine maintenance described 473 * in the class javadoc. 474 * 475 * @param duration the length of time after an entry is last accessed that it should be 476 * automatically removed 477 * @param unit the unit that {@code duration} is expressed in 478 * @throws IllegalArgumentException if {@code duration} is negative 479 * @throws IllegalStateException if the time to idle or time to live was already set 480 */ 481 public CacheBuilder<K, V> expireAfterAccess(long duration, TimeUnit unit) { 482 checkExpiration(duration, unit); 483 this.expireAfterAccessNanos = unit.toNanos(duration); 484 if (duration == 0 && this.nullRemovalCause == null) { 485 // SIZE trumps EXPIRED 486 this.nullRemovalCause = RemovalCause.EXPIRED; 487 } 488 return this; 489 } 490 491 long getExpireAfterAccessNanos() { 492 return (expireAfterAccessNanos == UNSET_INT) 493 ? DEFAULT_EXPIRATION_NANOS : expireAfterAccessNanos; 494 } 495 496 /** 497 * Specifies a nanosecond-precision time source for use in determining when entries should be 498 * expired. By default, {@link System#nanoTime} is used. 499 * 500 * <p>The primary intent of this method is to facilitate testing of caches which have been 501 * configured with {@link #expireAfterWrite} or {@link #expireAfterAccess}. 502 * 503 * @throws IllegalStateException if a ticker was already set 504 */ 505 public CacheBuilder<K, V> ticker(Ticker ticker) { 506 checkState(this.ticker == null); 507 this.ticker = checkNotNull(ticker); 508 return this; 509 } 510 511 Ticker getTicker() { 512 return firstNonNull(ticker, Ticker.systemTicker()); 513 } 514 515 /** 516 * Specifies a listener instance, which all caches built using this {@code CacheBuilder} will 517 * notify each time an entry is removed from the cache by any means. 518 * 519 * <p>Each cache built by this {@code CacheBuilder} after this method is called invokes the 520 * supplied listener after removing an element for any reason (see removal causes in {@link 521 * RemovalCause}). It will invoke the listener as part of the routine maintenance described 522 * in the class javadoc. 523 * 524 * <p><b>Important note:</b> Instead of returning <em>this</em> as a {@code CacheBuilder} 525 * instance, this method returns {@code CacheBuilder<K1, V1>}. From this point on, either the 526 * original reference or the returned reference may be used to complete configuration and build 527 * the cache, but only the "generic" one is type-safe. That is, it will properly prevent you from 528 * building caches whose key or value types are incompatible with the types accepted by the 529 * listener already provided; the {@code CacheBuilder} type cannot do this. For best results, 530 * simply use the standard method-chaining idiom, as illustrated in the documentation at top, 531 * configuring a {@code CacheBuilder} and building your {@link Cache} all in a single statement. 532 * 533 * <p><b>Warning:</b> if you ignore the above advice, and use this {@code CacheBuilder} to build 534 * a cache whose key or value type is incompatible with the listener, you will likely experience 535 * a {@link ClassCastException} at some <i>undefined</i> point in the future. 536 * 537 * @throws IllegalStateException if a removal listener was already set 538 */ 539 @CheckReturnValue 540 public <K1 extends K, V1 extends V> CacheBuilder<K1, V1> removalListener( 541 RemovalListener<? super K1, ? super V1> listener) { 542 checkState(this.removalListener == null); 543 544 // safely limiting the kinds of caches this can produce 545 @SuppressWarnings("unchecked") 546 CacheBuilder<K1, V1> me = (CacheBuilder<K1, V1>) this; 547 me.removalListener = checkNotNull(listener); 548 return me; 549 } 550 551 // Make a safe contravariant cast now so we don't have to do it over and over. 552 @SuppressWarnings("unchecked") 553 <K1 extends K, V1 extends V> RemovalListener<K1, V1> getRemovalListener() { 554 return (RemovalListener<K1, V1>) Objects.firstNonNull(removalListener, NullListener.INSTANCE); 555 } 556 557 /** 558 * Builds a cache, which either returns an already-loaded value for a given key or atomically 559 * computes or retrieves it using the supplied {@code CacheLoader}. If another thread is currently 560 * loading the value for this key, simply waits for that thread to finish and returns its 561 * loaded value. Note that multiple threads can concurrently load values for distinct keys. 562 * 563 * <p>This method does not alter the state of this {@code CacheBuilder} instance, so it can be 564 * invoked again to create multiple independent caches. 565 * 566 * @param loader the cache loader used to obtain new values 567 * @return a cache having the requested features 568 */ 569 public <K1 extends K, V1 extends V> Cache<K1, V1> build(CacheLoader<? super K1, V1> loader) { 570 return useNullCache() 571 ? new ComputingCache<K1, V1>(this, CACHE_STATS_COUNTER, loader) 572 : new NullCache<K1, V1>(this, CACHE_STATS_COUNTER, loader); 573 } 574 575 /** 576 * Returns a string representation for this CacheBuilder instance. The exact form of the returned 577 * string is not specificed. 578 */ 579 @Override 580 public String toString() { 581 Objects.ToStringHelper s = Objects.toStringHelper(this); 582 if (initialCapacity != UNSET_INT) { 583 s.add("initialCapacity", initialCapacity); 584 } 585 if (concurrencyLevel != UNSET_INT) { 586 s.add("concurrencyLevel", concurrencyLevel); 587 } 588 if (maximumSize != UNSET_INT) { 589 s.add("maximumSize", maximumSize); 590 } 591 if (expireAfterWriteNanos != UNSET_INT) { 592 s.add("expireAfterWrite", expireAfterWriteNanos + "ns"); 593 } 594 if (expireAfterAccessNanos != UNSET_INT) { 595 s.add("expireAfterAccess", expireAfterAccessNanos + "ns"); 596 } 597 if (keyStrength != null) { 598 s.add("keyStrength", Ascii.toLowerCase(keyStrength.toString())); 599 } 600 if (valueStrength != null) { 601 s.add("valueStrength", Ascii.toLowerCase(valueStrength.toString())); 602 } 603 if (keyEquivalence != null) { 604 s.addValue("keyEquivalence"); 605 } 606 if (valueEquivalence != null) { 607 s.addValue("valueEquivalence"); 608 } 609 if (removalListener != null) { 610 s.addValue("removalListener"); 611 } 612 return s.toString(); 613 } 614 615 /** A map that is always empty and evicts on insertion. */ 616 static class NullConcurrentMap<K, V> extends AbstractMap<K, V> 617 implements ConcurrentMap<K, V>, Serializable { 618 private static final long serialVersionUID = 0; 619 620 private final RemovalListener<K, V> removalListener; 621 private final RemovalCause removalCause; 622 623 NullConcurrentMap(CacheBuilder<? super K, ? super V> builder) { 624 removalListener = builder.getRemovalListener(); 625 removalCause = builder.nullRemovalCause; 626 } 627 628 // implements ConcurrentMap 629 630 @Override 631 public boolean containsKey(@Nullable Object key) { 632 return false; 633 } 634 635 @Override 636 public boolean containsValue(@Nullable Object value) { 637 return false; 638 } 639 640 @Override 641 public V get(@Nullable Object key) { 642 return null; 643 } 644 645 void notifyRemoval(K key, V value) { 646 RemovalNotification<K, V> notification = 647 new RemovalNotification<K, V>(key, value, removalCause); 648 removalListener.onRemoval(notification); 649 } 650 651 @Override 652 public V put(K key, V value) { 653 checkNotNull(key); 654 checkNotNull(value); 655 notifyRemoval(key, value); 656 return null; 657 } 658 659 @Override 660 public V putIfAbsent(K key, V value) { 661 return put(key, value); 662 } 663 664 @Override 665 public V remove(@Nullable Object key) { 666 return null; 667 } 668 669 @Override 670 public boolean remove(@Nullable Object key, @Nullable Object value) { 671 return false; 672 } 673 674 @Override 675 public V replace(K key, V value) { 676 checkNotNull(key); 677 checkNotNull(value); 678 return null; 679 } 680 681 @Override 682 public boolean replace(K key, @Nullable V oldValue, V newValue) { 683 checkNotNull(key); 684 checkNotNull(newValue); 685 return false; 686 } 687 688 @Override 689 public Set<Entry<K, V>> entrySet() { 690 return Collections.emptySet(); 691 } 692 } 693 694 // TODO(fry): remove, as no code path can hit this 695 /** Computes on retrieval and evicts the result. */ 696 static final class NullComputingConcurrentMap<K, V> extends NullConcurrentMap<K, V> { 697 private static final long serialVersionUID = 0; 698 699 final CacheLoader<? super K, ? extends V> loader; 700 701 NullComputingConcurrentMap(CacheBuilder<? super K, ? super V> builder, 702 CacheLoader<? super K, ? extends V> loader) { 703 super(builder); 704 this.loader = checkNotNull(loader); 705 } 706 707 @SuppressWarnings("unchecked") // unsafe, which is why Cache is preferred 708 @Override 709 public V get(Object k) { 710 K key = (K) k; 711 V value = compute(key); 712 checkNotNull(value, loader + " returned null for key " + key + "."); 713 notifyRemoval(key, value); 714 return value; 715 } 716 717 private V compute(K key) { 718 checkNotNull(key); 719 try { 720 return loader.load(key); 721 } catch (Exception e) { 722 throw new UncheckedExecutionException(e); 723 } catch (Error e) { 724 throw new ExecutionError(e); 725 } 726 } 727 } 728 729 /** Computes on retrieval and evicts the result. */ 730 static final class NullCache<K, V> extends AbstractCache<K, V> { 731 final NullConcurrentMap<K, V> map; 732 final CacheLoader<? super K, V> loader; 733 734 final StatsCounter statsCounter; 735 736 NullCache(CacheBuilder<? super K, ? super V> builder, 737 Supplier<? extends StatsCounter> statsCounterSupplier, 738 CacheLoader<? super K, V> loader) { 739 this.map = new NullConcurrentMap<K, V>(builder); 740 this.statsCounter = statsCounterSupplier.get(); 741 this.loader = checkNotNull(loader); 742 } 743 744 @Override 745 public V get(K key) throws ExecutionException { 746 V value = compute(key); 747 map.notifyRemoval(key, value); 748 return value; 749 } 750 751 private V compute(K key) throws ExecutionException { 752 checkNotNull(key); 753 long start = System.nanoTime(); 754 V value = null; 755 try { 756 value = loader.load(key); 757 } catch (RuntimeException e) { 758 throw new UncheckedExecutionException(e); 759 } catch (Exception e) { 760 throw new ExecutionException(e); 761 } catch (Error e) { 762 throw new ExecutionError(e); 763 } finally { 764 long elapsed = System.nanoTime() - start; 765 if (value == null) { 766 statsCounter.recordLoadException(elapsed); 767 } else { 768 statsCounter.recordLoadSuccess(elapsed); 769 } 770 statsCounter.recordEviction(); 771 } 772 if (value == null) { 773 throw new NullPointerException(); 774 } else { 775 return value; 776 } 777 } 778 779 @Override 780 public long size() { 781 return 0; 782 } 783 784 @Override 785 public void invalidate(Object key) { 786 // no-op 787 } 788 789 @Override public void invalidateAll() { 790 // no-op 791 } 792 793 @Override 794 public CacheStats stats() { 795 return statsCounter.snapshot(); 796 } 797 798 ConcurrentMap<K, V> asMap; 799 800 @Override 801 public ConcurrentMap<K, V> asMap() { 802 ConcurrentMap<K, V> am = asMap; 803 return (am != null) ? am : (asMap = new CacheAsMap<K, V>(map)); 804 } 805 } 806 807 static final class CacheAsMap<K, V> extends ForwardingConcurrentMap<K, V> { 808 private final ConcurrentMap<K, V> delegate; 809 810 CacheAsMap(ConcurrentMap<K, V> delegate) { 811 this.delegate = delegate; 812 } 813 814 @Override 815 protected ConcurrentMap<K, V> delegate() { 816 return delegate; 817 } 818 819 @Override 820 public V put(K key, V value) { 821 throw new UnsupportedOperationException(); 822 } 823 824 @Override 825 public void putAll(Map<? extends K, ? extends V> map) { 826 throw new UnsupportedOperationException(); 827 } 828 829 @Override 830 public V putIfAbsent(K key, V value) { 831 throw new UnsupportedOperationException(); 832 } 833 834 @Override 835 public V replace(K key, V value) { 836 throw new UnsupportedOperationException(); 837 } 838 839 @Override 840 public boolean replace(K key, V oldValue, V newValue) { 841 throw new UnsupportedOperationException(); 842 } 843 } 844 845 }