Skip to content

Commit 4a4de36

Browse files
authored
Merge pull request #1 from asthamohta/cross-region-backup
feat: max expire time and referencing backup
2 parents 0ecbeb7 + fad5c0a commit 4a4de36

File tree

4 files changed

+131
-18
lines changed

4 files changed

+131
-18
lines changed

google-cloud-spanner/clirr-ignored-differences.xml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,29 @@
3535
<className>com/google/cloud/spanner/connection/ConnectionOptions</className>
3636
<method>com.google.cloud.spanner.Dialect getDialect()</method>
3737
</difference>
38+
<difference>
39+
<differenceType>7013</differenceType>
40+
<className>com/google/cloud/spanner/BackupInfo$Builder</className>
41+
<method>com.google.cloud.spanner.BackupInfo$Builder setMaxExpireTime(com.google.cloud.Timestamp)</method>
42+
</difference>
43+
<difference>
44+
<differenceType>7013</differenceType>
45+
<className>com/google/cloud/spanner/BackupInfo$Builder</className>
46+
<method>com.google.cloud.spanner.BackupInfo$Builder setReferencingBackup(com.google.protobuf.ProtocolStringList)</method>
47+
</difference>
48+
<difference>
49+
<differenceType>7012</differenceType>
50+
<className>com/google/cloud/spanner/DatabaseAdminClient</className>
51+
<method>com.google.api.gax.longrunning.OperationFuture copyBackup(java.lang.String, java.lang.String, java.lang.String, com.google.cloud.Timestamp)</method>
52+
</difference>
53+
<difference>
54+
<differenceType>7012</differenceType>
55+
<className>com/google/cloud/spanner/DatabaseAdminClient</className>
56+
<method>com.google.api.gax.longrunning.OperationFuture copyBackup(com.google.cloud.spanner.BackupId, com.google.cloud.spanner.Backup)</method>
57+
</difference>
58+
<difference>
59+
<differenceType>7012</differenceType>
60+
<className>com/google/cloud/spanner/spi/v1/SpannerRpc</className>
61+
<method>com.google.api.gax.longrunning.OperationFuture copyBackUp(com.google.cloud.spanner.BackupId, com.google.cloud.spanner.Backup)</method>
62+
</difference>
3863
</differences>

google-cloud-spanner/src/main/java/com/google/cloud/spanner/Backup.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@ static Backup fromProto(
183183
.setDatabase(DatabaseId.of(proto.getDatabase()))
184184
.setEncryptionInfo(EncryptionInfo.fromProtoOrNull(proto.getEncryptionInfo()))
185185
.setProto(proto)
186+
.setMaxExpireTime(Timestamp.fromProto(proto.getMaxExpireTime()))
187+
.setReferencingBackup(proto.getReferencingBackupsList())
186188
.build();
187189
}
188190

google-cloud-spanner/src/main/java/com/google/cloud/spanner/BackupInfo.java

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.google.cloud.Timestamp;
2121
import com.google.cloud.spanner.encryption.BackupEncryptionConfig;
2222
import com.google.cloud.spanner.encryption.EncryptionInfo;
23+
import com.google.protobuf.ProtocolStringList;
2324
import com.google.spanner.admin.database.v1.Database;
2425
import java.util.Objects;
2526
import javax.annotation.Nullable;
@@ -84,6 +85,20 @@ public abstract static class Builder {
8485

8586
/** Builds the backup from this builder. */
8687
public abstract Backup build();
88+
89+
/**
90+
* Output Only.
91+
*
92+
* <p>Returns the max allowed expiration time of the backup, with microseconds granularity.
93+
*/
94+
protected abstract Builder setMaxExpireTime(Timestamp maxExpireTime);
95+
96+
/**
97+
* Output Only.
98+
*
99+
* <p>Returns the names of the destination backups being created by copying this source backup.
100+
*/
101+
protected abstract Builder setReferencingBackup(ProtocolStringList referencingBackup);
87102
}
88103

