From d20ec967c429e1bc0314aff03c70079cca6a0e56 Mon Sep 17 00:00:00 2001 From: kim <89579420+NyaaaWhatsUpDoc@users.noreply.github.com> Date: Fri, 22 Jul 2022 11:43:34 +0100 Subject: [PATCH] [bugfix] update go-cache library to fix critical bug during cache sweep scheduling (#725) * update go-cache library to fix critical bug regarding cache sweep scheduling Signed-off-by: kim * update go-sched Signed-off-by: kim --- go.mod | 6 +-- go.sum | 11 ++--- vendor/codeberg.org/gruf/go-runners/run.go | 40 ++++++++----------- vendor/codeberg.org/gruf/go-sched/job.go | 19 +++++++++ .../codeberg.org/gruf/go-sched/scheduler.go | 14 ++++++- vendor/modules.txt | 8 ++-- 6 files changed, 61 insertions(+), 37 deletions(-) diff --git a/go.mod b/go.mod index 445445bad..f6a3789ab 100644 --- a/go.mod +++ b/go.mod @@ -6,13 +6,13 @@ require ( codeberg.org/gruf/go-atomics v1.1.0 codeberg.org/gruf/go-bytesize v0.2.1 codeberg.org/gruf/go-byteutil v1.0.2 - codeberg.org/gruf/go-cache/v2 v2.1.1 + codeberg.org/gruf/go-cache/v2 v2.1.2 codeberg.org/gruf/go-debug v1.2.0 codeberg.org/gruf/go-errors/v2 v2.0.2 codeberg.org/gruf/go-kv v1.3.2 codeberg.org/gruf/go-logger/v2 v2.0.6 codeberg.org/gruf/go-mutexes v1.1.2 - codeberg.org/gruf/go-runners v1.2.1 + codeberg.org/gruf/go-runners v1.2.2 codeberg.org/gruf/go-store v1.3.8 github.com/buckket/go-blurhash v1.1.0 github.com/coreos/go-oidc/v3 v3.1.0 @@ -62,7 +62,7 @@ require ( codeberg.org/gruf/go-fastpath v1.0.3 // indirect codeberg.org/gruf/go-hashenc v1.0.2 // indirect codeberg.org/gruf/go-pools v1.1.0 // indirect - codeberg.org/gruf/go-sched v1.0.1 // indirect + codeberg.org/gruf/go-sched v1.0.4 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b // indirect diff --git a/go.sum b/go.sum index e1e18ba73..2d59d6dc5 100644 --- a/go.sum +++ b/go.sum @@ -50,8 +50,8 @@ codeberg.org/gruf/go-byteutil v1.0.0/go.mod h1:cWM3tgMCroSzqoBXUXMhvxTxYJp+TbCr6 codeberg.org/gruf/go-byteutil v1.0.2 h1:OesVyK5VKWeWdeDR00zRJ+Oy8hjXx1pBhn7WVvcZWVE= codeberg.org/gruf/go-byteutil v1.0.2/go.mod h1:cWM3tgMCroSzqoBXUXMhvxTxYJp+TbCr6ioISRY5vSU= codeberg.org/gruf/go-cache v1.1.2/go.mod h1:/Dbc+xU72Op3hMn6x2PXF3NE9uIDFeS+sXPF00hN/7o= -codeberg.org/gruf/go-cache/v2 v2.1.1 h1:Ate0URlO6dVTYGxcIST9sDKtwOqrqBmlm73zy3Bq1+k= -codeberg.org/gruf/go-cache/v2 v2.1.1/go.mod h1:XstSofaENTH3PNBoMrBcowFJ339OcJfTwO0PCOp5lKQ= +codeberg.org/gruf/go-cache/v2 v2.1.2 h1:MjnnsrZit4WYN4E6pZhcw3YY2QXNBRG5Ijz7z3r6z2o= +codeberg.org/gruf/go-cache/v2 v2.1.2/go.mod h1:bFZSpjN9cszV3ArmHW7IwvcDDn/SklfECv0U1FMRMdU= codeberg.org/gruf/go-ctx v1.0.2/go.mod h1:iMyid3m2Rr1wSWL+snliBK5qE51b4pLY5CozVUrb/QU= codeberg.org/gruf/go-debug v1.2.0 h1:WBbTMnK1ArFKUmgv04aO2JiC/daTOB8zQGi521qb7OU= codeberg.org/gruf/go-debug v1.2.0/go.mod h1:N+vSy9uJBQgpQcJUqjctvqFz7tBHJf+S/PIjLILzpLg= @@ -80,10 +80,11 @@ codeberg.org/gruf/go-nowish v1.1.2/go.mod h1:70nvICNcqQ9OHpF07N614Dyk7cpL5ToWU1K codeberg.org/gruf/go-pools v1.1.0 h1:LbYP24eQLl/YI1fSU2pafiwhGol1Z1zPjRrMsXpF88s= codeberg.org/gruf/go-pools v1.1.0/go.mod h1:ZMYpt/DjQWYC3zFD3T97QWSFKs62zAUGJ/tzvgB9D68= codeberg.org/gruf/go-runners v1.1.1/go.mod h1:9gTrmMnO3d+50C+hVzcmGBf+zTuswReS278E2EMvnmw= -codeberg.org/gruf/go-runners v1.2.1 h1:eXXofOMkLTkrdqI0qFYm00hP9IW42JZbc+IRKgVyQ28= codeberg.org/gruf/go-runners v1.2.1/go.mod h1:9gTrmMnO3d+50C+hVzcmGBf+zTuswReS278E2EMvnmw= -codeberg.org/gruf/go-sched v1.0.1 h1:+EAXSVI4orY5lMNX2Vrke/UxF2qjmEy6gHcyySZg/3k= -codeberg.org/gruf/go-sched v1.0.1/go.mod h1:LFzosJL0yrCNtXg9Vq9iwr4q6ANuRirO2cVwKYH7CLs= +codeberg.org/gruf/go-runners v1.2.2 h1:o0u8ggAeT5j8R0oaND961OeWEZOzW9wqwhmnVEeteqs= +codeberg.org/gruf/go-runners v1.2.2/go.mod h1:rl0EdZNozkRMb21DAtOL5L4oTfmslYQdZgq2RMMc/H4= +codeberg.org/gruf/go-sched v1.0.4 h1:gEfbDQbPUhCE+JPTo28l3eTaNilP+YXMjXS2e3KOtDQ= +codeberg.org/gruf/go-sched v1.0.4/go.mod h1:5C2IQtzxSPR0Q5+EWTAY5HcxZIIFr5B6MtFwL9FtsoA= codeberg.org/gruf/go-store v1.3.8 h1:7Hzzsa8gaOc6spuGWXJVUWRAyKiOR/m60/jNYrD8cT0= codeberg.org/gruf/go-store v1.3.8/go.mod h1:Fy5pXEHiIVFRWDx8DfILwXS1ulrj/jLdSK2C2oElz3I= codeberg.org/gruf/go-ulid v1.0.0/go.mod h1:dVNsZJpVTge8+jfBTjAMpnscYSiCqk+g32ZgtorCAMs= diff --git a/vendor/codeberg.org/gruf/go-runners/run.go b/vendor/codeberg.org/gruf/go-runners/run.go index 27f7fb9b8..67d19b40c 100644 --- a/vendor/codeberg.org/gruf/go-runners/run.go +++ b/vendor/codeberg.org/gruf/go-runners/run.go @@ -4,8 +4,9 @@ import ( "context" "errors" "fmt" - "sync" "time" + + "codeberg.org/gruf/go-atomics" ) // FuncRunner provides a means of managing long-running functions e.g. main logic loops. @@ -17,9 +18,8 @@ type FuncRunner struct { // provided function. This can be used both for logging, and for error filtering ErrorHandler func(err error) error - svc Service // underlying service to manage start/stop - err error // last-set error - mu sync.Mutex // protects err + svc Service // underlying service to manage start/stop + err atomics.Error } // Go will attempt to run 'fn' asynchronously. The provided context is used to propagate requested @@ -28,22 +28,20 @@ type FuncRunner struct { // time before considering the function as handed off. Returned bool is success state, i.e. returns true // if function is successfully handed off or returns within hand off time with nil error. func (r *FuncRunner) Go(fn func(ctx context.Context) error) bool { + var has bool + done := make(chan struct{}) go func() { var cancelled bool - has := r.svc.Run(func(ctx context.Context) { + has = r.svc.Run(func(ctx context.Context) { // reset error - r.mu.Lock() - r.err = nil - r.mu.Unlock() + r.err.Store(nil) // Run supplied func and set errror if returned if err := Run(func() error { return fn(ctx) }); err != nil { - r.mu.Lock() - r.err = err - r.mu.Unlock() + r.err.Store(err) } // signal done @@ -61,19 +59,18 @@ func (r *FuncRunner) Go(fn func(ctx context.Context) error) bool { switch has { // returned after starting case true: - r.mu.Lock() + // Load set error + err := r.err.Load() // filter out errors due FuncRunner.Stop() being called - if cancelled && errors.Is(r.err, context.Canceled) { + if cancelled && errors.Is(err, context.Canceled) { // filter out errors from FuncRunner.Stop() being called - r.err = nil - } else if r.err != nil && r.ErrorHandler != nil { + r.err.Store(nil) + } else if err != nil && r.ErrorHandler != nil { // pass any non-nil error to set handler - r.err = r.ErrorHandler(r.err) + r.err.Store(r.ErrorHandler(err)) } - r.mu.Unlock() - // already running case false: close(done) @@ -93,7 +90,7 @@ func (r *FuncRunner) Go(fn func(ctx context.Context) error) bool { // 'fn' returned, check error case <-done: - return (r.Err() == nil) + return has } } @@ -104,10 +101,7 @@ func (r *FuncRunner) Stop() bool { // Err returns the last-set error value. func (r *FuncRunner) Err() error { - r.mu.Lock() - err := r.err - r.mu.Unlock() - return err + return r.err.Load() } // Run will execute the supplied 'fn' catching any panics. Returns either function-returned error or formatted panic. diff --git a/vendor/codeberg.org/gruf/go-sched/job.go b/vendor/codeberg.org/gruf/go-sched/job.go index 66e24fe9a..7831a39bd 100644 --- a/vendor/codeberg.org/gruf/go-sched/job.go +++ b/vendor/codeberg.org/gruf/go-sched/job.go @@ -1,6 +1,9 @@ package sched import ( + "reflect" + "strconv" + "strings" "time" "codeberg.org/gruf/go-atomics" @@ -97,3 +100,19 @@ func (job *Job) Run(now time.Time) { }() job.call(now) } + +// String provides a debuggable string representation of Job including ID, next time and Timing type. +func (job *Job) String() string { + var buf strings.Builder + buf.WriteByte('{') + buf.WriteString("id=") + buf.WriteString(strconv.FormatUint(job.id, 10)) + buf.WriteByte(' ') + buf.WriteString("next=") + buf.WriteString(job.next.Load().Format(time.StampMicro)) + buf.WriteByte(' ') + buf.WriteString("timing=") + buf.WriteString(reflect.TypeOf(job.timing).String()) + buf.WriteByte('}') + return buf.String() +} diff --git a/vendor/codeberg.org/gruf/go-sched/scheduler.go b/vendor/codeberg.org/gruf/go-sched/scheduler.go index d017ddcf6..8d076fea0 100644 --- a/vendor/codeberg.org/gruf/go-sched/scheduler.go +++ b/vendor/codeberg.org/gruf/go-sched/scheduler.go @@ -132,7 +132,13 @@ func (sch *Scheduler) run(ctx context.Context) { // Get next job time next := sch.jobs[0].Next() - if until := next.Sub(now); until <= 0 { + // If this job is _just_ about to be ready, we + // don't bother sleeping. It's wasted cycles only + // sleeping for some obscenely tiny amount of time + // we can't guarantee precision for. + const precision = time.Millisecond + + if until := next.Sub(now); until <= precision/1e3 { // This job is behind schedule, // set timer to always tick tch = alwaysticks @@ -155,6 +161,10 @@ func (sch *Scheduler) run(ctx context.Context) { // Timer ticked, run scheduled case now := <-tch: + if !timerset { + // alwaysticks returns zero times + now = time.Now() + } sch.schedule(now) // Received update, handle job/id @@ -213,7 +223,7 @@ func (sch *Scheduler) schedule(now time.Time) { // Run this job async! go job.Run(now) - if job.Next().IsZero() { + if next.IsZero() { // Zero time, this job is done and can be dropped sch.jobs = append(sch.jobs[:i], sch.jobs[i+1:]...) continue diff --git a/vendor/modules.txt b/vendor/modules.txt index 05e467bbb..4ebfa0890 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -13,7 +13,7 @@ codeberg.org/gruf/go-bytesize # codeberg.org/gruf/go-byteutil v1.0.2 ## explicit; go 1.16 codeberg.org/gruf/go-byteutil -# codeberg.org/gruf/go-cache/v2 v2.1.1 +# codeberg.org/gruf/go-cache/v2 v2.1.2 ## explicit; go 1.18 codeberg.org/gruf/go-cache/v2 # codeberg.org/gruf/go-debug v1.2.0 @@ -44,11 +44,11 @@ codeberg.org/gruf/go-mutexes # codeberg.org/gruf/go-pools v1.1.0 ## explicit; go 1.16 codeberg.org/gruf/go-pools -# codeberg.org/gruf/go-runners v1.2.1 +# codeberg.org/gruf/go-runners v1.2.2 ## explicit; go 1.14 codeberg.org/gruf/go-runners -# codeberg.org/gruf/go-sched v1.0.1 -## explicit; go 1.18 +# codeberg.org/gruf/go-sched v1.0.4 +## explicit; go 1.16 codeberg.org/gruf/go-sched # codeberg.org/gruf/go-store v1.3.8 ## explicit; go 1.14