@Override public RunQueryResponse runQuery(RunQueryRequest request) { try { return client.runQuery(request); } catch (com.google.datastore.v1.client.DatastoreException ex) { throw translate(ex); } } }
@Override public RunQueryResponse runQuery(RunQueryRequest request) { try { return client.runQuery(request); } catch (com.google.datastore.v1.client.DatastoreException ex) { throw translate(ex); } } }
private RunQueryResponse runQueryWithRetries(RunQueryRequest request) throws Exception { Sleeper sleeper = Sleeper.DEFAULT; BackOff backoff = RUNQUERY_BACKOFF.backoff(); while (true) { try { RunQueryResponse response = datastore.runQuery(request); rpcSuccesses.inc(); return response; } catch (DatastoreException exception) { rpcErrors.inc(); if (NON_RETRYABLE_ERRORS.contains(exception.getCode())) { throw exception; } if (!BackOffUtils.next(sleeper, backoff)) { LOG.error("Aborting after {} retries.", MAX_RETRIES); throw exception; } } } }
/** * Run a query on the datastore. * * @return The entities returned by the query. * @throws DatastoreException on error */ private List<Entity> runQuery(Query query) throws DatastoreException { RunQueryRequest.Builder request = RunQueryRequest.newBuilder(); request.setQuery(query); RunQueryResponse response = datastore.runQuery(request.build()); if (response.getBatch().getMoreResults() == QueryResultBatch.MoreResultsType.NOT_FINISHED) { System.err.println("WARNING: partial results\n"); } List<EntityResult> results = response.getBatch().getEntityResultsList(); List<Entity> entities = new ArrayList<Entity>(results.size()); for (EntityResult result : results) { entities.add(result.getEntity()); } return entities; } }
/** * Tests {@link DatastoreV1.Read#getEstimatedSizeBytes} to fetch and return estimated size for a * query. */ @Test public void testEstimatedSizeBytes() throws Exception { long entityBytes = 100L; // In seconds long timestamp = 1234L; RunQueryRequest latestTimestampRequest = makeRequest(makeLatestTimestampQuery(NAMESPACE), NAMESPACE); RunQueryResponse latestTimestampResponse = makeLatestTimestampResponse(timestamp); // Per Kind statistics request and response RunQueryRequest statRequest = makeRequest(makeStatKindQuery(NAMESPACE, timestamp), NAMESPACE); RunQueryResponse statResponse = makeStatKindResponse(entityBytes); when(mockDatastore.runQuery(latestTimestampRequest)).thenReturn(latestTimestampResponse); when(mockDatastore.runQuery(statRequest)).thenReturn(statResponse); assertEquals(entityBytes, getEstimatedSizeBytes(mockDatastore, QUERY, NAMESPACE)); verify(mockDatastore, times(1)).runQuery(latestTimestampRequest); verify(mockDatastore, times(1)).runQuery(statRequest); }
/** Translates a gql query string to {@link Query}. */ private static Query translateGqlQuery(String gql, Datastore datastore, String namespace) throws DatastoreException { GqlQuery gqlQuery = GqlQuery.newBuilder().setQueryString(gql).setAllowLiterals(true).build(); RunQueryRequest req = makeRequest(gqlQuery, namespace); return datastore.runQuery(req).getQuery(); }
/** Tests {@link SplitQueryFn} when no query splits is specified. */ @Test public void testSplitQueryFnWithoutNumSplits() throws Exception { // Force SplitQueryFn to compute the number of query splits int numSplits = 0; int expectedNumSplits = 20; long entityBytes = expectedNumSplits * DEFAULT_BUNDLE_SIZE_BYTES; // In seconds long timestamp = 1234L; RunQueryRequest latestTimestampRequest = makeRequest(makeLatestTimestampQuery(NAMESPACE), NAMESPACE); RunQueryResponse latestTimestampResponse = makeLatestTimestampResponse(timestamp); // Per Kind statistics request and response RunQueryRequest statRequest = makeRequest(makeStatKindQuery(NAMESPACE, timestamp), NAMESPACE); RunQueryResponse statResponse = makeStatKindResponse(entityBytes); when(mockDatastore.runQuery(latestTimestampRequest)).thenReturn(latestTimestampResponse); when(mockDatastore.runQuery(statRequest)).thenReturn(statResponse); when(mockQuerySplitter.getSplits( eq(QUERY), any(PartitionId.class), eq(expectedNumSplits), any(Datastore.class))) .thenReturn(splitQuery(QUERY, expectedNumSplits)); SplitQueryFn splitQueryFn = new SplitQueryFn(V_1_OPTIONS, numSplits, mockDatastoreFactory); DoFnTester<Query, Query> doFnTester = DoFnTester.of(splitQueryFn); doFnTester.setCloningBehavior(CloningBehavior.DO_NOT_CLONE); List<Query> queries = doFnTester.processBundle(QUERY); assertEquals(expectedNumSplits, queries.size()); verify(mockQuerySplitter, times(1)) .getSplits(eq(QUERY), any(PartitionId.class), eq(expectedNumSplits), any(Datastore.class)); verify(mockDatastore, times(1)).runQuery(latestTimestampRequest); verify(mockDatastore, times(1)).runQuery(statRequest); }
/** Helper function to run a test reading from a {@link ReadFn}. */ private void readFnTest(int numEntities) throws Exception { // An empty query to read entities. Query query = Query.newBuilder().setLimit(Int32Value.newBuilder().setValue(numEntities)).build(); // Use mockResponseForQuery to generate results. when(mockDatastore.runQuery(any(RunQueryRequest.class))) .thenAnswer( invocationOnMock -> { Query q = ((RunQueryRequest) invocationOnMock.getArguments()[0]).getQuery(); return mockResponseForQuery(q); }); ReadFn readFn = new ReadFn(V_1_OPTIONS, mockDatastoreFactory); DoFnTester<Query, Entity> doFnTester = DoFnTester.of(readFn); /** * Although Datastore client is marked transient in {@link ReadFn}, when injected through mock * factory using a when clause for unit testing purposes, it is not serializable because it * doesn't have a no-arg constructor. Thus disabling the cloning to prevent the test object from * being serialized. */ doFnTester.setCloningBehavior(CloningBehavior.DO_NOT_CLONE); List<Entity> entities = doFnTester.processBundle(query); int expectedNumCallsToRunQuery = (int) Math.ceil((double) numEntities / QUERY_BATCH_LIMIT); verify(mockDatastore, times(expectedNumCallsToRunQuery)).runQuery(any(RunQueryRequest.class)); // Validate the number of results. assertEquals(numEntities, entities.size()); }
@Test public void testTranslateGqlQueryWithNoLimit() throws Exception { String gql = "SELECT * from DummyKind"; String gqlWithZeroLimit = gql + " LIMIT 0"; GqlQuery gqlQueryWithZeroLimit = GqlQuery.newBuilder().setQueryString(gqlWithZeroLimit).setAllowLiterals(true).build(); RunQueryRequest gqlRequestWithZeroLimit = makeRequest(gqlQueryWithZeroLimit, V_1_OPTIONS.getNamespace()); when(mockDatastore.runQuery(gqlRequestWithZeroLimit)) .thenReturn(RunQueryResponse.newBuilder().setQuery(QUERY).build()); assertEquals( translateGqlQueryWithLimitCheck(gql, mockDatastore, V_1_OPTIONS.getNamespace()), QUERY); verify(mockDatastore, times(1)).runQuery(gqlRequestWithZeroLimit); }
@Test public void testTranslateGqlQueryWithLimit() throws Exception { String gql = "SELECT * from DummyKind LIMIT 10"; String gqlWithZeroLimit = gql + " LIMIT 0"; GqlQuery gqlQuery = GqlQuery.newBuilder().setQueryString(gql).setAllowLiterals(true).build(); GqlQuery gqlQueryWithZeroLimit = GqlQuery.newBuilder().setQueryString(gqlWithZeroLimit).setAllowLiterals(true).build(); RunQueryRequest gqlRequest = makeRequest(gqlQuery, V_1_OPTIONS.getNamespace()); RunQueryRequest gqlRequestWithZeroLimit = makeRequest(gqlQueryWithZeroLimit, V_1_OPTIONS.getNamespace()); when(mockDatastore.runQuery(gqlRequestWithZeroLimit)) .thenThrow( new DatastoreException( "runQuery", Code.INVALID_ARGUMENT, "invalid query", // dummy new RuntimeException())); when(mockDatastore.runQuery(gqlRequest)) .thenReturn(RunQueryResponse.newBuilder().setQuery(QUERY).build()); assertEquals( translateGqlQueryWithLimitCheck(gql, mockDatastore, V_1_OPTIONS.getNamespace()), QUERY); verify(mockDatastore, times(1)).runQuery(gqlRequest); verify(mockDatastore, times(1)).runQuery(gqlRequestWithZeroLimit); }
RunQueryResponse response = datastore.runQuery(request); LOG.debug("Query for per-kind statistics took {}ms", System.currentTimeMillis() - now);
/** * Cloud Datastore system tables with statistics are periodically updated. This method fetches * the latest timestamp (in microseconds) of statistics update using the {@code __Stat_Total__} * table. */ private static long queryLatestStatisticsTimestamp( Datastore datastore, @Nullable String namespace) throws DatastoreException { Query.Builder query = Query.newBuilder(); // Note: namespace either being null or empty represents the default namespace, in which // case we treat it as not provided by the user. if (Strings.isNullOrEmpty(namespace)) { query.addKindBuilder().setName("__Stat_Total__"); } else { query.addKindBuilder().setName("__Stat_Ns_Total__"); } query.addOrder(makeOrder("timestamp", DESCENDING)); query.setLimit(Int32Value.newBuilder().setValue(1)); RunQueryRequest request = makeRequest(query.build(), namespace); RunQueryResponse response = datastore.runQuery(request); QueryResultBatch batch = response.getBatch(); if (batch.getEntityResultsCount() == 0) { throw new NoSuchElementException("Datastore total statistics unavailable"); } Entity entity = batch.getEntityResults(0).getEntity(); return entity.getProperties().get("timestamp").getTimestampValue().getSeconds() * 1000000; }
/** Tests that {@link ReadFn} retries after an error. */ @Test public void testReadFnRetriesErrors() throws Exception { // An empty query to read entities. Query query = Query.newBuilder().setLimit(Int32Value.newBuilder().setValue(1)).build(); // Use mockResponseForQuery to generate results. when(mockDatastore.runQuery(any(RunQueryRequest.class))) .thenThrow(new DatastoreException("RunQuery", Code.DEADLINE_EXCEEDED, "", null)) .thenAnswer( invocationOnMock -> { Query q = ((RunQueryRequest) invocationOnMock.getArguments()[0]).getQuery(); return mockResponseForQuery(q); }); ReadFn readFn = new ReadFn(V_1_OPTIONS, mockDatastoreFactory); DoFnTester<Query, Entity> doFnTester = DoFnTester.of(readFn); doFnTester.setCloningBehavior(CloningBehavior.DO_NOT_CLONE); doFnTester.processBundle(query); }
.setQuery(scatterPointQuery) .build(); batch = datastore.runQuery(scatterRequest).getBatch(); for (EntityResult result : batch.getEntityResultsList()) { keySplits.add(result.getEntity().getKey());
.setQuery(scatterPointQuery) .build(); batch = datastore.runQuery(scatterRequest).getBatch(); for (EntityResult result : batch.getEntityResultsList()) { keySplits.add(result.getEntity().getKey());
private Iterator<EntityResult> getIteratorAndMoveCursor() throws DatastoreException { Query.Builder query = this.query.toBuilder(); query.setLimit(Int32Value.newBuilder().setValue(QUERY_BATCH_LIMIT)); if (currentBatch != null && !currentBatch.getEndCursor().isEmpty()) { query.setStartCursor(currentBatch.getEndCursor()); } RunQueryRequest request = makeRequest(query.build(), namespace); RunQueryResponse response = datastore.runQuery(request); currentBatch = response.getBatch(); int numFetch = currentBatch.getEntityResultsCount(); // All indications from the API are that there are/may be more results. moreResults = ((numFetch == QUERY_BATCH_LIMIT) || (currentBatch.getMoreResults() == NOT_FINISHED)); // May receive a batch of 0 results if the number of records is a multiple // of the request limit. if (numFetch == 0) { return null; } return currentBatch.getEntityResultsList().iterator(); } }