Skip to content

Commit 2bb1c8c

Browse files
committed
Fair retry interval.
1 parent 844fab4 commit 2bb1c8c

File tree

1 file changed

+12
-32
lines changed

1 file changed

+12
-32
lines changed

conn.go

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"math"
7+
"math/rand"
78
"net/url"
89
"strings"
910
"time"
@@ -24,7 +25,6 @@ type Conn struct {
2425
interrupt context.Context
2526
pending *Stmt
2627
stmts []*Stmt
27-
timer *time.Timer
2828
busy func(context.Context, int) bool
2929
log func(xErrorCode, string)
3030
collation func(*Conn, string)
@@ -36,7 +36,8 @@ type Conn struct {
3636
rollback func()
3737
arena arena
3838

39-
handle uint32
39+
kickoff time.Time
40+
handle uint32
4041
}
4142

4243
// Open calls [OpenFlags] with [OPEN_READWRITE], [OPEN_CREATE] and [OPEN_URI].
@@ -389,38 +390,17 @@ func (c *Conn) BusyTimeout(timeout time.Duration) error {
389390
}
390391

391392
func timeoutCallback(ctx context.Context, mod api.Module, count, tmout int32) (retry uint32) {
393+
// https://fractaledmind.github.io/2024/04/15/sqlite-on-rails-the-how-and-why-of-optimal-performance/
392394
if c, ok := ctx.Value(connKey{}).(*Conn); ok && c.interrupt.Err() == nil {
393-
const delays = "\x01\x02\x05\x0a\x0f\x14\x19\x19\x19\x32\x32\x64"
394-
const totals = "\x00\x01\x03\x08\x12\x21\x35\x4e\x67\x80\xb2\xe4"
395-
const ndelay = int32(len(delays) - 1)
396-
397-
var delay, prior int32
398-
if count <= ndelay {
399-
delay = int32(delays[count])
400-
prior = int32(totals[count])
401-
} else {
402-
delay = int32(delays[ndelay])
403-
prior = int32(totals[ndelay]) + delay*(count-ndelay)
404-
}
405-
406-
if delay = min(delay, tmout-prior); delay > 0 {
407-
delay := time.Duration(delay) * time.Millisecond
408-
if c.interrupt.Done() == nil {
409-
time.Sleep(delay)
410-
return 1
411-
}
412-
if c.timer == nil {
413-
c.timer = time.NewTimer(delay)
414-
} else {
415-
c.timer.Reset(delay)
416-
}
417-
select {
418-
case <-c.interrupt.Done():
419-
c.timer.Stop()
420-
case <-c.timer.C:
421-
return 1
422-
}
395+
switch {
396+
case count == 0:
397+
c.kickoff = time.Now()
398+
case time.Since(c.kickoff) >= time.Duration(tmout)*time.Millisecond:
399+
return 0
423400
}
401+
const sleepIncrement = 4*1024*1024 - 1 // power of two, ~4ms
402+
time.Sleep(time.Duration(rand.Int63() & sleepIncrement))
403+
return 1
424404
}
425405
return 0
426406
}

0 commit comments

Comments
 (0)