From 01a226b3ecfc573dc91d43c6f9e1a4f91d4a8dbb Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 10 Nov 2022 09:48:46 +0300 Subject: [PATCH] [#2037] services/object: Fix concurrent map writes in traverser ``` fatal error: concurrent map writes goroutine 4337 [running]: github.com/nspcc-dev/neofs-node/pkg/services/object/put.(*traversal).submitProcessed(...) github.com/nspcc-dev/neofs-node/pkg/services/object/put/distributed.go:78 github.com/nspcc-dev/neofs-node/pkg/services/object/put.(*distributedTarget).iteratePlacement.func1() github.com/nspcc-dev/neofs-node/pkg/services/object/put/distributed.go:198 +0x265 github.com/panjf2000/ants/v2.(*goWorker).run.func1() github.com/panjf2000/ants/v2@v2.4.0/worker.go:68 +0x97 created by github.com/panjf2000/ants/v2.(*goWorker).run github.com/panjf2000/ants/v2@v2.4.0/worker.go:48 +0x65 ``` Signed-off-by: Evgenii Stratonikov --- CHANGELOG.md | 1 + pkg/services/object/put/distributed.go | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25ed2b9a9..80f4b6ae7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ Changelog for NeoFS Node - `neofs-cli lock object`'s `lifetime` flag handling (#1972) - Do not move write-cache in read-only mode for flushing (#1906) - Child object collection on CLI side with a bearer token (#2000) +- Fix concurrent map writes in `Object.Put` service ### Removed ### Updated diff --git a/pkg/services/object/put/distributed.go b/pkg/services/object/put/distributed.go index 640e37049..1ed21cadc 100644 --- a/pkg/services/object/put/distributed.go +++ b/pkg/services/object/put/distributed.go @@ -48,6 +48,9 @@ type traversal struct { // need of additional broadcast after the object is saved extraBroadcastEnabled bool + // mtx protects mExclude map. + mtx sync.RWMutex + // container nodes which was processed during the primary object placement mExclude map[string]struct{} } @@ -71,17 +74,23 @@ func (x *traversal) submitPrimaryPlacementFinish() bool { // marks the container node as processed during the primary object placement. func (x *traversal) submitProcessed(n placement.Node) { if x.extraBroadcastEnabled { + key := string(n.PublicKey()) + + x.mtx.Lock() if x.mExclude == nil { x.mExclude = make(map[string]struct{}, 1) } - x.mExclude[string(n.PublicKey())] = struct{}{} + x.mExclude[key] = struct{}{} + x.mtx.Unlock() } } // checks if specified node was processed during the primary object placement. -func (x traversal) processed(n placement.Node) bool { +func (x *traversal) processed(n placement.Node) bool { + x.mtx.RLock() _, ok := x.mExclude[string(n.PublicKey())] + x.mtx.RUnlock() return ok }