143 lines
3.2 KiB
Go
143 lines
3.2 KiB
Go
package blobovniczatree
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"path/filepath"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobovnicza"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// Open opens blobovnicza tree.
|
|
func (b *Blobovniczas) Open(readOnly bool) error {
|
|
b.readOnly = readOnly
|
|
b.metrics.SetMode(readOnly)
|
|
return nil
|
|
}
|
|
|
|
// Init initializes blobovnicza tree.
|
|
//
|
|
// Should be called exactly once.
|
|
func (b *Blobovniczas) Init() error {
|
|
b.log.Debug(logs.BlobovniczatreeInitializingBlobovniczas)
|
|
|
|
if b.readOnly {
|
|
b.log.Debug(logs.BlobovniczatreeReadonlyModeSkipBlobovniczasInitialization)
|
|
return nil
|
|
}
|
|
|
|
return b.iterateLeaves(context.TODO(), func(p string) (bool, error) {
|
|
blz, err := b.openBlobovniczaNoCache(p)
|
|
if err != nil {
|
|
return true, err
|
|
}
|
|
defer blz.Close()
|
|
|
|
if err := blz.Init(); err != nil {
|
|
return true, fmt.Errorf("could not initialize blobovnicza structure %s: %w", p, err)
|
|
}
|
|
|
|
b.log.Debug(logs.BlobovniczatreeBlobovniczaSuccessfullyInitializedClosing, zap.String("id", p))
|
|
return false, nil
|
|
})
|
|
}
|
|
|
|
// Close implements common.Storage.
|
|
func (b *Blobovniczas) Close() error {
|
|
b.activeMtx.Lock()
|
|
|
|
b.lruMtx.Lock()
|
|
|
|
for p, v := range b.active {
|
|
if err := v.blz.Close(); err != nil {
|
|
b.log.Debug(logs.BlobovniczatreeCouldNotCloseActiveBlobovnicza,
|
|
zap.String("path", p),
|
|
zap.String("error", err.Error()),
|
|
)
|
|
}
|
|
b.opened.Remove(p)
|
|
}
|
|
for _, k := range b.opened.Keys() {
|
|
blz, _ := b.opened.Get(k)
|
|
if err := blz.Close(); err != nil {
|
|
b.log.Debug(logs.BlobovniczatreeCouldNotCloseActiveBlobovnicza,
|
|
zap.String("path", k),
|
|
zap.String("error", err.Error()),
|
|
)
|
|
}
|
|
b.opened.Remove(k)
|
|
}
|
|
|
|
b.active = make(map[string]blobovniczaWithIndex)
|
|
b.metrics.Close()
|
|
|
|
b.lruMtx.Unlock()
|
|
|
|
b.activeMtx.Unlock()
|
|
|
|
return nil
|
|
}
|
|
|
|
// opens and returns blobovnicza with path p.
|
|
//
|
|
// If blobovnicza is already opened and cached, instance from cache is returned w/o changes.
|
|
func (b *Blobovniczas) openBlobovnicza(p string) (*blobovnicza.Blobovnicza, error) {
|
|
b.lruMtx.Lock()
|
|
v, ok := b.opened.Get(p)
|
|
b.lruMtx.Unlock()
|
|
if ok {
|
|
// blobovnicza should be opened in cache
|
|
return v, nil
|
|
}
|
|
|
|
lvlPath := filepath.Dir(p)
|
|
curIndex := u64FromHexString(filepath.Base(p))
|
|
|
|
b.activeMtx.RLock()
|
|
defer b.activeMtx.RUnlock()
|
|
|
|
active, ok := b.active[lvlPath]
|
|
if ok && active.ind == curIndex {
|
|
return active.blz, nil
|
|
}
|
|
|
|
b.lruMtx.Lock()
|
|
defer b.lruMtx.Unlock()
|
|
|
|
v, ok = b.opened.Get(p)
|
|
if ok {
|
|
return v, nil
|
|
}
|
|
|
|
blz, err := b.openBlobovniczaNoCache(p)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
b.opened.Add(p, blz)
|
|
|
|
return blz, nil
|
|
}
|
|
|
|
func (b *Blobovniczas) openBlobovniczaNoCache(p string) (*blobovnicza.Blobovnicza, error) {
|
|
b.openMtx.Lock()
|
|
defer b.openMtx.Unlock()
|
|
|
|
path := filepath.Join(b.rootPath, p)
|
|
|
|
blz := blobovnicza.New(append(b.blzOpts,
|
|
blobovnicza.WithReadOnly(b.readOnly),
|
|
blobovnicza.WithPath(path),
|
|
blobovnicza.WithMetrics(b.metrics.Blobovnicza()),
|
|
)...)
|
|
|
|
if err := blz.Open(); err != nil {
|
|
return nil, fmt.Errorf("could not open blobovnicza %s: %w", p, err)
|
|
}
|
|
if err := blz.Init(); err != nil {
|
|
return nil, fmt.Errorf("could not init blobovnicza %s: %w", p, err)
|
|
}
|
|
return blz, nil
|
|
}
|