Skip to content

bigquery/storage/managedwriter: resolvePool holds client mutex across GetWriteStream, serializing concurrent stream opens #20173

Description

@joy-twilio

Client

BigQuery Storage Write — bigquery/storage/managedwriter

Description

Client.resolvePool (bigquery/storage/managedwriter/client.go) holds the client-wide c.mu across the GetWriteStream RPC it uses to discover a stream's region:

func (c *Client) resolvePool(ctx context.Context, settings *streamSettings, streamFunc streamClientFunc) (*connectionPool, error) {
    c.mu.Lock()
    defer c.mu.Unlock()
    resp, err := c.getWriteStream(ctx, settings.streamID, false) // network RPC, under the lock
    ...
}

That GetWriteStream RPC touches no shared state (only the immutable rawClient) — the lock exists solely to guard the pools map. Holding it across the RPC serializes every concurrent NewManagedStream/resolvePool on a client behind a single ~one-RTT call.

Impact: for workloads that open streams frequently (e.g. opening a stream per write on the _default stream), open latency grows linearly with concurrency. Measured cross-region (AWS us-west-2 → BigQuery US multi-region): a single uncontended open is ~115ms, but at 20 concurrent opens on one client, open latency rises to ~1s (≈ 115ms × workers) and throughput plateaus because opens cannot overlap. The RPC itself is fast; the mutex scope is the bottleneck. Present through the latest release and main.

Proposed fix: move the GetWriteStream call outside the lock and take c.mu only for the pools map lookup/insert. The lookup and createPool stay atomic under the lock, so the create-once-per-location invariant is unchanged. I have a branch + regression test ready and will open a PR referencing this issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    api: bigqueryIssues related to the BigQuery API.

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions