forked from TrueCloudLab/frostfs-node
[#1630] pilorama: Support dropping trees
Signed-off-by: Evgenii Stratonikov <evgeniy@morphbits.ru>
This commit is contained in:
parent
699b534416
commit
a2bb3a2a96
6 changed files with 89 additions and 0 deletions
|
@ -159,3 +159,24 @@ func (e *StorageEngine) TreeGetOpLog(cid cidSDK.ID, treeID string, height uint64
|
||||||
}
|
}
|
||||||
return lm, err
|
return lm, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TreeDrop implements the pilorama.Forest interface.
|
||||||
|
func (e *StorageEngine) TreeDrop(cid cidSDK.ID, treeID string) error {
|
||||||
|
var err error
|
||||||
|
for _, sh := range e.sortShardsByWeight(cid) {
|
||||||
|
err = sh.TreeDrop(cid, treeID)
|
||||||
|
if err != nil {
|
||||||
|
if err == shard.ErrPiloramaDisabled {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if !errors.Is(err, pilorama.ErrTreeNotFound) && !errors.Is(err, shard.ErrReadOnlyMode) {
|
||||||
|
e.reportShardError(sh, "can't perform `TreeDrop`", err,
|
||||||
|
zap.Stringer("cid", cid),
|
||||||
|
zap.String("tree", treeID))
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package pilorama
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
|
@ -579,6 +580,17 @@ func (t *boltForest) TreeGetOpLog(cid cidSDK.ID, treeID string, height uint64) (
|
||||||
return lm, err
|
return lm, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TreeDrop implements the pilorama.Forest interface.
|
||||||
|
func (t *boltForest) TreeDrop(cid cidSDK.ID, treeID string) error {
|
||||||
|
return t.db.Batch(func(tx *bbolt.Tx) error {
|
||||||
|
err := tx.DeleteBucket(bucketName(cid, treeID))
|
||||||
|
if errors.Is(err, bbolt.ErrBucketNotFound) {
|
||||||
|
return ErrTreeNotFound
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (t *boltForest) getPathPrefix(bTree *bbolt.Bucket, attr string, path []string) (int, Node, error) {
|
func (t *boltForest) getPathPrefix(bTree *bbolt.Bucket, attr string, path []string) (int, Node, error) {
|
||||||
c := bTree.Cursor()
|
c := bTree.Cursor()
|
||||||
|
|
||||||
|
|
|
@ -179,3 +179,15 @@ func (f *memoryForest) TreeGetOpLog(cid cidSDK.ID, treeID string, height uint64)
|
||||||
}
|
}
|
||||||
return s.operations[n].Move, nil
|
return s.operations[n].Move, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TreeDrop implements the pilorama.Forest interface.
|
||||||
|
func (f *memoryForest) TreeDrop(cid cidSDK.ID, treeID string) error {
|
||||||
|
fullID := cid.String() + "/" + treeID
|
||||||
|
_, ok := f.treeMap[fullID]
|
||||||
|
if !ok {
|
||||||
|
return ErrTreeNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(f.treeMap, fullID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -167,6 +167,39 @@ func testForestTreeGetChildren(t *testing.T, s Forest) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestForest_TreeDrop(t *testing.T) {
|
||||||
|
for i := range providers {
|
||||||
|
t.Run(providers[i].name, func(t *testing.T) {
|
||||||
|
testForestTreeDrop(t, providers[i].construct(t))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testForestTreeDrop(t *testing.T, s Forest) {
|
||||||
|
cid := cidtest.ID()
|
||||||
|
|
||||||
|
t.Run("return nil if not found", func(t *testing.T) {
|
||||||
|
require.ErrorIs(t, s.TreeDrop(cid, "123"), ErrTreeNotFound)
|
||||||
|
})
|
||||||
|
|
||||||
|
trees := []string{"tree1", "tree2"}
|
||||||
|
d := CIDDescriptor{cid, 0, 1}
|
||||||
|
for i := range trees {
|
||||||
|
_, err := s.TreeAddByPath(d, trees[i], AttributeFilename, []string{"path"},
|
||||||
|
[]KeyValue{{Key: "TreeName", Value: []byte(trees[i])}})
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.TreeDrop(cid, trees[0])
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = s.TreeGetByPath(cid, trees[0], AttributeFilename, []string{"path"}, true)
|
||||||
|
require.ErrorIs(t, err, ErrTreeNotFound)
|
||||||
|
|
||||||
|
_, err = s.TreeGetByPath(cid, trees[1], AttributeFilename, []string{"path"}, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestForest_TreeAdd(t *testing.T) {
|
func TestForest_TreeAdd(t *testing.T) {
|
||||||
for i := range providers {
|
for i := range providers {
|
||||||
t.Run(providers[i].name, func(t *testing.T) {
|
t.Run(providers[i].name, func(t *testing.T) {
|
||||||
|
|
|
@ -34,6 +34,9 @@ type Forest interface {
|
||||||
// TreeGetOpLog returns first log operation stored at or above the height.
|
// TreeGetOpLog returns first log operation stored at or above the height.
|
||||||
// In case no such operation is found, empty Move and nil error should be returned.
|
// In case no such operation is found, empty Move and nil error should be returned.
|
||||||
TreeGetOpLog(cid cidSDK.ID, treeID string, height uint64) (Move, error)
|
TreeGetOpLog(cid cidSDK.ID, treeID string, height uint64) (Move, error)
|
||||||
|
// TreeDrop drops a tree from the database.
|
||||||
|
// If the tree is not found, ErrTreeNotFound should be returned.
|
||||||
|
TreeDrop(cid cidSDK.ID, treeID string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type ForestStorage interface {
|
type ForestStorage interface {
|
||||||
|
|
|
@ -76,3 +76,11 @@ func (s *Shard) TreeGetOpLog(cid cidSDK.ID, treeID string, height uint64) (pilor
|
||||||
}
|
}
|
||||||
return s.pilorama.TreeGetOpLog(cid, treeID, height)
|
return s.pilorama.TreeGetOpLog(cid, treeID, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TreeDrop implements the pilorama.Forest interface.
|
||||||
|
func (s *Shard) TreeDrop(cid cidSDK.ID, treeID string) error {
|
||||||
|
if s.pilorama == nil {
|
||||||
|
return ErrPiloramaDisabled
|
||||||
|
}
|
||||||
|
return s.pilorama.TreeDrop(cid, treeID)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue