mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-12 05:59:14 +00:00
Fair retry interval.
This commit is contained in:
44
conn.go
44
conn.go
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"math/rand"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -24,7 +25,6 @@ type Conn struct {
|
|||||||
interrupt context.Context
|
interrupt context.Context
|
||||||
pending *Stmt
|
pending *Stmt
|
||||||
stmts []*Stmt
|
stmts []*Stmt
|
||||||
timer *time.Timer
|
|
||||||
busy func(context.Context, int) bool
|
busy func(context.Context, int) bool
|
||||||
log func(xErrorCode, string)
|
log func(xErrorCode, string)
|
||||||
collation func(*Conn, string)
|
collation func(*Conn, string)
|
||||||
@@ -36,7 +36,8 @@ type Conn struct {
|
|||||||
rollback func()
|
rollback func()
|
||||||
arena arena
|
arena arena
|
||||||
|
|
||||||
handle uint32
|
kickoff time.Time
|
||||||
|
handle uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open calls [OpenFlags] with [OPEN_READWRITE], [OPEN_CREATE] and [OPEN_URI].
|
// Open calls [OpenFlags] with [OPEN_READWRITE], [OPEN_CREATE] and [OPEN_URI].
|
||||||
@@ -389,38 +390,17 @@ func (c *Conn) BusyTimeout(timeout time.Duration) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func timeoutCallback(ctx context.Context, mod api.Module, count, tmout int32) (retry uint32) {
|
func timeoutCallback(ctx context.Context, mod api.Module, count, tmout int32) (retry uint32) {
|
||||||
|
// https://fractaledmind.github.io/2024/04/15/sqlite-on-rails-the-how-and-why-of-optimal-performance/
|
||||||
if c, ok := ctx.Value(connKey{}).(*Conn); ok && c.interrupt.Err() == nil {
|
if c, ok := ctx.Value(connKey{}).(*Conn); ok && c.interrupt.Err() == nil {
|
||||||
const delays = "\x01\x02\x05\x0a\x0f\x14\x19\x19\x19\x32\x32\x64"
|
switch {
|
||||||
const totals = "\x00\x01\x03\x08\x12\x21\x35\x4e\x67\x80\xb2\xe4"
|
case count == 0:
|
||||||
const ndelay = int32(len(delays) - 1)
|
c.kickoff = time.Now()
|
||||||
|
case time.Since(c.kickoff) >= time.Duration(tmout)*time.Millisecond:
|
||||||
var delay, prior int32
|
return 0
|
||||||
if count <= ndelay {
|
|
||||||
delay = int32(delays[count])
|
|
||||||
prior = int32(totals[count])
|
|
||||||
} else {
|
|
||||||
delay = int32(delays[ndelay])
|
|
||||||
prior = int32(totals[ndelay]) + delay*(count-ndelay)
|
|
||||||
}
|
|
||||||
|
|
||||||
if delay = min(delay, tmout-prior); delay > 0 {
|
|
||||||
delay := time.Duration(delay) * time.Millisecond
|
|
||||||
if c.interrupt.Done() == nil {
|
|
||||||
time.Sleep(delay)
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
if c.timer == nil {
|
|
||||||
c.timer = time.NewTimer(delay)
|
|
||||||
} else {
|
|
||||||
c.timer.Reset(delay)
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
case <-c.interrupt.Done():
|
|
||||||
c.timer.Stop()
|
|
||||||
case <-c.timer.C:
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
const sleepIncrement = 4*1024*1024 - 1 // power of two, ~4ms
|
||||||
|
time.Sleep(time.Duration(rand.Int63() & sleepIncrement))
|
||||||
|
return 1
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user