Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
import com.google.cloud.bigtable.data.v2.internal.PrepareResponse;
import com.google.cloud.bigtable.data.v2.internal.RequestContext;
import com.google.cloud.bigtable.data.v2.internal.SqlRow;
import com.google.cloud.bigtable.data.v2.internal.api.MaterializedViewName;
import com.google.cloud.bigtable.data.v2.internal.csm.tracers.BigtableTracerStreamingCallable;
import com.google.cloud.bigtable.data.v2.internal.csm.tracers.BigtableTracerUnaryCallable;
import com.google.cloud.bigtable.data.v2.internal.csm.tracers.TracedBatcherUnaryCallable;
Expand Down Expand Up @@ -374,8 +375,14 @@ private <ReqT, RowT> ServerStreamingCallable<ReadRowsRequest, RowT> createReadRo
.setMethodDescriptor(BigtableGrpc.getReadRowsMethod())
.setParamsExtractor(
r ->
composeRequestParams(
r.getAppProfileId(), r.getTableName(), r.getAuthorizedViewName()))
r.getMaterializedViewName().isEmpty()
? composeRequestParams(
r.getAppProfileId(), r.getTableName(), r.getAuthorizedViewName())
: composeInstanceLevelRequestParams(
MaterializedViewName.parse(r.getMaterializedViewName())
.getInstanceName()
.toString(),
r.getAppProfileId()))
Comment on lines +378 to +385

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic to extract routing parameters for read operations (which can target a table, authorized view, or materialized view) is duplicated across multiple callables. Consider extracting this into a helper method to improve maintainability and readability.

Here is an example of the helper method you can add to the class:

private Map<String, String> composeReadRequestParams(
    String appProfileId,
    String tableName,
    String authorizedViewName,
    String materializedViewName) {
  if (materializedViewName.isEmpty()) {
    return composeRequestParams(appProfileId, tableName, authorizedViewName);
  }
  return composeInstanceLevelRequestParams(
      MaterializedViewName.parse(materializedViewName).getInstanceName().toString(),
      appProfileId);
}
                        composeReadRequestParams(
                            r.getAppProfileId(),
                            r.getTableName(),
                            r.getAuthorizedViewName(),
                            r.getMaterializedViewName())

.build(),
readRowsSettings.getRetryableCodes());

Expand Down Expand Up @@ -448,8 +455,14 @@ public <ReqT, RowT> ServerStreamingCallable<Query, RowT> createSkipLargeRowsCall
.setMethodDescriptor(BigtableGrpc.getReadRowsMethod())
.setParamsExtractor(
r ->
composeRequestParams(
r.getAppProfileId(), r.getTableName(), r.getAuthorizedViewName()))
r.getMaterializedViewName().isEmpty()
? composeRequestParams(
r.getAppProfileId(), r.getTableName(), r.getAuthorizedViewName())
: composeInstanceLevelRequestParams(
MaterializedViewName.parse(r.getMaterializedViewName())
.getInstanceName()
.toString(),
r.getAppProfileId()))
Comment on lines +458 to +465

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This block duplicates the routing parameter extraction logic. Use the extracted composeReadRequestParams helper method here as well.

                        composeReadRequestParams(
                            r.getAppProfileId(),
                            r.getTableName(),
                            r.getAuthorizedViewName(),
                            r.getMaterializedViewName())

.build(),
readRowsSettings.getRetryableCodes());

Expand Down Expand Up @@ -598,8 +611,16 @@ public ApiFuture<List<KeyOffset>> futureCall(String s, ApiCallContext apiCallCon
.setMethodDescriptor(BigtableGrpc.getSampleRowKeysMethod())
.setParamsExtractor(
r ->
composeRequestParams(
r.getAppProfileId(), r.getTableName(), r.getAuthorizedViewName()))
r.getMaterializedViewName().isEmpty()
? composeRequestParams(
r.getAppProfileId(),
r.getTableName(),
r.getAuthorizedViewName())
: composeInstanceLevelRequestParams(
MaterializedViewName.parse(r.getMaterializedViewName())
.getInstanceName()
.toString(),
r.getAppProfileId()))
Comment on lines +614 to +623

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This block duplicates the routing parameter extraction logic. Use the extracted composeReadRequestParams helper method here as well.

                            composeReadRequestParams(
                                r.getAppProfileId(),
                                r.getTableName(),
                                r.getAuthorizedViewName(),
                                r.getMaterializedViewName())

.build(),
perOpSettings.sampleRowKeysSettings.getRetryableCodes());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,16 @@
import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider;
import com.google.api.gax.rpc.ResponseObserver;
import com.google.api.gax.rpc.StreamController;
import com.google.cloud.bigtable.admin.v2.BigtableInstanceAdminClient;
import com.google.cloud.bigtable.admin.v2.BigtableTableAdminClient;
import com.google.cloud.bigtable.admin.v2.models.AuthorizedView;
import com.google.cloud.bigtable.admin.v2.models.CreateMaterializedViewRequest;
import com.google.cloud.bigtable.admin.v2.models.CreateTableRequest;
import com.google.cloud.bigtable.data.v2.BigtableDataClient;
import com.google.cloud.bigtable.data.v2.BigtableDataSettings;
import com.google.cloud.bigtable.data.v2.models.AuthorizedViewId;
import com.google.cloud.bigtable.data.v2.models.BulkMutation;
import com.google.cloud.bigtable.data.v2.models.MaterializedViewId;
import com.google.cloud.bigtable.data.v2.models.Query;
import com.google.cloud.bigtable.data.v2.models.Range.ByteStringRange;
import com.google.cloud.bigtable.data.v2.models.Row;
Expand All @@ -43,6 +48,7 @@
import com.google.cloud.bigtable.data.v2.models.RowMutationEntry;
import com.google.cloud.bigtable.data.v2.models.TableId;
import com.google.cloud.bigtable.test_helpers.env.EmulatorEnv;
import com.google.cloud.bigtable.test_helpers.env.PrefixGenerator;
import com.google.cloud.bigtable.test_helpers.env.TestEnvRule;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
Expand Down Expand Up @@ -219,6 +225,56 @@ public void readEmptyOnAuthorizedView() throws Throwable {
.deleteAuthorizedView(tableId.getTableId(), testAuthorizedView.getId());
}

@Test
public void readFromMaterializedView() throws Throwable {
assume()
.withMessage("MaterializedView is not supported on Emulator")
.that(testEnvRule.env())
.isNotInstanceOf(EmulatorEnv.class);

BigtableDataClient dataClient = testEnvRule.env().getDataClient();
BigtableTableAdminClient tableAdmin = testEnvRule.env().getTableAdminClient();
BigtableInstanceAdminClient instanceAdmin = testEnvRule.env().getInstanceAdminClient();
String instanceId = testEnvRule.env().getInstanceId();

String tableId = PrefixGenerator.newPrefix("ReadIT#readFromMaterializedView");
String materializedViewId = PrefixGenerator.newPrefix("ReadIT#readFromMaterializedView");
String rowKey = prefix + "-readFromMaterializedView";

tableAdmin.createTable(CreateTableRequest.of(tableId).addFamily("cf1"));
try {
dataClient.mutateRow(
RowMutation.create(TableId.of(tableId), rowKey).setCell("cf1", "column", "value"));

instanceAdmin.createMaterializedView(
CreateMaterializedViewRequest.of(instanceId, materializedViewId)
.setQuery(
"SELECT _key, MAX(cf1['column']) as column FROM `" + tableId + "` GROUP BY _key")
.setDeletionProtection(false));
try {
Row row = null;
long[] backoffSeconds = {5, 10, 15, 30, 30, 30};
for (long backoff : backoffSeconds) {
List<Row> rows =
Lists.newArrayList(
dataClient.readRows(Query.create(MaterializedViewId.of(materializedViewId))));
if (!rows.isEmpty()) {
row = rows.get(0);
break;
}
Thread.sleep(backoff * 1000);
}

assertThat(row).isNotNull();
assertThat(row.getKey()).isEqualTo(ByteString.copyFromUtf8(rowKey));
} finally {
instanceAdmin.deleteMaterializedView(instanceId, materializedViewId);
}
} finally {
tableAdmin.deleteTable(tableId);
}
}

@Test
public void read() throws Throwable {
int numRows = 5;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import com.google.cloud.bigtable.data.v2.FakeServiceBuilder;
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.MaterializedViewId;
import com.google.cloud.bigtable.data.v2.models.Mutation;
import com.google.cloud.bigtable.data.v2.models.Query;
import com.google.cloud.bigtable.data.v2.models.ReadModifyWriteRow;
Expand Down Expand Up @@ -135,13 +136,29 @@ public void readRowsTest() {
verifyHeaderSent();
}

@Test
public void readRowsMaterializedViewTest() {
// Materialized views are instance-scoped, so routing happens on the instance name.
client.readRows(Query.create(MaterializedViewId.of("fake-materialized-view")));
verifyHeaderSent(true);
}

@Test
public void sampleRowKeysTest() {
@SuppressWarnings("UnusedVariable")
ApiFuture<List<KeyOffset>> ignored = client.sampleRowKeysAsync(TABLE_ID);
verifyHeaderSent();
}

@Test
public void sampleRowKeysMaterializedViewTest() {
// Materialized views are instance-scoped, so routing happens on the instance name.
@SuppressWarnings("UnusedVariable")
ApiFuture<List<KeyOffset>> ignored =
client.sampleRowKeysAsync(MaterializedViewId.of("fake-materialized-view"));
verifyHeaderSent(true);
}

@Test
public void mutateRowTest() {
ApiFuture<Void> ignored =
Expand Down
Loading