1 // Copyright 2010 Google Inc. All Rights Reserved.
3 package com
.google
.appengine
.api
.datastore
;
5 import static com
.google
.common
.base
.Preconditions
.checkArgument
;
7 import com
.google
.appengine
.api
.datastore
.EntityCachingStrategy
.NoOpEntityCachingStrategy
;
8 import com
.google
.apphosting
.api
.ApiProxy
;
9 import com
.google
.apphosting
.datastore
.DatastoreV3Pb
;
11 import java
.util
.concurrent
.Future
;
12 import java
.util
.logging
.Logger
;
15 * State and behavior that is common to both synchronous and asynchronous
16 * Datastore API implementations.
19 abstract class BaseDatastoreServiceImpl
{
21 * It doesn't actually matter what this value is, the back end will set its
22 * own deadline. All that matters is that we set a value.
24 static final long ARBITRARY_FAILOVER_READ_MS
= -1;
27 * User-provided config options.
29 protected final DatastoreServiceConfig datastoreServiceConfig
;
32 * Config that we'll pass to all api calls.
34 final ApiProxy
.ApiConfig apiConfig
;
37 * Knows which transaction to use when the user does not explicitly provide
40 final TransactionStack defaultTxnProvider
;
42 EntityCachingStrategy entityCachingStrategy
;
44 final Logger logger
= Logger
.getLogger(getClass().getName());
46 BaseDatastoreServiceImpl(DatastoreServiceConfig datastoreServiceConfig
,
47 TransactionStack defaultTxnProvider
) {
48 this.datastoreServiceConfig
= datastoreServiceConfig
;
49 this.apiConfig
= createApiConfig(datastoreServiceConfig
);
50 this.defaultTxnProvider
= defaultTxnProvider
;
51 if (datastoreServiceConfig
.getEntityCacheConfig() == null) {
52 entityCachingStrategy
= NoOpEntityCachingStrategy
.INSTANCE
;
54 entityCachingStrategy
= EntityCachingStrategy
.createStrategy(datastoreServiceConfig
);
58 private ApiProxy
.ApiConfig
createApiConfig(DatastoreServiceConfig config
) {
59 ApiProxy
.ApiConfig apiConfig
= new ApiProxy
.ApiConfig();
60 apiConfig
.setDeadlineInSeconds(config
.getDeadline());
64 @SuppressWarnings("deprecation")
65 static void validateQuery(Query query
) {
66 checkArgument(query
.getFilterPredicates().isEmpty() || query
.getFilter() == null,
67 "A query cannot have both a filter and filter predicates set.");
68 checkArgument(query
.getProjections().isEmpty() || !query
.isKeysOnly(),
69 "A query cannot have both projections and keys-only set.");
73 * Return the current transaction if one already exists, otherwise create
74 * a new transaction or throw an exception according to the
75 * {@link ImplicitTransactionManagementPolicy}.
77 GetOrCreateTransactionResult
getOrCreateTransaction() {
78 Transaction currentTxn
= getCurrentTransaction(null);
79 if (currentTxn
!= null) {
80 return new GetOrCreateTransactionResult(false, currentTxn
);
83 switch(datastoreServiceConfig
.getImplicitTransactionManagementPolicy()) {
85 return new GetOrCreateTransactionResult(false, null);
87 return new GetOrCreateTransactionResult(true, beginTransactionInternal(
88 TransactionOptions
.Builder
.withDefaults(), false));
90 final String msg
= "Unexpected Transaction Creation Policy: " +
91 datastoreServiceConfig
.getImplicitTransactionManagementPolicy();
93 throw new IllegalArgumentException(msg
);
97 static DatastoreV3Pb
.Transaction
localTxnToRemoteTxn(Transaction local
) {
98 DatastoreV3Pb
.Transaction remote
= new DatastoreV3Pb
.Transaction();
99 remote
.setApp(local
.getApp());
100 remote
.setHandle(Long
.parseLong(local
.getId()));
104 Transaction
beginTransactionInternal(TransactionOptions options
, boolean isExplicit
) {
105 DatastoreV3Pb
.Transaction remoteTxn
= new DatastoreV3Pb
.Transaction();
106 DatastoreV3Pb
.BeginTransactionRequest request
= new DatastoreV3Pb
.BeginTransactionRequest();
107 request
.setApp(datastoreServiceConfig
.getAppIdNamespace().getAppId());
108 request
.setAllowMultipleEg(options
.isXG());
110 Future
<DatastoreV3Pb
.Transaction
> future
=
111 DatastoreApiHelper
.makeAsyncCall(apiConfig
, "BeginTransaction", request
, remoteTxn
);
113 Transaction localTxn
= new TransactionImpl(apiConfig
, request
.getApp(), future
,
114 defaultTxnProvider
, datastoreServiceConfig
.getDatastoreCallbacks(), entityCachingStrategy
,
118 defaultTxnProvider
.push(localTxn
);
123 public Transaction
getCurrentTransaction() {
124 return defaultTxnProvider
.peek();
127 public Transaction
getCurrentTransaction(Transaction returnedIfNoTxn
) {
128 return defaultTxnProvider
.peek(returnedIfNoTxn
);
131 DatastoreServiceConfig
getDatastoreServiceConfig() {
132 return datastoreServiceConfig
;