feat(bigtable): add debug tag counter (recordDebugTag / assertDebugTag) - #20114
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces two new files in the bigtable/internal/transport package: debug_tracer.go, which implements a lightweight tracer for unexpected events using OTel metrics and in-memory stats, and transport_type_name.go, which maps transport type enums to short string labels. The code review feedback highlights a critical data race on the global debugTagCounter interface, suggesting the use of atomic.Value for thread-safe operations. Additionally, it recommends renaming bumpDebugTagCountLocked to remove the misleading Locked suffix and optimizing lock hold times in DebugTags by releasing the read lock before sorting the local slice.
b728bf6 to
5e1d21b
Compare
Adds the Session struct itself along with the two "surface" halves that have no lifecycle behavior of their own — the OTel tracer and the in-process debug counters / event ring. Also adds SessionHandle, the per-session slot the pool checkout / picker code holds. Lifecycle (Start / Close / readLoop / heartBeatLoop) and vRPC (Invoke) come next in the reshaped googleapis#20112. - session.go — Session struct + hooks + NewSession + State transitions (transitionTo, is/notState, signalQuiescent), vrpcResult, sessionErr, unavailable, afeID. Uses the existing State enum from session_state.go (PR googleapis#19981) — no re-declaration. - session_debug.go — embedded sessionDebug: counters (retries, okRpcs, errorRpcs, msgsSent, msgsRecv), per-session event ring, latency histogram, cluster-id map, WithSessionLogger / WithSessionPoolName options, RemoteAddr / SampleUptime / RecordTransportOverhead accessors. Consumes metrics.TransportTypeName (googleapis#20115) and recordDebugTag (googleapis#20114). - session_tracer.go — OTel sessionTracer for per-session + per-attempt metrics (session duration, open latency, uptime, transport-overhead histogram). Consumes metrics.TransportTypeName. - picker.go — SessionHandle wrapping *Session with the per-pick counters (Picks, Outstanding, LastActivity) the pool needs. Its concrete users (SessionPool, AFE picker) come in later PRs; the handle type is here because Session embeds an atomic.Pointer to it. Part 3b/3c of the Session core sub-split. Stacks on bigtable-session-primitives (Part 3a), googleapis#20115 (metrics.TransportTypeName export), and googleapis#20114 (debug tag counter).
Adds the behavior half of the Session — the lifecycle state machine, the vRPC dispatch path, and the fake-driven test suite that exercises both. Together with the struct + surface half (bigtable-session-struct) and the primitives (bigtable-session-primitives), this completes the Session core. - session_lifecycle.go — Start, ForceClose, Close, Send, readLoop, heartBeatLoop, handleOpenSession / handleErrorResponse / handleGoAway / handleClose / handleSessionParameters, peerInfoExtracter. - session_vrpc.go — Invoke, buildInvokeRequest, awaitInvokeResult, handleVRPCResponse / handleVRPCErrorResponse, deliver, cancelActiveRPCs, noteRetryAttempt, releaseSlot. - session_test.go — fakeStream / fakeDesc plus tests for handleOpenSession, handleVRPC*, handleGoAway, handleErrorResponse, Invoke, ForceClose, Close, heartBeatLoop, PeerInfo extraction, AfeID, Start. Also folds in the pending gemini-code-assist review findings so this PR merges without a follow-up: - Fire onStart immediately after transitionTo(StateStarting) so the "onStart precedes onClose" invariant holds even when Send fails and ForceClose fires onClose. - Nil-guard handleErrorResponse / handleSessionParameters / handleVRPCResponse / handleVRPCErrorResponse and the res.resp branch in awaitInvokeResult; drop instead of panicking in the readLoop goroutine. - Retag pre-wire Send failures in Invoke as StateUncommitted (was StateTransportFailure) so the retry interceptor can retry non-idempotent ops when the frame never reached the server — Java parity with java-bigtable's classification. Part 3c of 3 in the Session core sub-split. Stacks on bigtable-session-struct (Part 3b), bigtable-session-primitives (Part 3a), googleapis#20115 (metrics.TransportTypeName), and googleapis#20114 (debug tag counter).
Adds the transport-package debug-tag counter used at "this branch shouldn't reach" sites in the Session, session pool, and configuration manager. Every emission is one atomic add plus one OTel Int64Counter increment; safe to sprinkle freely on cold paths. Metric name (`debug_tags`) matches java-bigtable's `ClientDebugTagCount` so cross-language dashboards join on the tag column. Provides: - `recordDebugTag(name)` — cheap observation counter (Warn level). - `recordDebugTagAt(level, name)` — same, with an explicit level. - `assertDebugTag(expr, name)` / `assertDebugTagf` — invariant checks that increment the counter and log at Error level when they fail. - `DebugTags()` + `snapshotDebugTagCounts()` — read-side for debug pages. - Tag catalog constants (`tagSession*`, `tagVRPC*`, etc.) referenced from Session-lifecycle and vRPC code in the follow-up PRs. Standalone — the Session/vRPC code that emits these tags lands in the Session core PR stacked on top. **Part 2/3 of the Session core split.** Stacked on googleapis#20113 (TransportTypeName).
5e1d21b to
27fd0bf
Compare
…type) Adds the standalone types that the Session struct and its lifecycle / vRPC / debug halves all depend on. Each file is self-contained (no cross-references) so this PR compiles and passes tests on its own. - attempt_outcome.go — AttemptState (StateUncommitted / StateTransportFailure / StateServerResult), tagErr, TagErr, ClassifyErr. Models Java's VRpc.VRpcResult.State so the RetryingVRpc interceptor (later PR) can classify errors the same way as java-bigtable. - vrpc.go — ctx-metadata helpers (WithVRpcMetadata, WithAttempt, VRpcAttempt, VRpcMethod, WithPrevAttemptErr, PrevAttemptErr). Session Invoke reads these from its ctx. - session_msgtype.go — reqMsgType / respMsgType enums + classifyReq / classifyResp helpers. Used by the debug surface + tracer to bucket Session request/response types. Part 3a/3c of the Session core sub-split (a follow-up to the original Session core PR googleapis#20112, which is being reshaped into three thinner PRs). Stacks on googleapis#20115 (metrics.TransportTypeName export) and googleapis#20114 (debug tag counter); each of those can merge in any order.
Adds the Session struct itself along with the two "surface" halves that have no lifecycle behavior of their own — the OTel tracer and the in-process debug counters / event ring. Also adds SessionHandle, the per-session slot the pool checkout / picker code holds. Lifecycle (Start / Close / readLoop / heartBeatLoop) and vRPC (Invoke) come next in the reshaped googleapis#20112. - session.go — Session struct + hooks + NewSession + State transitions (transitionTo, is/notState, signalQuiescent), vrpcResult, sessionErr, unavailable, afeID. Uses the existing State enum from session_state.go (PR googleapis#19981) — no re-declaration. - session_debug.go — embedded sessionDebug: counters (retries, okRpcs, errorRpcs, msgsSent, msgsRecv), per-session event ring, latency histogram, cluster-id map, WithSessionLogger / WithSessionPoolName options, RemoteAddr / SampleUptime / RecordTransportOverhead accessors. Consumes metrics.TransportTypeName (googleapis#20115) and recordDebugTag (googleapis#20114). - session_tracer.go — OTel sessionTracer for per-session + per-attempt metrics (session duration, open latency, uptime, transport-overhead histogram). Consumes metrics.TransportTypeName. - picker.go — SessionHandle wrapping *Session with the per-pick counters (Picks, Outstanding, LastActivity) the pool needs. Its concrete users (SessionPool, AFE picker) come in later PRs; the handle type is here because Session embeds an atomic.Pointer to it. Part 3b/3c of the Session core sub-split. Stacks on bigtable-session-primitives (Part 3a), googleapis#20115 (metrics.TransportTypeName export), and googleapis#20114 (debug tag counter).
Adds the behavior half of the Session — the lifecycle state machine, the vRPC dispatch path, and the fake-driven test suite that exercises both. Together with the struct + surface half (bigtable-session-struct) and the primitives (bigtable-session-primitives), this completes the Session core. - session_lifecycle.go — Start, ForceClose, Close, Send, readLoop, heartBeatLoop, handleOpenSession / handleErrorResponse / handleGoAway / handleClose / handleSessionParameters, peerInfoExtracter. - session_vrpc.go — Invoke, buildInvokeRequest, awaitInvokeResult, handleVRPCResponse / handleVRPCErrorResponse, deliver, cancelActiveRPCs, noteRetryAttempt, releaseSlot. - session_test.go — fakeStream / fakeDesc plus tests for handleOpenSession, handleVRPC*, handleGoAway, handleErrorResponse, Invoke, ForceClose, Close, heartBeatLoop, PeerInfo extraction, AfeID, Start. Also folds in the pending gemini-code-assist review findings so this PR merges without a follow-up: - Fire onStart immediately after transitionTo(StateStarting) so the "onStart precedes onClose" invariant holds even when Send fails and ForceClose fires onClose. - Nil-guard handleErrorResponse / handleSessionParameters / handleVRPCResponse / handleVRPCErrorResponse and the res.resp branch in awaitInvokeResult; drop instead of panicking in the readLoop goroutine. - Retag pre-wire Send failures in Invoke as StateUncommitted (was StateTransportFailure) so the retry interceptor can retry non-idempotent ops when the frame never reached the server — Java parity with java-bigtable's classification. Part 3c of 3 in the Session core sub-split. Stacks on bigtable-session-struct (Part 3b), bigtable-session-primitives (Part 3a), googleapis#20115 (metrics.TransportTypeName), and googleapis#20114 (debug tag counter).
…type) Adds the standalone types that the Session struct and its lifecycle / vRPC / debug halves all depend on. Each file is self-contained (no cross-references) so this PR compiles and passes tests on its own. - attempt_outcome.go — AttemptState (StateUncommitted / StateTransportFailure / StateServerResult), tagErr, TagErr, ClassifyErr. Models Java's VRpc.VRpcResult.State so the RetryingVRpc interceptor (later PR) can classify errors the same way as java-bigtable. - vrpc.go — ctx-metadata helpers (WithVRpcMetadata, WithAttempt, VRpcAttempt, VRpcMethod, WithPrevAttemptErr, PrevAttemptErr). Session Invoke reads these from its ctx. - session_msgtype.go — reqMsgType / respMsgType enums + classifyReq / classifyResp helpers. Used by the debug surface + tracer to bucket Session request/response types. Part 3a/3c of the Session core sub-split (a follow-up to the original Session core PR googleapis#20112, which is being reshaped into three thinner PRs). Stacks on googleapis#20115 (metrics.TransportTypeName export) and googleapis#20114 (debug tag counter); each of those can merge in any order.
Adds the Session struct itself along with the two "surface" halves that have no lifecycle behavior of their own — the OTel tracer and the in-process debug counters / event ring. Also adds SessionHandle, the per-session slot the pool checkout / picker code holds. Lifecycle (Start / Close / readLoop / heartBeatLoop) and vRPC (Invoke) come next in the reshaped googleapis#20112. - session.go — Session struct + hooks + NewSession + State transitions (transitionTo, is/notState, signalQuiescent), vrpcResult, sessionErr, unavailable, afeID. Uses the existing State enum from session_state.go (PR googleapis#19981) — no re-declaration. - session_debug.go — embedded sessionDebug: counters (retries, okRpcs, errorRpcs, msgsSent, msgsRecv), per-session event ring, latency histogram, cluster-id map, WithSessionLogger / WithSessionPoolName options, RemoteAddr / SampleUptime / RecordTransportOverhead accessors. Consumes metrics.TransportTypeName (googleapis#20115) and recordDebugTag (googleapis#20114). - session_tracer.go — OTel sessionTracer for per-session + per-attempt metrics (session duration, open latency, uptime, transport-overhead histogram). Consumes metrics.TransportTypeName. - picker.go — SessionHandle wrapping *Session with the per-pick counters (Picks, Outstanding, LastActivity) the pool needs. Its concrete users (SessionPool, AFE picker) come in later PRs; the handle type is here because Session embeds an atomic.Pointer to it. Part 3b/3c of the Session core sub-split. Stacks on bigtable-session-primitives (Part 3a), googleapis#20115 (metrics.TransportTypeName export), and googleapis#20114 (debug tag counter).
Adds the behavior half of the Session — the lifecycle state machine, the vRPC dispatch path, and the fake-driven test suite that exercises both. Together with the struct + surface half (bigtable-session-struct) and the primitives (bigtable-session-primitives), this completes the Session core. - session_lifecycle.go — Start, ForceClose, Close, Send, readLoop, heartBeatLoop, handleOpenSession / handleErrorResponse / handleGoAway / handleClose / handleSessionParameters, peerInfoExtracter. - session_vrpc.go — Invoke, buildInvokeRequest, awaitInvokeResult, handleVRPCResponse / handleVRPCErrorResponse, deliver, cancelActiveRPCs, noteRetryAttempt, releaseSlot. - session_test.go — fakeStream / fakeDesc plus tests for handleOpenSession, handleVRPC*, handleGoAway, handleErrorResponse, Invoke, ForceClose, Close, heartBeatLoop, PeerInfo extraction, AfeID, Start. Also folds in the pending gemini-code-assist review findings so this PR merges without a follow-up: - Fire onStart immediately after transitionTo(StateStarting) so the "onStart precedes onClose" invariant holds even when Send fails and ForceClose fires onClose. - Nil-guard handleErrorResponse / handleSessionParameters / handleVRPCResponse / handleVRPCErrorResponse and the res.resp branch in awaitInvokeResult; drop instead of panicking in the readLoop goroutine. - Retag pre-wire Send failures in Invoke as StateUncommitted (was StateTransportFailure) so the retry interceptor can retry non-idempotent ops when the frame never reached the server — Java parity with java-bigtable's classification. Part 3c of 3 in the Session core sub-split. Stacks on bigtable-session-struct (Part 3b), bigtable-session-primitives (Part 3a), googleapis#20115 (metrics.TransportTypeName), and googleapis#20114 (debug tag counter).
Address gemini-code-assist review on googleapis#20114: - Store debugTagCounter in an atomic.Value so the register-once write and every-emission reads don't race on the two-word interface value. - Rename bumpDebugTagCountLocked -> bumpDebugTagCount; it handles its own locking, so the "Locked" suffix (which conventionally means the caller holds the lock) was misleading. - Release DebugTags()'s RLock before sorting the local snapshot slice. The sort touches no shared state and there's no reason to hold the read lock across it.
Insert a blank line between the file-level how-to-use block and `package internal` so golint doesn't misread the block as the package comment and complain that it should be of the form "Package internal ...". The block documents the file, not the package — the detached form is the idiomatic fix.
Cut redundant prose across the file, function, and variable comments — the essential "why" and Java-parity notes stay, but the how-to-use material collapses to an entry-point list and three rules. Net -74 lines of comment weight; no behavior change.
| // java-bigtable); Go identifiers are camelCase. Grep either form to | ||
| // jump between the definition and its emission sites. | ||
| const ( | ||
| // Session-lifecycle observations. |
There was a problem hiding this comment.
should we have the same list as java?
SessionPoolImpl.java
- session_pool_drained_future_failed (ERROR) — SessionPoolImpl.java:347
- session_pool_no_budget (WARN) — SessionPoolImpl.java:405
- watchdog_close_session (WARN) — SessionPoolImpl.java:957
SessionImpl.java
- session_close_no_reason (WARN) — SessionImpl.java:385 and SessionImpl.java:783
- session_closed_discard_vrpc_response (WARN) — SessionImpl.java:574 and SessionImpl.java:644
- session_go_away_ignored (WARN) — SessionImpl.java:692
- session_unknown_response (WARN) — SessionImpl.java:720
- session_abnormal_close (WARN) — SessionImpl.java:740
And I'll port the ones that's not in java over.
…type) Adds the standalone types that the Session struct and its lifecycle / vRPC / debug halves all depend on. Each file is self-contained (no cross-references) so this PR compiles and passes tests on its own. - attempt_outcome.go — AttemptState (StateUncommitted / StateTransportFailure / StateServerResult), tagErr, TagErr, ClassifyErr. Models Java's VRpc.VRpcResult.State so the RetryingVRpc interceptor (later PR) can classify errors the same way as java-bigtable. - vrpc.go — ctx-metadata helpers (WithVRpcMetadata, WithAttempt, VRpcAttempt, VRpcMethod, WithPrevAttemptErr, PrevAttemptErr). Session Invoke reads these from its ctx. - session_msgtype.go — reqMsgType / respMsgType enums + classifyReq / classifyResp helpers. Used by the debug surface + tracer to bucket Session request/response types. Part 3a/3c of the Session core sub-split (a follow-up to the original Session core PR googleapis#20112, which is being reshaped into three thinner PRs). Stacks on googleapis#20115 (metrics.TransportTypeName export) and googleapis#20114 (debug tag counter); each of those can merge in any order.
…type) Adds the standalone types that the Session struct and its lifecycle / vRPC / debug halves all depend on. Each file is self-contained (no cross-references) so this PR compiles and passes tests on its own. - attempt_outcome.go — AttemptState (StateUncommitted / StateTransportFailure / StateServerResult), tagErr, TagErr, ClassifyErr. Models Java's VRpc.VRpcResult.State so the RetryingVRpc interceptor (later PR) can classify errors the same way as java-bigtable. - vrpc.go — ctx-metadata helpers (WithVRpcMetadata, WithAttempt, VRpcAttempt, VRpcMethod, WithPrevAttemptErr, PrevAttemptErr). Session Invoke reads these from its ctx. - session_msgtype.go — reqMsgType / respMsgType enums + classifyReq / classifyResp helpers. Used by the debug surface + tracer to bucket Session request/response types. Part 3a/3c of the Session core sub-split (a follow-up to the original Session core PR googleapis#20112, which is being reshaped into three thinner PRs). Stacks on googleapis#20115 (metrics.TransportTypeName export) and googleapis#20114 (debug tag counter); each of those can merge in any order.
Adds the Session struct itself along with the two "surface" halves that have no lifecycle behavior of their own — the OTel tracer and the in-process debug counters / event ring. Also adds SessionHandle, the per-session slot the pool checkout / picker code holds. Lifecycle (Start / Close / readLoop / heartBeatLoop) and vRPC (Invoke) come next in the reshaped googleapis#20112. - session.go — Session struct + hooks + NewSession + State transitions (transitionTo, is/notState, signalQuiescent), vrpcResult, sessionErr, unavailable, afeID. Uses the existing State enum from session_state.go (PR googleapis#19981) — no re-declaration. - session_debug.go — embedded sessionDebug: counters (retries, okRpcs, errorRpcs, msgsSent, msgsRecv), per-session event ring, latency histogram, cluster-id map, WithSessionLogger / WithSessionPoolName options, RemoteAddr / SampleUptime / RecordTransportOverhead accessors. Consumes metrics.TransportTypeName (googleapis#20115) and recordDebugTag (googleapis#20114). - session_tracer.go — OTel sessionTracer for per-session + per-attempt metrics (session duration, open latency, uptime, transport-overhead histogram). Consumes metrics.TransportTypeName. - picker.go — SessionHandle wrapping *Session with the per-pick counters (Picks, Outstanding, LastActivity) the pool needs. Its concrete users (SessionPool, AFE picker) come in later PRs; the handle type is here because Session embeds an atomic.Pointer to it. Part 3b/3c of the Session core sub-split. Stacks on bigtable-session-primitives (Part 3a), googleapis#20115 (metrics.TransportTypeName export), and googleapis#20114 (debug tag counter).
…type) Adds the standalone types that the Session struct and its lifecycle / vRPC / debug halves all depend on. Each file is self-contained (no cross-references) so this PR compiles and passes tests on its own. - attempt_outcome.go — AttemptState (StateUncommitted / StateTransportFailure / StateServerResult), tagErr, TagErr, ClassifyErr. Models Java's VRpc.VRpcResult.State so the RetryingVRpc interceptor (later PR) can classify errors the same way as java-bigtable. - vrpc.go — ctx-metadata helpers (WithVRpcMetadata, WithAttempt, VRpcAttempt, VRpcMethod, WithPrevAttemptErr, PrevAttemptErr). Session Invoke reads these from its ctx. - session_msgtype.go — reqMsgType / respMsgType enums + classifyReq / classifyResp helpers. Used by the debug surface + tracer to bucket Session request/response types. Part 3a/3c of the Session core sub-split (a follow-up to the original Session core PR googleapis#20112, which is being reshaped into three thinner PRs). Stacks on googleapis#20115 (metrics.TransportTypeName export) and googleapis#20114 (debug tag counter); each of those can merge in any order.
Adds the Session struct itself along with the two "surface" halves that have no lifecycle behavior of their own — the OTel tracer and the in-process debug counters / event ring. Also adds SessionHandle, the per-session slot the pool checkout / picker code holds. Lifecycle (Start / Close / readLoop / heartBeatLoop) and vRPC (Invoke) come next in the reshaped googleapis#20112. - session.go — Session struct + hooks + NewSession + State transitions (transitionTo, is/notState, signalQuiescent), vrpcResult, sessionErr, unavailable, afeID. Uses the existing State enum from session_state.go (PR googleapis#19981) — no re-declaration. - session_debug.go — embedded sessionDebug: counters (retries, okRpcs, errorRpcs, msgsSent, msgsRecv), per-session event ring, latency histogram, cluster-id map, WithSessionLogger / WithSessionPoolName options, RemoteAddr / SampleUptime / RecordTransportOverhead accessors. Consumes metrics.TransportTypeName (googleapis#20115) and recordDebugTag (googleapis#20114). - session_tracer.go — OTel sessionTracer for per-session + per-attempt metrics (session duration, open latency, uptime, transport-overhead histogram). Consumes metrics.TransportTypeName. - picker.go — SessionHandle wrapping *Session with the per-pick counters (Picks, Outstanding, LastActivity) the pool needs. Its concrete users (SessionPool, AFE picker) come in later PRs; the handle type is here because Session embeds an atomic.Pointer to it. Part 3b/3c of the Session core sub-split. Stacks on bigtable-session-primitives (Part 3a), googleapis#20115 (metrics.TransportTypeName export), and googleapis#20114 (debug tag counter).
Adds the behavior half of the Session — the lifecycle state machine, the vRPC dispatch path, and the fake-driven test suite that exercises both. Together with the struct + surface half (bigtable-session-struct) and the primitives (bigtable-session-primitives), this completes the Session core. - session_lifecycle.go — Start, ForceClose, Close, Send, readLoop, heartBeatLoop, handleOpenSession / handleErrorResponse / handleGoAway / handleClose / handleSessionParameters, peerInfoExtracter. - session_vrpc.go — Invoke, buildInvokeRequest, awaitInvokeResult, handleVRPCResponse / handleVRPCErrorResponse, deliver, cancelActiveRPCs, noteRetryAttempt, releaseSlot. - session_test.go — fakeStream / fakeDesc plus tests for handleOpenSession, handleVRPC*, handleGoAway, handleErrorResponse, Invoke, ForceClose, Close, heartBeatLoop, PeerInfo extraction, AfeID, Start. Also folds in the pending gemini-code-assist review findings so this PR merges without a follow-up: - Fire onStart immediately after transitionTo(StateStarting) so the "onStart precedes onClose" invariant holds even when Send fails and ForceClose fires onClose. - Nil-guard handleErrorResponse / handleSessionParameters / handleVRPCResponse / handleVRPCErrorResponse and the res.resp branch in awaitInvokeResult; drop instead of panicking in the readLoop goroutine. - Retag pre-wire Send failures in Invoke as StateUncommitted (was StateTransportFailure) so the retry interceptor can retry non-idempotent ops when the frame never reached the server — Java parity with java-bigtable's classification. Part 3c of 3 in the Session core sub-split. Stacks on bigtable-session-struct (Part 3b), bigtable-session-primitives (Part 3a), googleapis#20115 (metrics.TransportTypeName), and googleapis#20114 (debug tag counter).
…type) Adds the standalone types that the Session struct and its lifecycle / vRPC / debug halves all depend on. Each file is self-contained (no cross-references) so this PR compiles and passes tests on its own. - attempt_outcome.go — AttemptState (StateUncommitted / StateTransportFailure / StateServerResult), tagErr, TagErr, ClassifyErr. Models Java's VRpc.VRpcResult.State so the RetryingVRpc interceptor (later PR) can classify errors the same way as java-bigtable. - vrpc.go — ctx-metadata helpers (WithVRpcMetadata, WithAttempt, VRpcAttempt, VRpcMethod, WithPrevAttemptErr, PrevAttemptErr). Session Invoke reads these from its ctx. - session_msgtype.go — reqMsgType / respMsgType enums + classifyReq / classifyResp helpers. Used by the debug surface + tracer to bucket Session request/response types. Part 3a/3c of the Session core sub-split (a follow-up to the original Session core PR googleapis#20112, which is being reshaped into three thinner PRs). Stacks on googleapis#20115 (metrics.TransportTypeName export) and googleapis#20114 (debug tag counter); each of those can merge in any order.
…type) (#20116) ## Summary Adds the standalone types that the Session struct and its lifecycle / vRPC / debug halves all depend on. Each file is self-contained (no cross-references) so this PR compiles and passes tests on its own. - **`attempt_outcome.go`** — `AttemptState` (`StateUncommitted` / `StateTransportFailure` / `StateServerResult`), `tagErr`, `TagErr`, `ClassifyErr`. Models Java's `VRpc.VRpcResult.State` so the `RetryingVRpc` interceptor (later PR) can classify errors the same way as java-bigtable. - **`vrpc.go`** — ctx-metadata helpers (`WithVRpcMetadata`, `WithAttempt`, `VRpcAttempt`, `VRpcMethod`, `WithPrevAttemptErr`, `PrevAttemptErr`). `Session.Invoke` reads these from its ctx. - **`session_msgtype.go`** — `reqMsgType` / `respMsgType` enums + `classifyReq` / `classifyResp` helpers. Used by the debug surface + tracer to bucket Session request/response types. **Part 3a of 3 in the Session core sub-split** (a follow-up to the original Session core PR #20112, which is being reshaped into three thinner PRs). Stacks on #20115 (`metrics.TransportTypeName` export) and #20114 (debug tag counter); each of those can merge in any order. Sub-split order: 1. **3a — this PR:** Session primitives (~337 LOC). 2. **3b — TBD:** Session struct + tracer + debug surface + picker (~1.1k LOC). 3. **3c — reshaped #20112:** Session lifecycle + vRPC + tests (~2k LOC). ## Test plan - [x] `go build ./bigtable/...` - [x] `go test ./bigtable/internal/transport/ -count=1 -short` — passes (4.0s) - [x] `gofmt -l bigtable/internal/transport/` — clean - [ ] CI: presubmit
Adds the Session struct itself along with the two "surface" halves that have no lifecycle behavior of their own — the OTel tracer and the in-process debug counters / event ring. Also adds SessionHandle, the per-session slot the pool checkout / picker code holds. Lifecycle (Start / Close / readLoop / heartBeatLoop) and vRPC (Invoke) come next in the reshaped googleapis#20112. - session.go — Session struct + hooks + NewSession + State transitions (transitionTo, is/notState, signalQuiescent), vrpcResult, sessionErr, unavailable, afeID. Uses the existing State enum from session_state.go (PR googleapis#19981) — no re-declaration. - session_debug.go — embedded sessionDebug: counters (retries, okRpcs, errorRpcs, msgsSent, msgsRecv), per-session event ring, latency histogram, cluster-id map, WithSessionLogger / WithSessionPoolName options, RemoteAddr / SampleUptime / RecordTransportOverhead accessors. Consumes metrics.TransportTypeName (googleapis#20115) and recordDebugTag (googleapis#20114). - session_tracer.go — OTel sessionTracer for per-session + per-attempt metrics (session duration, open latency, uptime, transport-overhead histogram). Consumes metrics.TransportTypeName. - picker.go — SessionHandle wrapping *Session with the per-pick counters (Picks, Outstanding, LastActivity) the pool needs. Its concrete users (SessionPool, AFE picker) come in later PRs; the handle type is here because Session embeds an atomic.Pointer to it. Part 3b/3c of the Session core sub-split. Stacks on bigtable-session-primitives (Part 3a), googleapis#20115 (metrics.TransportTypeName export), and googleapis#20114 (debug tag counter).
🤖 I have created a release *beep* *boop* --- ## [1.51.0](bigtable/v1.50.0...bigtable/v1.51.0) (2026-07-23) ### Features * **bigtable:** Add ChainInterceptors and RetryingVRpc for vRPC pipeline ([#20185](#20185)) ([c7a832a](c7a832a)) * **bigtable:** Add ClientConfigurationManager ([#19986](#19986)) ([3a8f927](3a8f927)) * **bigtable:** Add debug tag counter (recordDebugTag / assertDebugTag) ([#20114](#20114)) ([3c97590](3c97590)) * **bigtable:** Add lazyPool helper for on-demand session pool opening ([#20182](#20182)) ([f6ae3fb](f6ae3fb)) * **bigtable:** Add PeakEwma continuous time-decay latency tracker ([#20187](#20187)) ([9d124ef](9d124ef)) * **bigtable:** Add PoolSizer for server-driven session pool capacity ([#20189](#20189)) ([57ebbeb](57ebbeb)) * **bigtable:** Add session package with SessionClient + SessionTableAPI interfaces ([#20180](#20180)) ([4b82fd2](4b82fd2)) * **bigtable:** Add Session primitives (AttemptOutcome, vRPC ctx, msgtype) ([#20116](#20116)) ([e1011e2](e1011e2)) * **bigtable:** Add Session state enum ([#19981](#19981)) ([0748972](0748972)) * **bigtable:** Add SessionThrottler / AdaptiveSessionThrottler for OpenSession pacing ([#20184](#20184)) ([02e3c6d](02e3c6d)) * **bigtable:** Add SessionThrottler / AdaptiveSessionThrottler for OpenSession pacing ([#20184](#20184)) ([29be83e](29be83e)) * **bigtable:** Add sessionTracer for per-Session lifecycle + vRPC metrics ([#20190](#20190)) ([a466345](a466345)) * **bigtable:** Enable new auth library and JWT for instance admin client ([#20013](#20013)) ([21c4a44](21c4a44)) * **bigtable:** Modularize channel priming behind a ChannelPrimer interface ([#20027](#20027)) ([5214ab7](5214ab7)) * **bigtable:** Modularize Direct Access compatibility check ([#19987](#19987)) ([a25e93d](a25e93d)) * **o11y:** Regenerate clients for LRO tracing ([#20107](#20107)) ([779074e](779074e)) ### Bug Fixes * **bigtable:** Default cluster/zone in toOtelMetricAttrs to avoid Monitoring reject ([#20178](#20178)) ([14493f4](14493f4)) * **bigtable:** Eliminate stats-handler MD race in internal/metrics tracer ([#20158](#20158)) ([c387066](c387066)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
Summary
Adds the transport-package debug-tag counter used at "this branch shouldn't reach" sites in the Session, session pool, and configuration manager. Every emission is one atomic add plus one OTel
Int64Counterincrement; safe to sprinkle freely on cold paths. Metric name (debug_tags) matches java-bigtable'sClientDebugTagCountso cross-language dashboards join on the tag column.Provides:
recordDebugTag(name)— cheap observation counter (Warn level).recordDebugTagAt(level, name)— same, with an explicit level.assertDebugTag(expr, name)/assertDebugTagf— invariant checks that increment the counter and log at Error level when they fail.DebugTags()+snapshotDebugTagCounts()— read-side for debug pages.tagSession*,tagVRPC*, etc.) referenced from Session-lifecycle and vRPC code in the follow-up PR.Standalone — the Session/vRPC code that emits these tags lands in the Session core PR (#20112) stacked on top. Independent of #20115 (metrics
TransportTypeNameexport); the two can merge in any order.Part 2/3 of the Session core split.
Test plan
go build ./bigtable/...go vet ./bigtable/internal/transport/...debug_tracer_test.golands in a follow-up along with a broader test-only split)