From ab99385edac3d54b1aeedcd41c817cd48fdfd470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20D=C3=A9trez?= Date: Tue, 30 Aug 2022 11:11:42 +0200 Subject: [PATCH 1/2] Fix log server not exiting properly on SIGINT Make the tree garbage collection coroutine exit immediately when the context is cancelled. --- CHANGELOG.md | 3 +++ server/admin/tree_gc.go | 16 ++++++++-------- server/admin/tree_gc_test.go | 16 +++++++++++----- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d2448d00a..4a0f400ce3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## HEAD +### Misc +* Fix log server not exiting properly on SIGINT + ## v.1.5.0 ### Storage diff --git a/server/admin/tree_gc.go b/server/admin/tree_gc.go index 9b1eacf0c1..ab55ce5f87 100644 --- a/server/admin/tree_gc.go +++ b/server/admin/tree_gc.go @@ -35,7 +35,7 @@ const ( var ( timeNow = time.Now - timeSleep = time.Sleep + timeAfter = time.After hardDeleteCounter monitoring.Counter metricsOnce sync.Once @@ -85,12 +85,6 @@ func NewDeletedTreeGC(admin storage.AdminStorage, threshold, minRunInterval time // Run starts the tree garbage collection process. It runs until ctx is cancelled. func (gc *DeletedTreeGC) Run(ctx context.Context) { for { - select { - case <-ctx.Done(): - return - default: - } - count, err := gc.RunOnce(ctx) if err != nil { klog.Errorf("DeletedTreeGC.Run: %v", err) @@ -100,7 +94,13 @@ func (gc *DeletedTreeGC) Run(ctx context.Context) { } d := gc.minRunInterval + time.Duration(rand.Int63n(gc.minRunInterval.Nanoseconds())) - timeSleep(d) + select { + case <-ctx.Done(): + return + case <-timeAfter(d): + default: + } + } } diff --git a/server/admin/tree_gc_test.go b/server/admin/tree_gc_test.go index 65f2916211..097de19193 100644 --- a/server/admin/tree_gc_test.go +++ b/server/admin/tree_gc_test.go @@ -40,7 +40,7 @@ func TestDeletedTreeGC_Run(t *testing.T) { // * Sleep (ctx cancelled) // // DeletedTreeGC.Run() until ctx in cancelled. Since it always sleeps between iterations, we - // make "timeSleep" cancel ctx the second time around to break the loop. + // make "timeAfter" cancel ctx the second time around to break the loop. tree1 := proto.Clone(testonly.LogTree).(*trillian.Tree) tree1.TreeId = 1 @@ -74,10 +74,10 @@ func TestDeletedTreeGC_Run(t *testing.T) { listTX2.EXPECT().Close().Return(nil) listTX2.EXPECT().Commit().Return(nil) - defer func(now func() time.Time, sleep func(time.Duration)) { + defer func(now func() time.Time, after func(time.Duration) <-chan time.Time) { timeNow = now - timeSleep = sleep - }(timeNow, timeSleep) + timeAfter = after + }(timeNow, timeAfter) const deleteThreshold = 1 * time.Hour const runInterval = 3 * time.Second @@ -87,14 +87,20 @@ func TestDeletedTreeGC_Run(t *testing.T) { timeNow = func() time.Time { return now } calls := 0 - timeSleep = func(d time.Duration) { + timeAfter = func(d time.Duration) <-chan time.Time { calls++ if d < runInterval || d >= 2*runInterval { t.Errorf("Called time.Sleep(%v), want %v", d, runInterval) } if calls >= 2 { cancel() + // Block to make sure we're exiting because of the cancelled context and + // not because the timer elapsed. + return make(chan time.Time) } + ch := make(chan time.Time, 1) + ch <- now + return ch } NewDeletedTreeGC(as, deleteThreshold, runInterval, nil /* mf */).Run(ctx) From 8a457e0172abe670f8964ee2c1808ed0fd3b9d41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20D=C3=A9trez?= Date: Mon, 5 Sep 2022 16:53:42 +0200 Subject: [PATCH 2/2] Remove erroneous default case --- server/admin/tree_gc.go | 1 - 1 file changed, 1 deletion(-) diff --git a/server/admin/tree_gc.go b/server/admin/tree_gc.go index ab55ce5f87..47af78a21c 100644 --- a/server/admin/tree_gc.go +++ b/server/admin/tree_gc.go @@ -98,7 +98,6 @@ func (gc *DeletedTreeGC) Run(ctx context.Context) { case <-ctx.Done(): return case <-timeAfter(d): - default: } }