Skip to content

Commit e55d3ed

Browse files
fix: verify partition count before invoking GetPartition RPC
1 parent e6157b5 commit e55d3ed

2 files changed

Lines changed: 49 additions & 28 deletions

File tree

google-cloud-firestore/src/main/java/com/google/cloud/firestore/CollectionGroup.java

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.google.api.gax.rpc.ApiExceptions;
2121
import com.google.api.gax.rpc.ApiStreamObserver;
2222
import com.google.cloud.firestore.v1.FirestoreClient;
23+
import com.google.common.base.Preconditions;
2324
import com.google.firestore.v1.Cursor;
2425
import com.google.firestore.v1.PartitionQueryRequest;
2526
import io.opencensus.common.Scope;
@@ -53,42 +54,51 @@ public class CollectionGroup extends Query {
5354
*/
5455
public void getPartitions(
5556
long desiredPartitionCount, ApiStreamObserver<QueryPartition> observer) {
57+
Preconditions.checkArgument(
58+
desiredPartitionCount > 0, "Desired partition count must be one or greater");
59+
5660
// Partition queries require explicit ordering by __name__.
5761
Query queryWithDefaultOrder = orderBy(FieldPath.DOCUMENT_ID);
5862

59-
PartitionQueryRequest.Builder request = PartitionQueryRequest.newBuilder();
60-
request.setStructuredQuery(queryWithDefaultOrder.buildQuery());
61-
request.setParent(options.getParentPath().toString());
63+
if (desiredPartitionCount == 1) {
64+
// Short circuit if the user only requested a single partition.
65+
observer.onNext(new QueryPartition(queryWithDefaultOrder, null, null));
66+
} else {
67+
PartitionQueryRequest.Builder request = PartitionQueryRequest.newBuilder();
68+
request.setStructuredQuery(queryWithDefaultOrder.buildQuery());
69+
request.setParent(options.getParentPath().toString());
6270

63-
// Since we are always returning an extra partition (with en empty endBefore cursor), we
64-
// reduce the desired partition count by one.
65-
request.setPartitionCount(desiredPartitionCount - 1);
71+
// Since we are always returning an extra partition (with en empty endBefore cursor), we
72+
// reduce the desired partition count by one.
73+
request.setPartitionCount(desiredPartitionCount - 1);
6674

67-
final FirestoreClient.PartitionQueryPagedResponse response;
68-
final TraceUtil traceUtil = TraceUtil.getInstance();
69-
Span span = traceUtil.startSpan(TraceUtil.SPAN_NAME_PARTITIONQUERY);
70-
try (Scope scope = traceUtil.getTracer().withSpan(span)) {
71-
response =
72-
ApiExceptions.callAndTranslateApiException(
73-
rpcContext.sendRequest(
74-
request.build(), rpcContext.getClient().partitionQueryPagedCallable()));
75-
} catch (ApiException exception) {
76-
span.setStatus(Status.UNKNOWN.withDescription(exception.getMessage()));
77-
throw FirestoreException.apiException(exception);
78-
} finally {
79-
span.end(TraceUtil.END_SPAN_OPTIONS);
80-
}
75+
final FirestoreClient.PartitionQueryPagedResponse response;
76+
final TraceUtil traceUtil = TraceUtil.getInstance();
77+
Span span = traceUtil.startSpan(TraceUtil.SPAN_NAME_PARTITIONQUERY);
78+
try (Scope scope = traceUtil.getTracer().withSpan(span)) {
79+
response =
80+
ApiExceptions.callAndTranslateApiException(
81+
rpcContext.sendRequest(
82+
request.build(), rpcContext.getClient().partitionQueryPagedCallable()));
83+
} catch (ApiException exception) {
84+
span.setStatus(Status.UNKNOWN.withDescription(exception.getMessage()));
85+
throw FirestoreException.apiException(exception);
86+
} finally {
87+
span.end(TraceUtil.END_SPAN_OPTIONS);
88+
}
8189

82-
@Nullable Object[] lastCursor = null;
83-
for (Cursor cursor : response.iterateAll()) {
84-
Object[] decodedCursorValue = new Object[cursor.getValuesCount()];
85-
for (int i = 0; i < cursor.getValuesCount(); ++i) {
86-
decodedCursorValue[i] = UserDataConverter.decodeValue(rpcContext, cursor.getValues(i));
90+
@Nullable Object[] lastCursor = null;
91+
for (Cursor cursor : response.iterateAll()) {
92+
Object[] decodedCursorValue = new Object[cursor.getValuesCount()];
93+
for (int i = 0; i < cursor.getValuesCount(); ++i) {
94+
decodedCursorValue[i] = UserDataConverter.decodeValue(rpcContext, cursor.getValues(i));
95+
}
96+
observer.onNext(new QueryPartition(queryWithDefaultOrder, lastCursor, decodedCursorValue));
97+
lastCursor = decodedCursorValue;
8798
}
88-
observer.onNext(new QueryPartition(queryWithDefaultOrder, lastCursor, decodedCursorValue));
89-
lastCursor = decodedCursorValue;
99+
observer.onNext(new QueryPartition(queryWithDefaultOrder, lastCursor, null));
90100
}
91-
observer.onNext(new QueryPartition(queryWithDefaultOrder, lastCursor, null));
101+
92102
observer.onCompleted();
93103
}
94104
}

google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,17 @@ public void emptyPartitionedQuery() throws Exception {
603603
assertNull(partitions.get(0).getEndBefore());
604604
}
605605

606+
@Test
607+
public void validatesPartitionCount() {
608+
StreamConsumer<QueryPartition> consumer = new StreamConsumer<>();
609+
try {
610+
firestore.collectionGroup(randomColl.getId()).getPartitions(0, consumer);
611+
fail();
612+
} catch (IllegalArgumentException e) {
613+
assertEquals("Desired partition count must be one or greater", e.getMessage());
614+
}
615+
}
616+
606617
@Test
607618
public void failedTransaction() {
608619
try {

0 commit comments

Comments
 (0)