@Test public void asyncLoad() throws Exception { CacheLoader<Integer, ?> loader = key -> key; CompletableFuture<?> future = loader.asyncLoad(1, Runnable::run); assertThat(future.get(), is(1)); }
@Test public void asyncReload() throws Exception { CacheLoader<Integer, Integer> loader = key -> -key; CompletableFuture<?> future = loader.asyncReload(1, 2, Runnable::run); assertThat(future.get(), is(-1)); } }
BoundedLocalLoadingCache(Caffeine<K, V> builder, CacheLoader<? super K, V> loader) { super(builder, loader); requireNonNull(loader); hasBulkLoader = hasLoadAll(loader); mappingFunction = key -> { try { return loader.load(key); } catch (RuntimeException e) { throw e; } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new CompletionException(e); } catch (Exception e) { throw new CompletionException(e); } }; }
V oldValue = cache().getIfPresentQuietly(key, writeTime); CompletableFuture<V> refreshFuture = (oldValue == null) ? cacheLoader().asyncLoad(key, cache().executor()) : cacheLoader().asyncReload(key, oldValue, cache().executor()); refreshFuture.whenComplete((newValue, error) -> { long loadTime = cache().statsTicker().read() - startTime;
@Override public Map<K, V> loadAll(Iterable<? extends K> keys) throws Exception { return delegate.loadAll(keys); } }
@Test public void reload() throws Exception { CacheLoader<Integer, Integer> loader = key -> key; assertThat(loader.reload(1, 1), is(1)); }
@Test(expectedExceptions = UnsupportedOperationException.class) public void asyncLoadAll() throws Throwable { CacheLoader<Object, ?> loader = key -> key; try { loader.asyncLoadAll(Collections.emptyList(), Runnable::run).get(); } catch (ExecutionException e) { throw e.getCause(); } }
V oldValue = cache().getIfPresentQuietly(key, writeTime); CompletableFuture<V> refreshFuture = (oldValue == null) ? cacheLoader().asyncLoad(key, cache().executor()) : cacheLoader().asyncReload(key, oldValue, cache().executor()); refreshFuture.whenComplete((newValue, error) -> { long loadTime = cache().statsTicker().read() - startTime;
@Test(expectedExceptions = UnsupportedOperationException.class) public void loadAll() throws Exception { CacheLoader<Object, ?> loader = key -> key; loader.loadAll(Collections.emptyList()); }
/** * Asynchronously computes or retrieves a replacement value corresponding to an already-cached * {@code key}. If the replacement value is not found then the mapping will be removed if * {@code null} is computed. This method is called when an existing cache entry is refreshed by * {@link Caffeine#refreshAfterWrite}, or through a call to {@link LoadingCache#refresh}. * <p> * <b>Note:</b> <i>all exceptions thrown by this method will be logged and then swallowed</i>. * * @param key the non-null key whose value should be loaded * @param oldValue the non-null old value corresponding to {@code key} * @param executor the executor with which the entry is asynchronously loaded * @return a future containing the new value associated with {@code key}, or containing * {@code null} if the mapping is to be removed */ @Override @NonNull default CompletableFuture<V> asyncReload( @NonNull K key, @NonNull V oldValue, @NonNull Executor executor) { requireNonNull(key); requireNonNull(executor); return CompletableFuture.supplyAsync(() -> { try { return reload(key, oldValue); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new CompletionException(e); } }, executor); } }
@Test public void asyncLoadAll_exception() throws Exception { Exception e = new Exception(); CacheLoader<Integer, Integer> loader = new CacheLoader<Integer, Integer>() { @Override public Integer load(Integer key) throws Exception { throw new AssertionError(); } @Override public Map<Integer, Integer> loadAll( Iterable<? extends Integer> keys) throws Exception { throw e; } }; try { loader.asyncLoadAll(Arrays.asList(1), Runnable::run).join(); } catch (CompletionException ex) { assertThat(ex.getCause(), is(sameInstance(e))); } }
UnboundedLocalLoadingCache(Caffeine<K, V> builder, CacheLoader<? super K, V> loader) { super(builder); this.loader = loader; this.hasBulkLoader = hasLoadAll(loader); this.mappingFunction = key -> { try { return loader.load(key); } catch (RuntimeException e) { throw e; } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new CompletionException(e); } catch (Exception e) { throw new CompletionException(e); } }; }
return CompletableFuture.supplyAsync(() -> { try { return loadAll(keys); } catch (RuntimeException e) { throw e;
@Test public void asyncReload_exception() throws Exception { for (Exception e : Arrays.asList(new Exception(), new RuntimeException())) { CacheLoader<Integer, Integer> loader = key -> { throw e; }; try { loader.asyncReload(1, 1, Runnable::run).join(); Assert.fail(); } catch (CompletionException ex) { assertThat(ex.getCause(), is(sameInstance(e))); } } }
/** * Asynchronously computes or retrieves a replacement value corresponding to an already-cached * {@code key}. If the replacement value is not found then the mapping will be removed if * {@code null} is computed. This method is called when an existing cache entry is refreshed by * {@link Caffeine#refreshAfterWrite}, or through a call to {@link LoadingCache#refresh}. * <p> * <b>Note:</b> <i>all exceptions thrown by this method will be logged and then swallowed</i>. * * @param key the non-null key whose value should be loaded * @param oldValue the non-null old value corresponding to {@code key} * @param executor the executor with which the entry is asynchronously loaded * @return a future containing the new value associated with {@code key}, or containing * {@code null} if the mapping is to be removed */ @Override @Nonnull default CompletableFuture<V> asyncReload( @Nonnull K key, @Nonnull V oldValue, @Nonnull Executor executor) { requireNonNull(key); requireNonNull(executor); return CompletableFuture.supplyAsync(() -> { try { return reload(key, oldValue); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new CompletionException(e); } }, executor); } }
@Test public void asyncLoad_exception() throws Exception { Exception e = new Exception(); CacheLoader<Integer, Integer> loader = key -> { throw e; }; try { loader.asyncLoad(1, Runnable::run).join(); } catch (CompletionException ex) { assertThat(ex.getCause(), is(sameInstance(e))); } }
/** * Asynchronously computes or retrieves the value corresponding to {@code key}. * * @param key the non-null key whose value should be loaded * @param executor the executor that asynchronously loads the entry * @return the future value associated with {@code key} */ @Override @NonNull default CompletableFuture<V> asyncLoad(@NonNull K key, @NonNull Executor executor) { requireNonNull(key); requireNonNull(executor); return CompletableFuture.supplyAsync(() -> { try { return load(key); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new CompletionException(e); } }, executor); }
try { @SuppressWarnings("unchecked") Map<K, V> loaded = (Map<K, V>) cacheLoader().loadAll(keysToLoad); loaded.forEach((key, value) -> { cache().put(key, value, /* notifyWriter */ false);
@SuppressWarnings("NullAway") CompletableFuture<V> refresh = future.thenCompose(value -> cacheLoader.asyncReload(key, value, executor)); refreshFuture = refresh; } else { CompletableFuture<V> refresh = cacheLoader.asyncReload(key, oldValue, executor); refreshFuture = refresh;
@Override public V load(K key) throws Exception { V value = delegate.load(key); if (value == null) { throw new CacheMissException(); } return value; } }