Add build full tree for history tree

This commit is contained in:
mcrakhman 2023-05-07 20:27:46 +02:00 committed by Mikhail Iudin
parent 527236b17b
commit a6d66c15a0
No known key found for this signature in database
GPG Key ID: FAAAA8BAABDFF1C0
5 changed files with 81 additions and 18 deletions

View File

@ -14,34 +14,47 @@ type historyTree struct {
*objectTree *objectTree
} }
func (h *historyTree) rebuildFromStorage(beforeId string, include bool) (err error) { func (h *historyTree) rebuildFromStorage(params HistoryTreeParams) (err error) {
ot := h.objectTree err = h.rebuild(params)
ot.treeBuilder.Reset() if err != nil {
if beforeId == ot.Id() && !include { return
}
h.aclList.RLock()
defer h.aclList.RUnlock()
state := h.aclList.AclState()
return h.readKeysFromAclState(state)
}
func (h *historyTree) rebuild(params HistoryTreeParams) (err error) {
var (
beforeId = params.BeforeId
include = params.IncludeBeforeId
full = params.BuildFullTree
)
h.treeBuilder.Reset()
if full {
h.tree, err = h.treeBuilder.BuildFull()
return
}
if beforeId == h.Id() && !include {
return ErrLoadBeforeRoot return ErrLoadBeforeRoot
} }
heads := []string{beforeId} heads := []string{beforeId}
if beforeId == "" { if beforeId == "" {
heads, err = ot.treeStorage.Heads() heads, err = h.treeStorage.Heads()
if err != nil { if err != nil {
return return
} }
} else if !include { } else if !include {
beforeChange, err := ot.treeBuilder.loadChange(beforeId) beforeChange, err := h.treeBuilder.loadChange(beforeId)
if err != nil { if err != nil {
return err return err
} }
heads = beforeChange.PreviousIds heads = beforeChange.PreviousIds
} }
ot.tree, err = ot.treeBuilder.build(heads, nil, nil) h.tree, err = h.treeBuilder.build(heads, nil, nil)
if err != nil { return
return
}
ot.aclList.RLock()
defer ot.aclList.RUnlock()
state := ot.aclList.AclState()
return ot.readKeysFromAclState(state)
} }

View File

@ -674,6 +674,37 @@ func TestObjectTree(t *testing.T) {
assert.Equal(t, "0", hTree.Root().Id) assert.Equal(t, "0", hTree.Root().Id)
}) })
t.Run("test history tree build full", func(t *testing.T) {
changeCreator, deps := prepareHistoryTreeDeps(aclList)
// sequence of snapshots: 5->1->0
rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.CreateRaw("1", aclList.Head().Id, "0", true, "0"),
changeCreator.CreateRaw("2", aclList.Head().Id, "1", false, "1"),
changeCreator.CreateRaw("3", aclList.Head().Id, "1", true, "2"),
changeCreator.CreateRaw("4", aclList.Head().Id, "1", false, "2"),
changeCreator.CreateRaw("5", aclList.Head().Id, "1", true, "3", "4"),
changeCreator.CreateRaw("6", aclList.Head().Id, "5", false, "5"),
}
deps.treeStorage.TransactionAdd(rawChanges, []string{"6"})
hTree, err := buildHistoryTree(deps, HistoryTreeParams{
BuildFullTree: true,
})
require.NoError(t, err)
// check tree heads
assert.Equal(t, []string{"6"}, hTree.Heads())
// check tree iterate
var iterChangesId []string
err = hTree.IterateFrom(hTree.Root().Id, nil, func(change *Change) bool {
iterChangesId = append(iterChangesId, change.Id)
return true
})
require.NoError(t, err, "iterate should be without error")
assert.Equal(t, []string{"0", "1", "2", "3", "4", "5", "6"}, iterChangesId)
assert.Equal(t, "0", hTree.Root().Id)
})
t.Run("test history tree include", func(t *testing.T) { t.Run("test history tree include", func(t *testing.T) {
changeCreator, deps := prepareHistoryTreeDeps(aclList) changeCreator, deps := prepareHistoryTreeDeps(aclList)

View File

@ -22,6 +22,7 @@ type HistoryTreeParams struct {
AclList list.AclList AclList list.AclList
BeforeId string BeforeId string
IncludeBeforeId bool IncludeBeforeId bool
BuildFullTree bool
} }
type objectTreeDeps struct { type objectTreeDeps struct {
@ -230,7 +231,7 @@ func buildHistoryTree(deps objectTreeDeps, params HistoryTreeParams) (ht History
} }
hTree := &historyTree{objectTree: objTree} hTree := &historyTree{objectTree: objTree}
err = hTree.rebuildFromStorage(params.BeforeId, params.IncludeBeforeId) err = hTree.rebuildFromStorage(params)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -51,6 +51,22 @@ func (tb *treeBuilder) Build(theirHeads []string, newChanges []*Change) (*Tree,
return tb.build(heads, theirHeads, newChanges) return tb.build(heads, theirHeads, newChanges)
} }
func (tb *treeBuilder) BuildFull() (*Tree, error) {
defer func() {
tb.cache = make(map[string]*Change)
}()
tb.cache = make(map[string]*Change)
heads, err := tb.treeStorage.Heads()
if err != nil {
return nil, err
}
err = tb.buildTree(heads, tb.treeStorage.Id())
if err != nil {
return nil, err
}
return tb.tree, nil
}
func (tb *treeBuilder) build(heads []string, theirHeads []string, newChanges []*Change) (*Tree, error) { func (tb *treeBuilder) build(heads []string, theirHeads []string, newChanges []*Change) (*Tree, error) {
defer func() { defer func() {
tb.cache = make(map[string]*Change) tb.cache = make(map[string]*Change)

View File

@ -323,8 +323,9 @@ type BuildTreeOpts struct {
} }
type HistoryTreeOpts struct { type HistoryTreeOpts struct {
BeforeId string BeforeId string
Include bool Include bool
BuildFullTree bool
} }
func (s *space) BuildTree(ctx context.Context, id string, opts BuildTreeOpts) (t objecttree.ObjectTree, err error) { func (s *space) BuildTree(ctx context.Context, id string, opts BuildTreeOpts) (t objecttree.ObjectTree, err error) {
@ -364,6 +365,7 @@ func (s *space) BuildHistoryTree(ctx context.Context, id string, opts HistoryTre
AclList: s.aclList, AclList: s.aclList,
BeforeId: opts.BeforeId, BeforeId: opts.BeforeId,
IncludeBeforeId: opts.Include, IncludeBeforeId: opts.Include,
BuildFullTree: opts.BuildFullTree,
} }
params.TreeStorage, err = s.storage.TreeStorage(id) params.TreeStorage, err = s.storage.TreeStorage(id)
if err != nil { if err != nil {