mirror of https://github.com/jackc/pgx.git
Fix data race with Rows and ConnPool
In an effort to reduce memory allocations, Rows was stored on the Conn. This caused a race condition where Rows are closed and this returns the Conn to the Pool. The Pool could then give out the Conn again. Rows would then be reanimated and the original Rows could reclose it.pull/37/head
parent
a5f082fa03
commit
a68115fc03
1
conn.go
1
conn.go
|
@ -53,7 +53,6 @@ type Conn struct {
|
|||
alive bool
|
||||
causeOfDeath error
|
||||
logger Logger
|
||||
rows Rows
|
||||
mr msgReader
|
||||
}
|
||||
|
||||
|
|
|
@ -410,6 +410,50 @@ func TestConnPoolQuery(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestConnPoolQueryConcurrentLoad(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pool := createConnPool(t, 10)
|
||||
defer pool.Close()
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
go func(i int) {
|
||||
var rowCount int32
|
||||
|
||||
rows, err := pool.Query("select generate_series(1,$1)", 1000)
|
||||
if err != nil {
|
||||
fmt.Println(i, err)
|
||||
t.Fatalf("pool.Query failed: %v", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var n int32
|
||||
err = rows.Scan(&n)
|
||||
if err != nil {
|
||||
fmt.Println(i, err)
|
||||
t.Fatalf("rows.Scan failed: %v", err)
|
||||
}
|
||||
if n != rowCount+1 {
|
||||
fmt.Println(i, err)
|
||||
t.Fatalf("Expected n to be %d, but it was %d", rowCount+1, n)
|
||||
}
|
||||
rowCount++
|
||||
}
|
||||
|
||||
if rows.Err() != nil {
|
||||
fmt.Println(i, err)
|
||||
t.Fatalf("conn.Query failed: ", err)
|
||||
}
|
||||
|
||||
if rowCount != 1000 {
|
||||
fmt.Println(i, err)
|
||||
t.Error("Select called onDataRow wrong number of times")
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnPoolQueryRow(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
3
query.go
3
query.go
|
@ -354,8 +354,7 @@ func (rows *Rows) Values() ([]interface{}, error) {
|
|||
// be returned in an error state. So it is allowed to ignore the error returned
|
||||
// from Query and handle it in *Rows.
|
||||
func (c *Conn) Query(sql string, args ...interface{}) (*Rows, error) {
|
||||
c.rows = Rows{conn: c, startTime: time.Now(), sql: sql, args: args, logger: c.logger}
|
||||
rows := &c.rows
|
||||
rows := &Rows{conn: c, startTime: time.Now(), sql: sql, args: args, logger: c.logger}
|
||||
|
||||
ps, ok := c.preparedStatements[sql]
|
||||
if !ok {
|
||||
|
|
Loading…
Reference in New Issue