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