mirror of
https://github.com/anyproto/any-sync.git
synced 2025-06-08 05:57:03 +09:00
Add compare diff
This commit is contained in:
parent
15a82b8675
commit
e03f2e6efd
2 changed files with 110 additions and 5 deletions
|
@ -42,6 +42,11 @@ type Diff interface {
|
|||
DiffType() spacesyncproto.DiffType
|
||||
}
|
||||
|
||||
type CompareDiff interface {
|
||||
CompareDiff(ctx context.Context, dl Remote) (newIds, ourChangedIds, theirChangedIds, removedIds []string, err error)
|
||||
Diff
|
||||
}
|
||||
|
||||
// New creates precalculated Diff container
|
||||
//
|
||||
// divideFactor - means how many hashes you want to ask for once
|
||||
|
@ -273,17 +278,18 @@ func (d *diff) Ranges(ctx context.Context, ranges []Range, resBuf []RangeResult)
|
|||
}
|
||||
|
||||
type diffCtx struct {
|
||||
newIds, changedIds, removedIds []string
|
||||
newIds, changedIds, theirChangedIds, removedIds []string
|
||||
|
||||
toSend, prepare []Range
|
||||
myRes, otherRes []RangeResult
|
||||
compareFunc func(dctx *diffCtx, my, other []Element)
|
||||
}
|
||||
|
||||
var errMismatched = errors.New("query and results mismatched")
|
||||
|
||||
// Diff makes diff with remote container
|
||||
func (d *diff) Diff(ctx context.Context, dl Remote) (newIds, changedIds, removedIds []string, err error) {
|
||||
dctx := &diffCtx{}
|
||||
dctx := &diffCtx{compareFunc: d.compareElementsEqual}
|
||||
dctx.toSend = append(dctx.toSend, Range{
|
||||
From: 0,
|
||||
To: math.MaxUint64,
|
||||
|
@ -314,18 +320,51 @@ func (d *diff) Diff(ctx context.Context, dl Remote) (newIds, changedIds, removed
|
|||
return dctx.newIds, dctx.changedIds, dctx.removedIds, nil
|
||||
}
|
||||
|
||||
func (d *diff) CompareDiff(ctx context.Context, dl Remote) (newIds, ourChangedIds, theirChangedIds, removedIds []string, err error) {
|
||||
dctx := &diffCtx{compareFunc: d.compareElementsGreater}
|
||||
dctx.toSend = append(dctx.toSend, Range{
|
||||
From: 0,
|
||||
To: math.MaxUint64,
|
||||
})
|
||||
for len(dctx.toSend) > 0 {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
err = ctx.Err()
|
||||
return
|
||||
default:
|
||||
}
|
||||
if dctx.otherRes, err = dl.Ranges(ctx, dctx.toSend, dctx.otherRes); err != nil {
|
||||
return
|
||||
}
|
||||
if dctx.myRes, err = d.Ranges(ctx, dctx.toSend, dctx.myRes); err != nil {
|
||||
return
|
||||
}
|
||||
if len(dctx.otherRes) != len(dctx.toSend) || len(dctx.myRes) != len(dctx.toSend) {
|
||||
err = errMismatched
|
||||
return
|
||||
}
|
||||
for i, r := range dctx.toSend {
|
||||
d.compareResults(dctx, r, dctx.myRes[i], dctx.otherRes[i])
|
||||
}
|
||||
dctx.toSend, dctx.prepare = dctx.prepare, dctx.toSend
|
||||
dctx.prepare = dctx.prepare[:0]
|
||||
}
|
||||
return dctx.newIds, dctx.changedIds, dctx.theirChangedIds, dctx.removedIds, nil
|
||||
}
|
||||
|
||||
func (d *diff) compareResults(dctx *diffCtx, r Range, myRes, otherRes RangeResult) {
|
||||
// both hash equals - do nothing
|
||||
if bytes.Equal(myRes.Hash, otherRes.Hash) {
|
||||
return
|
||||
}
|
||||
|
||||
// other has elements
|
||||
if len(otherRes.Elements) == otherRes.Count {
|
||||
if len(myRes.Elements) == myRes.Count {
|
||||
d.compareElements(dctx, myRes.Elements, otherRes.Elements)
|
||||
dctx.compareFunc(dctx, myRes.Elements, otherRes.Elements)
|
||||
} else {
|
||||
r.Elements = true
|
||||
d.compareElements(dctx, d.getRange(r).Elements, otherRes.Elements)
|
||||
dctx.compareFunc(dctx, d.getRange(r).Elements, otherRes.Elements)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -341,7 +380,7 @@ func (d *diff) compareResults(dctx *diffCtx, r Range, myRes, otherRes RangeResul
|
|||
return
|
||||
}
|
||||
|
||||
func (d *diff) compareElements(dctx *diffCtx, my, other []Element) {
|
||||
func (d *diff) compareElementsEqual(dctx *diffCtx, my, other []Element) {
|
||||
find := func(list []Element, targetEl Element) (has, eq bool) {
|
||||
for _, el := range list {
|
||||
if el.Id == targetEl.Id {
|
||||
|
@ -369,3 +408,40 @@ func (d *diff) compareElements(dctx *diffCtx, my, other []Element) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *diff) compareElementsGreater(dctx *diffCtx, my, other []Element) {
|
||||
find := func(list []Element, targetEl Element) (has, equal, greater bool) {
|
||||
for _, el := range list {
|
||||
if el.Id == targetEl.Id {
|
||||
if el.Head == targetEl.Head {
|
||||
return true, true, false
|
||||
}
|
||||
return true, false, el.Head > targetEl.Head
|
||||
}
|
||||
}
|
||||
return false, false, false
|
||||
}
|
||||
|
||||
for _, el := range my {
|
||||
has, eq, theirGreater := find(other, el)
|
||||
if !has {
|
||||
dctx.removedIds = append(dctx.removedIds, el.Id)
|
||||
continue
|
||||
} else {
|
||||
if eq {
|
||||
continue
|
||||
}
|
||||
if theirGreater {
|
||||
dctx.theirChangedIds = append(dctx.theirChangedIds, el.Id)
|
||||
} else {
|
||||
dctx.changedIds = append(dctx.changedIds, el.Id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, el := range other {
|
||||
if has, _, _ := find(my, el); !has {
|
||||
dctx.newIds = append(dctx.newIds, el.Id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -139,6 +139,35 @@ func TestDiff_Diff(t *testing.T) {
|
|||
assert.Len(t, changedIds, length/2)
|
||||
assert.Len(t, removedIds, 0)
|
||||
})
|
||||
t.Run("compare diff", func(t *testing.T) {
|
||||
d1 := New(16, 128).(CompareDiff)
|
||||
d2 := New(16, 128)
|
||||
|
||||
length := 10000
|
||||
for i := 0; i < length; i++ {
|
||||
id := fmt.Sprint(i)
|
||||
head := "a" + uuid.NewString()
|
||||
d1.Set(Element{
|
||||
Id: id,
|
||||
Head: head,
|
||||
})
|
||||
}
|
||||
for i := 0; i < length; i++ {
|
||||
id := fmt.Sprint(i)
|
||||
head := "b" + uuid.NewString()
|
||||
d2.Set(Element{
|
||||
Id: id,
|
||||
Head: head,
|
||||
})
|
||||
}
|
||||
|
||||
newIds, changedIds, theirChangedIds, removedIds, err := d1.CompareDiff(ctx, d2)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, newIds, 0)
|
||||
assert.Len(t, changedIds, 0)
|
||||
assert.Len(t, theirChangedIds, length)
|
||||
assert.Len(t, removedIds, 0)
|
||||
})
|
||||
t.Run("empty", func(t *testing.T) {
|
||||
d1 := New(16, 16)
|
||||
d2 := New(16, 16)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue