/** * Returns an iterator over the next batch of records for the query and updates the cursor to * get the next batch as needed. Query has specified limit and offset from InputSplit. */ private Iterator<EntityResult> getIteratorAndMoveCursor() throws DatastoreException { Query.Builder query = source.query.toBuilder().clone(); query.setLimit(Math.min(userLimit, QUERY_BATCH_LIMIT)); if (currentBatch != null && currentBatch.hasEndCursor()) { query.setStartCursor(currentBatch.getEndCursor()); } RunQueryRequest request = source.makeRequest(query.build()); RunQueryResponse response = datastore.runQuery(request); currentBatch = response.getBatch(); // MORE_RESULTS_AFTER_LIMIT is not implemented yet: // https://groups.google.com/forum/#!topic/gcd-discuss/iNs6M1jA2Vw, so // use result count to determine if more results might exist. int numFetch = currentBatch.getEntityResultCount(); if (source.query.hasLimit()) { verify( userLimit >= numFetch, "Expected userLimit %s >= numFetch %s, because query limit %s should be <= userLimit", userLimit, numFetch, query.getLimit()); userLimit -= numFetch; } moreResults = // User-limit does not exist (so userLimit == MAX_VALUE) and/or has not been satisfied. (userLimit > 0) // All indications from the API are that there are/may be more results. && ((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.getEntityResultList().iterator(); }