Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
feat: add BulkWriter (#323)
New BulkWriter leveraging [`BatchWriteRequest`](https://github.com/googleapis/googleapis/blob/393d03088e368d79c8f4cd5e3610c7df0bb118bf/google/firestore/v1/firestore.proto#L866-L881) which allows for fine grain batch processing of documents. Where as existing `WriteBatch` is an atomic write (all succeed or all fail).

BulkWriter has been implemented to follow the 500/50/5 rule from [Firestore Best Practices: Ramping up traffic](https://firebase.google.com/docs/firestore/best-practices#ramping_up_traffic). If your application is already managing compliance with the 500/50/5 rule, you can configure the `BulkWriter` by using the `Firestore#bulkWriter(com.google.cloud.firestore.BulkWriterOptions)` method.
  • Loading branch information
Brian Chen committed Aug 11, 2020
1 parent 269e62c commit e7054df
Show file tree
Hide file tree
Showing 20 changed files with 2,254 additions and 77 deletions.
38 changes: 38 additions & 0 deletions google-cloud-firestore/clirr-ignored-differences.xml
Expand Up @@ -161,6 +161,44 @@
<method>com.google.cloud.firestore.Query collectionGroup(java.lang.String)</method>
<to>com.google.cloud.firestore.CollectionGroup</to>
</difference>

<!--
BulkWriter
-->
<difference>
<differenceType>7012</differenceType>
<className>com/google/cloud/firestore/Firestore</className>
<method>com.google.cloud.firestore.BulkWriter bulkWriter(*)</method>
</difference>
<difference>
<differenceType>7006</differenceType>
<className>com/google/cloud/firestore/UpdateBuilder</className>
<method>com.google.cloud.firestore.UpdateBuilder create(*)</method>
<to>java.lang.Object</to>
</difference>
<difference>
<differenceType>7006</differenceType>
<className>com/google/cloud/firestore/UpdateBuilder</className>
<method>com.google.cloud.firestore.UpdateBuilder delete(*)</method>
<to>java.lang.Object</to>
</difference>
<difference>
<differenceType>7006</differenceType>
<className>com/google/cloud/firestore/UpdateBuilder</className>
<method>com.google.cloud.firestore.UpdateBuilder set(*)</method>
<to>java.lang.Object</to>
</difference>
<difference>
<differenceType>7006</differenceType>
<className>com/google/cloud/firestore/UpdateBuilder</className>
<method>com.google.cloud.firestore.UpdateBuilder update(*)</method>
<to>java.lang.Object</to>
</difference>
<difference>
<differenceType>7012</differenceType>
<className>com/google/cloud/firestore/spi/v1/FirestoreRpc</className>
<method>com.google.api.gax.rpc.UnaryCallable batchWriteCallable()</method>
</difference>

<!--
FakeCredentials Refactor
Expand Down
@@ -0,0 +1,55 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.cloud.firestore;

import com.google.api.core.InternalApi;
import com.google.cloud.Timestamp;
import javax.annotation.Nullable;

/**
* A BatchWriteResult wraps the write time and status returned by Firestore when making
* BatchWriteRequests.
*/
@InternalApi
public final class BatchWriteResult {
private final DocumentReference documentReference;
@Nullable private final Timestamp writeTime;
@Nullable private final Exception exception;

BatchWriteResult(
DocumentReference documentReference,
@Nullable Timestamp timestamp,
@Nullable Exception exception) {
this.documentReference = documentReference;
this.writeTime = timestamp;
this.exception = exception;
}

public DocumentReference getDocumentReference() {
return documentReference;
}

@Nullable
public Timestamp getWriteTime() {
return writeTime;
}

@Nullable
public Exception getException() {
return exception;
}
}
@@ -0,0 +1,63 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.cloud.firestore;

import com.google.api.core.ApiFuture;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import java.util.Set;

/** Used to represent a batch on the BatchQueue. */
class BulkCommitBatch extends UpdateBuilder<ApiFuture<WriteResult>> {

BulkCommitBatch(FirestoreImpl firestore, int maxBatchSize) {
super(firestore, maxBatchSize);
}

BulkCommitBatch(
FirestoreImpl firestore,
BulkCommitBatch retryBatch,
final Set<DocumentReference> docsToRetry) {
super(firestore);
this.writes.addAll(
FluentIterable.from(retryBatch.writes)
.filter(
new Predicate<WriteOperation>() {
@Override
public boolean apply(WriteOperation writeOperation) {
return docsToRetry.contains(writeOperation.documentReference);
}
})
.toList());

Preconditions.checkState(
retryBatch.state == BatchState.SENT,
"Batch should be SENT when creating a new BulkCommitBatch for retry");
this.state = retryBatch.state;
this.pendingOperations = retryBatch.pendingOperations;
}

ApiFuture<WriteResult> wrapResult(ApiFuture<WriteResult> result) {
return result;
}

@Override
boolean allowDuplicateDocs() {
return false;
}
}

0 comments on commit e7054df

Please sign in to comment.