From 143aaee42e1b59d125250982dbeb34a31d906e30 Mon Sep 17 00:00:00 2001 From: Mridula <66699525+mpeddada1@users.noreply.github.com> Date: Mon, 14 Feb 2022 10:39:24 -0500 Subject: [PATCH] docs(sample): Add sample for native image support in Bigtable (#1165) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs(sample): add sample for native image support * 🦉 Updates from OwlBot See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * add setup instructions to readme Co-authored-by: Owl Bot --- README.md | 1 + samples/native-image-sample/README.md | 113 +++++++++++++ samples/native-image-sample/pom.xml | 139 ++++++++++++++++ .../bigtable/NativeImageBigtableSample.java | 148 ++++++++++++++++++ .../bigtable/NativeImageBigtableTest.java | 122 +++++++++++++++ samples/pom.xml | 1 + 6 files changed, 524 insertions(+) create mode 100644 samples/native-image-sample/README.md create mode 100644 samples/native-image-sample/pom.xml create mode 100644 samples/native-image-sample/src/main/java/com/example/bigtable/NativeImageBigtableSample.java create mode 100644 samples/native-image-sample/src/test/java/com/example/bigtable/NativeImageBigtableTest.java diff --git a/README.md b/README.md index 993179ae52..49da4e0e1d 100644 --- a/README.md +++ b/README.md @@ -472,6 +472,7 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-bigtable/tree | Sample | Source Code | Try it | | --------------------------- | --------------------------------- | ------ | +| Native Image Bigtable Sample | [source code](https://github.com/googleapis/java-bigtable/blob/main/samples/native-image-sample/src/main/java/com/example/bigtable/NativeImageBigtableSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-bigtable&page=editor&open_in_editor=samples/native-image-sample/src/main/java/com/example/bigtable/NativeImageBigtableSample.java) | | Configure Connection Pool | [source code](https://github.com/googleapis/java-bigtable/blob/main/samples/snippets/src/main/java/com/example/bigtable/ConfigureConnectionPool.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-bigtable&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/bigtable/ConfigureConnectionPool.java) | | Filters | [source code](https://github.com/googleapis/java-bigtable/blob/main/samples/snippets/src/main/java/com/example/bigtable/Filters.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-bigtable&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/bigtable/Filters.java) | | Hello World | [source code](https://github.com/googleapis/java-bigtable/blob/main/samples/snippets/src/main/java/com/example/bigtable/HelloWorld.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-bigtable&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/bigtable/HelloWorld.java) | diff --git a/samples/native-image-sample/README.md b/samples/native-image-sample/README.md new file mode 100644 index 0000000000..a6b38de140 --- /dev/null +++ b/samples/native-image-sample/README.md @@ -0,0 +1,113 @@ +# BigTable Sample Application with Native Image + +This application uses the [Google Cloud BigTable Client Libraries](https://cloud.google.com/bigtable/docs/reference/libraries) and is compatible with Native Image compilation. + +The application runs through some simple BigTable Client Library operations to demonstrate compatibility. + +## Setup Instructions + +You will need to follow these prerequisite steps in order to run the samples: + +1. If you have not already, [create a Google Cloud Platform Project](https://cloud.google.com/resource-manager/docs/creating-managing-projects#creating_a_project). + +2. Install the [Google Cloud SDK](https://cloud.google.com/sdk/) which will allow you to run the sample with your project's credentials. + + Once installed, log in with Application Default Credentials using the following command: + + ``` + gcloud auth application-default login + ``` + + **Note:** Authenticating with Application Default Credentials is convenient to use during development, but we recommend [alternate methods of authentication](https://cloud.google.com/docs/authentication/production) during production use. + +3. Install the GraalVM compiler. + + You can follow the [official installation instructions](https://www.graalvm.org/docs/getting-started/#install-graalvm) from the GraalVM website. + After following the instructions, ensure that you install the native image extension installed by running: + + ``` + gu install native-image + ``` + + Once you finish following the instructions, verify that the default version of Java is set to the GraalVM version by running `java -version` in a terminal. + + You will see something similar to the below output: + + ``` + $ java -version + + openjdk version "11.0.7" 2020-04-14 + OpenJDK Runtime Environment GraalVM CE 20.1.0 (build 11.0.7+10-jvmci-20.1-b02) + OpenJDK 64-Bit Server VM GraalVM CE 20.1.0 (build 11.0.7+10-jvmci-20.1-b02, mixed mode, sharing) + ``` + +## BigTable Environment setup +The following sections describe how you can run the sample application against the BigTable emulator or a real BigTable instance. + +1. *(Using emulator)* If you wish to run the application against the [BigTable emulator](https://cloud.google.com/bigtable/docs/emulator), ensure that you have the [Google Cloud SDK](https://cloud.google.com/sdk) installed. + + In a new terminal window, start the emulator via `gcloud`: + + ``` + gcloud beta emulators bigtable start --host-port=localhost:9010 + ``` + + Leave the emulator running in this terminal for now. + In the next section, we will run the sample application against the BigTable emulator instance. + +2. *(Using real BigTable instance)* If instead you wish to run the application against a real BigTable instance, ensure you already have a BigTable instance created. + + For example, the following command creates a new BigTable instance named `nativeimage-test-instance`. + + ``` + gcloud bigtable instances create nativeimage-test-instance \ + --cluster=nativeimage-test-cluster \ + --cluster-zone=us-central1-c \ + --cluster-num-nodes=1 \ + --display-name=nativeimage-test-instance + ``` + + You can also manually manage your BigTable resources through the [BigTable Cloud Console view](http://console.cloud.google.com/bigtable). + +## Run with Native Image Compilation + +1. Compile the application with the Native Image compiler. + + ``` + mvn package -P native -DskipTests + ``` + +2. **(Optional)** If you're using the emulator, export the `BIGTABLE_EMULATOR_HOST` as an environment variable in your terminal. + + ``` + export BIGTABLE_EMULATOR_HOST=localhost:9010 + ``` + + The BigTable Client Libraries will detect this environment variable and automatically connect to the emulator instance if this variable is set. + +3. Run the application. + Pass in the BigTable instance you wish to use via the `-Dbigtable.instance` property. + + ``` + ./target/bigtable-sample -Dbigtable.instance={BIGTABLE_INSTANCE_NAME} + ``` + +4. The application will run through some basic BigTable operations and log some output statements. + + ``` + Created table: nativeimage-test-table2b5b0031-f4ea-4c39-bc0c-bf6c3c62c90c + Successfully wrote row: phone#1608775178843000 + Reading phone data in table: + Key: phone#1608775178843000 + connected_cell: @1608775178843000 + connected_wifi: @1608775178843000 + os_build: PQ2A.190405.003 @1608775178843000 + Deleted table: nativeimage-test-table2b5b0031-f4ea-4c39-bc0c-bf6c3c62c90c + ``` +## Run integration test for the sample + +In order to run the sample's integration test, call the following command: + + ``` + mvn test -P native + ``` \ No newline at end of file diff --git a/samples/native-image-sample/pom.xml b/samples/native-image-sample/pom.xml new file mode 100644 index 0000000000..b3f1fd3bda --- /dev/null +++ b/samples/native-image-sample/pom.xml @@ -0,0 +1,139 @@ + + + 4.0.0 + com.example.bigtable + native-image-sample + Native Image Sample + https://github.com/googleapis/java-bigtable + + + + com.google.cloud.samples + shared-configuration + 1.2.0 + + + + 1.8 + 1.8 + UTF-8 + + + + + + + + com.google.cloud + libraries-bom + 24.2.0 + pom + import + + + + + + + com.google.cloud + google-cloud-bigtable + + + + + junit + junit + 4.13.2 + test + + + com.google.truth + truth + 1.1.3 + test + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + com.example.bigquery.NativeImageBigtableSample + + + + + + + + + + + + native + + + + com.google.cloud + native-image-support + 0.10.0 + + + org.junit.vintage + junit-vintage-engine + 5.8.2 + test + + + org.graalvm.buildtools + junit-platform-native + 0.9.9 + test + + + + + + + org.graalvm.buildtools + native-maven-plugin + 0.9.9 + true + + com.example.bigtable.NativeImageBigtableSample + + + --no-fallback + --no-server + + + + + build-native + + build + test + + package + + + test-native + + test + + test + + + + + + + + \ No newline at end of file diff --git a/samples/native-image-sample/src/main/java/com/example/bigtable/NativeImageBigtableSample.java b/samples/native-image-sample/src/main/java/com/example/bigtable/NativeImageBigtableSample.java new file mode 100644 index 0000000000..99d902721b --- /dev/null +++ b/samples/native-image-sample/src/main/java/com/example/bigtable/NativeImageBigtableSample.java @@ -0,0 +1,148 @@ +/* + * Copyright 2020-2021 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.example.bigtable; + +import com.google.api.gax.rpc.ServerStream; +import com.google.cloud.ServiceOptions; +import com.google.cloud.bigtable.admin.v2.BigtableInstanceAdminClient; +import com.google.cloud.bigtable.admin.v2.BigtableInstanceAdminSettings; +import com.google.cloud.bigtable.admin.v2.BigtableTableAdminClient; +import com.google.cloud.bigtable.admin.v2.BigtableTableAdminSettings; +import com.google.cloud.bigtable.admin.v2.models.CreateInstanceRequest; +import com.google.cloud.bigtable.admin.v2.models.CreateTableRequest; +import com.google.cloud.bigtable.admin.v2.models.Instance; +import com.google.cloud.bigtable.admin.v2.models.StorageType; +import com.google.cloud.bigtable.data.v2.BigtableDataClient; +import com.google.cloud.bigtable.data.v2.BigtableDataSettings; +import com.google.cloud.bigtable.data.v2.models.Query; +import com.google.cloud.bigtable.data.v2.models.Row; +import com.google.cloud.bigtable.data.v2.models.RowCell; +import com.google.cloud.bigtable.data.v2.models.RowMutation; +import com.google.common.collect.ImmutableMap; +import com.google.protobuf.ByteString; +import java.io.IOException; +import java.util.Map.Entry; +import java.util.UUID; + +/** Sample Cloud BigTable application. */ +public class NativeImageBigtableSample { + + private static final String INSTANCE_NAME = + System.getProperty("bigtable.instance", "nativeimage-test-instance"); + private static final String TABLE_NAME = "nativeimage-test-"; + + private static final String COLUMN_FAMILY_NAME = "stats_summary"; + + /** Entrypoint to the BigTable sample application. */ + public static void main(String[] args) throws IOException { + String projectId = ServiceOptions.getDefaultProjectId(); + + BigtableTableAdminSettings adminClientSettings = + BigtableTableAdminSettings.newBuilder() + .setInstanceId(INSTANCE_NAME) + .setProjectId(projectId) + .build(); + BigtableDataSettings clientSettings = + BigtableDataSettings.newBuilder() + .setInstanceId(INSTANCE_NAME) + .setProjectId(projectId) + .build(); + BigtableInstanceAdminSettings instanceAdminSettings = + BigtableInstanceAdminSettings.newBuilder().setProjectId(projectId).build(); + + BigtableTableAdminClient adminClient = BigtableTableAdminClient.create(adminClientSettings); + BigtableDataClient standardClient = BigtableDataClient.create(clientSettings); + BigtableInstanceAdminClient instanceAdminClient = + BigtableInstanceAdminClient.create(instanceAdminSettings); + + if (!instanceAdminClient.exists(INSTANCE_NAME)) { + instanceAdminClient.createInstance( + CreateInstanceRequest.of(INSTANCE_NAME) + .addCluster("cluster", "us-central1-f", 3, StorageType.SSD) + .setType(Instance.Type.PRODUCTION) + .addLabel("example", "instance_admin")); + } + String tableName = TABLE_NAME + UUID.randomUUID().toString().replace("-", ""); + + createTable(adminClient, tableName); + + // Add data into table + ImmutableMap dataWithLong = + ImmutableMap.of("connected_cell", 1L, "connected_wifi", 1L); + ImmutableMap dataWithStrings = ImmutableMap.of("os_build", "PQ2A.190405.003"); + + long timestamp = System.currentTimeMillis() * 1000; + insertData(standardClient, tableName, timestamp, dataWithLong, dataWithStrings); + readData(standardClient, tableName); + + // Clean up + deleteTable(adminClient, tableName); + } + + static void readData(BigtableDataClient client, String tableId) { + Query query = Query.create(tableId).prefix(""); + ServerStream rows = client.readRows(query); + + System.out.println("Reading phone data in table:"); + for (Row row : rows) { + System.out.println("Key: " + row.getKey().toStringUtf8()); + for (RowCell cell : row.getCells()) { + System.out.printf( + "\t%s: %s @%s\n", + cell.getQualifier().toStringUtf8(), + cell.getValue().toStringUtf8(), + cell.getTimestamp()); + } + System.out.println(); + } + } + + public static void insertData( + BigtableDataClient client, + String tableId, + long timestamp, + ImmutableMap dataWithLong, + ImmutableMap dataWithStrings) { + String rowKey = String.format("phone#%d", timestamp); + RowMutation rowMutation = RowMutation.create(tableId, rowKey); + for (Entry longEntry : dataWithLong.entrySet()) { + rowMutation.setCell( + COLUMN_FAMILY_NAME, + ByteString.copyFrom(longEntry.getKey().getBytes()), + timestamp, + longEntry.getValue()); + } + + for (Entry stringEntry : dataWithStrings.entrySet()) { + rowMutation.setCell( + COLUMN_FAMILY_NAME, stringEntry.getKey(), timestamp, stringEntry.getValue()); + } + + client.mutateRow(rowMutation); + System.out.println("Successfully wrote row: " + rowKey); + } + + public static void createTable(BigtableTableAdminClient adminClient, String table) { + adminClient.createTable(CreateTableRequest.of(table).addFamily(COLUMN_FAMILY_NAME)); + System.out.println("Created table: " + table); + } + + static void deleteTable(BigtableTableAdminClient adminClient, String table) { + adminClient.deleteTable(table); + System.out.println("Deleted table: " + table); + } +} diff --git a/samples/native-image-sample/src/test/java/com/example/bigtable/NativeImageBigtableTest.java b/samples/native-image-sample/src/test/java/com/example/bigtable/NativeImageBigtableTest.java new file mode 100644 index 0000000000..f1ecf94661 --- /dev/null +++ b/samples/native-image-sample/src/test/java/com/example/bigtable/NativeImageBigtableTest.java @@ -0,0 +1,122 @@ +/* + * Copyright 2022 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.example.bigtable; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.cloud.ServiceOptions; +import com.google.cloud.bigtable.admin.v2.BigtableInstanceAdminClient; +import com.google.cloud.bigtable.admin.v2.BigtableInstanceAdminSettings; +import com.google.cloud.bigtable.admin.v2.BigtableTableAdminClient; +import com.google.cloud.bigtable.admin.v2.BigtableTableAdminSettings; +import com.google.cloud.bigtable.admin.v2.models.CreateInstanceRequest; +import com.google.cloud.bigtable.admin.v2.models.Instance; +import com.google.cloud.bigtable.admin.v2.models.StorageType; +import com.google.cloud.bigtable.data.v2.BigtableDataClient; +import com.google.cloud.bigtable.data.v2.BigtableDataSettings; +import com.google.common.collect.ImmutableMap; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.time.Instant; +import java.util.UUID; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class NativeImageBigtableTest { + + private static final String INSTANCE_NAME = + System.getProperty("bigtable.instance", "nativeimage-it-instance"); + private static final String TABLE_SUFFIX = "nativeimage-it-"; + + private static final String PROJECT_ID = ServiceOptions.getDefaultProjectId(); + + private static final Instant TIMESTAMP = Instant.EPOCH; + + private String tableName; + private BigtableDataClient dataClient; + private BigtableTableAdminClient adminClient; + + private static PrintStream originalOut; + public ByteArrayOutputStream bout; + + @After + public void tearDown() { + System.setOut(originalOut); + bout.reset(); + } + + @Before + public void setUp() throws IOException { + // Create instance if not present + BigtableInstanceAdminSettings instanceAdminSettings = + BigtableInstanceAdminSettings.newBuilder().setProjectId(PROJECT_ID).build(); + BigtableInstanceAdminClient instanceAdminClient = + BigtableInstanceAdminClient.create(instanceAdminSettings); + if (!instanceAdminClient.exists(INSTANCE_NAME)) { + instanceAdminClient.createInstance( + CreateInstanceRequest.of(INSTANCE_NAME) + .addCluster("cluster", "us-central1-f", 3, StorageType.SSD) + .setType(Instance.Type.PRODUCTION) + .addLabel("example", "instance_admin")); + } + + BigtableTableAdminSettings adminClientSettings = + BigtableTableAdminSettings.newBuilder() + .setInstanceId(INSTANCE_NAME) + .setProjectId(PROJECT_ID) + .build(); + BigtableDataSettings clientSettings = + BigtableDataSettings.newBuilder() + .setInstanceId(INSTANCE_NAME) + .setProjectId(PROJECT_ID) + .build(); + adminClient = BigtableTableAdminClient.create(adminClientSettings); + tableName = TABLE_SUFFIX + UUID.randomUUID().toString().replace("-", ""); + NativeImageBigtableSample.createTable(adminClient, tableName); + + dataClient = BigtableDataClient.create(clientSettings); + + // To test output stream + originalOut = System.out; + bout = new ByteArrayOutputStream(); + System.setOut(new PrintStream(bout)); + } + + @Test + public void testReadData() { + ImmutableMap dataWithInts = ImmutableMap.of("connection_cell", 1L); + ImmutableMap dataWithStrings = ImmutableMap.of("os_build", "build_value"); + NativeImageBigtableSample.insertData( + dataClient, tableName, TIMESTAMP.getEpochSecond(), dataWithInts, dataWithStrings); + + NativeImageBigtableSample.readData(dataClient, tableName); + + String output = bout.toString(); + assertThat(output) + .contains( + "Successfully wrote row: phone#0\n" + + "Reading phone data in table:\n" + + "Key: phone#0\n" + + "\tconnection_cell: \u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001 @0\n" + + "\tos_build: build_value @0\n\n"); + + // Clean up + NativeImageBigtableSample.deleteTable(adminClient, tableName); + } +} diff --git a/samples/pom.xml b/samples/pom.xml index a05f97835d..fb2c11e27f 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -31,6 +31,7 @@ install-without-bom snapshot snippets + native-image-sample