From 10ab028570a611e4f433e5eedabb548422ecda4e Mon Sep 17 00:00:00 2001 From: Anshul Goyal Date: Fri, 18 Feb 2022 23:35:12 +0530 Subject: [PATCH 01/21] feat: copy backup - porting code changes --- .../com/google/cloud/spanner/BackupInfo.java | 9 ++ .../cloud/spanner/DatabaseAdminClient.java | 76 ++++++++++++++++ .../spanner/DatabaseAdminClientImpl.java | 46 ++++++++++ .../EncryptionConfigProtoMapper.java | 23 +++++ .../cloud/spanner/spi/v1/GapicSpannerRpc.java | 68 ++++++++++++++ .../cloud/spanner/spi/v1/SpannerRpc.java | 14 +++ .../com/google/cloud/spanner/BackupTest.java | 14 +++ .../spanner/DatabaseAdminClientImplTest.java | 88 +++++++++++++++++++ 8 files changed, 338 insertions(+) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java index 0657ff2b7b8..6bd553bb27b 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java @@ -82,6 +82,8 @@ public abstract static class Builder { */ public abstract Builder setDatabase(DatabaseId database); + public abstract Builder setSourceBackup(String sourceBackup); + /** Builds the backup from this builder. */ public abstract Backup build(); } @@ -95,6 +97,7 @@ abstract static class BuilderImpl extends Builder { private long size; private BackupEncryptionConfig encryptionConfig; private EncryptionInfo encryptionInfo; + private String sourceBackup; private com.google.spanner.admin.database.v1.Backup proto; BuilderImpl(BackupId id) { @@ -125,6 +128,12 @@ public Builder setExpireTime(Timestamp expireTime) { return this; } + @Override + public Builder setSourceBackup(String sourceBackup) { + this.sourceBackup = Preconditions.checkNotNull(sourceBackup); + return this; + } + @Override public Builder setVersionTime(Timestamp versionTime) { this.versionTime = versionTime; diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java index 2e4fd09951e..8532011c23a 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java @@ -22,11 +22,13 @@ import com.google.cloud.Timestamp; import com.google.cloud.spanner.Options.ListOption; import com.google.longrunning.Operation; +import com.google.spanner.admin.database.v1.CopyBackupMetadata; import com.google.spanner.admin.database.v1.CreateBackupMetadata; import com.google.spanner.admin.database.v1.CreateDatabaseMetadata; import com.google.spanner.admin.database.v1.CreateDatabaseRequest; import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata; import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; + import java.util.List; import javax.annotation.Nullable; @@ -178,6 +180,66 @@ OperationFuture createBackup( */ OperationFuture createBackup(Backup backup) throws SpannerException; + /** + * Creates a copy of backup from an existing database backup in a Cloud Spanner instance. + * + *

Example to create a backup. + * + *

{@code
+   * String instance       = my_instance_id;
+   * String backupId       = my_backup_id;
+   * String databaseId     = my_database_id;
+   * Timestamp expireTime  = Timestamp.ofTimeMicroseconds(micros);
+   * OperationFuture op = dbAdminClient
+   *     .createBackup(
+   *         instanceId,
+   *         backupId,
+   *         databaseId,
+   *         expireTime);
+   * Backup backup = op.get();
+   * }
+ * + * @param sourceInstanceId the id of the instance where the database to backup is located and + * where the backup will be created. + * @param backupId the id of the backup which will be created. It must conform to the regular + * expression [a-z][a-z0-9_\-]*[a-z0-9] and be between 2 and 60 characters in length. + * @param sourceBackup the source backup id. + * @param expireTime the time that the backup will automatically expire. + */ + OperationFuture copyBackup( + String sourceInstanceId, String backupId, String sourceBackup, Timestamp expireTime) + throws SpannerException; + + + /** + * Creates a copy of backup from an existing database backup in Cloud Spanner. Any configuration options in the + * {@link Backup} instance will be included in the {@link + * com.google.spanner.admin.database.v1.CopyBackupRequest}. + * + *

Example to create an encrypted backup. + * + *

{@code
+   * BackupId backupId = BackupId.of("project", "instance", "backup-id");
+   * Timestamp expireTime = Timestamp.ofTimeMicroseconds(expireTimeMicros);
+   * EncryptionConfig encryptionConfig =
+   *         EncryptionConfig.ofKey(
+   *             "projects/my-project/locations/some-location/keyRings/my-keyring/cryptoKeys/my-key"));
+   *
+   * Backup backupToCopy = dbAdminClient
+   *     .newBackupBuilder(backupId)
+   *     .setExpireTime(expireTime)
+   *     .setVersionTime(versionTime)
+   *     .setEncryptionConfig(encryptionConfig)
+   *     .build();
+   *
+   * OperationFuture op = dbAdminClient.copyBackUp(backupToCopy);
+   * Backup copiedBackup = op.get();
+   * }
+ * + * @param backup the backup to be copied + */ + OperationFuture copyBackup(Backup backup) throws SpannerException; + /** * Restore a database from a backup. The database that is restored will be created and may not * already exist. @@ -267,6 +329,20 @@ OperationFuture restoreDatabase(Restore resto */ Backup getBackup(String instanceId, String backupId) throws SpannerException; + /** + * Creates a copy backup within this instance. + * + *

Example to get a backup. + * + *

{@code
+   * String sourceBackupId = source_backup_id;
+   * String backupId   = my_backup_id;
+   * Timestamp expireTime = expire_time;
+   * Backup backup = dbAdminClient.copyBackup(sourceBackupId, backupId, expireTime);
+   * }
+ */ +// Backup copyBackup(String sourceBackupId, Timestamp expireTime) throws SpannerException; + /** * Enqueues the given DDL statements to be applied, in order but not necessarily all at once, to * the database schema at some point (or points) in the future. The server checks that the diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java index 52df8701556..4dfe745b5f4 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java @@ -32,10 +32,12 @@ import com.google.longrunning.Operation; import com.google.protobuf.Empty; import com.google.protobuf.FieldMask; +import com.google.spanner.admin.database.v1.CopyBackupMetadata; import com.google.spanner.admin.database.v1.CreateBackupMetadata; import com.google.spanner.admin.database.v1.CreateDatabaseMetadata; import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata; import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; + import java.util.List; import java.util.UUID; import javax.annotation.Nullable; @@ -165,6 +167,50 @@ public OperationFuture createBackup(Backup backupI }); } + @Override + public OperationFuture copyBackup( + String instanceId,String backupId, String sourceBackUp, Timestamp expireTime) + throws SpannerException { + final Backup backupInfo = + newBackupBuilder(BackupId.of(projectId, instanceId, backupId)) + .setExpireTime(expireTime) + .setSourceBackup(sourceBackUp) + .build(); + + return copyBackup(backupInfo); + } + + @Override + public OperationFuture copyBackup(Backup backupInfo) + throws SpannerException { + Preconditions.checkArgument( + backupInfo.getId() != null, "Cannot create a backup without a source backup"); + + final OperationFuture + rawOperationFuture = rpc.copyBackUp(backupInfo); + + return new OperationFutureImpl<>( + rawOperationFuture.getPollingFuture(), + rawOperationFuture.getInitialFuture(), + snapshot -> { + com.google.spanner.admin.database.v1.Backup proto = + ProtoOperationTransformers.ResponseTransformer.create( + com.google.spanner.admin.database.v1.Backup.class) + .apply(snapshot); + return Backup.fromProto( + com.google.spanner.admin.database.v1.Backup.newBuilder(proto) + .setName(proto.getName()) + .setExpireTime(proto.getExpireTime()) + .setEncryptionInfo(proto.getEncryptionInfo()) + .build(), + DatabaseAdminClientImpl.this); + }, + ProtoOperationTransformers.MetadataTransformer.create(CopyBackupMetadata.class), + e -> { + throw SpannerExceptionFactory.newSpannerException(e); + }); + } + @Override public Backup updateBackup(String instanceId, String backupId, Timestamp expireTime) { String backupName = getBackupName(instanceId, backupId); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/encryption/EncryptionConfigProtoMapper.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/encryption/EncryptionConfigProtoMapper.java index 0a18e9844a1..c39ad12882f 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/encryption/EncryptionConfigProtoMapper.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/encryption/EncryptionConfigProtoMapper.java @@ -16,6 +16,7 @@ package com.google.cloud.spanner.encryption; +import com.google.spanner.admin.database.v1.CopyBackupEncryptionConfig; import com.google.spanner.admin.database.v1.CreateBackupEncryptionConfig; import com.google.spanner.admin.database.v1.EncryptionConfig; import com.google.spanner.admin.database.v1.RestoreDatabaseEncryptionConfig; @@ -50,6 +51,28 @@ public static CreateBackupEncryptionConfig createBackupEncryptionConfig( } } + /** Returns an encryption config to be used for a copy backup. */ + public static CopyBackupEncryptionConfig copyBackupEncryptionConfig( + BackupEncryptionConfig config) { + if (config instanceof CustomerManagedEncryption) { + return CopyBackupEncryptionConfig.newBuilder() + .setEncryptionType( + CopyBackupEncryptionConfig.EncryptionType.CUSTOMER_MANAGED_ENCRYPTION) + .setKmsKeyName(((CustomerManagedEncryption) config).getKmsKeyName()) + .build(); + } else if (config instanceof GoogleDefaultEncryption) { + return CopyBackupEncryptionConfig.newBuilder() + .setEncryptionType(CopyBackupEncryptionConfig.EncryptionType.GOOGLE_DEFAULT_ENCRYPTION) + .build(); + } else if (config instanceof UseBackupEncryption) { + return CopyBackupEncryptionConfig.newBuilder() + .setEncryptionType(CopyBackupEncryptionConfig.EncryptionType.USE_CONFIG_DEFAULT_OR_BACKUP_ENCRYPTION) + .build(); + } else { + throw new IllegalArgumentException("Unknown backup encryption configuration " + config); + } + } + /** Returns an encryption config to be used for a database restore. */ public static RestoreDatabaseEncryptionConfig restoreDatabaseEncryptionConfig( RestoreEncryptionConfig config) { diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java index 98a7e0927f3..06c08016e13 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java @@ -102,6 +102,8 @@ import com.google.protobuf.Message; import com.google.protobuf.Timestamp; import com.google.spanner.admin.database.v1.Backup; +import com.google.spanner.admin.database.v1.CopyBackupMetadata; +import com.google.spanner.admin.database.v1.CopyBackupRequest; import com.google.spanner.admin.database.v1.CreateBackupMetadata; import com.google.spanner.admin.database.v1.CreateBackupRequest; import com.google.spanner.admin.database.v1.CreateDatabaseMetadata; @@ -1264,6 +1266,72 @@ public OperationFuture createBackup( NanoClock.getDefaultClock()); } + + @Override + public OperationFuture copyBackUp( + final com.google.cloud.spanner.Backup backupInfo) throws SpannerException { + final String instanceName = backupInfo.getInstanceId().getName(); + final String databaseName = backupInfo.getDatabase().getName(); + final String backupId = backupInfo.getId().getBackup(); + final Backup.Builder backupBuilder = + com.google.spanner.admin.database.v1.Backup.newBuilder() + .setDatabase(databaseName) + .setExpireTime(backupInfo.getExpireTime().toProto()); + if (backupInfo.getVersionTime() != null) { + backupBuilder.setVersionTime(backupInfo.getVersionTime().toProto()); + } + final Backup backup = backupBuilder.build(); + + final CopyBackupRequest.Builder requestBuilder = + CopyBackupRequest.newBuilder() + .setParent(instanceName) + .setBackupId(backupId) + .setSourceBackup(backupId) + .setExpireTime(backup.getExpireTime()) ;//add +30 + + if (backupInfo.getEncryptionConfig() != null) { + requestBuilder.setEncryptionConfig( + EncryptionConfigProtoMapper.copyBackupEncryptionConfig( + backupInfo.getEncryptionConfig())); + } + final CopyBackupRequest request = requestBuilder.build(); + final OperationFutureCallable callable = + new OperationFutureCallable<>( + databaseAdminStub.copyBackupOperationCallable(), + request, + //calling copy backup method of dbClientImpl + DatabaseAdminGrpc.getCopyBackupMethod(), + instanceName, + nextPageToken -> + listBackupOperations( + instanceName, + 0, + String.format( + "(metadata.@type:type.googleapis.com/%s) AND (metadata.name:%s)", + CopyBackupMetadata.getDescriptor().getFullName(), + String.format("%s/backups/%s", instanceName, backupId)), + nextPageToken), + input -> { + try { + return input + .getMetadata() + .unpack(CopyBackupMetadata.class) + .getProgress() + .getStartTime(); + } catch (InvalidProtocolBufferException e) { + return null; + } + }); + return RetryHelper.runWithRetries( + callable, + databaseAdminStubSettings + .copyBackupOperationSettings() + .getInitialCallSettings() + .getRetrySettings(), + new OperationFutureRetryAlgorithm<>(), + NanoClock.getDefaultClock()); + } + @Override public OperationFuture restoreDatabase(final Restore restore) { final String databaseInstanceName = restore.getDestination().getInstanceId().getName(); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java index cce92e0f378..134e82de715 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java @@ -33,6 +33,7 @@ import com.google.protobuf.Empty; import com.google.protobuf.FieldMask; import com.google.spanner.admin.database.v1.Backup; +import com.google.spanner.admin.database.v1.CopyBackupMetadata; import com.google.spanner.admin.database.v1.CreateBackupMetadata; import com.google.spanner.admin.database.v1.CreateDatabaseMetadata; import com.google.spanner.admin.database.v1.Database; @@ -230,6 +231,19 @@ Paginated listBackups( OperationFuture createBackup( com.google.cloud.spanner.Backup backupInfo) throws SpannerException; + + /** + * Creates a copy backup from the source database specified in the {@link + * com.google.cloud.spanner.Backup} instance. + * + * @param backupInfo the backup to create. The instance, database, sourceBackupId and expireTime fields of the + * backup must be filled. + * @return the operation that monitors the backup creation. + */ + OperationFuture copyBackUp( + com.google.cloud.spanner.Backup backupInfo) throws SpannerException; + + /** * Restore a backup into the given database. * diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java index 2f12790437c..009e3be10f5 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java @@ -311,5 +311,19 @@ private Backup createBackup() { .setState(com.google.spanner.admin.database.v1.Backup.State.CREATING) .build(); return Backup.fromProto(proto, dbClient); + + private Backup copyBackup() { + com.google.spanner.admin.database.v1.Backup proto = + com.google.spanner.admin.database.v1.Backup.newBuilder() + .setName(NAME) + .setDatabase(DB) + .setExpireTime( + com.google.protobuf.Timestamp.newBuilder().setSeconds(1000L).setNanos(1000).build()) + .setVersionTime( + com.google.protobuf.Timestamp.newBuilder().setSeconds(2000L).setNanos(2000).build()) + .setEncryptionInfo(ENCRYPTION_INFO) + .setState(com.google.spanner.admin.database.v1.Backup.State.CREATING) + .build(); + return Backup.fromProto(proto, dbClient); } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java index 44a531d4a34..8e953697236 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java @@ -44,6 +44,7 @@ import com.google.protobuf.FieldMask; import com.google.protobuf.Message; import com.google.spanner.admin.database.v1.Backup; +import com.google.spanner.admin.database.v1.CopyBackupMetadata; import com.google.spanner.admin.database.v1.CreateBackupMetadata; import com.google.spanner.admin.database.v1.CreateDatabaseMetadata; import com.google.spanner.admin.database.v1.Database; @@ -51,6 +52,7 @@ import com.google.spanner.admin.database.v1.EncryptionInfo; import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata; import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; + import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -72,6 +74,7 @@ public class DatabaseAdminClientImplTest { private static final String DB_NAME2 = "projects/my-project/instances/my-instance/databases/my-db2"; private static final String BK_ID = "my-bk"; + private static final String SOURCE_BK = "my-bk"; private static final String BK_NAME = "projects/my-project/instances/my-instance/backups/my-bk"; private static final String BK_NAME2 = "projects/my-project/instances/my-instance/backups/my-bk2"; private static final Timestamp EARLIEST_VERSION_TIME = Timestamp.now(); @@ -454,6 +457,91 @@ public void createEncryptedBackup() throws ExecutionException, InterruptedExcept assertThat(op.get().getEncryptionInfo().getKmsKeyVersion()).isEqualTo(KMS_KEY_VERSION); } + @Test + public void copyBackupWithParams() throws Exception { + OperationFuture rawOperationFuture = + OperationFutureUtil.immediateOperationFuture( + "copyBackup", getBackupProto(), CopyBackupMetadata.getDefaultInstance()); + Timestamp t = + Timestamp.ofTimeMicroseconds( + TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()) + + TimeUnit.HOURS.toMicros(28)); + final com.google.cloud.spanner.Backup backup = + client + .newBackupBuilder(BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID)) + .setSourceBackup(SOURCE_BK) + .setExpireTime(t) + .build(); + when(rpc.copyBackUp(backup)).thenReturn(rawOperationFuture); + OperationFuture op = + client.copyBackup(INSTANCE_ID, BK_ID, DB_ID, t); + assertThat(op.isDone()).isTrue(); + assertThat(op.get().getId().getName()).isEqualTo(BK_NAME); + } + + @Test + public void copyBackupWithBackupObject() throws ExecutionException, InterruptedException { + final OperationFuture rawOperationFuture = + OperationFutureUtil.immediateOperationFuture( + "copyBackup", getBackupProto(), CopyBackupMetadata.getDefaultInstance()); + final Timestamp expireTime = + Timestamp.ofTimeMicroseconds( + TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()) + + TimeUnit.HOURS.toMicros(28)); + final Timestamp versionTime = + Timestamp.ofTimeMicroseconds( + TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()) - TimeUnit.DAYS.toMicros(2)); + final com.google.cloud.spanner.Backup requestBackup = + client + .newBackupBuilder(BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID)) + .setSourceBackup(SOURCE_BK) + .setExpireTime(expireTime) + .setVersionTime(versionTime) + .build(); + + when(rpc.copyBackUp(requestBackup)).thenReturn(rawOperationFuture); + + final OperationFuture op = + client.copyBackup(requestBackup); + assertThat(op.isDone()).isTrue(); + assertThat(op.get().getId().getName()).isEqualTo(BK_NAME); + } + + @Test(expected = IllegalArgumentException.class) + public void testCopyBackupNoSource() { + final com.google.cloud.spanner.Backup requestBackup = + client + .newBackupBuilder(BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID)) + .setExpireTime(Timestamp.now()) + .build(); + + client.copyBackup(requestBackup); + } + + @Test + public void copyEncryptedBackup() throws ExecutionException, InterruptedException { + final OperationFuture rawOperationFuture = + OperationFutureUtil.immediateOperationFuture( + "copyBackup", getEncryptedBackupProto(), CopyBackupMetadata.getDefaultInstance()); + final Timestamp t = + Timestamp.ofTimeMicroseconds( + TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()) + + TimeUnit.HOURS.toMicros(28)); + final com.google.cloud.spanner.Backup backup = + client + .newBackupBuilder(BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID)) + .setDatabase(DatabaseId.of(PROJECT_ID, INSTANCE_ID, DB_ID)) + .setExpireTime(t) + .setEncryptionConfig(EncryptionConfigs.customerManagedEncryption(KMS_KEY_NAME)) + .build(); + when(rpc.copyBackUp(backup)).thenReturn(rawOperationFuture); + final OperationFuture op = + client.copyBackup(backup); + assertThat(op.isDone()).isTrue(); + assertThat(op.get().getId().getName()).isEqualTo(BK_NAME); + assertThat(op.get().getEncryptionInfo().getKmsKeyVersion()).isEqualTo(KMS_KEY_VERSION); + } + @Test public void deleteBackup() { client.deleteBackup(INSTANCE_ID, BK_ID); From 1902e8339ec213d4bcb760de503d1c257cf05887 Mon Sep 17 00:00:00 2001 From: Anshul Goyal Date: Fri, 18 Feb 2022 23:55:31 +0530 Subject: [PATCH 02/21] feat: copy backup - porting partial sample --- .../com/example/spanner/SpannerSample.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) 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 d0ccd108145..1e53b792fcf 100644 --- a/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java +++ b/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java @@ -56,6 +56,7 @@ import com.google.common.io.BaseEncoding; import com.google.longrunning.Operation; import com.google.protobuf.InvalidProtocolBufferException; +import com.google.spanner.admin.database.v1.CopyBackupMetadata; import com.google.spanner.admin.database.v1.CreateBackupMetadata; import com.google.spanner.admin.database.v1.CreateDatabaseMetadata; import com.google.spanner.admin.database.v1.OptimizeRestoredDatabaseMetadata; @@ -63,6 +64,7 @@ import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions; import java.math.BigDecimal; +import Java.lang.math.min; import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; @@ -1611,6 +1613,48 @@ static void createBackup(DatabaseAdminClient dbAdminClient, DatabaseId databaseI } // [END spanner_create_backup] + // [START spanner_create_copy_backup] + static void createCopyBackup(String instanceId, String copyBackupId, String sourceBackupPath): + // Creates a copy backup of an existing backup with tables + Instance instance = instanceAdminClient.getInstance(instanceId.getInstance()); + + Timestamp expireTime = Timestamp.ofTimeMicroseconds(TimeUnit.MICROSECONDS.convert( + System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14), TimeUnit.MILLISECONDS)); + + Backup copyBackup = instance.co + + // Initiate the request which returns an OperationFuture. + System.out.println("Creating backup [" + backup.getId() + "]..."); + OperationFuture op = backup.copyBackup(); + try { + // Wait for the backup operation to complete. + backup = op.get(); + System.out.println("Created backup [" + backup.getId() + "]"); + } catch (ExecutionException e) { + throw (SpannerException) e.getCause(); + } catch (InterruptedException e) { + throw SpannerExceptionFactory.propagateInterrupt(e); + } + + // Reload the metadata of the backup from the server. + backup = backup.reload(); + System.out.println( + String.format( + "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()), + LocalDateTime.ofEpochSecond( + backup.getProto().getVersionTime().getSeconds(), + backup.getProto().getVersionTime().getNanos(), + OffsetDateTime.now().getOffset()) + )); + + // [END spanner_create_copy_backup] + // [START spanner_cancel_backup_create] static void cancelCreateBackup( DatabaseAdminClient dbAdminClient, DatabaseId databaseId, BackupId backupId) { @@ -1840,6 +1884,9 @@ static void updateBackup(DatabaseAdminClient dbAdminClient, BackupId backupId) { TimeUnit.SECONDS.toMicros(backup.getExpireTime().getSeconds()) + TimeUnit.NANOSECONDS.toMicros(backup.getExpireTime().getNanos()) + TimeUnit.DAYS.toMicros(30L)); + Timestamp newExpireTime = Math.min(expireTime, backup.getExpireTime()); + new_expire_time = min(backup.maxExpireTime, old_expire_time) + System.out.println(String.format( "Updating expire time of backup [%s] to %s...", backupId.toString(), From d4b83f97f842d2a7fdd900a177a1b46f4bb2f786 Mon Sep 17 00:00:00 2001 From: Anshul Goyal Date: Mon, 21 Feb 2022 12:05:56 +0530 Subject: [PATCH 03/21] feat: copy backup - cleaning up tests --- .../cloud/spanner/spi/v1/GapicSpannerRpc.java | 2 +- .../com/google/cloud/spanner/BackupTest.java | 23 +++++++++++-------- .../spanner/DatabaseAdminClientImplTest.java | 11 --------- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java index 06c08016e13..7eb66e5f3ce 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java @@ -1287,7 +1287,7 @@ public OperationFuture copyBackUp( .setParent(instanceName) .setBackupId(backupId) .setSourceBackup(backupId) - .setExpireTime(backup.getExpireTime()) ;//add +30 + .setExpireTime(backup.getExpireTime()) ; if (backupInfo.getEncryptionConfig() != null) { requestBuilder.setEncryptionConfig( diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java index 009e3be10f5..75f0004da55 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java @@ -293,24 +293,27 @@ public void fromProto() { public void testEqualsAndHashCode() { final Backup backup1 = createBackup(); final Backup backup2 = createBackup(); + final Backup copyBackup1 = copyBackup(); assertEquals(backup1, backup2); assertEquals(backup1.hashCode(), backup2.hashCode()); + assertEquals(backup1.hashCode(), copyBackup1.hashCode()); } private Backup createBackup() { com.google.spanner.admin.database.v1.Backup proto = - com.google.spanner.admin.database.v1.Backup.newBuilder() - .setName(NAME) - .setDatabase(DB) - .setExpireTime( - com.google.protobuf.Timestamp.newBuilder().setSeconds(1000L).setNanos(1000).build()) - .setVersionTime( - com.google.protobuf.Timestamp.newBuilder().setSeconds(2000L).setNanos(2000).build()) - .setEncryptionInfo(ENCRYPTION_INFO) - .setState(com.google.spanner.admin.database.v1.Backup.State.CREATING) - .build(); + com.google.spanner.admin.database.v1.Backup.newBuilder() + .setName(NAME) + .setDatabase(DB) + .setExpireTime( + com.google.protobuf.Timestamp.newBuilder().setSeconds(1000L).setNanos(1000).build()) + .setVersionTime( + com.google.protobuf.Timestamp.newBuilder().setSeconds(2000L).setNanos(2000).build()) + .setEncryptionInfo(ENCRYPTION_INFO) + .setState(com.google.spanner.admin.database.v1.Backup.State.CREATING) + .build(); return Backup.fromProto(proto, dbClient); + } private Backup copyBackup() { com.google.spanner.admin.database.v1.Backup proto = diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java index 8e953697236..5be3bfdb98c 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java @@ -507,17 +507,6 @@ public void copyBackupWithBackupObject() throws ExecutionException, InterruptedE assertThat(op.get().getId().getName()).isEqualTo(BK_NAME); } - @Test(expected = IllegalArgumentException.class) - public void testCopyBackupNoSource() { - final com.google.cloud.spanner.Backup requestBackup = - client - .newBackupBuilder(BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID)) - .setExpireTime(Timestamp.now()) - .build(); - - client.copyBackup(requestBackup); - } - @Test public void copyEncryptedBackup() throws ExecutionException, InterruptedException { final OperationFuture rawOperationFuture = From fe24c7e0093ed08c1da63b8cc087c51f171c6e99 Mon Sep 17 00:00:00 2001 From: Anshul Goyal Date: Mon, 21 Feb 2022 12:15:14 +0530 Subject: [PATCH 04/21] feat: copy backup - cleaning up samples --- .../com/example/spanner/SpannerSample.java | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) 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 1e53b792fcf..d8710e7eb2f 100644 --- a/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java +++ b/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java @@ -1613,23 +1613,25 @@ static void createBackup(DatabaseAdminClient dbAdminClient, DatabaseId databaseI } // [END spanner_create_backup] - // [START spanner_create_copy_backup] - static void createCopyBackup(String instanceId, String copyBackupId, String sourceBackupPath): + // [START spanner_copy_backup] + static void copyBackup(DatabaseAdminClient dbAdminClient, String backupId, String sourceBackupId) { + // Creates a copy backup of an existing backup with tables - Instance instance = instanceAdminClient.getInstance(instanceId.getInstance()); + Backup backup = dbAdminClient + .newBackupBuilder(backupId) + .setSourceBackup(sourceBackupId) + .build(); Timestamp expireTime = Timestamp.ofTimeMicroseconds(TimeUnit.MICROSECONDS.convert( System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14), TimeUnit.MILLISECONDS)); - Backup copyBackup = instance.co - // Initiate the request which returns an OperationFuture. - System.out.println("Creating backup [" + backup.getId() + "]..."); + System.out.println("Copying backup [" + backup.getId() + "]..."); OperationFuture op = backup.copyBackup(); - try { + try { // Wait for the backup operation to complete. backup = op.get(); - System.out.println("Created backup [" + backup.getId() + "]"); + System.out.println("Copied backup [" + backup.getId() + "]"); } catch (ExecutionException e) { throw (SpannerException) e.getCause(); } catch (InterruptedException e) { @@ -1640,20 +1642,20 @@ static void createCopyBackup(String instanceId, String copyBackupId, String sour backup = backup.reload(); System.out.println( String.format( - "Backup %s of size %d bytes was created at %s for version of database at %s", - backup.getId().getName(), - backup.getSize(), + "Backup %s of size %d bytes was copied 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()), - LocalDateTime.ofEpochSecond( - backup.getProto().getVersionTime().getSeconds(), - backup.getProto().getVersionTime().getNanos(), - OffsetDateTime.now().getOffset()) - )); - - // [END spanner_create_copy_backup] + backup.getProto().getCreateTime().getSeconds(), + backup.getProto().getCreateTime().getNanos(), + OffsetDateTime.now().getOffset()), + LocalDateTime.ofEpochSecond( + backup.getProto().getVersionTime().getSeconds(), + backup.getProto().getVersionTime().getNanos(), + OffsetDateTime.now().getOffset()) + )); + } + // [END spanner_copy_backup] // [START spanner_cancel_backup_create] static void cancelCreateBackup( From dc27ff70935d680d5689439785b31a523a2ecece Mon Sep 17 00:00:00 2001 From: Anshul Goyal Date: Mon, 21 Feb 2022 12:18:22 +0530 Subject: [PATCH 05/21] feat: copy backup - cleaning up samples --- .../src/main/java/com/example/spanner/SpannerSample.java | 1 - 1 file changed, 1 deletion(-) 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 d8710e7eb2f..712eccd4e2d 100644 --- a/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java +++ b/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java @@ -1887,7 +1887,6 @@ static void updateBackup(DatabaseAdminClient dbAdminClient, BackupId backupId) { + TimeUnit.NANOSECONDS.toMicros(backup.getExpireTime().getNanos()) + TimeUnit.DAYS.toMicros(30L)); Timestamp newExpireTime = Math.min(expireTime, backup.getExpireTime()); - new_expire_time = min(backup.maxExpireTime, old_expire_time) System.out.println(String.format( "Updating expire time of backup [%s] to %s...", From 3b4582b9ba3594fc6a451c1bcef60cdf83dde861 Mon Sep 17 00:00:00 2001 From: Anshul Goyal Date: Fri, 25 Feb 2022 07:40:06 +0000 Subject: [PATCH 06/21] feat: copy backup signature fixes --- samples/snippets/pom.xml | 1 + .../src/main/java/com/example/spanner/SpannerSample.java | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml index 74aaf074d52..5927d766b35 100644 --- a/samples/snippets/pom.xml +++ b/samples/snippets/pom.xml @@ -44,6 +44,7 @@ com.google.cloud google-cloud-spanner + 6.19.1-SNAPSHOT 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 712eccd4e2d..2a4db98cab0 100644 --- a/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java +++ b/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java @@ -64,7 +64,7 @@ import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions; import java.math.BigDecimal; -import Java.lang.math.min; +import java.lang.Math; import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; @@ -1614,7 +1614,7 @@ static void createBackup(DatabaseAdminClient dbAdminClient, DatabaseId databaseI // [END spanner_create_backup] // [START spanner_copy_backup] - static void copyBackup(DatabaseAdminClient dbAdminClient, String backupId, String sourceBackupId) { + static void copyBackup(DatabaseAdminClient dbAdminClient, BackupId backupId, String sourceBackupId) { // Creates a copy backup of an existing backup with tables Backup backup = dbAdminClient From 108710ef8fbfb8f4cfb175ac414400b988b4d717 Mon Sep 17 00:00:00 2001 From: Anshul Goyal Date: Fri, 25 Feb 2022 09:59:45 +0000 Subject: [PATCH 07/21] feat: copy backup sample fixes --- patch.patch | 42 +++++++++++++++++++ samples/snippets/pom.xml | 5 +++ .../com/example/spanner/SpannerSample.java | 7 ++-- 3 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 patch.patch diff --git a/patch.patch b/patch.patch new file mode 100644 index 00000000000..e5a1256475c --- /dev/null +++ b/patch.patch @@ -0,0 +1,42 @@ +diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml +index f5d1351a..9ede6f23 100644 +--- a/samples/snippets/pom.xml ++++ b/samples/snippets/pom.xml +@@ -47,6 +47,11 @@ + 6.19.1-SNAPSHOT + + ++ ++ com.google.api.grpc ++ proto-google-cloud-spanner-admin-database-v1 ++ 6.19.1-SNAPSHOT ++ + + + io.opencensus +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 2a4db98c..c44a012d 100644 +--- a/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java ++++ b/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java +@@ -1625,9 +1625,9 @@ public class SpannerSample { + Timestamp expireTime = Timestamp.ofTimeMicroseconds(TimeUnit.MICROSECONDS.convert( + System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14), TimeUnit.MILLISECONDS)); + +- // Initiate the request which returns an OperationFuture. ++ // Initiate the requefst which returns an OperationFuture. + System.out.println("Copying backup [" + backup.getId() + "]..."); +- OperationFuture op = backup.copyBackup(); ++ OperationFuture op = dbAdminClient.copyBackup(backup); + try { + // Wait for the backup operation to complete. + backup = op.get(); +@@ -1886,7 +1886,8 @@ public class SpannerSample { + TimeUnit.SECONDS.toMicros(backup.getExpireTime().getSeconds()) + + TimeUnit.NANOSECONDS.toMicros(backup.getExpireTime().getNanos()) + + TimeUnit.DAYS.toMicros(30L)); +- Timestamp newExpireTime = Math.min(expireTime, backup.getExpireTime()); ++ int timeDiff = expireTime.compareTo(backup.getExpireTime()); ++ Timestamp newExpireTime = (timeDiff < 0) ? expireTime : backup.getExpireTime(); + + System.out.println(String.format( + "Updating expire time of backup [%s] to %s...", diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml index 5927d766b35..395149db4a6 100644 --- a/samples/snippets/pom.xml +++ b/samples/snippets/pom.xml @@ -47,6 +47,11 @@ 6.19.1-SNAPSHOT + + com.google.api.grpc + proto-google-cloud-spanner-admin-database-v1 + 6.19.1-SNAPSHOT + io.opencensus 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 2a4db98cab0..c44a012d3e0 100644 --- a/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java +++ b/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java @@ -1625,9 +1625,9 @@ static void copyBackup(DatabaseAdminClient dbAdminClient, BackupId backupId, Str Timestamp expireTime = Timestamp.ofTimeMicroseconds(TimeUnit.MICROSECONDS.convert( System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14), TimeUnit.MILLISECONDS)); - // Initiate the request which returns an OperationFuture. + // Initiate the requefst which returns an OperationFuture. System.out.println("Copying backup [" + backup.getId() + "]..."); - OperationFuture op = backup.copyBackup(); + OperationFuture op = dbAdminClient.copyBackup(backup); try { // Wait for the backup operation to complete. backup = op.get(); @@ -1886,7 +1886,8 @@ static void updateBackup(DatabaseAdminClient dbAdminClient, BackupId backupId) { TimeUnit.SECONDS.toMicros(backup.getExpireTime().getSeconds()) + TimeUnit.NANOSECONDS.toMicros(backup.getExpireTime().getNanos()) + TimeUnit.DAYS.toMicros(30L)); - Timestamp newExpireTime = Math.min(expireTime, backup.getExpireTime()); + int timeDiff = expireTime.compareTo(backup.getExpireTime()); + Timestamp newExpireTime = (timeDiff < 0) ? expireTime : backup.getExpireTime(); System.out.println(String.format( "Updating expire time of backup [%s] to %s...", From ca2828ace39404caa7be4151123611aca0787c5e Mon Sep 17 00:00:00 2001 From: Anshul Goyal Date: Mon, 28 Feb 2022 08:59:43 +0530 Subject: [PATCH 08/21] feat: copy backup - review fixes --- .../cloud/spanner/DatabaseAdminClient.java | 44 +++++++------------ .../spanner/DatabaseAdminClientImpl.java | 4 +- .../cloud/spanner/spi/v1/GapicSpannerRpc.java | 3 +- .../spanner/DatabaseAdminClientImplTest.java | 2 +- 4 files changed, 19 insertions(+), 34 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java index 8532011c23a..3f738fe064c 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java @@ -183,31 +183,31 @@ OperationFuture createBackup( /** * Creates a copy of backup from an existing database backup in a Cloud Spanner instance. * - *

Example to create a backup. + *

Example to copy a backup. * *

{@code
-   * String instance       = my_instance_id;
-   * String backupId       = my_backup_id;
-   * String databaseId     = my_database_id;
-   * Timestamp expireTime  = Timestamp.ofTimeMicroseconds(micros);
-   * OperationFuture op = dbAdminClient
-   *     .createBackup(
+   * String instance                    = my_instance_id;
+   * String destinationBackupId         = my_backup_id;
+   * String sourceBackup                = source_backup;
+   * Timestamp expireTime               = Timestamp.ofTimeMicroseconds(micros);
+   * OperationFuture op = dbAdminClient
+   *     .copyBackup(
    *         instanceId,
-   *         backupId,
-   *         databaseId,
+   *         sourceBackup,
+   *         destinationBackupId,
    *         expireTime);
    * Backup backup = op.get();
    * }
* * @param sourceInstanceId the id of the instance where the database to backup is located and * where the backup will be created. - * @param backupId the id of the backup which will be created. It must conform to the regular - * expression [a-z][a-z0-9_\-]*[a-z0-9] and be between 2 and 60 characters in length. * @param sourceBackup the source backup id. + * @param destinationBackupId the id of the backup which will be created. It must conform to the regular + * expression [a-z][a-z0-9_\-]*[a-z0-9] and be between 2 and 60 characters in length. * @param expireTime the time that the backup will automatically expire. */ OperationFuture copyBackup( - String sourceInstanceId, String backupId, String sourceBackup, Timestamp expireTime) + String sourceInstanceId, String sourceBackup, String destinationBackupId, Timestamp expireTime) throws SpannerException; @@ -219,20 +219,20 @@ OperationFuture copyBackup( *

Example to create an encrypted backup. * *

{@code
-   * BackupId backupId = BackupId.of("project", "instance", "backup-id");
+   * BackupId destinationBackupId = BackupId.of("project", "instance", "backup-id");
    * Timestamp expireTime = Timestamp.ofTimeMicroseconds(expireTimeMicros);
    * EncryptionConfig encryptionConfig =
    *         EncryptionConfig.ofKey(
    *             "projects/my-project/locations/some-location/keyRings/my-keyring/cryptoKeys/my-key"));
    *
    * Backup backupToCopy = dbAdminClient
-   *     .newBackupBuilder(backupId)
+   *     .newBackupBuilder(destinationBackupId)
    *     .setExpireTime(expireTime)
    *     .setVersionTime(versionTime)
    *     .setEncryptionConfig(encryptionConfig)
    *     .build();
    *
-   * OperationFuture op = dbAdminClient.copyBackUp(backupToCopy);
+   * OperationFuture op = dbAdminClient.copyBackUp(backupToCopy);
    * Backup copiedBackup = op.get();
    * }
* @@ -329,20 +329,6 @@ OperationFuture restoreDatabase(Restore resto */ Backup getBackup(String instanceId, String backupId) throws SpannerException; - /** - * Creates a copy backup within this instance. - * - *

Example to get a backup. - * - *

{@code
-   * String sourceBackupId = source_backup_id;
-   * String backupId   = my_backup_id;
-   * Timestamp expireTime = expire_time;
-   * Backup backup = dbAdminClient.copyBackup(sourceBackupId, backupId, expireTime);
-   * }
- */ -// Backup copyBackup(String sourceBackupId, Timestamp expireTime) throws SpannerException; - /** * Enqueues the given DDL statements to be applied, in order but not necessarily all at once, to * the database schema at some point (or points) in the future. The server checks that the diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java index 4dfe745b5f4..32da0cbeaa1 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java @@ -169,10 +169,10 @@ public OperationFuture createBackup(Backup backupI @Override public OperationFuture copyBackup( - String instanceId,String backupId, String sourceBackUp, Timestamp expireTime) + String instanceId, String sourceBackUp, String destinationBackupId, Timestamp expireTime) throws SpannerException { final Backup backupInfo = - newBackupBuilder(BackupId.of(projectId, instanceId, backupId)) + newBackupBuilder(BackupId.of(projectId, instanceId, destinationBackupId)) .setExpireTime(expireTime) .setSourceBackup(sourceBackUp) .build(); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java index 7eb66e5f3ce..7fec8b0a197 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java @@ -1280,14 +1280,13 @@ public OperationFuture copyBackUp( if (backupInfo.getVersionTime() != null) { backupBuilder.setVersionTime(backupInfo.getVersionTime().toProto()); } - final Backup backup = backupBuilder.build(); final CopyBackupRequest.Builder requestBuilder = CopyBackupRequest.newBuilder() .setParent(instanceName) .setBackupId(backupId) .setSourceBackup(backupId) - .setExpireTime(backup.getExpireTime()) ; + .setExpireTime(backupInfo.getExpireTime().toProto()) ; if (backupInfo.getEncryptionConfig() != null) { requestBuilder.setEncryptionConfig( diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java index 5be3bfdb98c..9d4cd3201fc 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java @@ -474,7 +474,7 @@ public void copyBackupWithParams() throws Exception { .build(); when(rpc.copyBackUp(backup)).thenReturn(rawOperationFuture); OperationFuture op = - client.copyBackup(INSTANCE_ID, BK_ID, DB_ID, t); + client.copyBackup(INSTANCE_ID, DB_ID, BK_ID, t); assertThat(op.isDone()).isTrue(); assertThat(op.get().getId().getName()).isEqualTo(BK_NAME); } From 26a7a6e1b16b1a84b33e33eff884f3d853b88fee Mon Sep 17 00:00:00 2001 From: Anshul Goyal Date: Mon, 28 Feb 2022 08:59:43 +0530 Subject: [PATCH 09/21] feat: copy backup - review fixes From 1ef756388e612098c541e4ea2cae1288c02012ce Mon Sep 17 00:00:00 2001 From: Anshul Goyal Date: Mon, 28 Feb 2022 04:14:00 +0000 Subject: [PATCH 10/21] feat: copy backup checkstyle fixes --- .../src/main/java/com/example/spanner/SpannerSample.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 c44a012d3e0..10771e069d1 100644 --- a/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java +++ b/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java @@ -63,8 +63,8 @@ import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata; import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions; -import java.math.BigDecimal; import java.lang.Math; +import java.math.BigDecimal; import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; @@ -1614,7 +1614,8 @@ static void createBackup(DatabaseAdminClient dbAdminClient, DatabaseId databaseI // [END spanner_create_backup] // [START spanner_copy_backup] - static void copyBackup(DatabaseAdminClient dbAdminClient, BackupId backupId, String sourceBackupId) { + static void copyBackup(DatabaseAdminClient dbAdminClient, + BackupId backupId, String sourceBackupId) { // Creates a copy backup of an existing backup with tables Backup backup = dbAdminClient From 537f07bc253471217d8f28843af57eae58e84d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Mon, 28 Feb 2022 17:02:24 +0100 Subject: [PATCH 11/21] feat: make CopyBackup sample runnable --- .../com/google/cloud/spanner/BackupInfo.java | 9 -- .../cloud/spanner/DatabaseAdminClient.java | 51 ++++---- .../spanner/DatabaseAdminClientImpl.java | 64 +++++---- .../EncryptionConfigProtoMapper.java | 18 +-- .../cloud/spanner/spi/v1/GapicSpannerRpc.java | 99 +++++++------- .../cloud/spanner/spi/v1/SpannerRpc.java | 15 ++- .../com/google/cloud/spanner/BackupTest.java | 46 +++---- .../spanner/DatabaseAdminClientImplTest.java | 84 ++++++------ samples/snippets/pom.xml | 5 + .../com/example/spanner/CopyBackupSample.java | 121 ++++++++++++++++++ .../com/example/spanner/SpannerSample.java | 45 ------- 11 files changed, 313 insertions(+), 244 deletions(-) create mode 100644 samples/snippets/src/main/java/com/example/spanner/CopyBackupSample.java diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java index 6bd553bb27b..0657ff2b7b8 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java @@ -82,8 +82,6 @@ public abstract static class Builder { */ public abstract Builder setDatabase(DatabaseId database); - public abstract Builder setSourceBackup(String sourceBackup); - /** Builds the backup from this builder. */ public abstract Backup build(); } @@ -97,7 +95,6 @@ abstract static class BuilderImpl extends Builder { private long size; private BackupEncryptionConfig encryptionConfig; private EncryptionInfo encryptionInfo; - private String sourceBackup; private com.google.spanner.admin.database.v1.Backup proto; BuilderImpl(BackupId id) { @@ -128,12 +125,6 @@ public Builder setExpireTime(Timestamp expireTime) { return this; } - @Override - public Builder setSourceBackup(String sourceBackup) { - this.sourceBackup = Preconditions.checkNotNull(sourceBackup); - return this; - } - @Override public Builder setVersionTime(Timestamp versionTime) { this.versionTime = versionTime; diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java index 3f738fe064c..114628d136a 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java @@ -28,7 +28,6 @@ import com.google.spanner.admin.database.v1.CreateDatabaseRequest; import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata; import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; - import java.util.List; import javax.annotation.Nullable; @@ -181,64 +180,68 @@ OperationFuture createBackup( OperationFuture createBackup(Backup backup) throws SpannerException; /** - * Creates a copy of backup from an existing database backup in a Cloud Spanner instance. + * Creates a copy of backup from an existing backup in a Cloud Spanner instance. * *

Example to copy a backup. * *

{@code
-   * String instance                    = my_instance_id;
-   * String destinationBackupId         = my_backup_id;
-   * String sourceBackup                = source_backup;
+   * String instanceId                  = "my_instance_id";
+   * String sourceBackupId              = "source_backup_id";
+   * String destinationBackupId         = "destination_backup_id";
    * Timestamp expireTime               = Timestamp.ofTimeMicroseconds(micros);
    * OperationFuture op = dbAdminClient
    *     .copyBackup(
    *         instanceId,
-   *         sourceBackup,
+   *         sourceBackupId,
    *         destinationBackupId,
    *         expireTime);
    * Backup backup = op.get();
    * }
* - * @param sourceInstanceId the id of the instance where the database to backup is located and - * where the backup will be created. - * @param sourceBackup the source backup id. - * @param destinationBackupId the id of the backup which will be created. It must conform to the regular - * expression [a-z][a-z0-9_\-]*[a-z0-9] and be between 2 and 60 characters in length. - * @param expireTime the time that the backup will automatically expire. + * @param instanceId the id of the instance where the source backup is located and where the new + * backup will be created. + * @param sourceBackupId the source backup id. + * @param destinationBackupId the id of the backup which will be created. It must conform to the + * regular expression [a-z][a-z0-9_\-]*[a-z0-9] and be between 2 and 60 characters in length. + * @param expireTime the time that the new backup will automatically expire. */ OperationFuture copyBackup( - String sourceInstanceId, String sourceBackup, String destinationBackupId, Timestamp expireTime) - throws SpannerException; - + String instanceId, String sourceBackupId, String destinationBackupId, Timestamp expireTime) + throws SpannerException; /** - * Creates a copy of backup from an existing database backup in Cloud Spanner. Any configuration options in the - * {@link Backup} instance will be included in the {@link + * Creates a copy of backup from an existing backup in Cloud Spanner. Any configuration options in + * the {@link Backup} instance will be included in the {@link * com.google.spanner.admin.database.v1.CopyBackupRequest}. * - *

Example to create an encrypted backup. + *

The expire time of the new backup must be set and be at least 6 hours and at most 366 days + * after the creation time of the existing backup that is being copied. + * + *

Example to create a copy of a backup. * *

{@code
-   * BackupId destinationBackupId = BackupId.of("project", "instance", "backup-id");
+   * BackupId sourceBackupId = BackupId.of("source-project", "source-instance", "source-backup-id");
+   * BackupId destinationBackupId = BackupId.of("destination-project", "destination-instance", "new-backup-id");
    * Timestamp expireTime = Timestamp.ofTimeMicroseconds(expireTimeMicros);
    * EncryptionConfig encryptionConfig =
    *         EncryptionConfig.ofKey(
    *             "projects/my-project/locations/some-location/keyRings/my-keyring/cryptoKeys/my-key"));
    *
-   * Backup backupToCopy = dbAdminClient
+   * Backup destinationBackup = dbAdminClient
    *     .newBackupBuilder(destinationBackupId)
    *     .setExpireTime(expireTime)
-   *     .setVersionTime(versionTime)
    *     .setEncryptionConfig(encryptionConfig)
    *     .build();
    *
-   * OperationFuture op = dbAdminClient.copyBackUp(backupToCopy);
+   * OperationFuture op = dbAdminClient.copyBackUp(sourceBackupId, destinationBackup);
    * Backup copiedBackup = op.get();
    * }
* - * @param backup the backup to be copied + * @param sourceBackupId the backup to be copied + * @param destinationBackup the new backup to create */ - OperationFuture copyBackup(Backup backup) throws SpannerException; + OperationFuture copyBackup( + BackupId sourceBackupId, Backup destinationBackup) throws SpannerException; /** * Restore a database from a backup. The database that is restored will be created and may not diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java index 32da0cbeaa1..7792ec282f4 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java @@ -37,7 +37,6 @@ import com.google.spanner.admin.database.v1.CreateDatabaseMetadata; import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata; import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; - import java.util.List; import java.util.UUID; import javax.annotation.Nullable; @@ -169,46 +168,45 @@ public OperationFuture createBackup(Backup backupI @Override public OperationFuture copyBackup( - String instanceId, String sourceBackUp, String destinationBackupId, Timestamp expireTime) - throws SpannerException { - final Backup backupInfo = - newBackupBuilder(BackupId.of(projectId, instanceId, destinationBackupId)) - .setExpireTime(expireTime) - .setSourceBackup(sourceBackUp) - .build(); + String instanceId, String sourceBackupId, String destinationBackupId, Timestamp expireTime) + throws SpannerException { + final Backup destinationBackup = + newBackupBuilder(BackupId.of(projectId, instanceId, destinationBackupId)) + .setExpireTime(expireTime) + .build(); - return copyBackup(backupInfo); + return copyBackup(BackupId.of(projectId, instanceId, sourceBackupId), destinationBackup); } @Override - public OperationFuture copyBackup(Backup backupInfo) - throws SpannerException { - Preconditions.checkArgument( - backupInfo.getId() != null, "Cannot create a backup without a source backup"); + public OperationFuture copyBackup( + BackupId sourceBackupId, Backup destinationBackup) throws SpannerException { + Preconditions.checkNotNull(sourceBackupId); + Preconditions.checkNotNull(destinationBackup); final OperationFuture - rawOperationFuture = rpc.copyBackUp(backupInfo); + rawOperationFuture = rpc.copyBackUp(sourceBackupId, destinationBackup); return new OperationFutureImpl<>( - rawOperationFuture.getPollingFuture(), - rawOperationFuture.getInitialFuture(), - snapshot -> { - com.google.spanner.admin.database.v1.Backup proto = - ProtoOperationTransformers.ResponseTransformer.create( - com.google.spanner.admin.database.v1.Backup.class) - .apply(snapshot); - return Backup.fromProto( - com.google.spanner.admin.database.v1.Backup.newBuilder(proto) - .setName(proto.getName()) - .setExpireTime(proto.getExpireTime()) - .setEncryptionInfo(proto.getEncryptionInfo()) - .build(), - DatabaseAdminClientImpl.this); - }, - ProtoOperationTransformers.MetadataTransformer.create(CopyBackupMetadata.class), - e -> { - throw SpannerExceptionFactory.newSpannerException(e); - }); + rawOperationFuture.getPollingFuture(), + rawOperationFuture.getInitialFuture(), + snapshot -> { + com.google.spanner.admin.database.v1.Backup proto = + ProtoOperationTransformers.ResponseTransformer.create( + com.google.spanner.admin.database.v1.Backup.class) + .apply(snapshot); + return Backup.fromProto( + com.google.spanner.admin.database.v1.Backup.newBuilder(proto) + .setName(proto.getName()) + .setExpireTime(proto.getExpireTime()) + .setEncryptionInfo(proto.getEncryptionInfo()) + .build(), + DatabaseAdminClientImpl.this); + }, + ProtoOperationTransformers.MetadataTransformer.create(CopyBackupMetadata.class), + e -> { + throw SpannerExceptionFactory.newSpannerException(e); + }); } @Override diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/encryption/EncryptionConfigProtoMapper.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/encryption/EncryptionConfigProtoMapper.java index c39ad12882f..62d51bf76ed 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/encryption/EncryptionConfigProtoMapper.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/encryption/EncryptionConfigProtoMapper.java @@ -53,21 +53,21 @@ public static CreateBackupEncryptionConfig createBackupEncryptionConfig( /** Returns an encryption config to be used for a copy backup. */ public static CopyBackupEncryptionConfig copyBackupEncryptionConfig( - BackupEncryptionConfig config) { + BackupEncryptionConfig config) { if (config instanceof CustomerManagedEncryption) { return CopyBackupEncryptionConfig.newBuilder() - .setEncryptionType( - CopyBackupEncryptionConfig.EncryptionType.CUSTOMER_MANAGED_ENCRYPTION) - .setKmsKeyName(((CustomerManagedEncryption) config).getKmsKeyName()) - .build(); + .setEncryptionType(CopyBackupEncryptionConfig.EncryptionType.CUSTOMER_MANAGED_ENCRYPTION) + .setKmsKeyName(((CustomerManagedEncryption) config).getKmsKeyName()) + .build(); } else if (config instanceof GoogleDefaultEncryption) { return CopyBackupEncryptionConfig.newBuilder() - .setEncryptionType(CopyBackupEncryptionConfig.EncryptionType.GOOGLE_DEFAULT_ENCRYPTION) - .build(); + .setEncryptionType(CopyBackupEncryptionConfig.EncryptionType.GOOGLE_DEFAULT_ENCRYPTION) + .build(); } else if (config instanceof UseBackupEncryption) { return CopyBackupEncryptionConfig.newBuilder() - .setEncryptionType(CopyBackupEncryptionConfig.EncryptionType.USE_CONFIG_DEFAULT_OR_BACKUP_ENCRYPTION) - .build(); + .setEncryptionType( + CopyBackupEncryptionConfig.EncryptionType.USE_CONFIG_DEFAULT_OR_BACKUP_ENCRYPTION) + .build(); } else { throw new IllegalArgumentException("Unknown backup encryption configuration " + config); } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java index 7fec8b0a197..b065d871076 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java @@ -60,6 +60,7 @@ import com.google.cloud.grpc.GcpManagedChannelOptions.GcpMetricsOptions; import com.google.cloud.grpc.GrpcTransportOptions; import com.google.cloud.spanner.AdminRequestsPerMinuteExceededException; +import com.google.cloud.spanner.BackupId; import com.google.cloud.spanner.ErrorCode; import com.google.cloud.spanner.Restore; import com.google.cloud.spanner.SpannerException; @@ -1266,69 +1267,63 @@ public OperationFuture createBackup( NanoClock.getDefaultClock()); } - @Override public OperationFuture copyBackUp( - final com.google.cloud.spanner.Backup backupInfo) throws SpannerException { - final String instanceName = backupInfo.getInstanceId().getName(); - final String databaseName = backupInfo.getDatabase().getName(); - final String backupId = backupInfo.getId().getBackup(); - final Backup.Builder backupBuilder = - com.google.spanner.admin.database.v1.Backup.newBuilder() - .setDatabase(databaseName) - .setExpireTime(backupInfo.getExpireTime().toProto()); - if (backupInfo.getVersionTime() != null) { - backupBuilder.setVersionTime(backupInfo.getVersionTime().toProto()); - } + BackupId sourceBackupId, final com.google.cloud.spanner.Backup destinationBackup) + throws SpannerException { + Preconditions.checkNotNull(sourceBackupId); + Preconditions.checkNotNull(destinationBackup); + final String instanceName = destinationBackup.getInstanceId().getName(); + final String backupId = destinationBackup.getId().getBackup(); final CopyBackupRequest.Builder requestBuilder = - CopyBackupRequest.newBuilder() - .setParent(instanceName) - .setBackupId(backupId) - .setSourceBackup(backupId) - .setExpireTime(backupInfo.getExpireTime().toProto()) ; + CopyBackupRequest.newBuilder() + .setParent(instanceName) + .setBackupId(backupId) + .setSourceBackup(sourceBackupId.getName()) + .setExpireTime(destinationBackup.getExpireTime().toProto()); - if (backupInfo.getEncryptionConfig() != null) { + if (destinationBackup.getEncryptionConfig() != null) { requestBuilder.setEncryptionConfig( - EncryptionConfigProtoMapper.copyBackupEncryptionConfig( - backupInfo.getEncryptionConfig())); + EncryptionConfigProtoMapper.copyBackupEncryptionConfig( + destinationBackup.getEncryptionConfig())); } final CopyBackupRequest request = requestBuilder.build(); final OperationFutureCallable callable = - new OperationFutureCallable<>( - databaseAdminStub.copyBackupOperationCallable(), - request, - //calling copy backup method of dbClientImpl - DatabaseAdminGrpc.getCopyBackupMethod(), + new OperationFutureCallable<>( + databaseAdminStub.copyBackupOperationCallable(), + request, + // calling copy backup method of dbClientImpl + DatabaseAdminGrpc.getCopyBackupMethod(), + instanceName, + nextPageToken -> + listBackupOperations( instanceName, - nextPageToken -> - listBackupOperations( - instanceName, - 0, - String.format( - "(metadata.@type:type.googleapis.com/%s) AND (metadata.name:%s)", - CopyBackupMetadata.getDescriptor().getFullName(), - String.format("%s/backups/%s", instanceName, backupId)), - nextPageToken), - input -> { - try { - return input - .getMetadata() - .unpack(CopyBackupMetadata.class) - .getProgress() - .getStartTime(); - } catch (InvalidProtocolBufferException e) { - return null; - } - }); + 0, + String.format( + "(metadata.@type:type.googleapis.com/%s) AND (metadata.name:%s)", + CopyBackupMetadata.getDescriptor().getFullName(), + String.format("%s/backups/%s", instanceName, backupId)), + nextPageToken), + input -> { + try { + return input + .getMetadata() + .unpack(CopyBackupMetadata.class) + .getProgress() + .getStartTime(); + } catch (InvalidProtocolBufferException e) { + return null; + } + }); return RetryHelper.runWithRetries( - callable, - databaseAdminStubSettings - .copyBackupOperationSettings() - .getInitialCallSettings() - .getRetrySettings(), - new OperationFutureRetryAlgorithm<>(), - NanoClock.getDefaultClock()); + callable, + databaseAdminStubSettings + .copyBackupOperationSettings() + .getInitialCallSettings() + .getRetrySettings(), + new OperationFutureRetryAlgorithm<>(), + NanoClock.getDefaultClock()); } @Override diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java index 134e82de715..0cfd4306f03 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java @@ -22,6 +22,7 @@ import com.google.api.gax.retrying.RetrySettings; import com.google.api.gax.rpc.ServerStream; import com.google.cloud.ServiceRpc; +import com.google.cloud.spanner.BackupId; import com.google.cloud.spanner.Restore; import com.google.cloud.spanner.SpannerException; import com.google.cloud.spanner.admin.database.v1.stub.DatabaseAdminStub; @@ -231,18 +232,18 @@ Paginated listBackups( OperationFuture createBackup( com.google.cloud.spanner.Backup backupInfo) throws SpannerException; - /** - * Creates a copy backup from the source database specified in the {@link - * com.google.cloud.spanner.Backup} instance. + * Creates a copy backup from the source backup specified. * - * @param backupInfo the backup to create. The instance, database, sourceBackupId and expireTime fields of the - * backup must be filled. + * @param destinationBackup the backup to create. The instance, database, and expireTime fields of + * the backup must be filled. It may also optionally have an encryption config set. If no + * encryption config has been set, the new backup will use the same encryption config as the + * source backup. * @return the operation that monitors the backup creation. */ OperationFuture copyBackUp( - com.google.cloud.spanner.Backup backupInfo) throws SpannerException; - + BackupId sourceBackupId, com.google.cloud.spanner.Backup destinationBackup) + throws SpannerException; /** * Restore a backup into the given database. diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java index 75f0004da55..cf8d09eabe6 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java @@ -302,31 +302,31 @@ public void testEqualsAndHashCode() { private Backup createBackup() { com.google.spanner.admin.database.v1.Backup proto = - com.google.spanner.admin.database.v1.Backup.newBuilder() - .setName(NAME) - .setDatabase(DB) - .setExpireTime( - com.google.protobuf.Timestamp.newBuilder().setSeconds(1000L).setNanos(1000).build()) - .setVersionTime( - com.google.protobuf.Timestamp.newBuilder().setSeconds(2000L).setNanos(2000).build()) - .setEncryptionInfo(ENCRYPTION_INFO) - .setState(com.google.spanner.admin.database.v1.Backup.State.CREATING) - .build(); + com.google.spanner.admin.database.v1.Backup.newBuilder() + .setName(NAME) + .setDatabase(DB) + .setExpireTime( + com.google.protobuf.Timestamp.newBuilder().setSeconds(1000L).setNanos(1000).build()) + .setVersionTime( + com.google.protobuf.Timestamp.newBuilder().setSeconds(2000L).setNanos(2000).build()) + .setEncryptionInfo(ENCRYPTION_INFO) + .setState(com.google.spanner.admin.database.v1.Backup.State.CREATING) + .build(); return Backup.fromProto(proto, dbClient); } - private Backup copyBackup() { - com.google.spanner.admin.database.v1.Backup proto = - com.google.spanner.admin.database.v1.Backup.newBuilder() - .setName(NAME) - .setDatabase(DB) - .setExpireTime( - com.google.protobuf.Timestamp.newBuilder().setSeconds(1000L).setNanos(1000).build()) - .setVersionTime( - com.google.protobuf.Timestamp.newBuilder().setSeconds(2000L).setNanos(2000).build()) - .setEncryptionInfo(ENCRYPTION_INFO) - .setState(com.google.spanner.admin.database.v1.Backup.State.CREATING) - .build(); - return Backup.fromProto(proto, dbClient); + private Backup copyBackup() { + com.google.spanner.admin.database.v1.Backup proto = + com.google.spanner.admin.database.v1.Backup.newBuilder() + .setName(NAME) + .setDatabase(DB) + .setExpireTime( + com.google.protobuf.Timestamp.newBuilder().setSeconds(1000L).setNanos(1000).build()) + .setVersionTime( + com.google.protobuf.Timestamp.newBuilder().setSeconds(2000L).setNanos(2000).build()) + .setEncryptionInfo(ENCRYPTION_INFO) + .setState(com.google.spanner.admin.database.v1.Backup.State.CREATING) + .build(); + return Backup.fromProto(proto, dbClient); } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java index 9d4cd3201fc..a0c389360dc 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java @@ -52,7 +52,6 @@ import com.google.spanner.admin.database.v1.EncryptionInfo; import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata; import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; - import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -74,7 +73,7 @@ public class DatabaseAdminClientImplTest { private static final String DB_NAME2 = "projects/my-project/instances/my-instance/databases/my-db2"; private static final String BK_ID = "my-bk"; - private static final String SOURCE_BK = "my-bk"; + private static final String SOURCE_BK = "my-source-bk"; private static final String BK_NAME = "projects/my-project/instances/my-instance/backups/my-bk"; private static final String BK_NAME2 = "projects/my-project/instances/my-instance/backups/my-bk2"; private static final Timestamp EARLIEST_VERSION_TIME = Timestamp.now(); @@ -460,21 +459,21 @@ public void createEncryptedBackup() throws ExecutionException, InterruptedExcept @Test public void copyBackupWithParams() throws Exception { OperationFuture rawOperationFuture = - OperationFutureUtil.immediateOperationFuture( - "copyBackup", getBackupProto(), CopyBackupMetadata.getDefaultInstance()); + OperationFutureUtil.immediateOperationFuture( + "copyBackup", getBackupProto(), CopyBackupMetadata.getDefaultInstance()); Timestamp t = - Timestamp.ofTimeMicroseconds( - TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()) - + TimeUnit.HOURS.toMicros(28)); + Timestamp.ofTimeMicroseconds( + TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()) + + TimeUnit.HOURS.toMicros(28)); final com.google.cloud.spanner.Backup backup = - client - .newBackupBuilder(BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID)) - .setSourceBackup(SOURCE_BK) - .setExpireTime(t) - .build(); - when(rpc.copyBackUp(backup)).thenReturn(rawOperationFuture); + client + .newBackupBuilder(BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID)) + .setExpireTime(t) + .build(); + when(rpc.copyBackUp(BackupId.of(PROJECT_ID, INSTANCE_ID, SOURCE_BK), backup)) + .thenReturn(rawOperationFuture); OperationFuture op = - client.copyBackup(INSTANCE_ID, DB_ID, BK_ID, t); + client.copyBackup(INSTANCE_ID, SOURCE_BK, BK_ID, t); assertThat(op.isDone()).isTrue(); assertThat(op.get().getId().getName()).isEqualTo(BK_NAME); } @@ -482,27 +481,27 @@ public void copyBackupWithParams() throws Exception { @Test public void copyBackupWithBackupObject() throws ExecutionException, InterruptedException { final OperationFuture rawOperationFuture = - OperationFutureUtil.immediateOperationFuture( - "copyBackup", getBackupProto(), CopyBackupMetadata.getDefaultInstance()); + OperationFutureUtil.immediateOperationFuture( + "copyBackup", getBackupProto(), CopyBackupMetadata.getDefaultInstance()); final Timestamp expireTime = - Timestamp.ofTimeMicroseconds( - TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()) - + TimeUnit.HOURS.toMicros(28)); + Timestamp.ofTimeMicroseconds( + TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()) + + TimeUnit.HOURS.toMicros(28)); final Timestamp versionTime = - Timestamp.ofTimeMicroseconds( - TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()) - TimeUnit.DAYS.toMicros(2)); + Timestamp.ofTimeMicroseconds( + TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()) - TimeUnit.DAYS.toMicros(2)); final com.google.cloud.spanner.Backup requestBackup = - client - .newBackupBuilder(BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID)) - .setSourceBackup(SOURCE_BK) - .setExpireTime(expireTime) - .setVersionTime(versionTime) - .build(); + client + .newBackupBuilder(BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID)) + .setExpireTime(expireTime) + .setVersionTime(versionTime) + .build(); + BackupId sourceBackupId = BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID); - when(rpc.copyBackUp(requestBackup)).thenReturn(rawOperationFuture); + when(rpc.copyBackUp(sourceBackupId, requestBackup)).thenReturn(rawOperationFuture); final OperationFuture op = - client.copyBackup(requestBackup); + client.copyBackup(sourceBackupId, requestBackup); assertThat(op.isDone()).isTrue(); assertThat(op.get().getId().getName()).isEqualTo(BK_NAME); } @@ -510,22 +509,23 @@ public void copyBackupWithBackupObject() throws ExecutionException, InterruptedE @Test public void copyEncryptedBackup() throws ExecutionException, InterruptedException { final OperationFuture rawOperationFuture = - OperationFutureUtil.immediateOperationFuture( - "copyBackup", getEncryptedBackupProto(), CopyBackupMetadata.getDefaultInstance()); + OperationFutureUtil.immediateOperationFuture( + "copyBackup", getEncryptedBackupProto(), CopyBackupMetadata.getDefaultInstance()); final Timestamp t = - Timestamp.ofTimeMicroseconds( - TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()) - + TimeUnit.HOURS.toMicros(28)); + Timestamp.ofTimeMicroseconds( + TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()) + + TimeUnit.HOURS.toMicros(28)); final com.google.cloud.spanner.Backup backup = - client - .newBackupBuilder(BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID)) - .setDatabase(DatabaseId.of(PROJECT_ID, INSTANCE_ID, DB_ID)) - .setExpireTime(t) - .setEncryptionConfig(EncryptionConfigs.customerManagedEncryption(KMS_KEY_NAME)) - .build(); - when(rpc.copyBackUp(backup)).thenReturn(rawOperationFuture); + client + .newBackupBuilder(BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID)) + .setDatabase(DatabaseId.of(PROJECT_ID, INSTANCE_ID, DB_ID)) + .setExpireTime(t) + .setEncryptionConfig(EncryptionConfigs.customerManagedEncryption(KMS_KEY_NAME)) + .build(); + BackupId sourceBackupId = BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID); + when(rpc.copyBackUp(sourceBackupId, backup)).thenReturn(rawOperationFuture); final OperationFuture op = - client.copyBackup(backup); + client.copyBackup(sourceBackupId, backup); assertThat(op.isDone()).isTrue(); assertThat(op.get().getId().getName()).isEqualTo(BK_NAME); assertThat(op.get().getEncryptionInfo().getKmsKeyVersion()).isEqualTo(KMS_KEY_VERSION); diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml index 395149db4a6..a0ce1453146 100644 --- a/samples/snippets/pom.xml +++ b/samples/snippets/pom.xml @@ -47,6 +47,11 @@ 6.19.1-SNAPSHOT
+ + com.google.api.grpc + grpc-google-cloud-spanner-admin-database-v1 + 6.19.1-SNAPSHOT + com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 diff --git a/samples/snippets/src/main/java/com/example/spanner/CopyBackupSample.java b/samples/snippets/src/main/java/com/example/spanner/CopyBackupSample.java new file mode 100644 index 00000000000..c6176d6f9f7 --- /dev/null +++ b/samples/snippets/src/main/java/com/example/spanner/CopyBackupSample.java @@ -0,0 +1,121 @@ +/* + * Copyright 2022 Google Inc. + * + * 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_copy_backup] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.Timestamp; +import com.google.cloud.spanner.Backup; +import com.google.cloud.spanner.BackupId; +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.CopyBackupMetadata; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +public class CopyBackupSample { + + public static void main(String[] args) { + if (args.length != 4) { + throw new IllegalArgumentException( + "Invalid number of arguments. Usage: CopyBackupSample "); + } + String projectId = args[0]; + String instanceId = args[1]; + String sourceBackupId = args[2]; + String destinationBackupId = args[3]; + + try (Spanner spanner = + SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) { + DatabaseAdminClient databaseAdminClient = spanner.getDatabaseAdminClient(); + copyBackup(databaseAdminClient, projectId, instanceId, sourceBackupId, destinationBackupId); + } + } + + static void copyBackup() { + // TODO(developer): Replace these variables before running the sample. + String projectId = "my-project"; + String instanceId = "my-instance"; + String sourceBackupId = "my-backup"; + String destinationBackupId = "my-destination-backup"; + + try (Spanner spanner = + SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) { + DatabaseAdminClient databaseAdminClient = spanner.getDatabaseAdminClient(); + copyBackup(databaseAdminClient, projectId, instanceId, sourceBackupId, destinationBackupId); + } + } + + static Void copyBackup( + DatabaseAdminClient databaseAdminClient, + String projectId, + String instanceId, + String sourceBackupId, + String destinationBackupId) { + + Timestamp expireTime = + Timestamp.ofTimeMicroseconds( + TimeUnit.MICROSECONDS.convert( + System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14), TimeUnit.MILLISECONDS)); + // Creates a copy of an existing backup. + Backup destinationBackup = + databaseAdminClient + .newBackupBuilder(BackupId.of(projectId, instanceId, destinationBackupId)) + .setExpireTime(expireTime) + .build(); + + // Initiate the request which returns an OperationFuture. + System.out.println("Copying backup [" + destinationBackup.getId() + "]..."); + OperationFuture op = + databaseAdminClient.copyBackup( + BackupId.of(projectId, instanceId, sourceBackupId), destinationBackup); + try { + // Wait for the backup operation to complete. + destinationBackup = op.get(); + System.out.println("Copied backup [" + destinationBackup.getId() + "]"); + } catch (ExecutionException e) { + throw (SpannerException) e.getCause(); + } catch (InterruptedException e) { + throw SpannerExceptionFactory.propagateInterrupt(e); + } + + // Reload the metadata of the backup from the server. + destinationBackup = destinationBackup.reload(); + System.out.println( + String.format( + "Backup %s of size %d bytes was copied at %s for version of database at %s", + destinationBackup.getId().getName(), + destinationBackup.getSize(), + LocalDateTime.ofEpochSecond( + destinationBackup.getProto().getCreateTime().getSeconds(), + destinationBackup.getProto().getCreateTime().getNanos(), + OffsetDateTime.now().getOffset()), + LocalDateTime.ofEpochSecond( + destinationBackup.getProto().getVersionTime().getSeconds(), + destinationBackup.getProto().getVersionTime().getNanos(), + OffsetDateTime.now().getOffset()))); + + return null; + } +} +// [END spanner_copy_backup] 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 10771e069d1..cce9772e913 100644 --- a/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java +++ b/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java @@ -1613,51 +1613,6 @@ static void createBackup(DatabaseAdminClient dbAdminClient, DatabaseId databaseI } // [END spanner_create_backup] - // [START spanner_copy_backup] - static void copyBackup(DatabaseAdminClient dbAdminClient, - BackupId backupId, String sourceBackupId) { - - // Creates a copy backup of an existing backup with tables - Backup backup = dbAdminClient - .newBackupBuilder(backupId) - .setSourceBackup(sourceBackupId) - .build(); - - Timestamp expireTime = Timestamp.ofTimeMicroseconds(TimeUnit.MICROSECONDS.convert( - System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14), TimeUnit.MILLISECONDS)); - - // Initiate the requefst which returns an OperationFuture. - System.out.println("Copying backup [" + backup.getId() + "]..."); - OperationFuture op = dbAdminClient.copyBackup(backup); - try { - // Wait for the backup operation to complete. - backup = op.get(); - System.out.println("Copied backup [" + backup.getId() + "]"); - } catch (ExecutionException e) { - throw (SpannerException) e.getCause(); - } catch (InterruptedException e) { - throw SpannerExceptionFactory.propagateInterrupt(e); - } - - // Reload the metadata of the backup from the server. - backup = backup.reload(); - System.out.println( - String.format( - "Backup %s of size %d bytes was copied 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()), - LocalDateTime.ofEpochSecond( - backup.getProto().getVersionTime().getSeconds(), - backup.getProto().getVersionTime().getNanos(), - OffsetDateTime.now().getOffset()) - )); - } - // [END spanner_copy_backup] - // [START spanner_cancel_backup_create] static void cancelCreateBackup( DatabaseAdminClient dbAdminClient, DatabaseId databaseId, BackupId backupId) { From ca240c6a0caca92a0b32d07daf0db5ded03339fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Mon, 28 Feb 2022 17:16:37 +0100 Subject: [PATCH 12/21] fix: checkstyle violation --- .../src/main/java/com/example/spanner/CopyBackupSample.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/samples/snippets/src/main/java/com/example/spanner/CopyBackupSample.java b/samples/snippets/src/main/java/com/example/spanner/CopyBackupSample.java index c6176d6f9f7..3933fc00c3b 100644 --- a/samples/snippets/src/main/java/com/example/spanner/CopyBackupSample.java +++ b/samples/snippets/src/main/java/com/example/spanner/CopyBackupSample.java @@ -38,7 +38,9 @@ public class CopyBackupSample { public static void main(String[] args) { if (args.length != 4) { throw new IllegalArgumentException( - "Invalid number of arguments. Usage: CopyBackupSample "); + "Invalid number of arguments. " + + "Usage: CopyBackupSample " + + " "); } String projectId = args[0]; String instanceId = args[1]; From a94174bb8fee12921c7af01e29098d6e7da0f8ab Mon Sep 17 00:00:00 2001 From: Astha Mohta Date: Tue, 15 Mar 2022 13:55:34 +0530 Subject: [PATCH 13/21] feat: adding max expire time and get referencing database support --- .../java/com/google/cloud/spanner/Backup.java | 6 ++- .../com/google/cloud/spanner/BackupInfo.java | 48 +++++++++++++++++-- .../com/example/spanner/SpannerSample.java | 2 + 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Backup.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Backup.java index 27308c04009..34850791d0c 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Backup.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Backup.java @@ -16,8 +16,6 @@ package com.google.cloud.spanner; -import static com.google.common.base.Preconditions.checkArgument; - import com.google.api.client.util.Preconditions; import com.google.api.gax.longrunning.OperationFuture; import com.google.api.gax.paging.Page; @@ -28,6 +26,8 @@ import com.google.spanner.admin.database.v1.CreateBackupMetadata; import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata; +import static com.google.common.base.Preconditions.checkArgument; + /** * Represents a Cloud Spanner database backup. {@code Backup} adds a layer of service related * functionality over {@code BackupInfo}. @@ -183,6 +183,8 @@ static Backup fromProto( .setDatabase(DatabaseId.of(proto.getDatabase())) .setEncryptionInfo(EncryptionInfo.fromProtoOrNull(proto.getEncryptionInfo())) .setProto(proto) + .setMaxExpireTime(Timestamp.fromProto(proto.getMaxExpireTime())) + .setReferencingBackup(proto.getReferencingBackupsList()) .build(); } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java index 0657ff2b7b8..527fb3d8aa7 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java @@ -20,9 +20,11 @@ import com.google.cloud.Timestamp; import com.google.cloud.spanner.encryption.BackupEncryptionConfig; import com.google.cloud.spanner.encryption.EncryptionInfo; +import com.google.protobuf.ProtocolStringList; import com.google.spanner.admin.database.v1.Database; -import java.util.Objects; + import javax.annotation.Nullable; +import java.util.Objects; /** Represents a Cloud Spanner database backup. */ public class BackupInfo { @@ -84,6 +86,9 @@ public abstract static class Builder { /** Builds the backup from this builder. */ public abstract Backup build(); + + protected abstract Builder setMaxExpireTime(Timestamp maxExpireTime); + protected abstract Builder setReferencingBackup(ProtocolStringList referencingBackup); } abstract static class BuilderImpl extends Builder { @@ -96,6 +101,8 @@ abstract static class BuilderImpl extends Builder { private BackupEncryptionConfig encryptionConfig; private EncryptionInfo encryptionInfo; private com.google.spanner.admin.database.v1.Backup proto; + private Timestamp maxExpireTime; + private ProtocolStringList referencingBackup; BuilderImpl(BackupId id) { this.id = Preconditions.checkNotNull(id); @@ -111,6 +118,8 @@ abstract static class BuilderImpl extends Builder { this.encryptionConfig = other.encryptionConfig; this.encryptionInfo = other.encryptionInfo; this.proto = other.proto; + this.maxExpireTime = other.maxExpireTime; + this.referencingBackup = other.referencingBackup; } @Override @@ -163,6 +172,19 @@ Builder setProto(@Nullable com.google.spanner.admin.database.v1.Backup proto) { this.proto = proto; return this; } + + @Override + public Builder setMaxExpireTime(Timestamp maxExpireTime) { + this.maxExpireTime = Preconditions.checkNotNull(maxExpireTime); + return this; + } + + + @Override + public Builder setReferencingBackup(ProtocolStringList referencingBackup) { + this.referencingBackup = Preconditions.checkNotNull(referencingBackup); + return this; + } } /** State of the backup. */ @@ -184,6 +206,8 @@ public enum State { private final BackupEncryptionConfig encryptionConfig; private final EncryptionInfo encryptionInfo; private final com.google.spanner.admin.database.v1.Backup proto; + private final Timestamp maxExpireTime; + private final ProtocolStringList referencingBackup; BackupInfo(BuilderImpl builder) { this.id = builder.id; @@ -195,6 +219,8 @@ public enum State { this.versionTime = builder.versionTime; this.database = builder.database; this.proto = builder.proto; + this.maxExpireTime = builder.maxExpireTime; + this.referencingBackup = builder.referencingBackup; } /** Returns the backup id. */ @@ -253,6 +279,14 @@ public DatabaseId getDatabase() { return proto; } + public Timestamp getMaxExpireTime() { + return maxExpireTime; + } + + public ProtocolStringList getReferencingBackup() { + return referencingBackup; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -269,19 +303,21 @@ public boolean equals(Object o) { && Objects.equals(encryptionInfo, that.encryptionInfo) && Objects.equals(expireTime, that.expireTime) && Objects.equals(versionTime, that.versionTime) - && Objects.equals(database, that.database); + && Objects.equals(database, that.database) + && Objects.equals(maxExpireTime, that.maxExpireTime) + && Objects.equals(referencingBackup, that.referencingBackup); } @Override public int hashCode() { return Objects.hash( - id, state, size, encryptionConfig, encryptionInfo, expireTime, versionTime, database); + id, state, size, encryptionConfig, encryptionInfo, expireTime, versionTime, database, maxExpireTime, referencingBackup); } @Override public String toString() { return String.format( - "Backup[%s, %s, %d, %s, %s, %s, %s, %s]", + "Backup[%s, %s, %d, %s, %s, %s, %s, %s, %s, %s]", id.getName(), state, size, @@ -289,6 +325,8 @@ public String toString() { encryptionInfo, expireTime, versionTime, - database); + database, + maxExpireTime, + referencingBackup); } } 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 cce9772e913..1b766422c92 100644 --- a/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java +++ b/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java @@ -1842,6 +1842,8 @@ static void updateBackup(DatabaseAdminClient dbAdminClient, BackupId backupId) { TimeUnit.SECONDS.toMicros(backup.getExpireTime().getSeconds()) + TimeUnit.NANOSECONDS.toMicros(backup.getExpireTime().getNanos()) + TimeUnit.DAYS.toMicros(30L)); + // New Expire Time must be less than Max Expire Time + expireTime = expireTime.compareTo(backup.getMaxExpireTime())<0?expireTime:backup.getMaxExpireTime(); int timeDiff = expireTime.compareTo(backup.getExpireTime()); Timestamp newExpireTime = (timeDiff < 0) ? expireTime : backup.getExpireTime(); From 780d6743c06ce34d0fe3050b1cab288b3282bdcc Mon Sep 17 00:00:00 2001 From: Astha Mohta Date: Wed, 16 Mar 2022 16:24:51 +0530 Subject: [PATCH 14/21] samples: adding copy backup operation support --- .../com/example/spanner/SpannerSample.java | 51 ++++++++++++++----- 1 file changed, 37 insertions(+), 14 deletions(-) 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 1b766422c92..4db8de52573 100644 --- a/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java +++ b/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java @@ -1661,21 +1661,17 @@ static void cancelCreateBackup( // [END spanner_cancel_backup_create] // [START spanner_list_backup_operations] - static void listBackupOperations(InstanceAdminClient instanceAdminClient, DatabaseId databaseId) { + static void listBackupOperations(InstanceAdminClient instanceAdminClient, DatabaseId databaseId, BackupId backupId) { Instance instance = instanceAdminClient.getInstance(databaseId.getInstanceId().getInstance()); // Get create backup operations for the sample database. - Timestamp last24Hours = Timestamp.ofTimeSecondsAndNanos(TimeUnit.SECONDS.convert( - TimeUnit.HOURS.convert(Timestamp.now().getSeconds(), TimeUnit.SECONDS) - 24, - TimeUnit.HOURS), 0); String filter = String.format( - "(metadata.database:%s) AND " - + "(metadata.@type:type.googleapis.com/" - + "google.spanner.admin.database.v1.CreateBackupMetadata) AND " - + "(metadata.progress.start_time > \"%s\")", - databaseId.getName(), last24Hours); - Page operations = instance.listBackupOperations(Options.filter(filter)); - for (Operation op : operations.iterateAll()) { + "(metadata.@type:type.googleapis.com/google.spanner.admin.database.v1.CreateBackupMetadata) " + + "AND (metadata.database:%s)", + databaseId.getName()); + Page createBackupOperations = instance.listBackupOperations(Options.filter(filter)); + System.out.println("Create Backup Operations:"); + for (Operation op : createBackupOperations.iterateAll()) { try { CreateBackupMetadata metadata = op.getMetadata().unpack(CreateBackupMetadata.class); System.out.println( @@ -1689,6 +1685,30 @@ static void listBackupOperations(InstanceAdminClient instanceAdminClient, Databa System.err.println(e.getMessage()); } } + + // Get copy backup operations for the sample database. + filter = + String.format( + "(metadata.@type:type.googleapis.com/" + + "google.spanner.admin.database.v1.CopyBackupMetadata) " + + "AND (metadata.source_backup:%s)", + backupId.getName()); + Page copyBackupOperations = instance.listBackupOperations(Options.filter(filter)); + System.out.println("Copy Backup Operations:"); + for (Operation op : copyBackupOperations.iterateAll()) { + try { + CopyBackupMetadata copyBackupMetadata = op.getMetadata().unpack(CopyBackupMetadata.class); + System.out.println( + String.format( + "Copy Backup %s on backup %s pending: %d%% complete", + copyBackupMetadata.getName(), + copyBackupMetadata.getSourceBackup(), + copyBackupMetadata.getProgress().getProgressPercent())); + } catch (InvalidProtocolBufferException e) { + // The returned operation does not contain CopyBackupMetadata. + System.err.println(e.getMessage()); + } + } } // [END spanner_list_backup_operations] @@ -2055,7 +2075,7 @@ static void run( BackupId.of(backup.getInstanceId(), backup.getBackup() + "_cancel")); break; case "listbackupoperations": - listBackupOperations(instanceAdminClient, database); + listBackupOperations(instanceAdminClient, database, backup); break; case "listdatabaseoperations": listDatabaseOperations(instanceAdminClient, dbAdminClient, database.getInstanceId()); @@ -2151,14 +2171,14 @@ static void printUsageAndExit() { System.err.println(" SpannerExample querywithqueryoptions my-instance example-db"); System.err.println(" SpannerExample createbackup my-instance example-db"); System.err.println(" SpannerExample listbackups my-instance example-db"); - System.err.println(" SpannerExample listbackupoperations my-instance example-db"); + System.err.println(" SpannerExample listbackupoperations my-instance example-db backup-id"); System.err.println(" SpannerExample listdatabaseoperations my-instance example-db"); System.err.println(" SpannerExample restorebackup my-instance example-db"); System.exit(1); } public static void main(String[] args) throws Exception { - if (args.length != 3) { + if (args.length != 3 && args.length != 4) { printUsageAndExit(); } // [START init_client] @@ -2182,6 +2202,9 @@ public static void main(String[] args) throws Exception { String.format( "%s_%02d", db.getDatabase(), LocalDate.now().get(ChronoField.ALIGNED_WEEK_OF_YEAR)); + if( args.length == 4) { + backupName = args[3]; + } BackupId backup = BackupId.of(db.getInstanceId(), backupName); // [START init_client] From 8670fb6b746cddaf7ae323e702db1bca77f3c1e5 Mon Sep 17 00:00:00 2001 From: Astha Mohta Date: Mon, 21 Mar 2022 12:04:23 +0530 Subject: [PATCH 15/21] adding documentation --- .../java/com/google/cloud/spanner/Backup.java | 2 +- .../com/google/cloud/spanner/BackupInfo.java | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Backup.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Backup.java index 34850791d0c..f61158332de 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Backup.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Backup.java @@ -177,7 +177,7 @@ static Backup fromProto( checkArgument(!proto.getDatabase().isEmpty(), "Missing expected 'database' field"); return new Backup.Builder(client, BackupId.of(proto.getName())) .setState(fromProtoState(proto.getState())) - .setSize(proto.getSizeBytes()) + .setSize(proto.getSiprotected abstract Builder setMaxExpireTime(Timestamp maxExpireTime);zeBytes()) .setExpireTime(Timestamp.fromProto(proto.getExpireTime())) .setVersionTime(Timestamp.fromProto(proto.getVersionTime())) .setDatabase(DatabaseId.of(proto.getDatabase())) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java index 527fb3d8aa7..1e2edcaa1a8 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java @@ -87,7 +87,20 @@ public abstract static class Builder { /** Builds the backup from this builder. */ public abstract Backup build(); + /** + * Output Only. + * + *

Returns the max allowed expiration time of the backup, with + * microseconds granularity. + */ protected abstract Builder setMaxExpireTime(Timestamp maxExpireTime); + + /** + * Output Only. + * + *

Returns the names of the destination backups being created by copying + * this source backup. + */ protected abstract Builder setReferencingBackup(ProtocolStringList referencingBackup); } @@ -279,10 +292,13 @@ public DatabaseId getDatabase() { return proto; } + /** Returns the max expire time of this {@link Backup}. */ public Timestamp getMaxExpireTime() { return maxExpireTime; } + /** Returns the names of the destination backups being created by copying + * this source backup {@link Backup}. */ public ProtocolStringList getReferencingBackup() { return referencingBackup; } From 2d627aa6321f315871e71d35a70ff46cfee902f1 Mon Sep 17 00:00:00 2001 From: Astha Mohta Date: Mon, 21 Mar 2022 13:12:16 +0530 Subject: [PATCH 16/21] linting changes --- .../clirr-ignored-differences.xml | 25 +++++++++++ .../java/com/google/cloud/spanner/Backup.java | 6 +-- .../com/google/cloud/spanner/BackupInfo.java | 27 +++++++----- patch.patch | 42 ------------------- samples/pom.xml | 20 ++++++++- 5 files changed, 64 insertions(+), 56 deletions(-) delete mode 100644 patch.patch diff --git a/google-cloud-spanner/clirr-ignored-differences.xml b/google-cloud-spanner/clirr-ignored-differences.xml index 464f6e9e9f8..18805fb53c2 100644 --- a/google-cloud-spanner/clirr-ignored-differences.xml +++ b/google-cloud-spanner/clirr-ignored-differences.xml @@ -35,4 +35,29 @@ com/google/cloud/spanner/connection/ConnectionOptions com.google.cloud.spanner.Dialect getDialect() + + 7013 + com/google/cloud/spanner/BackupInfo$Builder + com.google.cloud.spanner.BackupInfo$Builder setMaxExpireTime(com.google.cloud.Timestamp) + + + 7013 + com/google/cloud/spanner/BackupInfo$Builder + com.google.cloud.spanner.BackupInfo$Builder setReferencingBackup(com.google.protobuf.ProtocolStringList) + + + 7012 + com/google/cloud/spanner/DatabaseAdminClient + com.google.api.gax.longrunning.OperationFuture copyBackup(java.lang.String, java.lang.String, java.lang.String, com.google.cloud.Timestamp) + + + 7012 + com/google/cloud/spanner/DatabaseAdminClient + com.google.api.gax.longrunning.OperationFuture copyBackup(com.google.cloud.spanner.BackupId, com.google.cloud.spanner.Backup) + + + 7012 + com/google/cloud/spanner/spi/v1/SpannerRpc + com.google.api.gax.longrunning.OperationFuture copyBackUp(com.google.cloud.spanner.BackupId, com.google.cloud.spanner.Backup) + diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Backup.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Backup.java index f61158332de..c824cf2de15 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Backup.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Backup.java @@ -16,6 +16,8 @@ package com.google.cloud.spanner; +import static com.google.common.base.Preconditions.checkArgument; + import com.google.api.client.util.Preconditions; import com.google.api.gax.longrunning.OperationFuture; import com.google.api.gax.paging.Page; @@ -26,8 +28,6 @@ import com.google.spanner.admin.database.v1.CreateBackupMetadata; import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata; -import static com.google.common.base.Preconditions.checkArgument; - /** * Represents a Cloud Spanner database backup. {@code Backup} adds a layer of service related * functionality over {@code BackupInfo}. @@ -177,7 +177,7 @@ static Backup fromProto( checkArgument(!proto.getDatabase().isEmpty(), "Missing expected 'database' field"); return new Backup.Builder(client, BackupId.of(proto.getName())) .setState(fromProtoState(proto.getState())) - .setSize(proto.getSiprotected abstract Builder setMaxExpireTime(Timestamp maxExpireTime);zeBytes()) + .setSize(proto.getSizeBytes()) .setExpireTime(Timestamp.fromProto(proto.getExpireTime())) .setVersionTime(Timestamp.fromProto(proto.getVersionTime())) .setDatabase(DatabaseId.of(proto.getDatabase())) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java index 1e2edcaa1a8..a8b19973c94 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java @@ -22,9 +22,8 @@ import com.google.cloud.spanner.encryption.EncryptionInfo; import com.google.protobuf.ProtocolStringList; import com.google.spanner.admin.database.v1.Database; - -import javax.annotation.Nullable; import java.util.Objects; +import javax.annotation.Nullable; /** Represents a Cloud Spanner database backup. */ public class BackupInfo { @@ -90,16 +89,14 @@ public abstract static class Builder { /** * Output Only. * - *

Returns the max allowed expiration time of the backup, with - * microseconds granularity. + *

Returns the max allowed expiration time of the backup, with microseconds granularity. */ protected abstract Builder setMaxExpireTime(Timestamp maxExpireTime); /** * Output Only. * - *

Returns the names of the destination backups being created by copying - * this source backup. + *

Returns the names of the destination backups being created by copying this source backup. */ protected abstract Builder setReferencingBackup(ProtocolStringList referencingBackup); } @@ -192,7 +189,6 @@ public Builder setMaxExpireTime(Timestamp maxExpireTime) { return this; } - @Override public Builder setReferencingBackup(ProtocolStringList referencingBackup) { this.referencingBackup = Preconditions.checkNotNull(referencingBackup); @@ -297,8 +293,10 @@ public Timestamp getMaxExpireTime() { return maxExpireTime; } - /** Returns the names of the destination backups being created by copying - * this source backup {@link Backup}. */ + /** + * Returns the names of the destination backups being created by copying this source backup {@link + * Backup}. + */ public ProtocolStringList getReferencingBackup() { return referencingBackup; } @@ -327,7 +325,16 @@ public boolean equals(Object o) { @Override public int hashCode() { return Objects.hash( - id, state, size, encryptionConfig, encryptionInfo, expireTime, versionTime, database, maxExpireTime, referencingBackup); + id, + state, + size, + encryptionConfig, + encryptionInfo, + expireTime, + versionTime, + database, + maxExpireTime, + referencingBackup); } @Override diff --git a/patch.patch b/patch.patch deleted file mode 100644 index e5a1256475c..00000000000 --- a/patch.patch +++ /dev/null @@ -1,42 +0,0 @@ -diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml -index f5d1351a..9ede6f23 100644 ---- a/samples/snippets/pom.xml -+++ b/samples/snippets/pom.xml -@@ -47,6 +47,11 @@ - 6.19.1-SNAPSHOT - - -+ -+ com.google.api.grpc -+ proto-google-cloud-spanner-admin-database-v1 -+ 6.19.1-SNAPSHOT -+ - - - io.opencensus -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 2a4db98c..c44a012d 100644 ---- a/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java -+++ b/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java -@@ -1625,9 +1625,9 @@ public class SpannerSample { - Timestamp expireTime = Timestamp.ofTimeMicroseconds(TimeUnit.MICROSECONDS.convert( - System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14), TimeUnit.MILLISECONDS)); - -- // Initiate the request which returns an OperationFuture. -+ // Initiate the requefst which returns an OperationFuture. - System.out.println("Copying backup [" + backup.getId() + "]..."); -- OperationFuture op = backup.copyBackup(); -+ OperationFuture op = dbAdminClient.copyBackup(backup); - try { - // Wait for the backup operation to complete. - backup = op.get(); -@@ -1886,7 +1886,8 @@ public class SpannerSample { - TimeUnit.SECONDS.toMicros(backup.getExpireTime().getSeconds()) - + TimeUnit.NANOSECONDS.toMicros(backup.getExpireTime().getNanos()) - + TimeUnit.DAYS.toMicros(30L)); -- Timestamp newExpireTime = Math.min(expireTime, backup.getExpireTime()); -+ int timeDiff = expireTime.compareTo(backup.getExpireTime()); -+ Timestamp newExpireTime = (timeDiff < 0) ? expireTime : backup.getExpireTime(); - - System.out.println(String.format( - "Updating expire time of backup [%s] to %s...", diff --git a/samples/pom.xml b/samples/pom.xml index 8271ea6812d..53b7c5519d8 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -33,6 +33,24 @@ snippets + + + com.google.cloud + google-cloud-spanner + 6.19.1-SNAPSHOT + + + + com.google.api.grpc + grpc-google-cloud-spanner-admin-database-v1 + 6.19.1-SNAPSHOT + + + com.google.api.grpc + proto-google-cloud-spanner-admin-database-v1 + 6.19.1-SNAPSHOT + + @@ -53,4 +71,4 @@ - + From 430f772fc7cfcc1503eea2ff9e7073cde9b964f2 Mon Sep 17 00:00:00 2001 From: Astha Mohta Date: Fri, 25 Mar 2022 13:19:24 +0530 Subject: [PATCH 17/21] changes as per review --- .../java/com/google/cloud/spanner/Backup.java | 6 ++-- .../com/google/cloud/spanner/BackupInfo.java | 21 ++++++++----- .../cloud/spanner/DatabaseAdminClient.java | 28 ++++++++--------- .../cloud/spanner/spi/v1/SpannerRpc.java | 31 ++++--------------- .../com/google/cloud/spanner/BackupTest.java | 27 ++++++++++------ .../com/example/spanner/SpannerSample.java | 3 +- 6 files changed, 54 insertions(+), 62 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Backup.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Backup.java index c824cf2de15..007a81630f3 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Backup.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Backup.java @@ -16,8 +16,6 @@ package com.google.cloud.spanner; -import static com.google.common.base.Preconditions.checkArgument; - import com.google.api.client.util.Preconditions; import com.google.api.gax.longrunning.OperationFuture; import com.google.api.gax.paging.Page; @@ -28,6 +26,8 @@ import com.google.spanner.admin.database.v1.CreateBackupMetadata; import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata; +import static com.google.common.base.Preconditions.checkArgument; + /** * Represents a Cloud Spanner database backup. {@code Backup} adds a layer of service related * functionality over {@code BackupInfo}. @@ -184,7 +184,7 @@ static Backup fromProto( .setEncryptionInfo(EncryptionInfo.fromProtoOrNull(proto.getEncryptionInfo())) .setProto(proto) .setMaxExpireTime(Timestamp.fromProto(proto.getMaxExpireTime())) - .setReferencingBackup(proto.getReferencingBackupsList()) + .addAllReferencingBackups(proto.getReferencingBackupsList()) .build(); } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java index a8b19973c94..e860758bf8b 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java @@ -20,10 +20,11 @@ import com.google.cloud.Timestamp; import com.google.cloud.spanner.encryption.BackupEncryptionConfig; import com.google.cloud.spanner.encryption.EncryptionInfo; -import com.google.protobuf.ProtocolStringList; import com.google.spanner.admin.database.v1.Database; -import java.util.Objects; + import javax.annotation.Nullable; +import java.util.List; +import java.util.Objects; /** Represents a Cloud Spanner database backup. */ public class BackupInfo { @@ -91,14 +92,18 @@ public abstract static class Builder { * *

Returns the max allowed expiration time of the backup, with microseconds granularity. */ - protected abstract Builder setMaxExpireTime(Timestamp maxExpireTime); + protected Builder setMaxExpireTime(Timestamp maxExpireTime) { + throw new UnsupportedOperationException("Unimplemented"); + } /** * Output Only. * *

Returns the names of the destination backups being created by copying this source backup. */ - protected abstract Builder setReferencingBackup(ProtocolStringList referencingBackup); + protected Builder addAllReferencingBackups(List referencingBackup) { + throw new UnsupportedOperationException("Unimplemented"); + } } abstract static class BuilderImpl extends Builder { @@ -112,7 +117,7 @@ abstract static class BuilderImpl extends Builder { private EncryptionInfo encryptionInfo; private com.google.spanner.admin.database.v1.Backup proto; private Timestamp maxExpireTime; - private ProtocolStringList referencingBackup; + private List referencingBackup; BuilderImpl(BackupId id) { this.id = Preconditions.checkNotNull(id); @@ -190,7 +195,7 @@ public Builder setMaxExpireTime(Timestamp maxExpireTime) { } @Override - public Builder setReferencingBackup(ProtocolStringList referencingBackup) { + public Builder addAllReferencingBackups(List referencingBackup) { this.referencingBackup = Preconditions.checkNotNull(referencingBackup); return this; } @@ -216,7 +221,7 @@ public enum State { private final EncryptionInfo encryptionInfo; private final com.google.spanner.admin.database.v1.Backup proto; private final Timestamp maxExpireTime; - private final ProtocolStringList referencingBackup; + private final List referencingBackup; BackupInfo(BuilderImpl builder) { this.id = builder.id; @@ -297,7 +302,7 @@ public Timestamp getMaxExpireTime() { * Returns the names of the destination backups being created by copying this source backup {@link * Backup}. */ - public ProtocolStringList getReferencingBackup() { + public List getReferencingBackup() { return referencingBackup; } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java index 114628d136a..e8afa40b87c 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java @@ -22,12 +22,7 @@ import com.google.cloud.Timestamp; import com.google.cloud.spanner.Options.ListOption; import com.google.longrunning.Operation; -import com.google.spanner.admin.database.v1.CopyBackupMetadata; -import com.google.spanner.admin.database.v1.CreateBackupMetadata; -import com.google.spanner.admin.database.v1.CreateDatabaseMetadata; -import com.google.spanner.admin.database.v1.CreateDatabaseRequest; -import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata; -import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; +import com.google.spanner.admin.database.v1.*; import java.util.List; import javax.annotation.Nullable; @@ -185,10 +180,10 @@ OperationFuture createBackup( *

Example to copy a backup. * *

{@code
-   * String instanceId                  = "my_instance_id";
-   * String sourceBackupId              = "source_backup_id";
-   * String destinationBackupId         = "destination_backup_id";
-   * Timestamp expireTime               = Timestamp.ofTimeMicroseconds(micros);
+   * String instanceId                  ="my_instance_id";
+   * String sourceBackupId              ="source_backup_id";
+   * String destinationBackupId         ="destination_backup_id";
+   * Timestamp expireTime               =Timestamp.ofTimeMicroseconds(micros);
    * OperationFuture op = dbAdminClient
    *     .copyBackup(
    *         instanceId,
@@ -205,9 +200,10 @@ OperationFuture createBackup(
    *     regular expression [a-z][a-z0-9_\-]*[a-z0-9] and be between 2 and 60 characters in length.
    * @param expireTime the time that the new backup will automatically expire.
    */
-  OperationFuture copyBackup(
-      String instanceId, String sourceBackupId, String destinationBackupId, Timestamp expireTime)
-      throws SpannerException;
+  default OperationFuture copyBackup(
+      String instanceId, String sourceBackupId, String destinationBackupId, Timestamp expireTime) {
+    throw new UnsupportedOperationException("Unimplemented");
+  }
 
   /**
    * Creates a copy of backup from an existing backup in Cloud Spanner. Any configuration options in
@@ -240,8 +236,10 @@ OperationFuture copyBackup(
    * @param sourceBackupId the backup to be copied
    * @param destinationBackup the new backup to create
    */
-  OperationFuture copyBackup(
-      BackupId sourceBackupId, Backup destinationBackup) throws SpannerException;
+  default OperationFuture copyBackup(
+      BackupId sourceBackupId, Backup destinationBackup) {
+    throw new UnsupportedOperationException("Unimplemented");
+  }
 
   /**
    * Restore a database from a backup. The database that is restored will be created and may not
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java
index 0cfd4306f03..9d87385ae7a 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java
@@ -33,32 +33,12 @@
 import com.google.longrunning.Operation;
 import com.google.protobuf.Empty;
 import com.google.protobuf.FieldMask;
-import com.google.spanner.admin.database.v1.Backup;
-import com.google.spanner.admin.database.v1.CopyBackupMetadata;
-import com.google.spanner.admin.database.v1.CreateBackupMetadata;
-import com.google.spanner.admin.database.v1.CreateDatabaseMetadata;
-import com.google.spanner.admin.database.v1.Database;
-import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata;
-import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
+import com.google.spanner.admin.database.v1.*;
 import com.google.spanner.admin.instance.v1.CreateInstanceMetadata;
 import com.google.spanner.admin.instance.v1.Instance;
 import com.google.spanner.admin.instance.v1.InstanceConfig;
 import com.google.spanner.admin.instance.v1.UpdateInstanceMetadata;
-import com.google.spanner.v1.BeginTransactionRequest;
-import com.google.spanner.v1.CommitRequest;
-import com.google.spanner.v1.CommitResponse;
-import com.google.spanner.v1.ExecuteBatchDmlRequest;
-import com.google.spanner.v1.ExecuteBatchDmlResponse;
-import com.google.spanner.v1.ExecuteSqlRequest;
-import com.google.spanner.v1.PartialResultSet;
-import com.google.spanner.v1.PartitionQueryRequest;
-import com.google.spanner.v1.PartitionReadRequest;
-import com.google.spanner.v1.PartitionResponse;
-import com.google.spanner.v1.ReadRequest;
-import com.google.spanner.v1.ResultSet;
-import com.google.spanner.v1.RollbackRequest;
-import com.google.spanner.v1.Session;
-import com.google.spanner.v1.Transaction;
+import com.google.spanner.v1.*;
 import java.util.List;
 import java.util.Map;
 import javax.annotation.Nullable;
@@ -241,9 +221,10 @@ OperationFuture createBackup(
    *     source backup.
    * @return the operation that monitors the backup creation.
    */
-  OperationFuture copyBackUp(
-      BackupId sourceBackupId, com.google.cloud.spanner.Backup destinationBackup)
-      throws SpannerException;
+  default OperationFuture copyBackUp(
+      BackupId sourceBackupId, com.google.cloud.spanner.Backup destinationBackup) {
+    throw new UnsupportedOperationException("Unimplemented");
+  }
 
   /**
    * Restore a backup into the given database.
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java
index cf8d09eabe6..37ee8f31abf 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java
@@ -16,15 +16,6 @@
 
 package com.google.cloud.spanner;
 
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThrows;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import static org.mockito.MockitoAnnotations.initMocks;
-
 import com.google.cloud.Identity;
 import com.google.cloud.Policy;
 import com.google.cloud.Role;
@@ -34,7 +25,6 @@
 import com.google.cloud.spanner.encryption.EncryptionInfo;
 import com.google.rpc.Code;
 import com.google.rpc.Status;
-import java.util.Collections;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -42,11 +32,22 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 
+import java.util.Arrays;
+import java.util.Collections;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
+
 @RunWith(JUnit4.class)
 public class BackupTest {
 
   private static final String NAME =
       "projects/test-project/instances/test-instance/backups/backup-1";
+  private static final String REFERENCING_BACKUP_NAME =
+      "projects/test-project/instances/test-instance/backups/backup-2";
   private static final String DB = "projects/test-project/instances/test-instance/databases/db-1";
   private static final Timestamp EXP_TIME = Timestamp.ofTimeSecondsAndNanos(1000L, 1000);
   private static final Timestamp VERSION_TIME = Timestamp.ofTimeSecondsAndNanos(2000L, 2000);
@@ -311,6 +312,9 @@ private Backup createBackup() {
                 com.google.protobuf.Timestamp.newBuilder().setSeconds(2000L).setNanos(2000).build())
             .setEncryptionInfo(ENCRYPTION_INFO)
             .setState(com.google.spanner.admin.database.v1.Backup.State.CREATING)
+            .setMaxExpireTime(
+                com.google.protobuf.Timestamp.newBuilder().setSeconds(3000L).setNanos(3000).build())
+            .addAllReferencingBackups(Arrays.asList(REFERENCING_BACKUP_NAME))
             .build();
     return Backup.fromProto(proto, dbClient);
   }
@@ -326,6 +330,9 @@ private Backup copyBackup() {
                 com.google.protobuf.Timestamp.newBuilder().setSeconds(2000L).setNanos(2000).build())
             .setEncryptionInfo(ENCRYPTION_INFO)
             .setState(com.google.spanner.admin.database.v1.Backup.State.CREATING)
+            .setMaxExpireTime(
+                com.google.protobuf.Timestamp.newBuilder().setSeconds(3000L).setNanos(3000).build())
+            .addAllReferencingBackups(Arrays.asList(REFERENCING_BACKUP_NAME))
             .build();
     return Backup.fromProto(proto, dbClient);
   }
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 4db8de52573..29a7c26ab56 100644
--- a/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java
@@ -1661,7 +1661,8 @@ static void cancelCreateBackup(
   // [END spanner_cancel_backup_create]
 
   // [START spanner_list_backup_operations]
-  static void listBackupOperations(InstanceAdminClient instanceAdminClient, DatabaseId databaseId, BackupId backupId) {
+  static void listBackupOperations(
+          InstanceAdminClient instanceAdminClient, DatabaseId databaseId, BackupId backupId) {
     Instance instance = instanceAdminClient.getInstance(databaseId.getInstanceId().getInstance());
     // Get create backup operations for the sample database.
     String filter =

From b06a3df559ee901a84a14a99624fa985b781d52d Mon Sep 17 00:00:00 2001
From: Astha Mohta 
Date: Fri, 25 Mar 2022 13:20:55 +0530
Subject: [PATCH 18/21] removing samples

---
 .../java/com/google/cloud/spanner/Backup.java |   4 +-
 .../com/google/cloud/spanner/BackupInfo.java  |   3 +-
 .../com/google/cloud/spanner/BackupTest.java  |  17 ++-
 samples/pom.xml                               |  20 +--
 samples/snippets/pom.xml                      |  11 --
 .../com/example/spanner/CopyBackupSample.java | 123 ------------------
 .../com/example/spanner/SpannerSample.java    |  59 ++-------
 7 files changed, 26 insertions(+), 211 deletions(-)
 delete mode 100644 samples/snippets/src/main/java/com/example/spanner/CopyBackupSample.java

diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Backup.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Backup.java
index 007a81630f3..6d694b0052a 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Backup.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Backup.java
@@ -16,6 +16,8 @@
 
 package com.google.cloud.spanner;
 
+import static com.google.common.base.Preconditions.checkArgument;
+
 import com.google.api.client.util.Preconditions;
 import com.google.api.gax.longrunning.OperationFuture;
 import com.google.api.gax.paging.Page;
@@ -26,8 +28,6 @@
 import com.google.spanner.admin.database.v1.CreateBackupMetadata;
 import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata;
 
-import static com.google.common.base.Preconditions.checkArgument;
-
 /**
  * Represents a Cloud Spanner database backup. {@code Backup} adds a layer of service related
  * functionality over {@code BackupInfo}.
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java
index e860758bf8b..c62d274185c 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java
@@ -21,10 +21,9 @@
 import com.google.cloud.spanner.encryption.BackupEncryptionConfig;
 import com.google.cloud.spanner.encryption.EncryptionInfo;
 import com.google.spanner.admin.database.v1.Database;
-
-import javax.annotation.Nullable;
 import java.util.List;
 import java.util.Objects;
+import javax.annotation.Nullable;
 
 /** Represents a Cloud Spanner database backup. */
 public class BackupInfo {
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java
index 37ee8f31abf..7551653da1f 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java
@@ -16,6 +16,12 @@
 
 package com.google.cloud.spanner;
 
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
+
 import com.google.cloud.Identity;
 import com.google.cloud.Policy;
 import com.google.cloud.Role;
@@ -25,6 +31,8 @@
 import com.google.cloud.spanner.encryption.EncryptionInfo;
 import com.google.rpc.Code;
 import com.google.rpc.Status;
+import java.util.Arrays;
+import java.util.Collections;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -32,15 +40,6 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 
-import java.util.Arrays;
-import java.util.Collections;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.*;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import static org.mockito.MockitoAnnotations.initMocks;
-
 @RunWith(JUnit4.class)
 public class BackupTest {
 
diff --git a/samples/pom.xml b/samples/pom.xml
index 53b7c5519d8..8271ea6812d 100644
--- a/samples/pom.xml
+++ b/samples/pom.xml
@@ -33,24 +33,6 @@
     snippets
   
 
-  
-  
-    com.google.cloud
-    google-cloud-spanner
-    6.19.1-SNAPSHOT
-  
-  
-  
-    com.google.api.grpc
-    grpc-google-cloud-spanner-admin-database-v1
-    6.19.1-SNAPSHOT
-  
-  
-    com.google.api.grpc
-    proto-google-cloud-spanner-admin-database-v1
-    6.19.1-SNAPSHOT
-  
-  
   
     
       
@@ -71,4 +53,4 @@
       
     
   
-
+ 
diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml
index a0ce1453146..74aaf074d52 100644
--- a/samples/snippets/pom.xml
+++ b/samples/snippets/pom.xml
@@ -44,19 +44,8 @@
     
       com.google.cloud
       google-cloud-spanner
-      6.19.1-SNAPSHOT
     
     
-    
-      com.google.api.grpc
-      grpc-google-cloud-spanner-admin-database-v1
-      6.19.1-SNAPSHOT
-    
-    
-      com.google.api.grpc
-      proto-google-cloud-spanner-admin-database-v1
-      6.19.1-SNAPSHOT
-    
 
     
       io.opencensus
diff --git a/samples/snippets/src/main/java/com/example/spanner/CopyBackupSample.java b/samples/snippets/src/main/java/com/example/spanner/CopyBackupSample.java
deleted file mode 100644
index 3933fc00c3b..00000000000
--- a/samples/snippets/src/main/java/com/example/spanner/CopyBackupSample.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2022 Google Inc.
- *
- * 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_copy_backup]
-
-import com.google.api.gax.longrunning.OperationFuture;
-import com.google.cloud.Timestamp;
-import com.google.cloud.spanner.Backup;
-import com.google.cloud.spanner.BackupId;
-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.CopyBackupMetadata;
-import java.time.LocalDateTime;
-import java.time.OffsetDateTime;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-
-public class CopyBackupSample {
-
-  public static void main(String[] args) {
-    if (args.length != 4) {
-      throw new IllegalArgumentException(
-          "Invalid number of arguments. "
-              + "Usage: CopyBackupSample "
-              + "   ");
-    }
-    String projectId = args[0];
-    String instanceId = args[1];
-    String sourceBackupId = args[2];
-    String destinationBackupId = args[3];
-
-    try (Spanner spanner =
-        SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
-      DatabaseAdminClient databaseAdminClient = spanner.getDatabaseAdminClient();
-      copyBackup(databaseAdminClient, projectId, instanceId, sourceBackupId, destinationBackupId);
-    }
-  }
-
-  static void copyBackup() {
-    // TODO(developer): Replace these variables before running the sample.
-    String projectId = "my-project";
-    String instanceId = "my-instance";
-    String sourceBackupId = "my-backup";
-    String destinationBackupId = "my-destination-backup";
-
-    try (Spanner spanner =
-        SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
-      DatabaseAdminClient databaseAdminClient = spanner.getDatabaseAdminClient();
-      copyBackup(databaseAdminClient, projectId, instanceId, sourceBackupId, destinationBackupId);
-    }
-  }
-
-  static Void copyBackup(
-      DatabaseAdminClient databaseAdminClient,
-      String projectId,
-      String instanceId,
-      String sourceBackupId,
-      String destinationBackupId) {
-
-    Timestamp expireTime =
-        Timestamp.ofTimeMicroseconds(
-            TimeUnit.MICROSECONDS.convert(
-                System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14), TimeUnit.MILLISECONDS));
-    // Creates a copy of an existing backup.
-    Backup destinationBackup =
-        databaseAdminClient
-            .newBackupBuilder(BackupId.of(projectId, instanceId, destinationBackupId))
-            .setExpireTime(expireTime)
-            .build();
-
-    // Initiate the request which returns an OperationFuture.
-    System.out.println("Copying backup [" + destinationBackup.getId() + "]...");
-    OperationFuture op =
-        databaseAdminClient.copyBackup(
-            BackupId.of(projectId, instanceId, sourceBackupId), destinationBackup);
-    try {
-      // Wait for the backup operation to complete.
-      destinationBackup = op.get();
-      System.out.println("Copied backup [" + destinationBackup.getId() + "]");
-    } catch (ExecutionException e) {
-      throw (SpannerException) e.getCause();
-    } catch (InterruptedException e) {
-      throw SpannerExceptionFactory.propagateInterrupt(e);
-    }
-
-    // Reload the metadata of the backup from the server.
-    destinationBackup = destinationBackup.reload();
-    System.out.println(
-        String.format(
-            "Backup %s of size %d bytes was copied at %s for version of database at %s",
-            destinationBackup.getId().getName(),
-            destinationBackup.getSize(),
-            LocalDateTime.ofEpochSecond(
-                destinationBackup.getProto().getCreateTime().getSeconds(),
-                destinationBackup.getProto().getCreateTime().getNanos(),
-                OffsetDateTime.now().getOffset()),
-            LocalDateTime.ofEpochSecond(
-                destinationBackup.getProto().getVersionTime().getSeconds(),
-                destinationBackup.getProto().getVersionTime().getNanos(),
-                OffsetDateTime.now().getOffset())));
-
-    return null;
-  }
-}
-// [END spanner_copy_backup]
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 29a7c26ab56..d0ccd108145 100644
--- a/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java
@@ -56,14 +56,12 @@
 import com.google.common.io.BaseEncoding;
 import com.google.longrunning.Operation;
 import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.spanner.admin.database.v1.CopyBackupMetadata;
 import com.google.spanner.admin.database.v1.CreateBackupMetadata;
 import com.google.spanner.admin.database.v1.CreateDatabaseMetadata;
 import com.google.spanner.admin.database.v1.OptimizeRestoredDatabaseMetadata;
 import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata;
 import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
 import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions;
-import java.lang.Math;
 import java.math.BigDecimal;
 import java.time.Instant;
 import java.util.ArrayList;
@@ -1661,18 +1659,21 @@ static void cancelCreateBackup(
   // [END spanner_cancel_backup_create]
 
   // [START spanner_list_backup_operations]
-  static void listBackupOperations(
-          InstanceAdminClient instanceAdminClient, DatabaseId databaseId, BackupId backupId) {
+  static void listBackupOperations(InstanceAdminClient instanceAdminClient, DatabaseId databaseId) {
     Instance instance = instanceAdminClient.getInstance(databaseId.getInstanceId().getInstance());
     // Get create backup operations for the sample database.
+    Timestamp last24Hours = Timestamp.ofTimeSecondsAndNanos(TimeUnit.SECONDS.convert(
+        TimeUnit.HOURS.convert(Timestamp.now().getSeconds(), TimeUnit.SECONDS) - 24,
+        TimeUnit.HOURS), 0);
     String filter =
         String.format(
-            "(metadata.@type:type.googleapis.com/google.spanner.admin.database.v1.CreateBackupMetadata) "
-                + "AND (metadata.database:%s)",
-            databaseId.getName());
-    Page createBackupOperations = instance.listBackupOperations(Options.filter(filter));
-    System.out.println("Create Backup Operations:");
-    for (Operation op : createBackupOperations.iterateAll()) {
+            "(metadata.database:%s) AND "
+                + "(metadata.@type:type.googleapis.com/"
+                + "google.spanner.admin.database.v1.CreateBackupMetadata) AND "
+                + "(metadata.progress.start_time > \"%s\")",
+            databaseId.getName(), last24Hours);
+    Page operations = instance.listBackupOperations(Options.filter(filter));
+    for (Operation op : operations.iterateAll()) {
       try {
         CreateBackupMetadata metadata = op.getMetadata().unpack(CreateBackupMetadata.class);
         System.out.println(
@@ -1686,30 +1687,6 @@ static void listBackupOperations(
         System.err.println(e.getMessage());
       }
     }
-
-    // Get copy backup operations for the sample database.
-    filter =
-            String.format(
-                    "(metadata.@type:type.googleapis.com/"
-                            + "google.spanner.admin.database.v1.CopyBackupMetadata) "
-                            + "AND (metadata.source_backup:%s)",
-                    backupId.getName());
-    Page  copyBackupOperations = instance.listBackupOperations(Options.filter(filter));
-    System.out.println("Copy Backup Operations:");
-    for (Operation op : copyBackupOperations.iterateAll()) {
-      try {
-        CopyBackupMetadata copyBackupMetadata = op.getMetadata().unpack(CopyBackupMetadata.class);
-        System.out.println(
-                String.format(
-                        "Copy Backup %s on backup %s pending: %d%% complete",
-                        copyBackupMetadata.getName(),
-                        copyBackupMetadata.getSourceBackup(),
-                        copyBackupMetadata.getProgress().getProgressPercent()));
-      } catch (InvalidProtocolBufferException e) {
-        // The returned operation does not contain CopyBackupMetadata.
-        System.err.println(e.getMessage());
-      }
-    }
   }
   // [END spanner_list_backup_operations]
 
@@ -1863,11 +1840,6 @@ static void updateBackup(DatabaseAdminClient dbAdminClient, BackupId backupId) {
             TimeUnit.SECONDS.toMicros(backup.getExpireTime().getSeconds())
                 + TimeUnit.NANOSECONDS.toMicros(backup.getExpireTime().getNanos())
                 + TimeUnit.DAYS.toMicros(30L));
-    // New Expire Time must be less than Max Expire Time
-    expireTime = expireTime.compareTo(backup.getMaxExpireTime())<0?expireTime:backup.getMaxExpireTime();
-    int timeDiff = expireTime.compareTo(backup.getExpireTime());
-    Timestamp newExpireTime = (timeDiff < 0) ? expireTime : backup.getExpireTime();
-
     System.out.println(String.format(
         "Updating expire time of backup [%s] to %s...",
         backupId.toString(),
@@ -2076,7 +2048,7 @@ static void run(
             BackupId.of(backup.getInstanceId(), backup.getBackup() + "_cancel"));
         break;
       case "listbackupoperations":
-        listBackupOperations(instanceAdminClient, database, backup);
+        listBackupOperations(instanceAdminClient, database);
         break;
       case "listdatabaseoperations":
         listDatabaseOperations(instanceAdminClient, dbAdminClient, database.getInstanceId());
@@ -2172,14 +2144,14 @@ static void printUsageAndExit() {
     System.err.println("    SpannerExample querywithqueryoptions my-instance example-db");
     System.err.println("    SpannerExample createbackup my-instance example-db");
     System.err.println("    SpannerExample listbackups my-instance example-db");
-    System.err.println("    SpannerExample listbackupoperations my-instance example-db backup-id");
+    System.err.println("    SpannerExample listbackupoperations my-instance example-db");
     System.err.println("    SpannerExample listdatabaseoperations my-instance example-db");
     System.err.println("    SpannerExample restorebackup my-instance example-db");
     System.exit(1);
   }
 
   public static void main(String[] args) throws Exception {
-    if (args.length != 3 && args.length != 4) {
+    if (args.length != 3) {
       printUsageAndExit();
     }
     // [START init_client]
@@ -2203,9 +2175,6 @@ public static void main(String[] args) throws Exception {
           String.format(
               "%s_%02d",
               db.getDatabase(), LocalDate.now().get(ChronoField.ALIGNED_WEEK_OF_YEAR));
-      if( args.length == 4) {
-        backupName = args[3];
-      }
       BackupId backup = BackupId.of(db.getInstanceId(), backupName);
 
       // [START init_client]

From 809465cad4234748eb7a06eaba61a7c334654ca6 Mon Sep 17 00:00:00 2001
From: Astha Mohta 
Date: Fri, 25 Mar 2022 15:32:01 +0530
Subject: [PATCH 19/21] review changes

---
 .../com/google/cloud/spanner/BackupInfo.java  | 26 +++++++++----------
 .../cloud/spanner/DatabaseAdminClient.java    | 11 +++++---
 2 files changed, 21 insertions(+), 16 deletions(-)

diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java
index c62d274185c..3ea3329a6db 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java
@@ -100,7 +100,7 @@ protected Builder setMaxExpireTime(Timestamp maxExpireTime) {
      *
      * 

Returns the names of the destination backups being created by copying this source backup. */ - protected Builder addAllReferencingBackups(List referencingBackup) { + protected Builder addAllReferencingBackups(List referencingBackups) { throw new UnsupportedOperationException("Unimplemented"); } } @@ -116,7 +116,7 @@ abstract static class BuilderImpl extends Builder { private EncryptionInfo encryptionInfo; private com.google.spanner.admin.database.v1.Backup proto; private Timestamp maxExpireTime; - private List referencingBackup; + private List referencingBackups; BuilderImpl(BackupId id) { this.id = Preconditions.checkNotNull(id); @@ -133,7 +133,7 @@ abstract static class BuilderImpl extends Builder { this.encryptionInfo = other.encryptionInfo; this.proto = other.proto; this.maxExpireTime = other.maxExpireTime; - this.referencingBackup = other.referencingBackup; + this.referencingBackups = other.referencingBackups; } @Override @@ -188,14 +188,14 @@ Builder setProto(@Nullable com.google.spanner.admin.database.v1.Backup proto) { } @Override - public Builder setMaxExpireTime(Timestamp maxExpireTime) { + protected Builder setMaxExpireTime(Timestamp maxExpireTime) { this.maxExpireTime = Preconditions.checkNotNull(maxExpireTime); return this; } @Override - public Builder addAllReferencingBackups(List referencingBackup) { - this.referencingBackup = Preconditions.checkNotNull(referencingBackup); + protected Builder addAllReferencingBackups(List referencingBackups) { + this.referencingBackups = Preconditions.checkNotNull(referencingBackups); return this; } } @@ -220,7 +220,7 @@ public enum State { private final EncryptionInfo encryptionInfo; private final com.google.spanner.admin.database.v1.Backup proto; private final Timestamp maxExpireTime; - private final List referencingBackup; + private final List referencingBackups; BackupInfo(BuilderImpl builder) { this.id = builder.id; @@ -233,7 +233,7 @@ public enum State { this.database = builder.database; this.proto = builder.proto; this.maxExpireTime = builder.maxExpireTime; - this.referencingBackup = builder.referencingBackup; + this.referencingBackups = builder.referencingBackups; } /** Returns the backup id. */ @@ -301,8 +301,8 @@ public Timestamp getMaxExpireTime() { * Returns the names of the destination backups being created by copying this source backup {@link * Backup}. */ - public List getReferencingBackup() { - return referencingBackup; + public List getReferencingBackups() { + return referencingBackups; } @Override @@ -323,7 +323,7 @@ public boolean equals(Object o) { && Objects.equals(versionTime, that.versionTime) && Objects.equals(database, that.database) && Objects.equals(maxExpireTime, that.maxExpireTime) - && Objects.equals(referencingBackup, that.referencingBackup); + && Objects.equals(referencingBackups, that.referencingBackups); } @Override @@ -338,7 +338,7 @@ public int hashCode() { versionTime, database, maxExpireTime, - referencingBackup); + referencingBackups); } @Override @@ -354,6 +354,6 @@ public String toString() { versionTime, database, maxExpireTime, - referencingBackup); + referencingBackups); } } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java index e8afa40b87c..6bb559af423 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java @@ -22,7 +22,12 @@ import com.google.cloud.Timestamp; import com.google.cloud.spanner.Options.ListOption; import com.google.longrunning.Operation; -import com.google.spanner.admin.database.v1.*; +import com.google.spanner.admin.database.v1.CopyBackupMetadata; +import com.google.spanner.admin.database.v1.CreateBackupMetadata; +import com.google.spanner.admin.database.v1.CreateDatabaseMetadata; +import com.google.spanner.admin.database.v1.CreateDatabaseRequest; +import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata; +import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; import java.util.List; import javax.annotation.Nullable; @@ -206,8 +211,8 @@ default OperationFuture copyBackup( } /** - * Creates a copy of backup from an existing backup in Cloud Spanner. Any configuration options in - * the {@link Backup} instance will be included in the {@link + * Creates a copy of backup from an existing backup in Cloud Spanner in the same instance. Any + * configuration options in the {@link Backup} instance will be included in the {@link * com.google.spanner.admin.database.v1.CopyBackupRequest}. * *

The expire time of the new backup must be set and be at least 6 hours and at most 366 days From a968222583cec4a84ba1cc9d5880ebe35f19f274 Mon Sep 17 00:00:00 2001 From: Astha Mohta Date: Mon, 28 Mar 2022 10:32:24 +0530 Subject: [PATCH 20/21] changes as per review --- google-cloud-spanner/clirr-ignored-differences.xml | 2 +- .../com/google/cloud/spanner/DatabaseAdminClient.java | 2 +- .../com/google/cloud/spanner/DatabaseAdminClientImpl.java | 8 ++------ .../com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java | 2 +- .../java/com/google/cloud/spanner/spi/v1/SpannerRpc.java | 2 +- .../test/java/com/google/cloud/spanner/BackupTest.java | 5 ++--- .../google/cloud/spanner/DatabaseAdminClientImplTest.java | 6 +++--- 7 files changed, 11 insertions(+), 16 deletions(-) diff --git a/google-cloud-spanner/clirr-ignored-differences.xml b/google-cloud-spanner/clirr-ignored-differences.xml index 18805fb53c2..899b44e3546 100644 --- a/google-cloud-spanner/clirr-ignored-differences.xml +++ b/google-cloud-spanner/clirr-ignored-differences.xml @@ -58,6 +58,6 @@ 7012 com/google/cloud/spanner/spi/v1/SpannerRpc - com.google.api.gax.longrunning.OperationFuture copyBackUp(com.google.cloud.spanner.BackupId, com.google.cloud.spanner.Backup) + com.google.api.gax.longrunning.OperationFuture copyBackup(com.google.cloud.spanner.BackupId, com.google.cloud.spanner.Backup) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java index 6bb559af423..d3aa8b4d18f 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java @@ -234,7 +234,7 @@ default OperationFuture copyBackup( * .setEncryptionConfig(encryptionConfig) * .build(); * - * OperationFuture op = dbAdminClient.copyBackUp(sourceBackupId, destinationBackup); + * OperationFuture op = dbAdminClient.copyBackup(sourceBackupId, destinationBackup); * Backup copiedBackup = op.get(); * }

* diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java index 7792ec282f4..3285dde5f5e 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java @@ -32,11 +32,7 @@ import com.google.longrunning.Operation; import com.google.protobuf.Empty; import com.google.protobuf.FieldMask; -import com.google.spanner.admin.database.v1.CopyBackupMetadata; -import com.google.spanner.admin.database.v1.CreateBackupMetadata; -import com.google.spanner.admin.database.v1.CreateDatabaseMetadata; -import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata; -import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; +import com.google.spanner.admin.database.v1.*; import java.util.List; import java.util.UUID; import javax.annotation.Nullable; @@ -185,7 +181,7 @@ public OperationFuture copyBackup( Preconditions.checkNotNull(destinationBackup); final OperationFuture - rawOperationFuture = rpc.copyBackUp(sourceBackupId, destinationBackup); + rawOperationFuture = rpc.copyBackup(sourceBackupId, destinationBackup); return new OperationFutureImpl<>( rawOperationFuture.getPollingFuture(), diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java index b065d871076..3a20c2a3c78 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java @@ -1268,7 +1268,7 @@ public OperationFuture createBackup( } @Override - public OperationFuture copyBackUp( + public OperationFuture copyBackup( BackupId sourceBackupId, final com.google.cloud.spanner.Backup destinationBackup) throws SpannerException { Preconditions.checkNotNull(sourceBackupId); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java index 9d87385ae7a..00382e228f3 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java @@ -221,7 +221,7 @@ OperationFuture createBackup( * source backup. * @return the operation that monitors the backup creation. */ - default OperationFuture copyBackUp( + default OperationFuture copyBackup( BackupId sourceBackupId, com.google.cloud.spanner.Backup destinationBackup) { throw new UnsupportedOperationException("Unimplemented"); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java index 7551653da1f..ea1d3724c41 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java @@ -31,7 +31,6 @@ import com.google.cloud.spanner.encryption.EncryptionInfo; import com.google.rpc.Code; import com.google.rpc.Status; -import java.util.Arrays; import java.util.Collections; import org.junit.Before; import org.junit.Test; @@ -313,7 +312,7 @@ private Backup createBackup() { .setState(com.google.spanner.admin.database.v1.Backup.State.CREATING) .setMaxExpireTime( com.google.protobuf.Timestamp.newBuilder().setSeconds(3000L).setNanos(3000).build()) - .addAllReferencingBackups(Arrays.asList(REFERENCING_BACKUP_NAME)) + .addAllReferencingBackups(Collections.singletonList(REFERENCING_BACKUP_NAME)) .build(); return Backup.fromProto(proto, dbClient); } @@ -331,7 +330,7 @@ private Backup copyBackup() { .setState(com.google.spanner.admin.database.v1.Backup.State.CREATING) .setMaxExpireTime( com.google.protobuf.Timestamp.newBuilder().setSeconds(3000L).setNanos(3000).build()) - .addAllReferencingBackups(Arrays.asList(REFERENCING_BACKUP_NAME)) + .addAllReferencingBackups(Collections.singletonList(REFERENCING_BACKUP_NAME)) .build(); return Backup.fromProto(proto, dbClient); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java index a0c389360dc..56dfd707307 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java @@ -470,7 +470,7 @@ public void copyBackupWithParams() throws Exception { .newBackupBuilder(BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID)) .setExpireTime(t) .build(); - when(rpc.copyBackUp(BackupId.of(PROJECT_ID, INSTANCE_ID, SOURCE_BK), backup)) + when(rpc.copyBackup(BackupId.of(PROJECT_ID, INSTANCE_ID, SOURCE_BK), backup)) .thenReturn(rawOperationFuture); OperationFuture op = client.copyBackup(INSTANCE_ID, SOURCE_BK, BK_ID, t); @@ -498,7 +498,7 @@ public void copyBackupWithBackupObject() throws ExecutionException, InterruptedE .build(); BackupId sourceBackupId = BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID); - when(rpc.copyBackUp(sourceBackupId, requestBackup)).thenReturn(rawOperationFuture); + when(rpc.copyBackup(sourceBackupId, requestBackup)).thenReturn(rawOperationFuture); final OperationFuture op = client.copyBackup(sourceBackupId, requestBackup); @@ -523,7 +523,7 @@ public void copyEncryptedBackup() throws ExecutionException, InterruptedExceptio .setEncryptionConfig(EncryptionConfigs.customerManagedEncryption(KMS_KEY_NAME)) .build(); BackupId sourceBackupId = BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID); - when(rpc.copyBackUp(sourceBackupId, backup)).thenReturn(rawOperationFuture); + when(rpc.copyBackup(sourceBackupId, backup)).thenReturn(rawOperationFuture); final OperationFuture op = client.copyBackup(sourceBackupId, backup); assertThat(op.isDone()).isTrue(); From 8d304dd82093987b03e7a5be35d81d1d7ce48db1 Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Mon, 28 Mar 2022 06:16:23 +0000 Subject: [PATCH 21/21] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20?= =?UTF-8?q?post-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 00209a3ee31..3cc889c220c 100644 --- a/README.md +++ b/README.md @@ -56,13 +56,13 @@ implementation 'com.google.cloud:google-cloud-spanner' If you are using Gradle without BOM, add this to your dependencies ```Groovy -implementation 'com.google.cloud:google-cloud-spanner:6.21.2' +implementation 'com.google.cloud:google-cloud-spanner:6.22.0' ``` If you are using SBT, add this to your dependencies ```Scala -libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.21.2" +libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.22.0" ``` ## Authentication