Skip to content

Commit c487581

Browse files
refactor: decouple ConsistencyRequest from TableAdminRequestContext (#2887)
* refactor: decouple ConsistencyRequest from TableAdminRequestContext This commit updates the internal plumbing for `ConsistencyRequest` and `AwaitConsistencyCallable` to support fully qualified table names without breaking the existing public API for the legacy `BigtableTableAdminClient`. b/502616786 * chore: generate libraries at Wed Apr 15 18:37:03 UTC 2026 * PR feedback * chore: generate libraries at Tue Apr 21 19:06:09 UTC 2026 * chore: generate libraries at Tue Apr 21 19:11:56 UTC 2026 * PR feedback * chore: generate libraries at Wed Apr 22 18:08:03 UTC 2026 --------- Co-authored-by: cloud-java-bot <cloud-java-bot@google.com>
1 parent 45905a0 commit c487581

4 files changed

Lines changed: 186 additions & 18 deletions

File tree

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/ConsistencyRequest.java

Lines changed: 83 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,11 @@ public abstract class ConsistencyRequest {
4343
@Nullable
4444
public abstract String getConsistencyToken();
4545

46+
protected abstract boolean isFullyQualified();
47+
4648
public static ConsistencyRequest forReplication(String tableId) {
4749
return new AutoValue_ConsistencyRequest(
48-
tableId, CheckConsistencyRequest.ModeCase.STANDARD_READ_REMOTE_WRITES, null);
50+
tableId, CheckConsistencyRequest.ModeCase.STANDARD_READ_REMOTE_WRITES, null, false);
4951
}
5052

5153
/**
@@ -59,37 +61,110 @@ public static ConsistencyRequest forReplication(String tableId, String consisten
5961
Preconditions.checkNotNull(consistencyToken, "consistencyToken must not be null");
6062

6163
return new AutoValue_ConsistencyRequest(
62-
tableId, CheckConsistencyRequest.ModeCase.STANDARD_READ_REMOTE_WRITES, consistencyToken);
64+
tableId,
65+
CheckConsistencyRequest.ModeCase.STANDARD_READ_REMOTE_WRITES,
66+
consistencyToken,
67+
false);
6368
}
6469

6570
public static ConsistencyRequest forDataBoost(String tableId) {
6671
return new AutoValue_ConsistencyRequest(
67-
tableId, CheckConsistencyRequest.ModeCase.DATA_BOOST_READ_LOCAL_WRITES, null);
72+
tableId, CheckConsistencyRequest.ModeCase.DATA_BOOST_READ_LOCAL_WRITES, null, false);
6873
}
6974

7075
@InternalApi
71-
public CheckConsistencyRequest toCheckConsistencyProto(
72-
TableAdminRequestContext requestContext, String token) {
76+
public static ConsistencyRequest forReplicationFromTableName(String tableName) {
77+
Preconditions.checkArgument(
78+
TableName.isParsableFrom(tableName), "tableName must be a fully qualified table name");
79+
return new AutoValue_ConsistencyRequest(
80+
tableName, CheckConsistencyRequest.ModeCase.STANDARD_READ_REMOTE_WRITES, null, true);
81+
}
82+
83+
@InternalApi
84+
public static ConsistencyRequest forReplicationFromTableName(
85+
String tableName, String consistencyToken) {
86+
Preconditions.checkArgument(
87+
TableName.isParsableFrom(tableName), "tableName must be a fully qualified table name");
88+
Preconditions.checkNotNull(consistencyToken, "consistencyToken must not be null");
89+
90+
return new AutoValue_ConsistencyRequest(
91+
tableName,
92+
CheckConsistencyRequest.ModeCase.STANDARD_READ_REMOTE_WRITES,
93+
consistencyToken,
94+
true);
95+
}
96+
97+
private CheckConsistencyRequest.Builder buildBaseRequest(String name, String token) {
7398
CheckConsistencyRequest.Builder builder = CheckConsistencyRequest.newBuilder();
74-
TableName tableName =
75-
TableName.of(requestContext.getProjectId(), requestContext.getInstanceId(), getTableId());
7699

77100
if (getMode().equals(CheckConsistencyRequest.ModeCase.STANDARD_READ_REMOTE_WRITES)) {
78101
builder.setStandardReadRemoteWrites(StandardReadRemoteWrites.newBuilder().build());
79102
} else {
80103
builder.setDataBoostReadLocalWrites(DataBoostReadLocalWrites.newBuilder().build());
81104
}
82105

83-
return builder.setName(tableName.toString()).setConsistencyToken(token).build();
106+
return builder.setName(name).setConsistencyToken(token);
107+
}
108+
109+
/**
110+
* Creates a CheckConsistencyRequest proto. This variant is used when the ConsistencyRequest was
111+
* initialized with a short table ID, relying on the TableAdminRequestContext to construct the
112+
* fully qualified table name.
113+
*/
114+
@InternalApi
115+
public CheckConsistencyRequest toCheckConsistencyProto(
116+
TableAdminRequestContext requestContext, String token) {
117+
Preconditions.checkState(
118+
!isFullyQualified(),
119+
"Use toCheckConsistencyProto(String token) for fully qualified table names.");
120+
TableName tableName =
121+
TableName.of(requestContext.getProjectId(), requestContext.getInstanceId(), getTableId());
122+
123+
return buildBaseRequest(tableName.toString(), token).build();
84124
}
85125

126+
/**
127+
* Creates a CheckConsistencyRequest proto. This variant is used when the ConsistencyRequest was
128+
* initialized with a fully qualified table name, eliminating the need for a request context.
129+
*/
130+
@InternalApi
131+
public CheckConsistencyRequest toCheckConsistencyProto(String token) {
132+
Preconditions.checkState(
133+
isFullyQualified(),
134+
"Use toCheckConsistencyProto(TableAdminRequestContext, String) for non-qualified table"
135+
+ " names.");
136+
137+
return buildBaseRequest(getTableId(), token).build();
138+
}
139+
140+
/**
141+
* Creates a GenerateConsistencyTokenRequest proto. This variant is used when the
142+
* ConsistencyRequest was initialized with a short table ID, relying on the
143+
* TableAdminRequestContext to construct the fully qualified table name.
144+
*/
86145
@InternalApi
87146
public GenerateConsistencyTokenRequest toGenerateTokenProto(
88147
TableAdminRequestContext requestContext) {
148+
Preconditions.checkState(
149+
!isFullyQualified(), "Use toGenerateTokenProto() for fully qualified table names.");
89150
GenerateConsistencyTokenRequest.Builder builder = GenerateConsistencyTokenRequest.newBuilder();
90151
TableName tableName =
91152
TableName.of(requestContext.getProjectId(), requestContext.getInstanceId(), getTableId());
92153

93154
return builder.setName(tableName.toString()).build();
94155
}
156+
157+
/**
158+
* Creates a GenerateConsistencyTokenRequest proto. This variant is used when the
159+
* ConsistencyRequest was initialized with a fully qualified table name, eliminating the need for
160+
* a request context.
161+
*/
162+
@InternalApi
163+
public GenerateConsistencyTokenRequest toGenerateTokenProto() {
164+
Preconditions.checkState(
165+
isFullyQualified(),
166+
"Use toGenerateTokenProto(TableAdminRequestContext) for non-qualified table names.");
167+
GenerateConsistencyTokenRequest.Builder builder = GenerateConsistencyTokenRequest.newBuilder();
168+
return builder.setName(getTableId()).build();
169+
}
95170
}

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/stub/AwaitConsistencyCallable.java

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import com.google.common.util.concurrent.MoreExecutors;
4343
import java.util.concurrent.Callable;
4444
import java.util.concurrent.CancellationException;
45+
import javax.annotation.Nullable;
4546

