Skip to content

Commit

Permalink
feat: Add APIs to enable request priorities
Browse files Browse the repository at this point in the history
  • Loading branch information
DerekLeeCS committed Oct 16, 2023
1 parent fe4b6bc commit 6f50530
Show file tree
Hide file tree
Showing 7 changed files with 341 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

import com.google.api.core.InternalApi;
import com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny;
import com.google.bigtable.admin.v2.AppProfile.Priority;
import com.google.bigtable.admin.v2.AppProfile.StandardIsolation;
import com.google.bigtable.admin.v2.AppProfileName;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
Expand Down Expand Up @@ -76,6 +78,15 @@ public RoutingPolicy getPolicy() {
}
}

public IsolationPolicy getIsolationPolicy() {
if (proto.hasStandardIsolation()) {
return new StandardIsolationPolicy(proto.getStandardIsolation());
} else {
// Should never happen because the constructor verifies that one must exist.
throw new VerifyException();
}
}

/** Gets the id of this AppProfile. */
@SuppressWarnings("WeakerAccess")
public String getId() {
Expand Down Expand Up @@ -292,4 +303,108 @@ public int hashCode() {
return Objects.hashCode(proto);
}
}

/** Represents the options for isolating this app profile's traffic from other use cases. */
@SuppressWarnings("WeakerAccess")
public interface IsolationPolicy {}

/**
* The possible priorities for an app profile. Note that higher priority writes can sometimes
* queue behind lower priority writes to the same tablet, as writes must be strictly sequenced in
* the durability log.
*/
public static enum Priority {
PRIORITY_LOW(com.google.bigtable.admin.v2.AppProfile.Priority.PRIORITY_LOW),
PRIORITY_MEDIUM(com.google.bigtable.admin.v2.AppProfile.Priority.PRIORITY_MEDIUM),
PRIORITY_HIGH(com.google.bigtable.admin.v2.AppProfile.Priority.PRIORITY_HIGH);

private final com.google.bigtable.admin.v2.AppProfile.Priority proto;

/**
* Wraps the protobuf. This method is considered an internal implementation detail and not meant
* to be used by applications.
*/
@InternalApi
public static Priority fromProto(com.google.bigtable.admin.v2.AppProfile.Priority proto) {
Preconditions.checkNotNull(proto);

for (Priority priority : values()) {
if (priority.proto.equals(proto)) {
return priority;
}
}

throw new IllegalArgumentException("Unknown priority: " + proto);
}

Priority(com.google.bigtable.admin.v2.AppProfile.Priority proto) {
this.proto = proto;
}

/**
* 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.AppProfile.Priority toProto() {
return proto;
}
}

/**
* A standard {@link IsolationPolicy} for isolating this app profile's traffic from other use
* cases.
*/
public static class StandardIsolationPolicy implements IsolationPolicy {
private final StandardIsolation proto;

/** Creates a new instance of {@link StandardIsolationPolicy}. */
public static StandardIsolationPolicy of() {
return new StandardIsolationPolicy(StandardIsolation.getDefaultInstance());
}

/** Creates a new instance of {@link StandardIsolationPolicy} with the specified priority. */
public static StandardIsolationPolicy of(Priority priority) {
return new StandardIsolationPolicy(
StandardIsolation.newBuilder().setPriority(priority.toProto()).build());
}

/*
* Returns the priority for this app profile.
*/
public Priority getPriority() {
return Priority.fromProto(proto.getPriority());
}

private StandardIsolationPolicy(
com.google.bigtable.admin.v2.AppProfile.StandardIsolation proto) {
this.proto = proto;
}

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

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

@Override
public int hashCode() {
return Objects.hashCode(proto);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@

import com.google.api.core.InternalApi;
import com.google.cloud.bigtable.admin.v2.internal.NameUtil;
import com.google.cloud.bigtable.admin.v2.models.AppProfile.IsolationPolicy;
import com.google.cloud.bigtable.admin.v2.models.AppProfile.MultiClusterRoutingPolicy;
import com.google.cloud.bigtable.admin.v2.models.AppProfile.RoutingPolicy;
import com.google.cloud.bigtable.admin.v2.models.AppProfile.SingleClusterRoutingPolicy;
import com.google.cloud.bigtable.admin.v2.models.AppProfile.StandardIsolationPolicy;
import com.google.common.base.Preconditions;
import javax.annotation.Nonnull;

Expand Down Expand Up @@ -92,6 +94,21 @@ public CreateAppProfileRequest setRoutingPolicy(RoutingPolicy routingPolicy) {
return this;
}

/** Sets the isolation policy for all read/write requests that use this app profile. */
public CreateAppProfileRequest setIsolationPolicy(IsolationPolicy isolationPolicy) {
Preconditions.checkNotNull(isolationPolicy);

if (isolationPolicy instanceof StandardIsolationPolicy) {
proto
.getAppProfileBuilder()
.setStandardIsolation(((StandardIsolationPolicy) isolationPolicy).toProto());
} else {
throw new IllegalArgumentException("Unknown policy type: " + isolationPolicy);
}

return this;
}

/**
* Creates the request protobuf. This method is considered an internal implementation detail and
* not meant to be used by applications.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@

import com.google.api.core.InternalApi;
import com.google.cloud.bigtable.admin.v2.internal.NameUtil;
import com.google.cloud.bigtable.admin.v2.models.AppProfile.IsolationPolicy;
import com.google.cloud.bigtable.admin.v2.models.AppProfile.MultiClusterRoutingPolicy;
import com.google.cloud.bigtable.admin.v2.models.AppProfile.RoutingPolicy;
import com.google.cloud.bigtable.admin.v2.models.AppProfile.SingleClusterRoutingPolicy;
import com.google.cloud.bigtable.admin.v2.models.AppProfile.StandardIsolationPolicy;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.protobuf.FieldMask;
Expand Down Expand Up @@ -121,6 +123,22 @@ public UpdateAppProfileRequest setRoutingPolicy(@Nonnull RoutingPolicy routingPo
return this;
}

/** Sets the isolation policy for all read/write requests that use this app profile. */
public UpdateAppProfileRequest setIsolationPolicy(@Nonnull IsolationPolicy isolationPolicy) {
Preconditions.checkNotNull(isolationPolicy);

if (isolationPolicy instanceof StandardIsolationPolicy) {
proto
.getAppProfileBuilder()
.setStandardIsolation(((StandardIsolationPolicy) isolationPolicy).toProto());
updateFieldMask(com.google.bigtable.admin.v2.AppProfile.STANDARD_ISOLATION_FIELD_NUMBER);
} else {
throw new IllegalArgumentException("Unknown policy type: " + isolationPolicy);
}

return this;
}

private void updateFieldMask(int fieldNumber) {
FieldMask newMask =
FieldMaskUtil.fromFieldNumbers(com.google.bigtable.admin.v2.AppProfile.class, fieldNumber);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
import com.google.cloud.bigtable.admin.v2.internal.NameUtil;
import com.google.cloud.bigtable.admin.v2.models.AppProfile;
import com.google.cloud.bigtable.admin.v2.models.AppProfile.MultiClusterRoutingPolicy;
import com.google.cloud.bigtable.admin.v2.models.AppProfile.Priority;
import com.google.cloud.bigtable.admin.v2.models.AppProfile.StandardIsolationPolicy;
import com.google.cloud.bigtable.admin.v2.models.Cluster;
import com.google.cloud.bigtable.admin.v2.models.ClusterAutoscalingConfig;
import com.google.cloud.bigtable.admin.v2.models.CreateAppProfileRequest;
Expand Down Expand Up @@ -82,7 +84,7 @@

@RunWith(JUnit4.class)
/**
* Tests for {@link BigtableTableAdminClient}. This test class uses Mockito so it has been
* Tests for {@link BigtableInstanceAdminClient}. This test class uses Mockito so it has been
* explicitly excluded from Native Image testing by not following the naming convention of (IT* and
* *ClientTest).
*/
Expand Down Expand Up @@ -983,6 +985,55 @@ public void testCreateAppProfileAddMultipleClusterIdsWithList() {
assertThat(actualResult).isEqualTo(AppProfile.fromProto(expectedResponse));
}

@Test
public void testCreateAppProfileAddPriority() {
// Setup
Mockito.when(mockStub.createAppProfileCallable()).thenReturn(mockCreateAppProfileCallable);

com.google.bigtable.admin.v2.CreateAppProfileRequest expectedRequest =
com.google.bigtable.admin.v2.CreateAppProfileRequest.newBuilder()
.setParent(NameUtil.formatInstanceName(PROJECT_ID, INSTANCE_ID))
.setAppProfileId(APP_PROFILE_ID)
.setAppProfile(
com.google.bigtable.admin.v2.AppProfile.newBuilder()
.setDescription("my description")
.setMultiClusterRoutingUseAny(
com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny
.newBuilder()
.addClusterIds("cluster-id-1"))
.setStandardIsolation(
com.google.bigtable.admin.v2.AppProfile.StandardIsolation.newBuilder()
.setPriority(
com.google.bigtable.admin.v2.AppProfile.Priority.PRIORITY_MEDIUM)))
.build();

com.google.bigtable.admin.v2.AppProfile expectedResponse =
com.google.bigtable.admin.v2.AppProfile.newBuilder()
.setName(APP_PROFILE_NAME)
.setDescription("my description")
.setMultiClusterRoutingUseAny(
com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny.newBuilder()
.addClusterIds("cluster-id-1"))
.setStandardIsolation(
com.google.bigtable.admin.v2.AppProfile.StandardIsolation.newBuilder()
.setPriority(com.google.bigtable.admin.v2.AppProfile.Priority.PRIORITY_MEDIUM))
.build();

Mockito.when(mockCreateAppProfileCallable.futureCall(expectedRequest))
.thenReturn(ApiFutures.immediateFuture(expectedResponse));

// Execute
AppProfile actualResult =
adminClient.createAppProfile(
CreateAppProfileRequest.of(INSTANCE_ID, APP_PROFILE_ID)
.setDescription("my description")
.setRoutingPolicy(MultiClusterRoutingPolicy.of("cluster-id-1"))
.setIsolationPolicy(StandardIsolationPolicy.of(Priority.PRIORITY_MEDIUM)));

// Verify
assertThat(actualResult).isEqualTo(AppProfile.fromProto(expectedResponse));
}

@Test
public void testGetAppProfile() {
// Setup
Expand Down Expand Up @@ -1101,6 +1152,47 @@ public void testUpdateAppProfile() {
assertThat(actualResult).isEqualTo(AppProfile.fromProto(expectedResponse));
}

@Test
public void testUpdateAppProfileStandardIsolation() {
// Setup
Mockito.when(mockStub.updateAppProfileOperationCallable())
.thenReturn(mockUpdateAppProfileCallable);

com.google.bigtable.admin.v2.UpdateAppProfileRequest expectedRequest =
com.google.bigtable.admin.v2.UpdateAppProfileRequest.newBuilder()
.setAppProfile(
com.google.bigtable.admin.v2.AppProfile.newBuilder()
.setName(APP_PROFILE_NAME)
.setStandardIsolation(
com.google.bigtable.admin.v2.AppProfile.StandardIsolation.newBuilder()
.setPriority(
com.google.bigtable.admin.v2.AppProfile.Priority.PRIORITY_LOW)))
.setUpdateMask(FieldMask.newBuilder().addPaths("standard_isolation"))
.build();

com.google.bigtable.admin.v2.AppProfile expectedResponse =
com.google.bigtable.admin.v2.AppProfile.newBuilder()
.setName(APP_PROFILE_NAME)
.setMultiClusterRoutingUseAny(
com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny
.getDefaultInstance())
.setStandardIsolation(
com.google.bigtable.admin.v2.AppProfile.StandardIsolation.newBuilder()
.setPriority(com.google.bigtable.admin.v2.AppProfile.Priority.PRIORITY_LOW))
.build();

mockOperationResult(mockUpdateAppProfileCallable, expectedRequest, expectedResponse);

// Execute
AppProfile actualResult =
adminClient.updateAppProfile(
UpdateAppProfileRequest.of(INSTANCE_ID, APP_PROFILE_ID)
.setIsolationPolicy(StandardIsolationPolicy.of(Priority.PRIORITY_LOW)));

// Verify
assertThat(actualResult).isEqualTo(AppProfile.fromProto(expectedResponse));
}

@Test
public void testDeleteAppProfile() throws Exception {
// Setup
Expand Down
Loading

0 comments on commit 6f50530

Please sign in to comment.