Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / appengine / api / datastore / MemcacheEntityCache.java
bloba9bf726130e3e94f284a83c9741e20385420e292
1 package com.google.appengine.api.datastore;
3 import static com.google.common.base.Preconditions.checkArgument;
5 import com.google.appengine.api.memcache.AsyncMemcacheService;
6 import com.google.appengine.api.memcache.ErrorHandlers;
7 import com.google.appengine.api.memcache.Expiration;
8 import com.google.appengine.api.memcache.InvalidValueException;
9 import com.google.appengine.api.memcache.MemcacheService.CasValues;
10 import com.google.appengine.api.memcache.MemcacheService.IdentifiableValue;
11 import com.google.appengine.api.memcache.MemcacheService.SetPolicy;
12 import com.google.appengine.api.memcache.MemcacheServiceFactory;
13 import com.google.appengine.api.utils.FutureWrapper;
14 import com.google.common.collect.ImmutableMap;
16 import java.util.Collection;
17 import java.util.Map;
18 import java.util.Set;
19 import java.util.concurrent.Future;
20 import java.util.logging.Level;
21 import java.util.logging.Logger;
23 /**
24 * A memcache backed cache used for entity caching.
25 * <p>
26 * If an RPC error or de-serialization error happens during a caching operation the error is
27 * logged and the cache operation completes with no results (an empty set or map).
30 class MemcacheEntityCache {
32 static Logger logger = Logger.getLogger(MemcacheEntityCache.class.getName());
33 private static final Level LOG_LEVEL = Level.INFO;
35 static final String NAMESPACE = "__ah-datastore-l2-v1__";
37 private Double rpcDeadlineSecs;
38 private Expiration defaultValueExpirationTime;
39 private final AsyncMemcacheService memcacheService;
41 private MemcacheEntityCache() {
42 memcacheService = MemcacheServiceFactory.getAsyncMemcacheService(NAMESPACE);
43 memcacheService.setErrorHandler(ErrorHandlers.getConsistentLogAndContinue(Level.INFO));
46 MemcacheEntityCache(AsyncMemcacheService memcacheService) {
47 this.memcacheService = memcacheService;
50 /**
51 * Updates the memcache operation RPC deadline to use for memcache RPCs.
53 * @param rpcDeadlineSecs the memcache operation RPC deadline in seconds.
54 * @return {@code this} (for chaining).
55 * @throws IllegalArgumentException if the {@code rpcDeadlineSecs} is not greater than zero.
57 public MemcacheEntityCache rpcDeadlineSecs(double rpcDeadlineSecs) {
58 checkArgument(rpcDeadlineSecs > 0, "The rpcDeadlineSecs argument must be greater than 0");
59 this.rpcDeadlineSecs = rpcDeadlineSecs;
60 return this;
63 /**
64 * @return the memcache operation RPC deadline in seconds or {@code null} if no deadline has
65 * been specified.
67 public Double getRpcDeadlineSecs() {
68 return rpcDeadlineSecs;
71 /**
72 * Updates the expiration time for values stored in the cache without an explicit expiration time.
73 * By default, values without an explicit expiration time are cached for as long of a duration as
74 * possible.
76 * @param defaultValueExpirationTime the default value expiration time. Or {@code null} to specify
77 * an indefinite default expiration time.
78 * @return {@code this} (for chaining).
80 public MemcacheEntityCache defaultValueExpirationTime( Expiration defaultValueExpirationTime) {
81 this.defaultValueExpirationTime = defaultValueExpirationTime;
82 return this;
85 /**
86 * @return the default value expiration time for values stored in the cache without
87 * an explicit expiration time or {@code null} if no default expiration time has been
88 * specified.
90 public Expiration getDefaultValueExpirationTime() {
91 return defaultValueExpirationTime;
94 /**
95 * Fetches previously-stored cache values. The values returned can be used in subsequent calls
96 * to {@link #putIfUntouched}.
98 * @param keys a collection of keys for which values should be retrieved
99 * @return a mapping from keys to values of any entries found. If a requested
100 * key is not found in the cache the key will not be in the returned Map.
101 * @throws IllegalArgumentException if any element of {@code keys} is {@code null}
102 * or not {@link Serializable}.
104 public <K> Future<Map<K, IdentifiableValue>> getIdentifiable(Collection<K> keys) {
105 return new GetIdentifiablesFutureWrapper<K>(
106 memcacheService.getIdentifiables(keys));
110 * Sets the value in the cache for each key/value pair in the {@code values} map if the update
111 * satisfies the cache update {@code policy}.
112 * <p>
113 * The expiration time for each value stored is specified by
114 * {@link #defaultValueExpirationTime(Expiration)}.
116 * @param values the key/value mappings to add to the cache
117 * @param policy what to do if the cache entry is or is not already present
118 * @return the set of keys for which entries were created. Keys in {@code values} may not be
119 * in the returned set because of the {@code policy} regarding pre-existing entries.
120 * @throws IllegalArgumentException if any of the keys or values are {@code null} or
121 * or are not {@link Serializable}.
123 public <K> Future<Set<K>> put(Map<K, ?> values, SetPolicy policy) {
124 return put(values, policy, defaultValueExpirationTime);
128 * Sets the value in the cache for each key/value pair in the {@code values} map if the update
129 * satisfies the cache update {@code policy}.
131 * @param values the key/value mappings to add to the cache
132 * @param policy what to do if the cache entry is or is not already present
133 * @param valueExpirationTime the memcache value expiration time to use for each value updated
134 * in the cache. This overrides the default value expiration time. If {@code null} the
135 * expiration time is indefinite.
136 * @return the set of keys for which entries were created. Keys in {@code values} may not be
137 * in the returned set because of the {@code policy} regarding pre-existing entries.
138 * @throws IllegalArgumentException if any of the keys or values are {@code null} or
139 * or are not {@link Serializable}.
141 public <K> Future<Set<K>> put(Map<K, ?> values, SetPolicy policy, Expiration valueExpirationTime) {
142 return memcacheService.putAll(values, valueExpirationTime, policy);
146 * Atomically stores the new value of each {@link CasValues} object in the {@code values} map if
147 * no other value has been stored in the cache since the {@code CasValues} object's old value
148 * was retrieved from {@link #getIdentifiable}. If another value in the cache for {@code key}
149 * has been stored, or if the cache entry has been evicted then nothing is stored by this call.
150 * <p>
151 * The expiration time for each {@CasValues} object with a {@code null} expiration time is
152 * specified by {@link #defaultValueExpirationTime(Expiration)}.
154 * @param values the key/values mappings to compare and swap.
155 * @return the set of keys for which the new value was stored.
156 * @throws IllegalArgumentException If any of the keys or newValues are {@code null} or
157 * or are not {@link Serializable}. Also throws IllegalArgumentException if {@code values} has
158 * any nulls.
160 public <K> Future<Set<K>> putIfUntouched(Map<K, CasValues> values) {
161 return putIfUntouched(values, defaultValueExpirationTime);
165 * Atomically stores the new value of each {@link CasValues} object in the {@code values} map if
166 * no other value has been stored in the cache since the {@code CasValues} object's old value
167 * was retrieved from {@link #getIdentifiable}. If another value in the cache for {@code key}
168 * has been stored, or if the cache entry has been evicted then nothing is stored by this call.
169 * <p>
171 * @param values the key/values mappings to compare and swap.
172 * @param valueExpirationTime the expiration time to use for all {@code values} with a
173 * {@code null} {@link Expiration expiration} value in the {@code CasValues} object.
174 * This overrides the default value expiration time. If this is {@code null} and the
175 * {@code CasValues} object's expiration time is {@code null} then an indefinite expiration
176 * time will be specified for that {@code CasValue} object.
177 * @return the set of keys for which the new value was stored.
178 * @throws IllegalArgumentException If any of the keys or newValues are {@code null} or
179 * or are not {@link Serializable}. Also throws IllegalArgumentException if {@code values} has
180 * any nulls.
182 public <K> Future<Set<K>> putIfUntouched(Map<K, CasValues> values, Expiration valueExpirationTime) {
183 return memcacheService.putIfUntouched(values, valueExpirationTime);
187 * This class logs and absorbs de-serialization errors encountered when invoking
188 * {@link AsyncMemcacheService#getIdentifiables(Collection)}.
190 private static final class GetIdentifiablesFutureWrapper<K>
191 extends FutureWrapper<Map<K, IdentifiableValue>, Map<K, IdentifiableValue>> {
193 private GetIdentifiablesFutureWrapper(Future<Map<K, IdentifiableValue>> parent) {
194 super(parent);
197 @Override
198 protected Map<K, IdentifiableValue> wrap(Map<K, IdentifiableValue> wrapped) throws Exception {
199 return wrapped;
202 @Override
203 protected Map<K, IdentifiableValue> absorbParentException(Throwable cause) throws Throwable {
204 if (cause instanceof InvalidValueException) {
205 logger.log(LOG_LEVEL, "Deserialization error in memcache entity cache", cause);
206 return ImmutableMap.of();
207 } else {
208 throw cause;
212 @Override
213 protected Throwable convertException(Throwable cause) {
214 return cause;
219 * Contains static creation methods for {@link MemcacheEntityCache} instances.
221 public static final class Builder {
224 * Creates a {@link MemcacheEntityCache} instance with the specified memcache RPC deadline to
225 * use for memcache RPCs.
227 * @param rpcDeadlineSecs the memcache operation RPC deadline in seconds.
228 * @return the newly created {@code MemcacheEntityCache} instance.
229 * @throws IllegalArgumentException if the {@code rpcDeadlineSecs} is not greater than zero.
231 public static MemcacheEntityCache withRpcDeadlineSecs(double rpcDeadlineSecs) {
232 return new MemcacheEntityCache().rpcDeadlineSecs(rpcDeadlineSecs);
236 * Creates a {@link MemcacheEntityCache} instance with the specified expiration time for values
237 * stored in the cache without an explicit expiration time. By default, values without an
238 * explicit expiration time are cached for as long of a duration as possible.
240 * @param defaultValueExpirationTime the default value expiration time. Or {@code null} to
241 * specify an indefinite default expiration time.
242 * @return the newly created {@code MemcacheEntityCache} instance.
244 public static MemcacheEntityCache withDefaultValueExpirationTime( Expiration defaultValueExpirationTime) {
245 return new MemcacheEntityCache().defaultValueExpirationTime(defaultValueExpirationTime);
249 * Creates a {@link MemcacheEntityCache} instance with the default configuration.
251 public static MemcacheEntityCache withDefaults() {
252 return new MemcacheEntityCache();
255 private Builder() {}