diff --git a/pkg/local_object_storage/engine/tree.go b/pkg/local_object_storage/engine/tree.go index 534103679..a62809d22 100644 --- a/pkg/local_object_storage/engine/tree.go +++ b/pkg/local_object_storage/engine/tree.go @@ -180,3 +180,9 @@ func (e *StorageEngine) TreeDrop(cid cidSDK.ID, treeID string) error { } return err } + +// TreeList implements the pilorama.Forest interface. +func (e *StorageEngine) TreeList(cid cidSDK.ID) ([]string, error) { + //TODO implement me + panic("implement me") +} diff --git a/pkg/local_object_storage/pilorama/boltdb.go b/pkg/local_object_storage/pilorama/boltdb.go index 7e010d87e..9266f7fe4 100644 --- a/pkg/local_object_storage/pilorama/boltdb.go +++ b/pkg/local_object_storage/pilorama/boltdb.go @@ -557,6 +557,31 @@ func (t *boltForest) TreeGetChildren(cid cidSDK.ID, treeID string, nodeID Node) return children, err } +// TreeList implements the Forest interface. +func (t *boltForest) TreeList(cid cidSDK.ID) ([]string, error) { + var ids []string + cidRaw := []byte(cid.EncodeToString()) + cidLen := len(cidRaw) + + err := t.db.View(func(tx *bbolt.Tx) error { + c := tx.Cursor() + for k, _ := c.Seek(cidRaw); k != nil; k, _ = c.Next() { + if !bytes.HasPrefix(k, cidRaw) { + return nil + } + + ids = append(ids, string(k[cidLen:])) + } + + return nil + }) + if err != nil { + return nil, fmt.Errorf("could not list trees: %w", err) + } + + return ids, nil +} + // TreeGetOpLog implements the pilorama.Forest interface. func (t *boltForest) TreeGetOpLog(cid cidSDK.ID, treeID string, height uint64) (Move, error) { key := make([]byte, 8) diff --git a/pkg/local_object_storage/pilorama/forest.go b/pkg/local_object_storage/pilorama/forest.go index bb9e5316d..79aaae91a 100644 --- a/pkg/local_object_storage/pilorama/forest.go +++ b/pkg/local_object_storage/pilorama/forest.go @@ -2,6 +2,7 @@ package pilorama import ( "sort" + "strings" "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard/mode" cidSDK "github.com/nspcc-dev/neofs-sdk-go/container/id" @@ -191,3 +192,20 @@ func (f *memoryForest) TreeDrop(cid cidSDK.ID, treeID string) error { delete(f.treeMap, fullID) return nil } + +// TreeGetTrees implements the pilorama.Forest interface. +func (f *memoryForest) TreeList(cid cidSDK.ID) ([]string, error) { + var res []string + cidStr := cid.EncodeToString() + + for k := range f.treeMap { + cidAndTree := strings.Split(k, "/") + if cidAndTree[0] != cidStr { + continue + } + + res = append(res, cidAndTree[1]) + } + + return res, nil +} diff --git a/pkg/local_object_storage/pilorama/forest_test.go b/pkg/local_object_storage/pilorama/forest_test.go index 016a78efe..1da666ad3 100644 --- a/pkg/local_object_storage/pilorama/forest_test.go +++ b/pkg/local_object_storage/pilorama/forest_test.go @@ -1,6 +1,7 @@ package pilorama import ( + "fmt" "math/rand" "os" "path/filepath" @@ -9,6 +10,7 @@ import ( cidSDK "github.com/nspcc-dev/neofs-sdk-go/container/id" cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test" + objectSDK "github.com/nspcc-dev/neofs-sdk-go/object" "github.com/stretchr/testify/require" ) @@ -720,3 +722,47 @@ func testMove(t *testing.T, s Forest, ts int, node, parent Node, d CIDDescriptor }, })) } + +func TestGetTrees(t *testing.T) { + for i := range providers { + t.Run(providers[i].name, func(t *testing.T) { + testTreeGetTrees(t, providers[i].construct(t)) + }) + } +} + +func testTreeGetTrees(t *testing.T, s Forest) { + cids := []cidSDK.ID{cidtest.ID(), cidtest.ID()} + d := CIDDescriptor{Position: 0, Size: 1} + + treeIDs := make(map[cidSDK.ID][]string, len(cids)) + for i, cid := range cids { + treeIDs[cid] = []string{ + fmt.Sprintf("test1_%d", i), + fmt.Sprintf("test2_%d", i), + fmt.Sprintf("test3_%d", i), + fmt.Sprintf("1test_%d", i), + fmt.Sprintf("2test_%d", i), + fmt.Sprintf("3test_%d", i), + "", + } + } + + for _, cid := range cids { + d.CID = cid + + for _, treeID := range treeIDs[cid] { + _, err := s.TreeAddByPath(d, treeID, objectSDK.AttributeFileName, []string{"path"}, nil) + require.NoError(t, err) + } + } + + for _, cid := range cids { + d.CID = cid + + trees, err := s.TreeList(cid) + require.NoError(t, err) + + require.ElementsMatch(t, treeIDs[cid], trees) + } +} diff --git a/pkg/local_object_storage/pilorama/interface.go b/pkg/local_object_storage/pilorama/interface.go index 02362ba21..34df19f24 100644 --- a/pkg/local_object_storage/pilorama/interface.go +++ b/pkg/local_object_storage/pilorama/interface.go @@ -37,6 +37,9 @@ type Forest interface { // TreeDrop drops a tree from the database. // If the tree is not found, ErrTreeNotFound should be returned. TreeDrop(cid cidSDK.ID, treeID string) error + // TreeList returns all the tree IDs that have been added to the + // passed container ID. Nil slice should be returned if no tree found. + TreeList(cid cidSDK.ID) ([]string, error) } type ForestStorage interface { diff --git a/pkg/local_object_storage/shard/tree.go b/pkg/local_object_storage/shard/tree.go index 54a42f160..617cab0f9 100644 --- a/pkg/local_object_storage/shard/tree.go +++ b/pkg/local_object_storage/shard/tree.go @@ -84,3 +84,9 @@ func (s *Shard) TreeDrop(cid cidSDK.ID, treeID string) error { } return s.pilorama.TreeDrop(cid, treeID) } + +// TreeList implements the pilorama.Forest interface. +func (s *Shard) TreeList(cid cidSDK.ID) ([]string, error) { + //TODO implement me + panic("implement me") +}