forked from TrueCloudLab/frostfs-node
116 lines
2.8 KiB
Go
116 lines
2.8 KiB
Go
package main
|
|
|
|
import (
|
|
"strings"
|
|
"time"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
|
frostfsidcore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/frostfsid"
|
|
"github.com/hashicorp/golang-lru/v2/expirable"
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
)
|
|
|
|
type subjectWithError struct {
|
|
subject *client.Subject
|
|
err error
|
|
}
|
|
|
|
type subjectExtWithError struct {
|
|
subject *client.SubjectExtended
|
|
err error
|
|
}
|
|
|
|
type morphFrostfsIDCache struct {
|
|
subjProvider frostfsidcore.SubjectProvider
|
|
|
|
subjCache *expirable.LRU[util.Uint160, subjectWithError]
|
|
|
|
subjExtCache *expirable.LRU[util.Uint160, subjectExtWithError]
|
|
|
|
metrics cacheMetrics
|
|
}
|
|
|
|
func newMorphFrostfsIDCache(subjProvider frostfsidcore.SubjectProvider, size int, ttl time.Duration, metrics cacheMetrics) frostfsidcore.SubjectProvider {
|
|
return &morphFrostfsIDCache{
|
|
subjProvider: subjProvider,
|
|
|
|
subjCache: expirable.NewLRU(size, func(util.Uint160, subjectWithError) {}, ttl),
|
|
|
|
subjExtCache: expirable.NewLRU(size, func(util.Uint160, subjectExtWithError) {}, ttl),
|
|
|
|
metrics: metrics,
|
|
}
|
|
}
|
|
|
|
func (m *morphFrostfsIDCache) GetSubject(addr util.Uint160) (*client.Subject, error) {
|
|
hit := false
|
|
startedAt := time.Now()
|
|
defer func() {
|
|
m.metrics.AddMethodDuration("GetSubject", time.Since(startedAt), hit)
|
|
}()
|
|
|
|
result, found := m.subjCache.Get(addr)
|
|
if found {
|
|
hit = true
|
|
return result.subject, result.err
|
|
}
|
|
|
|
subj, err := m.subjProvider.GetSubject(addr)
|
|
if err != nil {
|
|
if m.isCacheableError(err) {
|
|
m.subjCache.Add(addr, subjectWithError{
|
|
err: err,
|
|
})
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
m.subjCache.Add(addr, subjectWithError{subject: subj})
|
|
return subj, nil
|
|
}
|
|
|
|
func (m *morphFrostfsIDCache) GetSubjectExtended(addr util.Uint160) (*client.SubjectExtended, error) {
|
|
hit := false
|
|
startedAt := time.Now()
|
|
defer func() {
|
|
m.metrics.AddMethodDuration("GetSubjectExtended", time.Since(startedAt), hit)
|
|
}()
|
|
|
|
result, found := m.subjExtCache.Get(addr)
|
|
if found {
|
|
hit = true
|
|
return result.subject, result.err
|
|
}
|
|
|
|
subjExt, err := m.subjProvider.GetSubjectExtended(addr)
|
|
if err != nil {
|
|
if m.isCacheableError(err) {
|
|
m.subjExtCache.Add(addr, subjectExtWithError{
|
|
err: err,
|
|
})
|
|
m.subjCache.Add(addr, subjectWithError{
|
|
err: err,
|
|
})
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
m.subjExtCache.Add(addr, subjectExtWithError{subject: subjExt})
|
|
m.subjCache.Add(addr, subjectWithError{subject: subjectFromSubjectExtended(subjExt)})
|
|
|
|
return subjExt, nil
|
|
}
|
|
|
|
func (m *morphFrostfsIDCache) isCacheableError(err error) bool {
|
|
return strings.Contains(err.Error(), frostfsidcore.SubjectNotFoundErrorMessage)
|
|
}
|
|
|
|
func subjectFromSubjectExtended(subjExt *client.SubjectExtended) *client.Subject {
|
|
return &client.Subject{
|
|
PrimaryKey: subjExt.PrimaryKey,
|
|
AdditionalKeys: subjExt.AdditionalKeys,
|
|
Namespace: subjExt.Namespace,
|
|
Name: subjExt.Name,
|
|
KV: subjExt.KV,
|
|
}
|
|
}
|