The concurrent hash map implementation built by {@link CacheBuilder}. <p>This implementation is heavily derived from revision 1.96 of <a href="http://tinyurl.com/ConcurrentHashMap">ConcurrentHashMap.java</a>. @author Charles Fry @author Bob Lee ({@code com.google.common.collect.MapMaker}) @author
| 102 | * @author Doug Lea ({@code ConcurrentHashMap}) |
| 103 | */ |
| 104 | @SuppressWarnings({ |
| 105 | "GoodTime", // lots of violations (nanosecond math) |
| 106 | "nullness", // too much trouble for the payoff |
| 107 | }) |
| 108 | @GwtCompatible |
| 109 | @NullUnmarked // TODO(cpovirk): Annotate for nullness. |
| 110 | final class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> { |
| 111 | |
| 112 | /* |
| 113 | * The basic strategy is to subdivide the table among Segments, each of which itself is a |
| 114 | * concurrently readable hash table. The map supports non-blocking reads and concurrent writes |
| 115 | * across different segments. |
| 116 | * |
| 117 | * If a maximum size is specified, a best-effort bounding is performed per segment, using a |
| 118 | * page-replacement algorithm to determine which entries to evict when the capacity has been |
| 119 | * exceeded. |
| 120 | * |
| 121 | * The page replacement algorithm's data structures are kept casually consistent with the map. The |
| 122 | * ordering of writes to a segment is sequentially consistent. An update to the map and recording |
| 123 | * of reads may not be immediately reflected on the algorithm's data structures. These structures |
| 124 | * are guarded by a lock and operations are applied in batches to avoid lock contention. The |
| 125 | * penalty of applying the batches is spread across threads so that the amortized cost is slightly |
| 126 | * higher than performing just the operation without enforcing the capacity constraint. |
| 127 | * |
| 128 | * This implementation uses a per-segment queue to record a memento of the additions, removals, |
| 129 | * and accesses that were performed on the map. The queue is drained on writes and when it exceeds |
| 130 | * its capacity threshold. |
| 131 | * |
| 132 | * The Least Recently Used page replacement algorithm was chosen due to its simplicity, high hit |
| 133 | * rate, and ability to be implemented with O(1) time complexity. The initial LRU implementation |
| 134 | * operates per-segment rather than globally for increased implementation simplicity. We expect |
| 135 | * the cache hit rate to be similar to that of a global LRU algorithm. |
| 136 | */ |
| 137 | |
| 138 | // Constants |
| 139 | |
| 140 | /** |
| 141 | * The maximum capacity, used if a higher value is implicitly specified by either of the |
| 142 | * constructors with arguments. MUST be a power of two {@code <= 1<<30} to ensure that entries are |
| 143 | * indexable using ints. |
| 144 | */ |
| 145 | static final int MAXIMUM_CAPACITY = 1 << 30; |
| 146 | |
| 147 | /** The maximum number of segments to allow; used to bound constructor arguments. */ |
| 148 | static final int MAX_SEGMENTS = 1 << 16; // slightly conservative |
| 149 | |
| 150 | /** Number of (unsynchronized) retries in the containsValue method. */ |
| 151 | static final int CONTAINS_VALUE_RETRIES = 3; |
| 152 | |
| 153 | /** |
| 154 | * Number of cache access operations that can be buffered per segment before the cache's recency |
| 155 | * ordering information is updated. This is used to avoid lock contention by recording a memento |
| 156 | * of reads and delaying a lock acquisition until the threshold is crossed or a mutation occurs. |
| 157 | * |
| 158 | * <p>This must be a (2^n)-1 as it is used as a mask. |
| 159 | */ |
| 160 | static final int DRAIN_THRESHOLD = 0x3F; |
| 161 |