From ddd4d145751ceacc62158055a1508205cebb0f5b Mon Sep 17 00:00:00 2001 From: Igor Bernstein Date: Fri, 20 Feb 2026 17:18:31 -0500 Subject: [PATCH 1/3] Factor out operation settings out of EnhancedStubSettings Change-Id: I10b658c2a808543ba29830a9ccccb21cdf862768 --- .../data/v2/stub/ClientOperationSettings.java | 403 ++++++++++++++++++ .../v2/stub/EnhancedBigtableStubSettings.java | 391 ++--------------- 2 files changed, 436 insertions(+), 358 deletions(-) create mode 100644 google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/ClientOperationSettings.java diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/ClientOperationSettings.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/ClientOperationSettings.java new file mode 100644 index 000000000000..d2a7de8407ba --- /dev/null +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/ClientOperationSettings.java @@ -0,0 +1,403 @@ +/* + * Copyright 2026 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.data.v2.stub; + +import com.google.api.gax.batching.BatchingSettings; +import com.google.api.gax.batching.FlowControlSettings; +import com.google.api.gax.batching.FlowController; +import com.google.api.gax.retrying.RetrySettings; +import com.google.api.gax.rpc.ServerStreamingCallSettings; +import com.google.api.gax.rpc.StatusCode; +import com.google.api.gax.rpc.UnaryCallSettings; +import com.google.bigtable.v2.PingAndWarmRequest; +import com.google.cloud.bigtable.data.v2.internal.PrepareQueryRequest; +import com.google.cloud.bigtable.data.v2.internal.PrepareResponse; +import com.google.cloud.bigtable.data.v2.internal.SqlRow; +import com.google.cloud.bigtable.data.v2.models.ChangeStreamRecord; +import com.google.cloud.bigtable.data.v2.models.ConditionalRowMutation; +import com.google.cloud.bigtable.data.v2.models.KeyOffset; +import com.google.cloud.bigtable.data.v2.models.Query; +import com.google.cloud.bigtable.data.v2.models.Range; +import com.google.cloud.bigtable.data.v2.models.ReadChangeStreamQuery; +import com.google.cloud.bigtable.data.v2.models.ReadModifyWriteRow; +import com.google.cloud.bigtable.data.v2.models.Row; +import com.google.cloud.bigtable.data.v2.models.RowMutation; +import com.google.cloud.bigtable.data.v2.models.sql.BoundStatement; +import com.google.cloud.bigtable.data.v2.stub.mutaterows.MutateRowsBatchingDescriptor; +import com.google.cloud.bigtable.data.v2.stub.readrows.ReadRowsBatchingDescriptor; +import com.google.common.base.MoreObjects; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableSet; +import java.util.List; +import java.util.Set; +import org.threeten.bp.Duration; + +class ClientOperationSettings { + private static final Set IDEMPOTENT_RETRY_CODES = + ImmutableSet.of(StatusCode.Code.DEADLINE_EXCEEDED, StatusCode.Code.UNAVAILABLE); + + // Copy of default retrying settings in the yaml + private static final RetrySettings IDEMPOTENT_RETRY_SETTINGS = + RetrySettings.newBuilder() + .setInitialRetryDelay(Duration.ofMillis(10)) + .setRetryDelayMultiplier(2) + .setMaxRetryDelay(Duration.ofMinutes(1)) + .setInitialRpcTimeout(Duration.ofSeconds(20)) + .setRpcTimeoutMultiplier(1.0) + .setMaxRpcTimeout(Duration.ofSeconds(20)) + .setTotalTimeout(Duration.ofMinutes(10)) + .build(); + + // Allow retrying ABORTED statuses. These will be returned by the server when the client is + // too slow to read the rows. This makes sense for the java client because retries happen + // after the row merging logic. Which means that the retry will not be invoked until the + // current buffered chunks are consumed. + private static final Set READ_ROWS_RETRY_CODES = + ImmutableSet.builder() + .addAll(IDEMPOTENT_RETRY_CODES) + .add(StatusCode.Code.ABORTED) + .build(); + + // Priming request should have a shorter timeout + private static final Duration PRIME_REQUEST_TIMEOUT = Duration.ofSeconds(30); + + private static final RetrySettings READ_ROWS_RETRY_SETTINGS = + RetrySettings.newBuilder() + .setInitialRetryDelay(Duration.ofMillis(10)) + .setRetryDelayMultiplier(2.0) + .setMaxRetryDelay(Duration.ofMinutes(1)) + .setMaxAttempts(10) + .setInitialRpcTimeout(Duration.ofMinutes(30)) + .setRpcTimeoutMultiplier(2.0) + .setMaxRpcTimeout(Duration.ofMinutes(30)) + .setTotalTimeout(Duration.ofHours(12)) + .build(); + + private static final RetrySettings MUTATE_ROWS_RETRY_SETTINGS = + RetrySettings.newBuilder() + .setInitialRetryDelay(Duration.ofMillis(10)) + .setRetryDelayMultiplier(2) + .setMaxRetryDelay(Duration.ofMinutes(1)) + .setInitialRpcTimeout(Duration.ofMinutes(1)) + .setRpcTimeoutMultiplier(1.0) + .setMaxRpcTimeout(Duration.ofMinutes(1)) + .setTotalTimeout(Duration.ofMinutes(10)) + .build(); + + private static final Set GENERATE_INITIAL_CHANGE_STREAM_PARTITIONS_RETRY_CODES = + ImmutableSet.builder() + .addAll(IDEMPOTENT_RETRY_CODES) + .add(StatusCode.Code.ABORTED) + .build(); + + private static final RetrySettings GENERATE_INITIAL_CHANGE_STREAM_PARTITIONS_RETRY_SETTINGS = + RetrySettings.newBuilder() + .setInitialRetryDelay(Duration.ofMillis(10)) + .setRetryDelayMultiplier(2.0) + .setMaxRetryDelay(Duration.ofMinutes(1)) + .setMaxAttempts(10) + .setInitialRpcTimeout(Duration.ofMinutes(1)) + .setRpcTimeoutMultiplier(2.0) + .setMaxRpcTimeout(Duration.ofMinutes(10)) + .setTotalTimeout(Duration.ofMinutes(60)) + .build(); + + // Allow retrying ABORTED statuses. These will be returned by the server when the client is + // too slow to read the change stream records. This makes sense for the java client because + // retries happen after the mutation merging logic. Which means that the retry will not be + // invoked until the current buffered change stream mutations are consumed. + private static final Set READ_CHANGE_STREAM_RETRY_CODES = + ImmutableSet.builder() + .addAll(IDEMPOTENT_RETRY_CODES) + .add(StatusCode.Code.ABORTED) + .build(); + + private static final RetrySettings READ_CHANGE_STREAM_RETRY_SETTINGS = + RetrySettings.newBuilder() + .setInitialRetryDelay(Duration.ofMillis(10)) + .setRetryDelayMultiplier(2.0) + .setMaxRetryDelay(Duration.ofMinutes(1)) + .setMaxAttempts(10) + .setInitialRpcTimeout(Duration.ofMinutes(5)) + .setRpcTimeoutMultiplier(2.0) + .setMaxRpcTimeout(Duration.ofMinutes(5)) + .setTotalTimeout(Duration.ofHours(12)) + .build(); + + // Allow retrying ABORTED statuses. These will be returned by the server when the client is + // too slow to read the responses. + private static final Set EXECUTE_QUERY_RETRY_CODES = + ImmutableSet.builder() + .addAll(IDEMPOTENT_RETRY_CODES) + .add(StatusCode.Code.ABORTED) + .build(); + + // We use the same configuration as READ_ROWS + private static final RetrySettings EXECUTE_QUERY_RETRY_SETTINGS = + RetrySettings.newBuilder() + .setInitialRetryDelay(Duration.ofMillis(10)) + .setRetryDelayMultiplier(2.0) + .setMaxRetryDelay(Duration.ofMinutes(1)) + .setMaxAttempts(10) + .setInitialRpcTimeout(Duration.ofMinutes(30)) + .setRpcTimeoutMultiplier(1.0) + .setMaxRpcTimeout(Duration.ofMinutes(30)) + .setTotalTimeout(Duration.ofHours(12)) + .build(); + + // Similar to IDEMPOTENT but with a lower initial rpc timeout since we expect + // these calls to be quick in most circumstances + private static final RetrySettings PREPARE_QUERY_RETRY_SETTINGS = + RetrySettings.newBuilder() + .setInitialRetryDelay(Duration.ofMillis(10)) + .setRetryDelayMultiplier(2) + .setMaxRetryDelay(Duration.ofMinutes(1)) + .setInitialRpcTimeout(Duration.ofSeconds(5)) + .setRpcTimeoutMultiplier(1.0) + .setMaxRpcTimeout(Duration.ofSeconds(20)) + .setTotalTimeout(Duration.ofMinutes(10)) + .build(); + + final ServerStreamingCallSettings readRowsSettings; + final UnaryCallSettings readRowSettings; + final UnaryCallSettings> sampleRowKeysSettings; + final UnaryCallSettings mutateRowSettings; + final BigtableBatchingCallSettings bulkMutateRowsSettings; + final BigtableBulkReadRowsCallSettings bulkReadRowsSettings; + final UnaryCallSettings checkAndMutateRowSettings; + final UnaryCallSettings readModifyWriteRowSettings; + final ServerStreamingCallSettings + generateInitialChangeStreamPartitionsSettings; + final ServerStreamingCallSettings + readChangeStreamSettings; + final UnaryCallSettings pingAndWarmSettings; + final ServerStreamingCallSettings executeQuerySettings; + final UnaryCallSettings prepareQuerySettings; + + ClientOperationSettings(Builder builder) { + // Since point reads, streaming reads, bulk reads share the same base callable that converts + // grpc errors into ApiExceptions, they must have the same retry codes. + Preconditions.checkState( + builder + .readRowSettings + .getRetryableCodes() + .equals(builder.readRowsSettings.getRetryableCodes()), + "Single ReadRow retry codes must match ReadRows retry codes"); + Preconditions.checkState( + builder + .bulkReadRowsSettings + .getRetryableCodes() + .equals(builder.readRowsSettings.getRetryableCodes()), + "Bulk ReadRow retry codes must match ReadRows retry codes"); + + // Per method settings. + readRowsSettings = builder.readRowsSettings.build(); + readRowSettings = builder.readRowSettings.build(); + sampleRowKeysSettings = builder.sampleRowKeysSettings.build(); + mutateRowSettings = builder.mutateRowSettings.build(); + bulkMutateRowsSettings = builder.bulkMutateRowsSettings.build(); + bulkReadRowsSettings = builder.bulkReadRowsSettings.build(); + checkAndMutateRowSettings = builder.checkAndMutateRowSettings.build(); + readModifyWriteRowSettings = builder.readModifyWriteRowSettings.build(); + generateInitialChangeStreamPartitionsSettings = + builder.generateInitialChangeStreamPartitionsSettings.build(); + readChangeStreamSettings = builder.readChangeStreamSettings.build(); + pingAndWarmSettings = builder.pingAndWarmSettings.build(); + executeQuerySettings = builder.executeQuerySettings.build(); + prepareQuerySettings = builder.prepareQuerySettings.build(); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("readRowsSettings", readRowsSettings) + .add("readRowSettings", readRowSettings) + .add("sampleRowKeysSettings", sampleRowKeysSettings) + .add("mutateRowSettings", mutateRowSettings) + .add("bulkMutateRowsSettings", bulkMutateRowsSettings) + .add("bulkReadRowsSettings", bulkReadRowsSettings) + .add("checkAndMutateRowSettings", checkAndMutateRowSettings) + .add("readModifyWriteRowSettings", readModifyWriteRowSettings) + .add( + "generateInitialChangeStreamPartitionsSettings", + generateInitialChangeStreamPartitionsSettings) + .add("readChangeStreamSettings", readChangeStreamSettings) + .add("pingAndWarmSettings", pingAndWarmSettings) + .add("executeQuerySettings", executeQuerySettings) + .add("prepareQuerySettings", prepareQuerySettings) + .toString(); + } + + static class Builder { + ServerStreamingCallSettings.Builder readRowsSettings; + UnaryCallSettings.Builder readRowSettings; + UnaryCallSettings.Builder> sampleRowKeysSettings; + UnaryCallSettings.Builder mutateRowSettings; + BigtableBatchingCallSettings.Builder bulkMutateRowsSettings; + BigtableBulkReadRowsCallSettings.Builder bulkReadRowsSettings; + UnaryCallSettings.Builder checkAndMutateRowSettings; + UnaryCallSettings.Builder readModifyWriteRowSettings; + ServerStreamingCallSettings.Builder + generateInitialChangeStreamPartitionsSettings; + ServerStreamingCallSettings.Builder + readChangeStreamSettings; + UnaryCallSettings.Builder pingAndWarmSettings; + ServerStreamingCallSettings.Builder executeQuerySettings; + UnaryCallSettings.Builder prepareQuerySettings; + + Builder() { + BigtableStubSettings.Builder baseDefaults = BigtableStubSettings.newBuilder(); + + readRowsSettings = ServerStreamingCallSettings.newBuilder(); + + readRowsSettings + .setRetryableCodes(READ_ROWS_RETRY_CODES) + .setRetrySettings(READ_ROWS_RETRY_SETTINGS) + .setIdleTimeout(Duration.ofMinutes(5)) + .setWaitTimeout(Duration.ofMinutes(5)); + + readRowSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); + readRowSettings + .setRetryableCodes(readRowsSettings.getRetryableCodes()) + .setRetrySettings(IDEMPOTENT_RETRY_SETTINGS); + + sampleRowKeysSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); + sampleRowKeysSettings + .setRetryableCodes(IDEMPOTENT_RETRY_CODES) + .setRetrySettings( + IDEMPOTENT_RETRY_SETTINGS.toBuilder() + .setInitialRpcTimeout(Duration.ofMinutes(5)) + .setMaxRpcTimeout(Duration.ofMinutes(5)) + .build()); + + mutateRowSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); + copyRetrySettings(baseDefaults.mutateRowSettings(), mutateRowSettings); + + long maxBulkMutateElementPerBatch = 100L; + long maxBulkMutateOutstandingElementCount = 20_000L; + + bulkMutateRowsSettings = + BigtableBatchingCallSettings.newBuilder(new MutateRowsBatchingDescriptor()) + .setRetryableCodes(IDEMPOTENT_RETRY_CODES) + .setRetrySettings(MUTATE_ROWS_RETRY_SETTINGS) + .setBatchingSettings( + BatchingSettings.newBuilder() + .setIsEnabled(true) + .setElementCountThreshold(maxBulkMutateElementPerBatch) + .setRequestByteThreshold(20L * 1024 * 1024) + .setDelayThreshold(Duration.ofSeconds(1)) + .setFlowControlSettings( + FlowControlSettings.newBuilder() + .setLimitExceededBehavior(FlowController.LimitExceededBehavior.Block) + .setMaxOutstandingRequestBytes(100L * 1024 * 1024) + .setMaxOutstandingElementCount(maxBulkMutateOutstandingElementCount) + .build()) + .build()); + + long maxBulkReadElementPerBatch = 100L; + long maxBulkReadRequestSizePerBatch = 400L * 1024L; + long maxBulkReadOutstandingElementCount = 20_000L; + + bulkReadRowsSettings = + BigtableBulkReadRowsCallSettings.newBuilder(new ReadRowsBatchingDescriptor()) + .setRetryableCodes(readRowsSettings.getRetryableCodes()) + .setRetrySettings(IDEMPOTENT_RETRY_SETTINGS) + .setBatchingSettings( + BatchingSettings.newBuilder() + .setElementCountThreshold(maxBulkReadElementPerBatch) + .setRequestByteThreshold(maxBulkReadRequestSizePerBatch) + .setDelayThreshold(Duration.ofSeconds(1)) + .setFlowControlSettings( + FlowControlSettings.newBuilder() + .setLimitExceededBehavior(FlowController.LimitExceededBehavior.Block) + .setMaxOutstandingElementCount(maxBulkReadOutstandingElementCount) + .build()) + .build()); + + checkAndMutateRowSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); + copyRetrySettings(baseDefaults.checkAndMutateRowSettings(), checkAndMutateRowSettings); + + readModifyWriteRowSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); + copyRetrySettings(baseDefaults.readModifyWriteRowSettings(), readModifyWriteRowSettings); + + generateInitialChangeStreamPartitionsSettings = ServerStreamingCallSettings.newBuilder(); + generateInitialChangeStreamPartitionsSettings + .setRetryableCodes(GENERATE_INITIAL_CHANGE_STREAM_PARTITIONS_RETRY_CODES) + .setRetrySettings(GENERATE_INITIAL_CHANGE_STREAM_PARTITIONS_RETRY_SETTINGS) + .setIdleTimeout(Duration.ofMinutes(5)) + .setWaitTimeout(Duration.ofMinutes(1)); + + readChangeStreamSettings = ServerStreamingCallSettings.newBuilder(); + readChangeStreamSettings + .setRetryableCodes(READ_CHANGE_STREAM_RETRY_CODES) + .setRetrySettings(READ_CHANGE_STREAM_RETRY_SETTINGS) + .setIdleTimeout(Duration.ofMinutes(5)) + .setWaitTimeout(Duration.ofMinutes(1)); + + pingAndWarmSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); + pingAndWarmSettings.setRetrySettings( + RetrySettings.newBuilder() + .setMaxAttempts(1) + .setInitialRpcTimeout(PRIME_REQUEST_TIMEOUT) + .setMaxRpcTimeout(PRIME_REQUEST_TIMEOUT) + .setTotalTimeout(PRIME_REQUEST_TIMEOUT) + .build()); + + executeQuerySettings = ServerStreamingCallSettings.newBuilder(); + executeQuerySettings + .setRetryableCodes(EXECUTE_QUERY_RETRY_CODES) + .setRetrySettings(EXECUTE_QUERY_RETRY_SETTINGS) + .setIdleTimeout(Duration.ofMinutes(5)) + .setWaitTimeout(Duration.ofMinutes(5)); + + prepareQuerySettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); + prepareQuerySettings + .setRetryableCodes(IDEMPOTENT_RETRY_CODES) + .setRetrySettings(PREPARE_QUERY_RETRY_SETTINGS); + } + + Builder(ClientOperationSettings settings) { + readRowsSettings = settings.readRowsSettings.toBuilder(); + readRowSettings = settings.readRowSettings.toBuilder(); + sampleRowKeysSettings = settings.sampleRowKeysSettings.toBuilder(); + mutateRowSettings = settings.mutateRowSettings.toBuilder(); + bulkMutateRowsSettings = settings.bulkMutateRowsSettings.toBuilder(); + bulkReadRowsSettings = settings.bulkReadRowsSettings.toBuilder(); + checkAndMutateRowSettings = settings.checkAndMutateRowSettings.toBuilder(); + readModifyWriteRowSettings = settings.readModifyWriteRowSettings.toBuilder(); + generateInitialChangeStreamPartitionsSettings = + settings.generateInitialChangeStreamPartitionsSettings.toBuilder(); + readChangeStreamSettings = settings.readChangeStreamSettings.toBuilder(); + pingAndWarmSettings = settings.pingAndWarmSettings.toBuilder(); + executeQuerySettings = settings.executeQuerySettings.toBuilder(); + prepareQuerySettings = settings.prepareQuerySettings.toBuilder(); + } + + /** + * Copies settings from unary RPC to another. This is necessary when modifying request and + * response types while trying to retain retry settings. + */ + private static void copyRetrySettings( + UnaryCallSettings.Builder source, UnaryCallSettings.Builder dest) { + dest.setRetryableCodes(source.getRetryableCodes()); + dest.setRetrySettings(source.getRetrySettings()); + } + + ClientOperationSettings build() { + return new ClientOperationSettings(this); + } + } +} diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStubSettings.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStubSettings.java index 003823f5fc19..51fd1130db7b 100644 --- a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStubSettings.java +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStubSettings.java @@ -21,7 +21,6 @@ import com.google.api.gax.batching.BatchingSettings; import com.google.api.gax.batching.FlowControlSettings; import com.google.api.gax.batching.FlowController; -import com.google.api.gax.batching.FlowController.LimitExceededBehavior; import com.google.api.gax.core.GoogleCredentialsProvider; import com.google.api.gax.grpc.ChannelPoolSettings; import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider; @@ -50,13 +49,10 @@ import com.google.cloud.bigtable.data.v2.models.sql.BoundStatement; import com.google.cloud.bigtable.data.v2.stub.metrics.DefaultMetricsProvider; import com.google.cloud.bigtable.data.v2.stub.metrics.MetricsProvider; -import com.google.cloud.bigtable.data.v2.stub.mutaterows.MutateRowsBatchingDescriptor; -import com.google.cloud.bigtable.data.v2.stub.readrows.ReadRowsBatchingDescriptor; import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -64,7 +60,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Set; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.threeten.bp.Duration; @@ -110,120 +105,6 @@ public class EnhancedBigtableStubSettings extends StubSettings IDEMPOTENT_RETRY_CODES = - ImmutableSet.of(Code.DEADLINE_EXCEEDED, Code.UNAVAILABLE); - - // Copy of default retrying settings in the yaml - private static final RetrySettings IDEMPOTENT_RETRY_SETTINGS = - RetrySettings.newBuilder() - .setInitialRetryDelay(Duration.ofMillis(10)) - .setRetryDelayMultiplier(2) - .setMaxRetryDelay(Duration.ofMinutes(1)) - .setInitialRpcTimeout(Duration.ofSeconds(20)) - .setRpcTimeoutMultiplier(1.0) - .setMaxRpcTimeout(Duration.ofSeconds(20)) - .setTotalTimeout(Duration.ofMinutes(10)) - .build(); - - // Allow retrying ABORTED statuses. These will be returned by the server when the client is - // too slow to read the rows. This makes sense for the java client because retries happen - // after the row merging logic. Which means that the retry will not be invoked until the - // current buffered chunks are consumed. - private static final Set READ_ROWS_RETRY_CODES = - ImmutableSet.builder().addAll(IDEMPOTENT_RETRY_CODES).add(Code.ABORTED).build(); - - // Priming request should have a shorter timeout - private static Duration PRIME_REQUEST_TIMEOUT = Duration.ofSeconds(30); - - private static final RetrySettings READ_ROWS_RETRY_SETTINGS = - RetrySettings.newBuilder() - .setInitialRetryDelay(Duration.ofMillis(10)) - .setRetryDelayMultiplier(2.0) - .setMaxRetryDelay(Duration.ofMinutes(1)) - .setMaxAttempts(10) - .setInitialRpcTimeout(Duration.ofMinutes(30)) - .setRpcTimeoutMultiplier(2.0) - .setMaxRpcTimeout(Duration.ofMinutes(30)) - .setTotalTimeout(Duration.ofHours(12)) - .build(); - - private static final RetrySettings MUTATE_ROWS_RETRY_SETTINGS = - RetrySettings.newBuilder() - .setInitialRetryDelay(Duration.ofMillis(10)) - .setRetryDelayMultiplier(2) - .setMaxRetryDelay(Duration.ofMinutes(1)) - .setInitialRpcTimeout(Duration.ofMinutes(1)) - .setRpcTimeoutMultiplier(1.0) - .setMaxRpcTimeout(Duration.ofMinutes(1)) - .setTotalTimeout(Duration.ofMinutes(10)) - .build(); - - private static final Set GENERATE_INITIAL_CHANGE_STREAM_PARTITIONS_RETRY_CODES = - ImmutableSet.builder().addAll(IDEMPOTENT_RETRY_CODES).add(Code.ABORTED).build(); - - private static final RetrySettings GENERATE_INITIAL_CHANGE_STREAM_PARTITIONS_RETRY_SETTINGS = - RetrySettings.newBuilder() - .setInitialRetryDelay(Duration.ofMillis(10)) - .setRetryDelayMultiplier(2.0) - .setMaxRetryDelay(Duration.ofMinutes(1)) - .setMaxAttempts(10) - .setInitialRpcTimeout(Duration.ofMinutes(1)) - .setRpcTimeoutMultiplier(2.0) - .setMaxRpcTimeout(Duration.ofMinutes(10)) - .setTotalTimeout(Duration.ofMinutes(60)) - .build(); - - // Allow retrying ABORTED statuses. These will be returned by the server when the client is - // too slow to read the change stream records. This makes sense for the java client because - // retries happen after the mutation merging logic. Which means that the retry will not be - // invoked until the current buffered change stream mutations are consumed. - private static final Set READ_CHANGE_STREAM_RETRY_CODES = - ImmutableSet.builder().addAll(IDEMPOTENT_RETRY_CODES).add(Code.ABORTED).build(); - - private static final RetrySettings READ_CHANGE_STREAM_RETRY_SETTINGS = - RetrySettings.newBuilder() - .setInitialRetryDelay(Duration.ofMillis(10)) - .setRetryDelayMultiplier(2.0) - .setMaxRetryDelay(Duration.ofMinutes(1)) - .setMaxAttempts(10) - .setJittered(true) - .setInitialRpcTimeout(Duration.ofMinutes(5)) - .setRpcTimeoutMultiplier(2.0) - .setMaxRpcTimeout(Duration.ofMinutes(5)) - .setTotalTimeout(Duration.ofHours(12)) - .build(); - - // Allow retrying ABORTED statuses. These will be returned by the server when the client is - // too slow to read the responses. - private static final Set EXECUTE_QUERY_RETRY_CODES = - ImmutableSet.builder().addAll(IDEMPOTENT_RETRY_CODES).add(Code.ABORTED).build(); - - // We use the same configuration as READ_ROWS - private static final RetrySettings EXECUTE_QUERY_RETRY_SETTINGS = - RetrySettings.newBuilder() - .setInitialRetryDelay(Duration.ofMillis(10)) - .setRetryDelayMultiplier(2.0) - .setMaxRetryDelay(Duration.ofMinutes(1)) - .setMaxAttempts(10) - .setInitialRpcTimeout(Duration.ofMinutes(30)) - .setRpcTimeoutMultiplier(1.0) - .setMaxRpcTimeout(Duration.ofMinutes(30)) - .setTotalTimeout(Duration.ofHours(12)) - .build(); - - // Similar to IDEMPOTENT but with a lower initial rpc timeout since we expect - // these calls to be quick in most circumstances - private static final RetrySettings PREPARE_QUERY_RETRY_SETTINGS = - RetrySettings.newBuilder() - .setInitialRetryDelay(Duration.ofMillis(10)) - .setRetryDelayMultiplier(2) - .setMaxRetryDelay(Duration.ofMinutes(1)) - .setInitialRpcTimeout(Duration.ofSeconds(5)) - .setRpcTimeoutMultiplier(1.0) - .setMaxRpcTimeout(Duration.ofSeconds(20)) - .setTotalTimeout(Duration.ofMinutes(10)) - .build(); - /** * Scopes that are equivalent to JWT's audience. * @@ -249,21 +130,7 @@ public class EnhancedBigtableStubSettings extends StubSettings readRowsSettings; - private final UnaryCallSettings readRowSettings; - private final UnaryCallSettings> sampleRowKeysSettings; - private final UnaryCallSettings mutateRowSettings; - private final BigtableBatchingCallSettings bulkMutateRowsSettings; - private final BigtableBulkReadRowsCallSettings bulkReadRowsSettings; - private final UnaryCallSettings checkAndMutateRowSettings; - private final UnaryCallSettings readModifyWriteRowSettings; - private final ServerStreamingCallSettings - generateInitialChangeStreamPartitionsSettings; - private final ServerStreamingCallSettings - readChangeStreamSettings; - private final UnaryCallSettings pingAndWarmSettings; - private final ServerStreamingCallSettings executeQuerySettings; - private final UnaryCallSettings prepareQuerySettings; + private final ClientOperationSettings perOpSettings; private final FeatureFlags featureFlags; @@ -275,21 +142,6 @@ public class EnhancedBigtableStubSettings extends StubSettings */ public ServerStreamingCallSettings readRowsSettings() { - return readRowsSettings; + return perOpSettings.readRowsSettings; } /** @@ -500,7 +338,7 @@ public ServerStreamingCallSettings readRowsSettings() { * */ public UnaryCallSettings> sampleRowKeysSettings() { - return sampleRowKeysSettings; + return perOpSettings.sampleRowKeysSettings; } /** @@ -525,7 +363,7 @@ public UnaryCallSettings> sampleRowKeysSettings() { * @see RetrySettings for more explanation. */ public UnaryCallSettings readRowSettings() { - return readRowSettings; + return perOpSettings.readRowSettings; } /** @@ -550,7 +388,7 @@ public UnaryCallSettings readRowSettings() { * @see RetrySettings for more explanation. */ public UnaryCallSettings mutateRowSettings() { - return mutateRowSettings; + return perOpSettings.mutateRowSettings; } /** @@ -597,7 +435,7 @@ public UnaryCallSettings mutateRowSettings() { * related configuration explanation. */ public BigtableBatchingCallSettings bulkMutateRowsSettings() { - return bulkMutateRowsSettings; + return perOpSettings.bulkMutateRowsSettings; } /** @@ -638,7 +476,7 @@ public BigtableBatchingCallSettings bulkMutateRowsSettings() { * @see BatchingSettings for batch related configuration explanation. */ public BigtableBulkReadRowsCallSettings bulkReadRowsSettings() { - return bulkReadRowsSettings; + return perOpSettings.bulkReadRowsSettings; } /** @@ -652,7 +490,7 @@ public BigtableBulkReadRowsCallSettings bulkReadRowsSettings() { * @see RetrySettings for more explanation. */ public UnaryCallSettings checkAndMutateRowSettings() { - return checkAndMutateRowSettings; + return perOpSettings.checkAndMutateRowSettings; } /** @@ -666,21 +504,21 @@ public UnaryCallSettings checkAndMutateRowSetti * @see RetrySettings for more explanation. */ public UnaryCallSettings readModifyWriteRowSettings() { - return readModifyWriteRowSettings; + return perOpSettings.readModifyWriteRowSettings; } public ServerStreamingCallSettings generateInitialChangeStreamPartitionsSettings() { - return generateInitialChangeStreamPartitionsSettings; + return perOpSettings.generateInitialChangeStreamPartitionsSettings; } public ServerStreamingCallSettings readChangeStreamSettings() { - return readChangeStreamSettings; + return perOpSettings.readChangeStreamSettings; } public ServerStreamingCallSettings executeQuerySettings() { - return executeQuerySettings; + return perOpSettings.executeQuerySettings; } /** @@ -706,7 +544,7 @@ public ServerStreamingCallSettings executeQuerySettings( * @see RetrySettings for more explanation. */ public UnaryCallSettings prepareQuerySettings() { - return prepareQuerySettings; + return perOpSettings.prepareQuerySettings; } /** @@ -715,7 +553,7 @@ public UnaryCallSettings prepareQuerySetti *

