Skip to content

Commit d6bfd30

Browse files
feat: add BigtableDataClientFactory to create lightweight data clients (#112)
* feat: add BigtableDataClientFactory to create lightweight data clients The new factory allows users to construct a single heavy factory object that can create many lightweight clients. This is meant to be used in situations when a single application needs to access multiple instances or use different application profiles * code format * disclaimer comment
1 parent 9289a13 commit d6bfd30

File tree

4 files changed

+478
-4
lines changed

4 files changed

+478
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
/*
2+
* Copyright 2019 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.google.cloud.bigtable.data.v2;
17+
18+
import com.google.api.core.BetaApi;
19+
import com.google.api.gax.core.BackgroundResource;
20+
import com.google.api.gax.core.FixedCredentialsProvider;
21+
import com.google.api.gax.core.FixedExecutorProvider;
22+
import com.google.api.gax.rpc.ClientContext;
23+
import com.google.api.gax.rpc.FixedHeaderProvider;
24+
import com.google.api.gax.rpc.FixedTransportChannelProvider;
25+
import com.google.api.gax.rpc.FixedWatchdogProvider;
26+
import com.google.api.gax.rpc.StubSettings;
27+
import java.io.IOException;
28+
import javax.annotation.Nonnull;
29+
30+
/**
31+
* A factory to create multiple {@link BigtableDataClient} instances that all share the same channel
32+
* pool.
33+
*
34+
* <p>This allows multiple client instances to share the same gRPC channel pool, which makes client
35+
* creation very cheap. The intended use case is for applications that need to access multiple
36+
* Bigtable Instances from the same process.
37+
*
38+
* <p>Example Usage:
39+
*
40+
* <pre>{@code
41+
* BigtableDataSettings defaultSettings = BigtableDataSettings.newBuilder()
42+
* .setProject("my-default-project")
43+
* .setInstance("my-default-instance")
44+
* .build();
45+
*
46+
* BigtableDataClientFactory clientFactory = BigtableDataClientFactory.create(defaultSettings);
47+
*
48+
* // Create a new client for "my-default-instance" in "my-default-project";
49+
* BigtableDataClient defaultInstanceClient = clientFactory.createDefault();
50+
*
51+
* // Create a new client for a different application profile
52+
* BigtableDataClient otherAppProfileClient = clientFactory.createForAppProfile("other-app-profile");
53+
*
54+
* // Create a new client for a completely different instance and application profile.
55+
* BigtableDataClient otherInstanceClient = clientFactory
56+
* .createForInstance("my-other-project", "my-other-instance", "my-other-app-profile");
57+
*
58+
* // Clean up: make sure close the clients AND the factory.
59+
* defaultInstanceClient.close();
60+
* otherAppProfileClient.close();
61+
* otherInstanceClient.close();
62+
*
63+
* clientFactory.close();
64+
*
65+
* <p>Please note that this is an experimental feature and might be changed or removed in future.
66+
* }</pre>
67+
*/
68+
@BetaApi("This feature is currently experimental and can change in the future")
69+
public final class BigtableDataClientFactory implements AutoCloseable {
70+
private final BigtableDataSettings defaultSettings;
71+
private final ClientContext sharedClientContext;
72+
73+
/**
74+
* Create a instance of this factory.
75+
*
76+
* <p>The factory will be used to create clients using the provided settings as the base. Make
77+
* sure to call {@link #close()} on the factory after closing all clients.
78+
*/
79+
public static BigtableDataClientFactory create(BigtableDataSettings defaultSettings)
80+
throws IOException {
81+
ClientContext sharedClientContext = ClientContext.create(defaultSettings.getStubSettings());
82+
return new BigtableDataClientFactory(sharedClientContext, defaultSettings);
83+
}
84+
85+
private BigtableDataClientFactory(
86+
ClientContext sharedClientContext, BigtableDataSettings defaultSettings) {
87+
this.sharedClientContext = sharedClientContext;
88+
this.defaultSettings = defaultSettings;
89+
}
90+
91+
/**
92+
* Release all of the resources associated with this factory.
93+
*
94+
* <p>This will close the underlying channel pooling, disconnecting all create clients.
95+
*/
96+
@Override
97+
public void close() throws Exception {
98+
for (BackgroundResource resource : sharedClientContext.getBackgroundResources()) {
99+
resource.close();
100+
}
101+
}
102+
103+
/**
104+
* Create a lightweight client using the default settings in this factory. This will use the
105+
* factory default project, instance and application profile ids. The client will also share
106+
* resources like the channel pool with other clients created using this factory.
107+
*
108+
* <p>The client should be closed when it is no longer needed. Closing the client will release
109+
* client specific resources, but will leave shared resources like the channel pool open. To
110+
* release all resources, first close all of the created clients and then this factory instance.
111+
*/
112+
public BigtableDataClient createDefault() {
113+
BigtableDataSettings.Builder settingsBuilder = defaultSettings.toBuilder();
114+
patchStubSettings(settingsBuilder.stubSettings());
115+
BigtableDataSettings settings = settingsBuilder.build();
116+
117+
try {
118+
return BigtableDataClient.create(settings);
119+
} catch (IOException e) {
120+
// Should never happen because the connection has been established already
121+
throw new RuntimeException(
122+
"Failed to create a new client using factory default settings and shared resources.");
123+
}
124+
}
125+
126+
/**
127+
* Create a lightweight client with an overriden application profile and the factory default
128+
* project and instance ids. The client will also share resources like the channel pool with other
129+
* clients created using this factory.
130+
*
131+
* <p>The client should be closed when it is no longer needed. Closing the client will release
132+
* client specific resources, but will leave shared resources like the channel pool open. To
133+
* release all resources, first close all of the created clients and then this factory instance.
134+
*/
135+
public BigtableDataClient createForAppProfile(@Nonnull String appProfileId) throws IOException {
136+
BigtableDataSettings.Builder settingsBuilder =
137+
defaultSettings.toBuilder().setAppProfileId(appProfileId);
138+
139+
patchStubSettings(settingsBuilder.stubSettings());
140+
141+
return BigtableDataClient.create(settingsBuilder.build());
142+
}
143+
144+
/**
145+
* Create a lightweight client with the specified project and instance id. The resulting client
146+
* will use the server default application profile. The client will also share resources like the
147+
* channel pool with other clients created using this factory.
148+
*
149+
* <p>The client should be closed when it is no longer needed. Closing the client will release
150+
* client specific resources, but will leave shared resources like the channel pool open. To
151+
* release all resources, first close all of the created clients and then this factory instance.
152+
*/
153+
public BigtableDataClient createForInstance(@Nonnull String projectId, @Nonnull String instanceId)
154+
throws IOException {
155+
BigtableDataSettings.Builder settingsBuilder =
156+
defaultSettings
157+
.toBuilder()
158+
.setProjectId(projectId)
159+
.setInstanceId(instanceId)
160+
.setDefaultAppProfileId();
161+
162+
patchStubSettings(settingsBuilder.stubSettings());
163+
164+
return BigtableDataClient.create(settingsBuilder.build());
165+
}
166+
167+
/**
168+
* Create a lightweight client to the specified project, instance and application profile id. The
169+
* client will share resources like the channel pool with other clients created using this
170+
* factory.
171+
*
172+
* <p>The client should be closed when it is no longer needed. Closing the client will release
173+
* client specific resources, but will leave shared resources like the channel pool open. To
174+
* release all resources, first close all of the created clients and then this factory instance.
175+
*/
176+
public BigtableDataClient createForInstance(
177+
@Nonnull String projectId, @Nonnull String instanceId, @Nonnull String appProfileId)
178+
throws IOException {
179+
BigtableDataSettings.Builder settingsBuilder =
180+
defaultSettings
181+
.toBuilder()
182+
.setProjectId(projectId)
183+
.setInstanceId(instanceId)
184+
.setAppProfileId(appProfileId);
185+
186+
patchStubSettings(settingsBuilder.stubSettings());
187+
188+
return BigtableDataClient.create(settingsBuilder.build());
189+
}
190+
191+
// Update stub settings to use shared resources in this factory
192+
private void patchStubSettings(StubSettings.Builder stubSettings) {
193+
stubSettings
194+
.setTransportChannelProvider(
195+
FixedTransportChannelProvider.create(sharedClientContext.getTransportChannel()))
196+
.setCredentialsProvider(
197+
FixedCredentialsProvider.create(sharedClientContext.getCredentials()))
198+
.setExecutorProvider(FixedExecutorProvider.create(sharedClientContext.getExecutor()))
199+
.setStreamWatchdogProvider(
200+
FixedWatchdogProvider.create(sharedClientContext.getStreamWatchdog()))
201+
.setHeaderProvider(FixedHeaderProvider.create(sharedClientContext.getHeaders()))
202+
.setClock(sharedClientContext.getClock());
203+
}
204+
}

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/BigtableDataSettings.java

+22-4
Original file line numberDiff line numberDiff line change
@@ -255,16 +255,34 @@ public String getInstanceId() {
255255
}
256256

257257
/**
258-
* Sets the AppProfile to use. An application profile (sometimes also shortened to "app
259-
* profile") is a group of configuration parameters for an individual use case. A client will
260-
* identify itself with an application profile ID at connection time, and the requests will be
261-
* handled according to that application profile.
258+
* Sets the AppProfile to use.
259+
*
260+
* <p>An application profile (sometimes also shortened to "app profile") is a group of
261+
* configuration parameters for an individual use case. A client will identify itself with an
262+
* application profile ID at connection time, and the requests will be handled according to that
263+
* application profile.
262264
*/
263265
public Builder setAppProfileId(@Nonnull String appProfileId) {
264266
stubSettings.setAppProfileId(appProfileId);
265267
return this;
266268
}
267269

270+
/**
271+
* Resets the AppProfile id to the default for the instance.
272+
*
273+
* <p>An application profile (sometimes also shortened to "app profile") is a group of
274+
* configuration parameters for an individual use case. A client will identify itself with an
275+
* application profile ID at connection time, and the requests will be handled according to that
276+
* application profile.
277+
*
278+
* <p>Every Bigtable Instance has a default application profile associated with it, this method
279+
* configures the client to use it.
280+
*/
281+
public Builder setDefaultAppProfileId() {
282+
stubSettings.setDefaultAppProfileId();
283+
return this;
284+
}
285+
268286
/** Gets the app profile id that was previously set on this Builder. */
269287
public String getAppProfileId() {
270288
return stubSettings.getAppProfileId();

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStubSettings.java

+16
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,22 @@ public Builder setAppProfileId(@Nonnull String appProfileId) {
610610
return this;
611611
}
612612

613+
/**
614+
* Resets the AppProfile id to the default for the instance.
615+
*
616+
* <p>An application profile (sometimes also shortened to "app profile") is a group of
617+
* configuration parameters for an individual use case. A client will identify itself with an
618+
* application profile ID at connection time, and the requests will be handled according to that
619+
* application profile.
620+
*
621+
* <p>Every Bigtable Instance has a default application profile associated with it, this method
622+
* configures the client to use it.
623+
*/
624+
public Builder setDefaultAppProfileId() {
625+
setAppProfileId(SERVER_DEFAULT_APP_PROFILE_ID);
626+
return this;
627+
}
628+
613629
/** Gets the app profile id that was previously set on this Builder. */
614630
public String getAppProfileId() {
615631
return appProfileId;

0 commit comments

Comments
 (0)