diff --git a/pkg/local_object_storage/writecache/cachebbolt.go b/pkg/local_object_storage/writecache/cachebbolt.go index 254d8754f..cdd4ed442 100644 --- a/pkg/local_object_storage/writecache/cachebbolt.go +++ b/pkg/local_object_storage/writecache/cachebbolt.go @@ -4,6 +4,7 @@ import ( "context" "os" "sync" + "sync/atomic" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/fstree" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/metaerr" @@ -30,7 +31,7 @@ type cache struct { // flushCh is a channel with objects to flush. flushCh chan objectInfo // cancel is cancel function, protected by modeMtx in Close. - cancel func() + cancel atomic.Value // wg is a wait group for flush workers. wg sync.WaitGroup // store contains underlying database. @@ -54,7 +55,10 @@ const ( defaultMaxCacheSize = 1 << 30 // 1 GiB ) -var defaultBucket = []byte{0} +var ( + defaultBucket = []byte{0} + dummyCanceler context.CancelFunc = func() {} +) // New creates new writecache instance. func New(opts ...Option) Cache { @@ -114,20 +118,19 @@ func (c *cache) Open(_ context.Context, mod mode.Mode) error { func (c *cache) Init() error { c.metrics.SetMode(mode.ConvertToComponentModeDegraded(c.mode)) ctx, cancel := context.WithCancel(context.Background()) - c.cancel = cancel + c.cancel.Store(cancel) c.runFlushLoop(ctx) return nil } // Close closes db connection and stops services. Executes ObjectCounters.FlushAndClose op. func (c *cache) Close() error { + if cancelValue := c.cancel.Swap(dummyCanceler); cancelValue != nil { + cancelValue.(context.CancelFunc)() + } // We cannot lock mutex for the whole operation duration // because it is taken by some background workers, so `wg.Wait()` is done without modeMtx. c.modeMtx.Lock() - if c.cancel != nil { - c.cancel() - c.cancel = nil - } c.mode = mode.DegradedReadOnly // prevent new operations from being processed c.modeMtx.Unlock()