-
Notifications
You must be signed in to change notification settings - Fork 132
feat: Copy backup samples #1802
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
cbc0e65
ede01f2
1e983da
44ff9d1
1c76896
b02cdf1
50f18da
8917d66
bb39c9f
a3139b0
885c9a6
0920a95
3c14217
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/* | ||
* 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 { | ||
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<Backup, CopyBackupMetadata> operation = | ||
databaseAdminClient.copyBackup( | ||
BackupId.of(projectId, instanceId, sourceBackupId), destinationBackup); | ||
try { | ||
// Wait for the backup operation to complete. | ||
destinationBackup = operation.get(); | ||
System.out.println("Copied backup [" + destinationBackup.getId() + "]"); | ||
} catch (ExecutionException e) { | ||
throw (SpannerException) e.getCause(); | ||
asthamohta marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} catch (InterruptedException e) { | ||
throw SpannerExceptionFactory.propagateInterrupt(e); | ||
} | ||
// Load the metadata of the new 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; | ||
} | ||
} | ||
// [END spanner_copy_backup] |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; | ||
|
@@ -1659,21 +1660,23 @@ static void cancelCreateBackup( | |
// [END spanner_cancel_backup_create] | ||
|
||
// [START spanner_list_backup_operations] | ||
static void listBackupOperations(InstanceAdminClient instanceAdminClient, DatabaseId databaseId) { | ||
static void listBackupOperations( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't this a breaking change? Maybe customers won't care because it is in the sample , but I don't know what the policy is here. Yoshi team might know There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @olavloite pointed out that this is a non public method and hence can't be called so this will not be a breaking change There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is true, but we publish these samples in our public documentation, so we would be changing the signature. Anyway, if your team is ok with this, I am ok. |
||
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<Operation> 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<Operation> 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( | ||
|
@@ -1687,6 +1690,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<Operation> 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] | ||
|
||
|
@@ -1840,13 +1867,19 @@ 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(), | ||
LocalDateTime.ofEpochSecond( | ||
expireTime.getSeconds(), | ||
expireTime.getNanos(), | ||
OffsetDateTime.now().getOffset()).toString())); | ||
expireTime.getSeconds(), | ||
expireTime.getNanos(), | ||
OffsetDateTime.now().getOffset()).toString())); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. super nit: the |
||
|
||
// Update expire time. | ||
backup = backup.toBuilder().setExpireTime(expireTime).build(); | ||
|
@@ -2048,7 +2081,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()); | ||
|
@@ -2144,14 +2177,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] | ||
|
@@ -2176,6 +2209,9 @@ public static void main(String[] args) throws Exception { | |
"%s_%02d", | ||
db.getDatabase(), LocalDate.now().get(ChronoField.ALIGNED_WEEK_OF_YEAR)); | ||
BackupId backup = BackupId.of(db.getInstanceId(), backupName); | ||
if (args.length == 4) { | ||
backupName = args[3]; | ||
} | ||
|
||
// [START init_client] | ||
DatabaseClient dbClient = spanner.getDatabaseClient(db); | ||
|
Uh oh!
There was an error while loading. Please reload this page.