4647
/**
4748
* Callable that waits until either replication or Data Boost has caught up to the point it was
@@ -56,15 +57,15 @@ class AwaitConsistencyCallable extends UnaryCallable<ConsistencyRequest, Void> {
5657
private final UnaryCallable<CheckConsistencyRequest, CheckConsistencyResponse> checkCallable;
5758
private final RetryingExecutor<CheckConsistencyResponse> executor;
5859

59-
private final TableAdminRequestContext requestContext;
60+
@Nullable private final TableAdminRequestContext requestContext;
6061

6162
static AwaitConsistencyCallable create(
6263
UnaryCallable<GenerateConsistencyTokenRequest, GenerateConsistencyTokenResponse>
6364
generateCallable,
6465
UnaryCallable<CheckConsistencyRequest, CheckConsistencyResponse> checkCallable,
6566
ClientContext clientContext,
6667
RetrySettings pollingSettings,
67-
TableAdminRequestContext requestContext) {
68+
@Nullable TableAdminRequestContext requestContext) {
6869

6970
RetryAlgorithm<CheckConsistencyResponse> retryAlgorithm =
7071
new RetryAlgorithm<>(
@@ -78,13 +79,22 @@ static AwaitConsistencyCallable create(
7879
generateCallable, checkCallable, retryingExecutor, requestContext);
7980
}
8081

82+
static AwaitConsistencyCallable create(
83+
UnaryCallable<GenerateConsistencyTokenRequest, GenerateConsistencyTokenResponse>
84+
generateCallable,
85+
UnaryCallable<CheckConsistencyRequest, CheckConsistencyResponse> checkCallable,
86+
ClientContext clientContext,
87+
RetrySettings pollingSettings) {
88+
return create(generateCallable, checkCallable, clientContext, pollingSettings, null);
89+
}
90+
8191
@VisibleForTesting
8292
AwaitConsistencyCallable(
8393
UnaryCallable<GenerateConsistencyTokenRequest, GenerateConsistencyTokenResponse>
8494
generateCallable,
8595
UnaryCallable<CheckConsistencyRequest, CheckConsistencyResponse> checkCallable,
8696
RetryingExecutor<CheckConsistencyResponse> executor,
87-
TableAdminRequestContext requestContext) {
97+
@Nullable TableAdminRequestContext requestContext) {
8898
this.generateCallable = generateCallable;
8999
this.checkCallable = checkCallable;
90100
this.executor = executor;
@@ -98,22 +108,30 @@ public ApiFuture<Void> futureCall(
98108
// If the token is already provided, skip generation and poll directly.
99109
if (consistencyRequest.getConsistencyToken() != null) {
100110
CheckConsistencyRequest request =
101-
consistencyRequest.toCheckConsistencyProto(
102-
requestContext, consistencyRequest.getConsistencyToken());
111+
requestContext == null
112+
? consistencyRequest.toCheckConsistencyProto(consistencyRequest.getConsistencyToken())
113+
: consistencyRequest.toCheckConsistencyProto(
114+
requestContext, consistencyRequest.getConsistencyToken());
103115
return pollToken(request, apiCallContext);
104116
}
105117

106118
ApiFuture<GenerateConsistencyTokenResponse> tokenFuture =
107-
generateToken(consistencyRequest.toGenerateTokenProto(requestContext), apiCallContext);
119+
generateToken(
120+
requestContext == null
121+
? consistencyRequest.toGenerateTokenProto()
122+
: consistencyRequest.toGenerateTokenProto(requestContext),
123+
apiCallContext);
108124

109125
return ApiFutures.transformAsync(
110126
tokenFuture,
111127
new ApiAsyncFunction<GenerateConsistencyTokenResponse, Void>() {
112128
@Override
113129
public ApiFuture<Void> apply(GenerateConsistencyTokenResponse input) {
114130
CheckConsistencyRequest request =
115-
consistencyRequest.toCheckConsistencyProto(
116-
requestContext, input.getConsistencyToken());
131+
requestContext == null
132+
? consistencyRequest.toCheckConsistencyProto(input.getConsistencyToken())
133+
: consistencyRequest.toCheckConsistencyProto(
134+
requestContext, input.getConsistencyToken());
117135
return pollToken(request, apiCallContext);
118136
}
119137
},

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/stub/EnhancedBigtableTableAdminStub.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,38 @@ public class EnhancedBigtableTableAdminStub extends GrpcBigtableTableAdminStub {
5454
private final BigtableTableAdminStubSettings settings;
5555
private final ClientContext clientContext;
5656

57-
private final TableAdminRequestContext requestContext;
57+
@javax.annotation.Nullable private final TableAdminRequestContext requestContext;
5858

5959
@Deprecated private final AwaitReplicationCallable awaitReplicationCallable;
6060

6161
private final AwaitConsistencyCallable awaitConsistencyCallable;
6262
private final OperationCallable<Void, Empty, OptimizeRestoredTableMetadata>
6363
optimizeRestoredTableOperationBaseCallable;
6464

65+
/**
66+
* Creates an instance of {@link EnhancedBigtableTableAdminStub} using the provided settings. This
67+
* variant is used by the V2 client stack which relies on fully qualified table names and
68+
* therefore does not require a {@link TableAdminRequestContext}.
69+
*
70+
* @param settings The settings used to configure the stub.
71+
* @return A new instance of {@code EnhancedBigtableTableAdminStub}.
72+
* @throws IOException If there are errors creating the underlying client context.
73+
*/
74+
public static EnhancedBigtableTableAdminStub createEnhanced(
75+
BigtableTableAdminStubSettings settings) throws IOException {
76+
return new EnhancedBigtableTableAdminStub(settings, ClientContext.create(settings), null);
77+
}
78+
79+
/**
80+
* Creates an instance of {@link EnhancedBigtableTableAdminStub} using the provided settings. This
81+
* variant is used by the legacy client stack which relies on short table IDs and requires a
82+
* {@link TableAdminRequestContext} to construct fully qualified table names.
83+
*
84+
* @param settings The settings used to configure the stub.
85+
* @param requestContext The context used to format short table IDs.
86+
* @return A new instance of {@code EnhancedBigtableTableAdminStub}.
87+
* @throws IOException If there are errors creating the underlying client context.
88+
*/
6589
public static EnhancedBigtableTableAdminStub createEnhanced(
6690
BigtableTableAdminStubSettings settings, TableAdminRequestContext requestContext)
6791
throws IOException {
@@ -72,7 +96,7 @@ public static EnhancedBigtableTableAdminStub createEnhanced(
7296
private EnhancedBigtableTableAdminStub(
7397
BigtableTableAdminStubSettings settings,
7498
ClientContext clientContext,
75-
TableAdminRequestContext requestContext)
99+
@javax.annotation.Nullable TableAdminRequestContext requestContext)
76100
throws IOException {
77101
super(settings, clientContext);
78102

google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/models/ConsistencyRequestTest.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,55 @@ public void testToCheckConsistencyProtoWithToken() {
9797
assertThat(checkConsistencyRequest.getModeCase())
9898
.isEqualTo(CheckConsistencyRequest.ModeCase.STANDARD_READ_REMOTE_WRITES);
9999
}
100+
101+
@Test
102+
public void testToCheckConsistencyProtoFromTableName() {
103+
String fullTableName = NameUtil.formatTableName(PROJECT_ID, INSTANCE_ID, TABLE_ID);
104+
ConsistencyRequest consistencyRequest =
105+
ConsistencyRequest.forReplicationFromTableName(fullTableName);
106+
107+
CheckConsistencyRequest checkConsistencyRequest =
108+
consistencyRequest.toCheckConsistencyProto(CONSISTENCY_TOKEN);
109+
110+
assertThat(checkConsistencyRequest.getName()).isEqualTo(fullTableName);
111+
assertThat(checkConsistencyRequest.getConsistencyToken()).isEqualTo(CONSISTENCY_TOKEN);
112+
assertThat(checkConsistencyRequest.getModeCase())
113+
.isEqualTo(CheckConsistencyRequest.ModeCase.STANDARD_READ_REMOTE_WRITES);
114+
}
115+
116+
@Test
117+
public void testToCheckConsistencyProtoFromTableNameWithToken() {
118+
String fullTableName = NameUtil.formatTableName(PROJECT_ID, INSTANCE_ID, TABLE_ID);
119+
ConsistencyRequest consistencyRequest =
120+
ConsistencyRequest.forReplicationFromTableName(fullTableName, CONSISTENCY_TOKEN);
121+
122+
CheckConsistencyRequest checkConsistencyRequest =
123+
consistencyRequest.toCheckConsistencyProto(CONSISTENCY_TOKEN);
124+
125+
assertThat(checkConsistencyRequest.getName()).isEqualTo(fullTableName);
126+
assertThat(checkConsistencyRequest.getConsistencyToken()).isEqualTo(CONSISTENCY_TOKEN);
127+
assertThat(checkConsistencyRequest.getModeCase())
128+
.isEqualTo(CheckConsistencyRequest.ModeCase.STANDARD_READ_REMOTE_WRITES);
129+
}
130+
131+
@Test
132+
public void testToGenerateTokenProtoFromTableName() {
133+
String fullTableName = NameUtil.formatTableName(PROJECT_ID, INSTANCE_ID, TABLE_ID);
134+
ConsistencyRequest consistencyRequest =
135+
ConsistencyRequest.forReplicationFromTableName(fullTableName);
136+
137+
GenerateConsistencyTokenRequest generateRequest = consistencyRequest.toGenerateTokenProto();
138+
139+
assertThat(generateRequest.getName()).isEqualTo(fullTableName);
140+
}
141+
142+
@Test(expected = IllegalArgumentException.class)
143+
public void testForReplicationFromTableNameInvalid() {
144+
ConsistencyRequest.forReplicationFromTableName(TABLE_ID);
145+
}
146+
147+
@Test(expected = IllegalArgumentException.class)
148+
public void testForReplicationFromTableNameWithTokenInvalid() {
149+
ConsistencyRequest.forReplicationFromTableName(TABLE_ID, CONSISTENCY_TOKEN);
150+
}
100151
}

0 commit comments

Comments
 (0)