Refreshes the value associated with key, unless another thread is already doing so. Returns the newly refreshed value associated with key if it was refreshed inline, or null if another thread is performing the refresh or if an error occurs during refresh.
(K key, int hash, CacheLoader<? super K, V> loader, boolean checkTime)
| 2455 | */ |
| 2456 | |
| 2457 | @Nullable |
| 2458 | V refresh(K key, int hash, CacheLoader<? super K, V> loader, boolean checkTime) { |
| 2459 | final LoadingValueReference<K, V> loadingValueReference = insertLoadingValueReference(key, hash, checkTime); |
| 2460 | if (loadingValueReference == null) { |
| 2461 | return null; |
| 2462 | } |
| 2463 | ListenableFuture<V> result = loadAsync(key, hash, loadingValueReference, loader); |
| 2464 | if (result.isDone()) { |
| 2465 | try { |
| 2466 | return Uninterruptibles.getUninterruptibly(result); |
| 2467 | } catch (Throwable t) { |
| 2468 | // don't let refresh exceptions propagate; error was already logged} |
| 2469 | } |
| 2470 | return null; |
| 2471 | } |
| 2472 | |
| 2473 | /** |
| 2474 | * Returns a newly inserted {@code LoadingValueReference}, or null if the live value reference |
| 2475 | * is already loading. |
| 2476 | */ |
| 2477 | |
| 2478 | @Nullable |
| 2479 | LoadingValueReference<K, V> insertLoadingValueReference(final K key, final int hash, boolean checkTime) { |
| 2480 | ReferenceEntry<K, V> e = null; |
| 2481 | lock(); |
| 2482 | try { |
| 2483 | long now = map.ticker.read(); |
| 2484 | preWriteCleanup(now); |
| 2485 | AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table; |
| 2486 | int index = hash & (table.length() - 1); |
| 2487 | ReferenceEntry<K, V> first = table.get(index); |
| 2488 | |
| 2489 | // Look for an existing entry. |
| 2490 | for (e = first; e != null; e = e.getNext()) { |
| 2491 | K entryKey = e.getKey(); |
| 2492 | if (e.getHash() == hash && entryKey != null |
| 2493 | && map.keyEquivalence.equivalent(key, entryKey)) { |
| 2494 | // We found an existing entry. |
| 2495 | ValueReference<K, V> valueReference = e.getValueReference(); |
| 2496 | if (valueReference.isLoading() |
| 2497 | || (checkTime && (now - e.getWriteTime() < map.refreshNanos))) { |
| 2498 | // refresh is a no-op if loading is pending |
| 2499 | // if checkTime, we want to check *after* acquiring the lock if refresh still needs |
| 2500 | // to be scheduled |
| 2501 | return null; |
| 2502 | } |
| 2503 | |
| 2504 | // continue returning old value while loading |
| 2505 | ++modCount; |
| 2506 | LoadingValueReference<K, V> loadingValueReference = new LoadingValueReference<K, V>(valueReference); |
| 2507 | e.setValueReference(loadingValueReference); |
| 2508 | return loadingValueReference; |
| 2509 | } |
| 2510 | } |
| 2511 | ++modCount; |
| 2512 | LoadingValueReference<K, V> loadingValueReference = new LoadingValueReference<K, V>(); |
| 2513 | e = newEntry(key, hash, first); |
| 2514 | e.setValueReference(loadingValueReference); |
no test coverage detected