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