Fix bug with head update not being sent on first receive

This commit is contained in:
mcrakhman 2022-10-20 18:56:09 +02:00 committed by Mikhail Iudin
parent 1af3f1b290
commit f213ec7efe
No known key found for this signature in database
GPG Key ID: FAAAA8BAABDFF1C0
4 changed files with 28 additions and 26 deletions

View File

@ -13,8 +13,8 @@ import (
"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/common/commonspace/treegetter" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list"
storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage" aclstorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
tree2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree" tree "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/encryptionkey" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/encryptionkey"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/signingkey" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/signingkey"
"sync" "sync"
@ -54,9 +54,9 @@ type Space interface {
SpaceSyncRpc() RpcHandler SpaceSyncRpc() RpcHandler
DeriveTree(ctx context.Context, payload tree2.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree2.ObjectTree, error) DeriveTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree.ObjectTree, error)
CreateTree(ctx context.Context, payload tree2.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree2.ObjectTree, error) CreateTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree.ObjectTree, error)
BuildTree(ctx context.Context, id string, listener updatelistener.UpdateListener) (tree2.ObjectTree, error) BuildTree(ctx context.Context, id string, listener updatelistener.UpdateListener) (tree.ObjectTree, error)
Close() error Close() error
} }
@ -120,7 +120,7 @@ func (s *space) StoredIds() []string {
return s.diffService.AllIds() return s.diffService.AllIds()
} }
func (s *space) DeriveTree(ctx context.Context, payload tree2.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tr tree2.ObjectTree, err error) { func (s *space) DeriveTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tr tree.ObjectTree, err error) {
if s.isClosed.Load() { if s.isClosed.Load() {
err = ErrSpaceClosed err = ErrSpaceClosed
return return
@ -128,7 +128,7 @@ func (s *space) DeriveTree(ctx context.Context, payload tree2.ObjectTreeCreatePa
return synctree.DeriveSyncTree(ctx, payload, s.syncService.SyncClient(), 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 tree2.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tr tree2.ObjectTree, err error) { func (s *space) CreateTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tr tree.ObjectTree, err error) {
if s.isClosed.Load() { if s.isClosed.Load() {
err = ErrSpaceClosed err = ErrSpaceClosed
return return
@ -136,7 +136,7 @@ func (s *space) CreateTree(ctx context.Context, payload tree2.ObjectTreeCreatePa
return synctree.CreateSyncTree(ctx, payload, s.syncService.SyncClient(), 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 tree2.ObjectTree, err error) { func (s *space) BuildTree(ctx context.Context, id string, listener updatelistener.UpdateListener) (t tree.ObjectTree, err error) {
if s.isClosed.Load() { if s.isClosed.Load() {
err = ErrSpaceClosed err = ErrSpaceClosed
return return
@ -154,11 +154,13 @@ func (s *space) BuildTree(ctx context.Context, id string, listener updatelistene
} }
store, err := s.storage.TreeStorage(id) store, err := s.storage.TreeStorage(id)
if err != nil && err != storage2.ErrUnknownTreeId { if err != nil && err != aclstorage.ErrUnknownTreeId {
return return
} }
if err == storage2.ErrUnknownTreeId { isFirstBuild := false
if err == aclstorage.ErrUnknownTreeId {
isFirstBuild = true
var resp *spacesyncproto.ObjectSyncMessage var resp *spacesyncproto.ObjectSyncMessage
resp, err = getTreeRemote() resp, err = getTreeRemote()
if err != nil { if err != nil {
@ -166,7 +168,7 @@ func (s *space) BuildTree(ctx context.Context, id string, listener updatelistene
} }
fullSyncResp := resp.GetContent().GetFullSyncResponse() fullSyncResp := resp.GetContent().GetFullSyncResponse()
payload := storage2.TreeStorageCreatePayload{ payload := aclstorage.TreeStorageCreatePayload{
TreeId: resp.TreeId, TreeId: resp.TreeId,
RootRawChange: resp.RootChange, RootRawChange: resp.RootChange,
Changes: fullSyncResp.Changes, Changes: fullSyncResp.Changes,
@ -174,7 +176,7 @@ func (s *space) BuildTree(ctx context.Context, id string, listener updatelistene
} }
// basically building tree with inmemory storage and validating that it was without errors // basically building tree with inmemory storage and validating that it was without errors
err = tree2.ValidateRawTree(payload, s.aclList) err = tree.ValidateRawTree(payload, s.aclList)
if err != nil { if err != nil {
return return
} }
@ -184,7 +186,7 @@ func (s *space) BuildTree(ctx context.Context, id string, listener updatelistene
return return
} }
} }
return synctree.BuildSyncTree(ctx, s.syncService.SyncClient(), store.(storage2.TreeStorage), listener, s.aclList) return synctree.BuildSyncTree(ctx, s.syncService.SyncClient(), store.(aclstorage.TreeStorage), listener, s.aclList, isFirstBuild)
} }
func (s *space) Close() error { func (s *space) Close() error {

View File

@ -15,14 +15,6 @@ import (
"testing" "testing"
) )
type treeContainer struct {
objTree tree.ObjectTree
}
func (t treeContainer) Tree() tree.ObjectTree {
return t.objTree
}
type testObjTreeMock struct { type testObjTreeMock struct {
*mock_tree.MockObjectTree *mock_tree.MockObjectTree
m sync.Mutex m sync.Mutex

View File

@ -77,8 +77,9 @@ func BuildSyncTree(
syncClient syncservice.SyncClient, syncClient syncservice.SyncClient,
treeStorage storage.TreeStorage, treeStorage storage.TreeStorage,
listener updatelistener.UpdateListener, listener updatelistener.UpdateListener,
aclList list.ACLList) (t tree2.ObjectTree, err error) { aclList list.ACLList,
return buildSyncTree(ctx, syncClient, treeStorage, listener, aclList) isFirstBuild bool) (t tree2.ObjectTree, err error) {
return buildSyncTree(ctx, syncClient, treeStorage, listener, aclList, isFirstBuild)
} }
func buildSyncTree( func buildSyncTree(
@ -86,7 +87,8 @@ func buildSyncTree(
syncClient syncservice.SyncClient, syncClient syncservice.SyncClient,
treeStorage storage.TreeStorage, treeStorage storage.TreeStorage,
listener updatelistener.UpdateListener, listener updatelistener.UpdateListener,
aclList list.ACLList) (t tree2.ObjectTree, err error) { aclList list.ACLList,
isFirstBuild bool) (t tree2.ObjectTree, err error) {
t, err = buildObjectTree(treeStorage, aclList) t, err = buildObjectTree(treeStorage, aclList)
if err != nil { if err != nil {
return return
@ -99,7 +101,13 @@ func buildSyncTree(
headUpdate := syncClient.CreateHeadUpdate(t, nil) headUpdate := syncClient.CreateHeadUpdate(t, nil)
// here we will have different behaviour based on who is sending this update // here we will have different behaviour based on who is sending this update
err = syncClient.BroadcastAsyncOrSendResponsible(headUpdate) if isFirstBuild {
// send to everybody, because everybody should know that the node or client got new tree
err = syncClient.BroadcastAsync(headUpdate)
} else {
// send either to everybody if client or to replica set if node
err = syncClient.BroadcastAsyncOrSendResponsible(headUpdate)
}
return return
} }

View File

@ -104,7 +104,7 @@ func Test_BuildSyncTree(t *testing.T) {
syncClientMock.EXPECT().CreateHeadUpdate(syncTreeMatcher{objTreeMock, syncClientMock, updateListenerMock}, gomock.Nil()).Return(headUpdate) syncClientMock.EXPECT().CreateHeadUpdate(syncTreeMatcher{objTreeMock, syncClientMock, updateListenerMock}, gomock.Nil()).Return(headUpdate)
syncClientMock.EXPECT().BroadcastAsyncOrSendResponsible(gomock.Eq(headUpdate)).Return(nil) syncClientMock.EXPECT().BroadcastAsyncOrSendResponsible(gomock.Eq(headUpdate)).Return(nil)
tr, err := BuildSyncTree(ctx, syncClientMock, storageMock, updateListenerMock, aclListMock) tr, err := BuildSyncTree(ctx, syncClientMock, storageMock, updateListenerMock, aclListMock, false)
require.NoError(t, err) require.NoError(t, err)
t.Run("AddRawChanges update", func(t *testing.T) { t.Run("AddRawChanges update", func(t *testing.T) {