89104
abstract static class BuilderImpl extends Builder {
@@ -96,6 +111,8 @@ abstract static class BuilderImpl extends Builder {
96111
private BackupEncryptionConfig encryptionConfig;
97112
private EncryptionInfo encryptionInfo;
98113
private com.google.spanner.admin.database.v1.Backup proto;
114+
private Timestamp maxExpireTime;
115+
private ProtocolStringList referencingBackup;
99116

100117
BuilderImpl(BackupId id) {
101118
this.id = Preconditions.checkNotNull(id);
@@ -111,6 +128,8 @@ abstract static class BuilderImpl extends Builder {
111128
this.encryptionConfig = other.encryptionConfig;
112129
this.encryptionInfo = other.encryptionInfo;
113130
this.proto = other.proto;
131+
this.maxExpireTime = other.maxExpireTime;
132+
this.referencingBackup = other.referencingBackup;
114133
}
115134

116135
@Override
@@ -163,6 +182,18 @@ Builder setProto(@Nullable com.google.spanner.admin.database.v1.Backup proto) {
163182
this.proto = proto;
164183
return this;
165184
}
185+
186+
@Override
187+
public Builder setMaxExpireTime(Timestamp maxExpireTime) {
188+
this.maxExpireTime = Preconditions.checkNotNull(maxExpireTime);
189+
return this;
190+
}
191+
192+
@Override
193+
public Builder setReferencingBackup(ProtocolStringList referencingBackup) {
194+
this.referencingBackup = Preconditions.checkNotNull(referencingBackup);
195+
return this;
196+
}
166197
}
167198

168199
/** State of the backup. */
@@ -184,6 +215,8 @@ public enum State {
184215
private final BackupEncryptionConfig encryptionConfig;
185216
private final EncryptionInfo encryptionInfo;
186217
private final com.google.spanner.admin.database.v1.Backup proto;
218+
private final Timestamp maxExpireTime;
219+
private final ProtocolStringList referencingBackup;
187220

188221
BackupInfo(BuilderImpl builder) {
189222
this.id = builder.id;
@@ -195,6 +228,8 @@ public enum State {
195228
this.versionTime = builder.versionTime;
196229
this.database = builder.database;
197230
this.proto = builder.proto;
231+
this.maxExpireTime = builder.maxExpireTime;
232+
this.referencingBackup = builder.referencingBackup;
198233
}
199234

200235
/** Returns the backup id. */
@@ -253,6 +288,19 @@ public DatabaseId getDatabase() {
253288
return proto;
254289
}
255290

291+
/** Returns the max expire time of this {@link Backup}. */
292+
public Timestamp getMaxExpireTime() {
293+
return maxExpireTime;
294+
}
295+
296+
/**
297+
* Returns the names of the destination backups being created by copying this source backup {@link
298+
* Backup}.
299+
*/
300+
public ProtocolStringList getReferencingBackup() {
301+
return referencingBackup;
302+
}
303+
256304
@Override
257305
public boolean equals(Object o) {
258306
if (this == o) {
@@ -269,26 +317,39 @@ public boolean equals(Object o) {
269317
&& Objects.equals(encryptionInfo, that.encryptionInfo)
270318
&& Objects.equals(expireTime, that.expireTime)
271319
&& Objects.equals(versionTime, that.versionTime)
272-
&& Objects.equals(database, that.database);
320+
&& Objects.equals(database, that.database)
321+
&& Objects.equals(maxExpireTime, that.maxExpireTime)
322+
&& Objects.equals(referencingBackup, that.referencingBackup);
273323
}
274324

275325
@Override
276326
public int hashCode() {
277327
return Objects.hash(
278-
id, state, size, encryptionConfig, encryptionInfo, expireTime, versionTime, database);
328+
id,
329+
state,
330+
size,
331+
encryptionConfig,
332+
encryptionInfo,
333+
expireTime,
334+
versionTime,
335+
database,
336+
maxExpireTime,
337+
referencingBackup);
279338
}
280339

281340
@Override
282341
public String toString() {
283342
return String.format(
284-
"Backup[%s, %s, %d, %s, %s, %s, %s, %s]",
343+
"Backup[%s, %s, %d, %s, %s, %s, %s, %s, %s, %s]",
285344
id.getName(),
286345
state,
287346
size,
288347
encryptionConfig,
289348
encryptionInfo,
290349
expireTime,
291350
versionTime,
292-
database);
351+
database,
352+
maxExpireTime,
353+
referencingBackup);
293354
}
294355
}

samples/snippets/src/main/java/com/example/spanner/SpannerSample.java

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1661,21 +1661,17 @@ static void cancelCreateBackup(
16611661
// [END spanner_cancel_backup_create]
16621662

16631663
// [START spanner_list_backup_operations]
1664-
static void listBackupOperations(InstanceAdminClient instanceAdminClient, DatabaseId databaseId) {
1664+
static void listBackupOperations(InstanceAdminClient instanceAdminClient, DatabaseId databaseId, BackupId backupId) {
16651665
Instance instance = instanceAdminClient.getInstance(databaseId.getInstanceId().getInstance());
16661666
// Get create backup operations for the sample database.
1667-
Timestamp last24Hours = Timestamp.ofTimeSecondsAndNanos(TimeUnit.SECONDS.convert(
1668-
TimeUnit.HOURS.convert(Timestamp.now().getSeconds(), TimeUnit.SECONDS) - 24,
1669-
TimeUnit.HOURS), 0);
16701667
String filter =
16711668
String.format(
1672-
"(metadata.database:%s) AND "
1673-
+ "(metadata.@type:type.googleapis.com/"
1674-
+ "google.spanner.admin.database.v1.CreateBackupMetadata) AND "
1675-
+ "(metadata.progress.start_time > \"%s\")",
1676-
databaseId.getName(), last24Hours);
1677-
Page<Operation> operations = instance.listBackupOperations(Options.filter(filter));
1678-
for (Operation op : operations.iterateAll()) {
1669+
"(metadata.@type:type.googleapis.com/google.spanner.admin.database.v1.CreateBackupMetadata) "
1670+
+ "AND (metadata.database:%s)",
1671+
databaseId.getName());
1672+
Page<Operation> createBackupOperations = instance.listBackupOperations(Options.filter(filter));
1673+
System.out.println("Create Backup Operations:");
1674+
for (Operation op : createBackupOperations.iterateAll()) {
16791675
try {
16801676
CreateBackupMetadata metadata = op.getMetadata().unpack(CreateBackupMetadata.class);
16811677
System.out.println(
@@ -1689,6 +1685,30 @@ static void listBackupOperations(InstanceAdminClient instanceAdminClient, Databa
16891685
System.err.println(e.getMessage());
16901686
}
16911687
}
1688+
1689+
// Get copy backup operations for the sample database.
1690+
filter =
1691+
String.format(
1692+
"(metadata.@type:type.googleapis.com/"
1693+
+ "google.spanner.admin.database.v1.CopyBackupMetadata) "
1694+
+ "AND (metadata.source_backup:%s)",
1695+
backupId.getName());
1696+
Page<Operation> copyBackupOperations = instance.listBackupOperations(Options.filter(filter));
1697+
System.out.println("Copy Backup Operations:");
1698+
for (Operation op : copyBackupOperations.iterateAll()) {
1699+
try {
1700+
CopyBackupMetadata copyBackupMetadata = op.getMetadata().unpack(CopyBackupMetadata.class);
1701+
System.out.println(
1702+
String.format(
1703+
"Copy Backup %s on backup %s pending: %d%% complete",
1704+
copyBackupMetadata.getName(),
1705+
copyBackupMetadata.getSourceBackup(),
1706+
copyBackupMetadata.getProgress().getProgressPercent()));
1707+
} catch (InvalidProtocolBufferException e) {
1708+
// The returned operation does not contain CopyBackupMetadata.
1709+
System.err.println(e.getMessage());
1710+
}
1711+
}
16921712
}
16931713
// [END spanner_list_backup_operations]
16941714

@@ -1842,6 +1862,8 @@ static void updateBackup(DatabaseAdminClient dbAdminClient, BackupId backupId) {
18421862
TimeUnit.SECONDS.toMicros(backup.getExpireTime().getSeconds())
18431863
+ TimeUnit.NANOSECONDS.toMicros(backup.getExpireTime().getNanos())
18441864
+ TimeUnit.DAYS.toMicros(30L));
1865+
// New Expire Time must be less than Max Expire Time
1866+
expireTime = expireTime.compareTo(backup.getMaxExpireTime())<0?expireTime:backup.getMaxExpireTime();
18451867
int timeDiff = expireTime.compareTo(backup.getExpireTime());
18461868
Timestamp newExpireTime = (timeDiff < 0) ? expireTime : backup.getExpireTime();
18471869

@@ -2053,7 +2075,7 @@ static void run(
20532075
BackupId.of(backup.getInstanceId(), backup.getBackup() + "_cancel"));
20542076
break;
20552077
case "listbackupoperations":
2056-
listBackupOperations(instanceAdminClient, database);
2078+
listBackupOperations(instanceAdminClient, database, backup);
20572079
break;
20582080
case "listdatabaseoperations":
20592081
listDatabaseOperations(instanceAdminClient, dbAdminClient, database.getInstanceId());
@@ -2149,14 +2171,14 @@ static void printUsageAndExit() {
21492171
System.err.println(" SpannerExample querywithqueryoptions my-instance example-db");
21502172
System.err.println(" SpannerExample createbackup my-instance example-db");
21512173
System.err.println(" SpannerExample listbackups my-instance example-db");
2152-
System.err.println(" SpannerExample listbackupoperations my-instance example-db");
2174+
System.err.println(" SpannerExample listbackupoperations my-instance example-db backup-id");
21532175
System.err.println(" SpannerExample listdatabaseoperations my-instance example-db");
21542176
System.err.println(" SpannerExample restorebackup my-instance example-db");
21552177
System.exit(1);
21562178
}
21572179

21582180
public static void main(String[] args) throws Exception {
2159-
if (args.length != 3) {
2181+
if (args.length != 3 && args.length != 4) {
21602182
printUsageAndExit();
21612183
}
21622184
// [START init_client]
@@ -2180,6 +2202,9 @@ public static void main(String[] args) throws Exception {
21802202
String.format(
21812203
"%s_%02d",
21822204
db.getDatabase(), LocalDate.now().get(ChronoField.ALIGNED_WEEK_OF_YEAR));
2205+
if( args.length == 4) {
2206+
backupName = args[3];
2207+
}
21832208
BackupId backup = BackupId.of(db.getInstanceId(), backupName);
21842209

21852210
// [START init_client]

0 commit comments

Comments
 (0)