diff --git a/pkg/services/object_manager/placement/netmap.go b/pkg/services/object_manager/placement/netmap.go index 32f1adefeb..0c67b74704 100644 --- a/pkg/services/object_manager/placement/netmap.go +++ b/pkg/services/object_manager/placement/netmap.go @@ -3,7 +3,9 @@ package placement import ( "crypto/sha256" "fmt" + "sync" + "github.com/hashicorp/golang-lru/simplelru" "github.com/nspcc-dev/neofs-node/pkg/core/netmap" cid "github.com/nspcc-dev/neofs-sdk-go/container/id" netmapSDK "github.com/nspcc-dev/neofs-sdk-go/netmap" @@ -12,6 +14,12 @@ import ( type netMapBuilder struct { nmSrc netmap.Source + // mtx protects lastNm and containerCache fields. + mtx sync.Mutex + lastNm *netmapSDK.Netmap + // containerCache caches container nodes by ID. It is used to skip `GetContainerNodes` invocation if + // neither netmap nor container has changed. + containerCache simplelru.LRUCache } type netMapSrc struct { @@ -20,15 +28,22 @@ type netMapSrc struct { nm *netmapSDK.Netmap } +// defaultContainerCacheSize is the default size for the container cache. +const defaultContainerCacheSize = 10 + func NewNetworkMapBuilder(nm *netmapSDK.Netmap) Builder { + cache, _ := simplelru.NewLRU(defaultContainerCacheSize, nil) // no error return &netMapBuilder{ - nmSrc: &netMapSrc{nm: nm}, + nmSrc: &netMapSrc{nm: nm}, + containerCache: cache, } } func NewNetworkMapSourceBuilder(nmSrc netmap.Source) Builder { + cache, _ := simplelru.NewLRU(defaultContainerCacheSize, nil) // no error return &netMapBuilder{ - nmSrc: nmSrc, + nmSrc: nmSrc, + containerCache: cache, } } @@ -45,11 +60,28 @@ func (b *netMapBuilder) BuildPlacement(cnr cid.ID, obj *oid.ID, p *netmapSDK.Pla binCnr := make([]byte, sha256.Size) cnr.Encode(binCnr) + b.mtx.Lock() + if nm == b.lastNm { + raw, ok := b.containerCache.Get(string(binCnr)) + b.mtx.Unlock() + if ok { + cn := raw.(netmapSDK.ContainerNodes) + return BuildObjectPlacement(nm, cn, obj) + } + } else { + b.containerCache.Purge() + b.mtx.Unlock() + } + cn, err := nm.GetContainerNodes(p, binCnr) if err != nil { return nil, fmt.Errorf("could not get container nodes: %w", err) } + b.mtx.Lock() + b.containerCache.Add(string(binCnr), cn) + b.mtx.Unlock() + return BuildObjectPlacement(nm, cn, obj) }