Improve pool Acquire / Release performance

Release was using a goroutine every time. Now it only starts a goroutine
when doing something that may take a while. (Destroy and afterRelease)
pull/483/head
Jack Christensen 2019-05-04 17:34:09 -05:00
parent 3661a005fa
commit f572b336b1
4 changed files with 69 additions and 12 deletions

View File

@ -26,7 +26,7 @@ func BenchmarkMinimalPreparedSelect(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
err = conn.QueryRow(context.Background(), "ps1", int64(i)).Scan(&n)
err = conn.QueryRow(context.Background(), "ps1", i).Scan(&n)
if err != nil {
b.Fatal(err)
}
@ -37,6 +37,41 @@ func BenchmarkMinimalPreparedSelect(b *testing.B) {
}
}
func BenchmarkMinimalPgConnPreparedSelect(b *testing.B) {
conn := mustConnect(b, mustParseConfig(b, os.Getenv("PGX_TEST_DATABASE")))
defer closeConn(b, conn)
pgConn := conn.PgConn()
_, err := pgConn.Prepare(context.Background(), "ps1", "select $1::int8", nil)
if err != nil {
b.Fatal(err)
}
encodedBytes := make([]byte, 8)
b.ResetTimer()
for i := 0; i < b.N; i++ {
rr := pgConn.ExecPrepared(context.Background(), "ps1", [][]byte{encodedBytes}, []int16{1}, []int16{1})
if err != nil {
b.Fatal(err)
}
for rr.NextRow() {
for i := range rr.Values() {
if bytes.Compare(rr.Values()[0], encodedBytes) != 0 {
b.Fatalf("unexpected values: %s %s", rr.Values()[i], encodedBytes)
}
}
}
_, err = rr.Close()
if err != nil {
b.Fatal(err)
}
}
}
func BenchmarkPointerPointerWithNullValues(b *testing.B) {
conn := mustConnect(b, mustParseConfig(b, os.Getenv("PGX_TEST_DATABASE")))
defer closeConn(b, conn)

View File

@ -10,6 +10,21 @@ import (
"github.com/stretchr/testify/require"
)
func BenchmarkAcquireAndRelease(b *testing.B) {
pool, err := pool.Connect(context.Background(), os.Getenv("PGX_TEST_DATABASE"))
require.NoError(b, err)
defer pool.Close()
b.ResetTimer()
for i := 0; i < b.N; i++ {
c, err := pool.Acquire(context.Background())
if err != nil {
b.Fatal(err)
}
c.Release()
}
}
func BenchmarkMinimalPreparedSelectBaseline(b *testing.B) {
config, err := pool.ParseConfig(os.Getenv("PGX_TEST_DATABASE"))
require.NoError(b, err)

View File

@ -26,14 +26,19 @@ func (c *Conn) Release() {
res := c.res
c.res = nil
go func() {
now := time.Now()
if !conn.IsAlive() || conn.PgConn().TxStatus != 'I' || (now.Sub(res.CreationTime()) > c.p.maxConnLifetime) {
res.Destroy()
return
}
now := time.Now()
if !conn.IsAlive() || conn.PgConn().TxStatus != 'I' || (now.Sub(res.CreationTime()) > c.p.maxConnLifetime) {
res.Destroy()
return
}
if c.p.afterRelease == nil || c.p.afterRelease(conn) {
if c.p.afterRelease == nil {
res.Release()
return
}
go func() {
if c.p.afterRelease(conn) {
res.Release()
} else {
res.Destroy()
@ -66,7 +71,7 @@ func (c *Conn) Begin(ctx context.Context, txOptions *pgx.TxOptions) (*pgx.Tx, er
}
func (c *Conn) Conn() *pgx.Conn {
return c.res.Value().(*connResource).conn
return c.connResource().conn
}
func (c *Conn) connResource() *connResource {

View File

@ -150,9 +150,11 @@ func ConnectConfig(ctx context.Context, config *Config) (*Pool, error) {
return cr, nil
},
func(value interface{}) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
value.(*connResource).conn.Close(ctx)
cancel()
go func() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
value.(*connResource).conn.Close(ctx)
cancel()
}()
},
config.MaxConns,
)