Search in sources :

Example 1 with GetResponse

use of com.google.apphosting.datastore.DatastoreV3Pb.GetResponse in project appengine-java-standard by GoogleCloudPlatform.

the class RemoteApiServlet method executeTx.

private byte[] executeTx(Request request) {
    TransactionRequest txRequest = new TransactionRequest();
    parseFromBytes(txRequest, request.getRequestAsBytes());
    byte[] tx = beginTransaction(txRequest.isAllowMultipleEg());
    List<Precondition> preconditions = txRequest.preconditions();
    // Check transaction preconditions
    if (!preconditions.isEmpty()) {
        GetRequest getRequest = new GetRequest();
        for (Precondition precondition : preconditions) {
            OnestoreEntity.Reference key = precondition.getKey();
            OnestoreEntity.Reference requestKey = getRequest.addKey();
            requestKey.mergeFrom(key);
        }
        GetResponse getResponse = txGet(tx, getRequest);
        List<GetResponse.Entity> entities = getResponse.entitys();
        // TODO: Consider supporting deferred gets here.
        assert (entities.size() == preconditions.size());
        for (int i = 0; i < entities.size(); i++) {
            // Throw an exception if any of the Entities don't match the Precondition specification.
            assertEntityResultMatchesPrecondition(entities.get(i), preconditions.get(i));
        }
    }
    // Preconditions OK.
    // Perform puts.
    // a serialized VoidProto
    byte[] res = new byte[0];
    if (txRequest.hasPuts()) {
        PutRequest putRequest = txRequest.getPuts();
        parseFromBytes(putRequest.getMutableTransaction(), tx);
        res = ApiProxy.makeSyncCall("datastore_v3", "Put", putRequest.toByteArray());
    }
    // Perform deletes.
    if (txRequest.hasDeletes()) {
        DeleteRequest deleteRequest = txRequest.getDeletes();
        parseFromBytes(deleteRequest.getMutableTransaction(), tx);
        ApiProxy.makeSyncCall("datastore_v3", "Delete", deleteRequest.toByteArray());
    }
    // Commit transaction.
    ApiProxy.makeSyncCall("datastore_v3", "Commit", tx);
    return res;
}
Also used : OnestoreEntity(com.google.storage.onestore.v3.OnestoreEntity) Precondition(com.google.apphosting.utils.remoteapi.RemoteApiPb.TransactionRequest.Precondition) PutRequest(com.google.apphosting.datastore.DatastoreV3Pb.PutRequest) GetResponse(com.google.apphosting.datastore.DatastoreV3Pb.GetResponse) BeginTransactionRequest(com.google.apphosting.datastore.DatastoreV3Pb.BeginTransactionRequest) TransactionRequest(com.google.apphosting.utils.remoteapi.RemoteApiPb.TransactionRequest) GetRequest(com.google.apphosting.datastore.DatastoreV3Pb.GetRequest) OnestoreEntity(com.google.storage.onestore.v3.OnestoreEntity) DeleteRequest(com.google.apphosting.datastore.DatastoreV3Pb.DeleteRequest)

Example 2 with GetResponse

use of com.google.apphosting.datastore.DatastoreV3Pb.GetResponse in project appengine-java-standard by GoogleCloudPlatform.

the class RemoteApiServlet method txGet.

private static GetResponse txGet(byte[] tx, GetRequest request) {
    parseFromBytes(request.getMutableTransaction(), tx);
    GetResponse response = new GetResponse();
    byte[] resultBytes = ApiProxy.makeSyncCall("datastore_v3", "Get", request.toByteArray());
    parseFromBytes(response, resultBytes);
    return response;
}
Also used : GetResponse(com.google.apphosting.datastore.DatastoreV3Pb.GetResponse)

Example 3 with GetResponse

use of com.google.apphosting.datastore.DatastoreV3Pb.GetResponse in project appengine-java-standard by GoogleCloudPlatform.

the class AsyncDatastoreServiceImpl method doBatchGet.

