Fix treebuilder errors

This commit is contained in:
mcrakhman 2022-12-13 13:57:23 +01:00 committed by Mikhail Iudin
parent f2f2be36e9
commit fa733293cb
No known key found for this signature in database
GPG Key ID: FAAAA8BAABDFF1C0

View File

@ -42,29 +42,44 @@ func (tb *treeBuilder) Reset() {
func (tb *treeBuilder) Build(theirHeads []string, newChanges []*Change) (*Tree, error) { func (tb *treeBuilder) Build(theirHeads []string, newChanges []*Change) (*Tree, error) {
var proposedHeads []string var proposedHeads []string
tb.cache = make(map[string]*Change)
heads, err := tb.treeStorage.Heads() heads, err := tb.treeStorage.Heads()
if err != nil { if err != nil {
return nil, err return nil, err
} }
tb.cache = make(map[string]*Change)
proposedHeads = append(proposedHeads, heads...) // TODO: we can actually get this from database
// getting old common snapshot
oldBreakpoint, err := tb.findBreakpoint(heads, true)
if err != nil {
// this should never error out, because otherwise we have broken data
return nil, fmt.Errorf("findBreakpoint error: %v", err)
}
if len(theirHeads) > 0 { if len(theirHeads) > 0 {
proposedHeads = append(proposedHeads, theirHeads...) proposedHeads = append(proposedHeads, theirHeads...)
} }
for _, ch := range newChanges { for _, ch := range newChanges {
// we don't know what new heads are, so every change can be head
if len(theirHeads) == 0 { if len(theirHeads) == 0 {
// in this case we don't know what new heads are, so every change can be head
proposedHeads = append(proposedHeads, ch.Id) proposedHeads = append(proposedHeads, ch.Id)
} }
tb.cache[ch.Id] = ch tb.cache[ch.Id] = ch
} }
log.With(zap.Strings("heads", proposedHeads)).Debug("building tree") // getting common snapshot for new heads
breakpoint, err := tb.findBreakpoint(proposedHeads) breakpoint, err := tb.findBreakpoint(proposedHeads, false)
if err != nil { if err != nil {
return nil, fmt.Errorf("findBreakpoint error: %v", err) breakpoint = oldBreakpoint
} else {
breakpoint, err = tb.findCommonForTwoSnapshots(oldBreakpoint, breakpoint)
if err != nil {
breakpoint = oldBreakpoint
}
} }
proposedHeads = append(proposedHeads, heads...)
log.With(zap.Strings("heads", proposedHeads)).Debug("building tree")
if err = tb.buildTree(proposedHeads, breakpoint); err != nil { if err = tb.buildTree(proposedHeads, breakpoint); err != nil {
return nil, fmt.Errorf("buildTree error: %v", err) return nil, fmt.Errorf("buildTree error: %v", err)
} }
@ -78,13 +93,12 @@ func (tb *treeBuilder) buildTree(heads []string, breakpoint string) (err error)
return return
} }
tb.tree.AddFast(ch) tb.tree.AddFast(ch)
changes, err := tb.dfs(heads, breakpoint) changes := tb.dfs(heads, breakpoint)
tb.tree.AddFast(changes...) tb.tree.AddFast(changes...)
return return
} }
func (tb *treeBuilder) dfs(heads []string, breakpoint string) (buf []*Change, err error) { func (tb *treeBuilder) dfs(heads []string, breakpoint string) []*Change {
// initializing buffers // initializing buffers
tb.idStack = tb.idStack[:0] tb.idStack = tb.idStack[:0]
tb.loadBuffer = tb.loadBuffer[:0] tb.loadBuffer = tb.loadBuffer[:0]
@ -118,7 +132,7 @@ func (tb *treeBuilder) dfs(heads []string, breakpoint string) (buf []*Change, er
tb.idStack = append(tb.idStack, prev) tb.idStack = append(tb.idStack, prev)
} }
} }
return tb.loadBuffer, nil return tb.loadBuffer
} }
func (tb *treeBuilder) loadChange(id string) (ch *Change, err error) { func (tb *treeBuilder) loadChange(id string) (ch *Change, err error) {
@ -143,18 +157,34 @@ func (tb *treeBuilder) loadChange(id string) (ch *Change, err error) {
return ch, nil return ch, nil
} }
func (tb *treeBuilder) findBreakpoint(heads []string) (breakpoint string, err error) { func (tb *treeBuilder) findBreakpoint(heads []string, noError bool) (breakpoint string, err error) {
var ( var (
ch *Change ch *Change
snapshotIds []string snapshotIds []string
) )
for _, head := range heads { for _, head := range heads {
if ch, err = tb.loadChange(head); err != nil { if ch, err = tb.loadChange(head); err != nil {
return if noError {
return
}
log.With(zap.String("head", head), zap.Error(err)).Debug("couldn't find head")
continue
} }
shId := ch.SnapshotId shId := ch.SnapshotId
if ch.IsSnapshot { if ch.IsSnapshot {
shId = ch.Id shId = ch.Id
} else {
_, err = tb.loadChange(shId)
if err != nil {
if noError {
return
}
log.With(zap.String("snapshot id", shId), zap.Error(err)).Debug("couldn't find head's snapshot")
continue
}
} }
if slice.FindPos(snapshotIds, shId) == -1 { if slice.FindPos(snapshotIds, shId) == -1 {
snapshotIds = append(snapshotIds, shId) snapshotIds = append(snapshotIds, shId)
@ -170,6 +200,7 @@ func (tb *treeBuilder) findCommonSnapshot(snapshotIds []string) (snapshotId stri
return "", fmt.Errorf("snapshots not found") return "", fmt.Errorf("snapshots not found")
} }
// TODO: use divide and conquer to find the snapshot, then we will have only logN findCommonForTwoSnapshots calls
for len(snapshotIds) > 1 { for len(snapshotIds) > 1 {
l := len(snapshotIds) l := len(snapshotIds)
shId, e := tb.findCommonForTwoSnapshots(snapshotIds[l-2], snapshotIds[l-1]) shId, e := tb.findCommonForTwoSnapshots(snapshotIds[l-2], snapshotIds[l-1])