Creates a new, empty map with the specified strategy, initial capacity and concurrency level.
(CacheBuilder<? super K, ? super V> builder, @Nullable CacheLoader<? super K, V> loader)
| 239 | */ |
| 240 | |
| 241 | LocalCache(CacheBuilder<? super K, ? super V> builder, @Nullable CacheLoader<? super K, V> loader) { |
| 242 | concurrencyLevel = Math.min(builder.getConcurrencyLevel(), MAX_SEGMENTS); |
| 243 | keyStrength = builder.getKeyStrength(); |
| 244 | valueStrength = builder.getValueStrength(); |
| 245 | keyEquivalence = builder.getKeyEquivalence(); |
| 246 | valueEquivalence = builder.getValueEquivalence(); |
| 247 | maxWeight = builder.getMaximumWeight(); |
| 248 | weigher = builder.getWeigher(); |
| 249 | expireAfterAccessNanos = builder.getExpireAfterAccessNanos(); |
| 250 | expireAfterWriteNanos = builder.getExpireAfterWriteNanos(); |
| 251 | refreshNanos = builder.getRefreshNanos(); |
| 252 | removalListener = builder.getRemovalListener(); |
| 253 | removalNotificationQueue = (removalListener == NullListener.INSTANCE) |
| 254 | ? LocalCache.<RemovalNotification<K, V>>discardingQueue() |
| 255 | : new ConcurrentLinkedQueue<RemovalNotification<K, V>>(); |
| 256 | ticker = builder.getTicker(recordsTime()); |
| 257 | entryFactory = EntryFactory.getFactory(keyStrength, usesAccessEntries(), usesWriteEntries()); |
| 258 | globalStatsCounter = builder.getStatsCounterSupplier().get(); |
| 259 | defaultLoader = loader; |
| 260 | int initialCapacity = Math.min(builder.getInitialCapacity(), MAXIMUM_CAPACITY); |
| 261 | if (evictsBySize() && !customWeigher()) { |
| 262 | initialCapacity = Math.min(initialCapacity, (int) maxWeight); |
| 263 | } |
| 264 | |
| 265 | // Find the lowest power-of-two segmentCount that exceeds concurrencyLevel, unless |
| 266 | // maximumSize/Weight is specified in which case ensure that each segment gets at least 10 |
| 267 | // entries. The special casing for size-based eviction is only necessary because that eviction |
| 268 | // happens per segment instead of globally, so too many segments compared to the maximum size |
| 269 | // will result in random eviction behavior. |
| 270 | |
| 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 | this.segments = newSegmentArray(segmentCount); |
| 281 | int segmentCapacity = initialCapacity / segmentCount; |
| 282 | if (segmentCapacity * segmentCount < initialCapacity) { |
| 283 | ++segmentCapacity; |
| 284 | } |
| 285 | |
| 286 | int segmentSize = 1; |
| 287 | while (segmentSize < segmentCapacity) { |
| 288 | segmentSize <<= 1; |
| 289 | } |
| 290 | if (evictsBySize()) { |
| 291 | // Ensure sum of segment max weights = overall max weights |
| 292 | long maxSegmentWeight = maxWeight / segmentCount + 1; |
| 293 | long remainder = maxWeight % segmentCount; |
| 294 | for (int i = 0; i < this.segments.length; ++i) { |
| 295 | if (i == remainder) { |
| 296 | maxSegmentWeight--; |
| 297 | } |
| 298 | this.segments[i] = |
nothing calls this directly
no test coverage detected