1 /* 2 * Copyright (C) 2011 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15 package com.google.common.cache; 16 17 import static com.google.common.cache.TestingCacheLoaders.bulkLoader; 18 import static com.google.common.cache.TestingCacheLoaders.constantLoader; 19 import static com.google.common.cache.TestingCacheLoaders.errorLoader; 20 import static com.google.common.cache.TestingCacheLoaders.exceptionLoader; 21 import static com.google.common.cache.TestingCacheLoaders.identityLoader; 22 import static com.google.common.cache.TestingRemovalListeners.countingRemovalListener; 23 import static com.google.common.truth.Truth.assertThat; 24 import static java.lang.Thread.currentThread; 25 import static java.util.Arrays.asList; 26 import static java.util.concurrent.TimeUnit.MILLISECONDS; 27 28 import com.google.common.cache.CacheLoader.InvalidCacheLoadException; 29 import com.google.common.cache.TestingCacheLoaders.CountingLoader; 30 import com.google.common.cache.TestingCacheLoaders.IdentityLoader; 31 import com.google.common.cache.TestingRemovalListeners.CountingRemovalListener; 32 import com.google.common.collect.ImmutableList; 33 import com.google.common.collect.ImmutableMap; 34 import com.google.common.collect.Lists; 35 import com.google.common.collect.Maps; 36 import com.google.common.testing.FakeTicker; 37 import com.google.common.testing.TestLogHandler; 38 import com.google.common.util.concurrent.Callables; 39 import com.google.common.util.concurrent.ExecutionError; 40 import com.google.common.util.concurrent.Futures; 41 import com.google.common.util.concurrent.ListenableFuture; 42 import com.google.common.util.concurrent.UncheckedExecutionException; 43 import java.io.IOException; 44 import java.lang.ref.WeakReference; 45 import java.util.List; 46 import java.util.Map; 47 import java.util.Map.Entry; 48 import java.util.concurrent.Callable; 49 import java.util.concurrent.ConcurrentMap; 50 import java.util.concurrent.CountDownLatch; 51 import java.util.concurrent.ExecutionException; 52 import java.util.concurrent.TimeUnit; 53 import java.util.concurrent.atomic.AtomicInteger; 54 import java.util.concurrent.atomic.AtomicReferenceArray; 55 import java.util.logging.LogRecord; 56 import junit.framework.TestCase; 57 58 /** 59 * Tests relating to cache loading: concurrent loading, exceptions during loading, etc. 60 * 61 * @author mike nonemacher 62 */ 63 public class CacheLoadingTest extends TestCase { 64 TestLogHandler logHandler; 65 66 @Override setUp()67 public void setUp() throws Exception { 68 super.setUp(); 69 logHandler = new TestLogHandler(); 70 LocalCache.logger.addHandler(logHandler); 71 } 72 73 @Override tearDown()74 public void tearDown() throws Exception { 75 super.tearDown(); 76 // TODO(cpovirk): run tests in other thread instead of messing with main thread interrupt status 77 currentThread().interrupted(); 78 LocalCache.logger.removeHandler(logHandler); 79 } 80 popLoggedThrowable()81 private Throwable popLoggedThrowable() { 82 List<LogRecord> logRecords = logHandler.getStoredLogRecords(); 83 assertEquals(1, logRecords.size()); 84 LogRecord logRecord = logRecords.get(0); 85 logHandler.clear(); 86 return logRecord.getThrown(); 87 } 88 checkNothingLogged()89 private void checkNothingLogged() { 90 assertThat(logHandler.getStoredLogRecords()).isEmpty(); 91 } 92 checkLoggedCause(Throwable t)93 private void checkLoggedCause(Throwable t) { 94 assertThat(popLoggedThrowable()).hasCauseThat().isSameInstanceAs(t); 95 } 96 checkLoggedInvalidLoad()97 private void checkLoggedInvalidLoad() { 98 assertThat(popLoggedThrowable()).isInstanceOf(InvalidCacheLoadException.class); 99 } 100 testLoad()101 public void testLoad() throws ExecutionException { 102 LoadingCache<Object, Object> cache = 103 CacheBuilder.newBuilder().recordStats().build(identityLoader()); 104 CacheStats stats = cache.stats(); 105 assertEquals(0, stats.missCount()); 106 assertEquals(0, stats.loadSuccessCount()); 107 assertEquals(0, stats.loadExceptionCount()); 108 assertEquals(0, stats.hitCount()); 109 110 Object key = new Object(); 111 assertSame(key, cache.get(key)); 112 stats = cache.stats(); 113 assertEquals(1, stats.missCount()); 114 assertEquals(1, stats.loadSuccessCount()); 115 assertEquals(0, stats.loadExceptionCount()); 116 assertEquals(0, stats.hitCount()); 117 118 key = new Object(); 119 assertSame(key, cache.getUnchecked(key)); 120 stats = cache.stats(); 121 assertEquals(2, stats.missCount()); 122 assertEquals(2, stats.loadSuccessCount()); 123 assertEquals(0, stats.loadExceptionCount()); 124 assertEquals(0, stats.hitCount()); 125 126 key = new Object(); 127 cache.refresh(key); 128 checkNothingLogged(); 129 stats = cache.stats(); 130 assertEquals(2, stats.missCount()); 131 assertEquals(3, stats.loadSuccessCount()); 132 assertEquals(0, stats.loadExceptionCount()); 133 assertEquals(0, stats.hitCount()); 134 135 assertSame(key, cache.get(key)); 136 stats = cache.stats(); 137 assertEquals(2, stats.missCount()); 138 assertEquals(3, stats.loadSuccessCount()); 139 assertEquals(0, stats.loadExceptionCount()); 140 assertEquals(1, stats.hitCount()); 141 142 Object value = new Object(); 143 // callable is not called 144 assertSame(key, cache.get(key, throwing(new Exception()))); 145 stats = cache.stats(); 146 assertEquals(2, stats.missCount()); 147 assertEquals(3, stats.loadSuccessCount()); 148 assertEquals(0, stats.loadExceptionCount()); 149 assertEquals(2, stats.hitCount()); 150 151 key = new Object(); 152 assertSame(value, cache.get(key, Callables.returning(value))); 153 stats = cache.stats(); 154 assertEquals(3, stats.missCount()); 155 assertEquals(4, stats.loadSuccessCount()); 156 assertEquals(0, stats.loadExceptionCount()); 157 assertEquals(2, stats.hitCount()); 158 } 159 testReload()160 public void testReload() throws ExecutionException { 161 final Object one = new Object(); 162 final Object two = new Object(); 163 CacheLoader<Object, Object> loader = 164 new CacheLoader<Object, Object>() { 165 @Override 166 public Object load(Object key) { 167 return one; 168 } 169 170 @Override 171 public ListenableFuture<Object> reload(Object key, Object oldValue) { 172 return Futures.immediateFuture(two); 173 } 174 }; 175 176 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader); 177 Object key = new Object(); 178 CacheStats stats = cache.stats(); 179 assertEquals(0, stats.missCount()); 180 assertEquals(0, stats.loadSuccessCount()); 181 assertEquals(0, stats.loadExceptionCount()); 182 assertEquals(0, stats.hitCount()); 183 184 assertSame(one, cache.getUnchecked(key)); 185 stats = cache.stats(); 186 assertEquals(1, stats.missCount()); 187 assertEquals(1, stats.loadSuccessCount()); 188 assertEquals(0, stats.loadExceptionCount()); 189 assertEquals(0, stats.hitCount()); 190 191 cache.refresh(key); 192 checkNothingLogged(); 193 stats = cache.stats(); 194 assertEquals(1, stats.missCount()); 195 assertEquals(2, stats.loadSuccessCount()); 196 assertEquals(0, stats.loadExceptionCount()); 197 assertEquals(0, stats.hitCount()); 198 199 assertSame(two, cache.getUnchecked(key)); 200 stats = cache.stats(); 201 assertEquals(1, stats.missCount()); 202 assertEquals(2, stats.loadSuccessCount()); 203 assertEquals(0, stats.loadExceptionCount()); 204 assertEquals(1, stats.hitCount()); 205 } 206 testRefresh()207 public void testRefresh() { 208 final Object one = new Object(); 209 final Object two = new Object(); 210 FakeTicker ticker = new FakeTicker(); 211 CacheLoader<Object, Object> loader = 212 new CacheLoader<Object, Object>() { 213 @Override 214 public Object load(Object key) { 215 return one; 216 } 217 218 @Override 219 public ListenableFuture<Object> reload(Object key, Object oldValue) { 220 return Futures.immediateFuture(two); 221 } 222 }; 223 224 LoadingCache<Object, Object> cache = 225 CacheBuilder.newBuilder() 226 .recordStats() 227 .ticker(ticker) 228 .refreshAfterWrite(1, MILLISECONDS) 229 .build(loader); 230 Object key = new Object(); 231 CacheStats stats = cache.stats(); 232 assertEquals(0, stats.missCount()); 233 assertEquals(0, stats.loadSuccessCount()); 234 assertEquals(0, stats.loadExceptionCount()); 235 assertEquals(0, stats.hitCount()); 236 237 assertSame(one, cache.getUnchecked(key)); 238 stats = cache.stats(); 239 assertEquals(1, stats.missCount()); 240 assertEquals(1, stats.loadSuccessCount()); 241 assertEquals(0, stats.loadExceptionCount()); 242 assertEquals(0, stats.hitCount()); 243 244 ticker.advance(1, MILLISECONDS); 245 assertSame(one, cache.getUnchecked(key)); 246 stats = cache.stats(); 247 assertEquals(1, stats.missCount()); 248 assertEquals(1, stats.loadSuccessCount()); 249 assertEquals(0, stats.loadExceptionCount()); 250 assertEquals(1, stats.hitCount()); 251 252 ticker.advance(1, MILLISECONDS); 253 assertSame(two, cache.getUnchecked(key)); 254 stats = cache.stats(); 255 assertEquals(1, stats.missCount()); 256 assertEquals(2, stats.loadSuccessCount()); 257 assertEquals(0, stats.loadExceptionCount()); 258 assertEquals(2, stats.hitCount()); 259 260 ticker.advance(1, MILLISECONDS); 261 assertSame(two, cache.getUnchecked(key)); 262 stats = cache.stats(); 263 assertEquals(1, stats.missCount()); 264 assertEquals(2, stats.loadSuccessCount()); 265 assertEquals(0, stats.loadExceptionCount()); 266 assertEquals(3, stats.hitCount()); 267 } 268 testRefresh_getIfPresent()269 public void testRefresh_getIfPresent() { 270 final Object one = new Object(); 271 final Object two = new Object(); 272 FakeTicker ticker = new FakeTicker(); 273 CacheLoader<Object, Object> loader = 274 new CacheLoader<Object, Object>() { 275 @Override 276 public Object load(Object key) { 277 return one; 278 } 279 280 @Override 281 public ListenableFuture<Object> reload(Object key, Object oldValue) { 282 return Futures.immediateFuture(two); 283 } 284 }; 285 286 LoadingCache<Object, Object> cache = 287 CacheBuilder.newBuilder() 288 .recordStats() 289 .ticker(ticker) 290 .refreshAfterWrite(1, MILLISECONDS) 291 .build(loader); 292 Object key = new Object(); 293 CacheStats stats = cache.stats(); 294 assertEquals(0, stats.missCount()); 295 assertEquals(0, stats.loadSuccessCount()); 296 assertEquals(0, stats.loadExceptionCount()); 297 assertEquals(0, stats.hitCount()); 298 299 assertSame(one, cache.getUnchecked(key)); 300 stats = cache.stats(); 301 assertEquals(1, stats.missCount()); 302 assertEquals(1, stats.loadSuccessCount()); 303 assertEquals(0, stats.loadExceptionCount()); 304 assertEquals(0, stats.hitCount()); 305 306 ticker.advance(1, MILLISECONDS); 307 assertSame(one, cache.getIfPresent(key)); 308 stats = cache.stats(); 309 assertEquals(1, stats.missCount()); 310 assertEquals(1, stats.loadSuccessCount()); 311 assertEquals(0, stats.loadExceptionCount()); 312 assertEquals(1, stats.hitCount()); 313 314 ticker.advance(1, MILLISECONDS); 315 assertSame(two, cache.getIfPresent(key)); 316 stats = cache.stats(); 317 assertEquals(1, stats.missCount()); 318 assertEquals(2, stats.loadSuccessCount()); 319 assertEquals(0, stats.loadExceptionCount()); 320 assertEquals(2, stats.hitCount()); 321 322 ticker.advance(1, MILLISECONDS); 323 assertSame(two, cache.getIfPresent(key)); 324 stats = cache.stats(); 325 assertEquals(1, stats.missCount()); 326 assertEquals(2, stats.loadSuccessCount()); 327 assertEquals(0, stats.loadExceptionCount()); 328 assertEquals(3, stats.hitCount()); 329 } 330 testBulkLoad_default()331 public void testBulkLoad_default() throws ExecutionException { 332 LoadingCache<Integer, Integer> cache = 333 CacheBuilder.newBuilder() 334 .recordStats() 335 .build(TestingCacheLoaders.<Integer>identityLoader()); 336 CacheStats stats = cache.stats(); 337 assertEquals(0, stats.missCount()); 338 assertEquals(0, stats.loadSuccessCount()); 339 assertEquals(0, stats.loadExceptionCount()); 340 assertEquals(0, stats.hitCount()); 341 342 assertEquals(ImmutableMap.of(), cache.getAll(ImmutableList.<Integer>of())); 343 assertEquals(0, stats.missCount()); 344 assertEquals(0, stats.loadSuccessCount()); 345 assertEquals(0, stats.loadExceptionCount()); 346 assertEquals(0, stats.hitCount()); 347 348 assertEquals(ImmutableMap.of(1, 1), cache.getAll(asList(1))); 349 stats = cache.stats(); 350 assertEquals(1, stats.missCount()); 351 assertEquals(1, stats.loadSuccessCount()); 352 assertEquals(0, stats.loadExceptionCount()); 353 assertEquals(0, stats.hitCount()); 354 355 assertEquals(ImmutableMap.of(1, 1, 2, 2, 3, 3, 4, 4), cache.getAll(asList(1, 2, 3, 4))); 356 stats = cache.stats(); 357 assertEquals(4, stats.missCount()); 358 assertEquals(4, stats.loadSuccessCount()); 359 assertEquals(0, stats.loadExceptionCount()); 360 assertEquals(1, stats.hitCount()); 361 362 assertEquals(ImmutableMap.of(2, 2, 3, 3), cache.getAll(asList(2, 3))); 363 stats = cache.stats(); 364 assertEquals(4, stats.missCount()); 365 assertEquals(4, stats.loadSuccessCount()); 366 assertEquals(0, stats.loadExceptionCount()); 367 assertEquals(3, stats.hitCount()); 368 369 // duplicate keys are ignored, and don't impact stats 370 assertEquals(ImmutableMap.of(4, 4, 5, 5), cache.getAll(asList(4, 5))); 371 stats = cache.stats(); 372 assertEquals(5, stats.missCount()); 373 assertEquals(5, stats.loadSuccessCount()); 374 assertEquals(0, stats.loadExceptionCount()); 375 assertEquals(4, stats.hitCount()); 376 } 377 testBulkLoad_loadAll()378 public void testBulkLoad_loadAll() throws ExecutionException { 379 IdentityLoader<Integer> backingLoader = identityLoader(); 380 CacheLoader<Integer, Integer> loader = bulkLoader(backingLoader); 381 LoadingCache<Integer, Integer> cache = CacheBuilder.newBuilder().recordStats().build(loader); 382 CacheStats stats = cache.stats(); 383 assertEquals(0, stats.missCount()); 384 assertEquals(0, stats.loadSuccessCount()); 385 assertEquals(0, stats.loadExceptionCount()); 386 assertEquals(0, stats.hitCount()); 387 388 assertEquals(ImmutableMap.of(), cache.getAll(ImmutableList.<Integer>of())); 389 assertEquals(0, stats.missCount()); 390 assertEquals(0, stats.loadSuccessCount()); 391 assertEquals(0, stats.loadExceptionCount()); 392 assertEquals(0, stats.hitCount()); 393 394 assertEquals(ImmutableMap.of(1, 1), cache.getAll(asList(1))); 395 stats = cache.stats(); 396 assertEquals(1, stats.missCount()); 397 assertEquals(1, stats.loadSuccessCount()); 398 assertEquals(0, stats.loadExceptionCount()); 399 assertEquals(0, stats.hitCount()); 400 401 assertEquals(ImmutableMap.of(1, 1, 2, 2, 3, 3, 4, 4), cache.getAll(asList(1, 2, 3, 4))); 402 stats = cache.stats(); 403 assertEquals(4, stats.missCount()); 404 assertEquals(2, stats.loadSuccessCount()); 405 assertEquals(0, stats.loadExceptionCount()); 406 assertEquals(1, stats.hitCount()); 407 408 assertEquals(ImmutableMap.of(2, 2, 3, 3), cache.getAll(asList(2, 3))); 409 stats = cache.stats(); 410 assertEquals(4, stats.missCount()); 411 assertEquals(2, stats.loadSuccessCount()); 412 assertEquals(0, stats.loadExceptionCount()); 413 assertEquals(3, stats.hitCount()); 414 415 // duplicate keys are ignored, and don't impact stats 416 assertEquals(ImmutableMap.of(4, 4, 5, 5), cache.getAll(asList(4, 5))); 417 stats = cache.stats(); 418 assertEquals(5, stats.missCount()); 419 assertEquals(3, stats.loadSuccessCount()); 420 assertEquals(0, stats.loadExceptionCount()); 421 assertEquals(4, stats.hitCount()); 422 } 423 testBulkLoad_extra()424 public void testBulkLoad_extra() throws ExecutionException { 425 CacheLoader<Object, Object> loader = 426 new CacheLoader<Object, Object>() { 427 @Override 428 public Object load(Object key) throws Exception { 429 return new Object(); 430 } 431 432 @Override 433 public Map<Object, Object> loadAll(Iterable<?> keys) throws Exception { 434 Map<Object, Object> result = Maps.newHashMap(); 435 for (Object key : keys) { 436 Object value = new Object(); 437 result.put(key, value); 438 // add extra entries 439 result.put(value, key); 440 } 441 return result; 442 } 443 }; 444 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().build(loader); 445 446 Object[] lookupKeys = new Object[] {new Object(), new Object(), new Object()}; 447 Map<Object, Object> result = cache.getAll(asList(lookupKeys)); 448 assertThat(result.keySet()).containsExactlyElementsIn(asList(lookupKeys)); 449 for (Entry<Object, Object> entry : result.entrySet()) { 450 Object key = entry.getKey(); 451 Object value = entry.getValue(); 452 assertSame(value, result.get(key)); 453 assertNull(result.get(value)); 454 assertSame(value, cache.asMap().get(key)); 455 assertSame(key, cache.asMap().get(value)); 456 } 457 } 458 testBulkLoad_clobber()459 public void testBulkLoad_clobber() throws ExecutionException { 460 final Object extraKey = new Object(); 461 final Object extraValue = new Object(); 462 CacheLoader<Object, Object> loader = 463 new CacheLoader<Object, Object>() { 464 @Override 465 public Object load(Object key) throws Exception { 466 throw new AssertionError(); 467 } 468 469 @Override 470 public Map<Object, Object> loadAll(Iterable<?> keys) throws Exception { 471 Map<Object, Object> result = Maps.newHashMap(); 472 for (Object key : keys) { 473 Object value = new Object(); 474 result.put(key, value); 475 } 476 result.put(extraKey, extraValue); 477 return result; 478 } 479 }; 480 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().build(loader); 481 cache.asMap().put(extraKey, extraKey); 482 assertSame(extraKey, cache.asMap().get(extraKey)); 483 484 Object[] lookupKeys = new Object[] {new Object(), new Object(), new Object()}; 485 Map<Object, Object> result = cache.getAll(asList(lookupKeys)); 486 assertThat(result.keySet()).containsExactlyElementsIn(asList(lookupKeys)); 487 for (Entry<Object, Object> entry : result.entrySet()) { 488 Object key = entry.getKey(); 489 Object value = entry.getValue(); 490 assertSame(value, result.get(key)); 491 assertSame(value, cache.asMap().get(key)); 492 } 493 assertNull(result.get(extraKey)); 494 assertSame(extraValue, cache.asMap().get(extraKey)); 495 } 496 testBulkLoad_clobberNullValue()497 public void testBulkLoad_clobberNullValue() throws ExecutionException { 498 final Object extraKey = new Object(); 499 final Object extraValue = new Object(); 500 CacheLoader<Object, Object> loader = 501 new CacheLoader<Object, Object>() { 502 @Override 503 public Object load(Object key) throws Exception { 504 throw new AssertionError(); 505 } 506 507 @Override 508 public Map<Object, Object> loadAll(Iterable<?> keys) throws Exception { 509 Map<Object, Object> result = Maps.newHashMap(); 510 for (Object key : keys) { 511 Object value = new Object(); 512 result.put(key, value); 513 } 514 result.put(extraKey, extraValue); 515 result.put(extraValue, null); 516 return result; 517 } 518 }; 519 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().build(loader); 520 cache.asMap().put(extraKey, extraKey); 521 assertSame(extraKey, cache.asMap().get(extraKey)); 522 523 Object[] lookupKeys = new Object[] {new Object(), new Object(), new Object()}; 524 try { 525 cache.getAll(asList(lookupKeys)); 526 fail(); 527 } catch (InvalidCacheLoadException expected) { 528 } 529 530 for (Object key : lookupKeys) { 531 assertTrue(cache.asMap().containsKey(key)); 532 } 533 assertSame(extraValue, cache.asMap().get(extraKey)); 534 assertFalse(cache.asMap().containsKey(extraValue)); 535 } 536 testBulkLoad_clobberNullKey()537 public void testBulkLoad_clobberNullKey() throws ExecutionException { 538 final Object extraKey = new Object(); 539 final Object extraValue = new Object(); 540 CacheLoader<Object, Object> loader = 541 new CacheLoader<Object, Object>() { 542 @Override 543 public Object load(Object key) throws Exception { 544 throw new AssertionError(); 545 } 546 547 @Override 548 public Map<Object, Object> loadAll(Iterable<?> keys) throws Exception { 549 Map<Object, Object> result = Maps.newHashMap(); 550 for (Object key : keys) { 551 Object value = new Object(); 552 result.put(key, value); 553 } 554 result.put(extraKey, extraValue); 555 result.put(null, extraKey); 556 return result; 557 } 558 }; 559 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().build(loader); 560 cache.asMap().put(extraKey, extraKey); 561 assertSame(extraKey, cache.asMap().get(extraKey)); 562 563 Object[] lookupKeys = new Object[] {new Object(), new Object(), new Object()}; 564 try { 565 cache.getAll(asList(lookupKeys)); 566 fail(); 567 } catch (InvalidCacheLoadException expected) { 568 } 569 570 for (Object key : lookupKeys) { 571 assertTrue(cache.asMap().containsKey(key)); 572 } 573 assertSame(extraValue, cache.asMap().get(extraKey)); 574 assertFalse(cache.asMap().containsValue(extraKey)); 575 } 576 testBulkLoad_partial()577 public void testBulkLoad_partial() throws ExecutionException { 578 final Object extraKey = new Object(); 579 final Object extraValue = new Object(); 580 CacheLoader<Object, Object> loader = 581 new CacheLoader<Object, Object>() { 582 @Override 583 public Object load(Object key) throws Exception { 584 throw new AssertionError(); 585 } 586 587 @Override 588 public Map<Object, Object> loadAll(Iterable<?> keys) throws Exception { 589 Map<Object, Object> result = Maps.newHashMap(); 590 // ignore request keys 591 result.put(extraKey, extraValue); 592 return result; 593 } 594 }; 595 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().build(loader); 596 597 Object[] lookupKeys = new Object[] {new Object(), new Object(), new Object()}; 598 try { 599 cache.getAll(asList(lookupKeys)); 600 fail(); 601 } catch (InvalidCacheLoadException expected) { 602 } 603 assertSame(extraValue, cache.asMap().get(extraKey)); 604 } 605 testLoadNull()606 public void testLoadNull() throws ExecutionException { 607 LoadingCache<Object, Object> cache = 608 CacheBuilder.newBuilder().recordStats().build(constantLoader(null)); 609 CacheStats stats = cache.stats(); 610 assertEquals(0, stats.missCount()); 611 assertEquals(0, stats.loadSuccessCount()); 612 assertEquals(0, stats.loadExceptionCount()); 613 assertEquals(0, stats.hitCount()); 614 615 try { 616 cache.get(new Object()); 617 fail(); 618 } catch (InvalidCacheLoadException expected) { 619 } 620 stats = cache.stats(); 621 assertEquals(1, stats.missCount()); 622 assertEquals(0, stats.loadSuccessCount()); 623 assertEquals(1, stats.loadExceptionCount()); 624 assertEquals(0, stats.hitCount()); 625 626 try { 627 cache.getUnchecked(new Object()); 628 fail(); 629 } catch (InvalidCacheLoadException expected) { 630 } 631 stats = cache.stats(); 632 assertEquals(2, stats.missCount()); 633 assertEquals(0, stats.loadSuccessCount()); 634 assertEquals(2, stats.loadExceptionCount()); 635 assertEquals(0, stats.hitCount()); 636 637 cache.refresh(new Object()); 638 checkLoggedInvalidLoad(); 639 stats = cache.stats(); 640 assertEquals(2, stats.missCount()); 641 assertEquals(0, stats.loadSuccessCount()); 642 assertEquals(3, stats.loadExceptionCount()); 643 assertEquals(0, stats.hitCount()); 644 645 try { 646 cache.get(new Object(), Callables.returning(null)); 647 fail(); 648 } catch (InvalidCacheLoadException expected) { 649 } 650 stats = cache.stats(); 651 assertEquals(3, stats.missCount()); 652 assertEquals(0, stats.loadSuccessCount()); 653 assertEquals(4, stats.loadExceptionCount()); 654 assertEquals(0, stats.hitCount()); 655 656 try { 657 cache.getAll(asList(new Object())); 658 fail(); 659 } catch (InvalidCacheLoadException expected) { 660 } 661 stats = cache.stats(); 662 assertEquals(4, stats.missCount()); 663 assertEquals(0, stats.loadSuccessCount()); 664 assertEquals(5, stats.loadExceptionCount()); 665 assertEquals(0, stats.hitCount()); 666 } 667 testReloadNull()668 public void testReloadNull() throws ExecutionException { 669 final Object one = new Object(); 670 CacheLoader<Object, Object> loader = 671 new CacheLoader<Object, Object>() { 672 @Override 673 public Object load(Object key) { 674 return one; 675 } 676 677 @Override 678 public ListenableFuture<Object> reload(Object key, Object oldValue) { 679 return null; 680 } 681 }; 682 683 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader); 684 Object key = new Object(); 685 CacheStats stats = cache.stats(); 686 assertEquals(0, stats.missCount()); 687 assertEquals(0, stats.loadSuccessCount()); 688 assertEquals(0, stats.loadExceptionCount()); 689 assertEquals(0, stats.hitCount()); 690 691 assertSame(one, cache.getUnchecked(key)); 692 stats = cache.stats(); 693 assertEquals(1, stats.missCount()); 694 assertEquals(1, stats.loadSuccessCount()); 695 assertEquals(0, stats.loadExceptionCount()); 696 assertEquals(0, stats.hitCount()); 697 698 cache.refresh(key); 699 checkLoggedInvalidLoad(); 700 stats = cache.stats(); 701 assertEquals(1, stats.missCount()); 702 assertEquals(1, stats.loadSuccessCount()); 703 assertEquals(1, stats.loadExceptionCount()); 704 assertEquals(0, stats.hitCount()); 705 706 assertSame(one, cache.getUnchecked(key)); 707 stats = cache.stats(); 708 assertEquals(1, stats.missCount()); 709 assertEquals(1, stats.loadSuccessCount()); 710 assertEquals(1, stats.loadExceptionCount()); 711 assertEquals(1, stats.hitCount()); 712 } 713 testReloadNullFuture()714 public void testReloadNullFuture() throws ExecutionException { 715 final Object one = new Object(); 716 CacheLoader<Object, Object> loader = 717 new CacheLoader<Object, Object>() { 718 @Override 719 public Object load(Object key) { 720 return one; 721 } 722 723 @Override 724 public ListenableFuture<Object> reload(Object key, Object oldValue) { 725 return Futures.immediateFuture(null); 726 } 727 }; 728 729 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader); 730 Object key = new Object(); 731 CacheStats stats = cache.stats(); 732 assertEquals(0, stats.missCount()); 733 assertEquals(0, stats.loadSuccessCount()); 734 assertEquals(0, stats.loadExceptionCount()); 735 assertEquals(0, stats.hitCount()); 736 737 assertSame(one, cache.getUnchecked(key)); 738 stats = cache.stats(); 739 assertEquals(1, stats.missCount()); 740 assertEquals(1, stats.loadSuccessCount()); 741 assertEquals(0, stats.loadExceptionCount()); 742 assertEquals(0, stats.hitCount()); 743 744 cache.refresh(key); 745 checkLoggedInvalidLoad(); 746 stats = cache.stats(); 747 assertEquals(1, stats.missCount()); 748 assertEquals(1, stats.loadSuccessCount()); 749 assertEquals(1, stats.loadExceptionCount()); 750 assertEquals(0, stats.hitCount()); 751 752 assertSame(one, cache.getUnchecked(key)); 753 stats = cache.stats(); 754 assertEquals(1, stats.missCount()); 755 assertEquals(1, stats.loadSuccessCount()); 756 assertEquals(1, stats.loadExceptionCount()); 757 assertEquals(1, stats.hitCount()); 758 } 759 testRefreshNull()760 public void testRefreshNull() { 761 final Object one = new Object(); 762 FakeTicker ticker = new FakeTicker(); 763 CacheLoader<Object, Object> loader = 764 new CacheLoader<Object, Object>() { 765 @Override 766 public Object load(Object key) { 767 return one; 768 } 769 770 @Override 771 public ListenableFuture<Object> reload(Object key, Object oldValue) { 772 return Futures.immediateFuture(null); 773 } 774 }; 775 776 LoadingCache<Object, Object> cache = 777 CacheBuilder.newBuilder() 778 .recordStats() 779 .ticker(ticker) 780 .refreshAfterWrite(1, MILLISECONDS) 781 .build(loader); 782 Object key = new Object(); 783 CacheStats stats = cache.stats(); 784 assertEquals(0, stats.missCount()); 785 assertEquals(0, stats.loadSuccessCount()); 786 assertEquals(0, stats.loadExceptionCount()); 787 assertEquals(0, stats.hitCount()); 788 789 assertSame(one, cache.getUnchecked(key)); 790 stats = cache.stats(); 791 assertEquals(1, stats.missCount()); 792 assertEquals(1, stats.loadSuccessCount()); 793 assertEquals(0, stats.loadExceptionCount()); 794 assertEquals(0, stats.hitCount()); 795 796 ticker.advance(1, MILLISECONDS); 797 assertSame(one, cache.getUnchecked(key)); 798 stats = cache.stats(); 799 assertEquals(1, stats.missCount()); 800 assertEquals(1, stats.loadSuccessCount()); 801 assertEquals(0, stats.loadExceptionCount()); 802 assertEquals(1, stats.hitCount()); 803 804 ticker.advance(1, MILLISECONDS); 805 assertSame(one, cache.getUnchecked(key)); 806 // refreshed 807 stats = cache.stats(); 808 assertEquals(1, stats.missCount()); 809 assertEquals(1, stats.loadSuccessCount()); 810 assertEquals(1, stats.loadExceptionCount()); 811 assertEquals(2, stats.hitCount()); 812 813 ticker.advance(1, MILLISECONDS); 814 assertSame(one, cache.getUnchecked(key)); 815 stats = cache.stats(); 816 assertEquals(1, stats.missCount()); 817 assertEquals(1, stats.loadSuccessCount()); 818 assertEquals(2, stats.loadExceptionCount()); 819 assertEquals(3, stats.hitCount()); 820 } 821 testBulkLoadNull()822 public void testBulkLoadNull() throws ExecutionException { 823 LoadingCache<Object, Object> cache = 824 CacheBuilder.newBuilder().recordStats().build(bulkLoader(constantLoader(null))); 825 CacheStats stats = cache.stats(); 826 assertEquals(0, stats.missCount()); 827 assertEquals(0, stats.loadSuccessCount()); 828 assertEquals(0, stats.loadExceptionCount()); 829 assertEquals(0, stats.hitCount()); 830 831 try { 832 cache.getAll(asList(new Object())); 833 fail(); 834 } catch (InvalidCacheLoadException expected) { 835 } 836 stats = cache.stats(); 837 assertEquals(1, stats.missCount()); 838 assertEquals(0, stats.loadSuccessCount()); 839 assertEquals(1, stats.loadExceptionCount()); 840 assertEquals(0, stats.hitCount()); 841 } 842 testBulkLoadNullMap()843 public void testBulkLoadNullMap() throws ExecutionException { 844 LoadingCache<Object, Object> cache = 845 CacheBuilder.newBuilder() 846 .recordStats() 847 .build( 848 new CacheLoader<Object, Object>() { 849 @Override 850 public Object load(Object key) { 851 throw new AssertionError(); 852 } 853 854 @Override 855 public Map<Object, Object> loadAll(Iterable<?> keys) { 856 return null; 857 } 858 }); 859 860 CacheStats stats = cache.stats(); 861 assertEquals(0, stats.missCount()); 862 assertEquals(0, stats.loadSuccessCount()); 863 assertEquals(0, stats.loadExceptionCount()); 864 assertEquals(0, stats.hitCount()); 865 866 try { 867 cache.getAll(asList(new Object())); 868 fail(); 869 } catch (InvalidCacheLoadException expected) { 870 } 871 stats = cache.stats(); 872 assertEquals(1, stats.missCount()); 873 assertEquals(0, stats.loadSuccessCount()); 874 assertEquals(1, stats.loadExceptionCount()); 875 assertEquals(0, stats.hitCount()); 876 } 877 testLoadError()878 public void testLoadError() throws ExecutionException { 879 Error e = new Error(); 880 CacheLoader<Object, Object> loader = errorLoader(e); 881 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader); 882 CacheStats stats = cache.stats(); 883 assertEquals(0, stats.missCount()); 884 assertEquals(0, stats.loadSuccessCount()); 885 assertEquals(0, stats.loadExceptionCount()); 886 assertEquals(0, stats.hitCount()); 887 888 try { 889 cache.get(new Object()); 890 fail(); 891 } catch (ExecutionError expected) { 892 assertThat(expected).hasCauseThat().isSameInstanceAs(e); 893 } 894 stats = cache.stats(); 895 assertEquals(1, stats.missCount()); 896 assertEquals(0, stats.loadSuccessCount()); 897 assertEquals(1, stats.loadExceptionCount()); 898 assertEquals(0, stats.hitCount()); 899 900 try { 901 cache.getUnchecked(new Object()); 902 fail(); 903 } catch (ExecutionError expected) { 904 assertThat(expected).hasCauseThat().isSameInstanceAs(e); 905 } 906 stats = cache.stats(); 907 assertEquals(2, stats.missCount()); 908 assertEquals(0, stats.loadSuccessCount()); 909 assertEquals(2, stats.loadExceptionCount()); 910 assertEquals(0, stats.hitCount()); 911 912 cache.refresh(new Object()); 913 checkLoggedCause(e); 914 stats = cache.stats(); 915 assertEquals(2, stats.missCount()); 916 assertEquals(0, stats.loadSuccessCount()); 917 assertEquals(3, stats.loadExceptionCount()); 918 assertEquals(0, stats.hitCount()); 919 920 final Error callableError = new Error(); 921 try { 922 cache.get( 923 new Object(), 924 new Callable<Object>() { 925 @Override 926 public Object call() { 927 throw callableError; 928 } 929 }); 930 fail(); 931 } catch (ExecutionError expected) { 932 assertThat(expected).hasCauseThat().isSameInstanceAs(callableError); 933 } 934 stats = cache.stats(); 935 assertEquals(3, stats.missCount()); 936 assertEquals(0, stats.loadSuccessCount()); 937 assertEquals(4, stats.loadExceptionCount()); 938 assertEquals(0, stats.hitCount()); 939 940 try { 941 cache.getAll(asList(new Object())); 942 fail(); 943 } catch (ExecutionError expected) { 944 assertThat(expected).hasCauseThat().isSameInstanceAs(e); 945 } 946 stats = cache.stats(); 947 assertEquals(4, stats.missCount()); 948 assertEquals(0, stats.loadSuccessCount()); 949 assertEquals(5, stats.loadExceptionCount()); 950 assertEquals(0, stats.hitCount()); 951 } 952 testReloadError()953 public void testReloadError() throws ExecutionException { 954 final Object one = new Object(); 955 final Error e = new Error(); 956 CacheLoader<Object, Object> loader = 957 new CacheLoader<Object, Object>() { 958 @Override 959 public Object load(Object key) { 960 return one; 961 } 962 963 @Override 964 public ListenableFuture<Object> reload(Object key, Object oldValue) { 965 throw e; 966 } 967 }; 968 969 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader); 970 Object key = new Object(); 971 CacheStats stats = cache.stats(); 972 assertEquals(0, stats.missCount()); 973 assertEquals(0, stats.loadSuccessCount()); 974 assertEquals(0, stats.loadExceptionCount()); 975 assertEquals(0, stats.hitCount()); 976 977 assertSame(one, cache.getUnchecked(key)); 978 stats = cache.stats(); 979 assertEquals(1, stats.missCount()); 980 assertEquals(1, stats.loadSuccessCount()); 981 assertEquals(0, stats.loadExceptionCount()); 982 assertEquals(0, stats.hitCount()); 983 984 cache.refresh(key); 985 checkLoggedCause(e); 986 stats = cache.stats(); 987 assertEquals(1, stats.missCount()); 988 assertEquals(1, stats.loadSuccessCount()); 989 assertEquals(1, stats.loadExceptionCount()); 990 assertEquals(0, stats.hitCount()); 991 992 assertSame(one, cache.getUnchecked(key)); 993 stats = cache.stats(); 994 assertEquals(1, stats.missCount()); 995 assertEquals(1, stats.loadSuccessCount()); 996 assertEquals(1, stats.loadExceptionCount()); 997 assertEquals(1, stats.hitCount()); 998 } 999 testReloadFutureError()1000 public void testReloadFutureError() throws ExecutionException { 1001 final Object one = new Object(); 1002 final Error e = new Error(); 1003 CacheLoader<Object, Object> loader = 1004 new CacheLoader<Object, Object>() { 1005 @Override 1006 public Object load(Object key) { 1007 return one; 1008 } 1009 1010 @Override 1011 public ListenableFuture<Object> reload(Object key, Object oldValue) { 1012 return Futures.immediateFailedFuture(e); 1013 } 1014 }; 1015 1016 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader); 1017 Object key = new Object(); 1018 CacheStats stats = cache.stats(); 1019 assertEquals(0, stats.missCount()); 1020 assertEquals(0, stats.loadSuccessCount()); 1021 assertEquals(0, stats.loadExceptionCount()); 1022 assertEquals(0, stats.hitCount()); 1023 1024 assertSame(one, cache.getUnchecked(key)); 1025 stats = cache.stats(); 1026 assertEquals(1, stats.missCount()); 1027 assertEquals(1, stats.loadSuccessCount()); 1028 assertEquals(0, stats.loadExceptionCount()); 1029 assertEquals(0, stats.hitCount()); 1030 1031 cache.refresh(key); 1032 checkLoggedCause(e); 1033 stats = cache.stats(); 1034 assertEquals(1, stats.missCount()); 1035 assertEquals(1, stats.loadSuccessCount()); 1036 assertEquals(1, stats.loadExceptionCount()); 1037 assertEquals(0, stats.hitCount()); 1038 1039 assertSame(one, cache.getUnchecked(key)); 1040 stats = cache.stats(); 1041 assertEquals(1, stats.missCount()); 1042 assertEquals(1, stats.loadSuccessCount()); 1043 assertEquals(1, stats.loadExceptionCount()); 1044 assertEquals(1, stats.hitCount()); 1045 } 1046 testRefreshError()1047 public void testRefreshError() { 1048 final Object one = new Object(); 1049 final Error e = new Error(); 1050 FakeTicker ticker = new FakeTicker(); 1051 CacheLoader<Object, Object> loader = 1052 new CacheLoader<Object, Object>() { 1053 @Override 1054 public Object load(Object key) { 1055 return one; 1056 } 1057 1058 @Override 1059 public ListenableFuture<Object> reload(Object key, Object oldValue) { 1060 return Futures.immediateFailedFuture(e); 1061 } 1062 }; 1063 1064 LoadingCache<Object, Object> cache = 1065 CacheBuilder.newBuilder() 1066 .recordStats() 1067 .ticker(ticker) 1068 .refreshAfterWrite(1, MILLISECONDS) 1069 .build(loader); 1070 Object key = new Object(); 1071 CacheStats stats = cache.stats(); 1072 assertEquals(0, stats.missCount()); 1073 assertEquals(0, stats.loadSuccessCount()); 1074 assertEquals(0, stats.loadExceptionCount()); 1075 assertEquals(0, stats.hitCount()); 1076 1077 assertSame(one, cache.getUnchecked(key)); 1078 stats = cache.stats(); 1079 assertEquals(1, stats.missCount()); 1080 assertEquals(1, stats.loadSuccessCount()); 1081 assertEquals(0, stats.loadExceptionCount()); 1082 assertEquals(0, stats.hitCount()); 1083 1084 ticker.advance(1, MILLISECONDS); 1085 assertSame(one, cache.getUnchecked(key)); 1086 stats = cache.stats(); 1087 assertEquals(1, stats.missCount()); 1088 assertEquals(1, stats.loadSuccessCount()); 1089 assertEquals(0, stats.loadExceptionCount()); 1090 assertEquals(1, stats.hitCount()); 1091 1092 ticker.advance(1, MILLISECONDS); 1093 assertSame(one, cache.getUnchecked(key)); 1094 // refreshed 1095 stats = cache.stats(); 1096 assertEquals(1, stats.missCount()); 1097 assertEquals(1, stats.loadSuccessCount()); 1098 assertEquals(1, stats.loadExceptionCount()); 1099 assertEquals(2, stats.hitCount()); 1100 1101 ticker.advance(1, MILLISECONDS); 1102 assertSame(one, cache.getUnchecked(key)); 1103 stats = cache.stats(); 1104 assertEquals(1, stats.missCount()); 1105 assertEquals(1, stats.loadSuccessCount()); 1106 assertEquals(2, stats.loadExceptionCount()); 1107 assertEquals(3, stats.hitCount()); 1108 } 1109 testBulkLoadError()1110 public void testBulkLoadError() throws ExecutionException { 1111 Error e = new Error(); 1112 CacheLoader<Object, Object> loader = errorLoader(e); 1113 LoadingCache<Object, Object> cache = 1114 CacheBuilder.newBuilder().recordStats().build(bulkLoader(loader)); 1115 CacheStats stats = cache.stats(); 1116 assertEquals(0, stats.missCount()); 1117 assertEquals(0, stats.loadSuccessCount()); 1118 assertEquals(0, stats.loadExceptionCount()); 1119 assertEquals(0, stats.hitCount()); 1120 1121 try { 1122 cache.getAll(asList(new Object())); 1123 fail(); 1124 } catch (ExecutionError expected) { 1125 assertThat(expected).hasCauseThat().isSameInstanceAs(e); 1126 } 1127 stats = cache.stats(); 1128 assertEquals(1, stats.missCount()); 1129 assertEquals(0, stats.loadSuccessCount()); 1130 assertEquals(1, stats.loadExceptionCount()); 1131 assertEquals(0, stats.hitCount()); 1132 } 1133 testLoadCheckedException()1134 public void testLoadCheckedException() { 1135 Exception e = new Exception(); 1136 CacheLoader<Object, Object> loader = exceptionLoader(e); 1137 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader); 1138 CacheStats stats = cache.stats(); 1139 assertEquals(0, stats.missCount()); 1140 assertEquals(0, stats.loadSuccessCount()); 1141 assertEquals(0, stats.loadExceptionCount()); 1142 assertEquals(0, stats.hitCount()); 1143 1144 try { 1145 cache.get(new Object()); 1146 fail(); 1147 } catch (ExecutionException expected) { 1148 assertThat(expected).hasCauseThat().isSameInstanceAs(e); 1149 } 1150 stats = cache.stats(); 1151 assertEquals(1, stats.missCount()); 1152 assertEquals(0, stats.loadSuccessCount()); 1153 assertEquals(1, stats.loadExceptionCount()); 1154 assertEquals(0, stats.hitCount()); 1155 1156 try { 1157 cache.getUnchecked(new Object()); 1158 fail(); 1159 } catch (UncheckedExecutionException expected) { 1160 assertThat(expected).hasCauseThat().isSameInstanceAs(e); 1161 } 1162 stats = cache.stats(); 1163 assertEquals(2, stats.missCount()); 1164 assertEquals(0, stats.loadSuccessCount()); 1165 assertEquals(2, stats.loadExceptionCount()); 1166 assertEquals(0, stats.hitCount()); 1167 1168 cache.refresh(new Object()); 1169 checkLoggedCause(e); 1170 stats = cache.stats(); 1171 assertEquals(2, stats.missCount()); 1172 assertEquals(0, stats.loadSuccessCount()); 1173 assertEquals(3, stats.loadExceptionCount()); 1174 assertEquals(0, stats.hitCount()); 1175 1176 Exception callableException = new Exception(); 1177 try { 1178 cache.get(new Object(), throwing(callableException)); 1179 fail(); 1180 } catch (ExecutionException expected) { 1181 assertThat(expected).hasCauseThat().isSameInstanceAs(callableException); 1182 } 1183 stats = cache.stats(); 1184 assertEquals(3, stats.missCount()); 1185 assertEquals(0, stats.loadSuccessCount()); 1186 assertEquals(4, stats.loadExceptionCount()); 1187 assertEquals(0, stats.hitCount()); 1188 1189 try { 1190 cache.getAll(asList(new Object())); 1191 fail(); 1192 } catch (ExecutionException expected) { 1193 assertThat(expected).hasCauseThat().isSameInstanceAs(e); 1194 } 1195 stats = cache.stats(); 1196 assertEquals(4, stats.missCount()); 1197 assertEquals(0, stats.loadSuccessCount()); 1198 assertEquals(5, stats.loadExceptionCount()); 1199 assertEquals(0, stats.hitCount()); 1200 } 1201 testLoadInterruptedException()1202 public void testLoadInterruptedException() { 1203 Exception e = new InterruptedException(); 1204 CacheLoader<Object, Object> loader = exceptionLoader(e); 1205 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader); 1206 CacheStats stats = cache.stats(); 1207 assertEquals(0, stats.missCount()); 1208 assertEquals(0, stats.loadSuccessCount()); 1209 assertEquals(0, stats.loadExceptionCount()); 1210 assertEquals(0, stats.hitCount()); 1211 1212 // Sanity check: 1213 assertFalse(currentThread().interrupted()); 1214 1215 try { 1216 cache.get(new Object()); 1217 fail(); 1218 } catch (ExecutionException expected) { 1219 assertThat(expected).hasCauseThat().isSameInstanceAs(e); 1220 } 1221 assertTrue(currentThread().interrupted()); 1222 stats = cache.stats(); 1223 assertEquals(1, stats.missCount()); 1224 assertEquals(0, stats.loadSuccessCount()); 1225 assertEquals(1, stats.loadExceptionCount()); 1226 assertEquals(0, stats.hitCount()); 1227 1228 try { 1229 cache.getUnchecked(new Object()); 1230 fail(); 1231 } catch (UncheckedExecutionException expected) { 1232 assertThat(expected).hasCauseThat().isSameInstanceAs(e); 1233 } 1234 assertTrue(currentThread().interrupted()); 1235 stats = cache.stats(); 1236 assertEquals(2, stats.missCount()); 1237 assertEquals(0, stats.loadSuccessCount()); 1238 assertEquals(2, stats.loadExceptionCount()); 1239 assertEquals(0, stats.hitCount()); 1240 1241 cache.refresh(new Object()); 1242 assertTrue(currentThread().interrupted()); 1243 checkLoggedCause(e); 1244 stats = cache.stats(); 1245 assertEquals(2, stats.missCount()); 1246 assertEquals(0, stats.loadSuccessCount()); 1247 assertEquals(3, stats.loadExceptionCount()); 1248 assertEquals(0, stats.hitCount()); 1249 1250 Exception callableException = new InterruptedException(); 1251 try { 1252 cache.get(new Object(), throwing(callableException)); 1253 fail(); 1254 } catch (ExecutionException expected) { 1255 assertThat(expected).hasCauseThat().isSameInstanceAs(callableException); 1256 } 1257 assertTrue(currentThread().interrupted()); 1258 stats = cache.stats(); 1259 assertEquals(3, stats.missCount()); 1260 assertEquals(0, stats.loadSuccessCount()); 1261 assertEquals(4, stats.loadExceptionCount()); 1262 assertEquals(0, stats.hitCount()); 1263 1264 try { 1265 cache.getAll(asList(new Object())); 1266 fail(); 1267 } catch (ExecutionException expected) { 1268 assertThat(expected).hasCauseThat().isSameInstanceAs(e); 1269 } 1270 assertTrue(currentThread().interrupted()); 1271 stats = cache.stats(); 1272 assertEquals(4, stats.missCount()); 1273 assertEquals(0, stats.loadSuccessCount()); 1274 assertEquals(5, stats.loadExceptionCount()); 1275 assertEquals(0, stats.hitCount()); 1276 } 1277 testReloadCheckedException()1278 public void testReloadCheckedException() { 1279 final Object one = new Object(); 1280 final Exception e = new Exception(); 1281 CacheLoader<Object, Object> loader = 1282 new CacheLoader<Object, Object>() { 1283 @Override 1284 public Object load(Object key) { 1285 return one; 1286 } 1287 1288 @Override 1289 public ListenableFuture<Object> reload(Object key, Object oldValue) throws Exception { 1290 throw e; 1291 } 1292 }; 1293 1294 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader); 1295 Object key = new Object(); 1296 CacheStats stats = cache.stats(); 1297 assertEquals(0, stats.missCount()); 1298 assertEquals(0, stats.loadSuccessCount()); 1299 assertEquals(0, stats.loadExceptionCount()); 1300 assertEquals(0, stats.hitCount()); 1301 1302 assertSame(one, cache.getUnchecked(key)); 1303 stats = cache.stats(); 1304 assertEquals(1, stats.missCount()); 1305 assertEquals(1, stats.loadSuccessCount()); 1306 assertEquals(0, stats.loadExceptionCount()); 1307 assertEquals(0, stats.hitCount()); 1308 1309 cache.refresh(key); 1310 checkLoggedCause(e); 1311 stats = cache.stats(); 1312 assertEquals(1, stats.missCount()); 1313 assertEquals(1, stats.loadSuccessCount()); 1314 assertEquals(1, stats.loadExceptionCount()); 1315 assertEquals(0, stats.hitCount()); 1316 1317 assertSame(one, cache.getUnchecked(key)); 1318 stats = cache.stats(); 1319 assertEquals(1, stats.missCount()); 1320 assertEquals(1, stats.loadSuccessCount()); 1321 assertEquals(1, stats.loadExceptionCount()); 1322 assertEquals(1, stats.hitCount()); 1323 } 1324 testReloadFutureCheckedException()1325 public void testReloadFutureCheckedException() { 1326 final Object one = new Object(); 1327 final Exception e = new Exception(); 1328 CacheLoader<Object, Object> loader = 1329 new CacheLoader<Object, Object>() { 1330 @Override 1331 public Object load(Object key) { 1332 return one; 1333 } 1334 1335 @Override 1336 public ListenableFuture<Object> reload(Object key, Object oldValue) { 1337 return Futures.immediateFailedFuture(e); 1338 } 1339 }; 1340 1341 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader); 1342 Object key = new Object(); 1343 CacheStats stats = cache.stats(); 1344 assertEquals(0, stats.missCount()); 1345 assertEquals(0, stats.loadSuccessCount()); 1346 assertEquals(0, stats.loadExceptionCount()); 1347 assertEquals(0, stats.hitCount()); 1348 1349 assertSame(one, cache.getUnchecked(key)); 1350 stats = cache.stats(); 1351 assertEquals(1, stats.missCount()); 1352 assertEquals(1, stats.loadSuccessCount()); 1353 assertEquals(0, stats.loadExceptionCount()); 1354 assertEquals(0, stats.hitCount()); 1355 1356 cache.refresh(key); 1357 checkLoggedCause(e); 1358 stats = cache.stats(); 1359 assertEquals(1, stats.missCount()); 1360 assertEquals(1, stats.loadSuccessCount()); 1361 assertEquals(1, stats.loadExceptionCount()); 1362 assertEquals(0, stats.hitCount()); 1363 1364 assertSame(one, cache.getUnchecked(key)); 1365 stats = cache.stats(); 1366 assertEquals(1, stats.missCount()); 1367 assertEquals(1, stats.loadSuccessCount()); 1368 assertEquals(1, stats.loadExceptionCount()); 1369 assertEquals(1, stats.hitCount()); 1370 } 1371 testRefreshCheckedException()1372 public void testRefreshCheckedException() { 1373 final Object one = new Object(); 1374 final Exception e = new Exception(); 1375 FakeTicker ticker = new FakeTicker(); 1376 CacheLoader<Object, Object> loader = 1377 new CacheLoader<Object, Object>() { 1378 @Override 1379 public Object load(Object key) { 1380 return one; 1381 } 1382 1383 @Override 1384 public ListenableFuture<Object> reload(Object key, Object oldValue) { 1385 return Futures.immediateFailedFuture(e); 1386 } 1387 }; 1388 1389 LoadingCache<Object, Object> cache = 1390 CacheBuilder.newBuilder() 1391 .recordStats() 1392 .ticker(ticker) 1393 .refreshAfterWrite(1, MILLISECONDS) 1394 .build(loader); 1395 Object key = new Object(); 1396 CacheStats stats = cache.stats(); 1397 assertEquals(0, stats.missCount()); 1398 assertEquals(0, stats.loadSuccessCount()); 1399 assertEquals(0, stats.loadExceptionCount()); 1400 assertEquals(0, stats.hitCount()); 1401 1402 assertSame(one, cache.getUnchecked(key)); 1403 stats = cache.stats(); 1404 assertEquals(1, stats.missCount()); 1405 assertEquals(1, stats.loadSuccessCount()); 1406 assertEquals(0, stats.loadExceptionCount()); 1407 assertEquals(0, stats.hitCount()); 1408 1409 ticker.advance(1, MILLISECONDS); 1410 assertSame(one, cache.getUnchecked(key)); 1411 stats = cache.stats(); 1412 assertEquals(1, stats.missCount()); 1413 assertEquals(1, stats.loadSuccessCount()); 1414 assertEquals(0, stats.loadExceptionCount()); 1415 assertEquals(1, stats.hitCount()); 1416 1417 ticker.advance(1, MILLISECONDS); 1418 assertSame(one, cache.getUnchecked(key)); 1419 // refreshed 1420 stats = cache.stats(); 1421 assertEquals(1, stats.missCount()); 1422 assertEquals(1, stats.loadSuccessCount()); 1423 assertEquals(1, stats.loadExceptionCount()); 1424 assertEquals(2, stats.hitCount()); 1425 1426 ticker.advance(1, MILLISECONDS); 1427 assertSame(one, cache.getUnchecked(key)); 1428 stats = cache.stats(); 1429 assertEquals(1, stats.missCount()); 1430 assertEquals(1, stats.loadSuccessCount()); 1431 assertEquals(2, stats.loadExceptionCount()); 1432 assertEquals(3, stats.hitCount()); 1433 } 1434 testBulkLoadCheckedException()1435 public void testBulkLoadCheckedException() { 1436 Exception e = new Exception(); 1437 CacheLoader<Object, Object> loader = exceptionLoader(e); 1438 LoadingCache<Object, Object> cache = 1439 CacheBuilder.newBuilder().recordStats().build(bulkLoader(loader)); 1440 CacheStats stats = cache.stats(); 1441 assertEquals(0, stats.missCount()); 1442 assertEquals(0, stats.loadSuccessCount()); 1443 assertEquals(0, stats.loadExceptionCount()); 1444 assertEquals(0, stats.hitCount()); 1445 1446 try { 1447 cache.getAll(asList(new Object())); 1448 fail(); 1449 } catch (ExecutionException expected) { 1450 assertThat(expected).hasCauseThat().isSameInstanceAs(e); 1451 } 1452 stats = cache.stats(); 1453 assertEquals(1, stats.missCount()); 1454 assertEquals(0, stats.loadSuccessCount()); 1455 assertEquals(1, stats.loadExceptionCount()); 1456 assertEquals(0, stats.hitCount()); 1457 } 1458 testBulkLoadInterruptedException()1459 public void testBulkLoadInterruptedException() { 1460 Exception e = new InterruptedException(); 1461 CacheLoader<Object, Object> loader = exceptionLoader(e); 1462 LoadingCache<Object, Object> cache = 1463 CacheBuilder.newBuilder().recordStats().build(bulkLoader(loader)); 1464 CacheStats stats = cache.stats(); 1465 assertEquals(0, stats.missCount()); 1466 assertEquals(0, stats.loadSuccessCount()); 1467 assertEquals(0, stats.loadExceptionCount()); 1468 assertEquals(0, stats.hitCount()); 1469 1470 try { 1471 cache.getAll(asList(new Object())); 1472 fail(); 1473 } catch (ExecutionException expected) { 1474 assertThat(expected).hasCauseThat().isSameInstanceAs(e); 1475 } 1476 assertTrue(currentThread().interrupted()); 1477 stats = cache.stats(); 1478 assertEquals(1, stats.missCount()); 1479 assertEquals(0, stats.loadSuccessCount()); 1480 assertEquals(1, stats.loadExceptionCount()); 1481 assertEquals(0, stats.hitCount()); 1482 } 1483 testLoadUncheckedException()1484 public void testLoadUncheckedException() throws ExecutionException { 1485 Exception e = new RuntimeException(); 1486 CacheLoader<Object, Object> loader = exceptionLoader(e); 1487 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader); 1488 CacheStats stats = cache.stats(); 1489 assertEquals(0, stats.missCount()); 1490 assertEquals(0, stats.loadSuccessCount()); 1491 assertEquals(0, stats.loadExceptionCount()); 1492 assertEquals(0, stats.hitCount()); 1493 1494 try { 1495 cache.get(new Object()); 1496 fail(); 1497 } catch (UncheckedExecutionException expected) { 1498 assertThat(expected).hasCauseThat().isSameInstanceAs(e); 1499 } 1500 stats = cache.stats(); 1501 assertEquals(1, stats.missCount()); 1502 assertEquals(0, stats.loadSuccessCount()); 1503 assertEquals(1, stats.loadExceptionCount()); 1504 assertEquals(0, stats.hitCount()); 1505 1506 try { 1507 cache.getUnchecked(new Object()); 1508 fail(); 1509 } catch (UncheckedExecutionException expected) { 1510 assertThat(expected).hasCauseThat().isSameInstanceAs(e); 1511 } 1512 stats = cache.stats(); 1513 assertEquals(2, stats.missCount()); 1514 assertEquals(0, stats.loadSuccessCount()); 1515 assertEquals(2, stats.loadExceptionCount()); 1516 assertEquals(0, stats.hitCount()); 1517 1518 cache.refresh(new Object()); 1519 checkLoggedCause(e); 1520 stats = cache.stats(); 1521 assertEquals(2, stats.missCount()); 1522 assertEquals(0, stats.loadSuccessCount()); 1523 assertEquals(3, stats.loadExceptionCount()); 1524 assertEquals(0, stats.hitCount()); 1525 1526 Exception callableException = new RuntimeException(); 1527 try { 1528 cache.get(new Object(), throwing(callableException)); 1529 fail(); 1530 } catch (UncheckedExecutionException expected) { 1531 assertThat(expected).hasCauseThat().isSameInstanceAs(callableException); 1532 } 1533 stats = cache.stats(); 1534 assertEquals(3, stats.missCount()); 1535 assertEquals(0, stats.loadSuccessCount()); 1536 assertEquals(4, stats.loadExceptionCount()); 1537 assertEquals(0, stats.hitCount()); 1538 1539 try { 1540 cache.getAll(asList(new Object())); 1541 fail(); 1542 } catch (UncheckedExecutionException expected) { 1543 assertThat(expected).hasCauseThat().isSameInstanceAs(e); 1544 } 1545 stats = cache.stats(); 1546 assertEquals(4, stats.missCount()); 1547 assertEquals(0, stats.loadSuccessCount()); 1548 assertEquals(5, stats.loadExceptionCount()); 1549 assertEquals(0, stats.hitCount()); 1550 } 1551 testReloadUncheckedException()1552 public void testReloadUncheckedException() throws ExecutionException { 1553 final Object one = new Object(); 1554 final Exception e = new RuntimeException(); 1555 CacheLoader<Object, Object> loader = 1556 new CacheLoader<Object, Object>() { 1557 @Override 1558 public Object load(Object key) { 1559 return one; 1560 } 1561 1562 @Override 1563 public ListenableFuture<Object> reload(Object key, Object oldValue) throws Exception { 1564 throw e; 1565 } 1566 }; 1567 1568 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader); 1569 Object key = new Object(); 1570 CacheStats stats = cache.stats(); 1571 assertEquals(0, stats.missCount()); 1572 assertEquals(0, stats.loadSuccessCount()); 1573 assertEquals(0, stats.loadExceptionCount()); 1574 assertEquals(0, stats.hitCount()); 1575 1576 assertSame(one, cache.getUnchecked(key)); 1577 stats = cache.stats(); 1578 assertEquals(1, stats.missCount()); 1579 assertEquals(1, stats.loadSuccessCount()); 1580 assertEquals(0, stats.loadExceptionCount()); 1581 assertEquals(0, stats.hitCount()); 1582 1583 cache.refresh(key); 1584 checkLoggedCause(e); 1585 stats = cache.stats(); 1586 assertEquals(1, stats.missCount()); 1587 assertEquals(1, stats.loadSuccessCount()); 1588 assertEquals(1, stats.loadExceptionCount()); 1589 assertEquals(0, stats.hitCount()); 1590 1591 assertSame(one, cache.getUnchecked(key)); 1592 stats = cache.stats(); 1593 assertEquals(1, stats.missCount()); 1594 assertEquals(1, stats.loadSuccessCount()); 1595 assertEquals(1, stats.loadExceptionCount()); 1596 assertEquals(1, stats.hitCount()); 1597 } 1598 testReloadFutureUncheckedException()1599 public void testReloadFutureUncheckedException() throws ExecutionException { 1600 final Object one = new Object(); 1601 final Exception e = new RuntimeException(); 1602 CacheLoader<Object, Object> loader = 1603 new CacheLoader<Object, Object>() { 1604 @Override 1605 public Object load(Object key) { 1606 return one; 1607 } 1608 1609 @Override 1610 public ListenableFuture<Object> reload(Object key, Object oldValue) { 1611 return Futures.immediateFailedFuture(e); 1612 } 1613 }; 1614 1615 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader); 1616 Object key = new Object(); 1617 CacheStats stats = cache.stats(); 1618 assertEquals(0, stats.missCount()); 1619 assertEquals(0, stats.loadSuccessCount()); 1620 assertEquals(0, stats.loadExceptionCount()); 1621 assertEquals(0, stats.hitCount()); 1622 1623 assertSame(one, cache.getUnchecked(key)); 1624 stats = cache.stats(); 1625 assertEquals(1, stats.missCount()); 1626 assertEquals(1, stats.loadSuccessCount()); 1627 assertEquals(0, stats.loadExceptionCount()); 1628 assertEquals(0, stats.hitCount()); 1629 1630 cache.refresh(key); 1631 checkLoggedCause(e); 1632 stats = cache.stats(); 1633 assertEquals(1, stats.missCount()); 1634 assertEquals(1, stats.loadSuccessCount()); 1635 assertEquals(1, stats.loadExceptionCount()); 1636 assertEquals(0, stats.hitCount()); 1637 1638 assertSame(one, cache.getUnchecked(key)); 1639 stats = cache.stats(); 1640 assertEquals(1, stats.missCount()); 1641 assertEquals(1, stats.loadSuccessCount()); 1642 assertEquals(1, stats.loadExceptionCount()); 1643 assertEquals(1, stats.hitCount()); 1644 } 1645 testRefreshUncheckedException()1646 public void testRefreshUncheckedException() { 1647 final Object one = new Object(); 1648 final Exception e = new RuntimeException(); 1649 FakeTicker ticker = new FakeTicker(); 1650 CacheLoader<Object, Object> loader = 1651 new CacheLoader<Object, Object>() { 1652 @Override 1653 public Object load(Object key) { 1654 return one; 1655 } 1656 1657 @Override 1658 public ListenableFuture<Object> reload(Object key, Object oldValue) { 1659 return Futures.immediateFailedFuture(e); 1660 } 1661 }; 1662 1663 LoadingCache<Object, Object> cache = 1664 CacheBuilder.newBuilder() 1665 .recordStats() 1666 .ticker(ticker) 1667 .refreshAfterWrite(1, MILLISECONDS) 1668 .build(loader); 1669 Object key = new Object(); 1670 CacheStats stats = cache.stats(); 1671 assertEquals(0, stats.missCount()); 1672 assertEquals(0, stats.loadSuccessCount()); 1673 assertEquals(0, stats.loadExceptionCount()); 1674 assertEquals(0, stats.hitCount()); 1675 1676 assertSame(one, cache.getUnchecked(key)); 1677 stats = cache.stats(); 1678 assertEquals(1, stats.missCount()); 1679 assertEquals(1, stats.loadSuccessCount()); 1680 assertEquals(0, stats.loadExceptionCount()); 1681 assertEquals(0, stats.hitCount()); 1682 1683 ticker.advance(1, MILLISECONDS); 1684 assertSame(one, cache.getUnchecked(key)); 1685 stats = cache.stats(); 1686 assertEquals(1, stats.missCount()); 1687 assertEquals(1, stats.loadSuccessCount()); 1688 assertEquals(0, stats.loadExceptionCount()); 1689 assertEquals(1, stats.hitCount()); 1690 1691 ticker.advance(1, MILLISECONDS); 1692 assertSame(one, cache.getUnchecked(key)); 1693 // refreshed 1694 stats = cache.stats(); 1695 assertEquals(1, stats.missCount()); 1696 assertEquals(1, stats.loadSuccessCount()); 1697 assertEquals(1, stats.loadExceptionCount()); 1698 assertEquals(2, stats.hitCount()); 1699 1700 ticker.advance(1, MILLISECONDS); 1701 assertSame(one, cache.getUnchecked(key)); 1702 stats = cache.stats(); 1703 assertEquals(1, stats.missCount()); 1704 assertEquals(1, stats.loadSuccessCount()); 1705 assertEquals(2, stats.loadExceptionCount()); 1706 assertEquals(3, stats.hitCount()); 1707 } 1708 testBulkLoadUncheckedException()1709 public void testBulkLoadUncheckedException() throws ExecutionException { 1710 Exception e = new RuntimeException(); 1711 CacheLoader<Object, Object> loader = exceptionLoader(e); 1712 LoadingCache<Object, Object> cache = 1713 CacheBuilder.newBuilder().recordStats().build(bulkLoader(loader)); 1714 CacheStats stats = cache.stats(); 1715 assertEquals(0, stats.missCount()); 1716 assertEquals(0, stats.loadSuccessCount()); 1717 assertEquals(0, stats.loadExceptionCount()); 1718 assertEquals(0, stats.hitCount()); 1719 1720 try { 1721 cache.getAll(asList(new Object())); 1722 fail(); 1723 } catch (UncheckedExecutionException expected) { 1724 assertThat(expected).hasCauseThat().isSameInstanceAs(e); 1725 } 1726 stats = cache.stats(); 1727 assertEquals(1, stats.missCount()); 1728 assertEquals(0, stats.loadSuccessCount()); 1729 assertEquals(1, stats.loadExceptionCount()); 1730 assertEquals(0, stats.hitCount()); 1731 } 1732 testReloadAfterFailure()1733 public void testReloadAfterFailure() throws ExecutionException { 1734 final AtomicInteger count = new AtomicInteger(); 1735 final Exception e = new IllegalStateException("exception to trigger failure on first load()"); 1736 CacheLoader<Integer, String> failOnceFunction = 1737 new CacheLoader<Integer, String>() { 1738 1739 @Override 1740 public String load(Integer key) throws Exception { 1741 if (count.getAndIncrement() == 0) { 1742 throw e; 1743 } 1744 return key.toString(); 1745 } 1746 }; 1747 CountingRemovalListener<Integer, String> removalListener = countingRemovalListener(); 1748 LoadingCache<Integer, String> cache = 1749 CacheBuilder.newBuilder().removalListener(removalListener).build(failOnceFunction); 1750 1751 try { 1752 cache.getUnchecked(1); 1753 fail(); 1754 } catch (UncheckedExecutionException ue) { 1755 assertThat(ue).hasCauseThat().isSameInstanceAs(e); 1756 } 1757 1758 assertEquals("1", cache.getUnchecked(1)); 1759 assertEquals(0, removalListener.getCount()); 1760 1761 count.set(0); 1762 cache.refresh(2); 1763 checkLoggedCause(e); 1764 1765 assertEquals("2", cache.getUnchecked(2)); 1766 assertEquals(0, removalListener.getCount()); 1767 } 1768 testReloadAfterValueReclamation()1769 public void testReloadAfterValueReclamation() throws InterruptedException, ExecutionException { 1770 CountingLoader countingLoader = new CountingLoader(); 1771 LoadingCache<Object, Object> cache = 1772 CacheBuilder.newBuilder().weakValues().build(countingLoader); 1773 ConcurrentMap<Object, Object> map = cache.asMap(); 1774 1775 int iterations = 10; 1776 WeakReference<Object> ref = new WeakReference<>(null); 1777 int expectedComputations = 0; 1778 for (int i = 0; i < iterations; i++) { 1779 // The entry should get garbage collected and recomputed. 1780 Object oldValue = ref.get(); 1781 if (oldValue == null) { 1782 expectedComputations++; 1783 } 1784 ref = new WeakReference<>(cache.getUnchecked(1)); 1785 oldValue = null; 1786 Thread.sleep(i); 1787 System.gc(); 1788 } 1789 assertEquals(expectedComputations, countingLoader.getCount()); 1790 1791 for (int i = 0; i < iterations; i++) { 1792 // The entry should get garbage collected and recomputed. 1793 Object oldValue = ref.get(); 1794 if (oldValue == null) { 1795 expectedComputations++; 1796 } 1797 cache.refresh(1); 1798 checkNothingLogged(); 1799 ref = new WeakReference<>(map.get(1)); 1800 oldValue = null; 1801 Thread.sleep(i); 1802 System.gc(); 1803 } 1804 assertEquals(expectedComputations, countingLoader.getCount()); 1805 } 1806 testReloadAfterSimulatedValueReclamation()1807 public void testReloadAfterSimulatedValueReclamation() throws ExecutionException { 1808 CountingLoader countingLoader = new CountingLoader(); 1809 LoadingCache<Object, Object> cache = 1810 CacheBuilder.newBuilder().concurrencyLevel(1).weakValues().build(countingLoader); 1811 1812 Object key = new Object(); 1813 assertNotNull(cache.getUnchecked(key)); 1814 1815 CacheTesting.simulateValueReclamation(cache, key); 1816 1817 // this blocks if computation can't deal with partially-collected values 1818 assertNotNull(cache.getUnchecked(key)); 1819 assertEquals(1, cache.size()); 1820 assertEquals(2, countingLoader.getCount()); 1821 1822 CacheTesting.simulateValueReclamation(cache, key); 1823 cache.refresh(key); 1824 checkNothingLogged(); 1825 assertEquals(1, cache.size()); 1826 assertEquals(3, countingLoader.getCount()); 1827 } 1828 testReloadAfterSimulatedKeyReclamation()1829 public void testReloadAfterSimulatedKeyReclamation() throws ExecutionException { 1830 CountingLoader countingLoader = new CountingLoader(); 1831 LoadingCache<Object, Object> cache = 1832 CacheBuilder.newBuilder().concurrencyLevel(1).weakKeys().build(countingLoader); 1833 1834 Object key = new Object(); 1835 assertNotNull(cache.getUnchecked(key)); 1836 assertEquals(1, cache.size()); 1837 1838 CacheTesting.simulateKeyReclamation(cache, key); 1839 1840 // this blocks if computation can't deal with partially-collected values 1841 assertNotNull(cache.getUnchecked(key)); 1842 assertEquals(2, countingLoader.getCount()); 1843 1844 CacheTesting.simulateKeyReclamation(cache, key); 1845 cache.refresh(key); 1846 checkNothingLogged(); 1847 assertEquals(3, countingLoader.getCount()); 1848 } 1849 1850 /** 1851 * Make sure LoadingCache correctly wraps ExecutionExceptions and UncheckedExecutionExceptions. 1852 */ testLoadingExceptionWithCause()1853 public void testLoadingExceptionWithCause() { 1854 final Exception cause = new Exception(); 1855 final UncheckedExecutionException uee = new UncheckedExecutionException(cause); 1856 final ExecutionException ee = new ExecutionException(cause); 1857 1858 LoadingCache<Object, Object> cacheUnchecked = 1859 CacheBuilder.newBuilder().build(exceptionLoader(uee)); 1860 LoadingCache<Object, Object> cacheChecked = 1861 CacheBuilder.newBuilder().build(exceptionLoader(ee)); 1862 1863 try { 1864 cacheUnchecked.get(new Object()); 1865 fail(); 1866 } catch (ExecutionException e) { 1867 fail(); 1868 } catch (UncheckedExecutionException caughtEe) { 1869 assertThat(caughtEe).hasCauseThat().isSameInstanceAs(uee); 1870 } 1871 1872 try { 1873 cacheUnchecked.getUnchecked(new Object()); 1874 fail(); 1875 } catch (UncheckedExecutionException caughtUee) { 1876 assertThat(caughtUee).hasCauseThat().isSameInstanceAs(uee); 1877 } 1878 1879 cacheUnchecked.refresh(new Object()); 1880 checkLoggedCause(uee); 1881 1882 try { 1883 cacheUnchecked.getAll(asList(new Object())); 1884 fail(); 1885 } catch (ExecutionException e) { 1886 fail(); 1887 } catch (UncheckedExecutionException caughtEe) { 1888 assertThat(caughtEe).hasCauseThat().isSameInstanceAs(uee); 1889 } 1890 1891 try { 1892 cacheChecked.get(new Object()); 1893 fail(); 1894 } catch (ExecutionException caughtEe) { 1895 assertThat(caughtEe).hasCauseThat().isSameInstanceAs(ee); 1896 } 1897 1898 try { 1899 cacheChecked.getUnchecked(new Object()); 1900 fail(); 1901 } catch (UncheckedExecutionException caughtUee) { 1902 assertThat(caughtUee).hasCauseThat().isSameInstanceAs(ee); 1903 } 1904 1905 cacheChecked.refresh(new Object()); 1906 checkLoggedCause(ee); 1907 1908 try { 1909 cacheChecked.getAll(asList(new Object())); 1910 fail(); 1911 } catch (ExecutionException caughtEe) { 1912 assertThat(caughtEe).hasCauseThat().isSameInstanceAs(ee); 1913 } 1914 } 1915 testBulkLoadingExceptionWithCause()1916 public void testBulkLoadingExceptionWithCause() { 1917 final Exception cause = new Exception(); 1918 final UncheckedExecutionException uee = new UncheckedExecutionException(cause); 1919 final ExecutionException ee = new ExecutionException(cause); 1920 1921 LoadingCache<Object, Object> cacheUnchecked = 1922 CacheBuilder.newBuilder().build(bulkLoader(exceptionLoader(uee))); 1923 LoadingCache<Object, Object> cacheChecked = 1924 CacheBuilder.newBuilder().build(bulkLoader(exceptionLoader(ee))); 1925 1926 try { 1927 cacheUnchecked.getAll(asList(new Object())); 1928 fail(); 1929 } catch (ExecutionException e) { 1930 fail(); 1931 } catch (UncheckedExecutionException caughtEe) { 1932 assertThat(caughtEe).hasCauseThat().isSameInstanceAs(uee); 1933 } 1934 1935 try { 1936 cacheChecked.getAll(asList(new Object())); 1937 fail(); 1938 } catch (ExecutionException caughtEe) { 1939 assertThat(caughtEe).hasCauseThat().isSameInstanceAs(ee); 1940 } 1941 } 1942 testConcurrentLoading()1943 public void testConcurrentLoading() throws InterruptedException { 1944 testConcurrentLoading(CacheBuilder.newBuilder()); 1945 } 1946 testConcurrentLoading(CacheBuilder<Object, Object> builder)1947 private static void testConcurrentLoading(CacheBuilder<Object, Object> builder) 1948 throws InterruptedException { 1949 testConcurrentLoadingDefault(builder); 1950 testConcurrentLoadingNull(builder); 1951 testConcurrentLoadingUncheckedException(builder); 1952 testConcurrentLoadingCheckedException(builder); 1953 } 1954 testConcurrentExpirationLoading()1955 public void testConcurrentExpirationLoading() throws InterruptedException { 1956 testConcurrentLoading(CacheBuilder.newBuilder().expireAfterWrite(10, TimeUnit.SECONDS)); 1957 } 1958 1959 /** 1960 * On a successful concurrent computation, only one thread does the work, but all the threads get 1961 * the same result. 1962 */ testConcurrentLoadingDefault(CacheBuilder<Object, Object> builder)1963 private static void testConcurrentLoadingDefault(CacheBuilder<Object, Object> builder) 1964 throws InterruptedException { 1965 1966 int count = 10; 1967 final AtomicInteger callCount = new AtomicInteger(); 1968 final CountDownLatch startSignal = new CountDownLatch(count + 1); 1969 final Object result = new Object(); 1970 1971 LoadingCache<String, Object> cache = 1972 builder.build( 1973 new CacheLoader<String, Object>() { 1974 @Override 1975 public Object load(String key) throws InterruptedException { 1976 callCount.incrementAndGet(); 1977 startSignal.await(); 1978 return result; 1979 } 1980 }); 1981 1982 List<Object> resultArray = doConcurrentGet(cache, "bar", count, startSignal); 1983 1984 assertEquals(1, callCount.get()); 1985 for (int i = 0; i < count; i++) { 1986 assertSame("result(" + i + ") didn't match expected", result, resultArray.get(i)); 1987 } 1988 } 1989 1990 /** 1991 * On a concurrent computation that returns null, all threads should get an 1992 * InvalidCacheLoadException, with the loader only called once. The result should not be cached (a 1993 * later request should call the loader again). 1994 */ testConcurrentLoadingNull(CacheBuilder<Object, Object> builder)1995 private static void testConcurrentLoadingNull(CacheBuilder<Object, Object> builder) 1996 throws InterruptedException { 1997 1998 int count = 10; 1999 final AtomicInteger callCount = new AtomicInteger(); 2000 final CountDownLatch startSignal = new CountDownLatch(count + 1); 2001 2002 LoadingCache<String, String> cache = 2003 builder.build( 2004 new CacheLoader<String, String>() { 2005 @Override 2006 public String load(String key) throws InterruptedException { 2007 callCount.incrementAndGet(); 2008 startSignal.await(); 2009 return null; 2010 } 2011 }); 2012 2013 List<Object> result = doConcurrentGet(cache, "bar", count, startSignal); 2014 2015 assertEquals(1, callCount.get()); 2016 for (int i = 0; i < count; i++) { 2017 assertThat(result.get(i)).isInstanceOf(InvalidCacheLoadException.class); 2018 } 2019 2020 // subsequent calls should call the loader again, not get the old exception 2021 try { 2022 cache.getUnchecked("bar"); 2023 fail(); 2024 } catch (InvalidCacheLoadException expected) { 2025 } 2026 assertEquals(2, callCount.get()); 2027 } 2028 2029 /** 2030 * On a concurrent computation that throws an unchecked exception, all threads should get the 2031 * (wrapped) exception, with the loader called only once. The result should not be cached (a later 2032 * request should call the loader again). 2033 */ testConcurrentLoadingUncheckedException(CacheBuilder<Object, Object> builder)2034 private static void testConcurrentLoadingUncheckedException(CacheBuilder<Object, Object> builder) 2035 throws InterruptedException { 2036 2037 int count = 10; 2038 final AtomicInteger callCount = new AtomicInteger(); 2039 final CountDownLatch startSignal = new CountDownLatch(count + 1); 2040 final RuntimeException e = new RuntimeException(); 2041 2042 LoadingCache<String, String> cache = 2043 builder.build( 2044 new CacheLoader<String, String>() { 2045 @Override 2046 public String load(String key) throws InterruptedException { 2047 callCount.incrementAndGet(); 2048 startSignal.await(); 2049 throw e; 2050 } 2051 }); 2052 2053 List<Object> result = doConcurrentGet(cache, "bar", count, startSignal); 2054 2055 assertEquals(1, callCount.get()); 2056 for (int i = 0; i < count; i++) { 2057 // doConcurrentGet alternates between calling getUnchecked and calling get, but an unchecked 2058 // exception thrown by the loader is always wrapped as an UncheckedExecutionException. 2059 assertThat(result.get(i)).isInstanceOf(UncheckedExecutionException.class); 2060 assertThat(((UncheckedExecutionException) result.get(i))).hasCauseThat().isSameInstanceAs(e); 2061 } 2062 2063 // subsequent calls should call the loader again, not get the old exception 2064 try { 2065 cache.getUnchecked("bar"); 2066 fail(); 2067 } catch (UncheckedExecutionException expected) { 2068 } 2069 assertEquals(2, callCount.get()); 2070 } 2071 2072 /** 2073 * On a concurrent computation that throws a checked exception, all threads should get the 2074 * (wrapped) exception, with the loader called only once. The result should not be cached (a later 2075 * request should call the loader again). 2076 */ testConcurrentLoadingCheckedException(CacheBuilder<Object, Object> builder)2077 private static void testConcurrentLoadingCheckedException(CacheBuilder<Object, Object> builder) 2078 throws InterruptedException { 2079 2080 int count = 10; 2081 final AtomicInteger callCount = new AtomicInteger(); 2082 final CountDownLatch startSignal = new CountDownLatch(count + 1); 2083 final IOException e = new IOException(); 2084 2085 LoadingCache<String, String> cache = 2086 builder.build( 2087 new CacheLoader<String, String>() { 2088 @Override 2089 public String load(String key) throws IOException, InterruptedException { 2090 callCount.incrementAndGet(); 2091 startSignal.await(); 2092 throw e; 2093 } 2094 }); 2095 2096 List<Object> result = doConcurrentGet(cache, "bar", count, startSignal); 2097 2098 assertEquals(1, callCount.get()); 2099 for (int i = 0; i < count; i++) { 2100 // doConcurrentGet alternates between calling getUnchecked and calling get. If we call get(), 2101 // we should get an ExecutionException; if we call getUnchecked(), we should get an 2102 // UncheckedExecutionException. 2103 int mod = i % 3; 2104 if (mod == 0 || mod == 2) { 2105 assertThat(result.get(i)).isInstanceOf(ExecutionException.class); 2106 assertThat((ExecutionException) result.get(i)).hasCauseThat().isSameInstanceAs(e); 2107 } else { 2108 assertThat(result.get(i)).isInstanceOf(UncheckedExecutionException.class); 2109 assertThat((UncheckedExecutionException) result.get(i)).hasCauseThat().isSameInstanceAs(e); 2110 } 2111 } 2112 2113 // subsequent calls should call the loader again, not get the old exception 2114 try { 2115 cache.getUnchecked("bar"); 2116 fail(); 2117 } catch (UncheckedExecutionException expected) { 2118 } 2119 assertEquals(2, callCount.get()); 2120 } 2121 2122 /** 2123 * Test-helper method that performs {@code nThreads} concurrent calls to {@code cache.get(key)} or 2124 * {@code cache.getUnchecked(key)}, and returns a List containing each of the results. The result 2125 * for any given call to {@code cache.get} or {@code cache.getUnchecked} is the value returned, or 2126 * the exception thrown. 2127 * 2128 * <p>As we iterate from {@code 0} to {@code nThreads}, threads with an even index will call 2129 * {@code getUnchecked}, and threads with an odd index will call {@code get}. If the cache throws 2130 * exceptions, this difference may be visible in the returned List. 2131 */ doConcurrentGet( final LoadingCache<K, ?> cache, final K key, int nThreads, final CountDownLatch gettersStartedSignal)2132 private static <K> List<Object> doConcurrentGet( 2133 final LoadingCache<K, ?> cache, 2134 final K key, 2135 int nThreads, 2136 final CountDownLatch gettersStartedSignal) 2137 throws InterruptedException { 2138 2139 final AtomicReferenceArray<Object> result = new AtomicReferenceArray<>(nThreads); 2140 final CountDownLatch gettersComplete = new CountDownLatch(nThreads); 2141 for (int i = 0; i < nThreads; i++) { 2142 final int index = i; 2143 Thread thread = 2144 new Thread( 2145 new Runnable() { 2146 @Override 2147 public void run() { 2148 gettersStartedSignal.countDown(); 2149 Object value = null; 2150 try { 2151 int mod = index % 3; 2152 if (mod == 0) { 2153 value = cache.get(key); 2154 } else if (mod == 1) { 2155 value = cache.getUnchecked(key); 2156 } else { 2157 cache.refresh(key); 2158 value = cache.get(key); 2159 } 2160 result.set(index, value); 2161 } catch (Throwable t) { 2162 result.set(index, t); 2163 } 2164 gettersComplete.countDown(); 2165 } 2166 }); 2167 thread.start(); 2168 // we want to wait until each thread is WAITING - one thread waiting inside CacheLoader.load 2169 // (in startSignal.await()), and the others waiting for that thread's result. 2170 while (thread.isAlive() && thread.getState() != Thread.State.WAITING) { 2171 Thread.yield(); 2172 } 2173 } 2174 gettersStartedSignal.countDown(); 2175 gettersComplete.await(); 2176 2177 List<Object> resultList = Lists.newArrayListWithExpectedSize(nThreads); 2178 for (int i = 0; i < nThreads; i++) { 2179 resultList.add(result.get(i)); 2180 } 2181 return resultList; 2182 } 2183 testAsMapDuringLoading()2184 public void testAsMapDuringLoading() throws InterruptedException, ExecutionException { 2185 final CountDownLatch getStartedSignal = new CountDownLatch(2); 2186 final CountDownLatch letGetFinishSignal = new CountDownLatch(1); 2187 final CountDownLatch getFinishedSignal = new CountDownLatch(2); 2188 final String getKey = "get"; 2189 final String refreshKey = "refresh"; 2190 final String suffix = "Suffix"; 2191 2192 CacheLoader<String, String> computeFunction = 2193 new CacheLoader<String, String>() { 2194 @Override 2195 public String load(String key) throws InterruptedException { 2196 getStartedSignal.countDown(); 2197 letGetFinishSignal.await(); 2198 return key + suffix; 2199 } 2200 }; 2201 2202 final LoadingCache<String, String> cache = CacheBuilder.newBuilder().build(computeFunction); 2203 ConcurrentMap<String, String> map = cache.asMap(); 2204 map.put(refreshKey, refreshKey); 2205 assertEquals(1, map.size()); 2206 assertFalse(map.containsKey(getKey)); 2207 assertSame(refreshKey, map.get(refreshKey)); 2208 2209 new Thread() { 2210 @Override 2211 public void run() { 2212 cache.getUnchecked(getKey); 2213 getFinishedSignal.countDown(); 2214 } 2215 }.start(); 2216 new Thread() { 2217 @Override 2218 public void run() { 2219 cache.refresh(refreshKey); 2220 getFinishedSignal.countDown(); 2221 } 2222 }.start(); 2223 2224 getStartedSignal.await(); 2225 2226 // computation is in progress; asMap shouldn't have changed 2227 assertEquals(1, map.size()); 2228 assertFalse(map.containsKey(getKey)); 2229 assertSame(refreshKey, map.get(refreshKey)); 2230 2231 // let computation complete 2232 letGetFinishSignal.countDown(); 2233 getFinishedSignal.await(); 2234 checkNothingLogged(); 2235 2236 // asMap view should have been updated 2237 assertEquals(2, cache.size()); 2238 assertEquals(getKey + suffix, map.get(getKey)); 2239 assertEquals(refreshKey + suffix, map.get(refreshKey)); 2240 } 2241 testInvalidateDuringLoading()2242 public void testInvalidateDuringLoading() throws InterruptedException, ExecutionException { 2243 // computation starts; invalidate() is called on the key being computed, computation finishes 2244 final CountDownLatch computationStarted = new CountDownLatch(2); 2245 final CountDownLatch letGetFinishSignal = new CountDownLatch(1); 2246 final CountDownLatch getFinishedSignal = new CountDownLatch(2); 2247 final String getKey = "get"; 2248 final String refreshKey = "refresh"; 2249 final String suffix = "Suffix"; 2250 2251 CacheLoader<String, String> computeFunction = 2252 new CacheLoader<String, String>() { 2253 @Override 2254 public String load(String key) throws InterruptedException { 2255 computationStarted.countDown(); 2256 letGetFinishSignal.await(); 2257 return key + suffix; 2258 } 2259 }; 2260 2261 final LoadingCache<String, String> cache = CacheBuilder.newBuilder().build(computeFunction); 2262 ConcurrentMap<String, String> map = cache.asMap(); 2263 map.put(refreshKey, refreshKey); 2264 2265 new Thread() { 2266 @Override 2267 public void run() { 2268 cache.getUnchecked(getKey); 2269 getFinishedSignal.countDown(); 2270 } 2271 }.start(); 2272 new Thread() { 2273 @Override 2274 public void run() { 2275 cache.refresh(refreshKey); 2276 getFinishedSignal.countDown(); 2277 } 2278 }.start(); 2279 2280 computationStarted.await(); 2281 cache.invalidate(getKey); 2282 cache.invalidate(refreshKey); 2283 assertFalse(map.containsKey(getKey)); 2284 assertFalse(map.containsKey(refreshKey)); 2285 2286 // let computation complete 2287 letGetFinishSignal.countDown(); 2288 getFinishedSignal.await(); 2289 checkNothingLogged(); 2290 2291 // results should be visible 2292 assertEquals(2, cache.size()); 2293 assertEquals(getKey + suffix, map.get(getKey)); 2294 assertEquals(refreshKey + suffix, map.get(refreshKey)); 2295 assertEquals(2, cache.size()); 2296 } 2297 testInvalidateAndReloadDuringLoading()2298 public void testInvalidateAndReloadDuringLoading() 2299 throws InterruptedException, ExecutionException { 2300 // computation starts; clear() is called, computation finishes 2301 final CountDownLatch computationStarted = new CountDownLatch(2); 2302 final CountDownLatch letGetFinishSignal = new CountDownLatch(1); 2303 final CountDownLatch getFinishedSignal = new CountDownLatch(4); 2304 final String getKey = "get"; 2305 final String refreshKey = "refresh"; 2306 final String suffix = "Suffix"; 2307 2308 CacheLoader<String, String> computeFunction = 2309 new CacheLoader<String, String>() { 2310 @Override 2311 public String load(String key) throws InterruptedException { 2312 computationStarted.countDown(); 2313 letGetFinishSignal.await(); 2314 return key + suffix; 2315 } 2316 }; 2317 2318 final LoadingCache<String, String> cache = CacheBuilder.newBuilder().build(computeFunction); 2319 ConcurrentMap<String, String> map = cache.asMap(); 2320 map.put(refreshKey, refreshKey); 2321 2322 new Thread() { 2323 @Override 2324 public void run() { 2325 cache.getUnchecked(getKey); 2326 getFinishedSignal.countDown(); 2327 } 2328 }.start(); 2329 new Thread() { 2330 @Override 2331 public void run() { 2332 cache.refresh(refreshKey); 2333 getFinishedSignal.countDown(); 2334 } 2335 }.start(); 2336 2337 computationStarted.await(); 2338 cache.invalidate(getKey); 2339 cache.invalidate(refreshKey); 2340 assertFalse(map.containsKey(getKey)); 2341 assertFalse(map.containsKey(refreshKey)); 2342 2343 // start new computations 2344 new Thread() { 2345 @Override 2346 public void run() { 2347 cache.getUnchecked(getKey); 2348 getFinishedSignal.countDown(); 2349 } 2350 }.start(); 2351 new Thread() { 2352 @Override 2353 public void run() { 2354 cache.refresh(refreshKey); 2355 getFinishedSignal.countDown(); 2356 } 2357 }.start(); 2358 2359 // let computation complete 2360 letGetFinishSignal.countDown(); 2361 getFinishedSignal.await(); 2362 checkNothingLogged(); 2363 2364 // results should be visible 2365 assertEquals(2, cache.size()); 2366 assertEquals(getKey + suffix, map.get(getKey)); 2367 assertEquals(refreshKey + suffix, map.get(refreshKey)); 2368 } 2369 testExpandDuringLoading()2370 public void testExpandDuringLoading() throws InterruptedException { 2371 final int count = 3; 2372 final AtomicInteger callCount = new AtomicInteger(); 2373 // tells the computing thread when to start computing 2374 final CountDownLatch computeSignal = new CountDownLatch(1); 2375 // tells the main thread when computation is pending 2376 final CountDownLatch secondSignal = new CountDownLatch(1); 2377 // tells the main thread when the second get has started 2378 final CountDownLatch thirdSignal = new CountDownLatch(1); 2379 // tells the main thread when the third get has started 2380 final CountDownLatch fourthSignal = new CountDownLatch(1); 2381 // tells the test when all gets have returned 2382 final CountDownLatch doneSignal = new CountDownLatch(count); 2383 2384 CacheLoader<String, String> computeFunction = 2385 new CacheLoader<String, String>() { 2386 @Override 2387 public String load(String key) throws InterruptedException { 2388 callCount.incrementAndGet(); 2389 secondSignal.countDown(); 2390 computeSignal.await(); 2391 return key + "foo"; 2392 } 2393 }; 2394 2395 final LoadingCache<String, String> cache = 2396 CacheBuilder.newBuilder().weakKeys().build(computeFunction); 2397 2398 final AtomicReferenceArray<String> result = new AtomicReferenceArray<>(count); 2399 2400 final String key = "bar"; 2401 2402 // start computing thread 2403 new Thread() { 2404 @Override 2405 public void run() { 2406 result.set(0, cache.getUnchecked(key)); 2407 doneSignal.countDown(); 2408 } 2409 }.start(); 2410 2411 // wait for computation to start 2412 secondSignal.await(); 2413 2414 // start waiting thread 2415 new Thread() { 2416 @Override 2417 public void run() { 2418 thirdSignal.countDown(); 2419 result.set(1, cache.getUnchecked(key)); 2420 doneSignal.countDown(); 2421 } 2422 }.start(); 2423 2424 // give the second get a chance to run; it is okay for this to be racy 2425 // as the end result should be the same either way 2426 thirdSignal.await(); 2427 Thread.yield(); 2428 2429 // Expand! 2430 CacheTesting.forceExpandSegment(cache, key); 2431 2432 // start another waiting thread 2433 new Thread() { 2434 @Override 2435 public void run() { 2436 fourthSignal.countDown(); 2437 result.set(2, cache.getUnchecked(key)); 2438 doneSignal.countDown(); 2439 } 2440 }.start(); 2441 2442 // give the third get a chance to run; it is okay for this to be racy 2443 // as the end result should be the same either way 2444 fourthSignal.await(); 2445 Thread.yield(); 2446 2447 // let computation finish 2448 computeSignal.countDown(); 2449 doneSignal.await(); 2450 2451 assertTrue(callCount.get() == 1); 2452 assertEquals("barfoo", result.get(0)); 2453 assertEquals("barfoo", result.get(1)); 2454 assertEquals("barfoo", result.get(2)); 2455 assertEquals("barfoo", cache.getUnchecked(key)); 2456 } 2457 2458 // Test ignored because it is extremely flaky in CI builds 2459 2460 public void ignoreTestExpandDuringRefresh()2461 ignoreTestExpandDuringRefresh() 2462 throws InterruptedException, ExecutionException { 2463 final AtomicInteger callCount = new AtomicInteger(); 2464 // tells the computing thread when to start computing 2465 final CountDownLatch computeSignal = new CountDownLatch(1); 2466 // tells the main thread when computation is pending 2467 final CountDownLatch secondSignal = new CountDownLatch(1); 2468 // tells the main thread when the second get has started 2469 final CountDownLatch thirdSignal = new CountDownLatch(1); 2470 // tells the main thread when the third get has started 2471 final CountDownLatch fourthSignal = new CountDownLatch(1); 2472 // tells the test when all gets have returned 2473 final CountDownLatch doneSignal = new CountDownLatch(3); 2474 final String suffix = "Suffix"; 2475 2476 CacheLoader<String, String> computeFunction = 2477 new CacheLoader<String, String>() { 2478 @Override 2479 public String load(String key) throws InterruptedException { 2480 callCount.incrementAndGet(); 2481 secondSignal.countDown(); 2482 computeSignal.await(); 2483 return key + suffix; 2484 } 2485 }; 2486 2487 final AtomicReferenceArray<String> result = new AtomicReferenceArray<>(2); 2488 2489 final LoadingCache<String, String> cache = CacheBuilder.newBuilder().build(computeFunction); 2490 final String key = "bar"; 2491 cache.asMap().put(key, key); 2492 2493 // start computing thread 2494 new Thread() { 2495 @Override 2496 public void run() { 2497 cache.refresh(key); 2498 doneSignal.countDown(); 2499 } 2500 }.start(); 2501 2502 // wait for computation to start 2503 secondSignal.await(); 2504 checkNothingLogged(); 2505 2506 // start waiting thread 2507 new Thread() { 2508 @Override 2509 public void run() { 2510 thirdSignal.countDown(); 2511 result.set(0, cache.getUnchecked(key)); 2512 doneSignal.countDown(); 2513 } 2514 }.start(); 2515 2516 // give the second get a chance to run; it is okay for this to be racy 2517 // as the end result should be the same either way 2518 thirdSignal.await(); 2519 Thread.yield(); 2520 2521 // Expand! 2522 CacheTesting.forceExpandSegment(cache, key); 2523 2524 // start another waiting thread 2525 new Thread() { 2526 @Override 2527 public void run() { 2528 fourthSignal.countDown(); 2529 result.set(1, cache.getUnchecked(key)); 2530 doneSignal.countDown(); 2531 } 2532 }.start(); 2533 2534 // give the third get a chance to run; it is okay for this to be racy 2535 // as the end result should be the same either way 2536 fourthSignal.await(); 2537 Thread.yield(); 2538 2539 // let computation finish 2540 computeSignal.countDown(); 2541 doneSignal.await(); 2542 2543 assertTrue(callCount.get() == 1); 2544 assertEquals(key, result.get(0)); 2545 assertEquals(key, result.get(1)); 2546 assertEquals(key + suffix, cache.getUnchecked(key)); 2547 } 2548 throwing(final Exception exception)2549 static <T> Callable<T> throwing(final Exception exception) { 2550 return new Callable<T>() { 2551 @Override 2552 public T call() throws Exception { 2553 throw exception; 2554 } 2555 }; 2556 } 2557 } 2558