[#1234] pilorama: Fix GetByPath() on duplicate directories

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
This commit is contained in:
Evgenii Stratonikov 2024-07-08 13:52:59 +03:00 committed by Evgenii Stratonikov
parent 6ace2f597e
commit b027a7f91e
2 changed files with 46 additions and 15 deletions

View file

@ -906,7 +906,7 @@ func (t *boltForest) TreeGetByPath(ctx context.Context, cid cidSDK.ID, treeID st
b := treeRoot.Bucket(dataBucket) b := treeRoot.Bucket(dataBucket)
i, curNode, err := t.getPathPrefix(b, attr, path[:len(path)-1]) i, curNodes, err := t.getPathPrefixMultiTraversal(b, attr, path[:len(path)-1])
if err != nil { if err != nil {
return err return err
} }
@ -918,21 +918,23 @@ func (t *boltForest) TreeGetByPath(ctx context.Context, cid cidSDK.ID, treeID st
c := b.Cursor() c := b.Cursor()
attrKey := internalKey(nil, attr, path[len(path)-1], curNode, 0) for i := range curNodes {
attrKey = attrKey[:len(attrKey)-8] attrKey := internalKey(nil, attr, path[len(path)-1], curNodes[i], 0)
childKey, _ := c.Seek(attrKey) attrKey = attrKey[:len(attrKey)-8]
for len(childKey) == len(attrKey)+8 && bytes.Equal(attrKey, childKey[:len(childKey)-8]) { childKey, _ := c.Seek(attrKey)
child := binary.LittleEndian.Uint64(childKey[len(childKey)-8:]) for len(childKey) == len(attrKey)+8 && bytes.Equal(attrKey, childKey[:len(childKey)-8]) {
if latest { child := binary.LittleEndian.Uint64(childKey[len(childKey)-8:])
_, ts, _, _ := t.getState(b, stateKey(make([]byte, 9), child)) if latest {
if ts >= maxTimestamp { _, ts, _, _ := t.getState(b, stateKey(make([]byte, 9), child))
nodes = append(nodes[:0], child) if ts >= maxTimestamp {
maxTimestamp = ts nodes = append(nodes[:0], child)
maxTimestamp = ts
}
} else {
nodes = append(nodes, child)
} }
} else { childKey, _ = c.Next()
nodes = append(nodes, child)
} }
childKey, _ = c.Next()
} }
return nil return nil
})) }))
@ -1412,6 +1414,36 @@ func (t *boltForest) TreeListTrees(ctx context.Context, prm TreeListTreesPrm) (*
return &res, nil return &res, nil
} }
func (t *boltForest) getPathPrefixMultiTraversal(bTree *bbolt.Bucket, attr string, path []string) (int, []Node, error) {
c := bTree.Cursor()
var curNodes []Node
nextNodes := []Node{RootID}
var attrKey []byte
for i := range path {
curNodes, nextNodes = nextNodes, curNodes[:0]
for j := range curNodes {
attrKey = internalKey(attrKey, attr, path[i], curNodes[j], 0)
attrKey = attrKey[:len(attrKey)-8]
childKey, value := c.Seek(attrKey)
for len(childKey) == len(attrKey)+8 && bytes.Equal(attrKey, childKey[:len(childKey)-8]) {
if len(value) == 1 && value[0] == 1 {
nextNodes = append(nextNodes, binary.LittleEndian.Uint64(childKey[len(childKey)-8:]))
}
childKey, value = c.Next()
}
}
if len(nextNodes) == 0 {
return i, curNodes, nil
}
}
return len(path), nextNodes, nil
}
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()

View file

@ -10,7 +10,6 @@ import (
) )
func TestDuplicateDirectory(t *testing.T) { func TestDuplicateDirectory(t *testing.T) {
t.Skip()
for i := range providers { for i := range providers {
if providers[i].name == "inmemory" { if providers[i].name == "inmemory" {
continue continue