@Override
protected final Future<Map<Key, Entity>> doBatchGet(@Nullable Transaction txn, final Set<Key> keysToGet, final Map<Key, Entity> resultMap) {
    // Initializing base request.
    final GetRequest baseReq = new GetRequest();
    baseReq.setAllowDeferred(true);
    if (txn != null) {
        TransactionImpl.ensureTxnActive(txn);
        baseReq.setTransaction(InternalTransactionV3.toProto(txn));
    }
    if (datastoreServiceConfig.getReadPolicy().getConsistency() == EVENTUAL) {
        baseReq.setFailoverMs(ARBITRARY_FAILOVER_READ_MS);
        // Allows the datastore to always use READ_CONSISTENT.
        baseReq.setStrong(false);
    }
    final boolean shouldUseMultipleBatches = txn == null && datastoreServiceConfig.getReadPolicy().getConsistency() != EVENTUAL;
    // Batch and issue the request(s).
    Iterator<GetRequest> batches = getByKeyBatcher.getBatches(keysToGet, baseReq, baseReq.getSerializedSize(), shouldUseMultipleBatches);
    List<Future<GetResponse>> futures = getByKeyBatcher.makeCalls(batches);
    return registerInTransaction(txn, new MultiFuture<GetResponse, Map<Key, Entity>>(futures) {

        /**
         * A Map from a Reference without an App Id specified to the corresponding Key that the
         * user requested. This is a workaround for the Remote API to support matching requested
         * Keys to Entities that may be from a different App Id .
         */
        private Map<Reference, Key> keyMapIgnoringAppId;

        @Override
        public Map<Key, Entity> get() throws InterruptedException, ExecutionException {
            try {
                aggregate(futures, null, null);
            } catch (TimeoutException e) {
                // Should never happen because we are passing null for the timeout params.
                throw new RuntimeException(e);
            }
            return resultMap;
        }

        @Override
        public Map<Key, Entity> get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
            aggregate(futures, timeout, unit);
            return resultMap;
        }

        /**
         * Aggregates the results of the given Futures and issues (synchronous) followup requests
         * if any results were deferred.
         *
         * @param currentFutures the Futures corresponding to the batches of the initial
         *     GetRequests.
         * @param timeout the timeout to use while waiting on the Future, or null for none.
         * @param timeoutUnit the unit of the timeout, or null for none.
         */
        private void aggregate(Iterable<Future<GetResponse>> currentFutures, @Nullable Long timeout, @Nullable TimeUnit timeoutUnit) throws ExecutionException, InterruptedException, TimeoutException {
            // Use a while (true) loop so that we can issue followup requests for any deferred keys.
            while (true) {
                List<Reference> deferredRefs = Lists.newLinkedList();
                // roundtrips)
                for (Future<GetResponse> currentFuture : currentFutures) {
                    GetResponse resp = getFutureWithOptionalTimeout(currentFuture, timeout, timeoutUnit);
                    addEntitiesToResultMap(resp);
                    deferredRefs.addAll(resp.deferreds());
                }
                if (deferredRefs.isEmpty()) {
                    // Done.
                    break;
                }
                // Some keys were deferred.  Issue followup requests, and loop again.
                Iterator<GetRequest> followupBatches = getByReferenceBatcher.getBatches(deferredRefs, baseReq, baseReq.getSerializedSize(), shouldUseMultipleBatches);
                currentFutures = getByReferenceBatcher.makeCalls(followupBatches);
            }
        }

        /**
         * Convenience method to get the result of a Future and optionally specify a timeout.
         *
         * @param future the Future to get.
         * @param timeout the timeout to use while waiting on the Future, or null for none.
         * @param timeoutUnit the unit of the timeout, or null for none.
         * @return the result of the Future.
         * @throws TimeoutException will only ever be thrown if a timeout is provided.
         */
        private GetResponse getFutureWithOptionalTimeout(Future<GetResponse> future, @Nullable Long timeout, @Nullable TimeUnit timeoutUnit) throws ExecutionException, InterruptedException, TimeoutException {
            if (timeout == null) {
                return future.get();
            } else {
                return future.get(timeout, timeoutUnit);
            }
        }

        /**
         * Adds the Entities from the GetResponse to the resultMap. Will omit Keys that were
         * missing. Handles Keys with different App Ids from the Entity.Key. See {@link
         * #findKeyFromRequestIgnoringAppId(Reference)}
         */
        private void addEntitiesToResultMap(GetResponse response) {
            for (GetResponse.Entity entityResult : response.entitys()) {
                if (entityResult.hasEntity()) {
                    Entity responseEntity = EntityTranslator.createFromPb(entityResult.getEntity());
                    Key responseKey = responseEntity.getKey();
                    // Hack for Remote API which rewrites App Ids on Keys.
                    if (!keysToGet.contains(responseKey)) {
                        responseKey = findKeyFromRequestIgnoringAppId(entityResult.getEntity().getKey());
                    }
                    resultMap.put(responseKey, responseEntity);
                }
            // Else, the Key was missing.
            }
        }

        /**
         * This is a hack to support calls going through the Remote API. The problem is:
         *
         * <p>The requested Key may have a local app id. The returned Entity may have a remote app
         * id.
         *
         * <p>In this case, we want to return a Map.Entry with {LocalKey, RemoteEntity}. This way,
         * the user can always do map.get(keyFromRequest).
         *
         * <p>This method will find the corresponding requested LocalKey for a RemoteKey by
         * ignoring the AppId field.
         *
         * <p>Note that we used to be able to rely on the order of the Response Entities matching
         * the order of Request Keys. We can no longer do so with the addition of Deferred
         * results.
         *
         * @param referenceFromResponse the reference from the Response that did not match any of
         *     the requested Keys. (May be mutated.)
         * @return the Key from the request that corresponds to the given Reference from the
         *     Response (ignoring AppId.)
         */
        private Key findKeyFromRequestIgnoringAppId(Reference referenceFromResponse) {
            // We'll create this Map lazily the first time, then cache it for future calls.
            if (keyMapIgnoringAppId == null) {
                keyMapIgnoringAppId = Maps.newHashMap();
                for (Key requestKey : keysToGet) {
                    Reference requestKeyAsRefWithoutApp = KeyTranslator.convertToPb(requestKey).clearApp();
                    keyMapIgnoringAppId.put(requestKeyAsRefWithoutApp, requestKey);
                }
            }
            // Note: mutating the input ref, but that's ok.
            Key result = keyMapIgnoringAppId.get(referenceFromResponse.clearApp());
            if (result == null) {
                // TODO: What should we do here?
                throw new DatastoreFailureException("Internal error");
            }
            return result;
        }
    });
}
Also used : GetRequest(com.google.apphosting.datastore.DatastoreV3Pb.GetRequest) Iterator(java.util.Iterator) TimeUnit(java.util.concurrent.TimeUnit) ArrayList(java.util.ArrayList) List(java.util.List) ExecutionException(java.util.concurrent.ExecutionException) TimeoutException(java.util.concurrent.TimeoutException) Reference(com.google.storage.onestore.v3.OnestoreEntity.Reference) GetResponse(com.google.apphosting.datastore.DatastoreV3Pb.GetResponse) Future(java.util.concurrent.Future) MultiFuture(com.google.appengine.api.datastore.FutureHelper.MultiFuture) ReorderingMultiFuture(com.google.appengine.api.datastore.Batcher.ReorderingMultiFuture) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map)

