Skip to content

Commit

Permalink
Polish instance crudl
Browse files Browse the repository at this point in the history
  • Loading branch information
igorbernstein2 committed Aug 17, 2018
1 parent 21bb3fa commit db81392
Show file tree
Hide file tree
Showing 10 changed files with 809 additions and 86 deletions.
6 changes: 6 additions & 0 deletions google-cloud-clients/google-cloud-bigtable-admin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.api</groupId>
<artifactId>gax</artifactId>
<classifier>testlib</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,14 @@
import com.google.bigtable.admin.v2.ProjectName;
import com.google.cloud.bigtable.admin.v2.models.CreateInstanceRequest;
import com.google.cloud.bigtable.admin.v2.models.Instance;
import com.google.cloud.bigtable.admin.v2.models.PartialListInstancesException;
import com.google.cloud.bigtable.admin.v2.models.UpdateInstanceRequest;
import com.google.cloud.bigtable.admin.v2.stub.BigtableInstanceAdminStub;
import com.google.common.base.Verify;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.UncheckedExecutionException;
import com.google.protobuf.Empty;
import java.io.IOException;
import java.util.List;
Expand Down Expand Up @@ -96,7 +99,7 @@ public static BigtableInstanceAdminClient create(@Nonnull BigtableInstanceAdminS
return create(settings.getProjectName(), settings.getStubSettings().createStub());
}

