Skip to content

Commit f7afd50

Browse files
authored
feat: managed backups implementation (#2643)
* feat: managed backups * Revert "chore(cleanup): Marking snapshot operations as unsupported (#2467)" This reverts commit 4494e7a for tests * cherry pick remaining files in #2592 * fix deps build * cleanup * formatting * fix test * refactor and update tests * cleanup unused api * fix test * formatting * review feedback * add create backup test * clean up deps, remove client core dep in hbase-1x * test update * cleanup * cleanup
1 parent c5da82f commit f7afd50

File tree

33 files changed

+1946
-317
lines changed

33 files changed

+1946
-317
lines changed

bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableClusterName.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,15 +79,15 @@ public String getClusterId() {
7979
}
8080

8181
/**
82-
* Create a fully qualified snapshot name based on the the clusterName and the snapshotId.
83-
* Snapshot name will look like:
84-
* "projects/{projectId}/instances/{instanceId}/clusters/{clusterId}/snapshots/{snapshotId}".
82+
* Create a fully qualified backup name based on the the clusterName and the backupId. Backup name
83+
* will look like:
84+
* "projects/{projectId}/instances/{instanceId}/clusters/{clusterId}/backups/{backupId}".
8585
*
86-
* @param snapshotId The id of the snapshot
87-
* @return A fully qualified snapshot name that contains the fully qualified cluster name as the
88-
* parent and the snapshot name as the child.
86+
* @param backupId The id of the backup
87+
* @return A fully qualified backup name that contains the fully qualified cluster name as the
88+
* parent and the backup name as the child.
8989
*/
90-
public String toSnapshotName(String snapshotId) {
91-
return clusterName + "/snapshots/" + snapshotId;
90+
public String toBackupName(String backupId) {
91+
return clusterName + "/backups/" + backupId;
9292
}
9393
}

bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableInstanceGrpcClient.java

Lines changed: 6 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
*/
1616
package com.google.cloud.bigtable.grpc;
1717

18-
import com.google.api.client.util.BackOff;
19-
import com.google.api.client.util.ExponentialBackOff;
2018
import com.google.api.core.InternalApi;
2119
import com.google.bigtable.admin.v2.AppProfile;
2220
import com.google.bigtable.admin.v2.BigtableInstanceAdminGrpc;
@@ -38,7 +36,7 @@
3836
import com.google.bigtable.admin.v2.ListInstancesResponse;
3937
import com.google.bigtable.admin.v2.PartialUpdateInstanceRequest;
4038
import com.google.bigtable.admin.v2.UpdateAppProfileRequest;
41-
import com.google.common.primitives.Ints;
39+
import com.google.cloud.bigtable.util.OperationUtil;
4240
import com.google.iam.v1.GetIamPolicyRequest;
4341
import com.google.iam.v1.Policy;
4442
import com.google.iam.v1.SetIamPolicyRequest;
@@ -49,7 +47,6 @@
4947
import com.google.longrunning.OperationsGrpc;
5048
import com.google.protobuf.Empty;
5149
import io.grpc.Channel;
52-
import io.grpc.protobuf.StatusProto;
5350
import java.io.IOException;
5451
import java.util.concurrent.TimeUnit;
5552
import java.util.concurrent.TimeoutException;
@@ -63,7 +60,7 @@
6360
public class BigtableInstanceGrpcClient implements BigtableInstanceClient {
6461

6562
private final BigtableInstanceAdminGrpc.BigtableInstanceAdminBlockingStub instanceClient;
66-
private final OperationsGrpc.OperationsBlockingStub operationsStub;
63+
private final OperationUtil operationUtil;
6764

6865
/**
6966
* Constructor for BigtableInstanceGrpcClient.
@@ -72,7 +69,7 @@ public class BigtableInstanceGrpcClient implements BigtableInstanceClient {
7269
*/
7370
public BigtableInstanceGrpcClient(Channel channel) {
7471
this.instanceClient = BigtableInstanceAdminGrpc.newBlockingStub(channel);
75-
operationsStub = OperationsGrpc.newBlockingStub(channel);
72+
operationUtil = new OperationUtil(OperationsGrpc.newBlockingStub(channel));
7673
}
7774

7875
/** {@inheritDoc} */
@@ -84,65 +81,20 @@ public Operation createInstance(CreateInstanceRequest request) {
8481
/** {@inheritDoc} */
8582
@Override
8683
public Operation getOperation(GetOperationRequest request) {
87-
return operationsStub.getOperation(request);
84+
return operationUtil.getOperation(request);
8885
}
8986

9087
/** {@inheritDoc} */
9188
@Override
9289
public void waitForOperation(Operation operation) throws IOException, TimeoutException {
93-
waitForOperation(operation, 10, TimeUnit.MINUTES);
90+
operationUtil.waitForOperation(operation, 10, TimeUnit.MINUTES);
9491
}
9592

9693
/** {@inheritDoc} */
9794
@Override
9895
public void waitForOperation(Operation operation, long timeout, TimeUnit timeUnit)
9996
throws TimeoutException, IOException {
100-
GetOperationRequest request =
101-
GetOperationRequest.newBuilder().setName(operation.getName()).build();
102-
103-
ExponentialBackOff backOff =
104-
new ExponentialBackOff.Builder()
105-
.setInitialIntervalMillis(100)
106-
.setMultiplier(1.3)
107-
.setMaxIntervalMillis(Ints.checkedCast(TimeUnit.SECONDS.toMillis(60)))
108-
.setMaxElapsedTimeMillis(Ints.checkedCast(timeUnit.toMillis(timeout)))
109-
.build();
110-
111-
Operation currentOperationState = operation;
112-
113-
while (true) {
114-
if (currentOperationState.getDone()) {
115-
switch (currentOperationState.getResultCase()) {
116-
case RESPONSE:
117-
return;
118-
case ERROR:
119-
throw StatusProto.toStatusRuntimeException(currentOperationState.getError());
120-
case RESULT_NOT_SET:
121-
throw new IllegalStateException(
122-
"System returned invalid response for Operation check: " + currentOperationState);
123-
}
124-
}
125-
126-
final long backOffMillis;
127-
try {
128-
backOffMillis = backOff.nextBackOffMillis();
129-
} catch (IOException e) {
130-
// Should never happen.
131-
throw new RuntimeException(e);
132-
}
133-
if (backOffMillis == BackOff.STOP) {
134-
throw new TimeoutException("Operation did not complete in time");
135-
} else {
136-
try {
137-
Thread.sleep(backOffMillis);
138-
} catch (InterruptedException e) {
139-
Thread.currentThread().interrupt();
140-
throw new IOException("Interrupted while waiting for operation to finish");
141-
}
142-
}
143-
144-
currentOperationState = getOperation(request);
145-
}
97+
operationUtil.waitForOperation(operation, timeout, timeUnit);
14698
}
14799

148100
/** {@inheritDoc} */

bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableSessionSharedThreadPools.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ public static BigtableSessionSharedThreadPools getInstance() {
5858
/**
5959
* Getter for the field <code>batchThreadPool</code>.
6060
*
61+
* <p>This needs to be a cached thread pool because long running operations could tie up the
62+
* thread pool indefinitely
63+
*
6164
* @return a {@link java.util.concurrent.ExecutorService} object.
6265
*/
6366
public synchronized ExecutorService getBatchThreadPool() {

bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableTableAdminClient.java

Lines changed: 71 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,31 @@
1616
package com.google.cloud.bigtable.grpc;
1717

1818
import com.google.api.core.InternalExtensionOnly;
19-
import com.google.bigtable.admin.v2.CreateTableFromSnapshotRequest;
19+
import com.google.bigtable.admin.v2.CreateBackupRequest;
2020
import com.google.bigtable.admin.v2.CreateTableRequest;
21-
import com.google.bigtable.admin.v2.DeleteSnapshotRequest;
21+
import com.google.bigtable.admin.v2.DeleteBackupRequest;
2222
import com.google.bigtable.admin.v2.DeleteTableRequest;
2323
import com.google.bigtable.admin.v2.DropRowRangeRequest;
24-
import com.google.bigtable.admin.v2.GetSnapshotRequest;
24+
import com.google.bigtable.admin.v2.GetBackupRequest;
2525
import com.google.bigtable.admin.v2.GetTableRequest;
26-
import com.google.bigtable.admin.v2.ListSnapshotsRequest;
27-
import com.google.bigtable.admin.v2.ListSnapshotsResponse;
26+
import com.google.bigtable.admin.v2.ListBackupsRequest;
27+
import com.google.bigtable.admin.v2.ListBackupsResponse;
2828
import com.google.bigtable.admin.v2.ListTablesRequest;
2929
import com.google.bigtable.admin.v2.ListTablesResponse;
3030
import com.google.bigtable.admin.v2.ModifyColumnFamiliesRequest;
31-
import com.google.bigtable.admin.v2.Snapshot;
32-
import com.google.bigtable.admin.v2.SnapshotTableRequest;
31+
import com.google.bigtable.admin.v2.RestoreTableRequest;
3332
import com.google.bigtable.admin.v2.Table;
3433
import com.google.common.util.concurrent.ListenableFuture;
3534
import com.google.iam.v1.GetIamPolicyRequest;
3635
import com.google.iam.v1.Policy;
3736
import com.google.iam.v1.SetIamPolicyRequest;
3837
import com.google.iam.v1.TestIamPermissionsRequest;
3938
import com.google.iam.v1.TestIamPermissionsResponse;
39+
import com.google.longrunning.GetOperationRequest;
4040
import com.google.longrunning.Operation;
4141
import com.google.protobuf.Empty;
42+
import java.io.IOException;
43+
import java.util.concurrent.TimeUnit;
4244
import java.util.concurrent.TimeoutException;
4345

4446
/** A client for the Cloud Bigtable Table Admin API. */
@@ -183,24 +185,70 @@ void waitForReplication(BigtableTableName tableName, long timeout)
183185
*/
184186
TestIamPermissionsResponse testIamPermissions(TestIamPermissionsRequest request);
185187

186-
// ////////////// SNAPSHOT methods /////////////
187-
/** @deprecated Snapshots will be removed in the future */
188-
@Deprecated
189-
ListenableFuture<Operation> snapshotTableAsync(SnapshotTableRequest request);
188+
/**
189+
* Creates a new backup from a table in a specific cluster.
190+
*
191+
* @param request a {@link com.google.bigtable.admin.v2.CreateBackupRequest} object.
192+
* @return The long running {@link Operation} for the request.
193+
*/
194+
ListenableFuture<Operation> createBackupAsync(
195+
com.google.bigtable.admin.v2.CreateBackupRequest request);
196+
197+
/**
198+
* Lists all backups associated with the specified cluster.
199+
*
200+
* @param request a {@link GetBackupRequest} object.
201+
* @return The {@link ListBackupsResponse} which has the list of the backups in the cluster.
202+
*/
203+
ListenableFuture<ListBackupsResponse> listBackupsAsync(ListBackupsRequest request);
204+
205+
/**
206+
* Permanently deletes the specified backup.
207+
*
208+
* @param request a {@link DeleteBackupRequest} object.
209+
*/
210+
ListenableFuture<Empty> deleteBackupAsync(DeleteBackupRequest request);
190211

191-
/** @deprecated Snapshots will be removed in the future */
192-
@Deprecated
193-
ListenableFuture<Snapshot> getSnapshotAsync(GetSnapshotRequest request);
212+
/**
213+
* Creates a new table from a backup.
214+
*
215+
* @param request a {@link com.google.bigtable.admin.v2.RestoreTableRequest} object.
216+
* @return The long running {@link Operation} for the request.
217+
*/
218+
ListenableFuture<Operation> restoreTableAsync(
219+
com.google.bigtable.admin.v2.RestoreTableRequest request);
194220

195-
/** @deprecated Snapshots will be removed in the future */
196-
@Deprecated
197-
ListenableFuture<ListSnapshotsResponse> listSnapshotsAsync(ListSnapshotsRequest request);
221+
/**
222+
* Gets the latest state of a long-running operation. Clients may use this method to poll the
223+
* operation result at intervals as recommended by the API service.
224+
*
225+
* <p>{@link #createBackupAsync(CreateBackupRequest)} and {@link
226+
* #restoreTableAsync(RestoreTableRequest)} will return a {@link
227+
* com.google.longrunning.Operation}. Use this method and pass in the {@link
228+
* com.google.longrunning.Operation}'s name in the request to see if the Operation is done via
229+
* {@link com.google.longrunning.Operation#getDone()}. The backup will not be available until that
230+
* happens.
231+
*
232+
* @param request a {@link com.google.longrunning.GetOperationRequest} object.
233+
* @return a {@link com.google.longrunning.Operation} object.
234+
*/
235+
Operation getOperation(GetOperationRequest request);
198236

199-
/** @deprecated Snapshots will be removed in the future */
200-
@Deprecated
201-
ListenableFuture<Empty> deleteSnapshotAsync(DeleteSnapshotRequest request);
237+
/**
238+
* Waits for the long running operation to complete by polling with exponential backoff. A default
239+
* timeout of 10 minutes is used.
240+
*
241+
* @throws IOException
242+
* @throws TimeoutException If the timeout is exceeded.
243+
*/
244+
Operation waitForOperation(Operation operation) throws TimeoutException, IOException;
202245

203-
/** @deprecated Snapshots will be removed in the future */
204-
@Deprecated
205-
ListenableFuture<Operation> createTableFromSnapshotAsync(CreateTableFromSnapshotRequest request);
246+
/**
247+
* Waits for the long running operation to complete by polling with exponential backoff.
248+
*
249+
* @throws IOException
250+
* @throws TimeoutException If the timeout is exceeded.
251+
*/
252+
Operation waitForOperation(Operation operation, long timeout, TimeUnit timeUnit)
253+
throws IOException, TimeoutException;
206254
}

0 commit comments

Comments
 (0)