Example 4 with GetResponse

use of com.google.apphosting.datastore.DatastoreV3Pb.GetResponse in project appengine-java-standard by GoogleCloudPlatform.

the class LocalDatastoreService method get.

public GetResponse get(@SuppressWarnings("unused") Status status, GetRequest request) {
    GetResponse response = new GetResponse();
    LiveTxn liveTxn = null;
    for (Reference key : request.keys()) {
        validatePathComplete(key);
        String app = key.getApp();
        Path groupPath = getGroup(key);
        GetResponse.Entity responseEntity = response.addEntity();
        Profile profile = getOrCreateProfile(app);
        synchronized (profile) {
            Profile.EntityGroup eg = profile.getGroup(groupPath);
            if (request.hasTransaction()) {
                if (liveTxn == null) {
                    liveTxn = profile.getTxn(request.getTransaction().getHandle());
                }
                // this will throw an exception if we attempt to read from
                // the wrong entity group
                eg.addTransaction(liveTxn);
            }
            boolean eventualConsistency = request.hasFailoverMs() && liveTxn == null;
            EntityProto entity = pseudoKinds.get(liveTxn, eg, key, eventualConsistency);
            if (entity == PseudoKinds.NOT_A_PSEUDO_KIND) {
                VersionedEntity versionedEntity = eg.get(liveTxn, key, eventualConsistency);
                if (versionedEntity == null) {
                    entity = null;
                    if (!eventualConsistency) {
                        responseEntity.setVersion(profile.getReadTimestamp());
                    }
                } else {
                    entity = versionedEntity.entityProto();
                    responseEntity.setVersion(versionedEntity.version());
                }
            }
            if (entity != null) {
                responseEntity.getMutableEntity().copyFrom(entity);
                postprocessEntity(responseEntity.getMutableEntity());
            } else {
                responseEntity.getMutableKey().copyFrom(key);
            }
            // Give all entity groups with unapplied jobs the opportunity to catch
            // up.  Note that this will not impact the result we're about to return.
            profile.groom();
        }
    }
    return response;
}
Also used : Path(com.google.storage.onestore.v3.OnestoreEntity.Path) Reference(com.google.storage.onestore.v3.OnestoreEntity.Reference) ByteString(com.google.protobuf.ByteString) GetResponse(com.google.apphosting.datastore.DatastoreV3Pb.GetResponse) EntityProto(com.google.storage.onestore.v3.OnestoreEntity.EntityProto)

