Skip to content
Permalink
Browse files
feat: Cloud Bigtable Managed Backup Implementation (#305)
  • Loading branch information
liubonan committed Jul 20, 2020
1 parent 195f36b commit 9e3307a4872d3bae3c04e7857a9eb4859151965e
Showing with 2,171 additions and 0 deletions.
  1. +421 −0 google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClient.java
  2. +15 −0 google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/internal/NameUtil.java
  3. +161 −0 google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/Backup.java
  4. +93 −0 ...e-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/CreateBackupRequest.java
  5. +42 −0 .../src/main/java/com/google/cloud/bigtable/admin/v2/models/OptimizeRestoredTableOperationToken.java
  6. +79 −0 ...e-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/RestoreTableRequest.java
  7. +53 −0 ...e-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/RestoredTableResult.java
  8. +91 −0 ...e-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/UpdateBackupRequest.java
  9. +117 −0 ...igtable/src/main/java/com/google/cloud/bigtable/admin/v2/stub/EnhancedBigtableTableAdminStub.java
  10. +322 −0 ...cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientTest.java
  11. +48 −0 google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/internal/NameUtilTest.java
  12. +358 −0 google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/it/BigtableBackupIT.java
  13. +122 −0 google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/models/BackupTest.java
  14. +100 −0 ...oud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/models/CreateBackupRequestTest.java
  15. +69 −0 ...oud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/models/RestoreTableRequestTest.java
  16. +80 −0 ...oud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/models/UpdateBackupRequestTest.java

Large diffs are not rendered by default.

@@ -31,6 +31,8 @@ public class NameUtil {
Pattern.compile("projects/([^/]+)/instances/([^/]+)/tables/([^/]+)");
private static final Pattern LOCATION_PATTERN =
Pattern.compile("projects/([^/]+)/locations/([^/]+)");
private static final Pattern BACKUP_PATTERN =
Pattern.compile("projects/([^/]+)/instances/([^/]+)/clusters/([^/]+)/backups/([^/]+)");

public static String formatProjectName(String projectId) {
return "projects/" + projectId;
@@ -48,6 +50,11 @@ public static String formatLocationName(String projectId, String zone) {
return formatProjectName(projectId) + "/locations/" + zone;
}

public static String formatBackupName(
String projectId, String instanceId, String clusterId, String backupId) {
return formatClusterName(projectId, instanceId, clusterId) + "/backups/" + backupId;
}

public static String extractTableIdFromTableName(String fullTableName) {
Matcher matcher = TABLE_PATTERN.matcher(fullTableName);
if (!matcher.matches()) {
@@ -56,6 +63,14 @@ public static String extractTableIdFromTableName(String fullTableName) {
return matcher.group(3);
}

public static String extractBackupIdFromBackupName(String fullBackupName) {
Matcher matcher = BACKUP_PATTERN.matcher(fullBackupName);
if (!matcher.matches()) {
throw new IllegalArgumentException("Invalid backup name: " + fullBackupName);
}
return matcher.group(4);
}

public static String extractZoneIdFromLocationName(String fullLocationName) {
Matcher matcher = LOCATION_PATTERN.matcher(fullLocationName);
if (!matcher.matches()) {
@@ -0,0 +1,161 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://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.google.cloud.bigtable.admin.v2.models;

import com.google.api.core.InternalApi;
import com.google.bigtable.admin.v2.BackupName;
import com.google.cloud.bigtable.admin.v2.internal.NameUtil;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.protobuf.util.Timestamps;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.threeten.bp.Instant;

/**
* A backup lets you save a copy of a table's schema and data and restore the backup to a new table
* at a later time.
*/
public class Backup {
public enum State {
/** Not specified. */
STATE_UNSPECIFIED(com.google.bigtable.admin.v2.Backup.State.STATE_UNSPECIFIED),

/**
* The pending backup is still being created. Operations on the backup may fail with
* `FAILED_PRECONDITION` in this state.
*/
CREATING(com.google.bigtable.admin.v2.Backup.State.CREATING),
/** The backup is complete and ready for use. */
READY(com.google.bigtable.admin.v2.Backup.State.READY),

/** The state of the backup is not known by this client. Please upgrade your client. */
UNRECOGNIZED(com.google.bigtable.admin.v2.Backup.State.UNRECOGNIZED);

private final com.google.bigtable.admin.v2.Backup.State proto;

State(com.google.bigtable.admin.v2.Backup.State proto) {
this.proto = proto;
}

/**
* Wraps the protobuf. This method is considered an internal implementation detail and not meant
* to be used by applications.
*/
@InternalApi
public static Backup.State fromProto(com.google.bigtable.admin.v2.Backup.State proto) {
for (Backup.State state : values()) {
if (state.proto.equals(proto)) {
return state;
}
}
return STATE_UNSPECIFIED;
}

/**
* Creates the request protobuf. This method is considered an internal implementation detail and
* not meant to be used by applications.
*/
@InternalApi
public com.google.bigtable.admin.v2.Backup.State toProto() {
return proto;
}
}

@Nonnull private final com.google.bigtable.admin.v2.Backup proto;
@Nonnull private final String id;
@Nonnull private final String instanceId;

@InternalApi
public static Backup fromProto(@Nonnull com.google.bigtable.admin.v2.Backup proto) {
return new Backup(proto);
}

private Backup(@Nonnull com.google.bigtable.admin.v2.Backup proto) {
Preconditions.checkNotNull(proto);
Preconditions.checkArgument(!proto.getName().isEmpty(), "Name must be set");
Preconditions.checkArgument(!proto.getSourceTable().isEmpty(), "Source table must be set");

BackupName name = BackupName.parse(proto.getName());
this.id = name.getBackup();
this.instanceId = name.getInstance();
this.proto = proto;
}

/** Get the ID of this backup. */
public String getId() {
return id;
}

/** Get the source table ID from which the backup is created. */
public String getSourceTableId() {
return NameUtil.extractTableIdFromTableName(proto.getSourceTable());
}

/** Get the instance ID where this backup is located. */
public String getInstanceId() {
return instanceId;
}

/** Get the expire time of this backup. */
public Instant getExpireTime() {
return Instant.ofEpochMilli(Timestamps.toMillis(proto.getExpireTime()));
}

/** Get the start time when this backup is taken. */
public @Nullable Instant getStartTime() {
if (proto.hasStartTime()) {
return Instant.ofEpochMilli(Timestamps.toMillis(proto.getStartTime()));
}
return null;
}

/** Get the end time when the creation of this backup has completed. */
public @Nullable Instant getEndTime() {
if (proto.hasEndTime()) {
return Instant.ofEpochMilli(Timestamps.toMillis(proto.getEndTime()));
}
return null;
}

/** Get the size of this backup. */
public long getSizeBytes() {
return proto.getSizeBytes();
}

/** Get the state of this backup. */
public State getState() {
return State.fromProto(proto.getState());
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Backup backup = (Backup) o;
return Objects.equal(proto, backup.proto);
}

@Override
public int hashCode() {
return Objects.hashCode(proto);
}
}
@@ -0,0 +1,93 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://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.google.cloud.bigtable.admin.v2.models;

import com.google.api.core.InternalApi;
import com.google.cloud.bigtable.admin.v2.internal.NameUtil;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.protobuf.util.Timestamps;
import javax.annotation.Nonnull;
import org.threeten.bp.Instant;

/** Fluent wrapper for {@link com.google.bigtable.admin.v2.CreateBackupRequest} */
public final class CreateBackupRequest {
private final com.google.bigtable.admin.v2.CreateBackupRequest.Builder requestBuilder =
com.google.bigtable.admin.v2.CreateBackupRequest.newBuilder();
private final String clusterId;
private String sourceTableId;

public static CreateBackupRequest of(String clusterId, String backupId) {
CreateBackupRequest request = new CreateBackupRequest(clusterId, backupId);
return request;
}

private CreateBackupRequest(String clusterId, String backupId) {
Preconditions.checkNotNull(clusterId);
Preconditions.checkNotNull(backupId);

requestBuilder.setBackupId(backupId);
this.clusterId = clusterId;
this.sourceTableId = null;
}

public CreateBackupRequest setSourceTableId(String sourceTableId) {
Preconditions.checkNotNull(sourceTableId);
this.sourceTableId = sourceTableId;
return this;
}

public CreateBackupRequest setExpireTime(Instant expireTime) {
Preconditions.checkNotNull(expireTime);
requestBuilder
.getBackupBuilder()
.setExpireTime(Timestamps.fromMillis(expireTime.toEpochMilli()));
return this;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
CreateBackupRequest that = (CreateBackupRequest) o;
return Objects.equal(requestBuilder.getBackupId(), that.requestBuilder.getBackupId())
&& Objects.equal(clusterId, that.clusterId)
&& Objects.equal(sourceTableId, that.sourceTableId);
}

@Override
public int hashCode() {
return Objects.hashCode(requestBuilder.getBackupId(), clusterId, sourceTableId);
}

@InternalApi
public com.google.bigtable.admin.v2.CreateBackupRequest toProto(
@Nonnull String projectId, @Nonnull String instanceId) {
Preconditions.checkNotNull(projectId);
Preconditions.checkNotNull(instanceId);

requestBuilder
.getBackupBuilder()
.setSourceTable(NameUtil.formatTableName(projectId, instanceId, sourceTableId));
return requestBuilder
.setParent(NameUtil.formatClusterName(projectId, instanceId, clusterId))
.build();
}
}
@@ -0,0 +1,42 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://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.google.cloud.bigtable.admin.v2.models;

import com.google.api.core.InternalApi;
import com.google.common.base.Preconditions;

/**
* OptimizeRestoredTableOperationToken is a wrapper for the name of OptimizeRestoredTable operation.
*/
public class OptimizeRestoredTableOperationToken {
private final String operationName;

@InternalApi
public static OptimizeRestoredTableOperationToken of(String operationName) {
return new OptimizeRestoredTableOperationToken(operationName);
}

private OptimizeRestoredTableOperationToken(String operationName) {
Preconditions.checkNotNull(operationName);
Preconditions.checkState(!operationName.isEmpty());
this.operationName = operationName;
}

@InternalApi
public String getOperationName() {
return operationName;
}
}

0 comments on commit 9e3307a

Please sign in to comment.