2020-10-29 15:53:45 +00:00
|
|
|
package netmap
|
|
|
|
|
|
|
|
import (
|
2021-11-08 13:21:48 +00:00
|
|
|
"bytes"
|
2020-10-29 15:53:45 +00:00
|
|
|
"sync"
|
|
|
|
|
2023-03-07 13:38:26 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
2020-10-29 15:53:45 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type (
|
|
|
|
cleanupTable struct {
|
2023-05-30 07:14:37 +00:00
|
|
|
sync.RWMutex
|
2020-10-29 15:53:45 +00:00
|
|
|
enabled bool
|
|
|
|
threshold uint64
|
2021-11-08 13:21:48 +00:00
|
|
|
lastAccess map[string]epochStampWithNodeInfo
|
2020-10-29 15:53:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
epochStamp struct {
|
|
|
|
epoch uint64
|
|
|
|
removeFlag bool
|
|
|
|
}
|
2021-11-08 13:21:48 +00:00
|
|
|
|
|
|
|
epochStampWithNodeInfo struct {
|
|
|
|
epochStamp
|
|
|
|
|
|
|
|
binNodeInfo []byte
|
2023-10-26 07:36:22 +00:00
|
|
|
|
|
|
|
maintenance bool
|
2021-11-08 13:21:48 +00:00
|
|
|
}
|
2020-10-29 15:53:45 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func newCleanupTable(enabled bool, threshold uint64) cleanupTable {
|
|
|
|
return cleanupTable{
|
|
|
|
enabled: enabled,
|
|
|
|
threshold: threshold,
|
2021-11-08 13:21:48 +00:00
|
|
|
lastAccess: make(map[string]epochStampWithNodeInfo),
|
2020-10-29 15:53:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update cleanup table based on on-chain information about netmap.
|
2022-06-08 23:18:26 +00:00
|
|
|
func (c *cleanupTable) update(snapshot netmap.NetMap, now uint64) {
|
2020-10-29 15:53:45 +00:00
|
|
|
c.Lock()
|
|
|
|
defer c.Unlock()
|
|
|
|
|
2022-06-08 23:18:26 +00:00
|
|
|
nmNodes := snapshot.Nodes()
|
|
|
|
|
2020-10-29 15:53:45 +00:00
|
|
|
// replacing map is less memory efficient but faster
|
2022-06-08 23:18:26 +00:00
|
|
|
newMap := make(map[string]epochStampWithNodeInfo, len(nmNodes))
|
2020-10-29 15:53:45 +00:00
|
|
|
|
2022-06-08 23:18:26 +00:00
|
|
|
for i := range nmNodes {
|
|
|
|
binNodeInfo := nmNodes[i].Marshal()
|
2021-11-08 13:21:48 +00:00
|
|
|
|
2022-10-11 12:49:34 +00:00
|
|
|
keyString := netmap.StringifyPublicKey(nmNodes[i])
|
2021-11-08 13:21:48 +00:00
|
|
|
|
|
|
|
access, ok := c.lastAccess[keyString]
|
|
|
|
if ok {
|
2020-10-29 15:53:45 +00:00
|
|
|
access.removeFlag = false // reset remove Flag on each Update
|
|
|
|
} else {
|
2021-11-08 13:21:48 +00:00
|
|
|
access.epoch = now
|
2020-10-29 15:53:45 +00:00
|
|
|
}
|
2021-11-08 13:21:48 +00:00
|
|
|
|
|
|
|
access.binNodeInfo = binNodeInfo
|
2024-09-18 09:24:53 +00:00
|
|
|
access.maintenance = nmNodes[i].Status().IsMaintenance()
|
2021-11-08 13:21:48 +00:00
|
|
|
|
|
|
|
newMap[keyString] = access
|
2020-10-29 15:53:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
c.lastAccess = newMap
|
|
|
|
}
|
|
|
|
|
2021-11-08 13:21:48 +00:00
|
|
|
// updates last access time of the netmap node by string public key.
|
|
|
|
//
|
|
|
|
// Returns true if at least one condition is met:
|
2022-08-15 16:20:20 +00:00
|
|
|
// - node hasn't been accessed yet;
|
|
|
|
// - remove flag is set;
|
|
|
|
// - binary node info has changed.
|
2021-11-08 13:21:48 +00:00
|
|
|
func (c *cleanupTable) touch(keyString string, now uint64, binNodeInfo []byte) bool {
|
2020-10-29 15:53:45 +00:00
|
|
|
c.Lock()
|
|
|
|
defer c.Unlock()
|
|
|
|
|
|
|
|
access, ok := c.lastAccess[keyString]
|
2021-11-08 13:21:48 +00:00
|
|
|
result := !ok || access.removeFlag || !bytes.Equal(access.binNodeInfo, binNodeInfo)
|
2020-10-29 15:53:45 +00:00
|
|
|
|
|
|
|
access.removeFlag = false // reset remove flag on each touch
|
2024-04-10 11:16:18 +00:00
|
|
|
access.epoch = max(access.epoch, now)
|
2021-11-08 13:21:48 +00:00
|
|
|
access.binNodeInfo = binNodeInfo // update binary node info
|
|
|
|
|
2020-10-29 15:53:45 +00:00
|
|
|
c.lastAccess[keyString] = access
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *cleanupTable) flag(keyString string) {
|
|
|
|
c.Lock()
|
|
|
|
defer c.Unlock()
|
|
|
|
|
|
|
|
if access, ok := c.lastAccess[keyString]; ok {
|
|
|
|
access.removeFlag = true
|
|
|
|
c.lastAccess[keyString] = access
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *cleanupTable) forEachRemoveCandidate(epoch uint64, f func(string) error) error {
|
|
|
|
c.Lock()
|
|
|
|
defer c.Unlock()
|
|
|
|
|
|
|
|
for keyString, access := range c.lastAccess {
|
2023-10-26 07:36:22 +00:00
|
|
|
if !access.maintenance && epoch-access.epoch > c.threshold {
|
2020-10-29 15:53:45 +00:00
|
|
|
access.removeFlag = true // set remove flag
|
|
|
|
c.lastAccess[keyString] = access
|
|
|
|
|
|
|
|
if err := f(keyString); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|