diff --git a/app/ldiff/diff.go b/app/ldiff/diff.go index 877e5f2f..bd9ebcf2 100644 --- a/app/ldiff/diff.go +++ b/app/ldiff/diff.go @@ -7,6 +7,7 @@ package ldiff import ( "bytes" "context" + "encoding/hex" "errors" "github.com/cespare/xxhash" "github.com/huandu/skiplist" @@ -89,6 +90,8 @@ type Diff interface { Elements() []Element // Ids retrieves ids of all elements in the Diff Ids() []string + // Hash returns hash of all elements in the diff + Hash() string } // Remote interface for using in the Diff @@ -169,6 +172,13 @@ func (d *diff) Elements() (elements []Element) { return } +func (d *diff) Hash() string { + d.mu.RLock() + defer d.mu.RUnlock() + res := d.getRange(Range{To: math.MaxUint64}) + return hex.EncodeToString(res.Hash) +} + // RemoveId removes element by id func (d *diff) RemoveId(id string) error { d.mu.Lock() diff --git a/app/ldiff/diff_test.go b/app/ldiff/diff_test.go index d16b17c8..8d8db28d 100644 --- a/app/ldiff/diff_test.go +++ b/app/ldiff/diff_test.go @@ -138,3 +138,13 @@ func BenchmarkDiff_Ranges(b *testing.B) { resBuf = resBuf[:0] } } + +func TestDiff_Hash(t *testing.T) { + d := New(16, 16) + h1 := d.Hash() + assert.NotEmpty(t, h1) + d.Set(Element{Id: "1"}) + h2 := d.Hash() + assert.NotEmpty(t, h2) + assert.NotEqual(t, h1, h2) +} diff --git a/app/ldiff/mock_ldiff/mock_ldiff.go b/app/ldiff/mock_ldiff/mock_ldiff.go index 5c30b515..119d7042 100644 --- a/app/ldiff/mock_ldiff/mock_ldiff.go +++ b/app/ldiff/mock_ldiff/mock_ldiff.go @@ -66,6 +66,20 @@ func (mr *MockDiffMockRecorder) Elements() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Elements", reflect.TypeOf((*MockDiff)(nil).Elements)) } +// Hash mocks base method. +func (m *MockDiff) Hash() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Hash") + ret0, _ := ret[0].(string) + return ret0 +} + +// Hash indicates an expected call of Hash. +func (mr *MockDiffMockRecorder) Hash() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Hash", reflect.TypeOf((*MockDiff)(nil).Hash)) +} + // Ids mocks base method. func (m *MockDiff) Ids() []string { m.ctrl.T.Helper() diff --git a/commonspace/headsync/headsync.go b/commonspace/headsync/headsync.go index f7f78b6d..ec71f1ad 100644 --- a/commonspace/headsync/headsync.go +++ b/commonspace/headsync/headsync.go @@ -29,6 +29,9 @@ type HeadSync interface { DebugAllHeads() (res []TreeHeads) Init(objectIds []string, deletionState deletionstate.DeletionState) + + StateHash() string + Close() (err error) } @@ -103,6 +106,10 @@ func (d *headSync) RemoveObjects(ids []string) { d.syncer.RemoveObjects(ids) } +func (d *headSync) StateHash() string { + return d.diff.Hash() +} + func (d *headSync) Close() (err error) { d.periodicSync.Close() return nil diff --git a/commonspace/space.go b/commonspace/space.go index 9c16333d..1f28e327 100644 --- a/commonspace/space.go +++ b/commonspace/space.go @@ -88,6 +88,7 @@ type Space interface { BuildTree(ctx context.Context, id string, opts BuildTreeOpts) (t objecttree.ObjectTree, err error) DeleteTree(ctx context.Context, id string) (err error) + HeadSync() headsync.HeadSync SyncStatus() syncstatus.StatusUpdater Storage() spacestorage.SpaceStorage