Example 5 with GetResponse

use of com.google.apphosting.datastore.DatastoreV3Pb.GetResponse in project appengine-java-standard by GoogleCloudPlatform.

the class RemoteApiServlet method executeTxQuery.

private byte[] executeTxQuery(Request request) {
    RemoteApiPb.TransactionQueryResult result = new RemoteApiPb.TransactionQueryResult();
    Query query = new Query();
    parseFromBytes(query, request.getRequestAsBytes());
    if (!query.hasAncestor()) {
        throw new ApiProxy.ApplicationException(BAD_REQUEST.getValue(), "No ancestor in transactional query.");
    }
    // Make __entity_group__ key
    OnestoreEntity.Reference egKey = result.getMutableEntityGroupKey().mergeFrom(query.getAncestor());
    OnestoreEntity.Path.Element root = egKey.getPath().getElement(0);
    egKey.getMutablePath().clearElement().addElement(root);
    OnestoreEntity.Path.Element egElement = new OnestoreEntity.Path.Element();
    egElement.setType("__entity_group__").setId(1);
    egKey.getMutablePath().addElement(egElement);
    // And then perform the transaction with the ancestor query and __entity_group__ fetch.
    byte[] tx = beginTransaction(false);
    parseFromBytes(query.getMutableTransaction(), tx);
    byte[] queryBytes = ApiProxy.makeSyncCall("datastore_v3", "RunQuery", query.toByteArray());
    parseFromBytes(result.getMutableResult(), queryBytes);
    GetRequest egRequest = new GetRequest();
    egRequest.addKey(egKey);
    GetResponse egResponse = txGet(tx, egRequest);
    if (egResponse.getEntity(0).hasEntity()) {
        result.setEntityGroup(egResponse.getEntity(0).getEntity());
    }
    rollback(tx);
    return result.toByteArray();
}
Also used : Query(com.google.apphosting.datastore.DatastoreV3Pb.Query) Element(com.google.storage.onestore.v3.OnestoreEntity.Path.Element) GetResponse(com.google.apphosting.datastore.DatastoreV3Pb.GetResponse) GetRequest(com.google.apphosting.datastore.DatastoreV3Pb.GetRequest) Element(com.google.storage.onestore.v3.OnestoreEntity.Path.Element) OnestoreEntity(com.google.storage.onestore.v3.OnestoreEntity)

Aggregations

GetResponse (com.google.apphosting.datastore.DatastoreV3Pb.GetResponse)5 GetRequest (com.google.apphosting.datastore.DatastoreV3Pb.GetRequest)3 OnestoreEntity (com.google.storage.onestore.v3.OnestoreEntity)2 Reference (com.google.storage.onestore.v3.OnestoreEntity.Reference)2 ReorderingMultiFuture (com.google.appengine.api.datastore.Batcher.ReorderingMultiFuture)1 MultiFuture (com.google.appengine.api.datastore.FutureHelper.MultiFuture)1 BeginTransactionRequest (com.google.apphosting.datastore.DatastoreV3Pb.BeginTransactionRequest)1 DeleteRequest (com.google.apphosting.datastore.DatastoreV3Pb.DeleteRequest)1 PutRequest (com.google.apphosting.datastore.DatastoreV3Pb.PutRequest)1 Query (com.google.apphosting.datastore.DatastoreV3Pb.Query)1 TransactionRequest (com.google.apphosting.utils.remoteapi.RemoteApiPb.TransactionRequest)1 Precondition (com.google.apphosting.utils.remoteapi.RemoteApiPb.TransactionRequest.Precondition)1 ByteString (com.google.protobuf.ByteString)1 EntityProto (com.google.storage.onestore.v3.OnestoreEntity.EntityProto)1 Path (com.google.storage.onestore.v3.OnestoreEntity.Path)1 Element (com.google.storage.onestore.v3.OnestoreEntity.Path.Element)1 ArrayList (java.util.ArrayList)1 Iterator (java.util.Iterator)1 LinkedHashMap (java.util.LinkedHashMap)1 List (java.util.List)1