Commit b51da29
authored
fix(bigtable): guard NewStream OnFinish against grpc-go double-fire (#20295)
## Summary
grpc-go v1.82.x can invoke a registered `grpc.OnFinish` callback more
than once on some stream-creation failure paths (closed `ClientConn` is
the observed one: the retry unwinder fires it once from inside
`withRetry`, then `newClientStream`'s deferred stream-teardown fires it
again). Compounding that, the old `BigtableChannelPool.NewStream` also
manually decremented `streamingLoad` on the returned-error path assuming
OnFinish had NOT fired. Combined: `streamingLoad` went 2–3 decrements
deep per failed NewStream. Debug pages surfaced this as **\"Streaming in
flight: -9\"** on an idle classic pool.
## Fix
Trust `OnFinish` as the single source of truth for load accounting +
error attribution. Gate the callback body with
`atomic.Bool.CompareAndSwap(false, true)` so it runs exactly once
regardless of how many times grpc-go fires it. Belt-and-suspenders:
after `entry.conn.NewStream` returns an error, call the same accounting
closure directly — the CAS makes it a no-op if grpc-go already fired,
and it covers the zero-fire path if grpc-go ever returns an error
without arming OnFinish.
- Live path: one atomic Load per NewStream on the happy path; cache-map
lookup only on the recovery branch.
- Non-goal: no changes to per-attempt tracer / metric emission logic.
## Test plan
- [x] New regression test
\`TestPoolNewStream/ImmediateFailureLoadStaysNonNegative\` — closes the
underlying \`ClientConn\`, calls \`NewStream\` 5×, asserts
\`streamingLoad >= 0\` after each and \`== 0\` at end. Fails on pre-fix
code with \`streamingLoad\` going to \`-5\`.
- [x] New coverage test
\`TestPoolNewStream/OnFinishFiresAtLeastOncePerFailedNewStream\` — wraps
a user OnFinish counter around each NewStream on a closed conn, asserts
fires ∈ {1, 2, 3} — pins the \"at least once\" invariant the whole fix
leans on, and cries out early if grpc-go ever regresses to zero-fire.
- [x] Existing \`TestPoolNewStream\` subtests unchanged and passing
(\`Strategy_least_in_flight\`, \`Strategy_round_robin\`,
\`Strategy_power_of_two_least_in_flight\`, \`EmptyPoolNewStream\`,
\`NewStreamServerError\`).
- [x] \`go test ./internal/transport/ -race -count=1 -short\` clean.1 parent 425445d commit b51da29
2 files changed
Lines changed: 72 additions & 12 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
769 | 769 | | |
770 | 770 | | |
771 | 771 | | |
772 | | - | |
773 | | - | |
774 | | - | |
775 | | - | |
776 | | - | |
| 772 | + | |
| 773 | + | |
| 774 | + | |
| 775 | + | |
| 776 | + | |
| 777 | + | |
| 778 | + | |
| 779 | + | |
| 780 | + | |
| 781 | + | |
| 782 | + | |
| 783 | + | |
| 784 | + | |
| 785 | + | |
| 786 | + | |
| 787 | + | |
| 788 | + | |
| 789 | + | |
| 790 | + | |
| 791 | + | |
777 | 792 | | |
778 | 793 | | |
779 | 794 | | |
| |||
782 | 797 | | |
783 | 798 | | |
784 | 799 | | |
785 | | - | |
| 800 | + | |
| 801 | + | |
| 802 | + | |
| 803 | + | |
| 804 | + | |
| 805 | + | |
| 806 | + | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
786 | 810 | | |
787 | 811 | | |
788 | 812 | | |
789 | 813 | | |
790 | 814 | | |
791 | | - | |
| 815 | + | |
792 | 816 | | |
793 | 817 | | |
794 | 818 | | |
795 | | - | |
| 819 | + | |
796 | 820 | | |
797 | 821 | | |
798 | 822 | | |
799 | | - | |
800 | | - | |
801 | | - | |
| 823 | + | |
| 824 | + | |
| 825 | + | |
| 826 | + | |
| 827 | + | |
802 | 828 | | |
803 | 829 | | |
804 | | - | |
805 | 830 | | |
806 | 831 | | |
807 | 832 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
631 | 631 | | |
632 | 632 | | |
633 | 633 | | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
| 648 | + | |
| 649 | + | |
| 650 | + | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
| 660 | + | |
| 661 | + | |
| 662 | + | |
| 663 | + | |
| 664 | + | |
| 665 | + | |
| 666 | + | |
| 667 | + | |
| 668 | + | |
634 | 669 | | |
635 | 670 | | |
636 | 671 | | |
| |||
0 commit comments