/** Constructs an instance of BigtableInstanceAdminClient with the given Projectname and stub. */
/** Constructs an instance of BigtableInstanceAdminClient with the given ProjectName and stub. */
public static BigtableInstanceAdminClient create(@Nonnull ProjectName projectName,
@Nonnull BigtableInstanceAdminStub stub) {
return new BigtableInstanceAdminClient(projectName, stub);
Expand All @@ -110,6 +113,7 @@ private BigtableInstanceAdminClient(
}

/** Gets the ProjectName this client is associated with. */
@SuppressWarnings("WeakerAccess")
public ProjectName getProjectName() {
return projectName;
}
Expand All @@ -125,6 +129,7 @@ public void close() {
*
* @see CreateInstanceRequest for details.
*/
@SuppressWarnings("WeakerAccess")
public Instance createInstance(CreateInstanceRequest request) {
return awaitFuture(createInstanceAsync(request));
}
Expand All @@ -134,10 +139,16 @@ public Instance createInstance(CreateInstanceRequest request) {
*
* @see CreateInstanceRequest for details.
*/
@SuppressWarnings("WeakerAccess")
public ApiFuture<Instance> createInstanceAsync(CreateInstanceRequest request) {
return ApiFutures.transform(
stub.createInstanceOperationCallable().futureCall(request.toProto(projectName)),
Instance.PROTO_TRANSFORMER,
new ApiFunction<com.google.bigtable.admin.v2.Instance, Instance>() {
@Override
public Instance apply(com.google.bigtable.admin.v2.Instance proto) {
return Instance.fromProto(proto);
}
},
MoreExecutors.directExecutor());
}

Expand All @@ -146,6 +157,7 @@ public ApiFuture<Instance> createInstanceAsync(CreateInstanceRequest request) {
*
* @see UpdateInstanceRequest for details.
*/
@SuppressWarnings("WeakerAccess")
public Instance updateInstance(UpdateInstanceRequest request) {
return awaitFuture(updateInstanceAsync(request));
}
Expand All @@ -155,21 +167,28 @@ public Instance updateInstance(UpdateInstanceRequest request) {
*
* @see UpdateInstanceRequest for details.
*/
@SuppressWarnings("WeakerAccess")
public ApiFuture<Instance> updateInstanceAsync(UpdateInstanceRequest request) {
return ApiFutures.transform(
stub.partialUpdateInstanceOperationCallable().futureCall(request.toProto(projectName)),
Instance.PROTO_TRANSFORMER,
new ApiFunction<com.google.bigtable.admin.v2.Instance, Instance>() {
@Override
public Instance apply(com.google.bigtable.admin.v2.Instance proto) {
return Instance.fromProto(proto);
}
},
MoreExecutors.directExecutor());
}

/** Get the instance representation. */
@SuppressWarnings("WeakerAccess")
public Instance getInstance(String id) {
return awaitFuture(getInstanceAsync(id));
}

/** Asynchronously gets the instance representation wrapped in a future. */
@SuppressWarnings("WeakerAccess")
public ApiFuture<Instance> getInstanceAsync(String instanceId) {

InstanceName name = InstanceName.of(projectName.getProject(), instanceId);

GetInstanceRequest request = GetInstanceRequest.newBuilder()
Expand All @@ -178,16 +197,23 @@ public ApiFuture<Instance> getInstanceAsync(String instanceId) {

return ApiFutures.transform(
stub.getInstanceCallable().futureCall(request),
Instance.PROTO_TRANSFORMER,
new ApiFunction<com.google.bigtable.admin.v2.Instance, Instance>() {
@Override
public Instance apply(com.google.bigtable.admin.v2.Instance proto) {
return Instance.fromProto(proto);
}
},
MoreExecutors.directExecutor());
}

/** Lists all of the instances in the current project. */
@SuppressWarnings("WeakerAccess")
public List<Instance> listInstances() {
return awaitFuture(listInstancesAsync());
}

/** Asynchronously lists all of the instances in the current project. */
@SuppressWarnings("WeakerAccess")
public ApiFuture<List<Instance>> listInstancesAsync() {
ListInstancesRequest request = ListInstancesRequest.newBuilder()
.setParent(projectName.toString())
Expand All @@ -196,41 +222,47 @@ public ApiFuture<List<Instance>> listInstancesAsync() {
ApiFuture<ListInstancesResponse> responseFuture = stub.listInstancesCallable()
.futureCall(request);

return ApiFutures.transform(responseFuture, new ApiFunction<ListInstancesResponse, List<Instance>>() {
@Override
public List<Instance> apply(ListInstancesResponse proto) {
// NOTE: pagination is intentionally ignored. The server does not implement it.
Verify.verify(proto.getNextPageToken().isEmpty(),
"Server returned an unexpected paginated response");

ImmutableList.Builder<Instance> instances = ImmutableList.builder();

for (com.google.bigtable.admin.v2.Instance protoInstance : proto.getInstancesList()) {
instances.add(Instance.PROTO_TRANSFORMER.apply(protoInstance));
}

ImmutableList.Builder<String> failedZones = ImmutableList.builder();
for (String locationStr : proto.getFailedLocationsList()) {
failedZones.add(LocationName.parse(locationStr).getLocation());
}


if (!failedZones.build().isEmpty()) {
throw new PartialListInstancesException(failedZones.build(), instances.build());
}

return instances.build();
}
}, MoreExecutors.directExecutor());
return ApiFutures
.transform(responseFuture, new ApiFunction<ListInstancesResponse, List<Instance>>() {
@Override
public List<Instance> apply(ListInstancesResponse proto) {
// NOTE: pagination is intentionally ignored. The server does not implement it.
Verify.verify(proto.getNextPageToken().isEmpty(),
"Server returned an unexpected paginated response");

ImmutableList.Builder<Instance> instances = ImmutableList.builder();

for (com.google.bigtable.admin.v2.Instance protoInstance : proto.getInstancesList()) {
instances.add(Instance.fromProto(protoInstance));
}

ImmutableList.Builder<String> failedZones = ImmutableList.builder();
for (String locationStr : proto.getFailedLocationsList()) {
LocationName fullLocation = LocationName.parse(locationStr);
if (fullLocation == null) {
continue;
}
failedZones.add(fullLocation.getLocation());
}

if (!failedZones.build().isEmpty()) {
throw new PartialListInstancesException(failedZones.build(), instances.build());
}

return instances.build();
}
}, MoreExecutors.directExecutor());
}

/** Deletes the specified instance. */
@SuppressWarnings("WeakerAccess")
public void deleteInstance(String instanceId) {
awaitFuture(deleteInstanceAsync(instanceId));
}

/** Asynchronously deletes the specified instance. */
private ApiFuture<Void> deleteInstanceAsync(String instanceId) {
@SuppressWarnings("WeakerAccess")
public ApiFuture<Void> deleteInstanceAsync(String instanceId) {
InstanceName instanceName = InstanceName.of(projectName.getProject(), instanceId);

DeleteInstanceRequest request = DeleteInstanceRequest.newBuilder()
Expand All @@ -248,39 +280,32 @@ public Void apply(Empty input) {
);
}


private <T> T awaitFuture(ApiFuture<T> future) {
try {
return future.get();
} catch(Throwable t) {
// TODO(igorbernstein2): figure out a better wrapper exception.
throw new RuntimeException(t);
}
}

/**
* Exception thrown when some zones are unavailable and listInstances is unable to return a full
* instance list. This exception can be inspected to get a partial list.
* Awaits the result of a future, taking care to propagate errors while maintaining the call site
* in a suppressed exception. This allows semantic errors to be caught across threads, while
* preserving the call site in the error. The caller's stacktrace will be made available as a
* suppressed exception.
*/
public static class PartialListInstancesException extends RuntimeException {
private final List<String> failedZones;
private final List<Instance> instances;

PartialListInstancesException(List<String> failedZones, List<Instance> instances) {
super("Failed to list all instances, some zones where unavailable");
// TODO(igorbernstein2): try to move this into gax
private <T> T awaitFuture(ApiFuture<T> future) {
RuntimeException error;

this.failedZones = failedZones;
this.instances = instances;
try {
return Futures.getUnchecked(future);
} catch (UncheckedExecutionException e) {
if (e.getCause() instanceof RuntimeException) {
error = (RuntimeException) e.getCause();
} else {
error = e;
}
} catch (RuntimeException e) {
error = e;
}

/** A list of zones, whose unavailability caused this error. */
public List<String> getFailedZones() {
return failedZones;
}
// Add the caller's stack as a suppressed exception
error.addSuppressed(new RuntimeException("Encountered error while awaiting future"));

/** A partial list of instances that were found in the available zones. */
public List<Instance> getInstances() {
return instances;
}
throw error;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
public final class CreateClusterRequest {
private final com.google.bigtable.admin.v2.CreateClusterRequest.Builder proto = com.google.bigtable.admin.v2.CreateClusterRequest
.newBuilder();
// Partial ids will be set when the project is passed to toProto
private final String instanceId;
private String zone;

Expand All @@ -70,12 +71,14 @@ private CreateClusterRequest(String instanceId, String clusterId) {
* Sets the zone where the new cluster will be located. Must be different from the existing
* cluster.
*/
@SuppressWarnings("WeakerAccess")
public CreateClusterRequest setZone(String zone) {
this.zone = zone;
return this;
}

/** Sets the type of storage used by this cluster to serve its parent instance's tables. */
@SuppressWarnings("WeakerAccess")
public CreateClusterRequest setServeNodes(int numNodes) {
proto.getClusterBuilder().setServeNodes(numNodes);
return this;
Expand All @@ -86,6 +89,7 @@ public CreateClusterRequest setServeNodes(int numNodes) {
* Defaults to {@code SSD}.
*/
// TODO(igorbernstein2): try to avoid leaking protobuf generated enums
@SuppressWarnings("WeakerAccess")
public CreateClusterRequest setStorageType(StorageType storageType) {
proto.getClusterBuilder().setDefaultStorageType(storageType);
return this;
Expand Down Expand Up @@ -113,8 +117,8 @@ String getClusterId() {
}

/**
* Creates the request protobuf. This method is considered an internal implementation detail and
* not meant to be used by applications.
* Creates the request protobuf to be used in {@link CreateInstanceRequest}. This method is
* considered an internal implementation detail and not meant to be used by applications.
*/
@InternalApi
com.google.bigtable.admin.v2.Cluster toEmbeddedProto(ProjectName projectName) {
Expand Down
Loading

0 comments on commit db81392

Please sign in to comment.