Skip to content

Commit

Permalink
perf: improve user specified flush delay automatically by statistics
Browse files Browse the repository at this point in the history
  • Loading branch information
rueian committed Dec 14, 2022
1 parent 0758427 commit 08c3c3b
Showing 1 changed file with 39 additions and 8 deletions.
47 changes: 39 additions & 8 deletions pipe.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,35 +281,66 @@ func (p *pipe) _background() {
atomic.StoreInt32(&p.state, 4)
}

type flush struct {
works time.Duration
waits time.Duration
bytes int
}

const flushesKeep = 16
const flushesMask = flushesKeep - 1

func (p *pipe) _backgroundWrite() (err error) {
var (
ones = make([]cmds.Completed, 1)
multi []cmds.Completed
ch chan RedisResult

flushDelay = p.maxFlushDelay
flushStart = time.Time{}
flushes [flushesKeep]flush
flushId = 0
bytes = 1 // avoid zero
works = time.Duration(1)
waits = time.Duration(0)

userDelay = p.maxFlushDelay
)

var ts1 = time.Now()
for atomic.LoadInt32(&p.state) < 3 {
if ones[0], multi, ch = p.queue.NextWriteCmd(); ch == nil {
if flushDelay != 0 {
flushStart = time.Now()
}
if p.w.Buffered() == 0 {
buf := p.w.Buffered()
if buf == 0 {
err = p.Error()
} else if userDelay == 0 {
err = p.w.Flush()
} else {
ts2 := time.Now()
err = p.w.Flush()
dur, gap := time.Since(ts2), ts2.Sub(ts1)
bytes = bytes + buf - flushes[flushId].bytes
works = works + dur - flushes[flushId].works
waits = waits + gap - flushes[flushId].waits
flushes[flushId] = flush{bytes: buf, works: dur, waits: gap}
flushId = (flushId + 1) & flushesMask
ts1 = ts2
}

if err == nil {
if atomic.LoadInt32(&p.state) == 1 {
ones[0], multi, ch = p.queue.WaitForWrite()
} else {
runtime.Gosched()
continue
}
if flushDelay != 0 && atomic.LoadInt32(&p.waits) > 1 { // do not delay for sequential usage
time.Sleep(flushDelay - time.Since(flushStart)) // ref: https://github.com/rueian/rueidis/issues/156
if userDelay != 0 && atomic.LoadInt32(&p.waits) > 1 { // do not delay for sequential usage
avgWorks := works / flushesKeep
byteWork := works / time.Duration(bytes)
byteWait := waits / time.Duration(bytes)
if autoDelay := byteWait * avgWorks / (byteWait + byteWork); autoDelay <= userDelay {
time.Sleep(autoDelay)
} else {
time.Sleep(userDelay) // ref: https://github.com/rueian/rueidis/issues/156
}
}
}
}
Expand Down

0 comments on commit 08c3c3b

Please sign in to comment.