Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / appengine / api / datastore / DatastoreServiceConfig.java
blob6849a313cabc5e7f749b6c8317cfc3a4df5dc8ed
1 // Copyright 2010 Google Inc. All Rights Reserved.
2 package com.google.appengine.api.datastore;
4 import static com.google.common.base.Preconditions.checkNotNull;
6 import com.google.appengine.api.datastore.ReadPolicy.Consistency;
7 import com.google.apphosting.api.ApiProxy;
8 import com.google.common.base.Preconditions;
10 import java.io.ByteArrayInputStream;
11 import java.io.InputStream;
13 /**
14 * User-configurable properties of the datastore.
16 * Notes on usage:<br>
17 * The recommended way to instantiate a {@code DatastoreServiceConfig} object
18 * is to statically import {@link Builder}.* and invoke a static creation
19 * method followed by an instance mutator (if needed):
21 * <pre>
22 * import static com.google.appengine.api.datastore.DatastoreServiceConfig.Builder.*;
23 * import com.google.appengine.api.datastore.ReadPolicy.Consistency;
25 * ...
27 * // eventually consistent reads
28 * DatastoreServiceConfig config = withReadPolicy(new ReadPolicy(Consistency.EVENTUAL));
30 * // eventually consistent reads with a 5 second deadline
31 * DatastoreServiceConfig config =
32 * withReadPolicy(new ReadPolicy(Consistency.EVENTUAL)).deadline(5.0);
33 * </pre>
36 public final class DatastoreServiceConfig {
38 /**
39 * Datastore service API version.
41 enum ApiVersion {
42 V3(false),
43 V4(false),
44 CLOUD_DATASTORE(true);
46 private final boolean isCloudService;
48 private ApiVersion(boolean isCloudService) {
49 this.isCloudService = isCloudService;
52 boolean isCloudService() {
53 return isCloudService;
57 /**
58 * The default maximum size a request RPC can be.
60 static final int DEFAULT_RPC_SIZE_LIMIT_BYTES = 1024 * 1024;
62 /**
63 * The default maximum number of keys allowed in a Get request.
65 static final int DEFAULT_MAX_BATCH_GET_KEYS = 1000;
67 /**
68 * The default maximum number of entities allowed in a Put or Delete request.
70 static final int DEFAULT_MAX_BATCH_WRITE_ENTITIES = 500;
72 /**
73 * The default maximum number of keys allowed in a Allocate ID request.
75 static final int DEFAULT_ALLOCATEID_BATCH_KEYS = 500;
77 /**
78 * Name of a system property that users can specify to control the default
79 * max entity groups per rpc.
81 static final String DEFAULT_MAX_ENTITY_GROUPS_PER_RPC_SYS_PROP =
82 "appengine.datastore.defaultMaxEntityGroupsPerRpc";
84 /**
85 * The default number of max entity groups per rpc.
87 static final int DEFAULT_MAX_ENTITY_GROUPS_PER_RPC = getDefaultMaxEntityGroupsPerRpc();
89 static final String CALLBACKS_CONFIG_SYS_PROP = "appengine.datastore.callbacksConfig";
91 static volatile DatastoreCallbacks CALLBACKS = null;
93 /**
94 * Keep in sync with
95 * com.google.appengine.tools.compilation.DatastoreCallbacksProcessor.CALLBACKS_CONFIG_FILE
97 private static final String CALLBACKS_CONFIG_FILE = "/META-INF/datastorecallbacks.xml";
99 static int getDefaultMaxEntityGroupsPerRpc() {
100 return getDefaultMaxEntityGroupsPerRpc(DEFAULT_MAX_ENTITY_GROUPS_PER_RPC_SYS_PROP, 10);
103 static final String DATASTORE_SERVICE_VERSION_SYS_PROP = "appengine.datastore.v4service";
104 static final String FORCE_V4_SYS_PROP_VAL = "force";
107 * Returns the value of the given system property as an int, or return the
108 * default value if there is no property with that name set.
110 static int getDefaultMaxEntityGroupsPerRpc(String sysPropName, int defaultVal) {
111 String sysPropVal = System.getProperty(sysPropName);
112 return sysPropVal == null ? defaultVal : Integer.parseInt(sysPropVal);
115 private static InputStream getCallbacksConfigInputStream() {
116 InputStream is;
117 String callbacksConfig = System.getProperty(CALLBACKS_CONFIG_SYS_PROP);
118 if (callbacksConfig != null) {
119 is = new ByteArrayInputStream(callbacksConfig.getBytes());
120 } else {
121 is = DatastoreServiceConfig.class.getResourceAsStream(CALLBACKS_CONFIG_FILE);
123 return is;
126 private final DatastoreCallbacks instanceDatastoreCallbacks;
128 private ImplicitTransactionManagementPolicy implicitTransactionManagementPolicy =
129 ImplicitTransactionManagementPolicy.NONE;
131 private ReadPolicy readPolicy = new ReadPolicy(Consistency.STRONG);
133 private Double deadline;
135 private AppIdNamespace appIdNamespace;
137 int maxRpcSizeBytes = DEFAULT_RPC_SIZE_LIMIT_BYTES;
138 int maxBatchWriteEntities = DEFAULT_MAX_BATCH_WRITE_ENTITIES;
139 int maxBatchReadEntities = DEFAULT_MAX_BATCH_GET_KEYS;
140 int maxBatchAllocateIdKeys = DEFAULT_ALLOCATEID_BATCH_KEYS;
141 int maxEntityGroupsPerRpc = DEFAULT_MAX_ENTITY_GROUPS_PER_RPC;
143 private EntityCacheConfig entityCacheConfig = null;
146 * If set, overrides the service API version.
148 private ApiVersion apiVersion = null;
150 private DatastoreV4Proxy datastoreV4Proxy = null;
153 * Cannot be directly instantiated, use {@link Builder} instead.
155 * @param datastoreCallbacks the callback methods to invoke on specific datastore operations.
156 * If null the datastore callbacks are derived from {@link #getCallbacksConfigInputStream}.
158 private DatastoreServiceConfig( DatastoreCallbacks datastoreCallbacks) {
159 instanceDatastoreCallbacks = datastoreCallbacks;
163 * Copy constructor
165 DatastoreServiceConfig(DatastoreServiceConfig config) {
166 implicitTransactionManagementPolicy = config.implicitTransactionManagementPolicy;
167 readPolicy = config.readPolicy;
168 deadline = config.deadline;
169 maxRpcSizeBytes = config.maxRpcSizeBytes;
170 maxBatchWriteEntities = config.maxBatchWriteEntities;
171 maxBatchReadEntities = config.maxBatchReadEntities;
172 maxEntityGroupsPerRpc = config.maxEntityGroupsPerRpc;
173 instanceDatastoreCallbacks = config.instanceDatastoreCallbacks;
174 appIdNamespace = config.appIdNamespace;
175 apiVersion = config.apiVersion;
176 datastoreV4Proxy = config.datastoreV4Proxy;
180 * Sets the implicit transaction management policy.
181 * @param p the implicit transaction management policy to set.
182 * @return {@code this} (for chaining)
184 public DatastoreServiceConfig implicitTransactionManagementPolicy(
185 ImplicitTransactionManagementPolicy p) {
186 if (p == null) {
187 throw new NullPointerException("implicit transaction management policy must not be null");
189 implicitTransactionManagementPolicy = p;
190 return this;
194 * Sets the read policy.
195 * @param readPolicy the read policy to set.
196 * @return {@code this} (for chaining)
198 public DatastoreServiceConfig readPolicy(ReadPolicy readPolicy) {
199 if (readPolicy == null) {
200 throw new NullPointerException("read policy must not be null");
202 this.readPolicy = readPolicy;
203 return this;
207 * Sets the deadline, in seconds, for all rpcs initiated by the
208 * {@link DatastoreService} with which this config is associated.
209 * @param deadline the deadline to set.
210 * @throws IllegalArgumentException if deadline is not positive
211 * @return {@code this} (for chaining)
213 public DatastoreServiceConfig deadline(double deadline) {
214 if (deadline <= 0.0) {
215 throw new IllegalArgumentException("deadline must be > 0, got " + deadline);
217 this.deadline = deadline;
218 return this;
221 DatastoreServiceConfig appIdNamespace(AppIdNamespace appIdNamespace) {
222 this.appIdNamespace = appIdNamespace;
223 return this;
227 * Sets the maximum number of entities that can be modified in a single RPC.
228 * @param maxBatchWriteEntities the limit to set
229 * @throws IllegalArgumentException if maxBatchWriteEntities is not greater
230 * than zero
231 * @return {@code this} (for chaining)
233 DatastoreServiceConfig maxBatchWriteEntities(int maxBatchWriteEntities) {
234 if (maxBatchWriteEntities <= 0) {
235 throw new IllegalArgumentException("maxBatchWriteEntities must be > 0, got "
236 + maxBatchWriteEntities);
238 this.maxBatchWriteEntities = maxBatchWriteEntities;
239 return this;
243 * Sets the maximum number of entities that can be read in a single RPC.
244 * @param maxBatchReadEntities the limit to set
245 * @throws IllegalArgumentException if maxBatchReadEntities is not greater
246 * than zero
247 * @return {@code this} (for chaining)
249 DatastoreServiceConfig maxBatchReadEntities(int maxBatchReadEntities) {
250 if (maxBatchReadEntities <= 0) {
251 throw new IllegalArgumentException("maxBatchReadEntities must be > 0, got "
252 + maxBatchReadEntities);
254 this.maxBatchReadEntities = maxBatchReadEntities;
255 return this;
259 * Sets the maximum size in bytes an RPC can be.
261 * The size of the request can be exceeded if the RPC cannot be split enough
262 * to respect this limit. However there may be a hard limit on the RPC which,
263 * if exceeded, will cause an exception to be thrown.
265 * @param maxRpcSizeBytes the limit to set
266 * @throws IllegalArgumentException if maxRpcSizeBytes is not positive
267 * @return {@code this} (for chaining)
269 DatastoreServiceConfig maxRpcSizeBytes(int maxRpcSizeBytes) {
270 if (maxRpcSizeBytes < 0) {
271 throw new IllegalArgumentException("maxRpcSizeBytes must be >= 0, got "
272 + maxRpcSizeBytes);
274 this.maxRpcSizeBytes = maxRpcSizeBytes;
275 return this;
279 * Sets the maximum number of entity groups that can be represented in a
280 * single rpc.
282 * For a non-transactional operation that involves more entity groups than the
283 * maximum, the operation will be performed by executing multiple, asynchronous
284 * rpcs to the datastore, each of which has no more entity groups represented
285 * than the maximum. So, if a put() operation has 8 entity groups and the
286 * maximum is 3, we will send 3 rpcs, 2 with 3 entity groups and 1 with 2
287 * entity groups. This is a performance optimization - in many cases
288 * multiple, small, asynchronous rpcs will finish faster than a single large
289 * asynchronous rpc. The optimal value for this property will be
290 * application-specific, so experimentation is encouraged.
292 * @param maxEntityGroupsPerRpc the maximum number of entity groups per rpc
293 * @throws IllegalArgumentException if maxEntityGroupsPerRpc is not greater
294 * than zero
295 * @return {@code this} (for chaining)
297 public DatastoreServiceConfig maxEntityGroupsPerRpc(int maxEntityGroupsPerRpc) {
298 if (maxEntityGroupsPerRpc <= 0) {
299 throw new IllegalArgumentException("maxEntityGroupsPerRpc must be > 0, got "
300 + maxEntityGroupsPerRpc);
302 this.maxEntityGroupsPerRpc = maxEntityGroupsPerRpc;
303 return this;
307 * Sets the entity cache configuration to use for entity caching.
309 * To successfully use entity caching it is important that all application code that updates
310 * or reads the same set of entities uses a {@code DatastoreServiceConfig} with the same entity
311 * cache configuration.
313 * By default the datastore service does not do any entity caching.
315 * @param entityCacheConfig the entity cache configuration to use for entity caching.
316 * @return {@code this} (for chaining)
318 DatastoreServiceConfig entityCacheConfig(EntityCacheConfig entityCacheConfig) {
319 checkNotNull(entityCacheConfig, "The entityCacheConfig argument can not be null");
320 this.entityCacheConfig = entityCacheConfig;
321 return this;
325 * @return The {@code ImplicitTransactionManagementPolicy} to use.
327 public ImplicitTransactionManagementPolicy getImplicitTransactionManagementPolicy() {
328 return implicitTransactionManagementPolicy;
332 * @return The {@code ReadPolicy} to use.
334 public ReadPolicy getReadPolicy() {
335 return readPolicy;
339 * @return The maximum number of entity groups per rpc.
341 public Integer getMaxEntityGroupsPerRpc() {
342 return getMaxEntityGroupsPerRpcInternal();
345 int getMaxEntityGroupsPerRpcInternal() {
346 return maxEntityGroupsPerRpc;
350 * @return The deadline to use. Can be {@code null}.
352 public Double getDeadline() {
353 return deadline;
356 AppIdNamespace getAppIdNamespace() {
357 return appIdNamespace == null ? DatastoreApiHelper.getCurrentAppIdNamespace() : appIdNamespace;
360 DatastoreCallbacks getDatastoreCallbacks() {
361 if (instanceDatastoreCallbacks != null) {
362 return instanceDatastoreCallbacks;
365 if (CALLBACKS == null) {
366 InputStream is = getCallbacksConfigInputStream();
367 if (is == null) {
368 CALLBACKS = DatastoreCallbacks.NoOpDatastoreCallbacks.INSTANCE;
369 } else {
370 CALLBACKS = new DatastoreCallbacksImpl(is, false);
373 return CALLBACKS;
377 * @return the {@link EntityCacheConfig} to use or {@code null} if no entity cache configuration
378 * was specified.
380 EntityCacheConfig getEntityCacheConfig() {
381 return entityCacheConfig;
385 * Datastore service API version to use.
387 ApiVersion getApiVersion() {
388 if (apiVersion != null) {
389 return apiVersion;
392 boolean useV4 = FORCE_V4_SYS_PROP_VAL.equals(
393 System.getProperty(DATASTORE_SERVICE_VERSION_SYS_PROP));
394 boolean useCloudDatastore = Boolean.valueOf(EnvProxy.getenv("_DATASTORE_USE_CLOUD_DATASTORE"));
396 ApiVersion localApiVersion = ApiVersion.V3;
397 if (useV4 && useCloudDatastore) {
398 throw new IllegalArgumentException("Cannot use both v4 and Cloud Datastore APIs.");
399 } else if (useV4) {
400 localApiVersion = ApiVersion.V4;
401 } else if (useCloudDatastore) {
402 localApiVersion = ApiVersion.CLOUD_DATASTORE;
405 apiVersion = localApiVersion;
406 return apiVersion;
409 DatastoreServiceConfig setApiVersion( ApiVersion apiVersion) {
410 this.apiVersion = apiVersion;
411 return this;
414 ApiProxy.ApiConfig constructApiConfig() {
415 ApiProxy.ApiConfig apiConfig = new ApiProxy.ApiConfig();
416 apiConfig.setDeadlineInSeconds(deadline);
417 return apiConfig;
419 DatastoreV4Proxy getDatastoreV4Proxy() {
420 return datastoreV4Proxy;
424 * Contains static creation methods for {@link DatastoreServiceConfig}.
426 public static final class Builder {
429 * Create a {@link DatastoreServiceConfig} with the given implicit
430 * transaction management policy.
431 * @param p the implicit transaction management policy to set.
432 * @return The newly created DatastoreServiceConfig instance.
434 public static DatastoreServiceConfig withImplicitTransactionManagementPolicy(
435 ImplicitTransactionManagementPolicy p) {
436 return withDefaults().implicitTransactionManagementPolicy(p);
440 * Create a {@link DatastoreServiceConfig} with the given read
441 * policy.
442 * @param readPolicy the read policy to set.
443 * @return The newly created DatastoreServiceConfig instance.
445 public static DatastoreServiceConfig withReadPolicy(ReadPolicy readPolicy) {
446 return withDefaults().readPolicy(readPolicy);
450 * Create a {@link DatastoreServiceConfig} with the given deadline, in
451 * seconds.
452 * @param deadline the deadline to set.
453 * @throws IllegalArgumentException if deadline is not positive
454 * @return The newly created DatastoreServiceConfig instance.
456 public static DatastoreServiceConfig withDeadline(double deadline) {
457 return withDefaults().deadline(deadline);
461 * Create a {@link DatastoreServiceConfig} with the given maximum entity
462 * groups per rpc.
463 * @param maxEntityGroupsPerRpc the maximum entity groups per rpc to set.
464 * @return The newly created DatastoreServiceConfig instance.
466 * @see DatastoreServiceConfig#maxEntityGroupsPerRpc(int)
468 public static DatastoreServiceConfig withMaxEntityGroupsPerRpc(int maxEntityGroupsPerRpc) {
469 return withDefaults().maxEntityGroupsPerRpc(maxEntityGroupsPerRpc);
473 * Create a {@link DatastoreServiceConfig} with the given entity cache configuration.
475 * @param entityCacheConfig the entity cache configuration to use for entity caching.
477 * @see DatastoreServiceConfig#entityCacheConfig
479 static DatastoreServiceConfig withEntityCacheConfig(
480 EntityCacheConfig entityCacheConfig) {
481 return withDefaults().entityCacheConfig(entityCacheConfig);
485 * Helper method for creating a {@link DatastoreServiceConfig} instance with the
486 * specified {@code datastoreCallbacks}. The callbacks defined for the application are
487 * bypassed and the specified callbacks are used instead.
489 * @return The newly created DatastoreServiceConfig instance.
491 static DatastoreServiceConfig withDatastoreCallbacks(DatastoreCallbacks datastoreCallbacks) {
492 Preconditions.checkNotNull(datastoreCallbacks);
493 return new DatastoreServiceConfig(datastoreCallbacks);
497 * Helper method for creating a {@link DatastoreServiceConfig}
498 * instance with default values: Implicit transactions are disabled, reads
499 * execute with {@link Consistency#STRONG}, and no deadline is
500 * provided. When no deadline is provided, datastore rpcs execute with the
501 * system-defined deadline.
503 * @return The newly created DatastoreServiceConfig instance.
505 public static DatastoreServiceConfig withDefaults() {
506 return new DatastoreServiceConfig((DatastoreCallbacks) null);
509 private Builder() {}