diff --git a/google-cloud-bigtable/clirr-ignored-differences.xml b/google-cloud-bigtable/clirr-ignored-differences.xml index 1f0ff9f4a1..60b9dca093 100644 --- a/google-cloud-bigtable/clirr-ignored-differences.xml +++ b/google-cloud-bigtable/clirr-ignored-differences.xml @@ -156,4 +156,22 @@ com/google/cloud/bigtable/gaxx/retrying/ApiResultRetryAlgorithm * + + + 7004 + com/google/cloud/bigtable/data/v2/stub/mutaterows/MutateRowsRetryingCallable + * + + + + 7004 + com/google/cloud/bigtable/data/v2/models/MutateRowsException + * + + + + 7009 + com/google/cloud/bigtable/data/v2/models/MutateRowsException + * + diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/MutateRowsException.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/MutateRowsException.java index d1c0eda844..4ae0606ab9 100644 --- a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/MutateRowsException.java +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/MutateRowsException.java @@ -17,6 +17,7 @@ import com.google.api.core.InternalApi; import com.google.api.gax.rpc.ApiException; +import com.google.api.gax.rpc.ErrorDetails; import com.google.api.gax.rpc.StatusCode; import com.google.auto.value.AutoValue; import com.google.bigtable.v2.MutateRowsRequest; @@ -53,16 +54,36 @@ public Object getTransportCode() { * applications. */ @InternalApi - public MutateRowsException( + public static MutateRowsException create( @Nullable Throwable rpcError, @Nonnull List failedMutations, boolean retryable) { - super("Some mutations failed to apply", rpcError, LOCAL_STATUS, retryable); + ErrorDetails errorDetails = null; + if (rpcError instanceof ApiException) { + errorDetails = ((ApiException) rpcError).getErrorDetails(); + } + + return new MutateRowsException(rpcError, failedMutations, retryable, errorDetails); + } + + private MutateRowsException( + @Nullable Throwable rpcError, + @Nonnull List failedMutations, + boolean retryable, + @Nullable ErrorDetails errorDetails) { + super(rpcError, LOCAL_STATUS, retryable, errorDetails); Preconditions.checkNotNull(failedMutations); Preconditions.checkArgument(!failedMutations.isEmpty(), "failedMutations can't be empty"); this.failedMutations = failedMutations; } + // TODO: remove this after we add a ctor in gax to pass in a Throwable, a message and error + // details. + @Override + public String getMessage() { + return "Some mutations failed to apply"; + } + /** * Retrieve all of the failed mutations. This list will contain failures for all of the mutations * that have failed across all of the retry attempts so far. diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStub.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStub.java index a575aa8607..9245682dc1 100644 --- a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStub.java +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStub.java @@ -784,7 +784,8 @@ public Map extract(MutateRowsRequest mutateRowsRequest) { clientContext.getDefaultCallContext(), withBigtableTracer, retryingExecutor, - settings.bulkMutateRowsSettings().getRetryableCodes()); + settings.bulkMutateRowsSettings().getRetryableCodes(), + retryAlgorithm); } /** diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/mutaterows/MutateRowsAttemptCallable.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/mutaterows/MutateRowsAttemptCallable.java index 269ce79031..155ea43211 100644 --- a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/mutaterows/MutateRowsAttemptCallable.java +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/mutaterows/MutateRowsAttemptCallable.java @@ -19,7 +19,9 @@ import com.google.api.core.ApiFuture; import com.google.api.core.ApiFutures; import com.google.api.gax.grpc.GrpcStatusCode; +import com.google.api.gax.retrying.RetryAlgorithm; import com.google.api.gax.retrying.RetryingFuture; +import com.google.api.gax.retrying.TimedAttemptSettings; import com.google.api.gax.rpc.ApiCallContext; import com.google.api.gax.rpc.ApiException; import com.google.api.gax.rpc.ApiExceptionFactory; @@ -31,7 +33,6 @@ import com.google.bigtable.v2.MutateRowsResponse.Entry; import com.google.cloud.bigtable.data.v2.models.MutateRowsException; import com.google.cloud.bigtable.data.v2.models.MutateRowsException.FailedMutation; -import com.google.cloud.bigtable.gaxx.retrying.ApiExceptions; import com.google.cloud.bigtable.gaxx.retrying.NonCancellableFuture; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; @@ -111,6 +112,8 @@ public Object getTransportCode() { @Nullable private List originalIndexes; @Nonnull private final Set retryableCodes; @Nullable private final List permanentFailures; + @Nonnull private final RetryAlgorithm retryAlgorithm; + @Nonnull private TimedAttemptSettings attemptSettings; // Parent controller private RetryingFuture externalFuture; @@ -138,11 +141,14 @@ public List apply(Throwable throwable) { @Nonnull UnaryCallable> innerCallable, @Nonnull MutateRowsRequest originalRequest, @Nonnull ApiCallContext callContext, - @Nonnull Set retryableCodes) { + @Nonnull Set retryableCodes, + @Nonnull RetryAlgorithm retryAlgorithm) { this.innerCallable = Preconditions.checkNotNull(innerCallable, "innerCallable"); this.currentRequest = Preconditions.checkNotNull(originalRequest, "currentRequest"); this.callContext = Preconditions.checkNotNull(callContext, "callContext"); this.retryableCodes = Preconditions.checkNotNull(retryableCodes, "retryableCodes"); + this.retryAlgorithm = retryAlgorithm; + this.attemptSettings = retryAlgorithm.createFirstAttempt(); permanentFailures = Lists.newArrayList(); } @@ -230,14 +236,15 @@ private void handleAttemptError(Throwable rpcError) { Builder builder = lastRequest.toBuilder().clearEntries(); List newOriginalIndexes = Lists.newArrayList(); + attemptSettings = retryAlgorithm.createNextAttempt(null, entryError, null, attemptSettings); + for (int i = 0; i < currentRequest.getEntriesCount(); i++) { int origIndex = getOriginalIndex(i); FailedMutation failedMutation = FailedMutation.create(origIndex, entryError); allFailures.add(failedMutation); - if (!ApiExceptions.isRetryable2(failedMutation.getError()) - && !failedMutation.getError().isRetryable()) { + if (!retryAlgorithm.shouldRetry(null, failedMutation.getError(), null, attemptSettings)) { permanentFailures.add(failedMutation); } else { // Schedule the mutation entry for the next RPC by adding it to the request builder and @@ -250,7 +257,7 @@ private void handleAttemptError(Throwable rpcError) { currentRequest = builder.build(); originalIndexes = newOriginalIndexes; - throw new MutateRowsException(rpcError, allFailures.build(), entryError.isRetryable()); + throw MutateRowsException.create(rpcError, allFailures.build(), builder.getEntriesCount() > 0); } /** @@ -258,7 +265,7 @@ private void handleAttemptError(Throwable rpcError) { * transient failures are found, their corresponding mutations are scheduled for the next RPC. The * caller is notified of both new found errors and pre-existing permanent errors in the thrown * {@link MutateRowsException}. If no errors exist, then the attempt future is successfully - * completed. + * completed. We don't currently handle RetryInfo on entry level failures. */ private void handleAttemptSuccess(List responses) { List allFailures = Lists.newArrayList(permanentFailures); @@ -319,7 +326,7 @@ private void handleAttemptSuccess(List responses) { if (!allFailures.isEmpty()) { boolean isRetryable = builder.getEntriesCount() > 0; - throw new MutateRowsException(null, allFailures, isRetryable); + throw MutateRowsException.create(null, allFailures, isRetryable); } } @@ -354,10 +361,10 @@ private static ApiException createSyntheticErrorForRpcFailure(Throwable overallR ApiException requestApiException = (ApiException) overallRequestError; return ApiExceptionFactory.createException( - "Didn't receive a result for this mutation entry", overallRequestError, requestApiException.getStatusCode(), - requestApiException.isRetryable()); + requestApiException.isRetryable(), + requestApiException.getErrorDetails()); } return ApiExceptionFactory.createException( diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/mutaterows/MutateRowsRetryingCallable.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/mutaterows/MutateRowsRetryingCallable.java index ff0daf78bb..8ad1db258d 100644 --- a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/mutaterows/MutateRowsRetryingCallable.java +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/mutaterows/MutateRowsRetryingCallable.java @@ -16,6 +16,7 @@ package com.google.cloud.bigtable.data.v2.stub.mutaterows; import com.google.api.core.InternalApi; +import com.google.api.gax.retrying.RetryAlgorithm; import com.google.api.gax.retrying.RetryingExecutorWithContext; import com.google.api.gax.retrying.RetryingFuture; import com.google.api.gax.rpc.ApiCallContext; @@ -44,23 +45,26 @@ public class MutateRowsRetryingCallable extends UnaryCallable callable; private final RetryingExecutorWithContext executor; private final ImmutableSet retryCodes; + private final RetryAlgorithm retryAlgorithm; public MutateRowsRetryingCallable( @Nonnull ApiCallContext callContextPrototype, @Nonnull ServerStreamingCallable callable, @Nonnull RetryingExecutorWithContext executor, - @Nonnull Set retryCodes) { + @Nonnull Set retryCodes, + @Nonnull RetryAlgorithm retryAlgorithm) { this.callContextPrototype = Preconditions.checkNotNull(callContextPrototype); this.callable = Preconditions.checkNotNull(callable); this.executor = Preconditions.checkNotNull(executor); this.retryCodes = ImmutableSet.copyOf(retryCodes); + this.retryAlgorithm = retryAlgorithm; } @Override public RetryingFuture futureCall(MutateRowsRequest request, ApiCallContext inputContext) { ApiCallContext context = callContextPrototype.nullToSelf(inputContext); MutateRowsAttemptCallable retryCallable = - new MutateRowsAttemptCallable(callable.all(), request, context, retryCodes); + new MutateRowsAttemptCallable(callable.all(), request, context, retryCodes, retryAlgorithm); RetryingFuture retryingFuture = executor.createFuture(retryCallable, context); retryCallable.setExternalFuture(retryingFuture); diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/gaxx/retrying/ApiExceptions.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/gaxx/retrying/ApiExceptions.java deleted file mode 100644 index 4e794fa41a..0000000000 --- a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/gaxx/retrying/ApiExceptions.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2023 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 - * - * https://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.bigtable.gaxx.retrying; - -import com.google.api.core.InternalApi; - -// TODO: move this to gax later -@InternalApi -public class ApiExceptions { - - private ApiExceptions() {} - - // TODO: this should replace the existing ApiException#isRetryable() method, - // but that cant be done in bigtable, so this lives here for now. - public static boolean isRetryable2(Throwable e) { - if (RetryInfoRetryAlgorithm.extractRetryDelay(e) != null) { - return true; - } - return false; - } -} diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/gaxx/retrying/RetryInfoRetryAlgorithm.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/gaxx/retrying/RetryInfoRetryAlgorithm.java index 71457f7e9a..085b48bbb5 100644 --- a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/gaxx/retrying/RetryInfoRetryAlgorithm.java +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/gaxx/retrying/RetryInfoRetryAlgorithm.java @@ -20,12 +20,8 @@ import com.google.api.gax.retrying.RetryingContext; import com.google.api.gax.retrying.TimedAttemptSettings; import com.google.api.gax.rpc.ApiException; -import com.google.common.annotations.VisibleForTesting; import com.google.protobuf.util.Durations; import com.google.rpc.RetryInfo; -import io.grpc.Metadata; -import io.grpc.Status; -import io.grpc.protobuf.ProtoUtils; import org.checkerframework.checker.nullness.qual.Nullable; import org.threeten.bp.Duration; @@ -37,10 +33,6 @@ @InternalApi public class RetryInfoRetryAlgorithm extends BasicResultRetryAlgorithm { - @VisibleForTesting - public static final Metadata.Key RETRY_INFO_KEY = - ProtoUtils.keyForProto(RetryInfo.getDefaultInstance()); - @Override public TimedAttemptSettings createNextAttempt( Throwable prevThrowable, ResponseT prevResponse, TimedAttemptSettings prevSettings) { @@ -50,6 +42,7 @@ public TimedAttemptSettings createNextAttempt( .toBuilder() .setRandomizedRetryDelay(retryDelay) .setAttemptCount(prevSettings.getAttemptCount() + 1) + .setOverallAttemptCount(prevSettings.getAttemptCount() + 1) .build(); } return null; @@ -93,17 +86,17 @@ static Duration extractRetryDelay(@Nullable Throwable throwable) { if (throwable == null) { return null; } - Metadata trailers = Status.trailersFromThrowable(throwable); - if (trailers == null) { + if (!(throwable instanceof ApiException)) { return null; } - RetryInfo retryInfo = trailers.get(RETRY_INFO_KEY); - if (retryInfo == null) { + ApiException exception = (ApiException) throwable; + if (exception.getErrorDetails() == null) { return null; } - if (!retryInfo.hasRetryDelay()) { + if (exception.getErrorDetails().getRetryInfo() == null) { return null; } + RetryInfo retryInfo = exception.getErrorDetails().getRetryInfo(); return Duration.ofMillis(Durations.toMillis(retryInfo.getRetryDelay())); } } diff --git a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/RetryInfoTest.java b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/RetryInfoTest.java index b38e53480c..fef901ac2b 100644 --- a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/RetryInfoTest.java +++ b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/RetryInfoTest.java @@ -15,13 +15,13 @@ */ package com.google.cloud.bigtable.data.v2.stub; -import static com.google.cloud.bigtable.gaxx.retrying.RetryInfoRetryAlgorithm.RETRY_INFO_KEY; import static com.google.common.truth.Truth.assertThat; import com.google.api.gax.core.NoCredentialsProvider; import com.google.api.gax.grpc.GrpcStatusCode; import com.google.api.gax.grpc.GrpcTransportChannel; import com.google.api.gax.rpc.ApiException; +import com.google.api.gax.rpc.ErrorDetails; import com.google.api.gax.rpc.FixedTransportChannelProvider; import com.google.api.gax.rpc.InternalException; import com.google.api.gax.rpc.UnavailableException; @@ -55,7 +55,9 @@ import com.google.cloud.bigtable.data.v2.models.RowMutation; import com.google.cloud.bigtable.data.v2.models.RowMutationEntry; import com.google.common.base.Stopwatch; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Queues; +import com.google.protobuf.Any; import com.google.rpc.RetryInfo; import io.grpc.Metadata; import io.grpc.Status; @@ -77,13 +79,16 @@ public class RetryInfoTest { @Rule public GrpcServerRule serverRule = new GrpcServerRule(); + private static final Metadata.Key ERROR_DETAILS_KEY = + Metadata.Key.of("grpc-status-details-bin", Metadata.BINARY_BYTE_MARSHALLER); + private FakeBigtableService service; private BigtableDataClient client; private BigtableDataSettings.Builder settings; private AtomicInteger attemptCounter = new AtomicInteger(); private com.google.protobuf.Duration delay = - com.google.protobuf.Duration.newBuilder().setSeconds(1).setNanos(0).build(); + com.google.protobuf.Duration.newBuilder().setSeconds(2).setNanos(0).build(); @Before public void setUp() throws IOException { @@ -366,13 +371,18 @@ private void verifyRetryInfoCanBeDisabled(Runnable runnable) { private void enqueueRetryableExceptionWithDelay(com.google.protobuf.Duration delay) { Metadata trailers = new Metadata(); RetryInfo retryInfo = RetryInfo.newBuilder().setRetryDelay(delay).build(); - trailers.put(RETRY_INFO_KEY, retryInfo); + ErrorDetails errorDetails = + ErrorDetails.builder().setRawErrorMessages(ImmutableList.of(Any.pack(retryInfo))).build(); + byte[] status = + com.google.rpc.Status.newBuilder().addDetails(Any.pack(retryInfo)).build().toByteArray(); + trailers.put(ERROR_DETAILS_KEY, status); ApiException exception = new UnavailableException( new StatusRuntimeException(Status.UNAVAILABLE, trailers), GrpcStatusCode.of(Status.Code.UNAVAILABLE), - true); + true, + errorDetails); service.expectations.add(exception); } @@ -380,13 +390,18 @@ private void enqueueRetryableExceptionWithDelay(com.google.protobuf.Duration del private ApiException enqueueNonRetryableExceptionWithDelay(com.google.protobuf.Duration delay) { Metadata trailers = new Metadata(); RetryInfo retryInfo = RetryInfo.newBuilder().setRetryDelay(delay).build(); - trailers.put(RETRY_INFO_KEY, retryInfo); + ErrorDetails errorDetails = + ErrorDetails.builder().setRawErrorMessages(ImmutableList.of(Any.pack(retryInfo))).build(); + byte[] status = + com.google.rpc.Status.newBuilder().addDetails(Any.pack(retryInfo)).build().toByteArray(); + trailers.put(ERROR_DETAILS_KEY, status); ApiException exception = new InternalException( new StatusRuntimeException(Status.INTERNAL, trailers), GrpcStatusCode.of(Status.Code.INTERNAL), - false); + false, + errorDetails); service.expectations.add(exception); diff --git a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/mutaterows/MutateRowsAttemptCallableTest.java b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/mutaterows/MutateRowsAttemptCallableTest.java index 358ff01cde..e5d12ccaeb 100644 --- a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/mutaterows/MutateRowsAttemptCallableTest.java +++ b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/mutaterows/MutateRowsAttemptCallableTest.java @@ -16,16 +16,19 @@ package com.google.cloud.bigtable.data.v2.stub.mutaterows; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.any; import com.google.api.core.AbstractApiFuture; import com.google.api.core.ApiFuture; import com.google.api.core.ApiFutures; import com.google.api.gax.grpc.GrpcCallContext; import com.google.api.gax.grpc.GrpcStatusCode; +import com.google.api.gax.retrying.RetryAlgorithm; import com.google.api.gax.retrying.RetrySettings; import com.google.api.gax.retrying.RetryingFuture; import com.google.api.gax.retrying.TimedAttemptSettings; import com.google.api.gax.rpc.ApiCallContext; +import com.google.api.gax.rpc.ApiException; import com.google.api.gax.rpc.StatusCode.Code; import com.google.api.gax.rpc.UnaryCallable; import com.google.api.gax.rpc.UnavailableException; @@ -47,6 +50,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.mockito.Mockito; import org.threeten.bp.Duration; @RunWith(JUnit4.class) @@ -64,6 +68,8 @@ public class MutateRowsAttemptCallableTest { private Set retryCodes; private ApiCallContext callContext; private MockRetryingFuture parentFuture; + private final RetryAlgorithm mockRetryAlgorithm = + Mockito.mock(RetryAlgorithm.class); @Before public void setUp() { @@ -71,6 +77,12 @@ public void setUp() { retryCodes = ImmutableSet.of(Code.DEADLINE_EXCEEDED, Code.UNAVAILABLE); callContext = GrpcCallContext.createDefault(); parentFuture = new MockRetryingFuture(); + Mockito.when(mockRetryAlgorithm.shouldRetry(any(), any(), any(), any())) + .thenAnswer( + input -> { + Throwable throwable = input.getArgument(1); + return ((ApiException) throwable).isRetryable(); + }); } @Test @@ -84,7 +96,8 @@ public void singleEntrySuccessTest() throws Exception { .build()); MutateRowsAttemptCallable attemptCallable = - new MutateRowsAttemptCallable(innerCallable, request, callContext, retryCodes); + new MutateRowsAttemptCallable( + innerCallable, request, callContext, retryCodes, mockRetryAlgorithm); attemptCallable.setExternalFuture(parentFuture); attemptCallable.call(); @@ -107,7 +120,8 @@ public void missingEntry() { .build()); MutateRowsAttemptCallable attemptCallable = - new MutateRowsAttemptCallable(innerCallable, request, callContext, retryCodes); + new MutateRowsAttemptCallable( + innerCallable, request, callContext, retryCodes, mockRetryAlgorithm); attemptCallable.setExternalFuture(parentFuture); attemptCallable.call(); @@ -140,7 +154,8 @@ public void testNoRpcTimeout() { .build()); MutateRowsAttemptCallable attemptCallable = - new MutateRowsAttemptCallable(innerCallable, request, callContext, retryCodes); + new MutateRowsAttemptCallable( + innerCallable, request, callContext, retryCodes, mockRetryAlgorithm); attemptCallable.setExternalFuture(parentFuture); attemptCallable.call(); @@ -172,7 +187,8 @@ public void mixedTest() { .build()); MutateRowsAttemptCallable attemptCallable = - new MutateRowsAttemptCallable(innerCallable, request, callContext, retryCodes); + new MutateRowsAttemptCallable( + innerCallable, request, callContext, retryCodes, mockRetryAlgorithm); attemptCallable.setExternalFuture(parentFuture); // Make the only call @@ -230,7 +246,8 @@ public void nextAttemptTest() { .build()); MutateRowsAttemptCallable attemptCallable = - new MutateRowsAttemptCallable(innerCallable, request, callContext, retryCodes); + new MutateRowsAttemptCallable( + innerCallable, request, callContext, retryCodes, mockRetryAlgorithm); attemptCallable.setExternalFuture(parentFuture); // Make the first call @@ -295,7 +312,8 @@ public ApiFuture> futureCall( // Make the call MutateRowsAttemptCallable attemptCallable = - new MutateRowsAttemptCallable(innerCallable, request, callContext, retryCodes); + new MutateRowsAttemptCallable( + innerCallable, request, callContext, retryCodes, mockRetryAlgorithm); attemptCallable.setExternalFuture(parentFuture); attemptCallable.call(); @@ -347,7 +365,8 @@ public ApiFuture> futureCall( // Make the call MutateRowsAttemptCallable attemptCallable = - new MutateRowsAttemptCallable(innerCallable, request, callContext, retryCodes); + new MutateRowsAttemptCallable( + innerCallable, request, callContext, retryCodes, mockRetryAlgorithm); attemptCallable.setExternalFuture(parentFuture); attemptCallable.call(); diff --git a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/mutaterows/MutateRowsBatchingDescriptorTest.java b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/mutaterows/MutateRowsBatchingDescriptorTest.java index 81d5c67396..237444ba84 100644 --- a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/mutaterows/MutateRowsBatchingDescriptorTest.java +++ b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/mutaterows/MutateRowsBatchingDescriptorTest.java @@ -138,7 +138,7 @@ public void splitExceptionWithFailedMutationsTest() { // Threw an exception at 1st and 3rd entry MutateRowsException serverError = - new MutateRowsException( + MutateRowsException.create( null, ImmutableList.of( MutateRowsException.FailedMutation.create(