Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / appengine / api / datastore / DatastoreServiceConfig.java
blob7dd9cadd6059ac4defd3b20601b4003ff4b46cdc
1 // Copyright 2010 Google Inc. All Rights Reserved.
2 package com.google.appengine.api.datastore;
4 import com.google.appengine.api.datastore.ReadPolicy.Consistency;
5 import com.google.common.base.Preconditions;
7 import java.io.ByteArrayInputStream;
8 import java.io.InputStream;
10 /**
11 * User-configurable properties of the datastore.
13 * Notes on usage:<br>
14 * The recommended way to instantiate a {@code DatastoreServiceConfig} object
15 * is to statically import {@link Builder}.* and invoke a static creation
16 * method followed by an instance mutator (if needed):
18 * <pre>
19 * import static com.google.appengine.api.datastore.DatastoreServiceConfig.Builder.*;
20 * import com.google.appengine.api.datastore.ReadPolicy.Consistency;
22 * ...
24 * // eventually consistent reads
25 * DatastoreServiceConfig config = withReadPolicy(new ReadPolicy(Consistency.EVENTUAL));
27 * // eventually consistent reads with a 5 second deadline
28 * DatastoreServiceConfig config =
29 * withReadPolicy(new ReadPolicy(Consistency.EVENTUAL)).deadline(5.0);
30 * </pre>
33 public final class DatastoreServiceConfig {
34 /**
35 * The default maximum size a request RPC can be.
37 static final int DEFAULT_RPC_SIZE_LIMIT_BYTES = 1024 * 1024;
39 /**
40 * The default maximum number of keys allowed in a Get request.
42 static final int DEFAULT_MAX_BATCH_GET_KEYS = 1000;
44 /**
45 * The default maximum number of entities allowed in a Put or Delete request.
47 static final int DEFAULT_MAX_BATCH_WRITE_ENTITIES = 500;
49 /**
50 * Name of a system property that users can specify to control the default
51 * max entity groups per rpc.
53 static final String DEFAULT_MAX_ENTITY_GROUPS_PER_RPC_SYS_PROP =
54 "appengine.datastore.defaultMaxEntityGroupsPerRpc";
56 /**
57 * The default number of max entity groups per rpc.
59 static final int DEFAULT_MAX_ENTITY_GROUPS_PER_RPC = getDefaultMaxEntityGroupsPerRpc();
61 static final String CALLBACKS_CONFIG_SYS_PROP = "appengine.datastore.callbacksConfig";
63 static volatile DatastoreCallbacks CALLBACKS = null;
65 /**
66 * Keep in sync with
67 * com.google.appengine.tools.compilation.DatastoreCallbacksProcessor.CALLBACKS_CONFIG_FILE
69 private static final String CALLBACKS_CONFIG_FILE = "/META-INF/datastorecallbacks.xml";
71 static int getDefaultMaxEntityGroupsPerRpc() {
72 return getDefaultMaxEntityGroupsPerRpc(DEFAULT_MAX_ENTITY_GROUPS_PER_RPC_SYS_PROP, 10);
75 /**
76 * Returns the value of the given system property as an int, or return the
77 * default value if there is no property with that name set.
79 static int getDefaultMaxEntityGroupsPerRpc(String sysPropName, int defaultVal) {
80 String sysPropVal = System.getProperty(sysPropName);
81 return sysPropVal == null ? defaultVal : Integer.parseInt(sysPropVal);
84 private static InputStream getCallbacksConfigInputStream() {
85 InputStream is;
86 String callbacksConfig = System.getProperty(CALLBACKS_CONFIG_SYS_PROP);
87 if (callbacksConfig != null) {
88 is = new ByteArrayInputStream(callbacksConfig.getBytes());
89 } else {
90 is = DatastoreServiceConfig.class.getResourceAsStream(CALLBACKS_CONFIG_FILE);
92 return is;
95 private final DatastoreCallbacks instanceDatastoreCallbacks;
97 private ImplicitTransactionManagementPolicy implicitTransactionManagementPolicy =
98 ImplicitTransactionManagementPolicy.NONE;
100 private ReadPolicy readPolicy = new ReadPolicy(Consistency.STRONG);
102 private Double deadline;
104 private AppIdNamespace appIdNamespace;
106 private int maxRpcSizeBytes = DEFAULT_RPC_SIZE_LIMIT_BYTES;
107 private int maxBatchWriteEntities = DEFAULT_MAX_BATCH_WRITE_ENTITIES;
108 private int maxBatchReadEntities = DEFAULT_MAX_BATCH_GET_KEYS;
109 private int maxEntityGroupsPerRpc = DEFAULT_MAX_ENTITY_GROUPS_PER_RPC;
112 * Cannot be directly instantiated, use {@link Builder} instead.
114 * @param datastoreCallbacks the callback methods to invoke on specific datastore operations.
115 * If null the datastore callbacks are derived from {@link #getCallbacksConfigInputStream}.
117 private DatastoreServiceConfig( DatastoreCallbacks datastoreCallbacks) {
118 instanceDatastoreCallbacks = datastoreCallbacks;
122 * Copy constructor
124 DatastoreServiceConfig(DatastoreServiceConfig config) {
125 implicitTransactionManagementPolicy = config.implicitTransactionManagementPolicy;
126 readPolicy = config.readPolicy;
127 deadline = config.deadline;
128 maxRpcSizeBytes = config.maxRpcSizeBytes;
129 maxBatchWriteEntities = config.maxBatchWriteEntities;
130 maxBatchReadEntities = config.maxBatchReadEntities;
131 maxEntityGroupsPerRpc = config.maxEntityGroupsPerRpc;
132 instanceDatastoreCallbacks = config.instanceDatastoreCallbacks;
133 appIdNamespace = config.appIdNamespace;
137 * Sets the implicit transaction management policy.
138 * @param p the implicit transaction management policy to set.
139 * @return {@code this} (for chaining)
141 public DatastoreServiceConfig implicitTransactionManagementPolicy(
142 ImplicitTransactionManagementPolicy p) {
143 if (p == null) {
144 throw new NullPointerException("implicit transaction management policy must not be null");
146 implicitTransactionManagementPolicy = p;
147 return this;
151 * Sets the read policy.
152 * @param readPolicy the read policy to set.
153 * @return {@code this} (for chaining)
155 public DatastoreServiceConfig readPolicy(ReadPolicy readPolicy) {
156 if (readPolicy == null) {
157 throw new NullPointerException("read policy must not be null");
159 this.readPolicy = readPolicy;
160 return this;
164 * Sets the deadline, in seconds, for all rpcs initiated by the
165 * {@link DatastoreService} with which this config is associated.
166 * @param deadline the deadline to set.
167 * @throws IllegalArgumentException if deadline is not positive
168 * @return {@code this} (for chaining)
170 public DatastoreServiceConfig deadline(double deadline) {
171 if (deadline <= 0.0) {
172 throw new IllegalArgumentException("deadline must be > 0, got " + deadline);
174 this.deadline = deadline;
175 return this;
178 DatastoreServiceConfig appIdNamespace(AppIdNamespace appIdNamespace) {
179 this.appIdNamespace = appIdNamespace;
180 return this;
184 * Sets the maximum number of entities that can be modified in a single RPC.
185 * @param maxBatchWriteEntities the limit to set
186 * @throws IllegalArgumentException if maxBatchWriteEntities is not greater
187 * than zero
188 * @return {@code this} (for chaining)
190 DatastoreServiceConfig maxBatchWriteEntities(int maxBatchWriteEntities) {
191 if (maxBatchWriteEntities <= 0) {
192 throw new IllegalArgumentException("maxBatchWriteEntities must be > 0, got "
193 + maxBatchWriteEntities);
195 this.maxBatchWriteEntities = maxBatchWriteEntities;
196 return this;
200 * Sets the maximum number of entities that can be read in a single RPC.
201 * @param maxBatchReadEntities the limit to set
202 * @throws IllegalArgumentException if maxBatchReadEntities is not greater
203 * than zero
204 * @return {@code this} (for chaining)
206 DatastoreServiceConfig maxBatchReadEntities(int maxBatchReadEntities) {
207 if (maxBatchReadEntities <= 0) {
208 throw new IllegalArgumentException("maxBatchReadEntities must be > 0, got "
209 + maxBatchReadEntities);
211 this.maxBatchReadEntities = maxBatchReadEntities;
212 return this;
216 * Sets the maximum size in bytes an RPC can be.
218 * The size of the request can be exceeded if the RPC cannot be split enough
219 * to respect this limit. However there may be a hard limit on the RPC which,
220 * if exceeded, will cause an exception to be thrown.
222 * @param maxRpcSizeBytes the limit to set
223 * @throws IllegalArgumentException if maxRpcSizeBytes is not positive
224 * @return {@code this} (for chaining)
226 DatastoreServiceConfig maxRpcSizeBytes(int maxRpcSizeBytes) {
227 if (maxRpcSizeBytes < 0) {
228 throw new IllegalArgumentException("maxRpcSizeBytes must be >= 0, got "
229 + maxRpcSizeBytes);
231 this.maxRpcSizeBytes = maxRpcSizeBytes;
232 return this;
236 * Sets the maximum number of entity groups that can be represented in a
237 * single rpc.
239 * For a non-transactional operation that involves more entity groups than the
240 * maximum, the operation will be performed by executing multiple, asynchronous
241 * rpcs to the datastore, each of which has no more entity groups represented
242 * than the maximum. So, if a put() operation has 8 entity groups and the
243 * maximum is 3, we will send 3 rpcs, 2 with 3 entity groups and 1 with 2
244 * entity groups. This is a performance optimization - in many cases
245 * multiple, small, asynchronous rpcs will finish faster than a single large
246 * asynchronous rpc. The optimal value for this property will be
247 * application-specific, so experimentation is encouraged.
249 * @param maxEntityGroupsPerRpc the maximum number of entity groups per rpc
250 * @throws IllegalArgumentException if maxEntityGroupsPerRpc is not greater
251 * than zero
252 * @return {@code this} (for chaining)
254 public DatastoreServiceConfig maxEntityGroupsPerRpc(int maxEntityGroupsPerRpc) {
255 if (maxEntityGroupsPerRpc <= 0) {
256 throw new IllegalArgumentException("maxEntityGroupsPerRpc must be > 0, got "
257 + maxEntityGroupsPerRpc);
259 this.maxEntityGroupsPerRpc = maxEntityGroupsPerRpc;
260 return this;
264 * @return The {@code ImplicitTransactionManagementPolicy} to use.
266 public ImplicitTransactionManagementPolicy getImplicitTransactionManagementPolicy() {
267 return implicitTransactionManagementPolicy;
271 * @return The {@code ReadPolicy} to use.
273 public ReadPolicy getReadPolicy() {
274 return readPolicy;
278 * @return The maximum number of entity groups per rpc.
280 public Integer getMaxEntityGroupsPerRpc() {
281 return getMaxEntityGroupsPerRpcInternal();
284 int getMaxEntityGroupsPerRpcInternal() {
285 return maxEntityGroupsPerRpc;
289 * @return The deadline to use. Can be {@code null}.
291 public Double getDeadline() {
292 return deadline;
295 AppIdNamespace getAppIdNamespace() {
296 return appIdNamespace == null ? DatastoreApiHelper.getCurrentAppIdNamespace() : appIdNamespace;
299 boolean exceedsWriteLimits(int count, int size) {
300 return (count > maxBatchWriteEntities ||
301 (count > 1 && size > maxRpcSizeBytes));
304 boolean exceedsReadLimits(int count, int size) {
305 return (count > maxBatchReadEntities ||
306 (count > 1 && size > maxRpcSizeBytes));
309 DatastoreCallbacks getDatastoreCallbacks() {
310 if (instanceDatastoreCallbacks != null) {
311 return instanceDatastoreCallbacks;
314 if (CALLBACKS == null) {
315 InputStream is = getCallbacksConfigInputStream();
316 if (is == null) {
317 CALLBACKS = DatastoreCallbacks.NoOpDatastoreCallbacks.INSTANCE;
318 } else {
319 CALLBACKS = new DatastoreCallbacksImpl(is, false);
322 return CALLBACKS;
326 * Contains static creation methods for {@link DatastoreServiceConfig}.
328 public static final class Builder {
331 * Create a {@link DatastoreServiceConfig} with the given implicit
332 * transaction management policy.
333 * @param p the implicit transaction management policy to set.
334 * @return The newly created DatastoreServiceConfig instance.
336 public static DatastoreServiceConfig withImplicitTransactionManagementPolicy(
337 ImplicitTransactionManagementPolicy p) {
338 return withDefaults().implicitTransactionManagementPolicy(p);
342 * Create a {@link DatastoreServiceConfig} with the given read
343 * policy.
344 * @param readPolicy the read policy to set.
345 * @return The newly created DatastoreServiceConfig instance.
347 public static DatastoreServiceConfig withReadPolicy(ReadPolicy readPolicy) {
348 return withDefaults().readPolicy(readPolicy);
352 * Create a {@link DatastoreServiceConfig} with the given deadline, in
353 * seconds.
354 * @param deadline the deadline to set.
355 * @throws IllegalArgumentException if deadline is not positive
356 * @return The newly created DatastoreServiceConfig instance.
358 public static DatastoreServiceConfig withDeadline(double deadline) {
359 return withDefaults().deadline(deadline);
363 * Create a {@link DatastoreServiceConfig} with the given maximum entity
364 * groups per rpc.
365 * @param maxEntityGroupsPerRpc the maximum entity groups per rpc to set.
366 * @return The newly created DatastoreServiceConfig instance.
368 * @see DatastoreServiceConfig#maxEntityGroupsPerRpc(int)
370 public static DatastoreServiceConfig withMaxEntityGroupsPerRpc(int maxEntityGroupsPerRpc) {
371 return withDefaults().maxEntityGroupsPerRpc(maxEntityGroupsPerRpc);
375 * Helper method for creating a {@link DatastoreServiceConfig} instance with the
376 * specified {@code datastoreCallbacks}. The callbacks defined for the application are
377 * bypassed and the specified callbacks are used instead.
379 * @return The newly created DatastoreServiceConfig instance.
381 static DatastoreServiceConfig withDatastoreCallbacks(DatastoreCallbacks datastoreCallbacks) {
382 Preconditions.checkNotNull(datastoreCallbacks);
383 return new DatastoreServiceConfig(datastoreCallbacks);
387 * Helper method for creating a {@link DatastoreServiceConfig}
388 * instance with default values: Implicit transactions are disabled, reads
389 * execute with {@link Consistency#STRONG}, and no deadline is
390 * provided. When no deadline is provided, datastore rpcs execute with the
391 * system-defined deadline.
393 * @return The newly created DatastoreServiceConfig instance.
395 public static DatastoreServiceConfig withDefaults() {
396 return new DatastoreServiceConfig((DatastoreCallbacks) null);
399 private Builder() {}