Skip to content

fix(bigtable): resolve session diversion through a single shared rule - #14738

Open
mutianf wants to merge 1 commit into
googleapis:mainfrom
mutianf:fix/bigtable-session-scope-resolution
Open

mutianf wants to merge 1 commit into
googleapis:mainfrom
mutianf:fix/bigtable-session-scope-resolution

Conversation

@mutianf

@mutianf mutianf commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #14681, from reviewing it after it merged. Three independent fixes.

1. Two drifting resolution rules (the main one)

DivertingUnaryCallable.resolveSessionLoad (per RPC) and ClientConfigurationManager.divertsAnyTrafficToSessions (client-wide) answered "does traffic go to sessions?" with separately maintained rules that had already diverged:

per-RPC client-wide
diversion config present authoritative, flat load ignored ORs with flat session_load
per-scope map only this method's key any key, incl. methods the client never serves

So per_scope_diversion { "method:Bigtable.MutateRows": {session_load: 1.0} } made areSessionsRequired() true — flipping the sessions_required / sessions_compatible feature flags sent to the server and keeping the session config and channel pool alive — while DivertingUnaryCallable diverted exactly zero requests, because no callable asks for that scope. Same for session_load: 1.0 plus a CheckAndMutateRow-only map.

Both now go through a new SessionScope enum, which owns the four scopes this client serves, whether each honours the deprecated flat session_load, and the single resolution rule (moved verbatim out of DivertingUnaryCallable). ShimImpl passes SessionScope.READ_ROW instead of a String + boolean pair.

2. The default config shadowed the flat session_load

bigtable-default-client-config.textproto carried a zero-valued per_scope_diversion for ReadRow and MutateRow. Since a diversion configuration is authoritative once present, those entries forced every scope to 0 in any config derived from the default:

  • the initial normalizeConfig(defaultConfig) before the first GetClientConfiguration response,
  • the handleFailedFetch → setClientConfiguration(defaultConfig) path when the validity window expires during a config-service outage,
  • anything merged from the bigtable.internal.client-config-override sys-prop, including the bigtable-session-it Maven profile.

This surfaced as 10 ClientConfigurationManagerTest failures the moment fix 1 made the two checks agree — they had been passing only because the client-wide check disagreed and reported sessions as on. The entries were purely documentary (an absent key and an absent diversion config both resolve to 0), so they are removed.

3. ReadModifyWriteRow could return null on the session path

The extractor was r -> r.hasRow() ? r.getRow() : null, so a SessionReadModifyWriteRowResponse without a row handed user code a null the classic path never produces (EnhancedBigtableStub always builds a Row from the possibly-unset resp.getRow()). Unlike ReadRow — where a missing key legitimately means null — ReadModifyWriteRow always mutates and always yields a row, so it now extracts unconditionally. Both extractors are named constants with tests pinning the split.

Also forwards the per-method retry settings to the default call context for CheckAndMutateRow and ReadModifyWriteRow, matching the existing ReadRow and MutateRow wiring.

Testing

New SessionScopeTest (7 cases) covers the resolution rule and the agreement invariant; new cases in ShimImplTest pin the ReadRow-null / ReadModifyWriteRow-non-null split, and ClientConfigurationManagerTest gains one asserting the bundled default never shadows a flat session_load.

DivertingUnaryCallableTest, ClientConfigurationManagerTest, ShimImplTest, SessionDeadlineTest, SessionScopeTest, RowBuilderShimTest, ReadModifyWriteRowShimTest — 57 tests, all passing.

Follow-up to googleapis#14681. Three issues found reviewing the merged change.

1. The per-RPC diversion decision (DivertingUnaryCallable.resolveSessionLoad)
   and the client-wide "are sessions in use at all" decision
   (ClientConfigurationManager.divertsAnyTrafficToSessions) implemented two
   different, drifting rules. The client-wide one was the more permissive:
   it ORed the deprecated flat session_load with the diversion config and
   scanned every scope key, including methods no DivertingUnaryCallable asks
   for. So a config such as

     per_scope_diversion { "method:Bigtable.MutateRows": {session_load: 1.0} }

   made areSessionsRequired() true, flipping the sessions_required /
   sessions_compatible feature flags advertised to the server and keeping the
   session config and channel pool alive, while not a single request was ever
   diverted.

   Both now go through SessionScope, which owns the list of scopes this client
   actually serves, whether each honours the deprecated flat session_load, and
   the one resolution rule. The disagreement is no longer representable.

2. The default client config carried a zero-valued per_scope_diversion for
   ReadRow and MutateRow. A diversion configuration is authoritative once
   present, so those entries shadowed the flat session_load for every scope in
   any config derived from the default: the initial config before the first
   GetClientConfiguration response, the handleFailedFetch fallback when the
   validity window expires, and anything merged from the
   bigtable.internal.client-config-override sys-prop. The entries were purely
   documentary (an absent key and an absent config both resolve to 0), so they
   are removed.

3. ReadModifyWriteRow on the session path extracted its row with
   `r.hasRow() ? r.getRow() : null`, so a response without a row handed user
   code a null that the classic path never produces. Unlike ReadRow, where a
   missing key legitimately means null, ReadModifyWriteRow always mutates and
   always yields a row, so it now extracts unconditionally.

Also forwards the per-method retry settings to the default call context for
CheckAndMutateRow and ReadModifyWriteRow, matching ReadRow and MutateRow.

Change-Id: Ifa30efb0e07cf07495d753200bfec6d277f0e5e9
@mutianf
mutianf requested review from a team as code owners October 22, 2026 22:06

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new SessionScope enum to encapsulate per-method diversion scopes and their session load resolution rules. This refactoring unifies the diversion logic previously split across DivertingUnaryCallable and ClientConfigurationManager, ensuring consistency between per-RPC routing and client-wide session management. Additionally, retry settings are now correctly propagated to the default call context for check-and-mutate and read-modify-write row callables, and corresponding unit tests have been added or updated. There are no review comments, so I have no feedback to provide.

@mutianf mutianf added the kokoro:force-run Add this label to force Kokoro to re-run the tests. label Oct 23, 2026
@mutianf
mutianf enabled auto-merge (squash) October 23, 2026 01:28
@yoshi-kokoro yoshi-kokoro removed the kokoro:force-run Add this label to force Kokoro to re-run the tests. label Oct 23, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants