frostfs-node/pkg/core/container/info.go
Alexander Chuprov 9b113c3156
Some checks failed
DCO action / DCO (pull_request) Successful in 59s
Vulncheck / Vulncheck (pull_request) Successful in 1m4s
Pre-commit hooks / Pre-commit (pull_request) Successful in 1m55s
Build / Build Components (pull_request) Successful in 2m4s
Tests and linters / Staticcheck (pull_request) Successful in 2m38s
Tests and linters / Lint (pull_request) Successful in 3m16s
Tests and linters / Run gofumpt (pull_request) Successful in 3m54s
Tests and linters / Tests (pull_request) Successful in 4m12s
Tests and linters / gopls check (pull_request) Successful in 4m31s
Tests and linters / Tests with -race (pull_request) Successful in 4m38s
OCI image / Build container images (push) Failing after 18s
Vulncheck / Vulncheck (push) Successful in 1m2s
Pre-commit hooks / Pre-commit (push) Successful in 1m39s
Build / Build Components (push) Successful in 1m45s
Tests and linters / Staticcheck (push) Successful in 2m18s
Tests and linters / Run gofumpt (push) Successful in 2m46s
Tests and linters / Lint (push) Successful in 3m5s
Tests and linters / Tests with -race (push) Successful in 3m23s
Tests and linters / Tests (push) Successful in 3m52s
Tests and linters / gopls check (push) Successful in 4m18s
[#1613] morph: Add tracing for morph queries to neo-go
Signed-off-by: Alexander Chuprov <a.chuprov@yadro.com>
2025-02-05 16:38:20 +03:00

104 lines
2.1 KiB
Go

package container
import (
"context"
"sync"
utilSync "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/sync"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
)
type Info struct {
Indexed bool
Removed bool
}
type infoValue struct {
info Info
err error
}
type InfoProvider interface {
Info(ctx context.Context, id cid.ID) (Info, error)
}
type infoProvider struct {
mtx *sync.RWMutex
cache map[cid.ID]infoValue
kl *utilSync.KeyLocker[cid.ID]
source Source
sourceErr error
sourceOnce *sync.Once
sourceFactory func() (Source, error)
}
func NewInfoProvider(sourceFactory func() (Source, error)) InfoProvider {
return &infoProvider{
mtx: &sync.RWMutex{},
cache: make(map[cid.ID]infoValue),
sourceOnce: &sync.Once{},
kl: utilSync.NewKeyLocker[cid.ID](),
sourceFactory: sourceFactory,
}
}
func (r *infoProvider) Info(ctx context.Context, id cid.ID) (Info, error) {
v, found := r.tryGetFromCache(id)
if found {
return v.info, v.err
}
return r.getFromSource(ctx, id)
}
func (r *infoProvider) tryGetFromCache(id cid.ID) (infoValue, bool) {
r.mtx.RLock()
defer r.mtx.RUnlock()
value, found := r.cache[id]
return value, found
}
func (r *infoProvider) getFromSource(ctx context.Context, id cid.ID) (Info, error) {
r.kl.Lock(id)
defer r.kl.Unlock(id)
if v, ok := r.tryGetFromCache(id); ok {
return v.info, v.err
}
r.sourceOnce.Do(func() {
r.source, r.sourceErr = r.sourceFactory()
})
if r.sourceErr != nil {
return Info{}, r.sourceErr
}
cnr, err := r.source.Get(ctx, id)
var civ infoValue
if err != nil {
if client.IsErrContainerNotFound(err) {
removed, err := WasRemoved(ctx, r.source, id)
if err != nil {
civ.err = err
} else {
civ.info.Removed = removed
}
} else {
civ.err = err
}
} else {
civ.info.Indexed = IsIndexedContainer(cnr.Value)
}
r.putToCache(id, civ)
return civ.info, civ.err
}
func (r *infoProvider) putToCache(id cid.ID, ct infoValue) {
r.mtx.Lock()
defer r.mtx.Unlock()
r.cache[id] = ct
}