By default the retries are disabled for PingAndWarm and deadline is set to 30 seconds. */ UnaryCallSettings pingAndWarmSettings() { - return pingAndWarmSettings; + return perOpSettings.pingAndWarmSettings; } /** Returns a builder containing all the values of this settings class. */ @@ -732,23 +570,7 @@ public static class Builder extends StubSettings.Builder readRowsSettings; - private final UnaryCallSettings.Builder readRowSettings; - private final UnaryCallSettings.Builder> sampleRowKeysSettings; - private final UnaryCallSettings.Builder mutateRowSettings; - private final BigtableBatchingCallSettings.Builder bulkMutateRowsSettings; - private final BigtableBulkReadRowsCallSettings.Builder bulkReadRowsSettings; - private final UnaryCallSettings.Builder - checkAndMutateRowSettings; - private final UnaryCallSettings.Builder readModifyWriteRowSettings; - private final ServerStreamingCallSettings.Builder - generateInitialChangeStreamPartitionsSettings; - private final ServerStreamingCallSettings.Builder - readChangeStreamSettings; - private final UnaryCallSettings.Builder pingAndWarmSettings; - private final ServerStreamingCallSettings.Builder executeQuerySettings; - private final UnaryCallSettings.Builder - prepareQuerySettings; + private final ClientOperationSettings.Builder perOpSettings; private final FeatureFlags.Builder featureFlags; @@ -780,113 +602,7 @@ private Builder() { setStreamWatchdogCheckInterval(baseDefaults.getStreamWatchdogCheckInterval()); setStreamWatchdogProvider(baseDefaults.getStreamWatchdogProvider()); - // Per-method settings using baseSettings for defaults. - readRowsSettings = ServerStreamingCallSettings.newBuilder(); - - readRowsSettings - .setRetryableCodes(READ_ROWS_RETRY_CODES) - .setRetrySettings(READ_ROWS_RETRY_SETTINGS) - .setIdleTimeout(Duration.ofMinutes(5)) - .setWaitTimeout(Duration.ofMinutes(5)); - - readRowSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); - readRowSettings - .setRetryableCodes(readRowsSettings.getRetryableCodes()) - .setRetrySettings(IDEMPOTENT_RETRY_SETTINGS); - - sampleRowKeysSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); - sampleRowKeysSettings - .setRetryableCodes(IDEMPOTENT_RETRY_CODES) - .setRetrySettings( - IDEMPOTENT_RETRY_SETTINGS.toBuilder() - .setInitialRpcTimeout(Duration.ofMinutes(5)) - .setMaxRpcTimeout(Duration.ofMinutes(5)) - .build()); - - mutateRowSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); - copyRetrySettings(baseDefaults.mutateRowSettings(), mutateRowSettings); - - long maxBulkMutateElementPerBatch = 100L; - long maxBulkMutateOutstandingElementCount = 20_000L; - - bulkMutateRowsSettings = - BigtableBatchingCallSettings.newBuilder(new MutateRowsBatchingDescriptor()) - .setRetryableCodes(IDEMPOTENT_RETRY_CODES) - .setRetrySettings(MUTATE_ROWS_RETRY_SETTINGS) - .setBatchingSettings( - BatchingSettings.newBuilder() - .setIsEnabled(true) - .setElementCountThreshold(maxBulkMutateElementPerBatch) - .setRequestByteThreshold(20L * 1024 * 1024) - .setDelayThreshold(Duration.ofSeconds(1)) - .setFlowControlSettings( - FlowControlSettings.newBuilder() - .setLimitExceededBehavior(LimitExceededBehavior.Block) - .setMaxOutstandingRequestBytes(100L * 1024 * 1024) - .setMaxOutstandingElementCount(maxBulkMutateOutstandingElementCount) - .build()) - .build()); - - long maxBulkReadElementPerBatch = 100L; - long maxBulkReadRequestSizePerBatch = 400L * 1024L; - long maxBulkReadOutstandingElementCount = 20_000L; - - bulkReadRowsSettings = - BigtableBulkReadRowsCallSettings.newBuilder(new ReadRowsBatchingDescriptor()) - .setRetryableCodes(readRowsSettings.getRetryableCodes()) - .setRetrySettings(IDEMPOTENT_RETRY_SETTINGS) - .setBatchingSettings( - BatchingSettings.newBuilder() - .setElementCountThreshold(maxBulkReadElementPerBatch) - .setRequestByteThreshold(maxBulkReadRequestSizePerBatch) - .setDelayThreshold(Duration.ofSeconds(1)) - .setFlowControlSettings( - FlowControlSettings.newBuilder() - .setLimitExceededBehavior(LimitExceededBehavior.Block) - .setMaxOutstandingElementCount(maxBulkReadOutstandingElementCount) - .build()) - .build()); - - checkAndMutateRowSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); - copyRetrySettings(baseDefaults.checkAndMutateRowSettings(), checkAndMutateRowSettings); - - readModifyWriteRowSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); - copyRetrySettings(baseDefaults.readModifyWriteRowSettings(), readModifyWriteRowSettings); - - generateInitialChangeStreamPartitionsSettings = ServerStreamingCallSettings.newBuilder(); - generateInitialChangeStreamPartitionsSettings - .setRetryableCodes(GENERATE_INITIAL_CHANGE_STREAM_PARTITIONS_RETRY_CODES) - .setRetrySettings(GENERATE_INITIAL_CHANGE_STREAM_PARTITIONS_RETRY_SETTINGS) - .setIdleTimeout(Duration.ofMinutes(5)) - .setWaitTimeout(Duration.ofMinutes(1)); - - readChangeStreamSettings = ServerStreamingCallSettings.newBuilder(); - readChangeStreamSettings - .setRetryableCodes(READ_CHANGE_STREAM_RETRY_CODES) - .setRetrySettings(READ_CHANGE_STREAM_RETRY_SETTINGS) - .setIdleTimeout(Duration.ofMinutes(5)) - .setWaitTimeout(Duration.ofMinutes(1)); - - pingAndWarmSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); - pingAndWarmSettings.setRetrySettings( - RetrySettings.newBuilder() - .setMaxAttempts(1) - .setInitialRpcTimeout(PRIME_REQUEST_TIMEOUT) - .setMaxRpcTimeout(PRIME_REQUEST_TIMEOUT) - .setTotalTimeout(PRIME_REQUEST_TIMEOUT) - .build()); - - executeQuerySettings = ServerStreamingCallSettings.newBuilder(); - executeQuerySettings - .setRetryableCodes(EXECUTE_QUERY_RETRY_CODES) - .setRetrySettings(EXECUTE_QUERY_RETRY_SETTINGS) - .setIdleTimeout(Duration.ofMinutes(5)) - .setWaitTimeout(Duration.ofMinutes(5)); - - prepareQuerySettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); - prepareQuerySettings - .setRetryableCodes(IDEMPOTENT_RETRY_CODES) - .setRetrySettings(PREPARE_QUERY_RETRY_SETTINGS); + perOpSettings = new ClientOperationSettings.Builder(); featureFlags = FeatureFlags.newBuilder() @@ -908,38 +624,11 @@ private Builder(EnhancedBigtableStubSettings settings) { areInternalMetricsEnabled = settings.areInternalMetricsEnabled; jwtAudience = settings.jwtAudience; - // Per method settings. - readRowsSettings = settings.readRowsSettings.toBuilder(); - readRowSettings = settings.readRowSettings.toBuilder(); - sampleRowKeysSettings = settings.sampleRowKeysSettings.toBuilder(); - mutateRowSettings = settings.mutateRowSettings.toBuilder(); - bulkMutateRowsSettings = settings.bulkMutateRowsSettings.toBuilder(); - bulkReadRowsSettings = settings.bulkReadRowsSettings.toBuilder(); - checkAndMutateRowSettings = settings.checkAndMutateRowSettings.toBuilder(); - readModifyWriteRowSettings = settings.readModifyWriteRowSettings.toBuilder(); - generateInitialChangeStreamPartitionsSettings = - settings.generateInitialChangeStreamPartitionsSettings.toBuilder(); - readChangeStreamSettings = settings.readChangeStreamSettings.toBuilder(); - pingAndWarmSettings = settings.pingAndWarmSettings.toBuilder(); - executeQuerySettings = settings.executeQuerySettings().toBuilder(); - prepareQuerySettings = settings.prepareQuerySettings().toBuilder(); - featureFlags = settings.featureFlags.toBuilder(); - } - - // + this.perOpSettings = new ClientOperationSettings.Builder(settings.perOpSettings); - /** - * Copies settings from unary RPC to another. This is necessary when modifying request and - * response types while trying to retain retry settings. - */ - private static void copyRetrySettings( - UnaryCallSettings.Builder source, UnaryCallSettings.Builder dest) { - dest.setRetryableCodes(source.getRetryableCodes()); - dest.setRetrySettings(source.getRetrySettings()); + featureFlags = settings.featureFlags.toBuilder(); } - // - // /** * Sets the project id of that target instance. This setting is required. All RPCs will be made @@ -1167,48 +856,48 @@ public boolean getEnableRetryInfo() { /** Returns the builder for the settings used for calls to readRows. */ public ServerStreamingCallSettings.Builder readRowsSettings() { - return readRowsSettings; + return perOpSettings.readRowsSettings; } /** Returns the builder for the settings used for point reads using readRow. */ public UnaryCallSettings.Builder readRowSettings() { - return readRowSettings; + return perOpSettings.readRowSettings; } /** Returns the builder for the settings used for calls to SampleRowKeysSettings. */ public UnaryCallSettings.Builder> sampleRowKeysSettings() { - return sampleRowKeysSettings; + return perOpSettings.sampleRowKeysSettings; } /** Returns the builder for the settings used for calls to MutateRow. */ public UnaryCallSettings.Builder mutateRowSettings() { - return mutateRowSettings; + return perOpSettings.mutateRowSettings; } /** Returns the builder for the settings used for calls to MutateRows. */ public BigtableBatchingCallSettings.Builder bulkMutateRowsSettings() { - return bulkMutateRowsSettings; + return perOpSettings.bulkMutateRowsSettings; } /** Returns the builder for the settings used for calls to MutateRows. */ public BigtableBulkReadRowsCallSettings.Builder bulkReadRowsSettings() { - return bulkReadRowsSettings; + return perOpSettings.bulkReadRowsSettings; } /** Returns the builder for the settings used for calls to CheckAndMutateRow. */ public UnaryCallSettings.Builder checkAndMutateRowSettings() { - return checkAndMutateRowSettings; + return perOpSettings.checkAndMutateRowSettings; } /** Returns the builder with the settings used for calls to ReadModifyWriteRow. */ public UnaryCallSettings.Builder readModifyWriteRowSettings() { - return readModifyWriteRowSettings; + return perOpSettings.readModifyWriteRowSettings; } /** Returns the builder for the settings used for calls to ReadChangeStream. */ public ServerStreamingCallSettings.Builder readChangeStreamSettings() { - return readChangeStreamSettings; + return perOpSettings.readChangeStreamSettings; } /** @@ -1216,12 +905,12 @@ public UnaryCallSettings.Builder readModifyWriteRowSett */ public ServerStreamingCallSettings.Builder generateInitialChangeStreamPartitionsSettings() { - return generateInitialChangeStreamPartitionsSettings; + return perOpSettings.generateInitialChangeStreamPartitionsSettings; } /** Returns the builder with the settings used for calls to PingAndWarm. */ public UnaryCallSettings.Builder pingAndWarmSettings() { - return pingAndWarmSettings; + return perOpSettings.pingAndWarmSettings; } /** @@ -1232,13 +921,13 @@ public UnaryCallSettings.Builder pingAndWarmSettings() */ @BetaApi public ServerStreamingCallSettings.Builder executeQuerySettings() { - return executeQuerySettings; + return perOpSettings.executeQuerySettings; } /** Returns the builder with the settings used for calls to PrepareQuery */ @BetaApi public UnaryCallSettings.Builder prepareQuerySettings() { - return prepareQuerySettings; + return perOpSettings.prepareQuerySettings; } @SuppressWarnings("unchecked") @@ -1294,21 +983,7 @@ public String toString() { .add("instanceId", instanceId) .add("appProfileId", appProfileId) .add("isRefreshingChannel", isRefreshingChannel) - .add("readRowsSettings", readRowsSettings) - .add("readRowSettings", readRowSettings) - .add("sampleRowKeysSettings", sampleRowKeysSettings) - .add("mutateRowSettings", mutateRowSettings) - .add("bulkMutateRowsSettings", bulkMutateRowsSettings) - .add("bulkReadRowsSettings", bulkReadRowsSettings) - .add("checkAndMutateRowSettings", checkAndMutateRowSettings) - .add("readModifyWriteRowSettings", readModifyWriteRowSettings) - .add( - "generateInitialChangeStreamPartitionsSettings", - generateInitialChangeStreamPartitionsSettings) - .add("readChangeStreamSettings", readChangeStreamSettings) - .add("pingAndWarmSettings", pingAndWarmSettings) - .add("executeQuerySettings", executeQuerySettings) - .add("prepareQuerySettings", prepareQuerySettings) + .add("perOpSettings.", perOpSettings) .add("metricsProvider", metricsProvider) .add("metricsEndpoint", metricsEndpoint) .add("areInternalMetricsEnabled", areInternalMetricsEnabled) From 68b0abc8fe996f9c0688606d57b4a18b58452d40 Mon Sep 17 00:00:00 2001 From: Igor Bernstein Date: Mon, 23 Feb 2026 13:13:19 -0500 Subject: [PATCH 2/3] fix toString test Change-Id: I92a22daa8ed049b94093eccb054cdb2d401ffdea --- .../data/v2/stub/EnhancedBigtableStubSettings.java | 2 +- .../v2/stub/EnhancedBigtableStubSettingsTest.java | 14 +------------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStubSettings.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStubSettings.java index 51fd1130db7b..0ce0c7b299ea 100644 --- a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStubSettings.java +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStubSettings.java @@ -983,7 +983,7 @@ public String toString() { .add("instanceId", instanceId) .add("appProfileId", appProfileId) .add("isRefreshingChannel", isRefreshingChannel) - .add("perOpSettings.", perOpSettings) + .add("perOpSettings", perOpSettings) .add("metricsProvider", metricsProvider) .add("metricsEndpoint", metricsEndpoint) .add("areInternalMetricsEnabled", areInternalMetricsEnabled) diff --git a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStubSettingsTest.java b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStubSettingsTest.java index 9de631918237..ad0de696a313 100644 --- a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStubSettingsTest.java +++ b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStubSettingsTest.java @@ -919,19 +919,7 @@ public void isRefreshingChannelFalseValueTest() { "instanceId", "appProfileId", "isRefreshingChannel", - "readRowsSettings", - "readRowSettings", - "sampleRowKeysSettings", - "mutateRowSettings", - "bulkMutateRowsSettings", - "bulkReadRowsSettings", - "checkAndMutateRowSettings", - "readModifyWriteRowSettings", - "generateInitialChangeStreamPartitionsSettings", - "readChangeStreamSettings", - "pingAndWarmSettings", - "executeQuerySettings", - "prepareQuerySettings", + "perOpSettings", "metricsProvider", "metricsEndpoint", "areInternalMetricsEnabled", From 87442faa0b5269b88355bb1eebd31e41ecbec613 Mon Sep 17 00:00:00 2001 From: Igor Bernstein Date: Mon, 23 Feb 2026 13:27:15 -0500 Subject: [PATCH 3/3] chore: move tracer creation to bigtable client context - BigtableClientContext stores the resource anchor (instance name/app profile) - BigtableClientContext stores the opencensus deps - This allows it to create all of the tracers during initialization - BigtableClientContext can create lightweight copies of itself for BigtableDataClientFactory - close logic of shared contexts is now stored in BigtableClientContext via isChild Change-Id: Ic783fbdb583d96ddf47b4d61630655826f655b7d --- .../bigtable/data/v2/BigtableDataClient.java | 3 +- .../data/v2/BigtableDataClientFactory.java | 67 +++------ .../data/v2/stub/BigtableClientContext.java | 105 +++++++++++-- .../data/v2/stub/EnhancedBigtableStub.java | 140 +----------------- .../bigtable/data/v2/stub/metrics/Util.java | 60 ++++++++ .../metrics/BigtableTracerCallableTest.java | 39 ++--- .../v2/stub/metrics/MetricsTracerTest.java | 21 +-- 7 files changed, 205 insertions(+), 230 deletions(-) diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/BigtableDataClient.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/BigtableDataClient.java index cef5e58f3a29..5af8e9dc9618 100644 --- a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/BigtableDataClient.java +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/BigtableDataClient.java @@ -187,8 +187,7 @@ public static BigtableDataClient create(BigtableDataSettings settings) throws IO */ static BigtableDataClient createWithClientContext( BigtableDataSettings settings, BigtableClientContext context) throws IOException { - EnhancedBigtableStub stub = - EnhancedBigtableStub.createWithClientContext(settings.getStubSettings(), context); + EnhancedBigtableStub stub = new EnhancedBigtableStub(settings.getStubSettings(), context); return new BigtableDataClient(stub); } diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/BigtableDataClientFactory.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/BigtableDataClientFactory.java index 47cf7b15ed10..544d75d6a78e 100644 --- a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/BigtableDataClientFactory.java +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/BigtableDataClientFactory.java @@ -16,9 +16,8 @@ package com.google.cloud.bigtable.data.v2; import com.google.api.core.BetaApi; -import com.google.api.gax.rpc.ClientContext; +import com.google.bigtable.v2.InstanceName; import com.google.cloud.bigtable.data.v2.stub.BigtableClientContext; -import com.google.cloud.bigtable.data.v2.stub.EnhancedBigtableStub; import java.io.IOException; import javax.annotation.Nonnull; @@ -75,8 +74,7 @@ public final class BigtableDataClientFactory implements AutoCloseable { public static BigtableDataClientFactory create(BigtableDataSettings defaultSettings) throws IOException { BigtableClientContext sharedClientContext = - EnhancedBigtableStub.createBigtableClientContext(defaultSettings.getStubSettings()); - + BigtableClientContext.create(defaultSettings.getStubSettings()); return new BigtableDataClientFactory(sharedClientContext, defaultSettings); } @@ -107,17 +105,11 @@ public void close() throws Exception { */ public BigtableDataClient createDefault() { try { - ClientContext clientContext = - sharedClientContext.getClientContext().toBuilder() - .setTracerFactory( - EnhancedBigtableStub.createBigtableTracerFactory( - defaultSettings.getStubSettings(), - sharedClientContext.getBuiltinOpenTelemetry(), - sharedClientContext.getUserOpenTelemetry())) - .build(); + BigtableClientContext ctx = + sharedClientContext.createChild( + sharedClientContext.getInstanceName(), sharedClientContext.getAppProfileId()); - return BigtableDataClient.createWithClientContext( - defaultSettings, sharedClientContext.withClientContext(clientContext)); + return BigtableDataClient.createWithClientContext(defaultSettings, ctx); } catch (IOException e) { // Should never happen because the connection has been established already throw new RuntimeException( @@ -137,17 +129,12 @@ public BigtableDataClient createDefault() { public BigtableDataClient createForAppProfile(@Nonnull String appProfileId) throws IOException { BigtableDataSettings settings = defaultSettings.toBuilder().setAppProfileId(appProfileId).build(); + BigtableClientContext ctx = + sharedClientContext.createChild( + InstanceName.of(settings.getProjectId(), settings.getInstanceId()), + settings.getAppProfileId()); - ClientContext clientContext = - sharedClientContext.getClientContext().toBuilder() - .setTracerFactory( - EnhancedBigtableStub.createBigtableTracerFactory( - settings.getStubSettings(), - sharedClientContext.getBuiltinOpenTelemetry(), - sharedClientContext.getUserOpenTelemetry())) - .build(); - return BigtableDataClient.createWithClientContext( - settings, sharedClientContext.withClientContext(clientContext)); + return BigtableDataClient.createWithClientContext(settings, ctx); } /** @@ -167,18 +154,12 @@ public BigtableDataClient createForInstance(@Nonnull String projectId, @Nonnull .setInstanceId(instanceId) .setDefaultAppProfileId() .build(); + BigtableClientContext ctx = + sharedClientContext.createChild( + InstanceName.of(settings.getProjectId(), settings.getInstanceId()), + settings.getAppProfileId()); - ClientContext clientContext = - sharedClientContext.getClientContext().toBuilder() - .setTracerFactory( - EnhancedBigtableStub.createBigtableTracerFactory( - settings.getStubSettings(), - sharedClientContext.getBuiltinOpenTelemetry(), - sharedClientContext.getUserOpenTelemetry())) - .build(); - - return BigtableDataClient.createWithClientContext( - settings, sharedClientContext.withClientContext(clientContext)); + return BigtableDataClient.createWithClientContext(settings, ctx); } /** @@ -199,15 +180,11 @@ public BigtableDataClient createForInstance( .setInstanceId(instanceId) .setAppProfileId(appProfileId) .build(); - ClientContext clientContext = - sharedClientContext.getClientContext().toBuilder() - .setTracerFactory( - EnhancedBigtableStub.createBigtableTracerFactory( - settings.getStubSettings(), - sharedClientContext.getBuiltinOpenTelemetry(), - sharedClientContext.getUserOpenTelemetry())) - .build(); - return BigtableDataClient.createWithClientContext( - settings, sharedClientContext.withClientContext(clientContext)); + BigtableClientContext ctx = + sharedClientContext.createChild( + InstanceName.of(settings.getProjectId(), settings.getInstanceId()), + settings.getAppProfileId()); + + return BigtableDataClient.createWithClientContext(settings, ctx); } } diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/BigtableClientContext.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/BigtableClientContext.java index d71355d6cd9f..c89f36819064 100644 --- a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/BigtableClientContext.java +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/BigtableClientContext.java @@ -24,18 +24,25 @@ import com.google.api.gax.core.FixedExecutorProvider; import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider; import com.google.api.gax.rpc.ClientContext; +import com.google.api.gax.tracing.ApiTracerFactory; import com.google.auth.Credentials; import com.google.auth.oauth2.ServiceAccountJwtAccessCredentials; import com.google.bigtable.v2.InstanceName; import com.google.cloud.bigtable.data.v2.internal.JwtCredentialsWithAudience; import com.google.cloud.bigtable.data.v2.stub.metrics.BuiltinMetricsConstants; import com.google.cloud.bigtable.data.v2.stub.metrics.ChannelPoolMetricsTracer; +import com.google.cloud.bigtable.data.v2.stub.metrics.CompositeTracerFactory; import com.google.cloud.bigtable.data.v2.stub.metrics.CustomOpenTelemetryMetricsProvider; import com.google.cloud.bigtable.data.v2.stub.metrics.Util; import com.google.cloud.bigtable.gaxx.grpc.BigtableTransportChannelProvider; import com.google.cloud.bigtable.gaxx.grpc.ChannelPrimer; +import com.google.common.collect.ImmutableList; import io.grpc.ManagedChannelBuilder; import io.grpc.opentelemetry.GrpcOpenTelemetry; +import io.opencensus.stats.Stats; +import io.opencensus.stats.StatsRecorder; +import io.opencensus.tags.Tagger; +import io.opencensus.tags.Tags; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.sdk.OpenTelemetrySdk; import java.io.IOException; @@ -55,15 +62,30 @@ public class BigtableClientContext { private static final Logger logger = Logger.getLogger(BigtableClientContext.class.getName()); + private final boolean isChild; + private final InstanceName instanceName; + private final String appProfileId; + private final ApiTracerFactory userTracerFactory; @Nullable private final OpenTelemetrySdk builtinOpenTelemetry; @Nullable private final OpenTelemetry userOpenTelemetry; private final ClientContext clientContext; // the background executor shared for OTEL instances and monitoring client and all other // background tasks private final ExecutorProvider backgroundExecutorProvider; + private final Tagger ocTagger; + private final StatsRecorder ocRecorder; public static BigtableClientContext create(EnhancedBigtableStubSettings settings) throws IOException { + return create(settings, Tags.getTagger(), Stats.getStatsRecorder()); + } + + public static BigtableClientContext create( + EnhancedBigtableStubSettings settings, Tagger ocTagger, StatsRecorder ocRecorder) + throws IOException { + InstanceName instanceName = InstanceName.of(settings.getProjectId(), settings.getInstanceId()); + String appProfileId = settings.getAppProfileId(); + EnhancedBigtableStubSettings.Builder builder = settings.toBuilder(); // Set up credentials @@ -85,6 +107,8 @@ public static BigtableClientContext create(EnhancedBigtableStubSettings settings FixedExecutorProvider.create(backgroundExecutor, shouldAutoClose); builder.setBackgroundExecutorProvider(executorProvider); + ApiTracerFactory userTracerFactory = settings.getTracerFactory(); + // Set up OpenTelemetry @Nullable OpenTelemetry userOtel = null; if (settings.getMetricsProvider() instanceof CustomOpenTelemetryMetricsProvider) { @@ -158,7 +182,17 @@ public static BigtableClientContext create(EnhancedBigtableStubSettings settings channelPoolMetricsTracer.start(clientContext.getExecutor()); } - return new BigtableClientContext(clientContext, builtinOtel, userOtel, executorProvider); + return new BigtableClientContext( + false, + instanceName, + appProfileId, + clientContext, + userTracerFactory, + builtinOtel, + userOtel, + ocTagger, + ocRecorder, + executorProvider); } private static void configureGrpcOtel( @@ -189,14 +223,53 @@ private static void configureGrpcOtel( } private BigtableClientContext( + boolean isChild, + InstanceName instanceName, + String appProfileId, ClientContext clientContext, - @Nullable OpenTelemetrySdk internalOtel, - @Nullable OpenTelemetry userOpenTelemetry, - ExecutorProvider backgroundExecutorProvider) { - this.clientContext = clientContext; - this.userOpenTelemetry = userOpenTelemetry; - this.builtinOpenTelemetry = internalOtel; + ApiTracerFactory userTracerFactory, + @Nullable OpenTelemetrySdk builtinOtel, + @Nullable OpenTelemetry userOtel, + Tagger ocTagger, + StatsRecorder ocRecorder, + ExecutorProvider backgroundExecutorProvider) + throws IOException { + this.isChild = isChild; + this.instanceName = instanceName; + this.appProfileId = appProfileId; + + this.userTracerFactory = userTracerFactory; + this.builtinOpenTelemetry = builtinOtel; + this.userOpenTelemetry = userOtel; + this.ocTagger = ocTagger; + this.ocRecorder = ocRecorder; this.backgroundExecutorProvider = backgroundExecutorProvider; + + ImmutableList.Builder tracerFactories = ImmutableList.builder(); + tracerFactories + .add(Util.createOCTracingFactory(instanceName, appProfileId)) + .add(Util.createOCMetricsFactory(instanceName, appProfileId, ocTagger, ocRecorder)) + .add(userTracerFactory); + + if (builtinOtel != null) { + tracerFactories.add(Util.createOtelMetricsFactory(builtinOtel, instanceName, appProfileId)); + } + if (userOtel != null) { + tracerFactories.add(Util.createOtelMetricsFactory(userOtel, instanceName, appProfileId)); + } + + this.clientContext = + clientContext.toBuilder() + .setTracerFactory(new CompositeTracerFactory(tracerFactories.build())) + .build(); + } + + public InstanceName getInstanceName() { + return instanceName; + } + + public String getAppProfileId() { + return appProfileId; } @Nullable @@ -213,12 +286,26 @@ public ClientContext getClientContext() { return this.clientContext; } - public BigtableClientContext withClientContext(ClientContext clientContext) { + public BigtableClientContext createChild(InstanceName instanceName, String appProfileId) + throws IOException { return new BigtableClientContext( - clientContext, builtinOpenTelemetry, userOpenTelemetry, backgroundExecutorProvider); + true, + instanceName, + appProfileId, + clientContext, + userTracerFactory, + builtinOpenTelemetry, + userOpenTelemetry, + ocTagger, + ocRecorder, + backgroundExecutorProvider); } public void close() throws Exception { + if (isChild) { + return; + } + for (BackgroundResource resource : clientContext.getBackgroundResources()) { resource.close(); } 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 b3cc8d36551e..bf94964434af 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 @@ -15,18 +15,12 @@ */ package com.google.cloud.bigtable.data.v2.stub; -import static com.google.cloud.bigtable.data.v2.stub.metrics.BuiltinMetricsConstants.APP_PROFILE_KEY; -import static com.google.cloud.bigtable.data.v2.stub.metrics.BuiltinMetricsConstants.BIGTABLE_PROJECT_ID_KEY; -import static com.google.cloud.bigtable.data.v2.stub.metrics.BuiltinMetricsConstants.CLIENT_NAME_KEY; -import static com.google.cloud.bigtable.data.v2.stub.metrics.BuiltinMetricsConstants.INSTANCE_ID_KEY; - import com.google.api.core.ApiFuture; import com.google.api.core.BetaApi; import com.google.api.core.InternalApi; import com.google.api.gax.batching.Batcher; import com.google.api.gax.batching.BatcherImpl; import com.google.api.gax.batching.FlowController; -import com.google.api.gax.grpc.GaxGrpcProperties; import com.google.api.gax.grpc.GrpcCallContext; import com.google.api.gax.grpc.GrpcCallSettings; import com.google.api.gax.grpc.GrpcRawCallableFactory; @@ -45,8 +39,6 @@ import com.google.api.gax.rpc.ServerStreamingCallable; import com.google.api.gax.rpc.UnaryCallSettings; import com.google.api.gax.rpc.UnaryCallable; -import com.google.api.gax.tracing.ApiTracerFactory; -import com.google.api.gax.tracing.OpencensusTracerFactory; import com.google.api.gax.tracing.SpanName; import com.google.api.gax.tracing.TracedServerStreamingCallable; import com.google.api.gax.tracing.TracedUnaryCallable; @@ -64,7 +56,6 @@ import com.google.bigtable.v2.ReadRowsResponse; import com.google.bigtable.v2.RowRange; import com.google.bigtable.v2.SampleRowKeysResponse; -import com.google.cloud.bigtable.Version; import com.google.cloud.bigtable.data.v2.internal.NameUtil; import com.google.cloud.bigtable.data.v2.internal.PrepareQueryRequest; import com.google.cloud.bigtable.data.v2.internal.PrepareResponse; @@ -96,10 +87,6 @@ import com.google.cloud.bigtable.data.v2.stub.changestream.ReadChangeStreamUserCallable; import com.google.cloud.bigtable.data.v2.stub.metrics.BigtableTracerStreamingCallable; import com.google.cloud.bigtable.data.v2.stub.metrics.BigtableTracerUnaryCallable; -import com.google.cloud.bigtable.data.v2.stub.metrics.BuiltinMetricsTracerFactory; -import com.google.cloud.bigtable.data.v2.stub.metrics.CompositeTracerFactory; -import com.google.cloud.bigtable.data.v2.stub.metrics.MetricsTracerFactory; -import com.google.cloud.bigtable.data.v2.stub.metrics.RpcMeasureConstants; import com.google.cloud.bigtable.data.v2.stub.metrics.StatsHeadersServerStreamingCallable; import com.google.cloud.bigtable.data.v2.stub.metrics.StatsHeadersUnaryCallable; import com.google.cloud.bigtable.data.v2.stub.metrics.TracedBatcherUnaryCallable; @@ -122,22 +109,12 @@ import com.google.cloud.bigtable.data.v2.stub.sql.PlanRefreshingCallable; import com.google.cloud.bigtable.data.v2.stub.sql.SqlRowMergingCallable; import com.google.cloud.bigtable.gaxx.retrying.RetryInfoRetryAlgorithm; -import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Functions; import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.protobuf.ByteString; import io.grpc.MethodDescriptor; -import io.opencensus.stats.Stats; -import io.opencensus.stats.StatsRecorder; -import io.opencensus.tags.TagKey; -import io.opencensus.tags.TagValue; -import io.opencensus.tags.Tagger; -import io.opencensus.tags.Tags; -import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.common.Attributes; import java.io.IOException; import java.time.Duration; import java.util.List; @@ -167,7 +144,6 @@ public class EnhancedBigtableStub implements AutoCloseable { private final EnhancedBigtableStubSettings settings; private final BigtableClientContext bigtableClientContext; - private final boolean closeClientContext; private final RequestContext requestContext; private final FlowController bulkMutationFlowController; private final DynamicFlowControlStats bulkMutationDynamicFlowControlStats; @@ -198,117 +174,19 @@ public class EnhancedBigtableStub implements AutoCloseable { public static EnhancedBigtableStub create(EnhancedBigtableStubSettings settings) throws IOException { - BigtableClientContext bigtableClientContext = createBigtableClientContext(settings); - ClientContext contextWithTracer = - bigtableClientContext.getClientContext().toBuilder() - .setTracerFactory( - createBigtableTracerFactory( - settings, - bigtableClientContext.getBuiltinOpenTelemetry(), - bigtableClientContext.getUserOpenTelemetry())) - .build(); - bigtableClientContext = bigtableClientContext.withClientContext(contextWithTracer); + BigtableClientContext bigtableClientContext = BigtableClientContext.create(settings); return new EnhancedBigtableStub(settings, bigtableClientContext); } - public static EnhancedBigtableStub createWithClientContext( - EnhancedBigtableStubSettings settings, BigtableClientContext clientContext) - throws IOException { - - return new EnhancedBigtableStub(settings, clientContext, false); - } - - public static BigtableClientContext createBigtableClientContext( - EnhancedBigtableStubSettings settings) throws IOException { - return BigtableClientContext.create(settings); - } - - public static ApiTracerFactory createBigtableTracerFactory( - EnhancedBigtableStubSettings settings, - @Nullable OpenTelemetry builtinOtel, - @Nullable OpenTelemetry userOtel) - throws IOException { - return createBigtableTracerFactory( - settings, Tags.getTagger(), Stats.getStatsRecorder(), builtinOtel, userOtel); - } - - @VisibleForTesting - public static ApiTracerFactory createBigtableTracerFactory( - EnhancedBigtableStubSettings settings, - Tagger tagger, - StatsRecorder stats, - @Nullable OpenTelemetry builtinOtel, - @Nullable OpenTelemetry userOtel) - throws IOException { - String projectId = settings.getProjectId(); - String instanceId = settings.getInstanceId(); - String appProfileId = settings.getAppProfileId(); - - ImmutableMap attributes = - ImmutableMap.builder() - .put(RpcMeasureConstants.BIGTABLE_PROJECT_ID, TagValue.create(projectId)) - .put(RpcMeasureConstants.BIGTABLE_INSTANCE_ID, TagValue.create(instanceId)) - .put(RpcMeasureConstants.BIGTABLE_APP_PROFILE_ID, TagValue.create(appProfileId)) - .build(); - - ImmutableList.Builder tracerFactories = ImmutableList.builder(); - tracerFactories - .add( - // Add OpenCensus Tracing - new OpencensusTracerFactory( - ImmutableMap.builder() - // Annotate traces with the same tags as metrics - .put(RpcMeasureConstants.BIGTABLE_PROJECT_ID.getName(), projectId) - .put(RpcMeasureConstants.BIGTABLE_INSTANCE_ID.getName(), instanceId) - .put(RpcMeasureConstants.BIGTABLE_APP_PROFILE_ID.getName(), appProfileId) - // Also annotate traces with library versions - .put("gax", GaxGrpcProperties.getGaxGrpcVersion()) - .put("grpc", GaxGrpcProperties.getGrpcVersion()) - .put("gapic", Version.VERSION) - .build())) - // Add OpenCensus Metrics - .add(MetricsTracerFactory.create(tagger, stats, attributes)) - // Add user configured tracer - .add(settings.getTracerFactory()); - - if (builtinOtel != null) { - tracerFactories.add( - BuiltinMetricsTracerFactory.create(builtinOtel, createBuiltinAttributes(settings))); - } - if (userOtel != null) { - tracerFactories.add( - BuiltinMetricsTracerFactory.create(userOtel, createBuiltinAttributes(settings))); - } - return new CompositeTracerFactory(tracerFactories.build()); - } - - static Attributes createBuiltinAttributes(EnhancedBigtableStubSettings settings) { - return Attributes.of( - BIGTABLE_PROJECT_ID_KEY, - settings.getProjectId(), - INSTANCE_ID_KEY, - settings.getInstanceId(), - APP_PROFILE_KEY, - settings.getAppProfileId(), - CLIENT_NAME_KEY, - "bigtable-java/" + Version.VERSION); - } - public EnhancedBigtableStub( EnhancedBigtableStubSettings settings, BigtableClientContext clientContext) { - this(settings, clientContext, true); - } - - public EnhancedBigtableStub( - EnhancedBigtableStubSettings settings, - BigtableClientContext clientContext, - boolean closeClientContext) { this.settings = settings; this.bigtableClientContext = clientContext; - this.closeClientContext = closeClientContext; this.requestContext = RequestContext.create( - settings.getProjectId(), settings.getInstanceId(), settings.getAppProfileId()); + clientContext.getInstanceName().getProject(), + clientContext.getInstanceName().getInstance(), + clientContext.getAppProfileId()); this.bulkMutationFlowController = new FlowController(settings.bulkMutateRowsSettings().getDynamicFlowControlSettings()); this.bulkMutationDynamicFlowControlStats = new DynamicFlowControlStats(); @@ -1430,12 +1308,10 @@ private SpanName getSpanName(String methodName) { @Override public void close() { - if (closeClientContext) { - try { - bigtableClientContext.close(); - } catch (Exception e) { - throw new IllegalStateException("failed to close client context", e); - } + try { + bigtableClientContext.close(); + } catch (Exception e) { + throw new IllegalStateException("failed to close client context", e); } } } diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/metrics/Util.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/metrics/Util.java index f5ba5f52fcb8..cc341c994e21 100644 --- a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/metrics/Util.java +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/metrics/Util.java @@ -15,11 +15,19 @@ */ package com.google.cloud.bigtable.data.v2.stub.metrics; +import static com.google.cloud.bigtable.data.v2.stub.metrics.BuiltinMetricsConstants.APP_PROFILE_KEY; +import static com.google.cloud.bigtable.data.v2.stub.metrics.BuiltinMetricsConstants.BIGTABLE_PROJECT_ID_KEY; +import static com.google.cloud.bigtable.data.v2.stub.metrics.BuiltinMetricsConstants.CLIENT_NAME_KEY; +import static com.google.cloud.bigtable.data.v2.stub.metrics.BuiltinMetricsConstants.INSTANCE_ID_KEY; + import com.google.api.core.InternalApi; +import com.google.api.gax.grpc.GaxGrpcProperties; import com.google.api.gax.rpc.ApiCallContext; import com.google.api.gax.rpc.ApiException; import com.google.api.gax.rpc.StatusCode; import com.google.api.gax.rpc.StatusCode.Code; +import com.google.api.gax.tracing.ApiTracerFactory; +import com.google.api.gax.tracing.OpencensusTracerFactory; import com.google.auth.Credentials; import com.google.bigtable.v2.AuthorizedViewName; import com.google.bigtable.v2.CheckAndMutateRowRequest; @@ -35,6 +43,7 @@ import com.google.bigtable.v2.ResponseParams; import com.google.bigtable.v2.SampleRowKeysRequest; import com.google.bigtable.v2.TableName; +import com.google.cloud.bigtable.Version; import com.google.cloud.bigtable.data.v2.BigtableDataSettings; import com.google.cloud.bigtable.data.v2.stub.MetadataExtractorInterceptor; import com.google.common.base.Suppliers; @@ -44,6 +53,12 @@ import io.grpc.Status; import io.grpc.StatusException; import io.grpc.StatusRuntimeException; +import io.opencensus.stats.StatsRecorder; +import io.opencensus.tags.TagKey; +import io.opencensus.tags.TagValue; +import io.opencensus.tags.Tagger; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.common.Attributes; import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.metrics.InstrumentSelector; import io.opentelemetry.sdk.metrics.SdkMeterProvider; @@ -225,4 +240,49 @@ public static String formatZoneIdMetricLabel( .filter(s -> !s.isEmpty()) .orElse("global"); } + + public static ApiTracerFactory createOCTracingFactory( + InstanceName instanceName, String appProfileId) { + return new OpencensusTracerFactory( + ImmutableMap.builder() + // Annotate traces with the same tags as metrics + .put(RpcMeasureConstants.BIGTABLE_PROJECT_ID.getName(), instanceName.getProject()) + .put(RpcMeasureConstants.BIGTABLE_INSTANCE_ID.getName(), instanceName.getInstance()) + .put(RpcMeasureConstants.BIGTABLE_APP_PROFILE_ID.getName(), appProfileId) + // Also annotate traces with library versions + .put("gax", GaxGrpcProperties.getGaxGrpcVersion()) + .put("grpc", GaxGrpcProperties.getGrpcVersion()) + .put("gapic", Version.VERSION) + .build()); + } + + public static ApiTracerFactory createOCMetricsFactory( + InstanceName instanceName, String appProfileId, Tagger tagger, StatsRecorder stats) { + + ImmutableMap attributes = + ImmutableMap.builder() + .put( + RpcMeasureConstants.BIGTABLE_PROJECT_ID, TagValue.create(instanceName.getProject())) + .put( + RpcMeasureConstants.BIGTABLE_INSTANCE_ID, + TagValue.create(instanceName.getInstance())) + .put(RpcMeasureConstants.BIGTABLE_APP_PROFILE_ID, TagValue.create(appProfileId)) + .build(); + return MetricsTracerFactory.create(tagger, stats, attributes); + } + + public static BuiltinMetricsTracerFactory createOtelMetricsFactory( + OpenTelemetry otel, InstanceName instanceName, String appProfileId) throws IOException { + Attributes attributes = + Attributes.of( + BIGTABLE_PROJECT_ID_KEY, + instanceName.getProject(), + INSTANCE_ID_KEY, + instanceName.getInstance(), + APP_PROFILE_KEY, + appProfileId, + CLIENT_NAME_KEY, + "bigtable-java/" + Version.VERSION); + return BuiltinMetricsTracerFactory.create(otel, attributes); + } } diff --git a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/metrics/BigtableTracerCallableTest.java b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/metrics/BigtableTracerCallableTest.java index 639228b8e379..0f84417a7007 100644 --- a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/metrics/BigtableTracerCallableTest.java +++ b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/metrics/BigtableTracerCallableTest.java @@ -18,7 +18,6 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; -import com.google.api.gax.rpc.ClientContext; import com.google.api.gax.rpc.ServerStream; import com.google.api.gax.rpc.UnavailableException; import com.google.bigtable.v2.BigtableGrpc.BigtableImplBase; @@ -125,24 +124,17 @@ public void sendHeaders(Metadata headers) { .setProjectId(PROJECT_ID) .setInstanceId(INSTANCE_ID) .setAppProfileId(APP_PROFILE_ID) + // only testing opencensus + .setMetricsProvider(NoopMetricsProvider.INSTANCE) + .disableInternalMetrics() .build(); - BigtableClientContext bigtableClientContext = - EnhancedBigtableStub.createBigtableClientContext(settings.getStubSettings()); - ClientContext clientContext = - bigtableClientContext.getClientContext().toBuilder() - .setTracerFactory( - EnhancedBigtableStub.createBigtableTracerFactory( - settings.getStubSettings(), - Tags.getTagger(), - localStats.getStatsRecorder(), - null, - null)) - .build(); attempts = settings.getStubSettings().readRowsSettings().getRetrySettings().getMaxAttempts(); stub = new EnhancedBigtableStub( - settings.getStubSettings(), bigtableClientContext.withClientContext(clientContext)); + settings.getStubSettings(), + BigtableClientContext.create( + settings.getStubSettings(), Tags.getTagger(), localStats.getStatsRecorder())); // Create another server without injecting the server-timing header and another stub that // connects to it. @@ -153,24 +145,17 @@ public void sendHeaders(Metadata headers) { .setProjectId(PROJECT_ID) .setInstanceId(INSTANCE_ID) .setAppProfileId(APP_PROFILE_ID) + .setMetricsProvider(NoopMetricsProvider.INSTANCE) + .disableInternalMetrics() .build(); - BigtableClientContext noHeaderBigtableClientContext = - EnhancedBigtableStub.createBigtableClientContext(noHeaderSettings.getStubSettings()); - ClientContext noHeaderClientContext = - noHeaderBigtableClientContext.getClientContext().toBuilder() - .setTracerFactory( - EnhancedBigtableStub.createBigtableTracerFactory( - noHeaderSettings.getStubSettings(), - Tags.getTagger(), - localStats.getStatsRecorder(), - null, - null)) - .build(); noHeaderStub = new EnhancedBigtableStub( noHeaderSettings.getStubSettings(), - noHeaderBigtableClientContext.withClientContext(noHeaderClientContext)); + BigtableClientContext.create( + noHeaderSettings.getStubSettings(), + Tags.getTagger(), + localStats.getStatsRecorder())); } @After diff --git a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/metrics/MetricsTracerTest.java b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/metrics/MetricsTracerTest.java index 47b64fba1405..ab2fe6e205ef 100644 --- a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/metrics/MetricsTracerTest.java +++ b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/metrics/MetricsTracerTest.java @@ -25,7 +25,6 @@ import com.google.api.gax.batching.FlowController; import com.google.api.gax.grpc.GrpcCallContext; import com.google.api.gax.rpc.ApiCallContext; -import com.google.api.gax.rpc.ClientContext; import com.google.bigtable.v2.BigtableGrpc; import com.google.bigtable.v2.MutateRowsRequest; import com.google.bigtable.v2.MutateRowsResponse; @@ -120,23 +119,15 @@ public void setUp() throws Exception { .setProjectId(PROJECT_ID) .setInstanceId(INSTANCE_ID) .setAppProfileId(APP_PROFILE_ID) + .setMetricsProvider(NoopMetricsProvider.INSTANCE) + .disableInternalMetrics() .build(); BigtableClientContext bigtableClientContext = - EnhancedBigtableStub.createBigtableClientContext(settings.getStubSettings()); - ClientContext clientContext = - bigtableClientContext.getClientContext().toBuilder() - .setTracerFactory( - EnhancedBigtableStub.createBigtableTracerFactory( - settings.getStubSettings(), - Tags.getTagger(), - localStats.getStatsRecorder(), - null, - null)) - .build(); - stub = - new EnhancedBigtableStub( - settings.getStubSettings(), bigtableClientContext.withClientContext(clientContext)); + BigtableClientContext.create( + settings.getStubSettings(), Tags.getTagger(), localStats.getStatsRecorder()); + + stub = new EnhancedBigtableStub(settings.getStubSettings(), bigtableClientContext); } @After