mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
database/sql: do not exhaust connection pool on conn request timeout
Previously if a context was canceled while it was waiting for a connection request, that connection request would leak. To prevent this remove the pending connection request if the context is canceled and ensure no connection has been sent on the channel. This requires a change to how the connection requests are represented in the DB. Fixes #18995 Change-Id: I9a274b48b8f4f7ca46cdee166faa38f56d030852 Reviewed-on: https://go-review.googlesource.com/36563 Reviewed-by: Russ Cox <rsc@golang.org> Run-TryBot: Russ Cox <rsc@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
c57d91e34c
commit
4f6d4bb3f4
2 changed files with 93 additions and 13 deletions
|
|
@ -531,6 +531,63 @@ func TestQueryNamedArg(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestPoolExhaustOnCancel(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("long test")
|
||||
}
|
||||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
|
||||
max := 3
|
||||
|
||||
db.SetMaxOpenConns(max)
|
||||
|
||||
// First saturate the connection pool.
|
||||
// Then start new requests for a connection that is cancelled after it is requested.
|
||||
|
||||
var saturate, saturateDone sync.WaitGroup
|
||||
saturate.Add(max)
|
||||
saturateDone.Add(max)
|
||||
|
||||
for i := 0; i < max; i++ {
|
||||
go func() {
|
||||
saturate.Done()
|
||||
rows, err := db.Query("WAIT|500ms|SELECT|people|name,photo|")
|
||||
if err != nil {
|
||||
t.Fatalf("Query: %v", err)
|
||||
}
|
||||
rows.Close()
|
||||
saturateDone.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
saturate.Wait()
|
||||
|
||||
// Now cancel the request while it is waiting.
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
||||
defer cancel()
|
||||
|
||||
for i := 0; i < max; i++ {
|
||||
ctxReq, cancelReq := context.WithCancel(ctx)
|
||||
go func() {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
cancelReq()
|
||||
}()
|
||||
err := db.PingContext(ctxReq)
|
||||
if err != context.Canceled {
|
||||
t.Fatalf("PingContext (Exhaust): %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
saturateDone.Wait()
|
||||
|
||||
// Now try to open a normal connection.
|
||||
err := db.PingContext(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("PingContext (Normal): %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestByteOwnership(t *testing.T) {
|
||||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue