Commit 90f95ef
committed
feat(bigtable): BigtableDataClientFactory session support
This commit extends the session-based API path to support BigtableDataClientFactory.
Now the factory creates a single shared ChannelPool and
ClientConfigurationManager once and hands lightweight child clients a reference to both.
The bulk of the implementation work is a rewrite of ChannelPoolDpImpl to correctly handle multiple tenants (different instances/app profiles) sharing a single channel pool.
---
ChannelPoolDpImpl: New Placement Model
Old design
The old pool organized channels into AfeChannelGroup objects — one deque of channels per observed AFE. When a channel's first session revealed its AFE (via onBeforeSessionStart), the channel was rehomed from
the temporary startingGroup into the matching AfeChannelGroup, creating one if it didn't exist. New streams were then placed by picking the group with the fewest sessions.
This design had a problem for the multi-tenant factory case:
AFE affinity was tracked per channel, but for factory children different tenants on the same channel can be routed to different AFEs by RLS. A channel in group "AFE-7" might route tenant A to AFE-7 but
tenant B somewhere else entirely.
New design
The new pool replaces the nested group structure with a flat channels list plus a routeObservations map keyed on (channelId, tenantKey) → lastObservedAfeId.
Data structures:
- channels: List<ChannelWrapper> — all channels in ACTIVE or DRAINING state
- routeObservations: Map<RouteKey, AfeId> — the last AFE seen for a given (channel, tenant) pair, populated on every onBeforeSessionStart and self-healing as RLS routes drift over time
- sessionsPerAfeId: Multiset<AfeId> — global count of live sessions per AFE, used to find underloaded targets
- TenantKey (new value type) — stamped onto CallOptions by TableBase so the pool can distinguish tenants within the same shared pool
Placement (newStream):
1. Capacity mode — find the AFE with the smallest session count that is still below softMaxPerGroup:
- 3a — Preferred: pick the ACTIVE channel whose last observed route for this tenant was that AFE, choosing the least-loaded among candidates. This is the steady-state path: RLS is stable per (channel,
tenant), so repeat sessions for the same tenant land on the same AFE.
- 3b — Unobserved-tenant fallback: if no route observation exists for this tenant on any channel, pick any ACTIVE channel with remaining capacity (least-loaded). The actual AFE is unknown until
onBeforeSessionStart fires; routeObservations is updated then for future placements.
2. Diversity mode — entered when all known AFEs are at cap, or the pool is empty: prefer an ACTIVE channel with fewer than softMaxPerGroup / 2 outstanding streams. If none exists, open a new channel and
absorb whichever AFE it lands on.
Scale-in (DRAINING state):
The old "thinning" logic would call channel.shutdown() during serviceChannels(). The new approach introduces a two-state channel lifecycle
(ACTIVE / DRAINING). When serviceChannels() decides to shrink the pool it marks excess channels DRAINING — they stop accepting new streams but continue serving existing ones. A DRAINING channel is removed
only when its numOutstanding reaches zero (in releaseChannel). Drain candidates are chosen by pickDrainCandidates, which prefers idle channels first, then least-recently-used, then oldest.
Route observation cleanup:
removeChannel purges all routeObservations entries for the removed channel's ID, preventing the map from growing unboundedly as channels cycle.
---
Other changes
BigtableDataClientFactory / BigtableClientContext:
- BigtableDataClientFactory.create() now calls BigtableClientContext.createForFactory() (a new entry point) instead of manually disabling sessions. The factory context initializes a shared ShimImpl (channel
pool + config manager) that is reused by all children.
- BigtableClientContext.createChild() now creates a lightweight ShimImpl child via ShimImpl.createForFactoryChild() rather than sharing a DisabledShim.
ShimImpl / Client:
- Client.channelPool changed from a bare ChannelPool reference to Resource<ChannelPool> so the factory-child constructor can hold a shared (non-closing) reference and the standard constructor holds an owned
one.
- ShimImpl.configManager similarly wrapped in Resource<> so close() is a no-op for factory children (the parent owns the manager's lifecycle).1 parent 5ff7a0f commit 90f95ef
9 files changed
Lines changed: 477 additions & 242 deletions
File tree
- java-bigtable/google-cloud-bigtable/src
- main/java/com/google/cloud/bigtable/data/v2
- internal
- api
- channels
- compat
- stub
- test/java/com/google/cloud/bigtable/data/v2/internal/channels
Lines changed: 1 addition & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
74 | 74 | | |
75 | 75 | | |
76 | 76 | | |
77 | | - | |
78 | | - | |
79 | | - | |
80 | | - | |
81 | 77 | | |
82 | | - | |
| 78 | + | |
83 | 79 | | |
84 | 80 | | |
85 | 81 | | |
| |||
Lines changed: 46 additions & 11 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
73 | 73 | | |
74 | 74 | | |
75 | 75 | | |
76 | | - | |
| 76 | + | |
77 | 77 | | |
78 | 78 | | |
79 | 79 | | |
| |||
147 | 147 | | |
148 | 148 | | |
149 | 149 | | |
150 | | - | |
151 | 150 | | |
152 | 151 | | |
153 | | - | |
| 152 | + | |
| 153 | + | |
154 | 154 | | |
155 | 155 | | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
156 | 160 | | |
157 | 161 | | |
158 | 162 | | |
159 | | - | |
160 | 163 | | |
161 | 164 | | |
162 | | - | |
| 165 | + | |
| 166 | + | |
163 | 167 | | |
164 | 168 | | |
165 | 169 | | |
| |||
181 | 185 | | |
182 | 186 | | |
183 | 187 | | |
184 | | - | |
| 188 | + | |
185 | 189 | | |
186 | 190 | | |
187 | 191 | | |
188 | 192 | | |
189 | 193 | | |
190 | | - | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
191 | 216 | | |
192 | 217 | | |
193 | 218 | | |
| |||
200 | 225 | | |
201 | 226 | | |
202 | 227 | | |
203 | | - | |
| 228 | + | |
204 | 229 | | |
205 | 230 | | |
206 | 231 | | |
| |||
211 | 236 | | |
212 | 237 | | |
213 | 238 | | |
214 | | - | |
| 239 | + | |
215 | 240 | | |
216 | 241 | | |
217 | 242 | | |
| |||
228 | 253 | | |
229 | 254 | | |
230 | 255 | | |
231 | | - | |
| 256 | + | |
232 | 257 | | |
233 | 258 | | |
234 | 259 | | |
| |||
246 | 271 | | |
247 | 272 | | |
248 | 273 | | |
249 | | - | |
| 274 | + | |
250 | 275 | | |
251 | 276 | | |
252 | 277 | | |
| |||
256 | 281 | | |
257 | 282 | | |
258 | 283 | | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
259 | 294 | | |
260 | 295 | | |
261 | 296 | | |
| |||
Lines changed: 9 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
| 25 | + | |
| 26 | + | |
25 | 27 | | |
26 | 28 | | |
27 | 29 | | |
| |||
63 | 65 | | |
64 | 66 | | |
65 | 67 | | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
66 | 74 | | |
67 | 75 | | |
68 | 76 | | |
69 | 77 | | |
70 | 78 | | |
71 | 79 | | |
72 | 80 | | |
73 | | - | |
| 81 | + | |
74 | 82 | | |
75 | 83 | | |
76 | 84 | | |
| |||
0 commit comments