use of com.google.bigtable.v2.MutateRowsResponse in project java-bigtable by googleapis.
the class EnhancedBigtableStub method createMutateRowsBaseCallable.
/**
* Internal helper to create the base MutateRows callable chain. The chain is responsible for
* retrying individual entry in case of error.
*
* <p>NOTE: the caller is responsible for adding tracing & metrics.
*
* @see MutateRowsRetryingCallable for more details
*/
private UnaryCallable<MutateRowsRequest, Void> createMutateRowsBaseCallable() {
ServerStreamingCallable<MutateRowsRequest, MutateRowsResponse> base = GrpcRawCallableFactory.createServerStreamingCallable(GrpcCallSettings.<MutateRowsRequest, MutateRowsResponse>newBuilder().setMethodDescriptor(BigtableGrpc.getMutateRowsMethod()).setParamsExtractor(new RequestParamsExtractor<MutateRowsRequest>() {
@Override
public Map<String, String> extract(MutateRowsRequest mutateRowsRequest) {
return ImmutableMap.of("table_name", mutateRowsRequest.getTableName(), "app_profile_id", mutateRowsRequest.getAppProfileId());
}
}).build(), settings.bulkMutateRowsSettings().getRetryableCodes());
ServerStreamingCallable<MutateRowsRequest, MutateRowsResponse> withStatsHeaders = new StatsHeadersServerStreamingCallable<>(base);
RetryAlgorithm<Void> retryAlgorithm = new RetryAlgorithm<>(new ApiResultRetryAlgorithm<Void>(), new ExponentialRetryAlgorithm(settings.bulkMutateRowsSettings().getRetrySettings(), clientContext.getClock()));
RetryingExecutorWithContext<Void> retryingExecutor = new ScheduledRetryingExecutor<>(retryAlgorithm, clientContext.getExecutor());
return new MutateRowsRetryingCallable(clientContext.getDefaultCallContext(), withStatsHeaders, retryingExecutor, settings.bulkMutateRowsSettings().getRetryableCodes());
}
use of com.google.bigtable.v2.MutateRowsResponse in project java-bigtable by googleapis.
the class MetricsTracerTest method testBatchMutateRowsThrottledTime.
@Test
public void testBatchMutateRowsThrottledTime() throws Exception {
FlowController flowController = Mockito.mock(FlowController.class);
BatchingDescriptor batchingDescriptor = Mockito.mock(MutateRowsBatchingDescriptor.class);
// Mock throttling
final long throttled = 50;
doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Thread.sleep(throttled);
return null;
}
}).when(flowController).reserve(any(Long.class), any(Long.class));
when(flowController.getMaxElementCountLimit()).thenReturn(null);
when(flowController.getMaxRequestBytesLimit()).thenReturn(null);
when(batchingDescriptor.countBytes(any())).thenReturn(1l);
when(batchingDescriptor.newRequestBuilder(any())).thenCallRealMethod();
doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) {
@SuppressWarnings("unchecked") StreamObserver<MutateRowsResponse> observer = (StreamObserver<MutateRowsResponse>) invocation.getArguments()[1];
observer.onNext(MutateRowsResponse.getDefaultInstance());
observer.onCompleted();
return null;
}
}).when(mockService).mutateRows(any(MutateRowsRequest.class), any());
ApiCallContext defaultContext = GrpcCallContext.createDefault();
Batcher batcher = new BatcherImpl(batchingDescriptor, stub.bulkMutateRowsCallable().withDefaultCallContext(defaultContext), BulkMutation.create(TABLE_ID), settings.getStubSettings().bulkMutateRowsSettings().getBatchingSettings(), Executors.newSingleThreadScheduledExecutor(), flowController, defaultContext);
batcher.add(RowMutationEntry.create("key"));
batcher.sendOutstanding();
Thread.sleep(100);
long throttledTimeMetric = StatsTestUtils.getAggregationValueAsLong(localStats, RpcViewConstants.BIGTABLE_BATCH_THROTTLED_TIME_VIEW, ImmutableMap.of(RpcMeasureConstants.BIGTABLE_OP, TagValue.create("Bigtable.MutateRows")), PROJECT_ID, INSTANCE_ID, APP_PROFILE_ID);
assertThat(throttledTimeMetric).isAtLeast(throttled);
}
use of com.google.bigtable.v2.MutateRowsResponse in project java-bigtable by googleapis.
the class MutateRowsAttemptCallableTest method rpcPermanentError.
@Test
public void rpcPermanentError() {
// Setup the request & response
MutateRowsRequest request = MutateRowsRequest.newBuilder().addEntries(Entry.getDefaultInstance()).addEntries(Entry.getDefaultInstance()).build();
final UnavailableException rpcError = new UnavailableException("fake error", null, GrpcStatusCode.of(io.grpc.Status.Code.INVALID_ARGUMENT), false);
UnaryCallable<MutateRowsRequest, List<MutateRowsResponse>> innerCallable = new UnaryCallable<MutateRowsRequest, List<MutateRowsResponse>>() {
@Override
public ApiFuture<List<MutateRowsResponse>> futureCall(MutateRowsRequest request, ApiCallContext context) {
return ApiFutures.immediateFailedFuture(rpcError);
}
};
// Make the call
MutateRowsAttemptCallable attemptCallable = new MutateRowsAttemptCallable(innerCallable, request, callContext, retryCodes);
attemptCallable.setExternalFuture(parentFuture);
attemptCallable.call();
// Overall expectations: retryable error
Throwable actualError = null;
try {
parentFuture.attemptFuture.get();
} catch (Throwable t) {
actualError = t.getCause();
}
assertThat(actualError).isInstanceOf(MutateRowsException.class);
assertThat(((MutateRowsException) actualError).isRetryable()).isFalse();
// Entry expectations: both entries failed with an error whose cause is the rpc error
@SuppressWarnings("ConstantConditions") List<FailedMutation> failedMutations = ((MutateRowsException) actualError).getFailedMutations();
assertThat(failedMutations).hasSize(2);
assertThat(failedMutations.get(0).getIndex()).isEqualTo(0);
assertThat(failedMutations.get(0).getError().isRetryable()).isFalse();
assertThat(failedMutations.get(0).getError().getCause()).isEqualTo(rpcError);
assertThat(failedMutations.get(1).getIndex()).isEqualTo(1);
assertThat(failedMutations.get(1).getError().isRetryable()).isFalse();
assertThat(failedMutations.get(1).getError().getCause()).isEqualTo(rpcError);
}
use of com.google.bigtable.v2.MutateRowsResponse in project java-bigtable by googleapis.
the class MutateRowsAttemptCallableTest method rpcRetryableError.
@Test
public void rpcRetryableError() {
// Setup the request & response
MutateRowsRequest request = MutateRowsRequest.newBuilder().addEntries(Entry.getDefaultInstance()).addEntries(Entry.getDefaultInstance()).build();
final UnavailableException rpcError = new UnavailableException("fake error", null, GrpcStatusCode.of(io.grpc.Status.Code.UNAVAILABLE), true);
UnaryCallable<MutateRowsRequest, List<MutateRowsResponse>> innerCallable = new UnaryCallable<MutateRowsRequest, List<MutateRowsResponse>>() {
@Override
public ApiFuture<List<MutateRowsResponse>> futureCall(MutateRowsRequest request, ApiCallContext context) {
return ApiFutures.immediateFailedFuture(rpcError);
}
};
// Make the call
MutateRowsAttemptCallable attemptCallable = new MutateRowsAttemptCallable(innerCallable, request, callContext, retryCodes);
attemptCallable.setExternalFuture(parentFuture);
attemptCallable.call();
// Overall expectations: retryable error
Throwable actualError = null;
try {
parentFuture.attemptFuture.get();
} catch (Throwable t) {
actualError = t.getCause();
}
assertThat(actualError).isInstanceOf(MutateRowsException.class);
assertThat(((MutateRowsException) actualError).isRetryable()).isTrue();
// Entry expectations: both entries failed with an error whose cause is the rpc error
@SuppressWarnings("ConstantConditions") List<FailedMutation> failedMutations = ((MutateRowsException) actualError).getFailedMutations();
assertThat(failedMutations).hasSize(2);
assertThat(failedMutations.get(0).getIndex()).isEqualTo(0);
assertThat(failedMutations.get(0).getError().isRetryable()).isTrue();
assertThat(failedMutations.get(0).getError().getCause()).isEqualTo(rpcError);
assertThat(failedMutations.get(1).getIndex()).isEqualTo(1);
assertThat(failedMutations.get(1).getError().isRetryable()).isTrue();
assertThat(failedMutations.get(1).getError().getCause()).isEqualTo(rpcError);
}
use of com.google.bigtable.v2.MutateRowsResponse in project java-bigtable by googleapis.
the class MutateRowsAttemptCallable method handleAttemptSuccess.
/**
* Handle entry level failures. All new response entries are inspected for failure. If any
* 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.
*/
private void handleAttemptSuccess(List<MutateRowsResponse> responses) {
List<FailedMutation> allFailures = Lists.newArrayList(permanentFailures);
MutateRowsRequest lastRequest = currentRequest;
Builder builder = lastRequest.toBuilder().clearEntries();
List<Integer> newOriginalIndexes = Lists.newArrayList();
for (MutateRowsResponse response : responses) {
for (Entry entry : response.getEntriesList()) {
if (entry.getStatus().getCode() == Code.OK_VALUE) {
continue;
}
int origIndex = getOriginalIndex((int) entry.getIndex());
FailedMutation failedMutation = FailedMutation.create(origIndex, createEntryError(entry.getStatus()));
allFailures.add(failedMutation);
if (!failedMutation.getError().isRetryable()) {
permanentFailures.add(failedMutation);
} else {
// Schedule the mutation entry for the next RPC by adding it to the request builder and
// recording it's original index
newOriginalIndexes.add(origIndex);
builder.addEntries(lastRequest.getEntries((int) entry.getIndex()));
}
}
}
currentRequest = builder.build();
originalIndexes = newOriginalIndexes;
if (!allFailures.isEmpty()) {
boolean isRetryable = builder.getEntriesCount() > 0;
throw new MutateRowsException(null, allFailures, isRetryable);
}
}
Aggregations