1
0
Fork 0
mirror of https://github.com/anyproto/any-sync.git synced 2025-06-08 05:57:03 +09:00
any-sync/commonspace/object/tree/objecttree/treereduce.go
2023-01-05 15:34:09 +03:00

92 lines
1.9 KiB
Go

package objecttree
import "math"
// clearPossibleRoots force removes any snapshots which can further be deemed as roots
func (t *Tree) clearPossibleRoots() {
t.possibleRoots = t.possibleRoots[:0]
}
// checkRoot checks if a change can be a new root for the tree
// it returns total changes which were discovered during dfsPrev from heads
func (t *Tree) checkRoot(change *Change) (total int) {
t.stackBuf = t.stackBuf[:0]
stack := t.stackBuf
// starting with heads
for _, h := range t.headIds {
stack = append(stack, t.attached[h])
}
t.dfsPrev(
stack,
[]string{change.Id},
func(ch *Change) bool {
total += 1
return true
},
func(changes []*Change) {
if t.root.visited {
total = -1
}
},
)
return
}
// makeRootAndRemove removes all changes before start and makes start the root
func (t *Tree) makeRootAndRemove(start *Change) {
t.stackBuf = t.stackBuf[:0]
stack := t.stackBuf
for _, prev := range start.PreviousIds {
stack = append(stack, t.attached[prev])
}
t.dfsPrev(
stack,
[]string{},
func(ch *Change) bool {
return true
},
func(changes []*Change) {
for _, ch := range changes {
delete(t.attached, ch.Id)
}
},
)
// removing unattached because they may refer to previous root
t.unAttached = make(map[string]*Change)
t.root = start
}
// reduceTree tries to reduce the tree to one of possible tree roots
func (t *Tree) reduceTree() (res bool) {
if len(t.possibleRoots) == 0 {
return
}
var (
minRoot *Change
minTotal = math.MaxInt
)
// checking if we can reduce tree to other root
for _, root := range t.possibleRoots {
totalChanges := t.checkRoot(root)
// we prefer new root with min amount of total changes
if totalChanges != -1 && totalChanges < minTotal {
minRoot = root
minTotal = totalChanges
}
}
t.clearPossibleRoots()
if minRoot == nil {
return
}
t.makeRootAndRemove(minRoot)
res = true
return
}