1 /* 2 * Copyright (C) 2009 The Guava Authors 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.cache; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 import static com.google.common.base.Preconditions.checkState; 21 import static com.google.common.cache.CacheBuilder.NULL_TICKER; 22 import static com.google.common.cache.CacheBuilder.UNSET_INT; 23 import static com.google.common.util.concurrent.MoreExecutors.directExecutor; 24 import static com.google.common.util.concurrent.Uninterruptibles.getUninterruptibly; 25 import static java.util.concurrent.TimeUnit.NANOSECONDS; 26 27 import com.google.common.annotations.GwtCompatible; 28 import com.google.common.annotations.GwtIncompatible; 29 import com.google.common.annotations.VisibleForTesting; 30 import com.google.common.base.Equivalence; 31 import com.google.common.base.Function; 32 import com.google.common.base.Stopwatch; 33 import com.google.common.base.Ticker; 34 import com.google.common.cache.AbstractCache.SimpleStatsCounter; 35 import com.google.common.cache.AbstractCache.StatsCounter; 36 import com.google.common.cache.CacheBuilder.NullListener; 37 import com.google.common.cache.CacheBuilder.OneWeigher; 38 import com.google.common.cache.CacheLoader.InvalidCacheLoadException; 39 import com.google.common.cache.CacheLoader.UnsupportedLoadingOperationException; 40 import com.google.common.collect.AbstractSequentialIterator; 41 import com.google.common.collect.ImmutableMap; 42 import com.google.common.collect.ImmutableSet; 43 import com.google.common.collect.Maps; 44 import com.google.common.collect.Sets; 45 import com.google.common.primitives.Ints; 46 import com.google.common.util.concurrent.ExecutionError; 47 import com.google.common.util.concurrent.Futures; 48 import com.google.common.util.concurrent.ListenableFuture; 49 import com.google.common.util.concurrent.SettableFuture; 50 import com.google.common.util.concurrent.UncheckedExecutionException; 51 import com.google.common.util.concurrent.Uninterruptibles; 52 53 import java.io.IOException; 54 import java.io.ObjectInputStream; 55 import java.io.Serializable; 56 import java.lang.ref.Reference; 57 import java.lang.ref.ReferenceQueue; 58 import java.lang.ref.SoftReference; 59 import java.lang.ref.WeakReference; 60 import java.util.AbstractCollection; 61 import java.util.AbstractMap; 62 import java.util.AbstractQueue; 63 import java.util.AbstractSet; 64 import java.util.Collection; 65 import java.util.Iterator; 66 import java.util.Map; 67 import java.util.Map.Entry; 68 import java.util.NoSuchElementException; 69 import java.util.Queue; 70 import java.util.Set; 71 import java.util.concurrent.Callable; 72 import java.util.concurrent.ConcurrentLinkedQueue; 73 import java.util.concurrent.ConcurrentMap; 74 import java.util.concurrent.ExecutionException; 75 import java.util.concurrent.TimeUnit; 76 import java.util.concurrent.atomic.AtomicInteger; 77 import java.util.concurrent.atomic.AtomicReferenceArray; 78 import java.util.concurrent.locks.ReentrantLock; 79 import java.util.logging.Level; 80 import java.util.logging.Logger; 81 82 import javax.annotation.Nullable; 83 import javax.annotation.concurrent.GuardedBy; 84 85 /** 86 * The concurrent hash map implementation built by {@link CacheBuilder}. 87 * 88 * <p>This implementation is heavily derived from revision 1.96 of <a 89 * href="http://tinyurl.com/ConcurrentHashMap">ConcurrentHashMap.java</a>. 90 * 91 * @author Charles Fry 92 * @author Bob Lee ({@code com.google.common.collect.MapMaker}) 93 * @author Doug Lea ({@code ConcurrentHashMap}) 94 */ 95 @GwtCompatible(emulated = true) 96 class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> { 97 98 /* 99 * The basic strategy is to subdivide the table among Segments, each of which itself is a 100 * concurrently readable hash table. The map supports non-blocking reads and concurrent writes 101 * across different segments. 102 * 103 * If a maximum size is specified, a best-effort bounding is performed per segment, using a 104 * page-replacement algorithm to determine which entries to evict when the capacity has been 105 * exceeded. 106 * 107 * The page replacement algorithm's data structures are kept casually consistent with the map. The 108 * ordering of writes to a segment is sequentially consistent. An update to the map and recording 109 * of reads may not be immediately reflected on the algorithm's data structures. These structures 110 * are guarded by a lock and operations are applied in batches to avoid lock contention. The 111 * penalty of applying the batches is spread across threads so that the amortized cost is slightly 112 * higher than performing just the operation without enforcing the capacity constraint. 113 * 114 * This implementation uses a per-segment queue to record a memento of the additions, removals, 115 * and accesses that were performed on the map. The queue is drained on writes and when it exceeds 116 * its capacity threshold. 117 * 118 * The Least Recently Used page replacement algorithm was chosen due to its simplicity, high hit 119 * rate, and ability to be implemented with O(1) time complexity. The initial LRU implementation 120 * operates per-segment rather than globally for increased implementation simplicity. We expect 121 * the cache hit rate to be similar to that of a global LRU algorithm. 122 */ 123 124 // Constants 125 126 /** 127 * The maximum capacity, used if a higher value is implicitly specified by either of the 128 * constructors with arguments. MUST be a power of two <= 1<<30 to ensure that entries are 129 * indexable using ints. 130 */ 131 static final int MAXIMUM_CAPACITY = 1 << 30; 132 133 /** The maximum number of segments to allow; used to bound constructor arguments. */ 134 static final int MAX_SEGMENTS = 1 << 16; // slightly conservative 135 136 /** Number of (unsynchronized) retries in the containsValue method. */ 137 static final int CONTAINS_VALUE_RETRIES = 3; 138 139 /** 140 * Number of cache access operations that can be buffered per segment before the cache's recency 141 * ordering information is updated. This is used to avoid lock contention by recording a memento 142 * of reads and delaying a lock acquisition until the threshold is crossed or a mutation occurs. 143 * 144 * <p>This must be a (2^n)-1 as it is used as a mask. 145 */ 146 static final int DRAIN_THRESHOLD = 0x3F; 147 148 /** 149 * Maximum number of entries to be drained in a single cleanup run. This applies independently to 150 * the cleanup queue and both reference queues. 151 */ 152 // TODO(fry): empirically optimize this 153 static final int DRAIN_MAX = 16; 154 155 // Fields 156 157 static final Logger logger = Logger.getLogger(LocalCache.class.getName()); 158 159 /** 160 * Mask value for indexing into segments. The upper bits of a key's hash code are used to choose 161 * the segment. 162 */ 163 final int segmentMask; 164 165 /** 166 * Shift value for indexing within segments. Helps prevent entries that end up in the same segment 167 * from also ending up in the same bucket. 168 */ 169 final int segmentShift; 170 171 /** The segments, each of which is a specialized hash table. */ 172 final Segment<K, V>[] segments; 173 174 /** The concurrency level. */ 175 final int concurrencyLevel; 176 177 /** Strategy for comparing keys. */ 178 final Equivalence<Object> keyEquivalence; 179 180 /** Strategy for comparing values. */ 181 final Equivalence<Object> valueEquivalence; 182 183 /** Strategy for referencing keys. */ 184 final Strength keyStrength; 185 186 /** Strategy for referencing values. */ 187 final Strength valueStrength; 188 189 /** The maximum weight of this map. UNSET_INT if there is no maximum. */ 190 final long maxWeight; 191 192 /** Weigher to weigh cache entries. */ 193 final Weigher<K, V> weigher; 194 195 /** How long after the last access to an entry the map will retain that entry. */ 196 final long expireAfterAccessNanos; 197 198 /** How long after the last write to an entry the map will retain that entry. */ 199 final long expireAfterWriteNanos; 200 201 /** How long after the last write an entry becomes a candidate for refresh. */ 202 final long refreshNanos; 203 204 /** Entries waiting to be consumed by the removal listener. */ 205 // TODO(fry): define a new type which creates event objects and automates the clear logic 206 final Queue<RemovalNotification<K, V>> removalNotificationQueue; 207 208 /** 209 * A listener that is invoked when an entry is removed due to expiration or garbage collection of 210 * soft/weak entries. 211 */ 212 final RemovalListener<K, V> removalListener; 213 214 /** Measures time in a testable way. */ 215 final Ticker ticker; 216 217 /** Factory used to create new entries. */ 218 final EntryFactory entryFactory; 219 220 /** 221 * Accumulates global cache statistics. Note that there are also per-segments stats counters 222 * which must be aggregated to obtain a global stats view. 223 */ 224 final StatsCounter globalStatsCounter; 225 226 /** 227 * The default cache loader to use on loading operations. 228 */ 229 @Nullable 230 final CacheLoader<? super K, V> defaultLoader; 231 232 /** 233 * Creates a new, empty map with the specified strategy, initial capacity and concurrency level. 234 */ LocalCache( CacheBuilder<? super K, ? super V> builder, @Nullable CacheLoader<? super K, V> loader)235 LocalCache( 236 CacheBuilder<? super K, ? super V> builder, @Nullable CacheLoader<? super K, V> loader) { 237 concurrencyLevel = Math.min(builder.getConcurrencyLevel(), MAX_SEGMENTS); 238 239 keyStrength = builder.getKeyStrength(); 240 valueStrength = builder.getValueStrength(); 241 242 keyEquivalence = builder.getKeyEquivalence(); 243 valueEquivalence = builder.getValueEquivalence(); 244 245 maxWeight = builder.getMaximumWeight(); 246 weigher = builder.getWeigher(); 247 expireAfterAccessNanos = builder.getExpireAfterAccessNanos(); 248 expireAfterWriteNanos = builder.getExpireAfterWriteNanos(); 249 refreshNanos = builder.getRefreshNanos(); 250 251 removalListener = builder.getRemovalListener(); 252 removalNotificationQueue = (removalListener == NullListener.INSTANCE) 253 ? LocalCache.<RemovalNotification<K, V>>discardingQueue() 254 : new ConcurrentLinkedQueue<RemovalNotification<K, V>>(); 255 256 ticker = builder.getTicker(recordsTime()); 257 entryFactory = EntryFactory.getFactory(keyStrength, usesAccessEntries(), usesWriteEntries()); 258 globalStatsCounter = builder.getStatsCounterSupplier().get(); 259 defaultLoader = loader; 260 261 int initialCapacity = Math.min(builder.getInitialCapacity(), MAXIMUM_CAPACITY); 262 if (evictsBySize() && !customWeigher()) { 263 initialCapacity = Math.min(initialCapacity, (int) maxWeight); 264 } 265 266 // Find the lowest power-of-two segmentCount that exceeds concurrencyLevel, unless 267 // maximumSize/Weight is specified in which case ensure that each segment gets at least 10 268 // entries. The special casing for size-based eviction is only necessary because that eviction 269 // happens per segment instead of globally, so too many segments compared to the maximum size 270 // will result in random eviction behavior. 271 int segmentShift = 0; 272 int segmentCount = 1; 273 while (segmentCount < concurrencyLevel 274 && (!evictsBySize() || segmentCount * 20 <= maxWeight)) { 275 ++segmentShift; 276 segmentCount <<= 1; 277 } 278 this.segmentShift = 32 - segmentShift; 279 segmentMask = segmentCount - 1; 280 281 this.segments = newSegmentArray(segmentCount); 282 283 int segmentCapacity = initialCapacity / segmentCount; 284 if (segmentCapacity * segmentCount < initialCapacity) { 285 ++segmentCapacity; 286 } 287 288 int segmentSize = 1; 289 while (segmentSize < segmentCapacity) { 290 segmentSize <<= 1; 291 } 292 293 if (evictsBySize()) { 294 // Ensure sum of segment max weights = overall max weights 295 long maxSegmentWeight = maxWeight / segmentCount + 1; 296 long remainder = maxWeight % segmentCount; 297 for (int i = 0; i < this.segments.length; ++i) { 298 if (i == remainder) { 299 maxSegmentWeight--; 300 } 301 this.segments[i] = 302 createSegment(segmentSize, maxSegmentWeight, builder.getStatsCounterSupplier().get()); 303 } 304 } else { 305 for (int i = 0; i < this.segments.length; ++i) { 306 this.segments[i] = 307 createSegment(segmentSize, UNSET_INT, builder.getStatsCounterSupplier().get()); 308 } 309 } 310 } 311 evictsBySize()312 boolean evictsBySize() { 313 return maxWeight >= 0; 314 } 315 customWeigher()316 boolean customWeigher() { 317 return weigher != OneWeigher.INSTANCE; 318 } 319 expires()320 boolean expires() { 321 return expiresAfterWrite() || expiresAfterAccess(); 322 } 323 expiresAfterWrite()324 boolean expiresAfterWrite() { 325 return expireAfterWriteNanos > 0; 326 } 327 expiresAfterAccess()328 boolean expiresAfterAccess() { 329 return expireAfterAccessNanos > 0; 330 } 331 refreshes()332 boolean refreshes() { 333 return refreshNanos > 0; 334 } 335 usesAccessQueue()336 boolean usesAccessQueue() { 337 return expiresAfterAccess() || evictsBySize(); 338 } 339 usesWriteQueue()340 boolean usesWriteQueue() { 341 return expiresAfterWrite(); 342 } 343 recordsWrite()344 boolean recordsWrite() { 345 return expiresAfterWrite() || refreshes(); 346 } 347 recordsAccess()348 boolean recordsAccess() { 349 return expiresAfterAccess(); 350 } 351 recordsTime()352 boolean recordsTime() { 353 return recordsWrite() || recordsAccess(); 354 } 355 usesWriteEntries()356 boolean usesWriteEntries() { 357 return usesWriteQueue() || recordsWrite(); 358 } 359 usesAccessEntries()360 boolean usesAccessEntries() { 361 return usesAccessQueue() || recordsAccess(); 362 } 363 usesKeyReferences()364 boolean usesKeyReferences() { 365 return keyStrength != Strength.STRONG; 366 } 367 usesValueReferences()368 boolean usesValueReferences() { 369 return valueStrength != Strength.STRONG; 370 } 371 372 enum Strength { 373 /* 374 * TODO(kevinb): If we strongly reference the value and aren't loading, we needn't wrap the 375 * value. This could save ~8 bytes per entry. 376 */ 377 378 STRONG { 379 @Override referenceValue( Segment<K, V> segment, ReferenceEntry<K, V> entry, V value, int weight)380 <K, V> ValueReference<K, V> referenceValue( 381 Segment<K, V> segment, ReferenceEntry<K, V> entry, V value, int weight) { 382 return (weight == 1) 383 ? new StrongValueReference<K, V>(value) 384 : new WeightedStrongValueReference<K, V>(value, weight); 385 } 386 387 @Override defaultEquivalence()388 Equivalence<Object> defaultEquivalence() { 389 return Equivalence.equals(); 390 } 391 }, 392 393 SOFT { 394 @Override referenceValue( Segment<K, V> segment, ReferenceEntry<K, V> entry, V value, int weight)395 <K, V> ValueReference<K, V> referenceValue( 396 Segment<K, V> segment, ReferenceEntry<K, V> entry, V value, int weight) { 397 return (weight == 1) 398 ? new SoftValueReference<K, V>(segment.valueReferenceQueue, value, entry) 399 : new WeightedSoftValueReference<K, V>( 400 segment.valueReferenceQueue, value, entry, weight); 401 } 402 403 @Override defaultEquivalence()404 Equivalence<Object> defaultEquivalence() { 405 return Equivalence.identity(); 406 } 407 }, 408 409 WEAK { 410 @Override referenceValue( Segment<K, V> segment, ReferenceEntry<K, V> entry, V value, int weight)411 <K, V> ValueReference<K, V> referenceValue( 412 Segment<K, V> segment, ReferenceEntry<K, V> entry, V value, int weight) { 413 return (weight == 1) 414 ? new WeakValueReference<K, V>(segment.valueReferenceQueue, value, entry) 415 : new WeightedWeakValueReference<K, V>( 416 segment.valueReferenceQueue, value, entry, weight); 417 } 418 419 @Override defaultEquivalence()420 Equivalence<Object> defaultEquivalence() { 421 return Equivalence.identity(); 422 } 423 }; 424 425 /** 426 * Creates a reference for the given value according to this value strength. 427 */ referenceValue( Segment<K, V> segment, ReferenceEntry<K, V> entry, V value, int weight)428 abstract <K, V> ValueReference<K, V> referenceValue( 429 Segment<K, V> segment, ReferenceEntry<K, V> entry, V value, int weight); 430 431 /** 432 * Returns the default equivalence strategy used to compare and hash keys or values referenced 433 * at this strength. This strategy will be used unless the user explicitly specifies an 434 * alternate strategy. 435 */ defaultEquivalence()436 abstract Equivalence<Object> defaultEquivalence(); 437 } 438 439 /** 440 * Creates new entries. 441 */ 442 enum EntryFactory { 443 STRONG { 444 @Override newEntry( Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next)445 <K, V> ReferenceEntry<K, V> newEntry( 446 Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) { 447 return new StrongEntry<K, V>(key, hash, next); 448 } 449 }, 450 STRONG_ACCESS { 451 @Override newEntry( Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next)452 <K, V> ReferenceEntry<K, V> newEntry( 453 Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) { 454 return new StrongAccessEntry<K, V>(key, hash, next); 455 } 456 457 @Override copyEntry( Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext)458 <K, V> ReferenceEntry<K, V> copyEntry( 459 Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) { 460 ReferenceEntry<K, V> newEntry = super.copyEntry(segment, original, newNext); 461 copyAccessEntry(original, newEntry); 462 return newEntry; 463 } 464 }, 465 STRONG_WRITE { 466 @Override newEntry( Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next)467 <K, V> ReferenceEntry<K, V> newEntry( 468 Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) { 469 return new StrongWriteEntry<K, V>(key, hash, next); 470 } 471 472 @Override copyEntry( Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext)473 <K, V> ReferenceEntry<K, V> copyEntry( 474 Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) { 475 ReferenceEntry<K, V> newEntry = super.copyEntry(segment, original, newNext); 476 copyWriteEntry(original, newEntry); 477 return newEntry; 478 } 479 }, 480 STRONG_ACCESS_WRITE { 481 @Override newEntry( Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next)482 <K, V> ReferenceEntry<K, V> newEntry( 483 Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) { 484 return new StrongAccessWriteEntry<K, V>(key, hash, next); 485 } 486 487 @Override copyEntry( Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext)488 <K, V> ReferenceEntry<K, V> copyEntry( 489 Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) { 490 ReferenceEntry<K, V> newEntry = super.copyEntry(segment, original, newNext); 491 copyAccessEntry(original, newEntry); 492 copyWriteEntry(original, newEntry); 493 return newEntry; 494 } 495 }, 496 497 WEAK { 498 @Override newEntry( Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next)499 <K, V> ReferenceEntry<K, V> newEntry( 500 Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) { 501 return new WeakEntry<K, V>(segment.keyReferenceQueue, key, hash, next); 502 } 503 }, 504 WEAK_ACCESS { 505 @Override newEntry( Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next)506 <K, V> ReferenceEntry<K, V> newEntry( 507 Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) { 508 return new WeakAccessEntry<K, V>(segment.keyReferenceQueue, key, hash, next); 509 } 510 511 @Override copyEntry( Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext)512 <K, V> ReferenceEntry<K, V> copyEntry( 513 Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) { 514 ReferenceEntry<K, V> newEntry = super.copyEntry(segment, original, newNext); 515 copyAccessEntry(original, newEntry); 516 return newEntry; 517 } 518 }, 519 WEAK_WRITE { 520 @Override newEntry( Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next)521 <K, V> ReferenceEntry<K, V> newEntry( 522 Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) { 523 return new WeakWriteEntry<K, V>(segment.keyReferenceQueue, key, hash, next); 524 } 525 526 @Override copyEntry( Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext)527 <K, V> ReferenceEntry<K, V> copyEntry( 528 Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) { 529 ReferenceEntry<K, V> newEntry = super.copyEntry(segment, original, newNext); 530 copyWriteEntry(original, newEntry); 531 return newEntry; 532 } 533 }, 534 WEAK_ACCESS_WRITE { 535 @Override newEntry( Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next)536 <K, V> ReferenceEntry<K, V> newEntry( 537 Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) { 538 return new WeakAccessWriteEntry<K, V>(segment.keyReferenceQueue, key, hash, next); 539 } 540 541 @Override copyEntry( Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext)542 <K, V> ReferenceEntry<K, V> copyEntry( 543 Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) { 544 ReferenceEntry<K, V> newEntry = super.copyEntry(segment, original, newNext); 545 copyAccessEntry(original, newEntry); 546 copyWriteEntry(original, newEntry); 547 return newEntry; 548 } 549 }; 550 551 /** 552 * Masks used to compute indices in the following table. 553 */ 554 static final int ACCESS_MASK = 1; 555 static final int WRITE_MASK = 2; 556 static final int WEAK_MASK = 4; 557 558 /** 559 * Look-up table for factories. 560 */ 561 static final EntryFactory[] factories = { 562 STRONG, STRONG_ACCESS, STRONG_WRITE, STRONG_ACCESS_WRITE, 563 WEAK, WEAK_ACCESS, WEAK_WRITE, WEAK_ACCESS_WRITE, 564 }; 565 getFactory(Strength keyStrength, boolean usesAccessQueue, boolean usesWriteQueue)566 static EntryFactory getFactory(Strength keyStrength, boolean usesAccessQueue, 567 boolean usesWriteQueue) { 568 int flags = ((keyStrength == Strength.WEAK) ? WEAK_MASK : 0) 569 | (usesAccessQueue ? ACCESS_MASK : 0) 570 | (usesWriteQueue ? WRITE_MASK : 0); 571 return factories[flags]; 572 } 573 574 /** 575 * Creates a new entry. 576 * 577 * @param segment to create the entry for 578 * @param key of the entry 579 * @param hash of the key 580 * @param next entry in the same bucket 581 */ newEntry( Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next)582 abstract <K, V> ReferenceEntry<K, V> newEntry( 583 Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next); 584 585 /** 586 * Copies an entry, assigning it a new {@code next} entry. 587 * 588 * @param original the entry to copy 589 * @param newNext entry in the same bucket 590 */ 591 // Guarded By Segment.this copyEntry( Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext)592 <K, V> ReferenceEntry<K, V> copyEntry( 593 Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) { 594 return newEntry(segment, original.getKey(), original.getHash(), newNext); 595 } 596 597 // Guarded By Segment.this copyAccessEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newEntry)598 <K, V> void copyAccessEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newEntry) { 599 // TODO(fry): when we link values instead of entries this method can go 600 // away, as can connectAccessOrder, nullifyAccessOrder. 601 newEntry.setAccessTime(original.getAccessTime()); 602 603 connectAccessOrder(original.getPreviousInAccessQueue(), newEntry); 604 connectAccessOrder(newEntry, original.getNextInAccessQueue()); 605 606 nullifyAccessOrder(original); 607 } 608 609 // Guarded By Segment.this copyWriteEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newEntry)610 <K, V> void copyWriteEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newEntry) { 611 // TODO(fry): when we link values instead of entries this method can go 612 // away, as can connectWriteOrder, nullifyWriteOrder. 613 newEntry.setWriteTime(original.getWriteTime()); 614 615 connectWriteOrder(original.getPreviousInWriteQueue(), newEntry); 616 connectWriteOrder(newEntry, original.getNextInWriteQueue()); 617 618 nullifyWriteOrder(original); 619 } 620 } 621 622 /** 623 * A reference to a value. 624 */ 625 interface ValueReference<K, V> { 626 /** 627 * Returns the value. Does not block or throw exceptions. 628 */ 629 @Nullable get()630 V get(); 631 632 /** 633 * Waits for a value that may still be loading. Unlike get(), this method can block (in the 634 * case of FutureValueReference). 635 * 636 * @throws ExecutionException if the loading thread throws an exception 637 * @throws ExecutionError if the loading thread throws an error 638 */ waitForValue()639 V waitForValue() throws ExecutionException; 640 641 /** 642 * Returns the weight of this entry. This is assumed to be static between calls to setValue. 643 */ getWeight()644 int getWeight(); 645 646 /** 647 * Returns the entry associated with this value reference, or {@code null} if this value 648 * reference is independent of any entry. 649 */ 650 @Nullable getEntry()651 ReferenceEntry<K, V> getEntry(); 652 653 /** 654 * Creates a copy of this reference for the given entry. 655 * 656 * <p>{@code value} may be null only for a loading reference. 657 */ copyFor( ReferenceQueue<V> queue, @Nullable V value, ReferenceEntry<K, V> entry)658 ValueReference<K, V> copyFor( 659 ReferenceQueue<V> queue, @Nullable V value, ReferenceEntry<K, V> entry); 660 661 /** 662 * Notifify pending loads that a new value was set. This is only relevant to loading 663 * value references. 664 */ notifyNewValue(@ullable V newValue)665 void notifyNewValue(@Nullable V newValue); 666 667 /** 668 * Returns true if a new value is currently loading, regardless of whether or not there is an 669 * existing value. It is assumed that the return value of this method is constant for any given 670 * ValueReference instance. 671 */ isLoading()672 boolean isLoading(); 673 674 /** 675 * Returns true if this reference contains an active value, meaning one that is still considered 676 * present in the cache. Active values consist of live values, which are returned by cache 677 * lookups, and dead values, which have been evicted but awaiting removal. Non-active values 678 * consist strictly of loading values, though during refresh a value may be both active and 679 * loading. 680 */ isActive()681 boolean isActive(); 682 } 683 684 /** 685 * Placeholder. Indicates that the value hasn't been set yet. 686 */ 687 static final ValueReference<Object, Object> UNSET = new ValueReference<Object, Object>() { 688 @Override 689 public Object get() { 690 return null; 691 } 692 693 @Override 694 public int getWeight() { 695 return 0; 696 } 697 698 @Override 699 public ReferenceEntry<Object, Object> getEntry() { 700 return null; 701 } 702 703 @Override 704 public ValueReference<Object, Object> copyFor(ReferenceQueue<Object> queue, 705 @Nullable Object value, ReferenceEntry<Object, Object> entry) { 706 return this; 707 } 708 709 @Override 710 public boolean isLoading() { 711 return false; 712 } 713 714 @Override 715 public boolean isActive() { 716 return false; 717 } 718 719 @Override 720 public Object waitForValue() { 721 return null; 722 } 723 724 @Override 725 public void notifyNewValue(Object newValue) {} 726 }; 727 728 /** 729 * Singleton placeholder that indicates a value is being loaded. 730 */ 731 @SuppressWarnings("unchecked") // impl never uses a parameter or returns any non-null value unset()732 static <K, V> ValueReference<K, V> unset() { 733 return (ValueReference<K, V>) UNSET; 734 } 735 736 /** 737 * An entry in a reference map. 738 * 739 * Entries in the map can be in the following states: 740 * 741 * Valid: 742 * - Live: valid key/value are set 743 * - Loading: loading is pending 744 * 745 * Invalid: 746 * - Expired: time expired (key/value may still be set) 747 * - Collected: key/value was partially collected, but not yet cleaned up 748 * - Unset: marked as unset, awaiting cleanup or reuse 749 */ 750 interface ReferenceEntry<K, V> { 751 /** 752 * Returns the value reference from this entry. 753 */ getValueReference()754 ValueReference<K, V> getValueReference(); 755 756 /** 757 * Sets the value reference for this entry. 758 */ setValueReference(ValueReference<K, V> valueReference)759 void setValueReference(ValueReference<K, V> valueReference); 760 761 /** 762 * Returns the next entry in the chain. 763 */ 764 @Nullable getNext()765 ReferenceEntry<K, V> getNext(); 766 767 /** 768 * Returns the entry's hash. 769 */ getHash()770 int getHash(); 771 772 /** 773 * Returns the key for this entry. 774 */ 775 @Nullable getKey()776 K getKey(); 777 778 /* 779 * Used by entries that use access order. Access entries are maintained in a doubly-linked list. 780 * New entries are added at the tail of the list at write time; stale entries are expired from 781 * the head of the list. 782 */ 783 784 /** 785 * Returns the time that this entry was last accessed, in ns. 786 */ getAccessTime()787 long getAccessTime(); 788 789 /** 790 * Sets the entry access time in ns. 791 */ setAccessTime(long time)792 void setAccessTime(long time); 793 794 /** 795 * Returns the next entry in the access queue. 796 */ getNextInAccessQueue()797 ReferenceEntry<K, V> getNextInAccessQueue(); 798 799 /** 800 * Sets the next entry in the access queue. 801 */ setNextInAccessQueue(ReferenceEntry<K, V> next)802 void setNextInAccessQueue(ReferenceEntry<K, V> next); 803 804 /** 805 * Returns the previous entry in the access queue. 806 */ getPreviousInAccessQueue()807 ReferenceEntry<K, V> getPreviousInAccessQueue(); 808 809 /** 810 * Sets the previous entry in the access queue. 811 */ setPreviousInAccessQueue(ReferenceEntry<K, V> previous)812 void setPreviousInAccessQueue(ReferenceEntry<K, V> previous); 813 814 /* 815 * Implemented by entries that use write order. Write entries are maintained in a 816 * doubly-linked list. New entries are added at the tail of the list at write time and stale 817 * entries are expired from the head of the list. 818 */ 819 820 /** 821 * Returns the time that this entry was last written, in ns. 822 */ getWriteTime()823 long getWriteTime(); 824 825 /** 826 * Sets the entry write time in ns. 827 */ setWriteTime(long time)828 void setWriteTime(long time); 829 830 /** 831 * Returns the next entry in the write queue. 832 */ getNextInWriteQueue()833 ReferenceEntry<K, V> getNextInWriteQueue(); 834 835 /** 836 * Sets the next entry in the write queue. 837 */ setNextInWriteQueue(ReferenceEntry<K, V> next)838 void setNextInWriteQueue(ReferenceEntry<K, V> next); 839 840 /** 841 * Returns the previous entry in the write queue. 842 */ getPreviousInWriteQueue()843 ReferenceEntry<K, V> getPreviousInWriteQueue(); 844 845 /** 846 * Sets the previous entry in the write queue. 847 */ setPreviousInWriteQueue(ReferenceEntry<K, V> previous)848 void setPreviousInWriteQueue(ReferenceEntry<K, V> previous); 849 } 850 851 private enum NullEntry implements ReferenceEntry<Object, Object> { 852 INSTANCE; 853 854 @Override getValueReference()855 public ValueReference<Object, Object> getValueReference() { 856 return null; 857 } 858 859 @Override setValueReference(ValueReference<Object, Object> valueReference)860 public void setValueReference(ValueReference<Object, Object> valueReference) {} 861 862 @Override getNext()863 public ReferenceEntry<Object, Object> getNext() { 864 return null; 865 } 866 867 @Override getHash()868 public int getHash() { 869 return 0; 870 } 871 872 @Override getKey()873 public Object getKey() { 874 return null; 875 } 876 877 @Override getAccessTime()878 public long getAccessTime() { 879 return 0; 880 } 881 882 @Override setAccessTime(long time)883 public void setAccessTime(long time) {} 884 885 @Override getNextInAccessQueue()886 public ReferenceEntry<Object, Object> getNextInAccessQueue() { 887 return this; 888 } 889 890 @Override setNextInAccessQueue(ReferenceEntry<Object, Object> next)891 public void setNextInAccessQueue(ReferenceEntry<Object, Object> next) {} 892 893 @Override getPreviousInAccessQueue()894 public ReferenceEntry<Object, Object> getPreviousInAccessQueue() { 895 return this; 896 } 897 898 @Override setPreviousInAccessQueue(ReferenceEntry<Object, Object> previous)899 public void setPreviousInAccessQueue(ReferenceEntry<Object, Object> previous) {} 900 901 @Override getWriteTime()902 public long getWriteTime() { 903 return 0; 904 } 905 906 @Override setWriteTime(long time)907 public void setWriteTime(long time) {} 908 909 @Override getNextInWriteQueue()910 public ReferenceEntry<Object, Object> getNextInWriteQueue() { 911 return this; 912 } 913 914 @Override setNextInWriteQueue(ReferenceEntry<Object, Object> next)915 public void setNextInWriteQueue(ReferenceEntry<Object, Object> next) {} 916 917 @Override getPreviousInWriteQueue()918 public ReferenceEntry<Object, Object> getPreviousInWriteQueue() { 919 return this; 920 } 921 922 @Override setPreviousInWriteQueue(ReferenceEntry<Object, Object> previous)923 public void setPreviousInWriteQueue(ReferenceEntry<Object, Object> previous) {} 924 } 925 926 static abstract class AbstractReferenceEntry<K, V> implements ReferenceEntry<K, V> { 927 @Override getValueReference()928 public ValueReference<K, V> getValueReference() { 929 throw new UnsupportedOperationException(); 930 } 931 932 @Override setValueReference(ValueReference<K, V> valueReference)933 public void setValueReference(ValueReference<K, V> valueReference) { 934 throw new UnsupportedOperationException(); 935 } 936 937 @Override getNext()938 public ReferenceEntry<K, V> getNext() { 939 throw new UnsupportedOperationException(); 940 } 941 942 @Override getHash()943 public int getHash() { 944 throw new UnsupportedOperationException(); 945 } 946 947 @Override getKey()948 public K getKey() { 949 throw new UnsupportedOperationException(); 950 } 951 952 @Override getAccessTime()953 public long getAccessTime() { 954 throw new UnsupportedOperationException(); 955 } 956 957 @Override setAccessTime(long time)958 public void setAccessTime(long time) { 959 throw new UnsupportedOperationException(); 960 } 961 962 @Override getNextInAccessQueue()963 public ReferenceEntry<K, V> getNextInAccessQueue() { 964 throw new UnsupportedOperationException(); 965 } 966 967 @Override setNextInAccessQueue(ReferenceEntry<K, V> next)968 public void setNextInAccessQueue(ReferenceEntry<K, V> next) { 969 throw new UnsupportedOperationException(); 970 } 971 972 @Override getPreviousInAccessQueue()973 public ReferenceEntry<K, V> getPreviousInAccessQueue() { 974 throw new UnsupportedOperationException(); 975 } 976 977 @Override setPreviousInAccessQueue(ReferenceEntry<K, V> previous)978 public void setPreviousInAccessQueue(ReferenceEntry<K, V> previous) { 979 throw new UnsupportedOperationException(); 980 } 981 982 @Override getWriteTime()983 public long getWriteTime() { 984 throw new UnsupportedOperationException(); 985 } 986 987 @Override setWriteTime(long time)988 public void setWriteTime(long time) { 989 throw new UnsupportedOperationException(); 990 } 991 992 @Override getNextInWriteQueue()993 public ReferenceEntry<K, V> getNextInWriteQueue() { 994 throw new UnsupportedOperationException(); 995 } 996 997 @Override setNextInWriteQueue(ReferenceEntry<K, V> next)998 public void setNextInWriteQueue(ReferenceEntry<K, V> next) { 999 throw new UnsupportedOperationException(); 1000 } 1001 1002 @Override getPreviousInWriteQueue()1003 public ReferenceEntry<K, V> getPreviousInWriteQueue() { 1004 throw new UnsupportedOperationException(); 1005 } 1006 1007 @Override setPreviousInWriteQueue(ReferenceEntry<K, V> previous)1008 public void setPreviousInWriteQueue(ReferenceEntry<K, V> previous) { 1009 throw new UnsupportedOperationException(); 1010 } 1011 } 1012 1013 @SuppressWarnings("unchecked") // impl never uses a parameter or returns any non-null value nullEntry()1014 static <K, V> ReferenceEntry<K, V> nullEntry() { 1015 return (ReferenceEntry<K, V>) NullEntry.INSTANCE; 1016 } 1017 1018 static final Queue<? extends Object> DISCARDING_QUEUE = new AbstractQueue<Object>() { 1019 @Override 1020 public boolean offer(Object o) { 1021 return true; 1022 } 1023 1024 @Override 1025 public Object peek() { 1026 return null; 1027 } 1028 1029 @Override 1030 public Object poll() { 1031 return null; 1032 } 1033 1034 @Override 1035 public int size() { 1036 return 0; 1037 } 1038 1039 @Override 1040 public Iterator<Object> iterator() { 1041 return ImmutableSet.of().iterator(); 1042 } 1043 }; 1044 1045 /** 1046 * Queue that discards all elements. 1047 */ 1048 @SuppressWarnings("unchecked") // impl never uses a parameter or returns any non-null value discardingQueue()1049 static <E> Queue<E> discardingQueue() { 1050 return (Queue) DISCARDING_QUEUE; 1051 } 1052 1053 /* 1054 * Note: All of this duplicate code sucks, but it saves a lot of memory. If only Java had mixins! 1055 * To maintain this code, make a change for the strong reference type. Then, cut and paste, and 1056 * replace "Strong" with "Soft" or "Weak" within the pasted text. The primary difference is that 1057 * strong entries store the key reference directly while soft and weak entries delegate to their 1058 * respective superclasses. 1059 */ 1060 1061 /** 1062 * Used for strongly-referenced keys. 1063 */ 1064 static class StrongEntry<K, V> extends AbstractReferenceEntry<K, V> { 1065 final K key; 1066 StrongEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next)1067 StrongEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) { 1068 this.key = key; 1069 this.hash = hash; 1070 this.next = next; 1071 } 1072 1073 @Override getKey()1074 public K getKey() { 1075 return this.key; 1076 } 1077 1078 // The code below is exactly the same for each entry type. 1079 1080 final int hash; 1081 final ReferenceEntry<K, V> next; 1082 volatile ValueReference<K, V> valueReference = unset(); 1083 1084 @Override getValueReference()1085 public ValueReference<K, V> getValueReference() { 1086 return valueReference; 1087 } 1088 1089 @Override setValueReference(ValueReference<K, V> valueReference)1090 public void setValueReference(ValueReference<K, V> valueReference) { 1091 this.valueReference = valueReference; 1092 } 1093 1094 @Override getHash()1095 public int getHash() { 1096 return hash; 1097 } 1098 1099 @Override getNext()1100 public ReferenceEntry<K, V> getNext() { 1101 return next; 1102 } 1103 } 1104 1105 static final class StrongAccessEntry<K, V> extends StrongEntry<K, V> { StrongAccessEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next)1106 StrongAccessEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) { 1107 super(key, hash, next); 1108 } 1109 1110 // The code below is exactly the same for each access entry type. 1111 1112 volatile long accessTime = Long.MAX_VALUE; 1113 1114 @Override getAccessTime()1115 public long getAccessTime() { 1116 return accessTime; 1117 } 1118 1119 @Override setAccessTime(long time)1120 public void setAccessTime(long time) { 1121 this.accessTime = time; 1122 } 1123 1124 // Guarded By Segment.this 1125 ReferenceEntry<K, V> nextAccess = nullEntry(); 1126 1127 @Override getNextInAccessQueue()1128 public ReferenceEntry<K, V> getNextInAccessQueue() { 1129 return nextAccess; 1130 } 1131 1132 @Override setNextInAccessQueue(ReferenceEntry<K, V> next)1133 public void setNextInAccessQueue(ReferenceEntry<K, V> next) { 1134 this.nextAccess = next; 1135 } 1136 1137 // Guarded By Segment.this 1138 ReferenceEntry<K, V> previousAccess = nullEntry(); 1139 1140 @Override getPreviousInAccessQueue()1141 public ReferenceEntry<K, V> getPreviousInAccessQueue() { 1142 return previousAccess; 1143 } 1144 1145 @Override setPreviousInAccessQueue(ReferenceEntry<K, V> previous)1146 public void setPreviousInAccessQueue(ReferenceEntry<K, V> previous) { 1147 this.previousAccess = previous; 1148 } 1149 } 1150 1151 static final class StrongWriteEntry<K, V> extends StrongEntry<K, V> { StrongWriteEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next)1152 StrongWriteEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) { 1153 super(key, hash, next); 1154 } 1155 1156 // The code below is exactly the same for each write entry type. 1157 1158 volatile long writeTime = Long.MAX_VALUE; 1159 1160 @Override getWriteTime()1161 public long getWriteTime() { 1162 return writeTime; 1163 } 1164 1165 @Override setWriteTime(long time)1166 public void setWriteTime(long time) { 1167 this.writeTime = time; 1168 } 1169 1170 // Guarded By Segment.this 1171 ReferenceEntry<K, V> nextWrite = nullEntry(); 1172 1173 @Override getNextInWriteQueue()1174 public ReferenceEntry<K, V> getNextInWriteQueue() { 1175 return nextWrite; 1176 } 1177 1178 @Override setNextInWriteQueue(ReferenceEntry<K, V> next)1179 public void setNextInWriteQueue(ReferenceEntry<K, V> next) { 1180 this.nextWrite = next; 1181 } 1182 1183 // Guarded By Segment.this 1184 ReferenceEntry<K, V> previousWrite = nullEntry(); 1185 1186 @Override getPreviousInWriteQueue()1187 public ReferenceEntry<K, V> getPreviousInWriteQueue() { 1188 return previousWrite; 1189 } 1190 1191 @Override setPreviousInWriteQueue(ReferenceEntry<K, V> previous)1192 public void setPreviousInWriteQueue(ReferenceEntry<K, V> previous) { 1193 this.previousWrite = previous; 1194 } 1195 } 1196 1197 static final class StrongAccessWriteEntry<K, V> extends StrongEntry<K, V> { StrongAccessWriteEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next)1198 StrongAccessWriteEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) { 1199 super(key, hash, next); 1200 } 1201 1202 // The code below is exactly the same for each access entry type. 1203 1204 volatile long accessTime = Long.MAX_VALUE; 1205 1206 @Override getAccessTime()1207 public long getAccessTime() { 1208 return accessTime; 1209 } 1210 1211 @Override setAccessTime(long time)1212 public void setAccessTime(long time) { 1213 this.accessTime = time; 1214 } 1215 1216 // Guarded By Segment.this 1217 ReferenceEntry<K, V> nextAccess = nullEntry(); 1218 1219 @Override getNextInAccessQueue()1220 public ReferenceEntry<K, V> getNextInAccessQueue() { 1221 return nextAccess; 1222 } 1223 1224 @Override setNextInAccessQueue(ReferenceEntry<K, V> next)1225 public void setNextInAccessQueue(ReferenceEntry<K, V> next) { 1226 this.nextAccess = next; 1227 } 1228 1229 // Guarded By Segment.this 1230 ReferenceEntry<K, V> previousAccess = nullEntry(); 1231 1232 @Override getPreviousInAccessQueue()1233 public ReferenceEntry<K, V> getPreviousInAccessQueue() { 1234 return previousAccess; 1235 } 1236 1237 @Override setPreviousInAccessQueue(ReferenceEntry<K, V> previous)1238 public void setPreviousInAccessQueue(ReferenceEntry<K, V> previous) { 1239 this.previousAccess = previous; 1240 } 1241 1242 // The code below is exactly the same for each write entry type. 1243 1244 volatile long writeTime = Long.MAX_VALUE; 1245 1246 @Override getWriteTime()1247 public long getWriteTime() { 1248 return writeTime; 1249 } 1250 1251 @Override setWriteTime(long time)1252 public void setWriteTime(long time) { 1253 this.writeTime = time; 1254 } 1255 1256 // Guarded By Segment.this 1257 ReferenceEntry<K, V> nextWrite = nullEntry(); 1258 1259 @Override getNextInWriteQueue()1260 public ReferenceEntry<K, V> getNextInWriteQueue() { 1261 return nextWrite; 1262 } 1263 1264 @Override setNextInWriteQueue(ReferenceEntry<K, V> next)1265 public void setNextInWriteQueue(ReferenceEntry<K, V> next) { 1266 this.nextWrite = next; 1267 } 1268 1269 // Guarded By Segment.this 1270 ReferenceEntry<K, V> previousWrite = nullEntry(); 1271 1272 @Override getPreviousInWriteQueue()1273 public ReferenceEntry<K, V> getPreviousInWriteQueue() { 1274 return previousWrite; 1275 } 1276 1277 @Override setPreviousInWriteQueue(ReferenceEntry<K, V> previous)1278 public void setPreviousInWriteQueue(ReferenceEntry<K, V> previous) { 1279 this.previousWrite = previous; 1280 } 1281 } 1282 1283 /** 1284 * Used for weakly-referenced keys. 1285 */ 1286 static class WeakEntry<K, V> extends WeakReference<K> implements ReferenceEntry<K, V> { WeakEntry(ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next)1287 WeakEntry(ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) { 1288 super(key, queue); 1289 this.hash = hash; 1290 this.next = next; 1291 } 1292 1293 @Override getKey()1294 public K getKey() { 1295 return get(); 1296 } 1297 1298 /* 1299 * It'd be nice to get these for free from AbstractReferenceEntry, but we're already extending 1300 * WeakReference<K>. 1301 */ 1302 1303 // null access 1304 1305 @Override getAccessTime()1306 public long getAccessTime() { 1307 throw new UnsupportedOperationException(); 1308 } 1309 1310 @Override setAccessTime(long time)1311 public void setAccessTime(long time) { 1312 throw new UnsupportedOperationException(); 1313 } 1314 1315 @Override getNextInAccessQueue()1316 public ReferenceEntry<K, V> getNextInAccessQueue() { 1317 throw new UnsupportedOperationException(); 1318 } 1319 1320 @Override setNextInAccessQueue(ReferenceEntry<K, V> next)1321 public void setNextInAccessQueue(ReferenceEntry<K, V> next) { 1322 throw new UnsupportedOperationException(); 1323 } 1324 1325 @Override getPreviousInAccessQueue()1326 public ReferenceEntry<K, V> getPreviousInAccessQueue() { 1327 throw new UnsupportedOperationException(); 1328 } 1329 1330 @Override setPreviousInAccessQueue(ReferenceEntry<K, V> previous)1331 public void setPreviousInAccessQueue(ReferenceEntry<K, V> previous) { 1332 throw new UnsupportedOperationException(); 1333 } 1334 1335 // null write 1336 1337 @Override getWriteTime()1338 public long getWriteTime() { 1339 throw new UnsupportedOperationException(); 1340 } 1341 1342 @Override setWriteTime(long time)1343 public void setWriteTime(long time) { 1344 throw new UnsupportedOperationException(); 1345 } 1346 1347 @Override getNextInWriteQueue()1348 public ReferenceEntry<K, V> getNextInWriteQueue() { 1349 throw new UnsupportedOperationException(); 1350 } 1351 1352 @Override setNextInWriteQueue(ReferenceEntry<K, V> next)1353 public void setNextInWriteQueue(ReferenceEntry<K, V> next) { 1354 throw new UnsupportedOperationException(); 1355 } 1356 1357 @Override getPreviousInWriteQueue()1358 public ReferenceEntry<K, V> getPreviousInWriteQueue() { 1359 throw new UnsupportedOperationException(); 1360 } 1361 1362 @Override setPreviousInWriteQueue(ReferenceEntry<K, V> previous)1363 public void setPreviousInWriteQueue(ReferenceEntry<K, V> previous) { 1364 throw new UnsupportedOperationException(); 1365 } 1366 1367 // The code below is exactly the same for each entry type. 1368 1369 final int hash; 1370 final ReferenceEntry<K, V> next; 1371 volatile ValueReference<K, V> valueReference = unset(); 1372 1373 @Override getValueReference()1374 public ValueReference<K, V> getValueReference() { 1375 return valueReference; 1376 } 1377 1378 @Override setValueReference(ValueReference<K, V> valueReference)1379 public void setValueReference(ValueReference<K, V> valueReference) { 1380 this.valueReference = valueReference; 1381 } 1382 1383 @Override getHash()1384 public int getHash() { 1385 return hash; 1386 } 1387 1388 @Override getNext()1389 public ReferenceEntry<K, V> getNext() { 1390 return next; 1391 } 1392 } 1393 1394 static final class WeakAccessEntry<K, V> extends WeakEntry<K, V> { WeakAccessEntry( ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next)1395 WeakAccessEntry( 1396 ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) { 1397 super(queue, key, hash, next); 1398 } 1399 1400 // The code below is exactly the same for each access entry type. 1401 1402 volatile long accessTime = Long.MAX_VALUE; 1403 1404 @Override getAccessTime()1405 public long getAccessTime() { 1406 return accessTime; 1407 } 1408 1409 @Override setAccessTime(long time)1410 public void setAccessTime(long time) { 1411 this.accessTime = time; 1412 } 1413 1414 // Guarded By Segment.this 1415 ReferenceEntry<K, V> nextAccess = nullEntry(); 1416 1417 @Override getNextInAccessQueue()1418 public ReferenceEntry<K, V> getNextInAccessQueue() { 1419 return nextAccess; 1420 } 1421 1422 @Override setNextInAccessQueue(ReferenceEntry<K, V> next)1423 public void setNextInAccessQueue(ReferenceEntry<K, V> next) { 1424 this.nextAccess = next; 1425 } 1426 1427 // Guarded By Segment.this 1428 ReferenceEntry<K, V> previousAccess = nullEntry(); 1429 1430 @Override getPreviousInAccessQueue()1431 public ReferenceEntry<K, V> getPreviousInAccessQueue() { 1432 return previousAccess; 1433 } 1434 1435 @Override setPreviousInAccessQueue(ReferenceEntry<K, V> previous)1436 public void setPreviousInAccessQueue(ReferenceEntry<K, V> previous) { 1437 this.previousAccess = previous; 1438 } 1439 } 1440 1441 static final class WeakWriteEntry<K, V> extends WeakEntry<K, V> { WeakWriteEntry( ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next)1442 WeakWriteEntry( 1443 ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) { 1444 super(queue, key, hash, next); 1445 } 1446 1447 // The code below is exactly the same for each write entry type. 1448 1449 volatile long writeTime = Long.MAX_VALUE; 1450 1451 @Override getWriteTime()1452 public long getWriteTime() { 1453 return writeTime; 1454 } 1455 1456 @Override setWriteTime(long time)1457 public void setWriteTime(long time) { 1458 this.writeTime = time; 1459 } 1460 1461 // Guarded By Segment.this 1462 ReferenceEntry<K, V> nextWrite = nullEntry(); 1463 1464 @Override getNextInWriteQueue()1465 public ReferenceEntry<K, V> getNextInWriteQueue() { 1466 return nextWrite; 1467 } 1468 1469 @Override setNextInWriteQueue(ReferenceEntry<K, V> next)1470 public void setNextInWriteQueue(ReferenceEntry<K, V> next) { 1471 this.nextWrite = next; 1472 } 1473 1474 // Guarded By Segment.this 1475 ReferenceEntry<K, V> previousWrite = nullEntry(); 1476 1477 @Override getPreviousInWriteQueue()1478 public ReferenceEntry<K, V> getPreviousInWriteQueue() { 1479 return previousWrite; 1480 } 1481 1482 @Override setPreviousInWriteQueue(ReferenceEntry<K, V> previous)1483 public void setPreviousInWriteQueue(ReferenceEntry<K, V> previous) { 1484 this.previousWrite = previous; 1485 } 1486 } 1487 1488 static final class WeakAccessWriteEntry<K, V> extends WeakEntry<K, V> { WeakAccessWriteEntry( ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next)1489 WeakAccessWriteEntry( 1490 ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) { 1491 super(queue, key, hash, next); 1492 } 1493 1494 // The code below is exactly the same for each access entry type. 1495 1496 volatile long accessTime = Long.MAX_VALUE; 1497 1498 @Override getAccessTime()1499 public long getAccessTime() { 1500 return accessTime; 1501 } 1502 1503 @Override setAccessTime(long time)1504 public void setAccessTime(long time) { 1505 this.accessTime = time; 1506 } 1507 1508 // Guarded By Segment.this 1509 ReferenceEntry<K, V> nextAccess = nullEntry(); 1510 1511 @Override getNextInAccessQueue()1512 public ReferenceEntry<K, V> getNextInAccessQueue() { 1513 return nextAccess; 1514 } 1515 1516 @Override setNextInAccessQueue(ReferenceEntry<K, V> next)1517 public void setNextInAccessQueue(ReferenceEntry<K, V> next) { 1518 this.nextAccess = next; 1519 } 1520 1521 // Guarded By Segment.this 1522 ReferenceEntry<K, V> previousAccess = nullEntry(); 1523 1524 @Override getPreviousInAccessQueue()1525 public ReferenceEntry<K, V> getPreviousInAccessQueue() { 1526 return previousAccess; 1527 } 1528 1529 @Override setPreviousInAccessQueue(ReferenceEntry<K, V> previous)1530 public void setPreviousInAccessQueue(ReferenceEntry<K, V> previous) { 1531 this.previousAccess = previous; 1532 } 1533 1534 // The code below is exactly the same for each write entry type. 1535 1536 volatile long writeTime = Long.MAX_VALUE; 1537 1538 @Override getWriteTime()1539 public long getWriteTime() { 1540 return writeTime; 1541 } 1542 1543 @Override setWriteTime(long time)1544 public void setWriteTime(long time) { 1545 this.writeTime = time; 1546 } 1547 1548 // Guarded By Segment.this 1549 ReferenceEntry<K, V> nextWrite = nullEntry(); 1550 1551 @Override getNextInWriteQueue()1552 public ReferenceEntry<K, V> getNextInWriteQueue() { 1553 return nextWrite; 1554 } 1555 1556 @Override setNextInWriteQueue(ReferenceEntry<K, V> next)1557 public void setNextInWriteQueue(ReferenceEntry<K, V> next) { 1558 this.nextWrite = next; 1559 } 1560 1561 // Guarded By Segment.this 1562 ReferenceEntry<K, V> previousWrite = nullEntry(); 1563 1564 @Override getPreviousInWriteQueue()1565 public ReferenceEntry<K, V> getPreviousInWriteQueue() { 1566 return previousWrite; 1567 } 1568 1569 @Override setPreviousInWriteQueue(ReferenceEntry<K, V> previous)1570 public void setPreviousInWriteQueue(ReferenceEntry<K, V> previous) { 1571 this.previousWrite = previous; 1572 } 1573 } 1574 1575 /** 1576 * References a weak value. 1577 */ 1578 static class WeakValueReference<K, V> 1579 extends WeakReference<V> implements ValueReference<K, V> { 1580 final ReferenceEntry<K, V> entry; 1581 WeakValueReference(ReferenceQueue<V> queue, V referent, ReferenceEntry<K, V> entry)1582 WeakValueReference(ReferenceQueue<V> queue, V referent, ReferenceEntry<K, V> entry) { 1583 super(referent, queue); 1584 this.entry = entry; 1585 } 1586 1587 @Override getWeight()1588 public int getWeight() { 1589 return 1; 1590 } 1591 1592 @Override getEntry()1593 public ReferenceEntry<K, V> getEntry() { 1594 return entry; 1595 } 1596 1597 @Override notifyNewValue(V newValue)1598 public void notifyNewValue(V newValue) {} 1599 1600 @Override copyFor( ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry)1601 public ValueReference<K, V> copyFor( 1602 ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) { 1603 return new WeakValueReference<K, V>(queue, value, entry); 1604 } 1605 1606 @Override isLoading()1607 public boolean isLoading() { 1608 return false; 1609 } 1610 1611 @Override isActive()1612 public boolean isActive() { 1613 return true; 1614 } 1615 1616 @Override waitForValue()1617 public V waitForValue() { 1618 return get(); 1619 } 1620 } 1621 1622 /** 1623 * References a soft value. 1624 */ 1625 static class SoftValueReference<K, V> 1626 extends SoftReference<V> implements ValueReference<K, V> { 1627 final ReferenceEntry<K, V> entry; 1628 SoftValueReference(ReferenceQueue<V> queue, V referent, ReferenceEntry<K, V> entry)1629 SoftValueReference(ReferenceQueue<V> queue, V referent, ReferenceEntry<K, V> entry) { 1630 super(referent, queue); 1631 this.entry = entry; 1632 } 1633 1634 @Override getWeight()1635 public int getWeight() { 1636 return 1; 1637 } 1638 1639 @Override getEntry()1640 public ReferenceEntry<K, V> getEntry() { 1641 return entry; 1642 } 1643 1644 @Override notifyNewValue(V newValue)1645 public void notifyNewValue(V newValue) {} 1646 1647 @Override copyFor( ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry)1648 public ValueReference<K, V> copyFor( 1649 ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) { 1650 return new SoftValueReference<K, V>(queue, value, entry); 1651 } 1652 1653 @Override isLoading()1654 public boolean isLoading() { 1655 return false; 1656 } 1657 1658 @Override isActive()1659 public boolean isActive() { 1660 return true; 1661 } 1662 1663 @Override waitForValue()1664 public V waitForValue() { 1665 return get(); 1666 } 1667 } 1668 1669 /** 1670 * References a strong value. 1671 */ 1672 static class StrongValueReference<K, V> implements ValueReference<K, V> { 1673 final V referent; 1674 StrongValueReference(V referent)1675 StrongValueReference(V referent) { 1676 this.referent = referent; 1677 } 1678 1679 @Override get()1680 public V get() { 1681 return referent; 1682 } 1683 1684 @Override getWeight()1685 public int getWeight() { 1686 return 1; 1687 } 1688 1689 @Override getEntry()1690 public ReferenceEntry<K, V> getEntry() { 1691 return null; 1692 } 1693 1694 @Override copyFor( ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry)1695 public ValueReference<K, V> copyFor( 1696 ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) { 1697 return this; 1698 } 1699 1700 @Override isLoading()1701 public boolean isLoading() { 1702 return false; 1703 } 1704 1705 @Override isActive()1706 public boolean isActive() { 1707 return true; 1708 } 1709 1710 @Override waitForValue()1711 public V waitForValue() { 1712 return get(); 1713 } 1714 1715 @Override notifyNewValue(V newValue)1716 public void notifyNewValue(V newValue) {} 1717 } 1718 1719 /** 1720 * References a weak value. 1721 */ 1722 static final class WeightedWeakValueReference<K, V> extends WeakValueReference<K, V> { 1723 final int weight; 1724 WeightedWeakValueReference(ReferenceQueue<V> queue, V referent, ReferenceEntry<K, V> entry, int weight)1725 WeightedWeakValueReference(ReferenceQueue<V> queue, V referent, ReferenceEntry<K, V> entry, 1726 int weight) { 1727 super(queue, referent, entry); 1728 this.weight = weight; 1729 } 1730 1731 @Override getWeight()1732 public int getWeight() { 1733 return weight; 1734 } 1735 1736 @Override copyFor( ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry)1737 public ValueReference<K, V> copyFor( 1738 ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) { 1739 return new WeightedWeakValueReference<K, V>(queue, value, entry, weight); 1740 } 1741 } 1742 1743 /** 1744 * References a soft value. 1745 */ 1746 static final class WeightedSoftValueReference<K, V> extends SoftValueReference<K, V> { 1747 final int weight; 1748 WeightedSoftValueReference(ReferenceQueue<V> queue, V referent, ReferenceEntry<K, V> entry, int weight)1749 WeightedSoftValueReference(ReferenceQueue<V> queue, V referent, ReferenceEntry<K, V> entry, 1750 int weight) { 1751 super(queue, referent, entry); 1752 this.weight = weight; 1753 } 1754 1755 @Override getWeight()1756 public int getWeight() { 1757 return weight; 1758 } 1759 @Override copyFor( ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry)1760 public ValueReference<K, V> copyFor( 1761 ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) { 1762 return new WeightedSoftValueReference<K, V>(queue, value, entry, weight); 1763 } 1764 1765 } 1766 1767 /** 1768 * References a strong value. 1769 */ 1770 static final class WeightedStrongValueReference<K, V> extends StrongValueReference<K, V> { 1771 final int weight; 1772 WeightedStrongValueReference(V referent, int weight)1773 WeightedStrongValueReference(V referent, int weight) { 1774 super(referent); 1775 this.weight = weight; 1776 } 1777 1778 @Override getWeight()1779 public int getWeight() { 1780 return weight; 1781 } 1782 } 1783 1784 /** 1785 * Applies a supplemental hash function to a given hash code, which defends against poor quality 1786 * hash functions. This is critical when the concurrent hash map uses power-of-two length hash 1787 * tables, that otherwise encounter collisions for hash codes that do not differ in lower or 1788 * upper bits. 1789 * 1790 * @param h hash code 1791 */ rehash(int h)1792 static int rehash(int h) { 1793 // Spread bits to regularize both segment and index locations, 1794 // using variant of single-word Wang/Jenkins hash. 1795 // TODO(kevinb): use Hashing/move this to Hashing? 1796 h += (h << 15) ^ 0xffffcd7d; 1797 h ^= (h >>> 10); 1798 h += (h << 3); 1799 h ^= (h >>> 6); 1800 h += (h << 2) + (h << 14); 1801 return h ^ (h >>> 16); 1802 } 1803 1804 /** 1805 * This method is a convenience for testing. Code should call {@link Segment#newEntry} directly. 1806 */ 1807 @VisibleForTesting newEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next)1808 ReferenceEntry<K, V> newEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) { 1809 Segment<K, V> segment = segmentFor(hash); 1810 segment.lock(); 1811 try { 1812 return segment.newEntry(key, hash, next); 1813 } finally { 1814 segment.unlock(); 1815 } 1816 } 1817 1818 /** 1819 * This method is a convenience for testing. Code should call {@link Segment#copyEntry} directly. 1820 */ 1821 // Guarded By Segment.this 1822 @VisibleForTesting copyEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext)1823 ReferenceEntry<K, V> copyEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) { 1824 int hash = original.getHash(); 1825 return segmentFor(hash).copyEntry(original, newNext); 1826 } 1827 1828 /** 1829 * This method is a convenience for testing. Code should call {@link Segment#setValue} instead. 1830 */ 1831 // Guarded By Segment.this 1832 @VisibleForTesting newValueReference(ReferenceEntry<K, V> entry, V value, int weight)1833 ValueReference<K, V> newValueReference(ReferenceEntry<K, V> entry, V value, int weight) { 1834 int hash = entry.getHash(); 1835 return valueStrength.referenceValue(segmentFor(hash), entry, checkNotNull(value), weight); 1836 } 1837 hash(@ullable Object key)1838 int hash(@Nullable Object key) { 1839 int h = keyEquivalence.hash(key); 1840 return rehash(h); 1841 } 1842 reclaimValue(ValueReference<K, V> valueReference)1843 void reclaimValue(ValueReference<K, V> valueReference) { 1844 ReferenceEntry<K, V> entry = valueReference.getEntry(); 1845 int hash = entry.getHash(); 1846 segmentFor(hash).reclaimValue(entry.getKey(), hash, valueReference); 1847 } 1848 reclaimKey(ReferenceEntry<K, V> entry)1849 void reclaimKey(ReferenceEntry<K, V> entry) { 1850 int hash = entry.getHash(); 1851 segmentFor(hash).reclaimKey(entry, hash); 1852 } 1853 1854 /** 1855 * This method is a convenience for testing. Code should call {@link Segment#getLiveValue} 1856 * instead. 1857 */ 1858 @VisibleForTesting isLive(ReferenceEntry<K, V> entry, long now)1859 boolean isLive(ReferenceEntry<K, V> entry, long now) { 1860 return segmentFor(entry.getHash()).getLiveValue(entry, now) != null; 1861 } 1862 1863 /** 1864 * Returns the segment that should be used for a key with the given hash. 1865 * 1866 * @param hash the hash code for the key 1867 * @return the segment 1868 */ segmentFor(int hash)1869 Segment<K, V> segmentFor(int hash) { 1870 // TODO(fry): Lazily create segments? 1871 return segments[(hash >>> segmentShift) & segmentMask]; 1872 } 1873 createSegment( int initialCapacity, long maxSegmentWeight, StatsCounter statsCounter)1874 Segment<K, V> createSegment( 1875 int initialCapacity, long maxSegmentWeight, StatsCounter statsCounter) { 1876 return new Segment<K, V>(this, initialCapacity, maxSegmentWeight, statsCounter); 1877 } 1878 1879 /** 1880 * Gets the value from an entry. Returns null if the entry is invalid, partially-collected, 1881 * loading, or expired. Unlike {@link Segment#getLiveValue} this method does not attempt to 1882 * cleanup stale entries. As such it should only be called outside of a segment context, such as 1883 * during iteration. 1884 */ 1885 @Nullable getLiveValue(ReferenceEntry<K, V> entry, long now)1886 V getLiveValue(ReferenceEntry<K, V> entry, long now) { 1887 if (entry.getKey() == null) { 1888 return null; 1889 } 1890 V value = entry.getValueReference().get(); 1891 if (value == null) { 1892 return null; 1893 } 1894 1895 if (isExpired(entry, now)) { 1896 return null; 1897 } 1898 return value; 1899 } 1900 1901 // expiration 1902 1903 /** 1904 * Returns true if the entry has expired. 1905 */ isExpired(ReferenceEntry<K, V> entry, long now)1906 boolean isExpired(ReferenceEntry<K, V> entry, long now) { 1907 checkNotNull(entry); 1908 if (expiresAfterAccess() 1909 && (now - entry.getAccessTime() >= expireAfterAccessNanos)) { 1910 return true; 1911 } 1912 if (expiresAfterWrite() 1913 && (now - entry.getWriteTime() >= expireAfterWriteNanos)) { 1914 return true; 1915 } 1916 return false; 1917 } 1918 1919 // queues 1920 1921 // Guarded By Segment.this connectAccessOrder(ReferenceEntry<K, V> previous, ReferenceEntry<K, V> next)1922 static <K, V> void connectAccessOrder(ReferenceEntry<K, V> previous, ReferenceEntry<K, V> next) { 1923 previous.setNextInAccessQueue(next); 1924 next.setPreviousInAccessQueue(previous); 1925 } 1926 1927 // Guarded By Segment.this nullifyAccessOrder(ReferenceEntry<K, V> nulled)1928 static <K, V> void nullifyAccessOrder(ReferenceEntry<K, V> nulled) { 1929 ReferenceEntry<K, V> nullEntry = nullEntry(); 1930 nulled.setNextInAccessQueue(nullEntry); 1931 nulled.setPreviousInAccessQueue(nullEntry); 1932 } 1933 1934 // Guarded By Segment.this connectWriteOrder(ReferenceEntry<K, V> previous, ReferenceEntry<K, V> next)1935 static <K, V> void connectWriteOrder(ReferenceEntry<K, V> previous, ReferenceEntry<K, V> next) { 1936 previous.setNextInWriteQueue(next); 1937 next.setPreviousInWriteQueue(previous); 1938 } 1939 1940 // Guarded By Segment.this nullifyWriteOrder(ReferenceEntry<K, V> nulled)1941 static <K, V> void nullifyWriteOrder(ReferenceEntry<K, V> nulled) { 1942 ReferenceEntry<K, V> nullEntry = nullEntry(); 1943 nulled.setNextInWriteQueue(nullEntry); 1944 nulled.setPreviousInWriteQueue(nullEntry); 1945 } 1946 1947 /** 1948 * Notifies listeners that an entry has been automatically removed due to expiration, eviction, 1949 * or eligibility for garbage collection. This should be called every time expireEntries or 1950 * evictEntry is called (once the lock is released). 1951 */ processPendingNotifications()1952 void processPendingNotifications() { 1953 RemovalNotification<K, V> notification; 1954 while ((notification = removalNotificationQueue.poll()) != null) { 1955 try { 1956 removalListener.onRemoval(notification); 1957 } catch (Throwable e) { 1958 logger.log(Level.WARNING, "Exception thrown by removal listener", e); 1959 } 1960 } 1961 } 1962 1963 @SuppressWarnings("unchecked") newSegmentArray(int ssize)1964 final Segment<K, V>[] newSegmentArray(int ssize) { 1965 return new Segment[ssize]; 1966 } 1967 1968 // Inner Classes 1969 1970 /** 1971 * Segments are specialized versions of hash tables. This subclass inherits from ReentrantLock 1972 * opportunistically, just to simplify some locking and avoid separate construction. 1973 */ 1974 @SuppressWarnings("serial") // This class is never serialized. 1975 static class Segment<K, V> extends ReentrantLock { 1976 1977 /* 1978 * TODO(fry): Consider copying variables (like evictsBySize) from outer class into this class. 1979 * It will require more memory but will reduce indirection. 1980 */ 1981 1982 /* 1983 * Segments maintain a table of entry lists that are ALWAYS kept in a consistent state, so can 1984 * be read without locking. Next fields of nodes are immutable (final). All list additions are 1985 * performed at the front of each bin. This makes it easy to check changes, and also fast to 1986 * traverse. When nodes would otherwise be changed, new nodes are created to replace them. This 1987 * works well for hash tables since the bin lists tend to be short. (The average length is less 1988 * than two.) 1989 * 1990 * Read operations can thus proceed without locking, but rely on selected uses of volatiles to 1991 * ensure that completed write operations performed by other threads are noticed. For most 1992 * purposes, the "count" field, tracking the number of elements, serves as that volatile 1993 * variable ensuring visibility. This is convenient because this field needs to be read in many 1994 * read operations anyway: 1995 * 1996 * - All (unsynchronized) read operations must first read the "count" field, and should not 1997 * look at table entries if it is 0. 1998 * 1999 * - All (synchronized) write operations should write to the "count" field after structurally 2000 * changing any bin. The operations must not take any action that could even momentarily 2001 * cause a concurrent read operation to see inconsistent data. This is made easier by the 2002 * nature of the read operations in Map. For example, no operation can reveal that the table 2003 * has grown but the threshold has not yet been updated, so there are no atomicity requirements 2004 * for this with respect to reads. 2005 * 2006 * As a guide, all critical volatile reads and writes to the count field are marked in code 2007 * comments. 2008 */ 2009 2010 final LocalCache<K, V> map; 2011 2012 /** 2013 * The number of live elements in this segment's region. 2014 */ 2015 volatile int count; 2016 2017 /** 2018 * The weight of the live elements in this segment's region. 2019 */ 2020 @GuardedBy("this") 2021 long totalWeight; 2022 2023 /** 2024 * Number of updates that alter the size of the table. This is used during bulk-read methods to 2025 * make sure they see a consistent snapshot: If modCounts change during a traversal of segments 2026 * loading size or checking containsValue, then we might have an inconsistent view of state 2027 * so (usually) must retry. 2028 */ 2029 int modCount; 2030 2031 /** 2032 * The table is expanded when its size exceeds this threshold. (The value of this field is 2033 * always {@code (int) (capacity * 0.75)}.) 2034 */ 2035 int threshold; 2036 2037 /** 2038 * The per-segment table. 2039 */ 2040 volatile AtomicReferenceArray<ReferenceEntry<K, V>> table; 2041 2042 /** 2043 * The maximum weight of this segment. UNSET_INT if there is no maximum. 2044 */ 2045 final long maxSegmentWeight; 2046 2047 /** 2048 * The key reference queue contains entries whose keys have been garbage collected, and which 2049 * need to be cleaned up internally. 2050 */ 2051 final ReferenceQueue<K> keyReferenceQueue; 2052 2053 /** 2054 * The value reference queue contains value references whose values have been garbage collected, 2055 * and which need to be cleaned up internally. 2056 */ 2057 final ReferenceQueue<V> valueReferenceQueue; 2058 2059 /** 2060 * The recency queue is used to record which entries were accessed for updating the access 2061 * list's ordering. It is drained as a batch operation when either the DRAIN_THRESHOLD is 2062 * crossed or a write occurs on the segment. 2063 */ 2064 final Queue<ReferenceEntry<K, V>> recencyQueue; 2065 2066 /** 2067 * A counter of the number of reads since the last write, used to drain queues on a small 2068 * fraction of read operations. 2069 */ 2070 final AtomicInteger readCount = new AtomicInteger(); 2071 2072 /** 2073 * A queue of elements currently in the map, ordered by write time. Elements are added to the 2074 * tail of the queue on write. 2075 */ 2076 @GuardedBy("this") 2077 final Queue<ReferenceEntry<K, V>> writeQueue; 2078 2079 /** 2080 * A queue of elements currently in the map, ordered by access time. Elements are added to the 2081 * tail of the queue on access (note that writes count as accesses). 2082 */ 2083 @GuardedBy("this") 2084 final Queue<ReferenceEntry<K, V>> accessQueue; 2085 2086 /** Accumulates cache statistics. */ 2087 final StatsCounter statsCounter; 2088 Segment(LocalCache<K, V> map, int initialCapacity, long maxSegmentWeight, StatsCounter statsCounter)2089 Segment(LocalCache<K, V> map, int initialCapacity, long maxSegmentWeight, 2090 StatsCounter statsCounter) { 2091 this.map = map; 2092 this.maxSegmentWeight = maxSegmentWeight; 2093 this.statsCounter = checkNotNull(statsCounter); 2094 initTable(newEntryArray(initialCapacity)); 2095 2096 keyReferenceQueue = map.usesKeyReferences() 2097 ? new ReferenceQueue<K>() : null; 2098 2099 valueReferenceQueue = map.usesValueReferences() 2100 ? new ReferenceQueue<V>() : null; 2101 2102 recencyQueue = map.usesAccessQueue() 2103 ? new ConcurrentLinkedQueue<ReferenceEntry<K, V>>() 2104 : LocalCache.<ReferenceEntry<K, V>>discardingQueue(); 2105 2106 writeQueue = map.usesWriteQueue() 2107 ? new WriteQueue<K, V>() 2108 : LocalCache.<ReferenceEntry<K, V>>discardingQueue(); 2109 2110 accessQueue = map.usesAccessQueue() 2111 ? new AccessQueue<K, V>() 2112 : LocalCache.<ReferenceEntry<K, V>>discardingQueue(); 2113 } 2114 newEntryArray(int size)2115 AtomicReferenceArray<ReferenceEntry<K, V>> newEntryArray(int size) { 2116 return new AtomicReferenceArray<ReferenceEntry<K, V>>(size); 2117 } 2118 initTable(AtomicReferenceArray<ReferenceEntry<K, V>> newTable)2119 void initTable(AtomicReferenceArray<ReferenceEntry<K, V>> newTable) { 2120 this.threshold = newTable.length() * 3 / 4; // 0.75 2121 if (!map.customWeigher() && this.threshold == maxSegmentWeight) { 2122 // prevent spurious expansion before eviction 2123 this.threshold++; 2124 } 2125 this.table = newTable; 2126 } 2127 2128 @GuardedBy("this") newEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next)2129 ReferenceEntry<K, V> newEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) { 2130 return map.entryFactory.newEntry(this, checkNotNull(key), hash, next); 2131 } 2132 2133 /** 2134 * Copies {@code original} into a new entry chained to {@code newNext}. Returns the new entry, 2135 * or {@code null} if {@code original} was already garbage collected. 2136 */ 2137 @GuardedBy("this") copyEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext)2138 ReferenceEntry<K, V> copyEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) { 2139 if (original.getKey() == null) { 2140 // key collected 2141 return null; 2142 } 2143 2144 ValueReference<K, V> valueReference = original.getValueReference(); 2145 V value = valueReference.get(); 2146 if ((value == null) && valueReference.isActive()) { 2147 // value collected 2148 return null; 2149 } 2150 2151 ReferenceEntry<K, V> newEntry = map.entryFactory.copyEntry(this, original, newNext); 2152 newEntry.setValueReference(valueReference.copyFor(this.valueReferenceQueue, value, newEntry)); 2153 return newEntry; 2154 } 2155 2156 /** 2157 * Sets a new value of an entry. Adds newly created entries at the end of the access queue. 2158 */ 2159 @GuardedBy("this") setValue(ReferenceEntry<K, V> entry, K key, V value, long now)2160 void setValue(ReferenceEntry<K, V> entry, K key, V value, long now) { 2161 ValueReference<K, V> previous = entry.getValueReference(); 2162 int weight = map.weigher.weigh(key, value); 2163 checkState(weight >= 0, "Weights must be non-negative"); 2164 2165 ValueReference<K, V> valueReference = 2166 map.valueStrength.referenceValue(this, entry, value, weight); 2167 entry.setValueReference(valueReference); 2168 recordWrite(entry, weight, now); 2169 previous.notifyNewValue(value); 2170 } 2171 2172 // loading 2173 get(K key, int hash, CacheLoader<? super K, V> loader)2174 V get(K key, int hash, CacheLoader<? super K, V> loader) throws ExecutionException { 2175 checkNotNull(key); 2176 checkNotNull(loader); 2177 try { 2178 if (count != 0) { // read-volatile 2179 // don't call getLiveEntry, which would ignore loading values 2180 ReferenceEntry<K, V> e = getEntry(key, hash); 2181 if (e != null) { 2182 long now = map.ticker.read(); 2183 V value = getLiveValue(e, now); 2184 if (value != null) { 2185 recordRead(e, now); 2186 statsCounter.recordHits(1); 2187 return scheduleRefresh(e, key, hash, value, now, loader); 2188 } 2189 ValueReference<K, V> valueReference = e.getValueReference(); 2190 if (valueReference.isLoading()) { 2191 return waitForLoadingValue(e, key, valueReference); 2192 } 2193 } 2194 } 2195 2196 // at this point e is either null or expired; 2197 return lockedGetOrLoad(key, hash, loader); 2198 } catch (ExecutionException ee) { 2199 Throwable cause = ee.getCause(); 2200 if (cause instanceof Error) { 2201 throw new ExecutionError((Error) cause); 2202 } else if (cause instanceof RuntimeException) { 2203 throw new UncheckedExecutionException(cause); 2204 } 2205 throw ee; 2206 } finally { 2207 postReadCleanup(); 2208 } 2209 } 2210 lockedGetOrLoad(K key, int hash, CacheLoader<? super K, V> loader)2211 V lockedGetOrLoad(K key, int hash, CacheLoader<? super K, V> loader) 2212 throws ExecutionException { 2213 ReferenceEntry<K, V> e; 2214 ValueReference<K, V> valueReference = null; 2215 LoadingValueReference<K, V> loadingValueReference = null; 2216 boolean createNewEntry = true; 2217 2218 lock(); 2219 try { 2220 // re-read ticker once inside the lock 2221 long now = map.ticker.read(); 2222 preWriteCleanup(now); 2223 2224 int newCount = this.count - 1; 2225 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table; 2226 int index = hash & (table.length() - 1); 2227 ReferenceEntry<K, V> first = table.get(index); 2228 2229 for (e = first; e != null; e = e.getNext()) { 2230 K entryKey = e.getKey(); 2231 if (e.getHash() == hash && entryKey != null 2232 && map.keyEquivalence.equivalent(key, entryKey)) { 2233 valueReference = e.getValueReference(); 2234 if (valueReference.isLoading()) { 2235 createNewEntry = false; 2236 } else { 2237 V value = valueReference.get(); 2238 if (value == null) { 2239 enqueueNotification(entryKey, hash, valueReference, RemovalCause.COLLECTED); 2240 } else if (map.isExpired(e, now)) { 2241 // This is a duplicate check, as preWriteCleanup already purged expired 2242 // entries, but let's accomodate an incorrect expiration queue. 2243 enqueueNotification(entryKey, hash, valueReference, RemovalCause.EXPIRED); 2244 } else { 2245 recordLockedRead(e, now); 2246 statsCounter.recordHits(1); 2247 // we were concurrent with loading; don't consider refresh 2248 return value; 2249 } 2250 2251 // immediately reuse invalid entries 2252 writeQueue.remove(e); 2253 accessQueue.remove(e); 2254 this.count = newCount; // write-volatile 2255 } 2256 break; 2257 } 2258 } 2259 2260 if (createNewEntry) { 2261 loadingValueReference = new LoadingValueReference<K, V>(); 2262 2263 if (e == null) { 2264 e = newEntry(key, hash, first); 2265 e.setValueReference(loadingValueReference); 2266 table.set(index, e); 2267 } else { 2268 e.setValueReference(loadingValueReference); 2269 } 2270 } 2271 } finally { 2272 unlock(); 2273 postWriteCleanup(); 2274 } 2275 2276 if (createNewEntry) { 2277 try { 2278 // Synchronizes on the entry to allow failing fast when a recursive load is 2279 // detected. This may be circumvented when an entry is copied, but will fail fast most 2280 // of the time. 2281 synchronized (e) { 2282 return loadSync(key, hash, loadingValueReference, loader); 2283 } 2284 } finally { 2285 statsCounter.recordMisses(1); 2286 } 2287 } else { 2288 // The entry already exists. Wait for loading. 2289 return waitForLoadingValue(e, key, valueReference); 2290 } 2291 } 2292 waitForLoadingValue(ReferenceEntry<K, V> e, K key, ValueReference<K, V> valueReference)2293 V waitForLoadingValue(ReferenceEntry<K, V> e, K key, ValueReference<K, V> valueReference) 2294 throws ExecutionException { 2295 if (!valueReference.isLoading()) { 2296 throw new AssertionError(); 2297 } 2298 2299 checkState(!Thread.holdsLock(e), "Recursive load of: %s", key); 2300 // don't consider expiration as we're concurrent with loading 2301 try { 2302 V value = valueReference.waitForValue(); 2303 if (value == null) { 2304 throw new InvalidCacheLoadException("CacheLoader returned null for key " + key + "."); 2305 } 2306 // re-read ticker now that loading has completed 2307 long now = map.ticker.read(); 2308 recordRead(e, now); 2309 return value; 2310 } finally { 2311 statsCounter.recordMisses(1); 2312 } 2313 } 2314 2315 // at most one of loadSync/loadAsync may be called for any given LoadingValueReference 2316 loadSync(K key, int hash, LoadingValueReference<K, V> loadingValueReference, CacheLoader<? super K, V> loader)2317 V loadSync(K key, int hash, LoadingValueReference<K, V> loadingValueReference, 2318 CacheLoader<? super K, V> loader) throws ExecutionException { 2319 ListenableFuture<V> loadingFuture = loadingValueReference.loadFuture(key, loader); 2320 return getAndRecordStats(key, hash, loadingValueReference, loadingFuture); 2321 } 2322 loadAsync(final K key, final int hash, final LoadingValueReference<K, V> loadingValueReference, CacheLoader<? super K, V> loader)2323 ListenableFuture<V> loadAsync(final K key, final int hash, 2324 final LoadingValueReference<K, V> loadingValueReference, CacheLoader<? super K, V> loader) { 2325 final ListenableFuture<V> loadingFuture = loadingValueReference.loadFuture(key, loader); 2326 loadingFuture.addListener( 2327 new Runnable() { 2328 @Override 2329 public void run() { 2330 try { 2331 V newValue = getAndRecordStats(key, hash, loadingValueReference, loadingFuture); 2332 } catch (Throwable t) { 2333 logger.log(Level.WARNING, "Exception thrown during refresh", t); 2334 loadingValueReference.setException(t); 2335 } 2336 } 2337 }, directExecutor()); 2338 return loadingFuture; 2339 } 2340 2341 /** 2342 * Waits uninterruptibly for {@code newValue} to be loaded, and then records loading stats. 2343 */ getAndRecordStats(K key, int hash, LoadingValueReference<K, V> loadingValueReference, ListenableFuture<V> newValue)2344 V getAndRecordStats(K key, int hash, LoadingValueReference<K, V> loadingValueReference, 2345 ListenableFuture<V> newValue) throws ExecutionException { 2346 V value = null; 2347 try { 2348 value = getUninterruptibly(newValue); 2349 if (value == null) { 2350 throw new InvalidCacheLoadException("CacheLoader returned null for key " + key + "."); 2351 } 2352 statsCounter.recordLoadSuccess(loadingValueReference.elapsedNanos()); 2353 storeLoadedValue(key, hash, loadingValueReference, value); 2354 return value; 2355 } finally { 2356 if (value == null) { 2357 statsCounter.recordLoadException(loadingValueReference.elapsedNanos()); 2358 removeLoadingValue(key, hash, loadingValueReference); 2359 } 2360 } 2361 } 2362 scheduleRefresh(ReferenceEntry<K, V> entry, K key, int hash, V oldValue, long now, CacheLoader<? super K, V> loader)2363 V scheduleRefresh(ReferenceEntry<K, V> entry, K key, int hash, V oldValue, long now, 2364 CacheLoader<? super K, V> loader) { 2365 if (map.refreshes() && (now - entry.getWriteTime() > map.refreshNanos) 2366 && !entry.getValueReference().isLoading()) { 2367 V newValue = refresh(key, hash, loader, true); 2368 if (newValue != null) { 2369 return newValue; 2370 } 2371 } 2372 return oldValue; 2373 } 2374 2375 /** 2376 * Refreshes the value associated with {@code key}, unless another thread is already doing so. 2377 * Returns the newly refreshed value associated with {@code key} if it was refreshed inline, or 2378 * {@code null} if another thread is performing the refresh or if an error occurs during 2379 * refresh. 2380 */ 2381 @Nullable refresh(K key, int hash, CacheLoader<? super K, V> loader, boolean checkTime)2382 V refresh(K key, int hash, CacheLoader<? super K, V> loader, boolean checkTime) { 2383 final LoadingValueReference<K, V> loadingValueReference = 2384 insertLoadingValueReference(key, hash, checkTime); 2385 if (loadingValueReference == null) { 2386 return null; 2387 } 2388 2389 ListenableFuture<V> result = loadAsync(key, hash, loadingValueReference, loader); 2390 if (result.isDone()) { 2391 try { 2392 return Uninterruptibles.getUninterruptibly(result); 2393 } catch (Throwable t) { 2394 // don't let refresh exceptions propagate; error was already logged 2395 } 2396 } 2397 return null; 2398 } 2399 2400 /** 2401 * Returns a newly inserted {@code LoadingValueReference}, or null if the live value reference 2402 * is already loading. 2403 */ 2404 @Nullable insertLoadingValueReference(final K key, final int hash, boolean checkTime)2405 LoadingValueReference<K, V> insertLoadingValueReference(final K key, final int hash, 2406 boolean checkTime) { 2407 ReferenceEntry<K, V> e = null; 2408 lock(); 2409 try { 2410 long now = map.ticker.read(); 2411 preWriteCleanup(now); 2412 2413 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table; 2414 int index = hash & (table.length() - 1); 2415 ReferenceEntry<K, V> first = table.get(index); 2416 2417 // Look for an existing entry. 2418 for (e = first; e != null; e = e.getNext()) { 2419 K entryKey = e.getKey(); 2420 if (e.getHash() == hash && entryKey != null 2421 && map.keyEquivalence.equivalent(key, entryKey)) { 2422 // We found an existing entry. 2423 2424 ValueReference<K, V> valueReference = e.getValueReference(); 2425 if (valueReference.isLoading() 2426 || (checkTime && (now - e.getWriteTime() < map.refreshNanos))) { 2427 // refresh is a no-op if loading is pending 2428 // if checkTime, we want to check *after* acquiring the lock if refresh still needs 2429 // to be scheduled 2430 return null; 2431 } 2432 2433 // continue returning old value while loading 2434 ++modCount; 2435 LoadingValueReference<K, V> loadingValueReference = 2436 new LoadingValueReference<K, V>(valueReference); 2437 e.setValueReference(loadingValueReference); 2438 return loadingValueReference; 2439 } 2440 } 2441 2442 ++modCount; 2443 LoadingValueReference<K, V> loadingValueReference = new LoadingValueReference<K, V>(); 2444 e = newEntry(key, hash, first); 2445 e.setValueReference(loadingValueReference); 2446 table.set(index, e); 2447 return loadingValueReference; 2448 } finally { 2449 unlock(); 2450 postWriteCleanup(); 2451 } 2452 } 2453 2454 // reference queues, for garbage collection cleanup 2455 2456 /** 2457 * Cleanup collected entries when the lock is available. 2458 */ tryDrainReferenceQueues()2459 void tryDrainReferenceQueues() { 2460 if (tryLock()) { 2461 try { 2462 drainReferenceQueues(); 2463 } finally { 2464 unlock(); 2465 } 2466 } 2467 } 2468 2469 /** 2470 * Drain the key and value reference queues, cleaning up internal entries containing garbage 2471 * collected keys or values. 2472 */ 2473 @GuardedBy("this") drainReferenceQueues()2474 void drainReferenceQueues() { 2475 if (map.usesKeyReferences()) { 2476 drainKeyReferenceQueue(); 2477 } 2478 if (map.usesValueReferences()) { 2479 drainValueReferenceQueue(); 2480 } 2481 } 2482 2483 @GuardedBy("this") drainKeyReferenceQueue()2484 void drainKeyReferenceQueue() { 2485 Reference<? extends K> ref; 2486 int i = 0; 2487 while ((ref = keyReferenceQueue.poll()) != null) { 2488 @SuppressWarnings("unchecked") 2489 ReferenceEntry<K, V> entry = (ReferenceEntry<K, V>) ref; 2490 map.reclaimKey(entry); 2491 if (++i == DRAIN_MAX) { 2492 break; 2493 } 2494 } 2495 } 2496 2497 @GuardedBy("this") drainValueReferenceQueue()2498 void drainValueReferenceQueue() { 2499 Reference<? extends V> ref; 2500 int i = 0; 2501 while ((ref = valueReferenceQueue.poll()) != null) { 2502 @SuppressWarnings("unchecked") 2503 ValueReference<K, V> valueReference = (ValueReference<K, V>) ref; 2504 map.reclaimValue(valueReference); 2505 if (++i == DRAIN_MAX) { 2506 break; 2507 } 2508 } 2509 } 2510 2511 /** 2512 * Clears all entries from the key and value reference queues. 2513 */ clearReferenceQueues()2514 void clearReferenceQueues() { 2515 if (map.usesKeyReferences()) { 2516 clearKeyReferenceQueue(); 2517 } 2518 if (map.usesValueReferences()) { 2519 clearValueReferenceQueue(); 2520 } 2521 } 2522 clearKeyReferenceQueue()2523 void clearKeyReferenceQueue() { 2524 while (keyReferenceQueue.poll() != null) {} 2525 } 2526 clearValueReferenceQueue()2527 void clearValueReferenceQueue() { 2528 while (valueReferenceQueue.poll() != null) {} 2529 } 2530 2531 // recency queue, shared by expiration and eviction 2532 2533 /** 2534 * Records the relative order in which this read was performed by adding {@code entry} to the 2535 * recency queue. At write-time, or when the queue is full past the threshold, the queue will 2536 * be drained and the entries therein processed. 2537 * 2538 * <p>Note: locked reads should use {@link #recordLockedRead}. 2539 */ recordRead(ReferenceEntry<K, V> entry, long now)2540 void recordRead(ReferenceEntry<K, V> entry, long now) { 2541 if (map.recordsAccess()) { 2542 entry.setAccessTime(now); 2543 } 2544 recencyQueue.add(entry); 2545 } 2546 2547 /** 2548 * Updates the eviction metadata that {@code entry} was just read. This currently amounts to 2549 * adding {@code entry} to relevant eviction lists. 2550 * 2551 * <p>Note: this method should only be called under lock, as it directly manipulates the 2552 * eviction queues. Unlocked reads should use {@link #recordRead}. 2553 */ 2554 @GuardedBy("this") recordLockedRead(ReferenceEntry<K, V> entry, long now)2555 void recordLockedRead(ReferenceEntry<K, V> entry, long now) { 2556 if (map.recordsAccess()) { 2557 entry.setAccessTime(now); 2558 } 2559 accessQueue.add(entry); 2560 } 2561 2562 /** 2563 * Updates eviction metadata that {@code entry} was just written. This currently amounts to 2564 * adding {@code entry} to relevant eviction lists. 2565 */ 2566 @GuardedBy("this") recordWrite(ReferenceEntry<K, V> entry, int weight, long now)2567 void recordWrite(ReferenceEntry<K, V> entry, int weight, long now) { 2568 // we are already under lock, so drain the recency queue immediately 2569 drainRecencyQueue(); 2570 totalWeight += weight; 2571 2572 if (map.recordsAccess()) { 2573 entry.setAccessTime(now); 2574 } 2575 if (map.recordsWrite()) { 2576 entry.setWriteTime(now); 2577 } 2578 accessQueue.add(entry); 2579 writeQueue.add(entry); 2580 } 2581 2582 /** 2583 * Drains the recency queue, updating eviction metadata that the entries therein were read in 2584 * the specified relative order. This currently amounts to adding them to relevant eviction 2585 * lists (accounting for the fact that they could have been removed from the map since being 2586 * added to the recency queue). 2587 */ 2588 @GuardedBy("this") drainRecencyQueue()2589 void drainRecencyQueue() { 2590 ReferenceEntry<K, V> e; 2591 while ((e = recencyQueue.poll()) != null) { 2592 // An entry may be in the recency queue despite it being removed from 2593 // the map . This can occur when the entry was concurrently read while a 2594 // writer is removing it from the segment or after a clear has removed 2595 // all of the segment's entries. 2596 if (accessQueue.contains(e)) { 2597 accessQueue.add(e); 2598 } 2599 } 2600 } 2601 2602 // expiration 2603 2604 /** 2605 * Cleanup expired entries when the lock is available. 2606 */ tryExpireEntries(long now)2607 void tryExpireEntries(long now) { 2608 if (tryLock()) { 2609 try { 2610 expireEntries(now); 2611 } finally { 2612 unlock(); 2613 // don't call postWriteCleanup as we're in a read 2614 } 2615 } 2616 } 2617 2618 @GuardedBy("this") expireEntries(long now)2619 void expireEntries(long now) { 2620 drainRecencyQueue(); 2621 2622 ReferenceEntry<K, V> e; 2623 while ((e = writeQueue.peek()) != null && map.isExpired(e, now)) { 2624 if (!removeEntry(e, e.getHash(), RemovalCause.EXPIRED)) { 2625 throw new AssertionError(); 2626 } 2627 } 2628 while ((e = accessQueue.peek()) != null && map.isExpired(e, now)) { 2629 if (!removeEntry(e, e.getHash(), RemovalCause.EXPIRED)) { 2630 throw new AssertionError(); 2631 } 2632 } 2633 } 2634 2635 // eviction 2636 2637 @GuardedBy("this") enqueueNotification(ReferenceEntry<K, V> entry, RemovalCause cause)2638 void enqueueNotification(ReferenceEntry<K, V> entry, RemovalCause cause) { 2639 enqueueNotification(entry.getKey(), entry.getHash(), entry.getValueReference(), cause); 2640 } 2641 2642 @GuardedBy("this") enqueueNotification(@ullable K key, int hash, ValueReference<K, V> valueReference, RemovalCause cause)2643 void enqueueNotification(@Nullable K key, int hash, ValueReference<K, V> valueReference, 2644 RemovalCause cause) { 2645 totalWeight -= valueReference.getWeight(); 2646 if (cause.wasEvicted()) { 2647 statsCounter.recordEviction(); 2648 } 2649 if (map.removalNotificationQueue != DISCARDING_QUEUE) { 2650 V value = valueReference.get(); 2651 RemovalNotification<K, V> notification = new RemovalNotification<K, V>(key, value, cause); 2652 map.removalNotificationQueue.offer(notification); 2653 } 2654 } 2655 2656 /** 2657 * Performs eviction if the segment is full. This should only be called prior to adding a new 2658 * entry and increasing {@code count}. 2659 */ 2660 @GuardedBy("this") evictEntries()2661 void evictEntries() { 2662 if (!map.evictsBySize()) { 2663 return; 2664 } 2665 2666 drainRecencyQueue(); 2667 while (totalWeight > maxSegmentWeight) { 2668 ReferenceEntry<K, V> e = getNextEvictable(); 2669 if (!removeEntry(e, e.getHash(), RemovalCause.SIZE)) { 2670 throw new AssertionError(); 2671 } 2672 } 2673 } 2674 2675 // TODO(fry): instead implement this with an eviction head 2676 @GuardedBy("this") getNextEvictable()2677 ReferenceEntry<K, V> getNextEvictable() { 2678 for (ReferenceEntry<K, V> e : accessQueue) { 2679 int weight = e.getValueReference().getWeight(); 2680 if (weight > 0) { 2681 return e; 2682 } 2683 } 2684 throw new AssertionError(); 2685 } 2686 2687 /** 2688 * Returns first entry of bin for given hash. 2689 */ getFirst(int hash)2690 ReferenceEntry<K, V> getFirst(int hash) { 2691 // read this volatile field only once 2692 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table; 2693 return table.get(hash & (table.length() - 1)); 2694 } 2695 2696 // Specialized implementations of map methods 2697 2698 @Nullable getEntry(Object key, int hash)2699 ReferenceEntry<K, V> getEntry(Object key, int hash) { 2700 for (ReferenceEntry<K, V> e = getFirst(hash); e != null; e = e.getNext()) { 2701 if (e.getHash() != hash) { 2702 continue; 2703 } 2704 2705 K entryKey = e.getKey(); 2706 if (entryKey == null) { 2707 tryDrainReferenceQueues(); 2708 continue; 2709 } 2710 2711 if (map.keyEquivalence.equivalent(key, entryKey)) { 2712 return e; 2713 } 2714 } 2715 2716 return null; 2717 } 2718 2719 @Nullable getLiveEntry(Object key, int hash, long now)2720 ReferenceEntry<K, V> getLiveEntry(Object key, int hash, long now) { 2721 ReferenceEntry<K, V> e = getEntry(key, hash); 2722 if (e == null) { 2723 return null; 2724 } else if (map.isExpired(e, now)) { 2725 tryExpireEntries(now); 2726 return null; 2727 } 2728 return e; 2729 } 2730 2731 /** 2732 * Gets the value from an entry. Returns null if the entry is invalid, partially-collected, 2733 * loading, or expired. 2734 */ getLiveValue(ReferenceEntry<K, V> entry, long now)2735 V getLiveValue(ReferenceEntry<K, V> entry, long now) { 2736 if (entry.getKey() == null) { 2737 tryDrainReferenceQueues(); 2738 return null; 2739 } 2740 V value = entry.getValueReference().get(); 2741 if (value == null) { 2742 tryDrainReferenceQueues(); 2743 return null; 2744 } 2745 2746 if (map.isExpired(entry, now)) { 2747 tryExpireEntries(now); 2748 return null; 2749 } 2750 return value; 2751 } 2752 2753 @Nullable get(Object key, int hash)2754 V get(Object key, int hash) { 2755 try { 2756 if (count != 0) { // read-volatile 2757 long now = map.ticker.read(); 2758 ReferenceEntry<K, V> e = getLiveEntry(key, hash, now); 2759 if (e == null) { 2760 return null; 2761 } 2762 2763 V value = e.getValueReference().get(); 2764 if (value != null) { 2765 recordRead(e, now); 2766 return scheduleRefresh(e, e.getKey(), hash, value, now, map.defaultLoader); 2767 } 2768 tryDrainReferenceQueues(); 2769 } 2770 return null; 2771 } finally { 2772 postReadCleanup(); 2773 } 2774 } 2775 containsKey(Object key, int hash)2776 boolean containsKey(Object key, int hash) { 2777 try { 2778 if (count != 0) { // read-volatile 2779 long now = map.ticker.read(); 2780 ReferenceEntry<K, V> e = getLiveEntry(key, hash, now); 2781 if (e == null) { 2782 return false; 2783 } 2784 return e.getValueReference().get() != null; 2785 } 2786 2787 return false; 2788 } finally { 2789 postReadCleanup(); 2790 } 2791 } 2792 2793 /** 2794 * This method is a convenience for testing. Code should call {@link 2795 * LocalCache#containsValue} directly. 2796 */ 2797 @VisibleForTesting containsValue(Object value)2798 boolean containsValue(Object value) { 2799 try { 2800 if (count != 0) { // read-volatile 2801 long now = map.ticker.read(); 2802 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table; 2803 int length = table.length(); 2804 for (int i = 0; i < length; ++i) { 2805 for (ReferenceEntry<K, V> e = table.get(i); e != null; e = e.getNext()) { 2806 V entryValue = getLiveValue(e, now); 2807 if (entryValue == null) { 2808 continue; 2809 } 2810 if (map.valueEquivalence.equivalent(value, entryValue)) { 2811 return true; 2812 } 2813 } 2814 } 2815 } 2816 2817 return false; 2818 } finally { 2819 postReadCleanup(); 2820 } 2821 } 2822 2823 @Nullable put(K key, int hash, V value, boolean onlyIfAbsent)2824 V put(K key, int hash, V value, boolean onlyIfAbsent) { 2825 lock(); 2826 try { 2827 long now = map.ticker.read(); 2828 preWriteCleanup(now); 2829 2830 int newCount = this.count + 1; 2831 if (newCount > this.threshold) { // ensure capacity 2832 expand(); 2833 newCount = this.count + 1; 2834 } 2835 2836 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table; 2837 int index = hash & (table.length() - 1); 2838 ReferenceEntry<K, V> first = table.get(index); 2839 2840 // Look for an existing entry. 2841 for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) { 2842 K entryKey = e.getKey(); 2843 if (e.getHash() == hash && entryKey != null 2844 && map.keyEquivalence.equivalent(key, entryKey)) { 2845 // We found an existing entry. 2846 2847 ValueReference<K, V> valueReference = e.getValueReference(); 2848 V entryValue = valueReference.get(); 2849 2850 if (entryValue == null) { 2851 ++modCount; 2852 if (valueReference.isActive()) { 2853 enqueueNotification(key, hash, valueReference, RemovalCause.COLLECTED); 2854 setValue(e, key, value, now); 2855 newCount = this.count; // count remains unchanged 2856 } else { 2857 setValue(e, key, value, now); 2858 newCount = this.count + 1; 2859 } 2860 this.count = newCount; // write-volatile 2861 evictEntries(); 2862 return null; 2863 } else if (onlyIfAbsent) { 2864 // Mimic 2865 // "if (!map.containsKey(key)) ... 2866 // else return map.get(key); 2867 recordLockedRead(e, now); 2868 return entryValue; 2869 } else { 2870 // clobber existing entry, count remains unchanged 2871 ++modCount; 2872 enqueueNotification(key, hash, valueReference, RemovalCause.REPLACED); 2873 setValue(e, key, value, now); 2874 evictEntries(); 2875 return entryValue; 2876 } 2877 } 2878 } 2879 2880 // Create a new entry. 2881 ++modCount; 2882 ReferenceEntry<K, V> newEntry = newEntry(key, hash, first); 2883 setValue(newEntry, key, value, now); 2884 table.set(index, newEntry); 2885 newCount = this.count + 1; 2886 this.count = newCount; // write-volatile 2887 evictEntries(); 2888 return null; 2889 } finally { 2890 unlock(); 2891 postWriteCleanup(); 2892 } 2893 } 2894 2895 /** 2896 * Expands the table if possible. 2897 */ 2898 @GuardedBy("this") expand()2899 void expand() { 2900 AtomicReferenceArray<ReferenceEntry<K, V>> oldTable = table; 2901 int oldCapacity = oldTable.length(); 2902 if (oldCapacity >= MAXIMUM_CAPACITY) { 2903 return; 2904 } 2905 2906 /* 2907 * Reclassify nodes in each list to new Map. Because we are using power-of-two expansion, the 2908 * elements from each bin must either stay at same index, or move with a power of two offset. 2909 * We eliminate unnecessary node creation by catching cases where old nodes can be reused 2910 * because their next fields won't change. Statistically, at the default threshold, only 2911 * about one-sixth of them need cloning when a table doubles. The nodes they replace will be 2912 * garbage collectable as soon as they are no longer referenced by any reader thread that may 2913 * be in the midst of traversing table right now. 2914 */ 2915 2916 int newCount = count; 2917 AtomicReferenceArray<ReferenceEntry<K, V>> newTable = newEntryArray(oldCapacity << 1); 2918 threshold = newTable.length() * 3 / 4; 2919 int newMask = newTable.length() - 1; 2920 for (int oldIndex = 0; oldIndex < oldCapacity; ++oldIndex) { 2921 // We need to guarantee that any existing reads of old Map can 2922 // proceed. So we cannot yet null out each bin. 2923 ReferenceEntry<K, V> head = oldTable.get(oldIndex); 2924 2925 if (head != null) { 2926 ReferenceEntry<K, V> next = head.getNext(); 2927 int headIndex = head.getHash() & newMask; 2928 2929 // Single node on list 2930 if (next == null) { 2931 newTable.set(headIndex, head); 2932 } else { 2933 // Reuse the consecutive sequence of nodes with the same target 2934 // index from the end of the list. tail points to the first 2935 // entry in the reusable list. 2936 ReferenceEntry<K, V> tail = head; 2937 int tailIndex = headIndex; 2938 for (ReferenceEntry<K, V> e = next; e != null; e = e.getNext()) { 2939 int newIndex = e.getHash() & newMask; 2940 if (newIndex != tailIndex) { 2941 // The index changed. We'll need to copy the previous entry. 2942 tailIndex = newIndex; 2943 tail = e; 2944 } 2945 } 2946 newTable.set(tailIndex, tail); 2947 2948 // Clone nodes leading up to the tail. 2949 for (ReferenceEntry<K, V> e = head; e != tail; e = e.getNext()) { 2950 int newIndex = e.getHash() & newMask; 2951 ReferenceEntry<K, V> newNext = newTable.get(newIndex); 2952 ReferenceEntry<K, V> newFirst = copyEntry(e, newNext); 2953 if (newFirst != null) { 2954 newTable.set(newIndex, newFirst); 2955 } else { 2956 removeCollectedEntry(e); 2957 newCount--; 2958 } 2959 } 2960 } 2961 } 2962 } 2963 table = newTable; 2964 this.count = newCount; 2965 } 2966 replace(K key, int hash, V oldValue, V newValue)2967 boolean replace(K key, int hash, V oldValue, V newValue) { 2968 lock(); 2969 try { 2970 long now = map.ticker.read(); 2971 preWriteCleanup(now); 2972 2973 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table; 2974 int index = hash & (table.length() - 1); 2975 ReferenceEntry<K, V> first = table.get(index); 2976 2977 for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) { 2978 K entryKey = e.getKey(); 2979 if (e.getHash() == hash && entryKey != null 2980 && map.keyEquivalence.equivalent(key, entryKey)) { 2981 ValueReference<K, V> valueReference = e.getValueReference(); 2982 V entryValue = valueReference.get(); 2983 if (entryValue == null) { 2984 if (valueReference.isActive()) { 2985 // If the value disappeared, this entry is partially collected. 2986 int newCount = this.count - 1; 2987 ++modCount; 2988 ReferenceEntry<K, V> newFirst = removeValueFromChain( 2989 first, e, entryKey, hash, valueReference, RemovalCause.COLLECTED); 2990 newCount = this.count - 1; 2991 table.set(index, newFirst); 2992 this.count = newCount; // write-volatile 2993 } 2994 return false; 2995 } 2996 2997 if (map.valueEquivalence.equivalent(oldValue, entryValue)) { 2998 ++modCount; 2999 enqueueNotification(key, hash, valueReference, RemovalCause.REPLACED); 3000 setValue(e, key, newValue, now); 3001 evictEntries(); 3002 return true; 3003 } else { 3004 // Mimic 3005 // "if (map.containsKey(key) && map.get(key).equals(oldValue))..." 3006 recordLockedRead(e, now); 3007 return false; 3008 } 3009 } 3010 } 3011 3012 return false; 3013 } finally { 3014 unlock(); 3015 postWriteCleanup(); 3016 } 3017 } 3018 3019 @Nullable replace(K key, int hash, V newValue)3020 V replace(K key, int hash, V newValue) { 3021 lock(); 3022 try { 3023 long now = map.ticker.read(); 3024 preWriteCleanup(now); 3025 3026 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table; 3027 int index = hash & (table.length() - 1); 3028 ReferenceEntry<K, V> first = table.get(index); 3029 3030 for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) { 3031 K entryKey = e.getKey(); 3032 if (e.getHash() == hash && entryKey != null 3033 && map.keyEquivalence.equivalent(key, entryKey)) { 3034 ValueReference<K, V> valueReference = e.getValueReference(); 3035 V entryValue = valueReference.get(); 3036 if (entryValue == null) { 3037 if (valueReference.isActive()) { 3038 // If the value disappeared, this entry is partially collected. 3039 int newCount = this.count - 1; 3040 ++modCount; 3041 ReferenceEntry<K, V> newFirst = removeValueFromChain( 3042 first, e, entryKey, hash, valueReference, RemovalCause.COLLECTED); 3043 newCount = this.count - 1; 3044 table.set(index, newFirst); 3045 this.count = newCount; // write-volatile 3046 } 3047 return null; 3048 } 3049 3050 ++modCount; 3051 enqueueNotification(key, hash, valueReference, RemovalCause.REPLACED); 3052 setValue(e, key, newValue, now); 3053 evictEntries(); 3054 return entryValue; 3055 } 3056 } 3057 3058 return null; 3059 } finally { 3060 unlock(); 3061 postWriteCleanup(); 3062 } 3063 } 3064 3065 @Nullable remove(Object key, int hash)3066 V remove(Object key, int hash) { 3067 lock(); 3068 try { 3069 long now = map.ticker.read(); 3070 preWriteCleanup(now); 3071 3072 int newCount = this.count - 1; 3073 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table; 3074 int index = hash & (table.length() - 1); 3075 ReferenceEntry<K, V> first = table.get(index); 3076 3077 for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) { 3078 K entryKey = e.getKey(); 3079 if (e.getHash() == hash && entryKey != null 3080 && map.keyEquivalence.equivalent(key, entryKey)) { 3081 ValueReference<K, V> valueReference = e.getValueReference(); 3082 V entryValue = valueReference.get(); 3083 3084 RemovalCause cause; 3085 if (entryValue != null) { 3086 cause = RemovalCause.EXPLICIT; 3087 } else if (valueReference.isActive()) { 3088 cause = RemovalCause.COLLECTED; 3089 } else { 3090 // currently loading 3091 return null; 3092 } 3093 3094 ++modCount; 3095 ReferenceEntry<K, V> newFirst = removeValueFromChain( 3096 first, e, entryKey, hash, valueReference, cause); 3097 newCount = this.count - 1; 3098 table.set(index, newFirst); 3099 this.count = newCount; // write-volatile 3100 return entryValue; 3101 } 3102 } 3103 3104 return null; 3105 } finally { 3106 unlock(); 3107 postWriteCleanup(); 3108 } 3109 } 3110 storeLoadedValue(K key, int hash, LoadingValueReference<K, V> oldValueReference, V newValue)3111 boolean storeLoadedValue(K key, int hash, LoadingValueReference<K, V> oldValueReference, 3112 V newValue) { 3113 lock(); 3114 try { 3115 long now = map.ticker.read(); 3116 preWriteCleanup(now); 3117 3118 int newCount = this.count + 1; 3119 if (newCount > this.threshold) { // ensure capacity 3120 expand(); 3121 newCount = this.count + 1; 3122 } 3123 3124 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table; 3125 int index = hash & (table.length() - 1); 3126 ReferenceEntry<K, V> first = table.get(index); 3127 3128 for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) { 3129 K entryKey = e.getKey(); 3130 if (e.getHash() == hash && entryKey != null 3131 && map.keyEquivalence.equivalent(key, entryKey)) { 3132 ValueReference<K, V> valueReference = e.getValueReference(); 3133 V entryValue = valueReference.get(); 3134 // replace the old LoadingValueReference if it's live, otherwise 3135 // perform a putIfAbsent 3136 if (oldValueReference == valueReference 3137 || (entryValue == null && valueReference != UNSET)) { 3138 ++modCount; 3139 if (oldValueReference.isActive()) { 3140 RemovalCause cause = 3141 (entryValue == null) ? RemovalCause.COLLECTED : RemovalCause.REPLACED; 3142 enqueueNotification(key, hash, oldValueReference, cause); 3143 newCount--; 3144 } 3145 setValue(e, key, newValue, now); 3146 this.count = newCount; // write-volatile 3147 evictEntries(); 3148 return true; 3149 } 3150 3151 // the loaded value was already clobbered 3152 valueReference = new WeightedStrongValueReference<K, V>(newValue, 0); 3153 enqueueNotification(key, hash, valueReference, RemovalCause.REPLACED); 3154 return false; 3155 } 3156 } 3157 3158 ++modCount; 3159 ReferenceEntry<K, V> newEntry = newEntry(key, hash, first); 3160 setValue(newEntry, key, newValue, now); 3161 table.set(index, newEntry); 3162 this.count = newCount; // write-volatile 3163 evictEntries(); 3164 return true; 3165 } finally { 3166 unlock(); 3167 postWriteCleanup(); 3168 } 3169 } 3170 remove(Object key, int hash, Object value)3171 boolean remove(Object key, int hash, Object value) { 3172 lock(); 3173 try { 3174 long now = map.ticker.read(); 3175 preWriteCleanup(now); 3176 3177 int newCount = this.count - 1; 3178 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table; 3179 int index = hash & (table.length() - 1); 3180 ReferenceEntry<K, V> first = table.get(index); 3181 3182 for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) { 3183 K entryKey = e.getKey(); 3184 if (e.getHash() == hash && entryKey != null 3185 && map.keyEquivalence.equivalent(key, entryKey)) { 3186 ValueReference<K, V> valueReference = e.getValueReference(); 3187 V entryValue = valueReference.get(); 3188 3189 RemovalCause cause; 3190 if (map.valueEquivalence.equivalent(value, entryValue)) { 3191 cause = RemovalCause.EXPLICIT; 3192 } else if (entryValue == null && valueReference.isActive()) { 3193 cause = RemovalCause.COLLECTED; 3194 } else { 3195 // currently loading 3196 return false; 3197 } 3198 3199 ++modCount; 3200 ReferenceEntry<K, V> newFirst = removeValueFromChain( 3201 first, e, entryKey, hash, valueReference, cause); 3202 newCount = this.count - 1; 3203 table.set(index, newFirst); 3204 this.count = newCount; // write-volatile 3205 return (cause == RemovalCause.EXPLICIT); 3206 } 3207 } 3208 3209 return false; 3210 } finally { 3211 unlock(); 3212 postWriteCleanup(); 3213 } 3214 } 3215 clear()3216 void clear() { 3217 if (count != 0) { // read-volatile 3218 lock(); 3219 try { 3220 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table; 3221 for (int i = 0; i < table.length(); ++i) { 3222 for (ReferenceEntry<K, V> e = table.get(i); e != null; e = e.getNext()) { 3223 // Loading references aren't actually in the map yet. 3224 if (e.getValueReference().isActive()) { 3225 enqueueNotification(e, RemovalCause.EXPLICIT); 3226 } 3227 } 3228 } 3229 for (int i = 0; i < table.length(); ++i) { 3230 table.set(i, null); 3231 } 3232 clearReferenceQueues(); 3233 writeQueue.clear(); 3234 accessQueue.clear(); 3235 readCount.set(0); 3236 3237 ++modCount; 3238 count = 0; // write-volatile 3239 } finally { 3240 unlock(); 3241 postWriteCleanup(); 3242 } 3243 } 3244 } 3245 3246 @GuardedBy("this") 3247 @Nullable removeValueFromChain(ReferenceEntry<K, V> first, ReferenceEntry<K, V> entry, @Nullable K key, int hash, ValueReference<K, V> valueReference, RemovalCause cause)3248 ReferenceEntry<K, V> removeValueFromChain(ReferenceEntry<K, V> first, 3249 ReferenceEntry<K, V> entry, @Nullable K key, int hash, ValueReference<K, V> valueReference, 3250 RemovalCause cause) { 3251 enqueueNotification(key, hash, valueReference, cause); 3252 writeQueue.remove(entry); 3253 accessQueue.remove(entry); 3254 3255 if (valueReference.isLoading()) { 3256 valueReference.notifyNewValue(null); 3257 return first; 3258 } else { 3259 return removeEntryFromChain(first, entry); 3260 } 3261 } 3262 3263 @GuardedBy("this") 3264 @Nullable removeEntryFromChain(ReferenceEntry<K, V> first, ReferenceEntry<K, V> entry)3265 ReferenceEntry<K, V> removeEntryFromChain(ReferenceEntry<K, V> first, 3266 ReferenceEntry<K, V> entry) { 3267 int newCount = count; 3268 ReferenceEntry<K, V> newFirst = entry.getNext(); 3269 for (ReferenceEntry<K, V> e = first; e != entry; e = e.getNext()) { 3270 ReferenceEntry<K, V> next = copyEntry(e, newFirst); 3271 if (next != null) { 3272 newFirst = next; 3273 } else { 3274 removeCollectedEntry(e); 3275 newCount--; 3276 } 3277 } 3278 this.count = newCount; 3279 return newFirst; 3280 } 3281 3282 @GuardedBy("this") removeCollectedEntry(ReferenceEntry<K, V> entry)3283 void removeCollectedEntry(ReferenceEntry<K, V> entry) { 3284 enqueueNotification(entry, RemovalCause.COLLECTED); 3285 writeQueue.remove(entry); 3286 accessQueue.remove(entry); 3287 } 3288 3289 /** 3290 * Removes an entry whose key has been garbage collected. 3291 */ reclaimKey(ReferenceEntry<K, V> entry, int hash)3292 boolean reclaimKey(ReferenceEntry<K, V> entry, int hash) { 3293 lock(); 3294 try { 3295 int newCount = count - 1; 3296 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table; 3297 int index = hash & (table.length() - 1); 3298 ReferenceEntry<K, V> first = table.get(index); 3299 3300 for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) { 3301 if (e == entry) { 3302 ++modCount; 3303 ReferenceEntry<K, V> newFirst = removeValueFromChain( 3304 first, e, e.getKey(), hash, e.getValueReference(), RemovalCause.COLLECTED); 3305 newCount = this.count - 1; 3306 table.set(index, newFirst); 3307 this.count = newCount; // write-volatile 3308 return true; 3309 } 3310 } 3311 3312 return false; 3313 } finally { 3314 unlock(); 3315 postWriteCleanup(); 3316 } 3317 } 3318 3319 /** 3320 * Removes an entry whose value has been garbage collected. 3321 */ reclaimValue(K key, int hash, ValueReference<K, V> valueReference)3322 boolean reclaimValue(K key, int hash, ValueReference<K, V> valueReference) { 3323 lock(); 3324 try { 3325 int newCount = this.count - 1; 3326 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table; 3327 int index = hash & (table.length() - 1); 3328 ReferenceEntry<K, V> first = table.get(index); 3329 3330 for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) { 3331 K entryKey = e.getKey(); 3332 if (e.getHash() == hash && entryKey != null 3333 && map.keyEquivalence.equivalent(key, entryKey)) { 3334 ValueReference<K, V> v = e.getValueReference(); 3335 if (v == valueReference) { 3336 ++modCount; 3337 ReferenceEntry<K, V> newFirst = removeValueFromChain( 3338 first, e, entryKey, hash, valueReference, RemovalCause.COLLECTED); 3339 newCount = this.count - 1; 3340 table.set(index, newFirst); 3341 this.count = newCount; // write-volatile 3342 return true; 3343 } 3344 return false; 3345 } 3346 } 3347 3348 return false; 3349 } finally { 3350 unlock(); 3351 if (!isHeldByCurrentThread()) { // don't cleanup inside of put 3352 postWriteCleanup(); 3353 } 3354 } 3355 } 3356 removeLoadingValue(K key, int hash, LoadingValueReference<K, V> valueReference)3357 boolean removeLoadingValue(K key, int hash, LoadingValueReference<K, V> valueReference) { 3358 lock(); 3359 try { 3360 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table; 3361 int index = hash & (table.length() - 1); 3362 ReferenceEntry<K, V> first = table.get(index); 3363 3364 for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) { 3365 K entryKey = e.getKey(); 3366 if (e.getHash() == hash && entryKey != null 3367 && map.keyEquivalence.equivalent(key, entryKey)) { 3368 ValueReference<K, V> v = e.getValueReference(); 3369 if (v == valueReference) { 3370 if (valueReference.isActive()) { 3371 e.setValueReference(valueReference.getOldValue()); 3372 } else { 3373 ReferenceEntry<K, V> newFirst = removeEntryFromChain(first, e); 3374 table.set(index, newFirst); 3375 } 3376 return true; 3377 } 3378 return false; 3379 } 3380 } 3381 3382 return false; 3383 } finally { 3384 unlock(); 3385 postWriteCleanup(); 3386 } 3387 } 3388 3389 @GuardedBy("this") removeEntry(ReferenceEntry<K, V> entry, int hash, RemovalCause cause)3390 boolean removeEntry(ReferenceEntry<K, V> entry, int hash, RemovalCause cause) { 3391 int newCount = this.count - 1; 3392 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table; 3393 int index = hash & (table.length() - 1); 3394 ReferenceEntry<K, V> first = table.get(index); 3395 3396 for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) { 3397 if (e == entry) { 3398 ++modCount; 3399 ReferenceEntry<K, V> newFirst = removeValueFromChain( 3400 first, e, e.getKey(), hash, e.getValueReference(), cause); 3401 newCount = this.count - 1; 3402 table.set(index, newFirst); 3403 this.count = newCount; // write-volatile 3404 return true; 3405 } 3406 } 3407 3408 return false; 3409 } 3410 3411 /** 3412 * Performs routine cleanup following a read. Normally cleanup happens during writes. If cleanup 3413 * is not observed after a sufficient number of reads, try cleaning up from the read thread. 3414 */ postReadCleanup()3415 void postReadCleanup() { 3416 if ((readCount.incrementAndGet() & DRAIN_THRESHOLD) == 0) { 3417 cleanUp(); 3418 } 3419 } 3420 3421 /** 3422 * Performs routine cleanup prior to executing a write. This should be called every time a 3423 * write thread acquires the segment lock, immediately after acquiring the lock. 3424 * 3425 * <p>Post-condition: expireEntries has been run. 3426 */ 3427 @GuardedBy("this") preWriteCleanup(long now)3428 void preWriteCleanup(long now) { 3429 runLockedCleanup(now); 3430 } 3431 3432 /** 3433 * Performs routine cleanup following a write. 3434 */ postWriteCleanup()3435 void postWriteCleanup() { 3436 runUnlockedCleanup(); 3437 } 3438 cleanUp()3439 void cleanUp() { 3440 long now = map.ticker.read(); 3441 runLockedCleanup(now); 3442 runUnlockedCleanup(); 3443 } 3444 runLockedCleanup(long now)3445 void runLockedCleanup(long now) { 3446 if (tryLock()) { 3447 try { 3448 drainReferenceQueues(); 3449 expireEntries(now); // calls drainRecencyQueue 3450 readCount.set(0); 3451 } finally { 3452 unlock(); 3453 } 3454 } 3455 } 3456 runUnlockedCleanup()3457 void runUnlockedCleanup() { 3458 // locked cleanup may generate notifications we can send unlocked 3459 if (!isHeldByCurrentThread()) { 3460 map.processPendingNotifications(); 3461 } 3462 } 3463 3464 } 3465 3466 static class LoadingValueReference<K, V> implements ValueReference<K, V> { 3467 volatile ValueReference<K, V> oldValue; 3468 3469 // TODO(fry): rename get, then extend AbstractFuture instead of containing SettableFuture 3470 final SettableFuture<V> futureValue = SettableFuture.create(); 3471 final Stopwatch stopwatch = Stopwatch.createUnstarted(); 3472 LoadingValueReference()3473 public LoadingValueReference() { 3474 this(LocalCache.<K, V>unset()); 3475 } 3476 LoadingValueReference(ValueReference<K, V> oldValue)3477 public LoadingValueReference(ValueReference<K, V> oldValue) { 3478 this.oldValue = oldValue; 3479 } 3480 3481 @Override isLoading()3482 public boolean isLoading() { 3483 return true; 3484 } 3485 3486 @Override isActive()3487 public boolean isActive() { 3488 return oldValue.isActive(); 3489 } 3490 3491 @Override getWeight()3492 public int getWeight() { 3493 return oldValue.getWeight(); 3494 } 3495 set(@ullable V newValue)3496 public boolean set(@Nullable V newValue) { 3497 return futureValue.set(newValue); 3498 } 3499 setException(Throwable t)3500 public boolean setException(Throwable t) { 3501 return futureValue.setException(t); 3502 } 3503 fullyFailedFuture(Throwable t)3504 private ListenableFuture<V> fullyFailedFuture(Throwable t) { 3505 return Futures.immediateFailedFuture(t); 3506 } 3507 3508 @Override notifyNewValue(@ullable V newValue)3509 public void notifyNewValue(@Nullable V newValue) { 3510 if (newValue != null) { 3511 // The pending load was clobbered by a manual write. 3512 // Unblock all pending gets, and have them return the new value. 3513 set(newValue); 3514 } else { 3515 // The pending load was removed. Delay notifications until loading completes. 3516 oldValue = unset(); 3517 } 3518 3519 // TODO(fry): could also cancel loading if we had a handle on its future 3520 } 3521 loadFuture(K key, CacheLoader<? super K, V> loader)3522 public ListenableFuture<V> loadFuture(K key, CacheLoader<? super K, V> loader) { 3523 stopwatch.start(); 3524 V previousValue = oldValue.get(); 3525 try { 3526 if (previousValue == null) { 3527 V newValue = loader.load(key); 3528 return set(newValue) ? futureValue : Futures.immediateFuture(newValue); 3529 } 3530 ListenableFuture<V> newValue = loader.reload(key, previousValue); 3531 if (newValue == null) { 3532 return Futures.immediateFuture(null); 3533 } 3534 // To avoid a race, make sure the refreshed value is set into loadingValueReference 3535 // *before* returning newValue from the cache query. 3536 return Futures.transform(newValue, new Function<V, V>() { 3537 @Override 3538 public V apply(V newValue) { 3539 LoadingValueReference.this.set(newValue); 3540 return newValue; 3541 } 3542 }); 3543 } catch (Throwable t) { 3544 if (t instanceof InterruptedException) { 3545 Thread.currentThread().interrupt(); 3546 } 3547 return setException(t) ? futureValue : fullyFailedFuture(t); 3548 } 3549 } 3550 elapsedNanos()3551 public long elapsedNanos() { 3552 return stopwatch.elapsed(NANOSECONDS); 3553 } 3554 3555 @Override waitForValue()3556 public V waitForValue() throws ExecutionException { 3557 return getUninterruptibly(futureValue); 3558 } 3559 3560 @Override get()3561 public V get() { 3562 return oldValue.get(); 3563 } 3564 getOldValue()3565 public ValueReference<K, V> getOldValue() { 3566 return oldValue; 3567 } 3568 3569 @Override getEntry()3570 public ReferenceEntry<K, V> getEntry() { 3571 return null; 3572 } 3573 3574 @Override copyFor( ReferenceQueue<V> queue, @Nullable V value, ReferenceEntry<K, V> entry)3575 public ValueReference<K, V> copyFor( 3576 ReferenceQueue<V> queue, @Nullable V value, ReferenceEntry<K, V> entry) { 3577 return this; 3578 } 3579 } 3580 3581 // Queues 3582 3583 /** 3584 * A custom queue for managing eviction order. Note that this is tightly integrated with {@code 3585 * ReferenceEntry}, upon which it relies to perform its linking. 3586 * 3587 * <p>Note that this entire implementation makes the assumption that all elements which are in 3588 * the map are also in this queue, and that all elements not in the queue are not in the map. 3589 * 3590 * <p>The benefits of creating our own queue are that (1) we can replace elements in the middle 3591 * of the queue as part of copyWriteEntry, and (2) the contains method is highly optimized 3592 * for the current model. 3593 */ 3594 static final class WriteQueue<K, V> extends AbstractQueue<ReferenceEntry<K, V>> { 3595 final ReferenceEntry<K, V> head = new AbstractReferenceEntry<K, V>() { 3596 3597 @Override 3598 public long getWriteTime() { 3599 return Long.MAX_VALUE; 3600 } 3601 3602 @Override 3603 public void setWriteTime(long time) {} 3604 3605 ReferenceEntry<K, V> nextWrite = this; 3606 3607 @Override 3608 public ReferenceEntry<K, V> getNextInWriteQueue() { 3609 return nextWrite; 3610 } 3611 3612 @Override 3613 public void setNextInWriteQueue(ReferenceEntry<K, V> next) { 3614 this.nextWrite = next; 3615 } 3616 3617 ReferenceEntry<K, V> previousWrite = this; 3618 3619 @Override 3620 public ReferenceEntry<K, V> getPreviousInWriteQueue() { 3621 return previousWrite; 3622 } 3623 3624 @Override 3625 public void setPreviousInWriteQueue(ReferenceEntry<K, V> previous) { 3626 this.previousWrite = previous; 3627 } 3628 }; 3629 3630 // implements Queue 3631 3632 @Override 3633 public boolean offer(ReferenceEntry<K, V> entry) { 3634 // unlink 3635 connectWriteOrder(entry.getPreviousInWriteQueue(), entry.getNextInWriteQueue()); 3636 3637 // add to tail 3638 connectWriteOrder(head.getPreviousInWriteQueue(), entry); 3639 connectWriteOrder(entry, head); 3640 3641 return true; 3642 } 3643 3644 @Override 3645 public ReferenceEntry<K, V> peek() { 3646 ReferenceEntry<K, V> next = head.getNextInWriteQueue(); 3647 return (next == head) ? null : next; 3648 } 3649 3650 @Override 3651 public ReferenceEntry<K, V> poll() { 3652 ReferenceEntry<K, V> next = head.getNextInWriteQueue(); 3653 if (next == head) { 3654 return null; 3655 } 3656 3657 remove(next); 3658 return next; 3659 } 3660 3661 @Override 3662 @SuppressWarnings("unchecked") 3663 public boolean remove(Object o) { 3664 ReferenceEntry<K, V> e = (ReferenceEntry) o; 3665 ReferenceEntry<K, V> previous = e.getPreviousInWriteQueue(); 3666 ReferenceEntry<K, V> next = e.getNextInWriteQueue(); 3667 connectWriteOrder(previous, next); 3668 nullifyWriteOrder(e); 3669 3670 return next != NullEntry.INSTANCE; 3671 } 3672 3673 @Override 3674 @SuppressWarnings("unchecked") 3675 public boolean contains(Object o) { 3676 ReferenceEntry<K, V> e = (ReferenceEntry) o; 3677 return e.getNextInWriteQueue() != NullEntry.INSTANCE; 3678 } 3679 3680 @Override 3681 public boolean isEmpty() { 3682 return head.getNextInWriteQueue() == head; 3683 } 3684 3685 @Override 3686 public int size() { 3687 int size = 0; 3688 for (ReferenceEntry<K, V> e = head.getNextInWriteQueue(); e != head; 3689 e = e.getNextInWriteQueue()) { 3690 size++; 3691 } 3692 return size; 3693 } 3694 3695 @Override 3696 public void clear() { 3697 ReferenceEntry<K, V> e = head.getNextInWriteQueue(); 3698 while (e != head) { 3699 ReferenceEntry<K, V> next = e.getNextInWriteQueue(); 3700 nullifyWriteOrder(e); 3701 e = next; 3702 } 3703 3704 head.setNextInWriteQueue(head); 3705 head.setPreviousInWriteQueue(head); 3706 } 3707 3708 @Override 3709 public Iterator<ReferenceEntry<K, V>> iterator() { 3710 return new AbstractSequentialIterator<ReferenceEntry<K, V>>(peek()) { 3711 @Override 3712 protected ReferenceEntry<K, V> computeNext(ReferenceEntry<K, V> previous) { 3713 ReferenceEntry<K, V> next = previous.getNextInWriteQueue(); 3714 return (next == head) ? null : next; 3715 } 3716 }; 3717 } 3718 } 3719 3720 /** 3721 * A custom queue for managing access order. Note that this is tightly integrated with 3722 * {@code ReferenceEntry}, upon which it reliese to perform its linking. 3723 * 3724 * <p>Note that this entire implementation makes the assumption that all elements which are in 3725 * the map are also in this queue, and that all elements not in the queue are not in the map. 3726 * 3727 * <p>The benefits of creating our own queue are that (1) we can replace elements in the middle 3728 * of the queue as part of copyWriteEntry, and (2) the contains method is highly optimized 3729 * for the current model. 3730 */ 3731 static final class AccessQueue<K, V> extends AbstractQueue<ReferenceEntry<K, V>> { 3732 final ReferenceEntry<K, V> head = new AbstractReferenceEntry<K, V>() { 3733 3734 @Override 3735 public long getAccessTime() { 3736 return Long.MAX_VALUE; 3737 } 3738 3739 @Override 3740 public void setAccessTime(long time) {} 3741 3742 ReferenceEntry<K, V> nextAccess = this; 3743 3744 @Override 3745 public ReferenceEntry<K, V> getNextInAccessQueue() { 3746 return nextAccess; 3747 } 3748 3749 @Override 3750 public void setNextInAccessQueue(ReferenceEntry<K, V> next) { 3751 this.nextAccess = next; 3752 } 3753 3754 ReferenceEntry<K, V> previousAccess = this; 3755 3756 @Override 3757 public ReferenceEntry<K, V> getPreviousInAccessQueue() { 3758 return previousAccess; 3759 } 3760 3761 @Override 3762 public void setPreviousInAccessQueue(ReferenceEntry<K, V> previous) { 3763 this.previousAccess = previous; 3764 } 3765 }; 3766 3767 // implements Queue 3768 3769 @Override 3770 public boolean offer(ReferenceEntry<K, V> entry) { 3771 // unlink 3772 connectAccessOrder(entry.getPreviousInAccessQueue(), entry.getNextInAccessQueue()); 3773 3774 // add to tail 3775 connectAccessOrder(head.getPreviousInAccessQueue(), entry); 3776 connectAccessOrder(entry, head); 3777 3778 return true; 3779 } 3780 3781 @Override 3782 public ReferenceEntry<K, V> peek() { 3783 ReferenceEntry<K, V> next = head.getNextInAccessQueue(); 3784 return (next == head) ? null : next; 3785 } 3786 3787 @Override 3788 public ReferenceEntry<K, V> poll() { 3789 ReferenceEntry<K, V> next = head.getNextInAccessQueue(); 3790 if (next == head) { 3791 return null; 3792 } 3793 3794 remove(next); 3795 return next; 3796 } 3797 3798 @Override 3799 @SuppressWarnings("unchecked") 3800 public boolean remove(Object o) { 3801 ReferenceEntry<K, V> e = (ReferenceEntry) o; 3802 ReferenceEntry<K, V> previous = e.getPreviousInAccessQueue(); 3803 ReferenceEntry<K, V> next = e.getNextInAccessQueue(); 3804 connectAccessOrder(previous, next); 3805 nullifyAccessOrder(e); 3806 3807 return next != NullEntry.INSTANCE; 3808 } 3809 3810 @Override 3811 @SuppressWarnings("unchecked") 3812 public boolean contains(Object o) { 3813 ReferenceEntry<K, V> e = (ReferenceEntry) o; 3814 return e.getNextInAccessQueue() != NullEntry.INSTANCE; 3815 } 3816 3817 @Override 3818 public boolean isEmpty() { 3819 return head.getNextInAccessQueue() == head; 3820 } 3821 3822 @Override 3823 public int size() { 3824 int size = 0; 3825 for (ReferenceEntry<K, V> e = head.getNextInAccessQueue(); e != head; 3826 e = e.getNextInAccessQueue()) { 3827 size++; 3828 } 3829 return size; 3830 } 3831 3832 @Override 3833 public void clear() { 3834 ReferenceEntry<K, V> e = head.getNextInAccessQueue(); 3835 while (e != head) { 3836 ReferenceEntry<K, V> next = e.getNextInAccessQueue(); 3837 nullifyAccessOrder(e); 3838 e = next; 3839 } 3840 3841 head.setNextInAccessQueue(head); 3842 head.setPreviousInAccessQueue(head); 3843 } 3844 3845 @Override 3846 public Iterator<ReferenceEntry<K, V>> iterator() { 3847 return new AbstractSequentialIterator<ReferenceEntry<K, V>>(peek()) { 3848 @Override 3849 protected ReferenceEntry<K, V> computeNext(ReferenceEntry<K, V> previous) { 3850 ReferenceEntry<K, V> next = previous.getNextInAccessQueue(); 3851 return (next == head) ? null : next; 3852 } 3853 }; 3854 } 3855 } 3856 3857 // Cache support 3858 3859 public void cleanUp() { 3860 for (Segment<?, ?> segment : segments) { 3861 segment.cleanUp(); 3862 } 3863 } 3864 3865 // ConcurrentMap methods 3866 3867 @Override 3868 public boolean isEmpty() { 3869 /* 3870 * Sum per-segment modCounts to avoid mis-reporting when elements are concurrently added and 3871 * removed in one segment while checking another, in which case the table was never actually 3872 * empty at any point. (The sum ensures accuracy up through at least 1<<31 per-segment 3873 * modifications before recheck.) Method containsValue() uses similar constructions for 3874 * stability checks. 3875 */ 3876 long sum = 0L; 3877 Segment<K, V>[] segments = this.segments; 3878 for (int i = 0; i < segments.length; ++i) { 3879 if (segments[i].count != 0) { 3880 return false; 3881 } 3882 sum += segments[i].modCount; 3883 } 3884 3885 if (sum != 0L) { // recheck unless no modifications 3886 for (int i = 0; i < segments.length; ++i) { 3887 if (segments[i].count != 0) { 3888 return false; 3889 } 3890 sum -= segments[i].modCount; 3891 } 3892 if (sum != 0L) { 3893 return false; 3894 } 3895 } 3896 return true; 3897 } 3898 3899 long longSize() { 3900 Segment<K, V>[] segments = this.segments; 3901 long sum = 0; 3902 for (int i = 0; i < segments.length; ++i) { 3903 sum += segments[i].count; 3904 } 3905 return sum; 3906 } 3907 3908 @Override 3909 public int size() { 3910 return Ints.saturatedCast(longSize()); 3911 } 3912 3913 @Override 3914 @Nullable 3915 public V get(@Nullable Object key) { 3916 if (key == null) { 3917 return null; 3918 } 3919 int hash = hash(key); 3920 return segmentFor(hash).get(key, hash); 3921 } 3922 3923 @Nullable 3924 public V getIfPresent(Object key) { 3925 int hash = hash(checkNotNull(key)); 3926 V value = segmentFor(hash).get(key, hash); 3927 if (value == null) { 3928 globalStatsCounter.recordMisses(1); 3929 } else { 3930 globalStatsCounter.recordHits(1); 3931 } 3932 return value; 3933 } 3934 3935 V get(K key, CacheLoader<? super K, V> loader) throws ExecutionException { 3936 int hash = hash(checkNotNull(key)); 3937 return segmentFor(hash).get(key, hash, loader); 3938 } 3939 3940 V getOrLoad(K key) throws ExecutionException { 3941 return get(key, defaultLoader); 3942 } 3943 3944 ImmutableMap<K, V> getAllPresent(Iterable<?> keys) { 3945 int hits = 0; 3946 int misses = 0; 3947 3948 Map<K, V> result = Maps.newLinkedHashMap(); 3949 for (Object key : keys) { 3950 V value = get(key); 3951 if (value == null) { 3952 misses++; 3953 } else { 3954 // TODO(fry): store entry key instead of query key 3955 @SuppressWarnings("unchecked") 3956 K castKey = (K) key; 3957 result.put(castKey, value); 3958 hits++; 3959 } 3960 } 3961 globalStatsCounter.recordHits(hits); 3962 globalStatsCounter.recordMisses(misses); 3963 return ImmutableMap.copyOf(result); 3964 } 3965 3966 ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException { 3967 int hits = 0; 3968 int misses = 0; 3969 3970 Map<K, V> result = Maps.newLinkedHashMap(); 3971 Set<K> keysToLoad = Sets.newLinkedHashSet(); 3972 for (K key : keys) { 3973 V value = get(key); 3974 if (!result.containsKey(key)) { 3975 result.put(key, value); 3976 if (value == null) { 3977 misses++; 3978 keysToLoad.add(key); 3979 } else { 3980 hits++; 3981 } 3982 } 3983 } 3984 3985 try { 3986 if (!keysToLoad.isEmpty()) { 3987 try { 3988 Map<K, V> newEntries = loadAll(keysToLoad, defaultLoader); 3989 for (K key : keysToLoad) { 3990 V value = newEntries.get(key); 3991 if (value == null) { 3992 throw new InvalidCacheLoadException("loadAll failed to return a value for " + key); 3993 } 3994 result.put(key, value); 3995 } 3996 } catch (UnsupportedLoadingOperationException e) { 3997 // loadAll not implemented, fallback to load 3998 for (K key : keysToLoad) { 3999 misses--; // get will count this miss 4000 result.put(key, get(key, defaultLoader)); 4001 } 4002 } 4003 } 4004 return ImmutableMap.copyOf(result); 4005 } finally { 4006 globalStatsCounter.recordHits(hits); 4007 globalStatsCounter.recordMisses(misses); 4008 } 4009 } 4010 4011 /** 4012 * Returns the result of calling {@link CacheLoader#loadAll}, or null if {@code loader} doesn't 4013 * implement {@code loadAll}. 4014 */ 4015 @Nullable 4016 Map<K, V> loadAll(Set<? extends K> keys, CacheLoader<? super K, V> loader) 4017 throws ExecutionException { 4018 checkNotNull(loader); 4019 checkNotNull(keys); 4020 Stopwatch stopwatch = Stopwatch.createStarted(); 4021 Map<K, V> result; 4022 boolean success = false; 4023 try { 4024 @SuppressWarnings("unchecked") // safe since all keys extend K 4025 Map<K, V> map = (Map<K, V>) loader.loadAll(keys); 4026 result = map; 4027 success = true; 4028 } catch (UnsupportedLoadingOperationException e) { 4029 success = true; 4030 throw e; 4031 } catch (InterruptedException e) { 4032 Thread.currentThread().interrupt(); 4033 throw new ExecutionException(e); 4034 } catch (RuntimeException e) { 4035 throw new UncheckedExecutionException(e); 4036 } catch (Exception e) { 4037 throw new ExecutionException(e); 4038 } catch (Error e) { 4039 throw new ExecutionError(e); 4040 } finally { 4041 if (!success) { 4042 globalStatsCounter.recordLoadException(stopwatch.elapsed(NANOSECONDS)); 4043 } 4044 } 4045 4046 if (result == null) { 4047 globalStatsCounter.recordLoadException(stopwatch.elapsed(NANOSECONDS)); 4048 throw new InvalidCacheLoadException(loader + " returned null map from loadAll"); 4049 } 4050 4051 stopwatch.stop(); 4052 // TODO(fry): batch by segment 4053 boolean nullsPresent = false; 4054 for (Map.Entry<K, V> entry : result.entrySet()) { 4055 K key = entry.getKey(); 4056 V value = entry.getValue(); 4057 if (key == null || value == null) { 4058 // delay failure until non-null entries are stored 4059 nullsPresent = true; 4060 } else { 4061 put(key, value); 4062 } 4063 } 4064 4065 if (nullsPresent) { 4066 globalStatsCounter.recordLoadException(stopwatch.elapsed(NANOSECONDS)); 4067 throw new InvalidCacheLoadException(loader + " returned null keys or values from loadAll"); 4068 } 4069 4070 // TODO(fry): record count of loaded entries 4071 globalStatsCounter.recordLoadSuccess(stopwatch.elapsed(NANOSECONDS)); 4072 return result; 4073 } 4074 4075 /** 4076 * Returns the internal entry for the specified key. The entry may be loading, expired, or 4077 * partially collected. 4078 */ 4079 ReferenceEntry<K, V> getEntry(@Nullable Object key) { 4080 // does not impact recency ordering 4081 if (key == null) { 4082 return null; 4083 } 4084 int hash = hash(key); 4085 return segmentFor(hash).getEntry(key, hash); 4086 } 4087 4088 void refresh(K key) { 4089 int hash = hash(checkNotNull(key)); 4090 segmentFor(hash).refresh(key, hash, defaultLoader, false); 4091 } 4092 4093 @Override 4094 public boolean containsKey(@Nullable Object key) { 4095 // does not impact recency ordering 4096 if (key == null) { 4097 return false; 4098 } 4099 int hash = hash(key); 4100 return segmentFor(hash).containsKey(key, hash); 4101 } 4102 4103 @Override 4104 public boolean containsValue(@Nullable Object value) { 4105 // does not impact recency ordering 4106 if (value == null) { 4107 return false; 4108 } 4109 4110 // This implementation is patterned after ConcurrentHashMap, but without the locking. The only 4111 // way for it to return a false negative would be for the target value to jump around in the map 4112 // such that none of the subsequent iterations observed it, despite the fact that at every point 4113 // in time it was present somewhere int the map. This becomes increasingly unlikely as 4114 // CONTAINS_VALUE_RETRIES increases, though without locking it is theoretically possible. 4115 long now = ticker.read(); 4116 final Segment<K,V>[] segments = this.segments; 4117 long last = -1L; 4118 for (int i = 0; i < CONTAINS_VALUE_RETRIES; i++) { 4119 long sum = 0L; 4120 for (Segment<K, V> segment : segments) { 4121 // ensure visibility of most recent completed write 4122 @SuppressWarnings({"UnusedDeclaration", "unused"}) 4123 int c = segment.count; // read-volatile 4124 4125 AtomicReferenceArray<ReferenceEntry<K, V>> table = segment.table; 4126 for (int j = 0 ; j < table.length(); j++) { 4127 for (ReferenceEntry<K, V> e = table.get(j); e != null; e = e.getNext()) { 4128 V v = segment.getLiveValue(e, now); 4129 if (v != null && valueEquivalence.equivalent(value, v)) { 4130 return true; 4131 } 4132 } 4133 } 4134 sum += segment.modCount; 4135 } 4136 if (sum == last) { 4137 break; 4138 } 4139 last = sum; 4140 } 4141 return false; 4142 } 4143 4144 @Override 4145 public V put(K key, V value) { 4146 checkNotNull(key); 4147 checkNotNull(value); 4148 int hash = hash(key); 4149 return segmentFor(hash).put(key, hash, value, false); 4150 } 4151 4152 @Override 4153 public V putIfAbsent(K key, V value) { 4154 checkNotNull(key); 4155 checkNotNull(value); 4156 int hash = hash(key); 4157 return segmentFor(hash).put(key, hash, value, true); 4158 } 4159 4160 @Override 4161 public void putAll(Map<? extends K, ? extends V> m) { 4162 for (Entry<? extends K, ? extends V> e : m.entrySet()) { 4163 put(e.getKey(), e.getValue()); 4164 } 4165 } 4166 4167 @Override 4168 public V remove(@Nullable Object key) { 4169 if (key == null) { 4170 return null; 4171 } 4172 int hash = hash(key); 4173 return segmentFor(hash).remove(key, hash); 4174 } 4175 4176 @Override 4177 public boolean remove(@Nullable Object key, @Nullable Object value) { 4178 if (key == null || value == null) { 4179 return false; 4180 } 4181 int hash = hash(key); 4182 return segmentFor(hash).remove(key, hash, value); 4183 } 4184 4185 @Override 4186 public boolean replace(K key, @Nullable V oldValue, V newValue) { 4187 checkNotNull(key); 4188 checkNotNull(newValue); 4189 if (oldValue == null) { 4190 return false; 4191 } 4192 int hash = hash(key); 4193 return segmentFor(hash).replace(key, hash, oldValue, newValue); 4194 } 4195 4196 @Override 4197 public V replace(K key, V value) { 4198 checkNotNull(key); 4199 checkNotNull(value); 4200 int hash = hash(key); 4201 return segmentFor(hash).replace(key, hash, value); 4202 } 4203 4204 @Override 4205 public void clear() { 4206 for (Segment<K, V> segment : segments) { 4207 segment.clear(); 4208 } 4209 } 4210 4211 void invalidateAll(Iterable<?> keys) { 4212 // TODO(fry): batch by segment 4213 for (Object key : keys) { 4214 remove(key); 4215 } 4216 } 4217 4218 Set<K> keySet; 4219 4220 @Override 4221 public Set<K> keySet() { 4222 // does not impact recency ordering 4223 Set<K> ks = keySet; 4224 return (ks != null) ? ks : (keySet = new KeySet(this)); 4225 } 4226 4227 Collection<V> values; 4228 4229 @Override 4230 public Collection<V> values() { 4231 // does not impact recency ordering 4232 Collection<V> vs = values; 4233 return (vs != null) ? vs : (values = new Values(this)); 4234 } 4235 4236 Set<Entry<K, V>> entrySet; 4237 4238 @Override 4239 @GwtIncompatible("Not supported.") 4240 public Set<Entry<K, V>> entrySet() { 4241 // does not impact recency ordering 4242 Set<Entry<K, V>> es = entrySet; 4243 return (es != null) ? es : (entrySet = new EntrySet(this)); 4244 } 4245 4246 // Iterator Support 4247 4248 abstract class HashIterator<T> implements Iterator<T> { 4249 4250 int nextSegmentIndex; 4251 int nextTableIndex; 4252 Segment<K, V> currentSegment; 4253 AtomicReferenceArray<ReferenceEntry<K, V>> currentTable; 4254 ReferenceEntry<K, V> nextEntry; 4255 WriteThroughEntry nextExternal; 4256 WriteThroughEntry lastReturned; 4257 4258 HashIterator() { 4259 nextSegmentIndex = segments.length - 1; 4260 nextTableIndex = -1; 4261 advance(); 4262 } 4263 4264 @Override 4265 public abstract T next(); 4266 4267 final void advance() { 4268 nextExternal = null; 4269 4270 if (nextInChain()) { 4271 return; 4272 } 4273 4274 if (nextInTable()) { 4275 return; 4276 } 4277 4278 while (nextSegmentIndex >= 0) { 4279 currentSegment = segments[nextSegmentIndex--]; 4280 if (currentSegment.count != 0) { 4281 currentTable = currentSegment.table; 4282 nextTableIndex = currentTable.length() - 1; 4283 if (nextInTable()) { 4284 return; 4285 } 4286 } 4287 } 4288 } 4289 4290 /** 4291 * Finds the next entry in the current chain. Returns true if an entry was found. 4292 */ 4293 boolean nextInChain() { 4294 if (nextEntry != null) { 4295 for (nextEntry = nextEntry.getNext(); nextEntry != null; nextEntry = nextEntry.getNext()) { 4296 if (advanceTo(nextEntry)) { 4297 return true; 4298 } 4299 } 4300 } 4301 return false; 4302 } 4303 4304 /** 4305 * Finds the next entry in the current table. Returns true if an entry was found. 4306 */ 4307 boolean nextInTable() { 4308 while (nextTableIndex >= 0) { 4309 if ((nextEntry = currentTable.get(nextTableIndex--)) != null) { 4310 if (advanceTo(nextEntry) || nextInChain()) { 4311 return true; 4312 } 4313 } 4314 } 4315 return false; 4316 } 4317 4318 /** 4319 * Advances to the given entry. Returns true if the entry was valid, false if it should be 4320 * skipped. 4321 */ 4322 boolean advanceTo(ReferenceEntry<K, V> entry) { 4323 try { 4324 long now = ticker.read(); 4325 K key = entry.getKey(); 4326 V value = getLiveValue(entry, now); 4327 if (value != null) { 4328 nextExternal = new WriteThroughEntry(key, value); 4329 return true; 4330 } else { 4331 // Skip stale entry. 4332 return false; 4333 } 4334 } finally { 4335 currentSegment.postReadCleanup(); 4336 } 4337 } 4338 4339 @Override 4340 public boolean hasNext() { 4341 return nextExternal != null; 4342 } 4343 4344 WriteThroughEntry nextEntry() { 4345 if (nextExternal == null) { 4346 throw new NoSuchElementException(); 4347 } 4348 lastReturned = nextExternal; 4349 advance(); 4350 return lastReturned; 4351 } 4352 4353 @Override 4354 public void remove() { 4355 checkState(lastReturned != null); 4356 LocalCache.this.remove(lastReturned.getKey()); 4357 lastReturned = null; 4358 } 4359 } 4360 4361 final class KeyIterator extends HashIterator<K> { 4362 4363 @Override 4364 public K next() { 4365 return nextEntry().getKey(); 4366 } 4367 } 4368 4369 final class ValueIterator extends HashIterator<V> { 4370 4371 @Override 4372 public V next() { 4373 return nextEntry().getValue(); 4374 } 4375 } 4376 4377 /** 4378 * Custom Entry class used by EntryIterator.next(), that relays setValue changes to the 4379 * underlying map. 4380 */ 4381 final class WriteThroughEntry implements Entry<K, V> { 4382 final K key; // non-null 4383 V value; // non-null 4384 4385 WriteThroughEntry(K key, V value) { 4386 this.key = key; 4387 this.value = value; 4388 } 4389 4390 @Override 4391 public K getKey() { 4392 return key; 4393 } 4394 4395 @Override 4396 public V getValue() { 4397 return value; 4398 } 4399 4400 @Override 4401 public boolean equals(@Nullable Object object) { 4402 // Cannot use key and value equivalence 4403 if (object instanceof Entry) { 4404 Entry<?, ?> that = (Entry<?, ?>) object; 4405 return key.equals(that.getKey()) && value.equals(that.getValue()); 4406 } 4407 return false; 4408 } 4409 4410 @Override 4411 public int hashCode() { 4412 // Cannot use key and value equivalence 4413 return key.hashCode() ^ value.hashCode(); 4414 } 4415 4416 @Override 4417 public V setValue(V newValue) { 4418 throw new UnsupportedOperationException(); 4419 } 4420 4421 /** 4422 * Returns a string representation of the form <code>{key}={value}</code>. 4423 */ 4424 @Override public String toString() { 4425 return getKey() + "=" + getValue(); 4426 } 4427 } 4428 4429 final class EntryIterator extends HashIterator<Entry<K, V>> { 4430 4431 @Override 4432 public Entry<K, V> next() { 4433 return nextEntry(); 4434 } 4435 } 4436 4437 abstract class AbstractCacheSet<T> extends AbstractSet<T> { 4438 final ConcurrentMap<?, ?> map; 4439 4440 AbstractCacheSet(ConcurrentMap<?, ?> map) { 4441 this.map = map; 4442 } 4443 4444 @Override 4445 public int size() { 4446 return map.size(); 4447 } 4448 4449 @Override 4450 public boolean isEmpty() { 4451 return map.isEmpty(); 4452 } 4453 4454 @Override 4455 public void clear() { 4456 map.clear(); 4457 } 4458 } 4459 4460 final class KeySet extends AbstractCacheSet<K> { 4461 4462 KeySet(ConcurrentMap<?, ?> map) { 4463 super(map); 4464 } 4465 4466 @Override 4467 public Iterator<K> iterator() { 4468 return new KeyIterator(); 4469 } 4470 4471 @Override 4472 public boolean contains(Object o) { 4473 return map.containsKey(o); 4474 } 4475 4476 @Override 4477 public boolean remove(Object o) { 4478 return map.remove(o) != null; 4479 } 4480 } 4481 4482 final class Values extends AbstractCollection<V> { 4483 private final ConcurrentMap<?, ?> map; 4484 4485 Values(ConcurrentMap<?, ?> map) { 4486 this.map = map; 4487 } 4488 4489 @Override public int size() { 4490 return map.size(); 4491 } 4492 4493 @Override public boolean isEmpty() { 4494 return map.isEmpty(); 4495 } 4496 4497 @Override public void clear() { 4498 map.clear(); 4499 } 4500 4501 @Override 4502 public Iterator<V> iterator() { 4503 return new ValueIterator(); 4504 } 4505 4506 @Override 4507 public boolean contains(Object o) { 4508 return map.containsValue(o); 4509 } 4510 } 4511 4512 final class EntrySet extends AbstractCacheSet<Entry<K, V>> { 4513 4514 EntrySet(ConcurrentMap<?, ?> map) { 4515 super(map); 4516 } 4517 4518 @Override 4519 public Iterator<Entry<K, V>> iterator() { 4520 return new EntryIterator(); 4521 } 4522 4523 @Override 4524 public boolean contains(Object o) { 4525 if (!(o instanceof Entry)) { 4526 return false; 4527 } 4528 Entry<?, ?> e = (Entry<?, ?>) o; 4529 Object key = e.getKey(); 4530 if (key == null) { 4531 return false; 4532 } 4533 V v = LocalCache.this.get(key); 4534 4535 return v != null && valueEquivalence.equivalent(e.getValue(), v); 4536 } 4537 4538 @Override 4539 public boolean remove(Object o) { 4540 if (!(o instanceof Entry)) { 4541 return false; 4542 } 4543 Entry<?, ?> e = (Entry<?, ?>) o; 4544 Object key = e.getKey(); 4545 return key != null && LocalCache.this.remove(key, e.getValue()); 4546 } 4547 } 4548 4549 // Serialization Support 4550 4551 /** 4552 * Serializes the configuration of a LocalCache, reconsitituting it as a Cache using 4553 * CacheBuilder upon deserialization. An instance of this class is fit for use by the writeReplace 4554 * of LocalManualCache. 4555 * 4556 * Unfortunately, readResolve() doesn't get called when a circular dependency is present, so the 4557 * proxy must be able to behave as the cache itself. 4558 */ 4559 static class ManualSerializationProxy<K, V> 4560 extends ForwardingCache<K, V> implements Serializable { 4561 private static final long serialVersionUID = 1; 4562 4563 final Strength keyStrength; 4564 final Strength valueStrength; 4565 final Equivalence<Object> keyEquivalence; 4566 final Equivalence<Object> valueEquivalence; 4567 final long expireAfterWriteNanos; 4568 final long expireAfterAccessNanos; 4569 final long maxWeight; 4570 final Weigher<K, V> weigher; 4571 final int concurrencyLevel; 4572 final RemovalListener<? super K, ? super V> removalListener; 4573 final Ticker ticker; 4574 final CacheLoader<? super K, V> loader; 4575 4576 transient Cache<K, V> delegate; 4577 4578 ManualSerializationProxy(LocalCache<K, V> cache) { 4579 this( 4580 cache.keyStrength, 4581 cache.valueStrength, 4582 cache.keyEquivalence, 4583 cache.valueEquivalence, 4584 cache.expireAfterWriteNanos, 4585 cache.expireAfterAccessNanos, 4586 cache.maxWeight, 4587 cache.weigher, 4588 cache.concurrencyLevel, 4589 cache.removalListener, 4590 cache.ticker, 4591 cache.defaultLoader); 4592 } 4593 4594 private ManualSerializationProxy( 4595 Strength keyStrength, Strength valueStrength, 4596 Equivalence<Object> keyEquivalence, Equivalence<Object> valueEquivalence, 4597 long expireAfterWriteNanos, long expireAfterAccessNanos, long maxWeight, 4598 Weigher<K, V> weigher, int concurrencyLevel, 4599 RemovalListener<? super K, ? super V> removalListener, 4600 Ticker ticker, CacheLoader<? super K, V> loader) { 4601 this.keyStrength = keyStrength; 4602 this.valueStrength = valueStrength; 4603 this.keyEquivalence = keyEquivalence; 4604 this.valueEquivalence = valueEquivalence; 4605 this.expireAfterWriteNanos = expireAfterWriteNanos; 4606 this.expireAfterAccessNanos = expireAfterAccessNanos; 4607 this.maxWeight = maxWeight; 4608 this.weigher = weigher; 4609 this.concurrencyLevel = concurrencyLevel; 4610 this.removalListener = removalListener; 4611 this.ticker = (ticker == Ticker.systemTicker() || ticker == NULL_TICKER) 4612 ? null : ticker; 4613 this.loader = loader; 4614 } 4615 4616 CacheBuilder<K, V> recreateCacheBuilder() { 4617 CacheBuilder<K, V> builder = CacheBuilder.newBuilder() 4618 .setKeyStrength(keyStrength) 4619 .setValueStrength(valueStrength) 4620 .keyEquivalence(keyEquivalence) 4621 .valueEquivalence(valueEquivalence) 4622 .concurrencyLevel(concurrencyLevel) 4623 .removalListener(removalListener); 4624 builder.strictParsing = false; 4625 if (expireAfterWriteNanos > 0) { 4626 builder.expireAfterWrite(expireAfterWriteNanos, TimeUnit.NANOSECONDS); 4627 } 4628 if (expireAfterAccessNanos > 0) { 4629 builder.expireAfterAccess(expireAfterAccessNanos, TimeUnit.NANOSECONDS); 4630 } 4631 if (weigher != OneWeigher.INSTANCE) { 4632 builder.weigher(weigher); 4633 if (maxWeight != UNSET_INT) { 4634 builder.maximumWeight(maxWeight); 4635 } 4636 } else { 4637 if (maxWeight != UNSET_INT) { 4638 builder.maximumSize(maxWeight); 4639 } 4640 } 4641 if (ticker != null) { 4642 builder.ticker(ticker); 4643 } 4644 return builder; 4645 } 4646 4647 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 4648 in.defaultReadObject(); 4649 CacheBuilder<K, V> builder = recreateCacheBuilder(); 4650 this.delegate = builder.build(); 4651 } 4652 4653 private Object readResolve() { 4654 return delegate; 4655 } 4656 4657 @Override 4658 protected Cache<K, V> delegate() { 4659 return delegate; 4660 } 4661 } 4662 4663 /** 4664 * Serializes the configuration of a LocalCache, reconsitituting it as an LoadingCache using 4665 * CacheBuilder upon deserialization. An instance of this class is fit for use by the writeReplace 4666 * of LocalLoadingCache. 4667 * 4668 * Unfortunately, readResolve() doesn't get called when a circular dependency is present, so the 4669 * proxy must be able to behave as the cache itself. 4670 */ 4671 static final class LoadingSerializationProxy<K, V> 4672 extends ManualSerializationProxy<K, V> implements LoadingCache<K, V>, Serializable { 4673 private static final long serialVersionUID = 1; 4674 4675 transient LoadingCache<K, V> autoDelegate; 4676 4677 LoadingSerializationProxy(LocalCache<K, V> cache) { 4678 super(cache); 4679 } 4680 4681 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 4682 in.defaultReadObject(); 4683 CacheBuilder<K, V> builder = recreateCacheBuilder(); 4684 this.autoDelegate = builder.build(loader); 4685 } 4686 4687 @Override 4688 public V get(K key) throws ExecutionException { 4689 return autoDelegate.get(key); 4690 } 4691 4692 @Override 4693 public V getUnchecked(K key) { 4694 return autoDelegate.getUnchecked(key); 4695 } 4696 4697 @Override 4698 public ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException { 4699 return autoDelegate.getAll(keys); 4700 } 4701 4702 @Override 4703 public final V apply(K key) { 4704 return autoDelegate.apply(key); 4705 } 4706 4707 @Override 4708 public void refresh(K key) { 4709 autoDelegate.refresh(key); 4710 } 4711 4712 private Object readResolve() { 4713 return autoDelegate; 4714 } 4715 } 4716 4717 static class LocalManualCache<K, V> implements Cache<K, V>, Serializable { 4718 final LocalCache<K, V> localCache; 4719 4720 LocalManualCache(CacheBuilder<? super K, ? super V> builder) { 4721 this(new LocalCache<K, V>(builder, null)); 4722 } 4723 4724 private LocalManualCache(LocalCache<K, V> localCache) { 4725 this.localCache = localCache; 4726 } 4727 4728 // Cache methods 4729 4730 @Override 4731 @Nullable 4732 public V getIfPresent(Object key) { 4733 return localCache.getIfPresent(key); 4734 } 4735 4736 @Override 4737 public V get(K key, final Callable<? extends V> valueLoader) throws ExecutionException { 4738 checkNotNull(valueLoader); 4739 return localCache.get(key, new CacheLoader<Object, V>() { 4740 @Override 4741 public V load(Object key) throws Exception { 4742 return valueLoader.call(); 4743 } 4744 }); 4745 } 4746 4747 @Override 4748 public ImmutableMap<K, V> getAllPresent(Iterable<?> keys) { 4749 return localCache.getAllPresent(keys); 4750 } 4751 4752 @Override 4753 public void put(K key, V value) { 4754 localCache.put(key, value); 4755 } 4756 4757 @Override 4758 public void putAll(Map<? extends K, ? extends V> m) { 4759 localCache.putAll(m); 4760 } 4761 4762 @Override 4763 public void invalidate(Object key) { 4764 checkNotNull(key); 4765 localCache.remove(key); 4766 } 4767 4768 @Override 4769 public void invalidateAll(Iterable<?> keys) { 4770 localCache.invalidateAll(keys); 4771 } 4772 4773 @Override 4774 public void invalidateAll() { 4775 localCache.clear(); 4776 } 4777 4778 @Override 4779 public long size() { 4780 return localCache.longSize(); 4781 } 4782 4783 @Override 4784 public ConcurrentMap<K, V> asMap() { 4785 return localCache; 4786 } 4787 4788 @Override 4789 public CacheStats stats() { 4790 SimpleStatsCounter aggregator = new SimpleStatsCounter(); 4791 aggregator.incrementBy(localCache.globalStatsCounter); 4792 for (Segment<K, V> segment : localCache.segments) { 4793 aggregator.incrementBy(segment.statsCounter); 4794 } 4795 return aggregator.snapshot(); 4796 } 4797 4798 @Override 4799 public void cleanUp() { 4800 localCache.cleanUp(); 4801 } 4802 4803 // Serialization Support 4804 4805 private static final long serialVersionUID = 1; 4806 4807 Object writeReplace() { 4808 return new ManualSerializationProxy<K, V>(localCache); 4809 } 4810 } 4811 4812 static class LocalLoadingCache<K, V> 4813 extends LocalManualCache<K, V> implements LoadingCache<K, V> { 4814 4815 LocalLoadingCache(CacheBuilder<? super K, ? super V> builder, 4816 CacheLoader<? super K, V> loader) { 4817 super(new LocalCache<K, V>(builder, checkNotNull(loader))); 4818 } 4819 4820 // LoadingCache methods 4821 4822 @Override 4823 public V get(K key) throws ExecutionException { 4824 return localCache.getOrLoad(key); 4825 } 4826 4827 @Override 4828 public V getUnchecked(K key) { 4829 try { 4830 return get(key); 4831 } catch (ExecutionException e) { 4832 throw new UncheckedExecutionException(e.getCause()); 4833 } 4834 } 4835 4836 @Override 4837 public ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException { 4838 return localCache.getAll(keys); 4839 } 4840 4841 @Override 4842 public void refresh(K key) { 4843 localCache.refresh(key); 4844 } 4845 4846 @Override 4847 public final V apply(K key) { 4848 return getUnchecked(key); 4849 } 4850 4851 // Serialization Support 4852 4853 private static final long serialVersionUID = 1; 4854 4855 @Override 4856 Object writeReplace() { 4857 return new LoadingSerializationProxy<K, V>(localCache); 4858 } 4859 } 4860 } 4861