forked from TrueCloudLab/frostfs-node
[#1059] services/tree: Fast sorted listing
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
This commit is contained in:
parent
f23e38c285
commit
e12fcc041d
10 changed files with 638 additions and 29 deletions
|
@ -440,7 +440,94 @@ func (s *Service) GetSubTree(req *GetSubTreeRequest, srv TreeService_GetSubTreeS
|
|||
return getSubTree(srv.Context(), srv, cid, b, s.forest)
|
||||
}
|
||||
|
||||
func getSortedSubTree(ctx context.Context, srv TreeService_GetSubTreeServer, cid cidSDK.ID, b *GetSubTreeRequest_Body, forest pilorama.Forest) error {
|
||||
const batchSize = 1000
|
||||
|
||||
type stackItem struct {
|
||||
values []pilorama.NodeInfo
|
||||
parent pilorama.Node
|
||||
last string
|
||||
}
|
||||
|
||||
// Traverse the tree in a DFS manner. Because we need to support arbitrary depth,
|
||||
// recursive implementation is not suitable here, so we maintain explicit stack.
|
||||
m, p, err := forest.TreeGetMeta(ctx, cid, b.GetTreeId(), b.GetRootId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = srv.Send(&GetSubTreeResponse{
|
||||
Body: &GetSubTreeResponse_Body{
|
||||
NodeId: b.GetRootId(),
|
||||
ParentId: p,
|
||||
Timestamp: m.Time,
|
||||
Meta: metaToProto(m.Items),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stack := []stackItem{{
|
||||
values: nil,
|
||||
parent: b.GetRootId(),
|
||||
last: "",
|
||||
}}
|
||||
|
||||
for {
|
||||
if len(stack) == 0 {
|
||||
break
|
||||
} else if item := &stack[len(stack)-1]; len(item.values) == 0 {
|
||||
nodes, last, err := forest.TreeSortedByFilename(ctx, cid, b.GetTreeId(), item.parent, item.last, batchSize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
item.values = nodes
|
||||
item.last = last
|
||||
|
||||
if len(nodes) == 0 {
|
||||
stack = stack[:len(stack)-1]
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
node := stack[len(stack)-1].values[0]
|
||||
stack[len(stack)-1].values = stack[len(stack)-1].values[1:]
|
||||
|
||||
err = srv.Send(&GetSubTreeResponse{
|
||||
Body: &GetSubTreeResponse_Body{
|
||||
NodeId: node.ID,
|
||||
ParentId: node.ParentID,
|
||||
Timestamp: node.Meta.Time,
|
||||
Meta: metaToProto(node.Meta.Items),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if b.GetDepth() == 0 || uint32(len(stack)) < b.GetDepth() {
|
||||
children, last, err := forest.TreeSortedByFilename(ctx, cid, b.GetTreeId(), node.ID, "", batchSize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(children) != 0 {
|
||||
stack = append(stack, stackItem{
|
||||
values: children,
|
||||
parent: node.ID,
|
||||
last: last,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getSubTree(ctx context.Context, srv TreeService_GetSubTreeServer, cid cidSDK.ID, b *GetSubTreeRequest_Body, forest pilorama.Forest) error {
|
||||
if b.GetOrderBy().GetDirection() == GetSubTreeRequest_Body_Order_Asc {
|
||||
return getSortedSubTree(ctx, srv, cid, b, forest)
|
||||
}
|
||||
|
||||
// Traverse the tree in a DFS manner. Because we need to support arbitrary depth,
|
||||
// recursive implementation is not suitable here, so we maintain explicit stack.
|
||||
m, p, err := forest.TreeGetMeta(ctx, cid, b.GetTreeId(), b.GetRootId())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue