diff --git a/samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithVersionRetentionPeriodSample.java b/samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithVersionRetentionPeriodSample.java new file mode 100644 index 0000000000..1eaa7c403d --- /dev/null +++ b/samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithVersionRetentionPeriodSample.java @@ -0,0 +1,86 @@ +/* + * Copyright 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 + * + * http://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.spanner; + +// [START spanner_create_database_with_version_retention_period] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.spanner.Database; +import com.google.cloud.spanner.DatabaseAdminClient; +import com.google.cloud.spanner.Spanner; +import com.google.cloud.spanner.SpannerException; +import com.google.cloud.spanner.SpannerExceptionFactory; +import com.google.cloud.spanner.SpannerOptions; +import com.google.spanner.admin.database.v1.CreateDatabaseMetadata; +import java.util.Arrays; +import java.util.concurrent.ExecutionException; + +public class CreateDatabaseWithVersionRetentionPeriodSample { + + static void createDatabaseWithVersionRetentionPeriod() { + // TODO(developer): Replace these variables before running the sample. + String projectId = "my-project"; + String instanceId = "my-instance"; + String databaseId = "my-database"; + String versionRetentionPeriod = "7d"; + + try (Spanner spanner = + SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) { + DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient(); + createDatabaseWithVersionRetentionPeriod(adminClient, instanceId, databaseId, + versionRetentionPeriod); + } + } + + static void createDatabaseWithVersionRetentionPeriod(DatabaseAdminClient adminClient, + String instanceId, String databaseId, String versionRetentionPeriod) { + OperationFuture op = + adminClient.createDatabase( + instanceId, + databaseId, + Arrays.asList( + "CREATE TABLE Singers (" + + " SingerId INT64 NOT NULL," + + " FirstName STRING(1024)," + + " LastName STRING(1024)," + + " SingerInfo BYTES(MAX)" + + ") PRIMARY KEY (SingerId)", + "CREATE TABLE Albums (" + + " SingerId INT64 NOT NULL," + + " AlbumId INT64 NOT NULL," + + " AlbumTitle STRING(MAX)" + + ") PRIMARY KEY (SingerId, AlbumId)," + + " INTERLEAVE IN PARENT Singers ON DELETE CASCADE", + "ALTER DATABASE " + "`" + databaseId + "`" + + " SET OPTIONS ( version_retention_period = '" + versionRetentionPeriod + "' )" + )); + try { + Database database = op.get(); + System.out.println("Created database [" + database.getId() + "]"); + System.out.println("\tVersion retention period: " + database.getVersionRetentionPeriod()); + System.out.println("\tEarliest version time: " + database.getEarliestVersionTime()); + } catch (ExecutionException e) { + // If the operation failed during execution, expose the cause. + throw (SpannerException) e.getCause(); + } catch (InterruptedException e) { + // Throw when a thread is waiting, sleeping, or otherwise occupied, + // and the thread is interrupted, either before or during the activity. + throw SpannerExceptionFactory.propagateInterrupt(e); + } + } +} +// [END spanner_create_database_with_version_retention_period] diff --git a/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java b/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java index 874088775b..f7ac1113c3 100644 --- a/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java +++ b/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java @@ -1584,8 +1584,8 @@ static void queryWithQueryOptions(DatabaseClient dbClient) { // [END spanner_query_with_query_options] // [START spanner_create_backup] - static void createBackup( - DatabaseAdminClient dbAdminClient, DatabaseId databaseId, BackupId backupId) { + static void createBackup(DatabaseAdminClient dbAdminClient, DatabaseId databaseId, + BackupId backupId, Timestamp versionTime) { // Set expire time to 14 days from now. Timestamp expireTime = Timestamp.ofTimeMicroseconds(TimeUnit.MICROSECONDS.convert( System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14), TimeUnit.MILLISECONDS)); @@ -1594,6 +1594,7 @@ static void createBackup( .newBackupBuilder(backupId) .setDatabase(databaseId) .setExpireTime(expireTime) + .setVersionTime(versionTime) .build(); // Initiate the request which returns an OperationFuture. System.out.println("Creating backup [" + backup.getId() + "]..."); @@ -1612,13 +1613,18 @@ static void createBackup( backup = backup.reload(); System.out.println( String.format( - "Backup %s of size %d bytes was created at %s", + "Backup %s of size %d bytes was created at %s for version of database at %s", backup.getId().getName(), backup.getSize(), LocalDateTime.ofEpochSecond( backup.getProto().getCreateTime().getSeconds(), backup.getProto().getCreateTime().getNanos(), - OffsetDateTime.now().getOffset())).toString()); + OffsetDateTime.now().getOffset()), + LocalDateTime.ofEpochSecond( + backup.getProto().getVersionTime().getSeconds(), + backup.getProto().getVersionTime().getNanos(), + OffsetDateTime.now().getOffset()) + )); } // [END spanner_create_backup] @@ -1820,12 +1826,16 @@ static void restoreBackup( Database db = op.get(); // Refresh database metadata and get the restore info. RestoreInfo restore = db.reload().getRestoreInfo(); + Timestamp versionTime = Timestamp.fromProto(restore + .getProto() + .getBackupInfo() + .getVersionTime()); System.out.println( "Restored database [" + restore.getSourceDatabase().getName() + "] from [" + restore.getBackup().getName() - + "]"); + + "] with version time [" + versionTime + "]"); } catch (ExecutionException e) { throw SpannerExceptionFactory.newSpannerException(e.getCause()); } catch (InterruptedException e) { @@ -2044,7 +2054,7 @@ static void run( queryWithQueryOptions(dbClient); break; case "createbackup": - createBackup(dbAdminClient, database, backup); + createBackup(dbAdminClient, database, backup, getVersionTime(dbClient)); break; case "cancelcreatebackup": cancelCreateBackup( @@ -2079,6 +2089,17 @@ static void run( } } + static Timestamp getVersionTime(DatabaseClient dbClient) { + // Generates a version time for the backup + Timestamp versionTime; + try (ResultSet resultSet = dbClient.singleUse() + .executeQuery(Statement.of("SELECT CURRENT_TIMESTAMP()"))) { + resultSet.next(); + versionTime = resultSet.getTimestamp(0); + } + return versionTime; + } + static void printUsageAndExit() { System.err.println("Usage:"); System.err.println(" SpannerExample "); @@ -2177,6 +2198,7 @@ public static void main(String[] args) throws Exception { InstanceAdminClient instanceAdminClient = spanner.getInstanceAdminClient(); // Use client here... // [END init_client] + run(dbClient, dbAdminClient, instanceAdminClient, command, db, backup); // [START init_client] } finally { diff --git a/samples/snippets/src/test/java/com/example/spanner/CreateDatabaseWithVersionRetentionPeriodSampleIT.java b/samples/snippets/src/test/java/com/example/spanner/CreateDatabaseWithVersionRetentionPeriodSampleIT.java new file mode 100644 index 0000000000..34a732b19a --- /dev/null +++ b/samples/snippets/src/test/java/com/example/spanner/CreateDatabaseWithVersionRetentionPeriodSampleIT.java @@ -0,0 +1,115 @@ +/* + * Copyright 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 + * + * http://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.spanner; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.cloud.spanner.DatabaseAdminClient; +import com.google.cloud.spanner.Spanner; +import com.google.cloud.spanner.SpannerOptions; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Integration tests for {@link CreateDatabaseWithVersionRetentionPeriodSample} + */ +@RunWith(JUnit4.class) +public class CreateDatabaseWithVersionRetentionPeriodSampleIT { + + private static String projectId; + private static final String instanceId = System.getProperty("spanner.test.instance"); + private static final String baseDatabaseId = System.getProperty( + "spanner.sample.database", + "pitrsample" + ); + private static DatabaseAdminClient databaseAdminClient; + private static List databasesToDrop; + private static Spanner spanner; + + private String runSample( + String databaseId, + String versionRetentionPeriod + ) { + final PrintStream stdOut = System.out; + final ByteArrayOutputStream bout = new ByteArrayOutputStream(); + final PrintStream out = new PrintStream(bout); + System.setOut(out); + CreateDatabaseWithVersionRetentionPeriodSample.createDatabaseWithVersionRetentionPeriod( + databaseAdminClient, + instanceId, + databaseId, + versionRetentionPeriod + ); + System.setOut(stdOut); + return bout.toString(); + } + + @BeforeClass + public static void setUp() { + final SpannerOptions options = SpannerOptions + .newBuilder() + .setAutoThrottleAdministrativeRequests() + .build(); + projectId = options.getProjectId(); + spanner = options.getService(); + databaseAdminClient = spanner.getDatabaseAdminClient(); + databasesToDrop = new ArrayList<>(); + } + + @AfterClass + public static void tearDown() { + for (String databaseId : databasesToDrop) { + try { + databaseAdminClient.dropDatabase(instanceId, databaseId); + } catch (Exception e) { + System.out.println("Failed to drop database " + databaseId + ", skipping..."); + } + } + spanner.close(); + } + + @Test + public void createsDatabaseWithVersionRetentionPeriod() { + final String databaseId = generateDatabaseId(); + final String versionRetentionPeriod = "7d"; + + final String out = runSample(databaseId, versionRetentionPeriod); + + assertThat(out).contains( + "Created database [projects/" + projectId + "/instances/" + instanceId + "/databases/" + + databaseId + "]"); + assertThat(out).contains("Version retention period: " + versionRetentionPeriod); + } + + static String generateDatabaseId() { + final String databaseId = ( + baseDatabaseId + + "-" + + UUID.randomUUID().toString().replaceAll("-", "") + ).substring(0, 30); + databasesToDrop.add(databaseId); + return databaseId; + } +} diff --git a/samples/snippets/src/test/java/com/example/spanner/SpannerSampleIT.java b/samples/snippets/src/test/java/com/example/spanner/SpannerSampleIT.java index dee5816b38..32feedd9f7 100644 --- a/samples/snippets/src/test/java/com/example/spanner/SpannerSampleIT.java +++ b/samples/snippets/src/test/java/com/example/spanner/SpannerSampleIT.java @@ -439,4 +439,4 @@ private static Pattern getTestDbIdPattern(String baseDbId) { static String formatForTest(String name) { return name + "-" + UUID.randomUUID().toString().substring(0, DBID_LENGTH); } -} \ No newline at end of file +}