merge and fix test

This commit is contained in:
Sergey Cherepanov 2022-10-11 12:20:49 +03:00
commit bc9ffc1a79
No known key found for this signature in database
GPG Key ID: 87F8EDE8FBDF637C
47 changed files with 3480 additions and 606 deletions

View File

@ -31,12 +31,15 @@ proto:
$(GOGO_START) protoc --gogofaster_out=$(PKGMAP):. --go-drpc_out=protolib=github.com/gogo/protobuf:. common/commonspace/spacesyncproto/protos/*.proto $(GOGO_START) protoc --gogofaster_out=$(PKGMAP):. --go-drpc_out=protolib=github.com/gogo/protobuf:. common/commonspace/spacesyncproto/protos/*.proto
$(GOGO_START) protoc --gogofaster_out=:. --go-drpc_out=protolib=github.com/gogo/protobuf:. consensus/consensusproto/protos/*.proto $(GOGO_START) protoc --gogofaster_out=:. --go-drpc_out=protolib=github.com/gogo/protobuf:. consensus/consensusproto/protos/*.proto
build: build:
@$(eval FLAGS := $$(shell govvv -flags -pkg github.com/anytypeio/go-anytype-infrastructure-experiments/app)) @$(eval FLAGS := $$(shell govvv -flags -pkg github.com/anytypeio/go-anytype-infrastructure-experiments/app))
go build -v -o bin/anytype-node -ldflags "$(FLAGS)" cmd/node/node.go go build -v -o bin/anytype-node -ldflags "$(FLAGS)" cmd/node/node.go
test-deps:
@echo 'Generating test mocks...'
@go install github.com/golang/mock/mockgen
@go generate ./...
build-consensus: build-consensus:
@$(eval FLAGS := $$(shell govvv -flags -pkg github.com/anytypeio/go-anytype-infrastructure-experiments/app)) @$(eval FLAGS := $$(shell govvv -flags -pkg github.com/anytypeio/go-anytype-infrastructure-experiments/app))
go build -v -o bin/consensus-node -ldflags "$(FLAGS)" github.com/anytypeio/go-anytype-infrastructure-experiments/cmd/consensusnode go build -v -o bin/consensus-node -ldflags "$(FLAGS)" github.com/anytypeio/go-anytype-infrastructure-experiments/cmd/consensusnode

View File

@ -0,0 +1,108 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache (interfaces: TreeCache)
// Package mock_cache is a generated GoMock package.
package mock_cache
import (
context "context"
reflect "reflect"
app "github.com/anytypeio/go-anytype-infrastructure-experiments/app"
cache "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
gomock "github.com/golang/mock/gomock"
)
// MockTreeCache is a mock of TreeCache interface.
type MockTreeCache struct {
ctrl *gomock.Controller
recorder *MockTreeCacheMockRecorder
}
// MockTreeCacheMockRecorder is the mock recorder for MockTreeCache.
type MockTreeCacheMockRecorder struct {
mock *MockTreeCache
}
// NewMockTreeCache creates a new mock instance.
func NewMockTreeCache(ctrl *gomock.Controller) *MockTreeCache {
mock := &MockTreeCache{ctrl: ctrl}
mock.recorder = &MockTreeCacheMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockTreeCache) EXPECT() *MockTreeCacheMockRecorder {
return m.recorder
}
// Close mocks base method.
func (m *MockTreeCache) Close(arg0 context.Context) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Close", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// Close indicates an expected call of Close.
func (mr *MockTreeCacheMockRecorder) Close(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockTreeCache)(nil).Close), arg0)
}
// GetTree mocks base method.
func (m *MockTreeCache) GetTree(arg0 context.Context, arg1, arg2 string) (cache.TreeResult, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetTree", arg0, arg1, arg2)
ret0, _ := ret[0].(cache.TreeResult)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetTree indicates an expected call of GetTree.
func (mr *MockTreeCacheMockRecorder) GetTree(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTree", reflect.TypeOf((*MockTreeCache)(nil).GetTree), arg0, arg1, arg2)
}
// Init mocks base method.
func (m *MockTreeCache) Init(arg0 *app.App) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Init", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// Init indicates an expected call of Init.
func (mr *MockTreeCacheMockRecorder) Init(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockTreeCache)(nil).Init), arg0)
}
// Name mocks base method.
func (m *MockTreeCache) Name() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Name")
ret0, _ := ret[0].(string)
return ret0
}
// Name indicates an expected call of Name.
func (mr *MockTreeCacheMockRecorder) Name() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockTreeCache)(nil).Name))
}
// Run mocks base method.
func (m *MockTreeCache) Run(arg0 context.Context) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Run", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// Run indicates an expected call of Run.
func (mr *MockTreeCacheMockRecorder) Run(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*MockTreeCache)(nil).Run), arg0)
}

View File

@ -1,3 +1,4 @@
//go:generate mockgen -destination mock_cache/mock_cache.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache TreeCache
package cache package cache
import ( import (

View File

@ -1,3 +1,4 @@
//go:generate mockgen -destination mock_diffservice/mock_diffservice.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice DiffSyncer,PeriodicSync
package diffservice package diffservice
import ( import (
@ -6,13 +7,10 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/remotediff" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/remotediff"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/rpcerr"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff"
"go.uber.org/zap" "go.uber.org/zap"
"strings" "strings"
"time"
) )
type DiffService interface { type DiffService interface {
@ -26,11 +24,9 @@ type DiffService interface {
type diffService struct { type diffService struct {
spaceId string spaceId string
periodicSync *periodicSync periodicSync PeriodicSync
storage storage.SpaceStorage storage storage.SpaceStorage
nconf nodeconf.Configuration
diff ldiff.Diff diff ldiff.Diff
cache cache.TreeCache
log *zap.Logger log *zap.Logger
syncPeriod int syncPeriod int
@ -40,23 +36,29 @@ func NewDiffService(
spaceId string, spaceId string,
syncPeriod int, syncPeriod int,
storage storage.SpaceStorage, storage storage.SpaceStorage,
nconf nodeconf.Configuration, confConnector nodeconf.ConfConnector,
cache cache.TreeCache, cache cache.TreeCache,
log *zap.Logger) DiffService { log *zap.Logger) DiffService {
diff := ldiff.New(16, 16)
l := log.With(zap.String("spaceId", spaceId))
factory := spacesyncproto.ClientFactoryFunc(spacesyncproto.NewDRPCSpaceClient)
syncer := newDiffSyncer(spaceId, diff, confConnector, cache, storage, factory, l)
periodicSync := newPeriodicSync(syncPeriod, syncer, l)
return &diffService{ return &diffService{
spaceId: spaceId, spaceId: spaceId,
storage: storage, storage: storage,
nconf: nconf, periodicSync: periodicSync,
cache: cache, diff: diff,
log: log, log: log,
syncPeriod: syncPeriod, syncPeriod: syncPeriod,
} }
} }
func (d *diffService) Init(objectIds []string) { func (d *diffService) Init(objectIds []string) {
d.periodicSync = newPeriodicSync(d.syncPeriod, d.sync, d.log.With(zap.String("spaceId", d.spaceId)))
d.diff = ldiff.New(16, 16)
d.fillDiff(objectIds) d.fillDiff(objectIds)
d.periodicSync.Run()
} }
func (d *diffService) HandleRangeRequest(ctx context.Context, req *spacesyncproto.HeadSyncRequest) (resp *spacesyncproto.HeadSyncResponse, err error) { func (d *diffService) HandleRangeRequest(ctx context.Context, req *spacesyncproto.HeadSyncRequest) (resp *spacesyncproto.HeadSyncResponse, err error) {
@ -80,49 +82,6 @@ func (d *diffService) Close() (err error) {
return nil return nil
} }
func (d *diffService) sync(ctx context.Context) error {
st := time.Now()
// diffing with responsible peers according to configuration
peers, err := d.nconf.ResponsiblePeers(ctx, d.spaceId)
if err != nil {
return err
}
for _, p := range peers {
if err := d.syncWithPeer(ctx, p); err != nil {
d.log.Error("can't sync with peer", zap.String("peer", p.Id()), zap.Error(err))
}
}
d.log.Info("synced", zap.String("spaceId", d.spaceId), zap.Duration("dur", time.Since(st)))
return nil
}
func (d *diffService) syncWithPeer(ctx context.Context, p peer.Peer) (err error) {
cl := spacesyncproto.NewDRPCSpaceClient(p)
rdiff := remotediff.NewRemoteDiff(d.spaceId, cl)
newIds, changedIds, removedIds, err := d.diff.Diff(ctx, rdiff)
err = rpcerr.Unwrap(err)
if err != nil && err != spacesyncproto.ErrSpaceMissing {
return err
}
if err == spacesyncproto.ErrSpaceMissing {
return d.sendPushSpaceRequest(ctx, cl)
}
d.pingTreesInCache(ctx, newIds)
d.pingTreesInCache(ctx, changedIds)
d.log.Info("sync done:", zap.Int("newIds", len(newIds)),
zap.Int("changedIds", len(changedIds)),
zap.Int("removedIds", len(removedIds)))
return
}
func (d *diffService) pingTreesInCache(ctx context.Context, trees []string) {
for _, tId := range trees {
_, _ = d.cache.GetTree(ctx, d.spaceId, tId)
}
}
func (d *diffService) fillDiff(objectIds []string) { func (d *diffService) fillDiff(objectIds []string) {
var els = make([]ldiff.Element, 0, len(objectIds)) var els = make([]ldiff.Element, 0, len(objectIds))
for _, id := range objectIds { for _, id := range objectIds {
@ -142,30 +101,6 @@ func (d *diffService) fillDiff(objectIds []string) {
d.diff.Set(els...) d.diff.Set(els...)
} }
func (d *diffService) sendPushSpaceRequest(ctx context.Context, cl spacesyncproto.DRPCSpaceClient) (err error) {
aclStorage, err := d.storage.ACLStorage()
if err != nil {
return
}
root, err := aclStorage.Root()
if err != nil {
return
}
header, err := d.storage.SpaceHeader()
if err != nil {
return
}
_, err = cl.PushSpace(ctx, &spacesyncproto.PushSpaceRequest{
SpaceId: d.spaceId,
SpaceHeader: header,
AclRoot: root,
})
return
}
func concatStrings(strs []string) string { func concatStrings(strs []string) string {
var ( var (
b strings.Builder b strings.Builder

View File

@ -0,0 +1,59 @@
package diffservice
import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice/mock_diffservice"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage/mock_storage"
mock_storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage/mock_storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff/mock_ldiff"
"github.com/golang/mock/gomock"
"testing"
)
func TestDiffService(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
spaceId := "spaceId"
l := logger.NewNamed("sync")
pSyncMock := mock_diffservice.NewMockPeriodicSync(ctrl)
storageMock := mock_storage.NewMockSpaceStorage(ctrl)
treeStorageMock := mock_storage2.NewMockTreeStorage(ctrl)
diffMock := mock_ldiff.NewMockDiff(ctrl)
syncPeriod := 1
initId := "initId"
service := &diffService{
spaceId: spaceId,
storage: storageMock,
periodicSync: pSyncMock,
diff: diffMock,
log: l,
syncPeriod: syncPeriod,
}
t.Run("init", func(t *testing.T) {
storageMock.EXPECT().TreeStorage(initId).Return(treeStorageMock, nil)
treeStorageMock.EXPECT().Heads().Return([]string{"h1", "h2"}, nil)
diffMock.EXPECT().Set(ldiff.Element{
Id: initId,
Head: "h1h2",
})
pSyncMock.EXPECT().Run()
service.Init([]string{initId})
})
t.Run("update heads", func(t *testing.T) {
diffMock.EXPECT().Set(ldiff.Element{
Id: initId,
Head: "h1h2",
})
service.UpdateHeads(initId, []string{"h1", "h2"})
})
t.Run("close", func(t *testing.T) {
pSyncMock.EXPECT().Close()
service.Close()
})
}

View File

@ -0,0 +1,115 @@
package diffservice
import (
"context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/remotediff"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/rpcerr"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff"
"go.uber.org/zap"
"time"
)
type DiffSyncer interface {
Sync(ctx context.Context) error
}
func newDiffSyncer(
spaceId string,
diff ldiff.Diff,
confConnector nodeconf.ConfConnector,
cache cache.TreeCache,
storage storage.SpaceStorage,
clientFactory spacesyncproto.ClientFactory,
log *zap.Logger) DiffSyncer {
return &diffSyncer{
diff: diff,
spaceId: spaceId,
cache: cache,
storage: storage,
confConnector: confConnector,
clientFactory: clientFactory,
log: log,
}
}
type diffSyncer struct {
spaceId string
diff ldiff.Diff
confConnector nodeconf.ConfConnector
cache cache.TreeCache
storage storage.SpaceStorage
clientFactory spacesyncproto.ClientFactory
log *zap.Logger
}
func (d *diffSyncer) Sync(ctx context.Context) error {
st := time.Now()
// diffing with responsible peers according to configuration
peers, err := d.confConnector.GetResponsiblePeers(ctx, d.spaceId)
if err != nil {
return err
}
for _, p := range peers {
if err := d.syncWithPeer(ctx, p); err != nil {
d.log.Error("can't sync with peer", zap.String("peer", p.Id()), zap.Error(err))
}
}
d.log.Info("synced", zap.String("spaceId", d.spaceId), zap.Duration("dur", time.Since(st)))
return nil
}
func (d *diffSyncer) syncWithPeer(ctx context.Context, p peer.Peer) (err error) {
cl := d.clientFactory.Client(p)
rdiff := remotediff.NewRemoteDiff(d.spaceId, cl)
newIds, changedIds, removedIds, err := d.diff.Diff(ctx, rdiff)
err = rpcerr.Unwrap(err)
if err != nil && err != spacesyncproto.ErrSpaceMissing {
return err
}
if err == spacesyncproto.ErrSpaceMissing {
return d.sendPushSpaceRequest(ctx, cl)
}
d.pingTreesInCache(ctx, newIds)
d.pingTreesInCache(ctx, changedIds)
d.log.Info("sync done:", zap.Int("newIds", len(newIds)),
zap.Int("changedIds", len(changedIds)),
zap.Int("removedIds", len(removedIds)))
return
}
func (d *diffSyncer) pingTreesInCache(ctx context.Context, trees []string) {
for _, tId := range trees {
_, _ = d.cache.GetTree(ctx, d.spaceId, tId)
}
}
func (d *diffSyncer) sendPushSpaceRequest(ctx context.Context, cl spacesyncproto.DRPCSpaceClient) (err error) {
aclStorage, err := d.storage.ACLStorage()
if err != nil {
return
}
root, err := aclStorage.Root()
if err != nil {
return
}
header, err := d.storage.SpaceHeader()
if err != nil {
return
}
_, err = cl.PushSpace(ctx, &spacesyncproto.PushSpaceRequest{
SpaceId: d.spaceId,
SpaceHeader: header,
AclRoot: root,
})
return
}

View File

@ -0,0 +1,162 @@
package diffservice
import (
"context"
"fmt"
"github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache/mock_cache"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/remotediff"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto/mock_spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage/mock_storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf/mock_nodeconf"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclrecordproto"
mock_aclstorage "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage/mock_storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff/mock_ldiff"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
"storj.io/drpc"
"testing"
"time"
)
type pushSpaceRequestMatcher struct {
spaceId string
aclRoot *aclrecordproto.RawACLRecordWithId
spaceHeader *spacesyncproto.SpaceHeader
}
func (p pushSpaceRequestMatcher) Matches(x interface{}) bool {
res, ok := x.(*spacesyncproto.PushSpaceRequest)
if !ok {
return false
}
return res.SpaceId == p.spaceId && res.AclRoot == p.aclRoot && res.SpaceHeader == p.spaceHeader
}
func (p pushSpaceRequestMatcher) String() string {
return ""
}
type mockPeer struct{}
func (m mockPeer) Id() string {
return "mockId"
}
func (m mockPeer) LastUsage() time.Time {
return time.Time{}
}
func (m mockPeer) UpdateLastUsage() {
}
func (m mockPeer) Close() error {
return nil
}
func (m mockPeer) Closed() <-chan struct{} {
return make(chan struct{})
}
func (m mockPeer) Invoke(ctx context.Context, rpc string, enc drpc.Encoding, in, out drpc.Message) error {
return nil
}
func (m mockPeer) NewStream(ctx context.Context, rpc string, enc drpc.Encoding) (drpc.Stream, error) {
return nil, nil
}
func newPushSpaceRequestMatcher(
spaceId string,
aclRoot *aclrecordproto.RawACLRecordWithId,
spaceHeader *spacesyncproto.SpaceHeader) *pushSpaceRequestMatcher {
return &pushSpaceRequestMatcher{
spaceId: spaceId,
aclRoot: aclRoot,
spaceHeader: spaceHeader,
}
}
func TestDiffSyncer_Sync(t *testing.T) {
// setup
ctx := context.Background()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
diffMock := mock_ldiff.NewMockDiff(ctrl)
connectorMock := mock_nodeconf.NewMockConfConnector(ctrl)
cacheMock := mock_cache.NewMockTreeCache(ctrl)
stMock := mock_storage.NewMockSpaceStorage(ctrl)
clientMock := mock_spacesyncproto.NewMockDRPCSpaceClient(ctrl)
factory := spacesyncproto.ClientFactoryFunc(func(cc drpc.Conn) spacesyncproto.DRPCSpaceClient {
return clientMock
})
spaceId := "spaceId"
l := logger.NewNamed(spaceId)
diffSyncer := newDiffSyncer(spaceId, diffMock, connectorMock, cacheMock, stMock, factory, l)
t.Run("diff syncer sync simple", func(t *testing.T) {
connectorMock.EXPECT().
GetResponsiblePeers(gomock.Any(), spaceId).
Return([]peer.Peer{mockPeer{}}, nil)
diffMock.EXPECT().
Diff(gomock.Any(), gomock.Eq(remotediff.NewRemoteDiff(spaceId, clientMock))).
Return([]string{"new"}, []string{"changed"}, nil, nil)
for _, arg := range []string{"new", "changed"} {
cacheMock.EXPECT().
GetTree(gomock.Any(), spaceId, arg).
Return(cache.TreeResult{}, nil)
}
require.NoError(t, diffSyncer.Sync(ctx))
})
t.Run("diff syncer sync conf error", func(t *testing.T) {
connectorMock.EXPECT().
GetResponsiblePeers(gomock.Any(), spaceId).
Return(nil, fmt.Errorf("some error"))
require.Error(t, diffSyncer.Sync(ctx))
})
t.Run("diff syncer sync space missing", func(t *testing.T) {
aclStorageMock := mock_aclstorage.NewMockListStorage(ctrl)
aclRoot := &aclrecordproto.RawACLRecordWithId{}
spaceHeader := &spacesyncproto.SpaceHeader{}
connectorMock.EXPECT().
GetResponsiblePeers(gomock.Any(), spaceId).
Return([]peer.Peer{mockPeer{}}, nil)
diffMock.EXPECT().
Diff(gomock.Any(), gomock.Eq(remotediff.NewRemoteDiff(spaceId, clientMock))).
Return(nil, nil, nil, spacesyncproto.ErrSpaceMissing)
stMock.EXPECT().
ACLStorage().
Return(aclStorageMock, nil)
stMock.EXPECT().
SpaceHeader().
Return(spaceHeader, nil)
aclStorageMock.EXPECT().
Root().
Return(aclRoot, nil)
clientMock.EXPECT().
PushSpace(gomock.Any(), newPushSpaceRequestMatcher(spaceId, aclRoot, spaceHeader)).
Return(nil, nil)
require.NoError(t, diffSyncer.Sync(ctx))
})
t.Run("diff syncer sync other error", func(t *testing.T) {
connectorMock.EXPECT().
GetResponsiblePeers(gomock.Any(), spaceId).
Return([]peer.Peer{mockPeer{}}, nil)
diffMock.EXPECT().
Diff(gomock.Any(), gomock.Eq(remotediff.NewRemoteDiff(spaceId, clientMock))).
Return(nil, nil, nil, spacesyncproto.ErrUnexpected)
require.NoError(t, diffSyncer.Sync(ctx))
})
}

View File

@ -0,0 +1,96 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice (interfaces: DiffSyncer,PeriodicSync)
// Package mock_diffservice is a generated GoMock package.
package mock_diffservice
import (
context "context"
reflect "reflect"
gomock "github.com/golang/mock/gomock"
)
// MockDiffSyncer is a mock of DiffSyncer interface.
type MockDiffSyncer struct {
ctrl *gomock.Controller
recorder *MockDiffSyncerMockRecorder
}
// MockDiffSyncerMockRecorder is the mock recorder for MockDiffSyncer.
type MockDiffSyncerMockRecorder struct {
mock *MockDiffSyncer
}
// NewMockDiffSyncer creates a new mock instance.
func NewMockDiffSyncer(ctrl *gomock.Controller) *MockDiffSyncer {
mock := &MockDiffSyncer{ctrl: ctrl}
mock.recorder = &MockDiffSyncerMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockDiffSyncer) EXPECT() *MockDiffSyncerMockRecorder {
return m.recorder
}
// Sync mocks base method.
func (m *MockDiffSyncer) Sync(arg0 context.Context) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Sync", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// Sync indicates an expected call of Sync.
func (mr *MockDiffSyncerMockRecorder) Sync(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sync", reflect.TypeOf((*MockDiffSyncer)(nil).Sync), arg0)
}
// MockPeriodicSync is a mock of PeriodicSync interface.
type MockPeriodicSync struct {
ctrl *gomock.Controller
recorder *MockPeriodicSyncMockRecorder
}
// MockPeriodicSyncMockRecorder is the mock recorder for MockPeriodicSync.
type MockPeriodicSyncMockRecorder struct {
mock *MockPeriodicSync
}
// NewMockPeriodicSync creates a new mock instance.
func NewMockPeriodicSync(ctrl *gomock.Controller) *MockPeriodicSync {
mock := &MockPeriodicSync{ctrl: ctrl}
mock.recorder = &MockPeriodicSyncMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockPeriodicSync) EXPECT() *MockPeriodicSyncMockRecorder {
return m.recorder
}
// Close mocks base method.
func (m *MockPeriodicSync) Close() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Close")
}
// Close indicates an expected call of Close.
func (mr *MockPeriodicSyncMockRecorder) Close() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockPeriodicSync)(nil).Close))
}
// Run mocks base method.
func (m *MockPeriodicSync) Run() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Run")
}
// Run indicates an expected call of Run.
func (mr *MockPeriodicSyncMockRecorder) Run() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*MockPeriodicSync)(nil).Run))
}

View File

@ -6,25 +6,34 @@ import (
"time" "time"
) )
func newPeriodicSync(periodSeconds int, sync func(ctx context.Context) error, l *zap.Logger) *periodicSync { type PeriodicSync interface {
Run()
Close()
}
func newPeriodicSync(periodSeconds int, syncer DiffSyncer, l *zap.Logger) *periodicSync {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
ps := &periodicSync{ return &periodicSync{
log: l, syncer: syncer,
sync: sync, log: l,
syncCtx: ctx, syncCtx: ctx,
syncCancel: cancel, syncCancel: cancel,
syncLoopDone: make(chan struct{}), syncLoopDone: make(chan struct{}),
periodSeconds: periodSeconds,
} }
go ps.syncLoop(periodSeconds)
return ps
} }
type periodicSync struct { type periodicSync struct {
log *zap.Logger log *zap.Logger
sync func(ctx context.Context) error syncer DiffSyncer
syncCtx context.Context syncCtx context.Context
syncCancel context.CancelFunc syncCancel context.CancelFunc
syncLoopDone chan struct{} syncLoopDone chan struct{}
periodSeconds int
}
func (p *periodicSync) Run() {
go p.syncLoop(p.periodSeconds)
} }
func (p *periodicSync) syncLoop(periodSeconds int) { func (p *periodicSync) syncLoop(periodSeconds int) {
@ -33,7 +42,7 @@ func (p *periodicSync) syncLoop(periodSeconds int) {
doSync := func() { doSync := func() {
ctx, cancel := context.WithTimeout(p.syncCtx, time.Minute) ctx, cancel := context.WithTimeout(p.syncCtx, time.Minute)
defer cancel() defer cancel()
if err := p.sync(ctx); err != nil { if err := p.syncer.Sync(ctx); err != nil {
p.log.Warn("periodic sync error", zap.Error(err)) p.log.Warn("periodic sync error", zap.Error(err))
} }
} }

View File

@ -0,0 +1,38 @@
package diffservice
import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice/mock_diffservice"
"github.com/golang/mock/gomock"
"testing"
"time"
)
func TestPeriodicSync_Run(t *testing.T) {
// setup
ctrl := gomock.NewController(t)
defer ctrl.Finish()
l := logger.NewNamed("sync")
diffSyncer := mock_diffservice.NewMockDiffSyncer(ctrl)
t.Run("diff syncer 1 time", func(t *testing.T) {
secs := 0
pSync := newPeriodicSync(secs, diffSyncer, l)
diffSyncer.EXPECT().Sync(gomock.Any()).Times(1).Return(nil)
pSync.Run()
pSync.Close()
})
t.Run("diff syncer 2 times", func(t *testing.T) {
secs := 1
pSync := newPeriodicSync(secs, diffSyncer, l)
diffSyncer.EXPECT().Sync(gomock.Any()).Times(2).Return(nil)
pSync.Run()
time.Sleep(time.Second * time.Duration(secs))
pSync.Close()
})
}

View File

@ -0,0 +1,193 @@
package commonspace
import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclrecordproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/cid"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey"
"hash/fnv"
"math/rand"
"time"
)
func storagePayloadForSpaceCreate(payload SpaceCreatePayload) (storagePayload storage.SpaceStorageCreatePayload, err error) {
// unmarshalling signing and encryption keys
identity, err := payload.SigningKey.GetPublic().Raw()
if err != nil {
return
}
encPubKey, err := payload.EncryptionKey.GetPublic().Raw()
if err != nil {
return
}
// preparing header and space id
bytes := make([]byte, 32)
_, err = rand.Read(bytes)
if err != nil {
return
}
header := &spacesyncproto.SpaceHeader{
Identity: identity,
Timestamp: time.Now().UnixNano(),
SpaceType: payload.SpaceType,
ReplicationKey: payload.ReplicationKey,
Seed: bytes,
}
marshalled, err := header.Marshal()
if err != nil {
return
}
id, err := cid.NewCIDFromBytes(marshalled)
if err != nil {
return
}
spaceId := NewSpaceId(id, payload.ReplicationKey)
// encrypting read key
hasher := fnv.New64()
_, err = hasher.Write(payload.ReadKey)
if err != nil {
return
}
readKeyHash := hasher.Sum64()
encReadKey, err := payload.EncryptionKey.GetPublic().Encrypt(payload.ReadKey)
if err != nil {
return
}
// preparing acl
aclRoot := &aclrecordproto.ACLRoot{
Identity: identity,
EncryptionKey: encPubKey,
SpaceId: spaceId,
EncryptedReadKey: encReadKey,
DerivationScheme: "",
CurrentReadKeyHash: readKeyHash,
Timestamp: time.Now().UnixNano(),
}
rawWithId, err := marshalACLRoot(aclRoot, payload.SigningKey)
if err != nil {
return
}
// creating storage
storagePayload = storage.SpaceStorageCreatePayload{
RecWithId: rawWithId,
SpaceHeader: header,
Id: id,
}
return
}
func storagePayloadForSpaceDerive(payload SpaceDerivePayload) (storagePayload storage.SpaceStorageCreatePayload, err error) {
// unmarshalling signing and encryption keys
identity, err := payload.SigningKey.GetPublic().Raw()
if err != nil {
return
}
signPrivKey, err := payload.SigningKey.Raw()
if err != nil {
return
}
encPubKey, err := payload.EncryptionKey.GetPublic().Raw()
if err != nil {
return
}
encPrivKey, err := payload.EncryptionKey.Raw()
if err != nil {
return
}
// preparing replication key
hasher := fnv.New64()
_, err = hasher.Write(identity)
if err != nil {
return
}
repKey := hasher.Sum64()
// preparing header and space id
header := &spacesyncproto.SpaceHeader{
Identity: identity,
SpaceType: SpaceTypeDerived,
ReplicationKey: repKey,
}
marshalled, err := header.Marshal()
if err != nil {
return
}
id, err := cid.NewCIDFromBytes(marshalled)
if err != nil {
return
}
spaceId := NewSpaceId(id, repKey)
// deriving and encrypting read key
readKey, err := aclrecordproto.ACLReadKeyDerive(signPrivKey, encPrivKey)
if err != nil {
return
}
hasher = fnv.New64()
_, err = hasher.Write(readKey.Bytes())
if err != nil {
return
}
readKeyHash := hasher.Sum64()
encReadKey, err := payload.EncryptionKey.GetPublic().Encrypt(readKey.Bytes())
if err != nil {
return
}
// preparing acl
aclRoot := &aclrecordproto.ACLRoot{
Identity: identity,
EncryptionKey: encPubKey,
SpaceId: spaceId,
EncryptedReadKey: encReadKey,
DerivationScheme: "",
CurrentReadKeyHash: readKeyHash,
Timestamp: time.Now().UnixNano(),
}
rawWithId, err := marshalACLRoot(aclRoot, payload.SigningKey)
if err != nil {
return
}
// creating storage
storagePayload = storage.SpaceStorageCreatePayload{
RecWithId: rawWithId,
SpaceHeader: header,
Id: id,
}
return
}
func marshalACLRoot(aclRoot *aclrecordproto.ACLRoot, key signingkey.PrivKey) (rawWithId *aclrecordproto.RawACLRecordWithId, err error) {
marshalledRoot, err := aclRoot.Marshal()
if err != nil {
return
}
signature, err := key.Sign(marshalledRoot)
if err != nil {
return
}
raw := &aclrecordproto.RawACLRecord{
Payload: marshalledRoot,
Signature: signature,
}
marshalledRaw, err := raw.Marshal()
if err != nil {
return
}
aclHeadId, err := cid.NewCIDFromBytes(marshalledRaw)
if err != nil {
return
}
rawWithId = &aclrecordproto.RawACLRecordWithId{
Payload: marshalledRaw,
Id: aclHeadId,
}
return
}

View File

@ -19,5 +19,5 @@ func (r *rpcHandler) HeadSync(ctx context.Context, req *spacesyncproto.HeadSyncR
} }
func (r *rpcHandler) Stream(stream spacesyncproto.DRPCSpace_StreamStream) (err error) { func (r *rpcHandler) Stream(stream spacesyncproto.DRPCSpace_StreamStream) (err error) {
return r.s.SyncService().StreamPool().AddAndReadStreamSync(stream) return r.s.SyncService().SyncClient().AddAndReadStreamSync(stream)
} }

View File

@ -6,17 +6,11 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger" "github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
"github.com/anytypeio/go-anytype-infrastructure-experiments/config" "github.com/anytypeio/go-anytype-infrastructure-experiments/config"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclrecordproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/cid"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey"
"hash/fnv"
"math/rand"
"time"
) )
const CName = "common.commonspace" const CName = "common.commonspace"
@ -39,6 +33,7 @@ type service struct {
configurationService nodeconf.Service configurationService nodeconf.Service
storageProvider storage.SpaceStorageProvider storageProvider storage.SpaceStorageProvider
cache cache.TreeCache cache cache.TreeCache
pool pool.Pool
} }
func (s *service) Init(a *app.App) (err error) { func (s *service) Init(a *app.App) (err error) {
@ -46,6 +41,7 @@ func (s *service) Init(a *app.App) (err error) {
s.storageProvider = a.MustComponent(storage.CName).(storage.SpaceStorageProvider) s.storageProvider = a.MustComponent(storage.CName).(storage.SpaceStorageProvider)
s.configurationService = a.MustComponent(nodeconf.CName).(nodeconf.Service) s.configurationService = a.MustComponent(nodeconf.CName).(nodeconf.Service)
s.cache = a.MustComponent(cache.CName).(cache.TreeCache) s.cache = a.MustComponent(cache.CName).(cache.TreeCache)
s.pool = a.MustComponent(pool.CName).(pool.Pool)
return nil return nil
} }
@ -57,171 +53,32 @@ func (s *service) CreateSpace(
ctx context.Context, ctx context.Context,
cache cache.TreeCache, cache cache.TreeCache,
payload SpaceCreatePayload) (sp Space, err error) { payload SpaceCreatePayload) (sp Space, err error) {
storageCreate, err := storagePayloadForSpaceCreate(payload)
// unmarshalling signing and encryption keys
identity, err := payload.SigningKey.GetPublic().Raw()
if err != nil { if err != nil {
return return
} }
encPubKey, err := payload.EncryptionKey.GetPublic().Raw()
if err != nil {
return
}
// preparing header and space id
bytes := make([]byte, 32)
_, err = rand.Read(bytes)
if err != nil {
return
}
header := &spacesyncproto.SpaceHeader{
Identity: identity,
Timestamp: time.Now().UnixNano(),
SpaceType: payload.SpaceType,
ReplicationKey: payload.ReplicationKey,
Seed: bytes,
}
marshalled, err := header.Marshal()
if err != nil {
return
}
id, err := cid.NewCIDFromBytes(marshalled)
if err != nil {
return
}
spaceId := NewSpaceId(id, payload.ReplicationKey)
// encrypting read key
hasher := fnv.New64()
_, err = hasher.Write(payload.ReadKey)
if err != nil {
return
}
readKeyHash := hasher.Sum64()
encReadKey, err := payload.EncryptionKey.GetPublic().Encrypt(payload.ReadKey)
if err != nil {
return
}
// preparing acl
aclRoot := &aclrecordproto.ACLRoot{
Identity: identity,
EncryptionKey: encPubKey,
SpaceId: spaceId,
EncryptedReadKey: encReadKey,
DerivationScheme: "",
CurrentReadKeyHash: readKeyHash,
Timestamp: time.Now().UnixNano(),
}
rawWithId, err := marshalACLRoot(aclRoot, payload.SigningKey)
if err != nil {
return
}
// creating storage
storageCreate := storage.SpaceStorageCreatePayload{
RecWithId: rawWithId,
SpaceHeader: header,
Id: id,
}
_, err = s.storageProvider.CreateSpaceStorage(storageCreate) _, err = s.storageProvider.CreateSpaceStorage(storageCreate)
if err != nil { if err != nil {
return return
} }
return s.GetSpace(ctx, spaceId) return s.GetSpace(ctx, storageCreate.Id)
} }
func (s *service) DeriveSpace( func (s *service) DeriveSpace(
ctx context.Context, ctx context.Context,
cache cache.TreeCache, cache cache.TreeCache,
payload SpaceDerivePayload) (sp Space, err error) { payload SpaceDerivePayload) (sp Space, err error) {
storageCreate, err := storagePayloadForSpaceDerive(payload)
// unmarshalling signing and encryption keys
identity, err := payload.SigningKey.GetPublic().Raw()
if err != nil { if err != nil {
return return
} }
signPrivKey, err := payload.SigningKey.Raw()
if err != nil {
return
}
encPubKey, err := payload.EncryptionKey.GetPublic().Raw()
if err != nil {
return
}
encPrivKey, err := payload.EncryptionKey.Raw()
if err != nil {
return
}
// preparing replication key
hasher := fnv.New64()
_, err = hasher.Write(identity)
if err != nil {
return
}
repKey := hasher.Sum64()
// preparing header and space id
header := &spacesyncproto.SpaceHeader{
Identity: identity,
SpaceType: SpaceTypeDerived,
ReplicationKey: repKey,
}
marshalled, err := header.Marshal()
if err != nil {
return
}
id, err := cid.NewCIDFromBytes(marshalled)
if err != nil {
return
}
spaceId := NewSpaceId(id, repKey)
// deriving and encrypting read key
readKey, err := aclrecordproto.ACLReadKeyDerive(signPrivKey, encPrivKey)
if err != nil {
return
}
hasher = fnv.New64()
_, err = hasher.Write(readKey.Bytes())
if err != nil {
return
}
readKeyHash := hasher.Sum64()
encReadKey, err := payload.EncryptionKey.GetPublic().Encrypt(readKey.Bytes())
if err != nil {
return
}
// preparing acl
aclRoot := &aclrecordproto.ACLRoot{
Identity: identity,
EncryptionKey: encPubKey,
SpaceId: spaceId,
EncryptedReadKey: encReadKey,
DerivationScheme: "",
CurrentReadKeyHash: readKeyHash,
Timestamp: time.Now().UnixNano(),
}
rawWithId, err := marshalACLRoot(aclRoot, payload.SigningKey)
if err != nil {
return
}
// creating storage
storageCreate := storage.SpaceStorageCreatePayload{
RecWithId: rawWithId,
SpaceHeader: header,
Id: id,
}
_, err = s.storageProvider.CreateSpaceStorage(storageCreate) _, err = s.storageProvider.CreateSpaceStorage(storageCreate)
if err != nil { if err != nil {
return return
} }
return s.GetSpace(ctx, spaceId) return s.GetSpace(ctx, storageCreate.Id)
} }
func (s *service) GetSpace(ctx context.Context, id string) (Space, error) { func (s *service) GetSpace(ctx context.Context, id string) (Space, error) {
@ -230,8 +87,9 @@ func (s *service) GetSpace(ctx context.Context, id string) (Space, error) {
return nil, err return nil, err
} }
lastConfiguration := s.configurationService.GetLast() lastConfiguration := s.configurationService.GetLast()
diffService := diffservice.NewDiffService(id, s.config.SyncPeriod, st, lastConfiguration, s.cache, log) confConnector := nodeconf.NewConfConnector(lastConfiguration, s.pool)
syncService := syncservice.NewSyncService(id, diffService, s.cache, lastConfiguration) diffService := diffservice.NewDiffService(id, s.config.SyncPeriod, st, confConnector, s.cache, log)
syncService := syncservice.NewSyncService(id, diffService, s.cache, lastConfiguration, confConnector)
sp := &space{ sp := &space{
id: id, id: id,
syncService: syncService, syncService: syncService,
@ -244,31 +102,3 @@ func (s *service) GetSpace(ctx context.Context, id string) (Space, error) {
} }
return sp, nil return sp, nil
} }
func marshalACLRoot(aclRoot *aclrecordproto.ACLRoot, key signingkey.PrivKey) (rawWithId *aclrecordproto.RawACLRecordWithId, err error) {
marshalledRoot, err := aclRoot.Marshal()
if err != nil {
return
}
signature, err := key.Sign(marshalledRoot)
if err != nil {
return
}
raw := &aclrecordproto.RawACLRecord{
Payload: marshalledRoot,
Signature: signature,
}
marshalledRaw, err := raw.Marshal()
if err != nil {
return
}
aclHeadId, err := cid.NewCIDFromBytes(marshalledRaw)
if err != nil {
return
}
rawWithId = &aclrecordproto.RawACLRecordWithId{
Payload: marshalledRaw,
Id: aclHeadId,
}
return
}

View File

@ -90,11 +90,11 @@ func (s *space) DiffService() diffservice.DiffService {
} }
func (s *space) DeriveTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree.ObjectTree, error) { func (s *space) DeriveTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree.ObjectTree, error) {
return synctree.DeriveSyncTree(ctx, payload, s.syncService, listener, s.aclList, s.storage.CreateTreeStorage) return synctree.DeriveSyncTree(ctx, payload, s.syncService.SyncClient(), listener, s.aclList, s.storage.CreateTreeStorage)
} }
func (s *space) CreateTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree.ObjectTree, error) { func (s *space) CreateTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree.ObjectTree, error) {
return synctree.CreateSyncTree(ctx, payload, s.syncService, listener, s.aclList, s.storage.CreateTreeStorage) return synctree.CreateSyncTree(ctx, payload, s.syncService.SyncClient(), listener, s.aclList, s.storage.CreateTreeStorage)
} }
func (s *space) BuildTree(ctx context.Context, id string, listener updatelistener.UpdateListener) (t tree.ObjectTree, err error) { func (s *space) BuildTree(ctx context.Context, id string, listener updatelistener.UpdateListener) (t tree.ObjectTree, err error) {
@ -104,10 +104,9 @@ func (s *space) BuildTree(ctx context.Context, id string, listener updatelistene
if err != nil { if err != nil {
return nil, err return nil, err
} }
return s.syncService.SyncClient().SendSync(
return s.syncService.StreamPool().SendSync(
peerId, peerId,
spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{}, nil, id, ""), s.syncService.SyncClient().CreateNewTreeRequest(id),
) )
} }
@ -142,7 +141,7 @@ func (s *space) BuildTree(ctx context.Context, id string, listener updatelistene
return return
} }
} }
return synctree.BuildSyncTree(ctx, s.syncService, store.(treestorage.TreeStorage), listener, s.aclList) return synctree.BuildSyncTree(ctx, s.syncService.SyncClient(), store.(treestorage.TreeStorage), listener, s.aclList)
} }
func (s *space) Close() error { func (s *space) Close() error {

View File

@ -0,0 +1,96 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto (interfaces: DRPCSpaceClient)
// Package mock_spacesyncproto is a generated GoMock package.
package mock_spacesyncproto
import (
context "context"
reflect "reflect"
spacesyncproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
gomock "github.com/golang/mock/gomock"
drpc "storj.io/drpc"
)
// MockDRPCSpaceClient is a mock of DRPCSpaceClient interface.
type MockDRPCSpaceClient struct {
ctrl *gomock.Controller
recorder *MockDRPCSpaceClientMockRecorder
}
// MockDRPCSpaceClientMockRecorder is the mock recorder for MockDRPCSpaceClient.
type MockDRPCSpaceClientMockRecorder struct {
mock *MockDRPCSpaceClient
}
// NewMockDRPCSpaceClient creates a new mock instance.
func NewMockDRPCSpaceClient(ctrl *gomock.Controller) *MockDRPCSpaceClient {
mock := &MockDRPCSpaceClient{ctrl: ctrl}
mock.recorder = &MockDRPCSpaceClientMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockDRPCSpaceClient) EXPECT() *MockDRPCSpaceClientMockRecorder {
return m.recorder
}
// DRPCConn mocks base method.
func (m *MockDRPCSpaceClient) DRPCConn() drpc.Conn {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DRPCConn")
ret0, _ := ret[0].(drpc.Conn)
return ret0
}
// DRPCConn indicates an expected call of DRPCConn.
func (mr *MockDRPCSpaceClientMockRecorder) DRPCConn() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DRPCConn", reflect.TypeOf((*MockDRPCSpaceClient)(nil).DRPCConn))
}
// HeadSync mocks base method.
func (m *MockDRPCSpaceClient) HeadSync(arg0 context.Context, arg1 *spacesyncproto.HeadSyncRequest) (*spacesyncproto.HeadSyncResponse, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "HeadSync", arg0, arg1)
ret0, _ := ret[0].(*spacesyncproto.HeadSyncResponse)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// HeadSync indicates an expected call of HeadSync.
func (mr *MockDRPCSpaceClientMockRecorder) HeadSync(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeadSync", reflect.TypeOf((*MockDRPCSpaceClient)(nil).HeadSync), arg0, arg1)
}
// PushSpace mocks base method.
func (m *MockDRPCSpaceClient) PushSpace(arg0 context.Context, arg1 *spacesyncproto.PushSpaceRequest) (*spacesyncproto.PushSpaceResponse, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PushSpace", arg0, arg1)
ret0, _ := ret[0].(*spacesyncproto.PushSpaceResponse)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// PushSpace indicates an expected call of PushSpace.
func (mr *MockDRPCSpaceClientMockRecorder) PushSpace(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PushSpace", reflect.TypeOf((*MockDRPCSpaceClient)(nil).PushSpace), arg0, arg1)
}
// Stream mocks base method.
func (m *MockDRPCSpaceClient) Stream(arg0 context.Context) (spacesyncproto.DRPCSpace_StreamClient, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Stream", arg0)
ret0, _ := ret[0].(spacesyncproto.DRPCSpace_StreamClient)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Stream indicates an expected call of Stream.
func (mr *MockDRPCSpaceClientMockRecorder) Stream(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stream", reflect.TypeOf((*MockDRPCSpaceClient)(nil).Stream), arg0)
}

View File

@ -1,9 +1,23 @@
//go:generate mockgen -destination mock_spacesyncproto/mock_spacesyncproto.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto DRPCSpaceClient
package spacesyncproto package spacesyncproto
import "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto" import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto"
"storj.io/drpc"
)
type SpaceStream = DRPCSpace_StreamStream type SpaceStream = DRPCSpace_StreamStream
type ClientFactoryFunc func(cc drpc.Conn) DRPCSpaceClient
func (c ClientFactoryFunc) Client(cc drpc.Conn) DRPCSpaceClient {
return c(cc)
}
type ClientFactory interface {
Client(cc drpc.Conn) DRPCSpaceClient
}
func WrapHeadUpdate(update *ObjectHeadUpdate, rootChange *treechangeproto.RawTreeChangeWithId, treeId, trackingId string) *ObjectSyncMessage { func WrapHeadUpdate(update *ObjectHeadUpdate, rootChange *treechangeproto.RawTreeChangeWithId, treeId, trackingId string) *ObjectSyncMessage {
return &ObjectSyncMessage{ return &ObjectSyncMessage{
Content: &ObjectSyncContentValue{ Content: &ObjectSyncContentValue{

View File

@ -0,0 +1,194 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage (interfaces: SpaceStorageProvider,SpaceStorage)
// Package mock_storage is a generated GoMock package.
package mock_storage
import (
reflect "reflect"
app "github.com/anytypeio/go-anytype-infrastructure-experiments/app"
spacesyncproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
storage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
storage0 "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage"
gomock "github.com/golang/mock/gomock"
)
// MockSpaceStorageProvider is a mock of SpaceStorageProvider interface.
type MockSpaceStorageProvider struct {
ctrl *gomock.Controller
recorder *MockSpaceStorageProviderMockRecorder
}
// MockSpaceStorageProviderMockRecorder is the mock recorder for MockSpaceStorageProvider.
type MockSpaceStorageProviderMockRecorder struct {
mock *MockSpaceStorageProvider
}
// NewMockSpaceStorageProvider creates a new mock instance.
func NewMockSpaceStorageProvider(ctrl *gomock.Controller) *MockSpaceStorageProvider {
mock := &MockSpaceStorageProvider{ctrl: ctrl}
mock.recorder = &MockSpaceStorageProviderMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockSpaceStorageProvider) EXPECT() *MockSpaceStorageProviderMockRecorder {
return m.recorder
}
// CreateSpaceStorage mocks base method.
func (m *MockSpaceStorageProvider) CreateSpaceStorage(arg0 storage.SpaceStorageCreatePayload) (storage.SpaceStorage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CreateSpaceStorage", arg0)
ret0, _ := ret[0].(storage.SpaceStorage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// CreateSpaceStorage indicates an expected call of CreateSpaceStorage.
func (mr *MockSpaceStorageProviderMockRecorder) CreateSpaceStorage(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSpaceStorage", reflect.TypeOf((*MockSpaceStorageProvider)(nil).CreateSpaceStorage), arg0)
}
// Init mocks base method.
func (m *MockSpaceStorageProvider) Init(arg0 *app.App) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Init", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// Init indicates an expected call of Init.
func (mr *MockSpaceStorageProviderMockRecorder) Init(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockSpaceStorageProvider)(nil).Init), arg0)
}
// Name mocks base method.
func (m *MockSpaceStorageProvider) Name() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Name")
ret0, _ := ret[0].(string)
return ret0
}
// Name indicates an expected call of Name.
func (mr *MockSpaceStorageProviderMockRecorder) Name() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockSpaceStorageProvider)(nil).Name))
}
// SpaceStorage mocks base method.
func (m *MockSpaceStorageProvider) SpaceStorage(arg0 string) (storage.SpaceStorage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SpaceStorage", arg0)
ret0, _ := ret[0].(storage.SpaceStorage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// SpaceStorage indicates an expected call of SpaceStorage.
func (mr *MockSpaceStorageProviderMockRecorder) SpaceStorage(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpaceStorage", reflect.TypeOf((*MockSpaceStorageProvider)(nil).SpaceStorage), arg0)
}
// MockSpaceStorage is a mock of SpaceStorage interface.
type MockSpaceStorage struct {
ctrl *gomock.Controller
recorder *MockSpaceStorageMockRecorder
}
// MockSpaceStorageMockRecorder is the mock recorder for MockSpaceStorage.
type MockSpaceStorageMockRecorder struct {
mock *MockSpaceStorage
}
// NewMockSpaceStorage creates a new mock instance.
func NewMockSpaceStorage(ctrl *gomock.Controller) *MockSpaceStorage {
mock := &MockSpaceStorage{ctrl: ctrl}
mock.recorder = &MockSpaceStorageMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockSpaceStorage) EXPECT() *MockSpaceStorageMockRecorder {
return m.recorder
}
// ACLStorage mocks base method.
func (m *MockSpaceStorage) ACLStorage() (storage0.ListStorage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ACLStorage")
ret0, _ := ret[0].(storage0.ListStorage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ACLStorage indicates an expected call of ACLStorage.
func (mr *MockSpaceStorageMockRecorder) ACLStorage() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ACLStorage", reflect.TypeOf((*MockSpaceStorage)(nil).ACLStorage))
}
// CreateTreeStorage mocks base method.
func (m *MockSpaceStorage) CreateTreeStorage(arg0 storage0.TreeStorageCreatePayload) (storage0.TreeStorage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CreateTreeStorage", arg0)
ret0, _ := ret[0].(storage0.TreeStorage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// CreateTreeStorage indicates an expected call of CreateTreeStorage.
func (mr *MockSpaceStorageMockRecorder) CreateTreeStorage(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateTreeStorage", reflect.TypeOf((*MockSpaceStorage)(nil).CreateTreeStorage), arg0)
}
// SpaceHeader mocks base method.
func (m *MockSpaceStorage) SpaceHeader() (*spacesyncproto.SpaceHeader, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SpaceHeader")
ret0, _ := ret[0].(*spacesyncproto.SpaceHeader)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// SpaceHeader indicates an expected call of SpaceHeader.
func (mr *MockSpaceStorageMockRecorder) SpaceHeader() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpaceHeader", reflect.TypeOf((*MockSpaceStorage)(nil).SpaceHeader))
}
// StoredIds mocks base method.
func (m *MockSpaceStorage) StoredIds() ([]string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "StoredIds")
ret0, _ := ret[0].([]string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// StoredIds indicates an expected call of StoredIds.
func (mr *MockSpaceStorageMockRecorder) StoredIds() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoredIds", reflect.TypeOf((*MockSpaceStorage)(nil).StoredIds))
}
// TreeStorage mocks base method.
func (m *MockSpaceStorage) TreeStorage(arg0 string) (storage0.TreeStorage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "TreeStorage", arg0)
ret0, _ := ret[0].(storage0.TreeStorage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// TreeStorage indicates an expected call of TreeStorage.
func (mr *MockSpaceStorageMockRecorder) TreeStorage(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TreeStorage", reflect.TypeOf((*MockSpaceStorage)(nil).TreeStorage), arg0)
}

View File

@ -1,3 +1,4 @@
//go:generate mockgen -destination mock_storage/mock_storage.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage SpaceStorageProvider,SpaceStorage
package storage package storage
import ( import (

View File

@ -0,0 +1,206 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice (interfaces: SyncClient)
// Package mock_syncservice is a generated GoMock package.
package mock_syncservice
import (
reflect "reflect"
spacesyncproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
tree "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"
treechangeproto "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto"
gomock "github.com/golang/mock/gomock"
)
// MockSyncClient is a mock of SyncClient interface.
type MockSyncClient struct {
ctrl *gomock.Controller
recorder *MockSyncClientMockRecorder
}
// MockSyncClientMockRecorder is the mock recorder for MockSyncClient.
type MockSyncClientMockRecorder struct {
mock *MockSyncClient
}
// NewMockSyncClient creates a new mock instance.
func NewMockSyncClient(ctrl *gomock.Controller) *MockSyncClient {
mock := &MockSyncClient{ctrl: ctrl}
mock.recorder = &MockSyncClientMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockSyncClient) EXPECT() *MockSyncClientMockRecorder {
return m.recorder
}
// AddAndReadStreamAsync mocks base method.
func (m *MockSyncClient) AddAndReadStreamAsync(arg0 spacesyncproto.DRPCSpace_StreamStream) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "AddAndReadStreamAsync", arg0)
}
// AddAndReadStreamAsync indicates an expected call of AddAndReadStreamAsync.
func (mr *MockSyncClientMockRecorder) AddAndReadStreamAsync(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddAndReadStreamAsync", reflect.TypeOf((*MockSyncClient)(nil).AddAndReadStreamAsync), arg0)
}
// AddAndReadStreamSync mocks base method.
func (m *MockSyncClient) AddAndReadStreamSync(arg0 spacesyncproto.DRPCSpace_StreamStream) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddAndReadStreamSync", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// AddAndReadStreamSync indicates an expected call of AddAndReadStreamSync.
func (mr *MockSyncClientMockRecorder) AddAndReadStreamSync(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddAndReadStreamSync", reflect.TypeOf((*MockSyncClient)(nil).AddAndReadStreamSync), arg0)
}
// BroadcastAsync mocks base method.
func (m *MockSyncClient) BroadcastAsync(arg0 *spacesyncproto.ObjectSyncMessage) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BroadcastAsync", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// BroadcastAsync indicates an expected call of BroadcastAsync.
func (mr *MockSyncClientMockRecorder) BroadcastAsync(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BroadcastAsync", reflect.TypeOf((*MockSyncClient)(nil).BroadcastAsync), arg0)
}
// BroadcastAsyncOrSendResponsible mocks base method.
func (m *MockSyncClient) BroadcastAsyncOrSendResponsible(arg0 *spacesyncproto.ObjectSyncMessage) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BroadcastAsyncOrSendResponsible", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// BroadcastAsyncOrSendResponsible indicates an expected call of BroadcastAsyncOrSendResponsible.
func (mr *MockSyncClientMockRecorder) BroadcastAsyncOrSendResponsible(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BroadcastAsyncOrSendResponsible", reflect.TypeOf((*MockSyncClient)(nil).BroadcastAsyncOrSendResponsible), arg0)
}
// Close mocks base method.
func (m *MockSyncClient) Close() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Close")
ret0, _ := ret[0].(error)
return ret0
}
// Close indicates an expected call of Close.
func (mr *MockSyncClientMockRecorder) Close() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockSyncClient)(nil).Close))
}
// CreateFullSyncRequest mocks base method.
func (m *MockSyncClient) CreateFullSyncRequest(arg0 tree.ObjectTree, arg1, arg2 []string, arg3 string) (*spacesyncproto.ObjectSyncMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CreateFullSyncRequest", arg0, arg1, arg2, arg3)
ret0, _ := ret[0].(*spacesyncproto.ObjectSyncMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// CreateFullSyncRequest indicates an expected call of CreateFullSyncRequest.
func (mr *MockSyncClientMockRecorder) CreateFullSyncRequest(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateFullSyncRequest", reflect.TypeOf((*MockSyncClient)(nil).CreateFullSyncRequest), arg0, arg1, arg2, arg3)
}
// CreateFullSyncResponse mocks base method.
func (m *MockSyncClient) CreateFullSyncResponse(arg0 tree.ObjectTree, arg1, arg2 []string, arg3 string) (*spacesyncproto.ObjectSyncMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CreateFullSyncResponse", arg0, arg1, arg2, arg3)
ret0, _ := ret[0].(*spacesyncproto.ObjectSyncMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// CreateFullSyncResponse indicates an expected call of CreateFullSyncResponse.
func (mr *MockSyncClientMockRecorder) CreateFullSyncResponse(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateFullSyncResponse", reflect.TypeOf((*MockSyncClient)(nil).CreateFullSyncResponse), arg0, arg1, arg2, arg3)
}
// CreateHeadUpdate mocks base method.
func (m *MockSyncClient) CreateHeadUpdate(arg0 tree.ObjectTree, arg1 []*treechangeproto.RawTreeChangeWithId) *spacesyncproto.ObjectSyncMessage {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CreateHeadUpdate", arg0, arg1)
ret0, _ := ret[0].(*spacesyncproto.ObjectSyncMessage)
return ret0
}
// CreateHeadUpdate indicates an expected call of CreateHeadUpdate.
func (mr *MockSyncClientMockRecorder) CreateHeadUpdate(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateHeadUpdate", reflect.TypeOf((*MockSyncClient)(nil).CreateHeadUpdate), arg0, arg1)
}
// CreateNewTreeRequest mocks base method.
func (m *MockSyncClient) CreateNewTreeRequest(arg0 string) *spacesyncproto.ObjectSyncMessage {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CreateNewTreeRequest", arg0)
ret0, _ := ret[0].(*spacesyncproto.ObjectSyncMessage)
return ret0
}
// CreateNewTreeRequest indicates an expected call of CreateNewTreeRequest.
func (mr *MockSyncClientMockRecorder) CreateNewTreeRequest(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateNewTreeRequest", reflect.TypeOf((*MockSyncClient)(nil).CreateNewTreeRequest), arg0)
}
// HasActiveStream mocks base method.
func (m *MockSyncClient) HasActiveStream(arg0 string) bool {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "HasActiveStream", arg0)
ret0, _ := ret[0].(bool)
return ret0
}
// HasActiveStream indicates an expected call of HasActiveStream.
func (mr *MockSyncClientMockRecorder) HasActiveStream(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasActiveStream", reflect.TypeOf((*MockSyncClient)(nil).HasActiveStream), arg0)
}
// SendAsync mocks base method.
func (m *MockSyncClient) SendAsync(arg0 []string, arg1 *spacesyncproto.ObjectSyncMessage) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SendAsync", arg0, arg1)
ret0, _ := ret[0].(error)
return ret0
}
// SendAsync indicates an expected call of SendAsync.
func (mr *MockSyncClientMockRecorder) SendAsync(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendAsync", reflect.TypeOf((*MockSyncClient)(nil).SendAsync), arg0, arg1)
}
// SendSync mocks base method.
func (m *MockSyncClient) SendSync(arg0 string, arg1 *spacesyncproto.ObjectSyncMessage) (*spacesyncproto.ObjectSyncMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SendSync", arg0, arg1)
ret0, _ := ret[0].(*spacesyncproto.ObjectSyncMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// SendSync indicates an expected call of SendSync.
func (mr *MockSyncClientMockRecorder) SendSync(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendSync", reflect.TypeOf((*MockSyncClient)(nil).SendSync), arg0, arg1)
}

View File

@ -0,0 +1,73 @@
package syncservice
import (
"fmt"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice"
)
type RequestFactory interface {
CreateHeadUpdate(t tree.ObjectTree, added []*treechangeproto.RawTreeChangeWithId) (msg *spacesyncproto.ObjectSyncMessage)
CreateNewTreeRequest(id string) (msg *spacesyncproto.ObjectSyncMessage)
CreateFullSyncRequest(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (req *spacesyncproto.ObjectSyncMessage, err error)
CreateFullSyncResponse(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (*spacesyncproto.ObjectSyncMessage, error)
}
func newRequestFactory() RequestFactory {
return &requestFactory{}
}
type requestFactory struct{}
func (r *requestFactory) CreateHeadUpdate(t tree.ObjectTree, added []*treechangeproto.RawTreeChangeWithId) (msg *spacesyncproto.ObjectSyncMessage) {
return spacesyncproto.WrapHeadUpdate(&spacesyncproto.ObjectHeadUpdate{
Heads: t.Heads(),
Changes: added,
SnapshotPath: t.SnapshotPath(),
}, t.Header(), t.ID(), "")
}
func (r *requestFactory) CreateNewTreeRequest(id string) (msg *spacesyncproto.ObjectSyncMessage) {
return spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{}, nil, id, "")
}
func (r *requestFactory) CreateFullSyncRequest(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (msg *spacesyncproto.ObjectSyncMessage, err error) {
req := &spacesyncproto.ObjectFullSyncRequest{}
if t == nil {
return nil, fmt.Errorf("tree should not be empty")
}
req.Heads = t.Heads()
req.SnapshotPath = t.SnapshotPath()
var changesAfterSnapshot []*treechangeproto.RawTreeChangeWithId
changesAfterSnapshot, err = t.ChangesAfterCommonSnapshot(theirSnapshotPath, theirHeads)
if err != nil {
return
}
req.Changes = changesAfterSnapshot
msg = spacesyncproto.WrapFullRequest(req, t.Header(), t.ID(), trackingId)
return
}
func (r *requestFactory) CreateFullSyncResponse(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (msg *spacesyncproto.ObjectSyncMessage, err error) {
resp := &spacesyncproto.ObjectFullSyncResponse{
Heads: t.Heads(),
SnapshotPath: t.SnapshotPath(),
}
if slice.UnsortedEquals(theirHeads, t.Heads()) {
msg = spacesyncproto.WrapFullResponse(resp, t.Header(), t.ID(), trackingId)
return
}
ourChanges, err := t.ChangesAfterCommonSnapshot(theirSnapshotPath, theirHeads)
if err != nil {
return
}
resp.Changes = ourChanges
msg = spacesyncproto.WrapFullResponse(resp, t.Header(), t.ID(), trackingId)
return
}

View File

@ -18,16 +18,16 @@ const maxSimultaneousOperationsPerStream = 10
// StreamPool can be made generic to work with different streams // StreamPool can be made generic to work with different streams
type StreamPool interface { type StreamPool interface {
SyncClient Sender
AddAndReadStreamSync(stream spacesyncproto.SpaceStream) (err error) AddAndReadStreamSync(stream spacesyncproto.SpaceStream) (err error)
AddAndReadStreamAsync(stream spacesyncproto.SpaceStream) AddAndReadStreamAsync(stream spacesyncproto.SpaceStream)
HasActiveStream(peerId string) bool HasActiveStream(peerId string) bool
Close() (err error) Close() (err error)
} }
type SyncClient interface { type Sender interface {
SendSync(peerId string, message *spacesyncproto.ObjectSyncMessage) (reply *spacesyncproto.ObjectSyncMessage, err error) SendSync(peerId string, message *spacesyncproto.ObjectSyncMessage) (reply *spacesyncproto.ObjectSyncMessage, err error)
SendAsync(peerId string, message *spacesyncproto.ObjectSyncMessage) (err error) SendAsync(peers []string, message *spacesyncproto.ObjectSyncMessage) (err error)
BroadcastAsync(message *spacesyncproto.ObjectSyncMessage) (err error) BroadcastAsync(message *spacesyncproto.ObjectSyncMessage) (err error)
} }
@ -56,6 +56,8 @@ func newStreamPool(messageHandler MessageHandler) StreamPool {
} }
func (s *streamPool) HasActiveStream(peerId string) (res bool) { func (s *streamPool) HasActiveStream(peerId string) (res bool) {
s.Lock()
defer s.Unlock()
_, err := s.getOrDeleteStream(peerId) _, err := s.getOrDeleteStream(peerId)
return err == nil return err == nil
} }
@ -73,7 +75,7 @@ func (s *streamPool) SendSync(
s.waiters[msg.TrackingId] = waiter s.waiters[msg.TrackingId] = waiter
s.waitersMx.Unlock() s.waitersMx.Unlock()
err = s.SendAsync(peerId, msg) err = s.SendAsync([]string{peerId}, msg)
if err != nil { if err != nil {
return return
} }
@ -82,18 +84,31 @@ func (s *streamPool) SendSync(
return return
} }
func (s *streamPool) SendAsync(peerId string, message *spacesyncproto.ObjectSyncMessage) (err error) { func (s *streamPool) SendAsync(peers []string, message *spacesyncproto.ObjectSyncMessage) (err error) {
stream, err := s.getOrDeleteStream(peerId) getStreams := func() (streams []spacesyncproto.SpaceStream) {
if err != nil { for _, pId := range peers {
return stream, err := s.getOrDeleteStream(pId)
if err != nil {
continue
}
streams = append(streams, stream)
}
return streams
} }
return stream.Send(message) s.Lock()
streams := getStreams()
s.Unlock()
for _, s := range streams {
if len(peers) == 1 {
err = s.Send(message)
}
}
return err
} }
func (s *streamPool) getOrDeleteStream(id string) (stream spacesyncproto.SpaceStream, err error) { func (s *streamPool) getOrDeleteStream(id string) (stream spacesyncproto.SpaceStream, err error) {
s.Lock()
defer s.Unlock()
stream, exists := s.peerStreams[id] stream, exists := s.peerStreams[id]
if !exists { if !exists {
err = ErrEmptyPeer err = ErrEmptyPeer

View File

@ -0,0 +1,49 @@
package syncservice
import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
)
type SyncClient interface {
StreamPool
RequestFactory
BroadcastAsyncOrSendResponsible(message *spacesyncproto.ObjectSyncMessage) (err error)
}
type syncClient struct {
StreamPool
RequestFactory
spaceId string
notifiable HeadNotifiable
configuration nodeconf.Configuration
}
func newSyncClient(spaceId string, pool StreamPool, notifiable HeadNotifiable, factory RequestFactory, configuration nodeconf.Configuration) SyncClient {
return &syncClient{
StreamPool: pool,
RequestFactory: factory,
notifiable: notifiable,
configuration: configuration,
spaceId: spaceId,
}
}
func (s *syncClient) BroadcastAsync(message *spacesyncproto.ObjectSyncMessage) (err error) {
s.notifyIfNeeded(message)
return s.BroadcastAsync(message)
}
func (s *syncClient) BroadcastAsyncOrSendResponsible(message *spacesyncproto.ObjectSyncMessage) (err error) {
if s.configuration.IsResponsible(s.spaceId) {
return s.SendAsync(s.configuration.NodeIds(s.spaceId), message)
}
return s.BroadcastAsync(message)
}
func (s *syncClient) notifyIfNeeded(message *spacesyncproto.ObjectSyncMessage) {
if message.GetContent().GetHeadUpdate() != nil {
update := message.GetContent().GetHeadUpdate()
s.notifiable.UpdateHeads(message.TreeId, update.Heads)
}
}

View File

@ -5,7 +5,6 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice" "github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice"
) )
@ -31,24 +30,24 @@ func (s *syncHandler) HandleMessage(ctx context.Context, senderId string, msg *s
content := msg.GetContent() content := msg.GetContent()
switch { switch {
case content.GetFullSyncRequest() != nil: case content.GetFullSyncRequest() != nil:
return s.HandleFullSyncRequest(ctx, senderId, content.GetFullSyncRequest(), msg) return s.handleFullSyncRequest(ctx, senderId, content.GetFullSyncRequest(), msg)
case content.GetFullSyncResponse() != nil: case content.GetFullSyncResponse() != nil:
return s.HandleFullSyncResponse(ctx, senderId, content.GetFullSyncResponse(), msg) return s.handleFullSyncResponse(ctx, senderId, content.GetFullSyncResponse(), msg)
case content.GetHeadUpdate() != nil: case content.GetHeadUpdate() != nil:
return s.HandleHeadUpdate(ctx, senderId, content.GetHeadUpdate(), msg) return s.handleHeadUpdate(ctx, senderId, content.GetHeadUpdate(), msg)
} }
return nil return nil
} }
func (s *syncHandler) HandleHeadUpdate( func (s *syncHandler) handleHeadUpdate(
ctx context.Context, ctx context.Context,
senderId string, senderId string,
update *spacesyncproto.ObjectHeadUpdate, update *spacesyncproto.ObjectHeadUpdate,
msg *spacesyncproto.ObjectSyncMessage) (err error) { msg *spacesyncproto.ObjectSyncMessage) (err error) {
var ( var (
fullRequest *spacesyncproto.ObjectFullSyncRequest fullRequest *spacesyncproto.ObjectSyncMessage
result tree.AddResult isEmptyUpdate = len(update.Changes) == 0
) )
res, err := s.treeCache.GetTree(ctx, s.spaceId, msg.TreeId) res, err := s.treeCache.GetTree(ctx, s.spaceId, msg.TreeId)
if err != nil { if err != nil {
@ -61,44 +60,51 @@ func (s *syncHandler) HandleHeadUpdate(
defer res.Release() defer res.Release()
defer objTree.Unlock() defer objTree.Unlock()
if slice.UnsortedEquals(update.Heads, objTree.Heads()) { // isEmptyUpdate is sent when the tree is brought up from cache
if isEmptyUpdate {
if slice.UnsortedEquals(objTree.Heads(), update.Heads) {
return nil
}
// we need to sync in any case
fullRequest, err = s.syncClient.CreateFullSyncRequest(objTree, update.Heads, update.SnapshotPath, msg.TrackingId)
return err
}
if s.alreadyHasHeads(objTree, update.Heads) {
return nil return nil
} }
result, err = objTree.AddRawChanges(ctx, update.Changes...) _, err = objTree.AddRawChanges(ctx, update.Changes...)
if err != nil { if err != nil {
return err return err
} }
// if we couldn't add all the changes if s.alreadyHasHeads(objTree, update.Heads) {
if len(update.Changes) != len(result.Added) { return nil
fullRequest, err = s.prepareFullSyncRequest(objTree, update)
if err != nil {
return err
}
} }
return nil
fullRequest, err = s.syncClient.CreateFullSyncRequest(objTree, update.Heads, update.SnapshotPath, msg.TrackingId)
return err
}() }()
if fullRequest != nil { if fullRequest != nil {
return s.syncClient.SendAsync(senderId, return s.syncClient.SendAsync([]string{senderId}, fullRequest)
spacesyncproto.WrapFullRequest(fullRequest, msg.RootChange, msg.TreeId, msg.TrackingId))
} }
return return
} }
func (s *syncHandler) HandleFullSyncRequest( func (s *syncHandler) handleFullSyncRequest(
ctx context.Context, ctx context.Context,
senderId string, senderId string,
request *spacesyncproto.ObjectFullSyncRequest, request *spacesyncproto.ObjectFullSyncRequest,
msg *spacesyncproto.ObjectSyncMessage) (err error) { msg *spacesyncproto.ObjectSyncMessage) (err error) {
var ( var (
fullResponse *spacesyncproto.ObjectFullSyncResponse fullResponse *spacesyncproto.ObjectSyncMessage
header = msg.RootChange header = msg.RootChange
) )
defer func() { defer func() {
if err != nil { if err != nil {
s.syncClient.SendAsync(senderId, spacesyncproto.WrapError(err, header, msg.TreeId, msg.TrackingId)) s.syncClient.SendAsync([]string{senderId}, spacesyncproto.WrapError(err, header, msg.TreeId, msg.TrackingId))
} }
}() }()
@ -117,23 +123,24 @@ func (s *syncHandler) HandleFullSyncRequest(
header = objTree.Header() header = objTree.Header()
} }
_, err = objTree.AddRawChanges(ctx, request.Changes...) if len(request.Changes) != 0 && !s.alreadyHasHeads(objTree, request.Heads) {
if err != nil { _, err = objTree.AddRawChanges(ctx, request.Changes...)
return err if err != nil {
return err
}
} }
fullResponse, err = s.prepareFullSyncResponse(request.SnapshotPath, request.Heads, objTree) fullResponse, err = s.syncClient.CreateFullSyncResponse(objTree, request.Heads, request.SnapshotPath, msg.TrackingId)
return err return err
}() }()
if err != nil { if err != nil {
return return
} }
return s.syncClient.SendAsync(senderId, return s.syncClient.SendAsync([]string{senderId}, fullResponse)
spacesyncproto.WrapFullResponse(fullResponse, header, msg.TreeId, msg.TrackingId))
} }
func (s *syncHandler) HandleFullSyncResponse( func (s *syncHandler) handleFullSyncResponse(
ctx context.Context, ctx context.Context,
senderId string, senderId string,
response *spacesyncproto.ObjectFullSyncResponse, response *spacesyncproto.ObjectFullSyncResponse,
@ -149,8 +156,7 @@ func (s *syncHandler) HandleFullSyncResponse(
defer res.Release() defer res.Release()
defer objTree.Unlock() defer objTree.Unlock()
// if we already have the heads for whatever reason if s.alreadyHasHeads(objTree, response.Heads) {
if slice.UnsortedEquals(response.Heads, objTree.Heads()) {
return nil return nil
} }
@ -161,39 +167,6 @@ func (s *syncHandler) HandleFullSyncResponse(
return return
} }
func (s *syncHandler) prepareFullSyncRequest( func (s *syncHandler) alreadyHasHeads(t tree.ObjectTree, heads []string) bool {
t tree.ObjectTree, return slice.UnsortedEquals(t.Heads(), heads) || t.HasChanges(heads...)
update *spacesyncproto.ObjectHeadUpdate) (req *spacesyncproto.ObjectFullSyncRequest, err error) {
req = &spacesyncproto.ObjectFullSyncRequest{
Heads: t.Heads(),
SnapshotPath: t.SnapshotPath(),
}
if len(update.Changes) != 0 {
var changesAfterSnapshot []*treechangeproto.RawTreeChangeWithId
changesAfterSnapshot, err = t.ChangesAfterCommonSnapshot(update.SnapshotPath, update.Heads)
if err != nil {
return
}
req.Changes = changesAfterSnapshot
}
return &spacesyncproto.ObjectFullSyncRequest{
Heads: t.Heads(),
SnapshotPath: t.SnapshotPath(),
}, nil
}
func (s *syncHandler) prepareFullSyncResponse(
theirPath,
theirHeads []string,
t tree.ObjectTree) (*spacesyncproto.ObjectFullSyncResponse, error) {
ourChanges, err := t.ChangesAfterCommonSnapshot(theirPath, theirHeads)
if err != nil {
return nil, err
}
return &spacesyncproto.ObjectFullSyncResponse{
Heads: t.Heads(),
Changes: ourChanges,
SnapshotPath: t.SnapshotPath(),
}, nil
} }

View File

@ -0,0 +1,397 @@
package syncservice
import (
"context"
"fmt"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache/mock_cache"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice/mock_syncservice"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"
mock_tree "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree/mock_objecttree"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
"sync"
"testing"
)
type treeContainer struct {
objTree tree.ObjectTree
}
func (t treeContainer) Tree() tree.ObjectTree {
return t.objTree
}
type testObjTreeMock struct {
*mock_tree.MockObjectTree
m sync.Mutex
}
func newTestObjMock(mockTree *mock_tree.MockObjectTree) *testObjTreeMock {
return &testObjTreeMock{
MockObjectTree: mockTree,
}
}
func (t *testObjTreeMock) Lock() {
t.m.Lock()
}
func (t *testObjTreeMock) Unlock() {
t.m.Unlock()
}
func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ctx := context.Background()
spaceId := "spaceId"
cacheMock := mock_cache.NewMockTreeCache(ctrl)
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl)
objectTreeMock := newTestObjMock(mock_tree.NewMockObjectTree(ctrl))
syncHandler := newSyncHandler(spaceId, cacheMock, syncClientMock)
t.Run("head update non empty all heads added", func(t *testing.T) {
treeId := "treeId"
senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{}
headUpdate := &spacesyncproto.ObjectHeadUpdate{
Heads: []string{"h1"},
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
SnapshotPath: []string{"h1"},
}
msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "")
cacheMock.EXPECT().
GetTree(gomock.Any(), spaceId, treeId).
Return(cache.TreeResult{
Release: func() {},
TreeContainer: treeContainer{objectTreeMock},
}, nil)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h2"})
objectTreeMock.EXPECT().
HasChanges(gomock.Eq([]string{"h1"})).
Return(false)
objectTreeMock.EXPECT().
AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})).
Return(tree.AddResult{}, nil)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h2", "h1"})
objectTreeMock.EXPECT().
HasChanges(gomock.Eq([]string{"h1"})).
Return(true)
err := syncHandler.HandleMessage(ctx, senderId, msg)
require.NoError(t, err)
})
t.Run("head update non empty heads not added", func(t *testing.T) {
treeId := "treeId"
senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{}
headUpdate := &spacesyncproto.ObjectHeadUpdate{
Heads: []string{"h1"},
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
SnapshotPath: []string{"h1"},
}
fullRequest := &spacesyncproto.ObjectSyncMessage{}
msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "")
cacheMock.EXPECT().
GetTree(gomock.Any(), spaceId, treeId).
Return(cache.TreeResult{
Release: func() {},
TreeContainer: treeContainer{objectTreeMock},
}, nil)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h2"})
objectTreeMock.EXPECT().
HasChanges(gomock.Eq([]string{"h1"})).
Return(false)
objectTreeMock.EXPECT().
AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})).
Return(tree.AddResult{}, nil)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h2"})
objectTreeMock.EXPECT().
HasChanges(gomock.Eq([]string{"h1"})).
Return(false)
syncClientMock.EXPECT().
CreateFullSyncRequest(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"}), gomock.Eq("")).
Return(fullRequest, nil)
syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest))
err := syncHandler.HandleMessage(ctx, senderId, msg)
require.NoError(t, err)
})
t.Run("head update non empty equal heads", func(t *testing.T) {
treeId := "treeId"
senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{}
headUpdate := &spacesyncproto.ObjectHeadUpdate{
Heads: []string{"h1"},
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
SnapshotPath: []string{"h1"},
}
msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "")
cacheMock.EXPECT().
GetTree(gomock.Any(), spaceId, treeId).
Return(cache.TreeResult{
Release: func() {},
TreeContainer: treeContainer{objectTreeMock},
}, nil)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h1"})
err := syncHandler.HandleMessage(ctx, senderId, msg)
require.NoError(t, err)
})
t.Run("head update empty", func(t *testing.T) {
treeId := "treeId"
senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{}
headUpdate := &spacesyncproto.ObjectHeadUpdate{
Heads: []string{"h1"},
Changes: nil,
SnapshotPath: []string{"h1"},
}
fullRequest := &spacesyncproto.ObjectSyncMessage{}
msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "")
cacheMock.EXPECT().
GetTree(gomock.Any(), spaceId, treeId).
Return(cache.TreeResult{
Release: func() {},
TreeContainer: treeContainer{objectTreeMock},
}, nil)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h2"})
syncClientMock.EXPECT().
CreateFullSyncRequest(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"}), gomock.Eq("")).
Return(fullRequest, nil)
syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest))
err := syncHandler.HandleMessage(ctx, senderId, msg)
require.NoError(t, err)
})
t.Run("head update empty equal heads", func(t *testing.T) {
treeId := "treeId"
senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{}
headUpdate := &spacesyncproto.ObjectHeadUpdate{
Heads: []string{"h1"},
Changes: nil,
SnapshotPath: []string{"h1"},
}
msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "")
cacheMock.EXPECT().
GetTree(gomock.Any(), spaceId, treeId).
Return(cache.TreeResult{
Release: func() {},
TreeContainer: treeContainer{objectTreeMock},
}, nil)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h1"})
err := syncHandler.HandleMessage(ctx, senderId, msg)
require.NoError(t, err)
})
}
func TestSyncHandler_HandleFullSyncRequest(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ctx := context.Background()
spaceId := "spaceId"
cacheMock := mock_cache.NewMockTreeCache(ctrl)
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl)
objectTreeMock := newTestObjMock(mock_tree.NewMockObjectTree(ctrl))
syncHandler := newSyncHandler(spaceId, cacheMock, syncClientMock)
t.Run("full sync request with change", func(t *testing.T) {
treeId := "treeId"
senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{}
msg := spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{
Heads: []string{"h1"},
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
SnapshotPath: []string{"h1"},
}, chWithId, treeId, "")
fullRequest := &spacesyncproto.ObjectSyncMessage{}
cacheMock.EXPECT().
GetTree(gomock.Any(), spaceId, treeId).
Return(cache.TreeResult{
Release: func() {},
TreeContainer: treeContainer{objectTreeMock},
}, nil)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h2"})
objectTreeMock.EXPECT().
HasChanges(gomock.Eq([]string{"h1"})).
Return(false)
objectTreeMock.EXPECT().
AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})).
Return(tree.AddResult{}, nil)
syncClientMock.EXPECT().
CreateFullSyncResponse(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"}), gomock.Eq("")).
Return(fullRequest, nil)
syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest))
err := syncHandler.HandleMessage(ctx, senderId, msg)
require.NoError(t, err)
})
t.Run("full sync request with change same heads", func(t *testing.T) {
treeId := "treeId"
senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{}
msg := spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{
Heads: []string{"h2"},
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
SnapshotPath: []string{"h2"},
}, chWithId, treeId, "")
fullRequest := &spacesyncproto.ObjectSyncMessage{}
cacheMock.EXPECT().
GetTree(gomock.Any(), spaceId, treeId).
Return(cache.TreeResult{
Release: func() {},
TreeContainer: treeContainer{objectTreeMock},
}, nil)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h2"})
syncClientMock.EXPECT().
CreateFullSyncResponse(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h2"}), gomock.Eq([]string{"h2"}), gomock.Eq("")).
Return(fullRequest, nil)
syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest))
err := syncHandler.HandleMessage(ctx, senderId, msg)
require.NoError(t, err)
})
t.Run("full sync request without change", func(t *testing.T) {
treeId := "treeId"
senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{}
msg := spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{
Heads: []string{"h1"},
SnapshotPath: []string{"h1"},
}, chWithId, treeId, "")
fullRequest := &spacesyncproto.ObjectSyncMessage{}
cacheMock.EXPECT().
GetTree(gomock.Any(), spaceId, treeId).
Return(cache.TreeResult{
Release: func() {},
TreeContainer: treeContainer{objectTreeMock},
}, nil)
syncClientMock.EXPECT().
CreateFullSyncResponse(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"}), gomock.Eq("")).
Return(fullRequest, nil)
syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest))
err := syncHandler.HandleMessage(ctx, senderId, msg)
require.NoError(t, err)
})
t.Run("full sync request with get tree error", func(t *testing.T) {
treeId := "treeId"
senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{}
msg := spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{
Heads: []string{"h1"},
SnapshotPath: []string{"h1"},
}, chWithId, treeId, "")
cacheMock.EXPECT().
GetTree(gomock.Any(), spaceId, treeId).
Return(cache.TreeResult{}, fmt.Errorf("some"))
syncClientMock.EXPECT().
SendAsync(gomock.Eq([]string{senderId}), gomock.Any())
err := syncHandler.HandleMessage(ctx, senderId, msg)
require.Error(t, err)
})
}
func TestSyncHandler_HandleFullSyncResponse(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ctx := context.Background()
spaceId := "spaceId"
cacheMock := mock_cache.NewMockTreeCache(ctrl)
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl)
objectTreeMock := newTestObjMock(mock_tree.NewMockObjectTree(ctrl))
syncHandler := newSyncHandler(spaceId, cacheMock, syncClientMock)
t.Run("full sync response with change", func(t *testing.T) {
treeId := "treeId"
senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{}
msg := spacesyncproto.WrapFullResponse(&spacesyncproto.ObjectFullSyncResponse{
Heads: []string{"h1"},
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
SnapshotPath: []string{"h1"},
}, chWithId, treeId, "")
cacheMock.EXPECT().
GetTree(gomock.Any(), spaceId, treeId).
Return(cache.TreeResult{
Release: func() {},
TreeContainer: treeContainer{objectTreeMock},
}, nil)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h2"})
objectTreeMock.EXPECT().
HasChanges(gomock.Eq([]string{"h1"})).
Return(false)
objectTreeMock.EXPECT().
AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})).
Return(tree.AddResult{}, nil)
err := syncHandler.HandleMessage(ctx, senderId, msg)
require.NoError(t, err)
})
t.Run("full sync response same heads", func(t *testing.T) {
treeId := "treeId"
senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{}
msg := spacesyncproto.WrapFullResponse(&spacesyncproto.ObjectFullSyncResponse{
Heads: []string{"h1"},
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
SnapshotPath: []string{"h1"},
}, chWithId, treeId, "")
cacheMock.EXPECT().
GetTree(gomock.Any(), spaceId, treeId).
Return(cache.TreeResult{
Release: func() {},
TreeContainer: treeContainer{objectTreeMock},
}, nil)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h1"})
err := syncHandler.HandleMessage(ctx, senderId, msg)
require.NoError(t, err)
})
}

View File

@ -1,3 +1,4 @@
//go:generate mockgen -destination mock_syncservice/mock_syncservice.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice SyncClient
package syncservice package syncservice
import ( import (
@ -7,19 +8,13 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/rpcerr" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/rpcerr"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto"
"time" "time"
) )
var log = logger.NewNamed("syncservice").Sugar() var log = logger.NewNamed("syncservice").Sugar()
type SyncService interface { type SyncService interface {
NotifyHeadUpdate( SyncClient() SyncClient
ctx context.Context,
treeId string,
root *treechangeproto.RawTreeChangeWithId,
update *spacesyncproto.ObjectHeadUpdate) (err error)
StreamPool() StreamPool
Init() Init()
Close() (err error) Close() (err error)
@ -34,36 +29,44 @@ const respPeersStreamCheckInterval = time.Second * 10
type syncService struct { type syncService struct {
spaceId string spaceId string
syncHandler SyncHandler syncClient SyncClient
streamPool StreamPool clientFactory spacesyncproto.ClientFactory
headNotifiable HeadNotifiable
configuration nodeconf.Configuration
streamLoopCtx context.Context streamLoopCtx context.Context
stopStreamLoop context.CancelFunc stopStreamLoop context.CancelFunc
connector nodeconf.ConfConnector
streamLoopDone chan struct{} streamLoopDone chan struct{}
} }
func NewSyncService(spaceId string, headNotifiable HeadNotifiable, cache cache.TreeCache, configuration nodeconf.Configuration) SyncService { func NewSyncService(
spaceId string,
headNotifiable HeadNotifiable,
cache cache.TreeCache,
configuration nodeconf.Configuration,
confConnector nodeconf.ConfConnector) SyncService {
var syncHandler SyncHandler var syncHandler SyncHandler
streamPool := newStreamPool(func(ctx context.Context, senderId string, message *spacesyncproto.ObjectSyncMessage) (err error) { streamPool := newStreamPool(func(ctx context.Context, senderId string, message *spacesyncproto.ObjectSyncMessage) (err error) {
return syncHandler.HandleMessage(ctx, senderId, message) return syncHandler.HandleMessage(ctx, senderId, message)
}) })
syncHandler = newSyncHandler(spaceId, cache, streamPool) factory := newRequestFactory()
return newSyncService(spaceId, headNotifiable, syncHandler, streamPool, configuration) syncClient := newSyncClient(spaceId, streamPool, headNotifiable, factory, configuration)
syncHandler = newSyncHandler(spaceId, cache, syncClient)
return newSyncService(
spaceId,
syncClient,
spacesyncproto.ClientFactoryFunc(spacesyncproto.NewDRPCSpaceClient),
confConnector)
} }
func newSyncService( func newSyncService(
spaceId string, spaceId string,
headNotifiable HeadNotifiable, syncClient SyncClient,
syncHandler SyncHandler, clientFactory spacesyncproto.ClientFactory,
streamPool StreamPool, connector nodeconf.ConfConnector) *syncService {
configuration nodeconf.Configuration) *syncService {
return &syncService{ return &syncService{
syncHandler: syncHandler, syncClient: syncClient,
streamPool: streamPool, connector: connector,
headNotifiable: headNotifiable, clientFactory: clientFactory,
configuration: configuration,
spaceId: spaceId, spaceId: spaceId,
streamLoopDone: make(chan struct{}), streamLoopDone: make(chan struct{}),
} }
@ -77,32 +80,24 @@ func (s *syncService) Init() {
func (s *syncService) Close() (err error) { func (s *syncService) Close() (err error) {
s.stopStreamLoop() s.stopStreamLoop()
<-s.streamLoopDone <-s.streamLoopDone
return s.streamPool.Close() return s.syncClient.Close()
}
func (s *syncService) NotifyHeadUpdate(
ctx context.Context,
treeId string,
header *treechangeproto.RawTreeChangeWithId,
update *spacesyncproto.ObjectHeadUpdate) (err error) {
s.headNotifiable.UpdateHeads(treeId, update.Heads)
return s.streamPool.BroadcastAsync(spacesyncproto.WrapHeadUpdate(update, header, treeId, ""))
} }
func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) { func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) {
defer close(s.streamLoopDone) defer close(s.streamLoopDone)
checkResponsiblePeers := func() { checkResponsiblePeers := func() {
respPeers, err := s.configuration.ResponsiblePeers(ctx, s.spaceId) respPeers, err := s.connector.DialResponsiblePeers(ctx, s.spaceId)
if err != nil { if err != nil {
return return
} }
for _, peer := range respPeers { for _, peer := range respPeers {
if s.streamPool.HasActiveStream(peer.Id()) { if s.syncClient.HasActiveStream(peer.Id()) {
continue continue
} }
cl := spacesyncproto.NewDRPCSpaceClient(peer) stream, err := s.clientFactory.Client(peer).Stream(ctx)
stream, err := cl.Stream(ctx)
if err != nil { if err != nil {
err = rpcerr.Unwrap(err)
log.With("spaceId", s.spaceId).Errorf("failed to open stream: %v", err)
// so here probably the request is failed because there is no such space, // so here probably the request is failed because there is no such space,
// but diffService should handle such cases by sending pushSpace // but diffService should handle such cases by sending pushSpace
continue continue
@ -111,10 +106,10 @@ func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) {
err = stream.Send(&spacesyncproto.ObjectSyncMessage{SpaceId: s.spaceId}) err = stream.Send(&spacesyncproto.ObjectSyncMessage{SpaceId: s.spaceId})
if err != nil { if err != nil {
err = rpcerr.Unwrap(err) err = rpcerr.Unwrap(err)
log.With("spaceId", s.spaceId).Errorf("failed to open stream: %v", err) log.With("spaceId", s.spaceId).Errorf("failed to send first message to stream: %v", err)
continue continue
} }
s.streamPool.AddAndReadStreamAsync(stream) s.syncClient.AddAndReadStreamAsync(stream)
} }
} }
@ -131,6 +126,6 @@ func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) {
} }
} }
func (s *syncService) StreamPool() StreamPool { func (s *syncService) SyncClient() SyncClient {
return s.streamPool return s.syncClient
} }

View File

@ -2,7 +2,6 @@ package synctree
import ( import (
"context" "context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list"
@ -14,105 +13,101 @@ import (
// SyncTree sends head updates to sync service and also sends new changes to update listener // SyncTree sends head updates to sync service and also sends new changes to update listener
type SyncTree struct { type SyncTree struct {
tree.ObjectTree tree.ObjectTree
syncService syncservice.SyncService syncClient syncservice.SyncClient
listener updatelistener.UpdateListener listener updatelistener.UpdateListener
} }
var createDerivedObjectTree = tree.CreateDerivedObjectTree
var createObjectTree = tree.CreateObjectTree
var buildObjectTree = tree.BuildObjectTree
func DeriveSyncTree( func DeriveSyncTree(
ctx context.Context, ctx context.Context,
payload tree.ObjectTreeCreatePayload, payload tree.ObjectTreeCreatePayload,
syncService syncservice.SyncService, syncClient syncservice.SyncClient,
listener updatelistener.UpdateListener, listener updatelistener.UpdateListener,
aclList list.ACLList, aclList list.ACLList,
createStorage storage.TreeStorageCreatorFunc) (t tree.ObjectTree, err error) { createStorage storage.TreeStorageCreatorFunc) (t tree.ObjectTree, err error) {
t, err = tree.CreateDerivedObjectTree(payload, aclList, createStorage) t, err = createDerivedObjectTree(payload, aclList, createStorage)
if err != nil { if err != nil {
return return
} }
t = &SyncTree{ t = &SyncTree{
ObjectTree: t, ObjectTree: t,
syncService: syncService, syncClient: syncClient,
listener: listener, listener: listener,
} }
err = syncService.NotifyHeadUpdate(ctx, t.ID(), t.Header(), &spacesyncproto.ObjectHeadUpdate{ headUpdate := syncClient.CreateHeadUpdate(t, nil)
Heads: t.Heads(), err = syncClient.BroadcastAsync(headUpdate)
SnapshotPath: t.SnapshotPath(),
})
return return
} }
func CreateSyncTree( func CreateSyncTree(
ctx context.Context, ctx context.Context,
payload tree.ObjectTreeCreatePayload, payload tree.ObjectTreeCreatePayload,
syncService syncservice.SyncService, syncClient syncservice.SyncClient,
listener updatelistener.UpdateListener, listener updatelistener.UpdateListener,
aclList list.ACLList, aclList list.ACLList,
createStorage storage.TreeStorageCreatorFunc) (t tree.ObjectTree, err error) { createStorage storage.TreeStorageCreatorFunc) (t tree.ObjectTree, err error) {
t, err = tree.CreateObjectTree(payload, aclList, createStorage) t, err = createObjectTree(payload, aclList, createStorage)
if err != nil { if err != nil {
return return
} }
t = &SyncTree{ t = &SyncTree{
ObjectTree: t, ObjectTree: t,
syncService: syncService, syncClient: syncClient,
listener: listener, listener: listener,
} }
err = syncService.NotifyHeadUpdate(ctx, t.ID(), t.Header(), &spacesyncproto.ObjectHeadUpdate{ headUpdate := syncClient.CreateHeadUpdate(t, nil)
Heads: t.Heads(), err = syncClient.BroadcastAsync(headUpdate)
SnapshotPath: t.SnapshotPath(),
})
return return
} }
func BuildSyncTree( func BuildSyncTree(
ctx context.Context, ctx context.Context,
syncService syncservice.SyncService, syncClient syncservice.SyncClient,
treeStorage storage.TreeStorage, treeStorage storage.TreeStorage,
listener updatelistener.UpdateListener, listener updatelistener.UpdateListener,
aclList list.ACLList) (t tree.ObjectTree, err error) { aclList list.ACLList) (t tree.ObjectTree, err error) {
return buildSyncTree(ctx, syncService, treeStorage, listener, aclList) return buildSyncTree(ctx, syncClient, treeStorage, listener, aclList)
} }
func buildSyncTree( func buildSyncTree(
ctx context.Context, ctx context.Context,
syncService syncservice.SyncService, syncClient syncservice.SyncClient,
treeStorage storage.TreeStorage, treeStorage storage.TreeStorage,
listener updatelistener.UpdateListener, listener updatelistener.UpdateListener,
aclList list.ACLList) (t tree.ObjectTree, err error) { aclList list.ACLList) (t tree.ObjectTree, err error) {
t, err = tree.BuildObjectTree(treeStorage, aclList) t, err = buildObjectTree(treeStorage, aclList)
if err != nil { if err != nil {
return return
} }
t = &SyncTree{ t = &SyncTree{
ObjectTree: t, ObjectTree: t,
syncService: syncService, syncClient: syncClient,
listener: listener, listener: listener,
} }
err = syncService.NotifyHeadUpdate(ctx, t.ID(), t.Header(), &spacesyncproto.ObjectHeadUpdate{ headUpdate := syncClient.CreateHeadUpdate(t, nil)
Heads: t.Heads(), // here we will have different behaviour based on who is sending this update
SnapshotPath: t.SnapshotPath(), err = syncClient.BroadcastAsyncOrSendResponsible(headUpdate)
})
return return
} }
func (s *SyncTree) AddContent(ctx context.Context, content tree.SignableChangeContent) (res tree.AddResult, err error) { func (s *SyncTree) AddContent(ctx context.Context, content tree.SignableChangeContent) (res tree.AddResult, err error) {
res, err = s.AddContent(ctx, content) res, err = s.ObjectTree.AddContent(ctx, content)
if err != nil { if err != nil {
return return
} }
err = s.syncService.NotifyHeadUpdate(ctx, s.ID(), s.Header(), &spacesyncproto.ObjectHeadUpdate{ headUpdate := s.syncClient.CreateHeadUpdate(s, res.Added)
Heads: res.Heads, err = s.syncClient.BroadcastAsync(headUpdate)
Changes: res.Added,
SnapshotPath: s.SnapshotPath(),
})
return return
} }
func (s *SyncTree) AddRawChanges(ctx context.Context, changes ...*treechangeproto.RawTreeChangeWithId) (res tree.AddResult, err error) { func (s *SyncTree) AddRawChanges(ctx context.Context, changes ...*treechangeproto.RawTreeChangeWithId) (res tree.AddResult, err error) {
res, err = s.AddRawChanges(ctx, changes...) res, err = s.ObjectTree.AddRawChanges(ctx, changes...)
if err != nil { if err != nil {
return return
} }
@ -125,11 +120,8 @@ func (s *SyncTree) AddRawChanges(ctx context.Context, changes ...*treechangeprot
s.listener.Rebuild(s) s.listener.Rebuild(s)
} }
err = s.syncService.NotifyHeadUpdate(ctx, s.ID(), s.Header(), &spacesyncproto.ObjectHeadUpdate{ headUpdate := s.syncClient.CreateHeadUpdate(s, res.Added)
Heads: res.Heads, err = s.syncClient.BroadcastAsync(headUpdate)
Changes: res.Added,
SnapshotPath: s.SnapshotPath(),
})
return return
} }

View File

@ -0,0 +1,176 @@
package synctree
import (
"context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice/mock_syncservice"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener/mock_updatelistener"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list/mock_list"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage/mock_storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"
mock_tree "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree/mock_objecttree"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
"testing"
)
type syncTreeMatcher struct {
objTree tree.ObjectTree
client syncservice.SyncClient
listener updatelistener.UpdateListener
}
func (s syncTreeMatcher) Matches(x interface{}) bool {
t, ok := x.(*SyncTree)
if !ok {
return false
}
return s.objTree == t.ObjectTree && t.syncClient == s.client && t.listener == s.listener
}
func (s syncTreeMatcher) String() string {
return ""
}
func Test_DeriveSyncTree(t *testing.T) {
ctx := context.Background()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
updateListenerMock := mock_updatelistener.NewMockUpdateListener(ctrl)
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl)
aclListMock := mock_list.NewMockACLList(ctrl)
createStorage := storage.TreeStorageCreatorFunc(func(payload storage.TreeStorageCreatePayload) (storage.TreeStorage, error) {
return nil, nil
})
objTreeMock := mock_tree.NewMockObjectTree(ctrl)
createDerivedObjectTree = func(payload tree.ObjectTreeCreatePayload, l list.ACLList, create storage.TreeStorageCreatorFunc) (objTree tree.ObjectTree, err error) {
require.Equal(t, l, aclListMock)
return objTreeMock, nil
}
headUpdate := &spacesyncproto.ObjectSyncMessage{}
syncClientMock.EXPECT().CreateHeadUpdate(syncTreeMatcher{objTreeMock, syncClientMock, updateListenerMock}, gomock.Nil()).Return(headUpdate)
syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil)
_, err := DeriveSyncTree(ctx, tree.ObjectTreeCreatePayload{}, syncClientMock, updateListenerMock, aclListMock, createStorage)
require.NoError(t, err)
}
func Test_CreateSyncTree(t *testing.T) {
ctx := context.Background()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
updateListenerMock := mock_updatelistener.NewMockUpdateListener(ctrl)
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl)
aclListMock := mock_list.NewMockACLList(ctrl)
createStorage := storage.TreeStorageCreatorFunc(func(payload storage.TreeStorageCreatePayload) (storage.TreeStorage, error) {
return nil, nil
})
objTreeMock := mock_tree.NewMockObjectTree(ctrl)
createObjectTree = func(payload tree.ObjectTreeCreatePayload, l list.ACLList, create storage.TreeStorageCreatorFunc) (objTree tree.ObjectTree, err error) {
require.Equal(t, l, aclListMock)
return objTreeMock, nil
}
headUpdate := &spacesyncproto.ObjectSyncMessage{}
syncClientMock.EXPECT().CreateHeadUpdate(syncTreeMatcher{objTreeMock, syncClientMock, updateListenerMock}, gomock.Nil()).Return(headUpdate)
syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil)
_, err := CreateSyncTree(ctx, tree.ObjectTreeCreatePayload{}, syncClientMock, updateListenerMock, aclListMock, createStorage)
require.NoError(t, err)
}
func Test_BuildSyncTree(t *testing.T) {
ctx := context.Background()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
updateListenerMock := mock_updatelistener.NewMockUpdateListener(ctrl)
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl)
aclListMock := mock_list.NewMockACLList(ctrl)
storageMock := mock_storage.NewMockTreeStorage(ctrl)
objTreeMock := mock_tree.NewMockObjectTree(ctrl)
buildObjectTree = func(store storage.TreeStorage, l list.ACLList) (objTree tree.ObjectTree, err error) {
require.Equal(t, aclListMock, l)
require.Equal(t, store, storageMock)
return objTreeMock, nil
}
headUpdate := &spacesyncproto.ObjectSyncMessage{}
syncClientMock.EXPECT().CreateHeadUpdate(syncTreeMatcher{objTreeMock, syncClientMock, updateListenerMock}, gomock.Nil()).Return(headUpdate)
syncClientMock.EXPECT().BroadcastAsyncOrSendResponsible(gomock.Eq(headUpdate)).Return(nil)
tr, err := BuildSyncTree(ctx, syncClientMock, storageMock, updateListenerMock, aclListMock)
require.NoError(t, err)
t.Run("AddRawChanges update", func(t *testing.T) {
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
expectedRes := tree.AddResult{
Added: changes,
Mode: tree.Append,
}
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(changes)).
Return(expectedRes, nil)
updateListenerMock.EXPECT().Update(tr)
syncClientMock.EXPECT().CreateHeadUpdate(gomock.Eq(tr), gomock.Eq(changes)).Return(headUpdate)
syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil)
res, err := tr.AddRawChanges(ctx, changes...)
require.NoError(t, err)
require.Equal(t, expectedRes, res)
})
t.Run("AddRawChanges rebuild", func(t *testing.T) {
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
expectedRes := tree.AddResult{
Added: changes,
Mode: tree.Rebuild,
}
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(changes)).
Return(expectedRes, nil)
updateListenerMock.EXPECT().Rebuild(tr)
syncClientMock.EXPECT().CreateHeadUpdate(gomock.Eq(tr), gomock.Eq(changes)).Return(headUpdate)
syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil)
res, err := tr.AddRawChanges(ctx, changes...)
require.NoError(t, err)
require.Equal(t, expectedRes, res)
})
t.Run("AddRawChanges nothing", func(t *testing.T) {
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
expectedRes := tree.AddResult{
Added: changes,
Mode: tree.Nothing,
}
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(changes)).
Return(expectedRes, nil)
res, err := tr.AddRawChanges(ctx, changes...)
require.NoError(t, err)
require.Equal(t, expectedRes, res)
})
t.Run("AddContent", func(t *testing.T) {
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
content := tree.SignableChangeContent{
Data: []byte("abcde"),
}
expectedRes := tree.AddResult{
Mode: tree.Append,
Added: changes,
}
objTreeMock.EXPECT().AddContent(gomock.Any(), gomock.Eq(content)).
Return(expectedRes, nil)
syncClientMock.EXPECT().CreateHeadUpdate(gomock.Eq(tr), gomock.Eq(changes)).Return(headUpdate)
syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil)
res, err := tr.AddContent(ctx, content)
require.NoError(t, err)
require.Equal(t, expectedRes, res)
})
}

View File

@ -0,0 +1,59 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener (interfaces: UpdateListener)
// Package mock_updatelistener is a generated GoMock package.
package mock_updatelistener
import (
reflect "reflect"
tree "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"
gomock "github.com/golang/mock/gomock"
)
// MockUpdateListener is a mock of UpdateListener interface.
type MockUpdateListener struct {
ctrl *gomock.Controller
recorder *MockUpdateListenerMockRecorder
}
// MockUpdateListenerMockRecorder is the mock recorder for MockUpdateListener.
type MockUpdateListenerMockRecorder struct {
mock *MockUpdateListener
}
// NewMockUpdateListener creates a new mock instance.
func NewMockUpdateListener(ctrl *gomock.Controller) *MockUpdateListener {
mock := &MockUpdateListener{ctrl: ctrl}
mock.recorder = &MockUpdateListenerMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockUpdateListener) EXPECT() *MockUpdateListenerMockRecorder {
return m.recorder
}
// Rebuild mocks base method.
func (m *MockUpdateListener) Rebuild(arg0 tree.ObjectTree) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Rebuild", arg0)
}
// Rebuild indicates an expected call of Rebuild.
func (mr *MockUpdateListenerMockRecorder) Rebuild(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Rebuild", reflect.TypeOf((*MockUpdateListener)(nil).Rebuild), arg0)
}
// Update mocks base method.
func (m *MockUpdateListener) Update(arg0 tree.ObjectTree) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Update", arg0)
}
// Update indicates an expected call of Update.
func (mr *MockUpdateListenerMockRecorder) Update(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockUpdateListener)(nil).Update), arg0)
}

View File

@ -1,3 +1,4 @@
//go:generate mockgen -destination mock_updatelistener/mock_updatelistener.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener UpdateListener
package updatelistener package updatelistener
import "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree" import "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"

View File

@ -0,0 +1,54 @@
package nodeconf
import (
"context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool"
)
type ConfConnector interface {
GetResponsiblePeers(ctx context.Context, spaceId string) ([]peer.Peer, error)
DialResponsiblePeers(ctx context.Context, spaceId string) ([]peer.Peer, error)
}
type confConnector struct {
conf Configuration
pool pool.Pool
}
func NewConfConnector(conf Configuration, pool pool.Pool) ConfConnector {
return &confConnector{conf: conf, pool: pool}
}
func (s *confConnector) GetResponsiblePeers(ctx context.Context, spaceId string) ([]peer.Peer, error) {
return s.dialOrConnect(ctx, spaceId, s.pool.Get, s.pool.GetOneOf)
}
func (s *confConnector) DialResponsiblePeers(ctx context.Context, spaceId string) ([]peer.Peer, error) {
return s.dialOrConnect(ctx, spaceId, s.pool.Dial, s.pool.DialOneOf)
}
func (s *confConnector) dialOrConnect(
ctx context.Context, spaceId string,
connectOne func(context.Context, string) (peer.Peer, error),
connectOneOf func(context.Context, []string) (peer.Peer, error)) (peers []peer.Peer, err error) {
allNodes := s.conf.NodeIds(spaceId)
if !s.conf.IsResponsible(spaceId) {
for _, id := range allNodes {
var p peer.Peer
p, err = connectOne(ctx, id)
if err != nil {
continue
}
peers = append(peers, p)
}
} else {
var p peer.Peer
p, err = connectOneOf(ctx, allNodes)
if err != nil {
return
}
peers = []peer.Peer{p}
}
return
}

View File

@ -1,10 +1,7 @@
//go:generate mockgen -destination mock_nodeconf/mock_nodeconf.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf Configuration,ConfConnector
package nodeconf package nodeconf
import ( import (
"context"
"fmt"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool"
"github.com/anytypeio/go-chash" "github.com/anytypeio/go-chash"
) )
@ -15,12 +12,6 @@ func New() Service {
type Configuration interface { type Configuration interface {
// Id returns current nodeconf id // Id returns current nodeconf id
Id() string Id() string
// AllPeers returns all peers by spaceId except current account
AllPeers(ctx context.Context, spaceId string) (peers []peer.Peer, err error)
// OnePeer returns one of peer for spaceId
OnePeer(ctx context.Context, spaceId string) (p peer.Peer, err error)
// ResponsiblePeers returns peers for the space id that are responsible for the space
ResponsiblePeers(ctx context.Context, spaceId string) (peers []peer.Peer, err error)
// NodeIds returns list of peerId for given spaceId // NodeIds returns list of peerId for given spaceId
NodeIds(spaceId string) []string NodeIds(spaceId string) []string
// IsResponsible checks if current account responsible for given spaceId // IsResponsible checks if current account responsible for given spaceId
@ -30,7 +21,6 @@ type Configuration interface {
type configuration struct { type configuration struct {
id string id string
accountId string accountId string
pool pool.Pool
chash chash.CHash chash chash.CHash
} }
@ -38,40 +28,6 @@ func (c *configuration) Id() string {
return c.id return c.id
} }
func (c *configuration) AllPeers(ctx context.Context, spaceId string) (peers []peer.Peer, err error) {
nodeIds := c.NodeIds(spaceId)
peers = make([]peer.Peer, 0, len(nodeIds))
for _, id := range nodeIds {
p, e := c.pool.Get(ctx, id)
if e == nil {
peers = append(peers, p)
}
}
if len(peers) == 0 {
return nil, fmt.Errorf("unable to connect to any node")
}
return
}
func (c *configuration) ResponsiblePeers(ctx context.Context, spaceId string) (peers []peer.Peer, err error) {
if c.IsResponsible(spaceId) {
return c.AllPeers(ctx, spaceId)
} else {
var one peer.Peer
one, err = c.OnePeer(ctx, spaceId)
if err != nil {
return
}
peers = []peer.Peer{one}
return
}
}
func (c *configuration) OnePeer(ctx context.Context, spaceId string) (p peer.Peer, err error) {
nodeIds := c.NodeIds(spaceId)
return c.pool.GetOneOf(ctx, nodeIds)
}
func (c *configuration) NodeIds(spaceId string) []string { func (c *configuration) NodeIds(spaceId string) []string {
members := c.chash.GetMembers(spaceId) members := c.chash.GetMembers(spaceId)
res := make([]string, 0, len(members)) res := make([]string, 0, len(members))

View File

@ -0,0 +1,131 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf (interfaces: Configuration,ConfConnector)
// Package mock_nodeconf is a generated GoMock package.
package mock_nodeconf
import (
context "context"
reflect "reflect"
peer "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer"
gomock "github.com/golang/mock/gomock"
)
// MockConfiguration is a mock of Configuration interface.
type MockConfiguration struct {
ctrl *gomock.Controller
recorder *MockConfigurationMockRecorder
}
// MockConfigurationMockRecorder is the mock recorder for MockConfiguration.
type MockConfigurationMockRecorder struct {
mock *MockConfiguration
}
// NewMockConfiguration creates a new mock instance.
func NewMockConfiguration(ctrl *gomock.Controller) *MockConfiguration {
mock := &MockConfiguration{ctrl: ctrl}
mock.recorder = &MockConfigurationMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockConfiguration) EXPECT() *MockConfigurationMockRecorder {
return m.recorder
}
// Id mocks base method.
func (m *MockConfiguration) Id() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Id")
ret0, _ := ret[0].(string)
return ret0
}
// Id indicates an expected call of Id.
func (mr *MockConfigurationMockRecorder) Id() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Id", reflect.TypeOf((*MockConfiguration)(nil).Id))
}
// IsResponsible mocks base method.
func (m *MockConfiguration) IsResponsible(arg0 string) bool {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "IsResponsible", arg0)
ret0, _ := ret[0].(bool)
return ret0
}
// IsResponsible indicates an expected call of IsResponsible.
func (mr *MockConfigurationMockRecorder) IsResponsible(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsResponsible", reflect.TypeOf((*MockConfiguration)(nil).IsResponsible), arg0)
}
// NodeIds mocks base method.
func (m *MockConfiguration) NodeIds(arg0 string) []string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "NodeIds", arg0)
ret0, _ := ret[0].([]string)
return ret0
}
// NodeIds indicates an expected call of NodeIds.
func (mr *MockConfigurationMockRecorder) NodeIds(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeIds", reflect.TypeOf((*MockConfiguration)(nil).NodeIds), arg0)
}
// MockConfConnector is a mock of ConfConnector interface.
type MockConfConnector struct {
ctrl *gomock.Controller
recorder *MockConfConnectorMockRecorder
}
// MockConfConnectorMockRecorder is the mock recorder for MockConfConnector.
type MockConfConnectorMockRecorder struct {
mock *MockConfConnector
}
// NewMockConfConnector creates a new mock instance.
func NewMockConfConnector(ctrl *gomock.Controller) *MockConfConnector {
mock := &MockConfConnector{ctrl: ctrl}
mock.recorder = &MockConfConnectorMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockConfConnector) EXPECT() *MockConfConnectorMockRecorder {
return m.recorder
}
// DialResponsiblePeers mocks base method.
func (m *MockConfConnector) DialResponsiblePeers(arg0 context.Context, arg1 string) ([]peer.Peer, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DialResponsiblePeers", arg0, arg1)
ret0, _ := ret[0].([]peer.Peer)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// DialResponsiblePeers indicates an expected call of DialResponsiblePeers.
func (mr *MockConfConnectorMockRecorder) DialResponsiblePeers(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DialResponsiblePeers", reflect.TypeOf((*MockConfConnector)(nil).DialResponsiblePeers), arg0, arg1)
}
// GetResponsiblePeers mocks base method.
func (m *MockConfConnector) GetResponsiblePeers(arg0 context.Context, arg1 string) ([]peer.Peer, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetResponsiblePeers", arg0, arg1)
ret0, _ := ret[0].([]peer.Peer)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetResponsiblePeers indicates an expected call of GetResponsiblePeers.
func (mr *MockConfConnectorMockRecorder) GetResponsiblePeers(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetResponsiblePeers", reflect.TypeOf((*MockConfConnector)(nil).GetResponsiblePeers), arg0, arg1)
}

View File

@ -3,7 +3,6 @@ package nodeconf
import ( import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/app" "github.com/anytypeio/go-anytype-infrastructure-experiments/app"
"github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger" "github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool"
"github.com/anytypeio/go-anytype-infrastructure-experiments/config" "github.com/anytypeio/go-anytype-infrastructure-experiments/config"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys" "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/encryptionkey" "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/encryptionkey"
@ -29,7 +28,6 @@ type Service interface {
type service struct { type service struct {
accountId string accountId string
pool pool.Pool
consensusPeers []string consensusPeers []string
last Configuration last Configuration
@ -53,12 +51,10 @@ func (n *Node) Capacity() float64 {
func (s *service) Init(a *app.App) (err error) { func (s *service) Init(a *app.App) (err error) {
conf := a.MustComponent(config.CName).(*config.Config) conf := a.MustComponent(config.CName).(*config.Config)
s.accountId = conf.Account.PeerId s.accountId = conf.Account.PeerId
s.pool = a.MustComponent(pool.CName).(pool.Pool)
config := &configuration{ config := &configuration{
id: "config", id: "config",
accountId: s.accountId, accountId: s.accountId,
pool: s.pool,
} }
if config.chash, err = chash.New(chash.Config{ if config.chash, err = chash.New(chash.Config{
PartitionCount: partitionCount, PartitionCount: partitionCount,

View File

@ -48,12 +48,16 @@ type service struct {
func (s *service) Init(a *app.App) (err error) { func (s *service) Init(a *app.App) (err error) {
s.db = a.MustComponent(db.CName).(db.Service) s.db = a.MustComponent(db.CName).(db.Service)
s.cache = ocache.New(s.loadLog,
cacheOpts := []ocache.Option{
ocache.WithTTL(cacheTTL), ocache.WithTTL(cacheTTL),
ocache.WithRefCounter(false), ocache.WithRefCounter(false),
ocache.WithLogger(log.Named("cache").Sugar()), ocache.WithLogger(log.Named("cache").Sugar()),
ocache.WithPrometheus(a.MustComponent(metric.CName).(metric.Metric).Registry(), "consensus", "logcache"), }
) if ms := a.Component(metric.CName); ms != nil {
cacheOpts = append(cacheOpts, ocache.WithPrometheus(ms.(metric.Metric).Registry(), "consensus", "logcache"))
}
s.cache = ocache.New(s.loadLog, cacheOpts...)
return s.db.SetChangeReceiver(s.receiveChange) return s.db.SetChangeReceiver(s.receiveChange)
} }

9
go.mod
View File

@ -6,15 +6,19 @@ require (
github.com/anytypeio/go-chash v0.0.0-20220629194632-4ad1154fe232 github.com/anytypeio/go-chash v0.0.0-20220629194632-4ad1154fe232
github.com/awalterschulze/gographviz v0.0.0-20190522210029-fa59802746ab github.com/awalterschulze/gographviz v0.0.0-20190522210029-fa59802746ab
github.com/cespare/xxhash v1.1.0 github.com/cespare/xxhash v1.1.0
github.com/cheggaaa/mb/v2 v2.0.1
github.com/goccy/go-graphviz v0.0.9 github.com/goccy/go-graphviz v0.0.9
github.com/gogo/protobuf v1.3.2 github.com/gogo/protobuf v1.3.2
github.com/golang/mock v1.6.0
github.com/huandu/skiplist v1.2.0 github.com/huandu/skiplist v1.2.0
github.com/ipfs/go-cid v0.1.0 github.com/ipfs/go-cid v0.1.0
github.com/libp2p/go-libp2p v0.20.3 github.com/libp2p/go-libp2p v0.20.3
github.com/libp2p/go-libp2p-core v0.16.1 github.com/libp2p/go-libp2p-core v0.16.1
github.com/minio/sha256-simd v1.0.0 github.com/minio/sha256-simd v1.0.0
github.com/mr-tron/base58 v1.2.0
github.com/multiformats/go-multibase v0.0.3 github.com/multiformats/go-multibase v0.0.3
github.com/multiformats/go-multihash v0.1.0 github.com/multiformats/go-multihash v0.1.0
github.com/prometheus/client_golang v1.13.0
github.com/stretchr/testify v1.8.0 github.com/stretchr/testify v1.8.0
github.com/zeebo/blake3 v0.2.3 github.com/zeebo/blake3 v0.2.3
github.com/zeebo/errs v1.3.0 github.com/zeebo/errs v1.3.0
@ -32,7 +36,6 @@ require (
github.com/btcsuite/btcd/btcec/v2 v2.1.3 // indirect github.com/btcsuite/btcd/btcec/v2 v2.1.3 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cheggaaa/mb/v2 v2.0.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/fogleman/gg v1.3.0 // indirect github.com/fogleman/gg v1.3.0 // indirect
@ -46,7 +49,6 @@ require (
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/multiformats/go-base32 v0.0.3 // indirect github.com/multiformats/go-base32 v0.0.3 // indirect
github.com/multiformats/go-base36 v0.1.0 // indirect github.com/multiformats/go-base36 v0.1.0 // indirect
github.com/multiformats/go-multiaddr v0.5.0 // indirect github.com/multiformats/go-multiaddr v0.5.0 // indirect
@ -54,7 +56,6 @@ require (
github.com/multiformats/go-varint v0.0.6 // indirect github.com/multiformats/go-varint v0.0.6 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.13.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect
@ -72,7 +73,5 @@ require (
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
golang.org/x/text v0.3.7 // indirect golang.org/x/text v0.3.7 // indirect
google.golang.org/protobuf v1.28.1 // indirect google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
lukechampine.com/blake3 v1.1.6 // indirect lukechampine.com/blake3 v1.1.6 // indirect
) )

11
go.sum
View File

@ -63,8 +63,6 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cheggaaa/mb v1.0.3 h1:03ksWum+6kHclB+kjwKMaBtgl5gtNYUwNpxsHQciKe8=
github.com/cheggaaa/mb v1.0.3/go.mod h1:NUl0GBtFLlfg2o6iZwxzcG7Lslc2wV/ADTFbLXtVPE4=
github.com/cheggaaa/mb/v2 v2.0.1 h1:gn0khbEbKlw3i5VOYi0VnHEHayjZKfUDOyGSpHAybBs= github.com/cheggaaa/mb/v2 v2.0.1 h1:gn0khbEbKlw3i5VOYi0VnHEHayjZKfUDOyGSpHAybBs=
github.com/cheggaaa/mb/v2 v2.0.1/go.mod h1:XGeZw20Iqgjky26KL0mvCwk3+4NyZCUbshSo6ALne+c= github.com/cheggaaa/mb/v2 v2.0.1/go.mod h1:XGeZw20Iqgjky26KL0mvCwk3+4NyZCUbshSo6ALne+c=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
@ -117,6 +115,8 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@ -145,10 +145,10 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@ -435,7 +435,6 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -483,8 +482,6 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc=
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
@ -543,11 +540,11 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=

View File

@ -1,3 +1,4 @@
//go:generate mockgen -destination mock_list/mock_list.go github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list ACLList
package list package list
import ( import (

View File

@ -0,0 +1,222 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list (interfaces: ACLList)
// Package mock_list is a generated GoMock package.
package mock_list
import (
reflect "reflect"
aclrecordproto "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclrecordproto"
list "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list"
gomock "github.com/golang/mock/gomock"
)
// MockACLList is a mock of ACLList interface.
type MockACLList struct {
ctrl *gomock.Controller
recorder *MockACLListMockRecorder
}
// MockACLListMockRecorder is the mock recorder for MockACLList.
type MockACLListMockRecorder struct {
mock *MockACLList
}
// NewMockACLList creates a new mock instance.
func NewMockACLList(ctrl *gomock.Controller) *MockACLList {
mock := &MockACLList{ctrl: ctrl}
mock.recorder = &MockACLListMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockACLList) EXPECT() *MockACLListMockRecorder {
return m.recorder
}
// ACLState mocks base method.
func (m *MockACLList) ACLState() *list.ACLState {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ACLState")
ret0, _ := ret[0].(*list.ACLState)
return ret0
}
// ACLState indicates an expected call of ACLState.
func (mr *MockACLListMockRecorder) ACLState() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ACLState", reflect.TypeOf((*MockACLList)(nil).ACLState))
}
// Close mocks base method.
func (m *MockACLList) Close() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Close")
ret0, _ := ret[0].(error)
return ret0
}
// Close indicates an expected call of Close.
func (mr *MockACLListMockRecorder) Close() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockACLList)(nil).Close))
}
// Get mocks base method.
func (m *MockACLList) Get(arg0 string) (*list.ACLRecord, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Get", arg0)
ret0, _ := ret[0].(*list.ACLRecord)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Get indicates an expected call of Get.
func (mr *MockACLListMockRecorder) Get(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockACLList)(nil).Get), arg0)
}
// Head mocks base method.
func (m *MockACLList) Head() *list.ACLRecord {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Head")
ret0, _ := ret[0].(*list.ACLRecord)
return ret0
}
// Head indicates an expected call of Head.
func (mr *MockACLListMockRecorder) Head() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Head", reflect.TypeOf((*MockACLList)(nil).Head))
}
// ID mocks base method.
func (m *MockACLList) ID() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ID")
ret0, _ := ret[0].(string)
return ret0
}
// ID indicates an expected call of ID.
func (mr *MockACLListMockRecorder) ID() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockACLList)(nil).ID))
}
// IsAfter mocks base method.
func (m *MockACLList) IsAfter(arg0, arg1 string) (bool, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "IsAfter", arg0, arg1)
ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// IsAfter indicates an expected call of IsAfter.
func (mr *MockACLListMockRecorder) IsAfter(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsAfter", reflect.TypeOf((*MockACLList)(nil).IsAfter), arg0, arg1)
}
// Iterate mocks base method.
func (m *MockACLList) Iterate(arg0 func(*list.ACLRecord) bool) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Iterate", arg0)
}
// Iterate indicates an expected call of Iterate.
func (mr *MockACLListMockRecorder) Iterate(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Iterate", reflect.TypeOf((*MockACLList)(nil).Iterate), arg0)
}
// IterateFrom mocks base method.
func (m *MockACLList) IterateFrom(arg0 string, arg1 func(*list.ACLRecord) bool) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "IterateFrom", arg0, arg1)
}
// IterateFrom indicates an expected call of IterateFrom.
func (mr *MockACLListMockRecorder) IterateFrom(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateFrom", reflect.TypeOf((*MockACLList)(nil).IterateFrom), arg0, arg1)
}
// Lock mocks base method.
func (m *MockACLList) Lock() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Lock")
}
// Lock indicates an expected call of Lock.
func (mr *MockACLListMockRecorder) Lock() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Lock", reflect.TypeOf((*MockACLList)(nil).Lock))
}
// RLock mocks base method.
func (m *MockACLList) RLock() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "RLock")
}
// RLock indicates an expected call of RLock.
func (mr *MockACLListMockRecorder) RLock() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RLock", reflect.TypeOf((*MockACLList)(nil).RLock))
}
// RUnlock mocks base method.
func (m *MockACLList) RUnlock() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "RUnlock")
}
// RUnlock indicates an expected call of RUnlock.
func (mr *MockACLListMockRecorder) RUnlock() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RUnlock", reflect.TypeOf((*MockACLList)(nil).RUnlock))
}
// Records mocks base method.
func (m *MockACLList) Records() []*list.ACLRecord {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Records")
ret0, _ := ret[0].([]*list.ACLRecord)
return ret0
}
// Records indicates an expected call of Records.
func (mr *MockACLListMockRecorder) Records() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Records", reflect.TypeOf((*MockACLList)(nil).Records))
}
// Root mocks base method.
func (m *MockACLList) Root() *aclrecordproto.ACLRoot {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Root")
ret0, _ := ret[0].(*aclrecordproto.ACLRoot)
return ret0
}
// Root indicates an expected call of Root.
func (mr *MockACLListMockRecorder) Root() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Root", reflect.TypeOf((*MockACLList)(nil).Root))
}
// Unlock mocks base method.
func (m *MockACLList) Unlock() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Unlock")
}
// Unlock indicates an expected call of Unlock.
func (mr *MockACLListMockRecorder) Unlock() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unlock", reflect.TypeOf((*MockACLList)(nil).Unlock))
}

View File

@ -87,6 +87,11 @@ func NewInMemoryTreeStorage(
}, nil }, nil
} }
func (t *inMemoryTreeStorage) HasChange(ctx context.Context, id string) (bool, error) {
_, exists := t.changes[id]
return exists, nil
}
func (t *inMemoryTreeStorage) ID() (string, error) { func (t *inMemoryTreeStorage) ID() (string, error) {
t.RLock() t.RLock()
defer t.RUnlock() defer t.RUnlock()

View File

@ -1,3 +1,4 @@
//go:generate mockgen -destination mock_storage/mock_storage.go github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage ListStorage,TreeStorage
package storage package storage
import ( import (

View File

@ -0,0 +1,237 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage (interfaces: ListStorage,TreeStorage)
// Package mock_storage is a generated GoMock package.
package mock_storage
import (
context "context"
reflect "reflect"
aclrecordproto "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclrecordproto"
treechangeproto "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto"
gomock "github.com/golang/mock/gomock"
)
// MockListStorage is a mock of ListStorage interface.
type MockListStorage struct {
ctrl *gomock.Controller
recorder *MockListStorageMockRecorder
}
// MockListStorageMockRecorder is the mock recorder for MockListStorage.
type MockListStorageMockRecorder struct {
mock *MockListStorage
}
// NewMockListStorage creates a new mock instance.
func NewMockListStorage(ctrl *gomock.Controller) *MockListStorage {
mock := &MockListStorage{ctrl: ctrl}
mock.recorder = &MockListStorageMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockListStorage) EXPECT() *MockListStorageMockRecorder {
return m.recorder
}
// AddRawRecord mocks base method.
func (m *MockListStorage) AddRawRecord(arg0 context.Context, arg1 *aclrecordproto.RawACLRecordWithId) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddRawRecord", arg0, arg1)
ret0, _ := ret[0].(error)
return ret0
}
// AddRawRecord indicates an expected call of AddRawRecord.
func (mr *MockListStorageMockRecorder) AddRawRecord(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRawRecord", reflect.TypeOf((*MockListStorage)(nil).AddRawRecord), arg0, arg1)
}
// GetRawRecord mocks base method.
func (m *MockListStorage) GetRawRecord(arg0 context.Context, arg1 string) (*aclrecordproto.RawACLRecordWithId, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetRawRecord", arg0, arg1)
ret0, _ := ret[0].(*aclrecordproto.RawACLRecordWithId)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetRawRecord indicates an expected call of GetRawRecord.
func (mr *MockListStorageMockRecorder) GetRawRecord(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRawRecord", reflect.TypeOf((*MockListStorage)(nil).GetRawRecord), arg0, arg1)
}
// Head mocks base method.
func (m *MockListStorage) Head() (*aclrecordproto.RawACLRecordWithId, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Head")
ret0, _ := ret[0].(*aclrecordproto.RawACLRecordWithId)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Head indicates an expected call of Head.
func (mr *MockListStorageMockRecorder) Head() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Head", reflect.TypeOf((*MockListStorage)(nil).Head))
}
// ID mocks base method.
func (m *MockListStorage) ID() (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ID")
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ID indicates an expected call of ID.
func (mr *MockListStorageMockRecorder) ID() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockListStorage)(nil).ID))
}
// Root mocks base method.
func (m *MockListStorage) Root() (*aclrecordproto.RawACLRecordWithId, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Root")
ret0, _ := ret[0].(*aclrecordproto.RawACLRecordWithId)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Root indicates an expected call of Root.
func (mr *MockListStorageMockRecorder) Root() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Root", reflect.TypeOf((*MockListStorage)(nil).Root))
}
// MockTreeStorage is a mock of TreeStorage interface.
type MockTreeStorage struct {
ctrl *gomock.Controller
recorder *MockTreeStorageMockRecorder
}
// MockTreeStorageMockRecorder is the mock recorder for MockTreeStorage.
type MockTreeStorageMockRecorder struct {
mock *MockTreeStorage
}
// NewMockTreeStorage creates a new mock instance.
func NewMockTreeStorage(ctrl *gomock.Controller) *MockTreeStorage {
mock := &MockTreeStorage{ctrl: ctrl}
mock.recorder = &MockTreeStorageMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockTreeStorage) EXPECT() *MockTreeStorageMockRecorder {
return m.recorder
}
// AddRawChange mocks base method.
func (m *MockTreeStorage) AddRawChange(arg0 *treechangeproto.RawTreeChangeWithId) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddRawChange", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// AddRawChange indicates an expected call of AddRawChange.
func (mr *MockTreeStorageMockRecorder) AddRawChange(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRawChange", reflect.TypeOf((*MockTreeStorage)(nil).AddRawChange), arg0)
}
// GetRawChange mocks base method.
func (m *MockTreeStorage) GetRawChange(arg0 context.Context, arg1 string) (*treechangeproto.RawTreeChangeWithId, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetRawChange", arg0, arg1)
ret0, _ := ret[0].(*treechangeproto.RawTreeChangeWithId)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetRawChange indicates an expected call of GetRawChange.
func (mr *MockTreeStorageMockRecorder) GetRawChange(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRawChange", reflect.TypeOf((*MockTreeStorage)(nil).GetRawChange), arg0, arg1)
}
// HasChange mocks base method.
func (m *MockTreeStorage) HasChange(arg0 context.Context, arg1 string) (bool, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "HasChange", arg0, arg1)
ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// HasChange indicates an expected call of HasChange.
func (mr *MockTreeStorageMockRecorder) HasChange(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasChange", reflect.TypeOf((*MockTreeStorage)(nil).HasChange), arg0, arg1)
}
// Heads mocks base method.
func (m *MockTreeStorage) Heads() ([]string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Heads")
ret0, _ := ret[0].([]string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Heads indicates an expected call of Heads.
func (mr *MockTreeStorageMockRecorder) Heads() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Heads", reflect.TypeOf((*MockTreeStorage)(nil).Heads))
}
// ID mocks base method.
func (m *MockTreeStorage) ID() (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ID")
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ID indicates an expected call of ID.
func (mr *MockTreeStorageMockRecorder) ID() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockTreeStorage)(nil).ID))
}
// Root mocks base method.
func (m *MockTreeStorage) Root() (*treechangeproto.RawTreeChangeWithId, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Root")
ret0, _ := ret[0].(*treechangeproto.RawTreeChangeWithId)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Root indicates an expected call of Root.
func (mr *MockTreeStorageMockRecorder) Root() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Root", reflect.TypeOf((*MockTreeStorage)(nil).Root))
}
// SetHeads mocks base method.
func (m *MockTreeStorage) SetHeads(arg0 []string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SetHeads", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// SetHeads indicates an expected call of SetHeads.
func (mr *MockTreeStorageMockRecorder) SetHeads(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetHeads", reflect.TypeOf((*MockTreeStorage)(nil).SetHeads), arg0)
}

View File

@ -13,6 +13,7 @@ type TreeStorage interface {
AddRawChange(change *treechangeproto.RawTreeChangeWithId) error AddRawChange(change *treechangeproto.RawTreeChangeWithId) error
GetRawChange(ctx context.Context, id string) (*treechangeproto.RawTreeChangeWithId, error) GetRawChange(ctx context.Context, id string) (*treechangeproto.RawTreeChangeWithId, error)
HasChange(ctx context.Context, id string) (bool, error)
} }
type TreeStorageCreatorFunc = func(payload TreeStorageCreatePayload) (TreeStorage, error) type TreeStorageCreatorFunc = func(payload TreeStorageCreatePayload) (TreeStorage, error)

View File

@ -0,0 +1,295 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree (interfaces: ObjectTree)
// Package mock_tree is a generated GoMock package.
package mock_tree
import (
context "context"
reflect "reflect"
storage "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage"
tree "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"
treechangeproto "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto"
gomock "github.com/golang/mock/gomock"
)
// MockObjectTree is a mock of ObjectTree interface.
type MockObjectTree struct {
ctrl *gomock.Controller
recorder *MockObjectTreeMockRecorder
}
// MockObjectTreeMockRecorder is the mock recorder for MockObjectTree.
type MockObjectTreeMockRecorder struct {
mock *MockObjectTree
}
// NewMockObjectTree creates a new mock instance.
func NewMockObjectTree(ctrl *gomock.Controller) *MockObjectTree {
mock := &MockObjectTree{ctrl: ctrl}
mock.recorder = &MockObjectTreeMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockObjectTree) EXPECT() *MockObjectTreeMockRecorder {
return m.recorder
}
// AddContent mocks base method.
func (m *MockObjectTree) AddContent(arg0 context.Context, arg1 tree.SignableChangeContent) (tree.AddResult, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddContent", arg0, arg1)
ret0, _ := ret[0].(tree.AddResult)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AddContent indicates an expected call of AddContent.
func (mr *MockObjectTreeMockRecorder) AddContent(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddContent", reflect.TypeOf((*MockObjectTree)(nil).AddContent), arg0, arg1)
}
// AddRawChanges mocks base method.
func (m *MockObjectTree) AddRawChanges(arg0 context.Context, arg1 ...*treechangeproto.RawTreeChangeWithId) (tree.AddResult, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0}
for _, a := range arg1 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "AddRawChanges", varargs...)
ret0, _ := ret[0].(tree.AddResult)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AddRawChanges indicates an expected call of AddRawChanges.
func (mr *MockObjectTreeMockRecorder) AddRawChanges(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0}, arg1...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRawChanges", reflect.TypeOf((*MockObjectTree)(nil).AddRawChanges), varargs...)
}
// ChangesAfterCommonSnapshot mocks base method.
func (m *MockObjectTree) ChangesAfterCommonSnapshot(arg0, arg1 []string) ([]*treechangeproto.RawTreeChangeWithId, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ChangesAfterCommonSnapshot", arg0, arg1)
ret0, _ := ret[0].([]*treechangeproto.RawTreeChangeWithId)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ChangesAfterCommonSnapshot indicates an expected call of ChangesAfterCommonSnapshot.
func (mr *MockObjectTreeMockRecorder) ChangesAfterCommonSnapshot(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangesAfterCommonSnapshot", reflect.TypeOf((*MockObjectTree)(nil).ChangesAfterCommonSnapshot), arg0, arg1)
}
// Close mocks base method.
func (m *MockObjectTree) Close() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Close")
ret0, _ := ret[0].(error)
return ret0
}
// Close indicates an expected call of Close.
func (mr *MockObjectTreeMockRecorder) Close() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockObjectTree)(nil).Close))
}
// DebugDump mocks base method.
func (m *MockObjectTree) DebugDump() (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DebugDump")
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// DebugDump indicates an expected call of DebugDump.
func (mr *MockObjectTreeMockRecorder) DebugDump() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DebugDump", reflect.TypeOf((*MockObjectTree)(nil).DebugDump))
}
// HasChanges mocks base method.
func (m *MockObjectTree) HasChanges(arg0 ...string) bool {
m.ctrl.T.Helper()
varargs := []interface{}{}
for _, a := range arg0 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "HasChanges", varargs...)
ret0, _ := ret[0].(bool)
return ret0
}
// HasChanges indicates an expected call of HasChanges.
func (mr *MockObjectTreeMockRecorder) HasChanges(arg0 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasChanges", reflect.TypeOf((*MockObjectTree)(nil).HasChanges), arg0...)
}
// Header mocks base method.
func (m *MockObjectTree) Header() *treechangeproto.RawTreeChangeWithId {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Header")
ret0, _ := ret[0].(*treechangeproto.RawTreeChangeWithId)
return ret0
}
// Header indicates an expected call of Header.
func (mr *MockObjectTreeMockRecorder) Header() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Header", reflect.TypeOf((*MockObjectTree)(nil).Header))
}
// Heads mocks base method.
func (m *MockObjectTree) Heads() []string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Heads")
ret0, _ := ret[0].([]string)
return ret0
}
// Heads indicates an expected call of Heads.
func (mr *MockObjectTreeMockRecorder) Heads() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Heads", reflect.TypeOf((*MockObjectTree)(nil).Heads))
}
// ID mocks base method.
func (m *MockObjectTree) ID() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ID")
ret0, _ := ret[0].(string)
return ret0
}
// ID indicates an expected call of ID.
func (mr *MockObjectTreeMockRecorder) ID() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockObjectTree)(nil).ID))
}
// Iterate mocks base method.
func (m *MockObjectTree) Iterate(arg0 func([]byte) (interface{}, error), arg1 func(*tree.Change) bool) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Iterate", arg0, arg1)
ret0, _ := ret[0].(error)
return ret0
}
// Iterate indicates an expected call of Iterate.
func (mr *MockObjectTreeMockRecorder) Iterate(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Iterate", reflect.TypeOf((*MockObjectTree)(nil).Iterate), arg0, arg1)
}
// IterateFrom mocks base method.
func (m *MockObjectTree) IterateFrom(arg0 string, arg1 func([]byte) (interface{}, error), arg2 func(*tree.Change) bool) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "IterateFrom", arg0, arg1, arg2)
ret0, _ := ret[0].(error)
return ret0
}
// IterateFrom indicates an expected call of IterateFrom.
func (mr *MockObjectTreeMockRecorder) IterateFrom(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateFrom", reflect.TypeOf((*MockObjectTree)(nil).IterateFrom), arg0, arg1, arg2)
}
// Lock mocks base method.
func (m *MockObjectTree) Lock() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Lock")
}
// Lock indicates an expected call of Lock.
func (mr *MockObjectTreeMockRecorder) Lock() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Lock", reflect.TypeOf((*MockObjectTree)(nil).Lock))
}
// RLock mocks base method.
func (m *MockObjectTree) RLock() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "RLock")
}
// RLock indicates an expected call of RLock.
func (mr *MockObjectTreeMockRecorder) RLock() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RLock", reflect.TypeOf((*MockObjectTree)(nil).RLock))
}
// RUnlock mocks base method.
func (m *MockObjectTree) RUnlock() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "RUnlock")
}
// RUnlock indicates an expected call of RUnlock.
func (mr *MockObjectTreeMockRecorder) RUnlock() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RUnlock", reflect.TypeOf((*MockObjectTree)(nil).RUnlock))
}
// Root mocks base method.
func (m *MockObjectTree) Root() *tree.Change {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Root")
ret0, _ := ret[0].(*tree.Change)
return ret0
}
// Root indicates an expected call of Root.
func (mr *MockObjectTreeMockRecorder) Root() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Root", reflect.TypeOf((*MockObjectTree)(nil).Root))
}
// SnapshotPath mocks base method.
func (m *MockObjectTree) SnapshotPath() []string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SnapshotPath")
ret0, _ := ret[0].([]string)
return ret0
}
// SnapshotPath indicates an expected call of SnapshotPath.
func (mr *MockObjectTreeMockRecorder) SnapshotPath() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SnapshotPath", reflect.TypeOf((*MockObjectTree)(nil).SnapshotPath))
}
// Storage mocks base method.
func (m *MockObjectTree) Storage() storage.TreeStorage {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Storage")
ret0, _ := ret[0].(storage.TreeStorage)
return ret0
}
// Storage indicates an expected call of Storage.
func (mr *MockObjectTreeMockRecorder) Storage() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Storage", reflect.TypeOf((*MockObjectTree)(nil).Storage))
}
// Unlock mocks base method.
func (m *MockObjectTree) Unlock() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Unlock")
}
// Unlock indicates an expected call of Unlock.
func (mr *MockObjectTreeMockRecorder) Unlock() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unlock", reflect.TypeOf((*MockObjectTree)(nil).Unlock))
}

View File

@ -1,3 +1,4 @@
//go:generate mockgen -destination mock_objecttree/mock_objecttree.go github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree ObjectTree
package tree package tree
import ( import (
@ -42,7 +43,7 @@ type ObjectTree interface {
Header() *treechangeproto.RawTreeChangeWithId Header() *treechangeproto.RawTreeChangeWithId
Heads() []string Heads() []string
Root() *Change Root() *Change
HasChange(string) bool HasChanges(...string) bool
DebugDump() (string, error) DebugDump() (string, error)
Iterate(convert ChangeConvertFunc, iterate ChangeIterateFunc) error Iterate(convert ChangeConvertFunc, iterate ChangeIterateFunc) error
@ -75,7 +76,7 @@ type objectTree struct {
// buffers // buffers
difSnapshotBuf []*treechangeproto.RawTreeChangeWithId difSnapshotBuf []*treechangeproto.RawTreeChangeWithId
tmpChangesBuf []*Change newChangesBuf []*Change
newSnapshotsBuf []*Change newSnapshotsBuf []*Change
notSeenIdxBuf []int notSeenIdxBuf []int
@ -226,7 +227,7 @@ func (ot *objectTree) AddRawChanges(ctx context.Context, rawChanges ...*treechan
func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*treechangeproto.RawTreeChangeWithId) (addResult AddResult, err error) { func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*treechangeproto.RawTreeChangeWithId) (addResult AddResult, err error) {
// resetting buffers // resetting buffers
ot.tmpChangesBuf = ot.tmpChangesBuf[:0] ot.newChangesBuf = ot.newChangesBuf[:0]
ot.notSeenIdxBuf = ot.notSeenIdxBuf[:0] ot.notSeenIdxBuf = ot.notSeenIdxBuf[:0]
ot.difSnapshotBuf = ot.difSnapshotBuf[:0] ot.difSnapshotBuf = ot.difSnapshotBuf[:0]
ot.newSnapshotsBuf = ot.newSnapshotsBuf[:0] ot.newSnapshotsBuf = ot.newSnapshotsBuf[:0]
@ -246,20 +247,21 @@ func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*treechan
if _, exists := ot.tree.attached[ch.Id]; exists { if _, exists := ot.tree.attached[ch.Id]; exists {
continue continue
} }
if _, exists := ot.tree.unAttached[ch.Id]; exists {
continue
}
var change *Change var change *Change
change, err = ot.changeBuilder.ConvertFromRaw(ch, true) if unAttached, exists := ot.tree.unAttached[ch.Id]; exists {
if err != nil { change = unAttached
return } else {
change, err = ot.changeBuilder.ConvertFromRaw(ch, true)
if err != nil {
return
}
} }
if change.IsSnapshot { if change.IsSnapshot {
ot.newSnapshotsBuf = append(ot.newSnapshotsBuf, change) ot.newSnapshotsBuf = append(ot.newSnapshotsBuf, change)
} }
ot.tmpChangesBuf = append(ot.tmpChangesBuf, change) ot.newChangesBuf = append(ot.newChangesBuf, change)
ot.notSeenIdxBuf = append(ot.notSeenIdxBuf, idx) ot.notSeenIdxBuf = append(ot.notSeenIdxBuf, idx)
} }
@ -273,6 +275,106 @@ func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*treechan
return return
} }
rollback := func(changes []*Change) {
for _, ch := range changes {
if _, exists := ot.tree.attached[ch.Id]; exists {
delete(ot.tree.attached, ch.Id)
}
}
}
// checks if we need to go to database
isOldSnapshot := func(ch *Change) bool {
if ch.SnapshotId == ot.tree.RootId() {
return false
}
for _, sn := range ot.newSnapshotsBuf {
// if change refers to newly received snapshot
if ch.SnapshotId == sn.Id {
return false
}
}
return true
}
shouldRebuildFromStorage := false
// checking if we have some changes with different snapshot and then rebuilding
for idx, ch := range ot.newChangesBuf {
if isOldSnapshot(ch) {
var exists bool
// checking if it exists in the storage, if yes, then at some point it was added to the tree
// thus we don't need to look at this change
exists, err = ot.treeStorage.HasChange(ctx, ch.Id)
if err != nil {
return
}
if exists {
// marking as nil to delete after
ot.newChangesBuf[idx] = nil
continue
}
// we haven't seen the change, and it refers to old snapshot, so we should rebuild
shouldRebuildFromStorage = true
}
}
// discarding all previously seen changes
ot.newChangesBuf = discardFromSlice(ot.newChangesBuf, func(ch *Change) bool { return ch == nil })
if shouldRebuildFromStorage {
err = ot.rebuildFromStorage(ot.newChangesBuf)
if err != nil {
// rebuilding without new changes
ot.rebuildFromStorage(nil)
return
}
addResult, err = ot.createAddResult(prevHeadsCopy, Rebuild, nil, rawChanges)
if err != nil {
// that means that some unattached changes were somehow corrupted in memory
// this shouldn't happen but if that happens, then rebuilding from storage
ot.rebuildFromStorage(nil)
return
}
return
}
// normal mode of operation, where we don't need to rebuild from database
mode, treeChangesAdded := ot.tree.Add(ot.newChangesBuf...)
switch mode {
case Nothing:
addResult = AddResult{
OldHeads: prevHeadsCopy,
Heads: prevHeadsCopy,
Mode: mode,
}
return
default:
// we need to validate only newly added changes
err = ot.validateTree(treeChangesAdded)
if err != nil {
rollback(treeChangesAdded)
err = ErrHasInvalidChanges
return
}
addResult, err = ot.createAddResult(prevHeadsCopy, mode, treeChangesAdded, rawChanges)
if err != nil {
// that means that some unattached changes were somehow corrupted in memory
// this shouldn't happen but if that happens, then rebuilding from storage
ot.rebuildFromStorage(nil)
return
}
return
}
return
}
func (ot *objectTree) createAddResult(oldHeads []string, mode Mode, treeChangesAdded []*Change, rawChanges []*treechangeproto.RawTreeChangeWithId) (addResult AddResult, err error) {
headsCopy := func() []string {
newHeads := make([]string, 0, len(ot.tree.Heads()))
newHeads = append(newHeads, ot.tree.Heads()...)
return newHeads
}
// returns changes that we added to the tree as attached this round // returns changes that we added to the tree as attached this round
// they can include not only the changes that were added now, // they can include not only the changes that were added now,
// but also the changes that were previously in the tree // but also the changes that were previously in the tree
@ -312,88 +414,16 @@ func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*treechan
return return
} }
rollback := func(changes []*Change) { var added []*treechangeproto.RawTreeChangeWithId
for _, ch := range changes { added, err = getAddedChanges(treeChangesAdded)
if _, exists := ot.tree.attached[ch.Id]; exists { if err != nil {
delete(ot.tree.attached, ch.Id)
}
}
}
// checks if we need to go to database
isOldSnapshot := func(ch *Change) bool {
if ch.SnapshotId == ot.tree.RootId() {
return false
}
for _, sn := range ot.newSnapshotsBuf {
// if change refers to newly received snapshot
if ch.SnapshotId == sn.Id {
return false
}
}
return true
}
// checking if we have some changes with different snapshot and then rebuilding
for _, ch := range ot.tmpChangesBuf {
if isOldSnapshot(ch) {
err = ot.rebuildFromStorage(ot.tmpChangesBuf)
if err != nil {
// rebuilding without new changes
ot.rebuildFromStorage(nil)
return
}
var added []*treechangeproto.RawTreeChangeWithId
added, err = getAddedChanges(nil)
// we shouldn't get any error in this case
if err != nil {
panic(err)
}
addResult = AddResult{
OldHeads: prevHeadsCopy,
Heads: headsCopy(),
Added: added,
Mode: Rebuild,
}
return
}
}
// normal mode of operation, where we don't need to rebuild from database
mode, treeChangesAdded := ot.tree.Add(ot.tmpChangesBuf...)
switch mode {
case Nothing:
addResult = AddResult{
OldHeads: prevHeadsCopy,
Heads: prevHeadsCopy,
Mode: mode,
}
return return
}
default: addResult = AddResult{
// we need to validate only newly added changes OldHeads: oldHeads,
err = ot.validateTree(treeChangesAdded) Heads: headsCopy(),
if err != nil { Added: added,
rollback(treeChangesAdded) Mode: mode,
err = ErrHasInvalidChanges
return
}
var added []*treechangeproto.RawTreeChangeWithId
added, err = getAddedChanges(treeChangesAdded)
if err != nil {
// that means that some unattached changes were somehow corrupted in memory
// this shouldn't happen but if that happens, then rebuilding from storage
ot.rebuildFromStorage(nil)
return
}
addResult = AddResult{
OldHeads: prevHeadsCopy,
Heads: headsCopy(),
Added: added,
Mode: mode,
}
} }
return return
} }
@ -440,9 +470,28 @@ func (ot *objectTree) IterateFrom(id string, convert ChangeConvertFunc, iterate
return return
} }
func (ot *objectTree) HasChange(s string) bool { func (ot *objectTree) HasChanges(chs ...string) bool {
_, attachedExists := ot.tree.attached[s] hasChange := func(s string) bool {
return attachedExists _, attachedExists := ot.tree.attached[s]
if attachedExists {
return attachedExists
}
has, err := ot.treeStorage.HasChange(context.Background(), s)
if err != nil {
return false
}
return has
}
for _, ch := range chs {
if !hasChange(ch) {
return false
}
}
return true
} }
func (ot *objectTree) Heads() []string { func (ot *objectTree) Heads() []string {

View File

@ -104,7 +104,7 @@ func buildObjectTree(deps objectTreeDeps) (ObjectTree, error) {
rawChangeLoader: deps.rawChangeLoader, rawChangeLoader: deps.rawChangeLoader,
tree: nil, tree: nil,
keys: make(map[uint64]*symmetric.Key), keys: make(map[uint64]*symmetric.Key),
tmpChangesBuf: make([]*Change, 0, 10), newChangesBuf: make([]*Change, 0, 10),
difSnapshotBuf: make([]*treechangeproto.RawTreeChangeWithId, 0, 10), difSnapshotBuf: make([]*treechangeproto.RawTreeChangeWithId, 0, 10),
notSeenIdxBuf: make([]int, 0, 10), notSeenIdxBuf: make([]int, 0, 10),
newSnapshotsBuf: make([]*Change, 0, 10), newSnapshotsBuf: make([]*Change, 0, 10),

View File

@ -1,3 +1,4 @@
//go:generate mockgen -destination mock_ldiff/mock_ldiff.go github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff Diff,Remote
// Package ldiff provides a container of elements with fixed id and changeable content. // Package ldiff provides a container of elements with fixed id and changeable content.
// Diff can calculate the difference with another diff container (you can make it remote) with minimum hops and traffic. // Diff can calculate the difference with another diff container (you can make it remote) with minimum hops and traffic.
package ldiff package ldiff

View File

@ -0,0 +1,136 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff (interfaces: Diff,Remote)
// Package mock_ldiff is a generated GoMock package.
package mock_ldiff
import (
context "context"
reflect "reflect"
ldiff "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff"
gomock "github.com/golang/mock/gomock"
)
// MockDiff is a mock of Diff interface.
type MockDiff struct {
ctrl *gomock.Controller
recorder *MockDiffMockRecorder
}
// MockDiffMockRecorder is the mock recorder for MockDiff.
type MockDiffMockRecorder struct {
mock *MockDiff
}
// NewMockDiff creates a new mock instance.
func NewMockDiff(ctrl *gomock.Controller) *MockDiff {
mock := &MockDiff{ctrl: ctrl}
mock.recorder = &MockDiffMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockDiff) EXPECT() *MockDiffMockRecorder {
return m.recorder
}
// Diff mocks base method.
func (m *MockDiff) Diff(arg0 context.Context, arg1 ldiff.Remote) ([]string, []string, []string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Diff", arg0, arg1)
ret0, _ := ret[0].([]string)
ret1, _ := ret[1].([]string)
ret2, _ := ret[2].([]string)
ret3, _ := ret[3].(error)
return ret0, ret1, ret2, ret3
}
// Diff indicates an expected call of Diff.
func (mr *MockDiffMockRecorder) Diff(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Diff", reflect.TypeOf((*MockDiff)(nil).Diff), arg0, arg1)
}
// Ranges mocks base method.
func (m *MockDiff) Ranges(arg0 context.Context, arg1 []ldiff.Range, arg2 []ldiff.RangeResult) ([]ldiff.RangeResult, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Ranges", arg0, arg1, arg2)
ret0, _ := ret[0].([]ldiff.RangeResult)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Ranges indicates an expected call of Ranges.
func (mr *MockDiffMockRecorder) Ranges(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ranges", reflect.TypeOf((*MockDiff)(nil).Ranges), arg0, arg1, arg2)
}
// RemoveId mocks base method.
func (m *MockDiff) RemoveId(arg0 string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RemoveId", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// RemoveId indicates an expected call of RemoveId.
func (mr *MockDiffMockRecorder) RemoveId(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveId", reflect.TypeOf((*MockDiff)(nil).RemoveId), arg0)
}
// Set mocks base method.
func (m *MockDiff) Set(arg0 ...ldiff.Element) {
m.ctrl.T.Helper()
varargs := []interface{}{}
for _, a := range arg0 {
varargs = append(varargs, a)
}
m.ctrl.Call(m, "Set", varargs...)
}
// Set indicates an expected call of Set.
func (mr *MockDiffMockRecorder) Set(arg0 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockDiff)(nil).Set), arg0...)
}
// MockRemote is a mock of Remote interface.
type MockRemote struct {
ctrl *gomock.Controller
recorder *MockRemoteMockRecorder
}
// MockRemoteMockRecorder is the mock recorder for MockRemote.
type MockRemoteMockRecorder struct {
mock *MockRemote
}
// NewMockRemote creates a new mock instance.
func NewMockRemote(ctrl *gomock.Controller) *MockRemote {
mock := &MockRemote{ctrl: ctrl}
mock.recorder = &MockRemoteMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockRemote) EXPECT() *MockRemoteMockRecorder {
return m.recorder
}
// Ranges mocks base method.
func (m *MockRemote) Ranges(arg0 context.Context, arg1 []ldiff.Range, arg2 []ldiff.RangeResult) ([]ldiff.RangeResult, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Ranges", arg0, arg1, arg2)
ret0, _ := ret[0].([]ldiff.RangeResult)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Ranges indicates an expected call of Ranges.
func (mr *MockRemoteMockRecorder) Ranges(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ranges", reflect.TypeOf((*MockRemote)(nil).Ranges), arg0, arg1, arg2)
}