Skip to content

Commit 08c3299

Browse files
committed
database/sql: remove a distracting alloc, use atomic.Bool
This removes an allocation in Conn.grabConn that, while not super important, was distracting me when optimizing code elsewhere. While here, convert an atomic that was forgotten when this package was earlier updated to use the new Go 1.19 typed atomics. Change-Id: I4666256b4c0512e2162bd485c389130699f9d5ed Reviewed-on: https://go-review.googlesource.com/c/go/+/475415 Reviewed-by: David Crawshaw <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Cherry Mui <[email protected]> Run-TryBot: Brad Fitzpatrick <[email protected]>
1 parent 46bc9a6 commit 08c3299

File tree

2 files changed

+47
-6
lines changed

2 files changed

+47
-6
lines changed

src/database/sql/sql.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1947,20 +1947,27 @@ type Conn struct {
19471947
// it's returned to the connection pool.
19481948
dc *driverConn
19491949

1950-
// done transitions from 0 to 1 exactly once, on close.
1950+
// done transitions from false to true exactly once, on close.
19511951
// Once done, all operations fail with ErrConnDone.
1952-
// Use atomic operations on value when checking value.
1953-
done int32
1952+
done atomic.Bool
1953+
1954+
// releaseConn is a cache of c.closemuRUnlockCondReleaseConn
1955+
// to save allocations in a call to grabConn.
1956+
releaseConnOnce sync.Once
1957+
releaseConnCache releaseConn
19541958
}
19551959

19561960
// grabConn takes a context to implement stmtConnGrabber
19571961
// but the context is not used.
19581962
func (c *Conn) grabConn(context.Context) (*driverConn, releaseConn, error) {
1959-
if atomic.LoadInt32(&c.done) != 0 {
1963+
if c.done.Load() {
19601964
return nil, nil, ErrConnDone
19611965
}
1966+
c.releaseConnOnce.Do(func() {
1967+
c.releaseConnCache = c.closemuRUnlockCondReleaseConn
1968+
})
19621969
c.closemu.RLock()
1963-
return c.dc, c.closemuRUnlockCondReleaseConn, nil
1970+
return c.dc, c.releaseConnCache, nil
19641971
}
19651972

19661973
// PingContext verifies the connection to the database is still alive.
@@ -2084,7 +2091,7 @@ func (c *Conn) txCtx() context.Context {
20842091
}
20852092

20862093
func (c *Conn) close(err error) error {
2087-
if !atomic.CompareAndSwapInt32(&c.done, 0, 1) {
2094+
if !c.done.CompareAndSwap(false, true) {
20882095
return ErrConnDone
20892096
}
20902097

src/database/sql/sql_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99
"database/sql/driver"
1010
"errors"
1111
"fmt"
12+
"internal/race"
13+
"internal/testenv"
1214
"math/rand"
1315
"reflect"
1416
"runtime"
@@ -4583,3 +4585,35 @@ func BenchmarkManyConcurrentQueries(b *testing.B) {
45834585
}
45844586
})
45854587
}
4588+
4589+
func TestGrabConnAllocs(t *testing.T) {
4590+
testenv.SkipIfOptimizationOff(t)
4591+
if race.Enabled {
4592+
t.Skip("skipping allocation test when using race detector")
4593+
}
4594+
c := new(Conn)
4595+
ctx := context.Background()
4596+
n := int(testing.AllocsPerRun(1000, func() {
4597+
_, release, err := c.grabConn(ctx)
4598+
if err != nil {
4599+
t.Fatal(err)
4600+
}
4601+
release(nil)
4602+
}))
4603+
if n > 0 {
4604+
t.Fatalf("Conn.grabConn allocated %v objects; want 0", n)
4605+
}
4606+
}
4607+
4608+
func BenchmarkGrabConn(b *testing.B) {
4609+
b.ReportAllocs()
4610+
c := new(Conn)
4611+
ctx := context.Background()
4612+
for i := 0; i < b.N; i++ {
4613+
_, release, err := c.grabConn(ctx)
4614+
if err != nil {
4615+
b.Fatal(err)
4616+
}
4617+
release(nil)
4618+
}
4619+
}

0 commit comments

Comments
 (0)