[#1248] placement: Use epoch to track netmap versions

Previously we used pointer, this could have worked,
because most of the time, the netmap is cached.
This didn't work, however, because `lastNm` field was always nil.

Rework the mechanism completely:
1. Use epoch to track netmap versions, as it it simpler and
   is unrelated to the TTL of an underlying cache.
2. Fix a bug where the epoch could change while mutex was unlocked.

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
This commit is contained in:
Evgenii Stratonikov 2024-07-12 17:16:06 +03:00 committed by Evgenii Stratonikov
parent 21431f22c0
commit 3a48b282b6

View file

@ -14,9 +14,10 @@ import (
type netMapBuilder struct {
nmSrc netmap.Source
// mtx protects lastNm and containerCache fields.
// mtx protects lastEpoch and containerCache fields.
mtx sync.Mutex
lastNm *netmapSDK.NetMap
// lastEpoch contains contains network map epoch for all values in the container cache.
lastEpoch uint64
// containerCache caches container nodes by ID. It is used to skip `GetContainerNodes` invocation if
// neither netmap nor container has changed.
containerCache simplelru.LRUCache[cid.ID, [][]netmapSDK.NodeInfo]
@ -61,13 +62,14 @@ func (b *netMapBuilder) BuildPlacement(cnr cid.ID, obj *oid.ID, p netmapSDK.Plac
cnr.Encode(binCnr)
b.mtx.Lock()
if nm == b.lastNm {
if nm.Epoch() == b.lastEpoch {
raw, ok := b.containerCache.Get(cnr)
b.mtx.Unlock()
if ok {
return BuildObjectPlacement(nm, raw, obj)
}
} else {
b.lastEpoch = nm.Epoch()
b.containerCache.Purge()
b.mtx.Unlock()
}
@ -78,7 +80,9 @@ func (b *netMapBuilder) BuildPlacement(cnr cid.ID, obj *oid.ID, p netmapSDK.Plac
}
b.mtx.Lock()
if b.lastEpoch == nm.Epoch() {
b.containerCache.Add(cnr, cn)
}
b.mtx.Unlock()
return BuildObjectPlacement(nm, cn, obj)