Skip to content

Commit f18ec39

Browse files
committed
Release CacheLoader.asyncReload() in Guava 17.0.
------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=59050926
1 parent 426c442 commit f18ec39

File tree

2 files changed

+147
-0
lines changed

2 files changed

+147
-0
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* Copyright (C) 2011 The Guava Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.common.cache;
18+
19+
import com.google.common.collect.ImmutableList;
20+
import com.google.common.collect.ImmutableMap;
21+
import com.google.common.collect.Lists;
22+
import com.google.common.util.concurrent.Futures;
23+
import com.google.common.util.concurrent.ListenableFuture;
24+
25+
import junit.framework.TestCase;
26+
27+
import java.util.LinkedList;
28+
import java.util.Map;
29+
import java.util.concurrent.Executor;
30+
import java.util.concurrent.atomic.AtomicInteger;
31+
32+
/**
33+
* Unit tests for {@link CacheLoader}.
34+
*
35+
* @author Charles Fry
36+
*/
37+
public class CacheLoaderTest extends TestCase {
38+
39+
private static class QueuingExecutor implements Executor {
40+
private LinkedList<Runnable> tasks = Lists.newLinkedList();
41+
42+
@Override
43+
public void execute(Runnable task) {
44+
tasks.add(task);
45+
}
46+
47+
private void runNext() {
48+
tasks.pop().run();
49+
}
50+
}
51+
52+
public void testAsyncReload() throws Exception {
53+
final AtomicInteger loadCount = new AtomicInteger();
54+
final AtomicInteger reloadCount = new AtomicInteger();
55+
final AtomicInteger loadAllCount = new AtomicInteger();
56+
57+
CacheLoader<Object, Object> baseLoader = new CacheLoader<Object, Object>() {
58+
@Override
59+
public Object load(Object key) {
60+
loadCount.incrementAndGet();
61+
return new Object();
62+
}
63+
64+
@Override
65+
public ListenableFuture<Object> reload(Object key, Object oldValue) {
66+
reloadCount.incrementAndGet();
67+
return Futures.immediateFuture(new Object());
68+
}
69+
70+
@Override
71+
public Map<Object, Object> loadAll(Iterable<? extends Object> keys) {
72+
loadAllCount.incrementAndGet();
73+
return ImmutableMap.of();
74+
}
75+
};
76+
77+
assertEquals(0, loadCount.get());
78+
assertEquals(0, reloadCount.get());
79+
assertEquals(0, loadAllCount.get());
80+
81+
baseLoader.load(new Object());
82+
baseLoader.reload(new Object(), new Object());
83+
baseLoader.loadAll(ImmutableList.of(new Object()));
84+
assertEquals(1, loadCount.get());
85+
assertEquals(1, reloadCount.get());
86+
assertEquals(1, loadAllCount.get());
87+
88+
QueuingExecutor executor = new QueuingExecutor();
89+
CacheLoader<Object, Object> asyncReloader =
90+
CacheLoader.asyncReload(baseLoader, executor);
91+
92+
asyncReloader.load(new Object());
93+
asyncReloader.reload(new Object(), new Object());
94+
asyncReloader.loadAll(ImmutableList.of(new Object()));
95+
assertEquals(2, loadCount.get());
96+
assertEquals(1, reloadCount.get());
97+
assertEquals(2, loadAllCount.get());
98+
99+
executor.runNext();
100+
assertEquals(2, loadCount.get());
101+
assertEquals(2, reloadCount.get());
102+
assertEquals(2, loadAllCount.get());
103+
}
104+
}

guava/src/com/google/common/cache/CacheLoader.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,12 @@
2525
import com.google.common.base.Supplier;
2626
import com.google.common.util.concurrent.Futures;
2727
import com.google.common.util.concurrent.ListenableFuture;
28+
import com.google.common.util.concurrent.ListenableFutureTask;
2829

2930
import java.io.Serializable;
3031
import java.util.Map;
32+
import java.util.concurrent.Callable;
33+
import java.util.concurrent.Executor;
3134

3235
/**
3336
* Computes or retrieves values, based on a key, for use in populating a {@link LoadingCache}.
@@ -165,6 +168,46 @@ public static <V> CacheLoader<Object, V> from(Supplier<V> supplier) {
165168
return new SupplierToCacheLoader<V>(supplier);
166169
}
167170

171+
/**
172+
* Returns a {@code CacheLoader} which wraps {@code loader}, executing calls to
173+
* {@link CacheLoader#reload} using {@code executor}.
174+
*
175+
* <p>This method is useful only when {@code loader.reload} has a synchronous implementation,
176+
* such as {@linkplain #reload the default implementation}.
177+
*
178+
* @since 17.0
179+
*/
180+
@Beta
181+
@GwtIncompatible("Executor + Futures")
182+
public static <K, V> CacheLoader<K, V> asyncReload(final CacheLoader<K, V> loader,
183+
final Executor executor) {
184+
checkNotNull(loader);
185+
checkNotNull(executor);
186+
return new CacheLoader<K, V>() {
187+
@Override
188+
public V load(K key) throws Exception {
189+
return loader.load(key);
190+
}
191+
192+
@Override
193+
public ListenableFuture<V> reload(final K key, final V oldValue) throws Exception {
194+
ListenableFutureTask<V> task = ListenableFutureTask.create(new Callable<V>() {
195+
@Override
196+
public V call() throws Exception {
197+
return loader.reload(key, oldValue).get();
198+
}
199+
});
200+
executor.execute(task);
201+
return task;
202+
}
203+
204+
@Override
205+
public Map<K, V> loadAll(Iterable<? extends K> keys) throws Exception {
206+
return loader.loadAll(keys);
207+
}
208+
};
209+
}
210+
168211
private static final class SupplierToCacheLoader<V>
169212
extends CacheLoader<Object, V> implements Serializable {
170213
private final Supplier<V> computingSupplier;

0 commit comments

Comments
 (0)