Fix settings state rebuild
This commit is contained in:
parent
6e48b2dcff
commit
5532c2c482
@ -47,10 +47,7 @@ type deletionManager struct {
|
|||||||
|
|
||||||
func (d *deletionManager) UpdateState(ctx context.Context, state *settingsstate.State) error {
|
func (d *deletionManager) UpdateState(ctx context.Context, state *settingsstate.State) error {
|
||||||
log := log.With(zap.String("spaceId", d.spaceId))
|
log := log.With(zap.String("spaceId", d.spaceId))
|
||||||
err := d.deletionState.Add(state.DeletedIds)
|
d.deletionState.Add(state.DeletedIds)
|
||||||
if err != nil {
|
|
||||||
log.Debug("failed to add deleted ids to deletion state")
|
|
||||||
}
|
|
||||||
if state.DeleterId == "" {
|
if state.DeleterId == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -59,10 +56,7 @@ func (d *deletionManager) UpdateState(ctx context.Context, state *settingsstate.
|
|||||||
allIds := slice.DiscardFromSlice(d.provider.AllIds(), func(id string) bool {
|
allIds := slice.DiscardFromSlice(d.provider.AllIds(), func(id string) bool {
|
||||||
return id == d.settingsId
|
return id == d.settingsId
|
||||||
})
|
})
|
||||||
err := d.deletionState.Add(allIds)
|
d.deletionState.Add(allIds)
|
||||||
if err != nil {
|
|
||||||
log.Debug("failed to add all ids to deletion state")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
d.onSpaceDelete()
|
d.onSpaceDelete()
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -29,7 +29,7 @@ func TestDeletionManager_UpdateState_NotResponsible(t *testing.T) {
|
|||||||
delState := mock_settingsstate.NewMockObjectDeletionState(ctrl)
|
delState := mock_settingsstate.NewMockObjectDeletionState(ctrl)
|
||||||
treeManager := mock_treemanager.NewMockTreeManager(ctrl)
|
treeManager := mock_treemanager.NewMockTreeManager(ctrl)
|
||||||
|
|
||||||
delState.EXPECT().Add(state.DeletedIds).Return(nil)
|
delState.EXPECT().Add(state.DeletedIds)
|
||||||
|
|
||||||
delManager := newDeletionManager(spaceId,
|
delManager := newDeletionManager(spaceId,
|
||||||
settingsId,
|
settingsId,
|
||||||
@ -62,9 +62,9 @@ func TestDeletionManager_UpdateState_Responsible(t *testing.T) {
|
|||||||
treeManager := mock_treemanager.NewMockTreeManager(ctrl)
|
treeManager := mock_treemanager.NewMockTreeManager(ctrl)
|
||||||
provider := mock_settings.NewMockSpaceIdsProvider(ctrl)
|
provider := mock_settings.NewMockSpaceIdsProvider(ctrl)
|
||||||
|
|
||||||
delState.EXPECT().Add(state.DeletedIds).Return(nil)
|
delState.EXPECT().Add(state.DeletedIds)
|
||||||
provider.EXPECT().AllIds().Return([]string{"id", "otherId", settingsId})
|
provider.EXPECT().AllIds().Return([]string{"id", "otherId", settingsId})
|
||||||
delState.EXPECT().Add([]string{"id", "otherId"}).Return(nil)
|
delState.EXPECT().Add([]string{"id", "otherId"})
|
||||||
delManager := newDeletionManager(spaceId,
|
delManager := newDeletionManager(spaceId,
|
||||||
settingsId,
|
settingsId,
|
||||||
true,
|
true,
|
||||||
|
|||||||
@ -40,7 +40,16 @@ var (
|
|||||||
ErrCantDeleteSpace = errors.New("not able to delete space")
|
ErrCantDeleteSpace = errors.New("not able to delete space")
|
||||||
)
|
)
|
||||||
|
|
||||||
var doSnapshot = objecttree.DoSnapshot
|
var (
|
||||||
|
doSnapshot = objecttree.DoSnapshot
|
||||||
|
buildHistoryTree = func(objTree objecttree.ObjectTree) (objecttree.ReadableObjectTree, error) {
|
||||||
|
return objecttree.BuildHistoryTree(objecttree.HistoryTreeParams{
|
||||||
|
TreeStorage: objTree.Storage(),
|
||||||
|
AclList: objTree.AclList(),
|
||||||
|
BuildFullTree: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
type BuildTreeFunc func(ctx context.Context, id string, listener updatelistener.UpdateListener) (t synctree.SyncTree, err error)
|
type BuildTreeFunc func(ctx context.Context, id string, listener updatelistener.UpdateListener) (t synctree.SyncTree, err error)
|
||||||
|
|
||||||
@ -166,11 +175,36 @@ func (s *settingsObject) Init(ctx context.Context) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// TODO: remove this check when everybody updates
|
||||||
|
if err = s.checkHistoryState(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
s.loop.Run()
|
s.loop.Run()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *settingsObject) checkHistoryState(ctx context.Context) (err error) {
|
||||||
|
historyTree, err := buildHistoryTree(s.SyncTree)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fullState, err := s.builder.Build(historyTree, nil)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(fullState.DeletedIds) != len(s.state.DeletedIds) {
|
||||||
|
log.WarnCtx(ctx, "state does not have all deleted ids",
|
||||||
|
zap.Int("fullstate ids", len(fullState.DeletedIds)),
|
||||||
|
zap.Int("state ids", len(fullState.DeletedIds)))
|
||||||
|
s.state = fullState
|
||||||
|
err = s.deletionManager.UpdateState(context.Background(), s.state)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (s *settingsObject) Close() error {
|
func (s *settingsObject) Close() error {
|
||||||
s.loop.Close()
|
s.loop.Close()
|
||||||
return s.SyncTree.Close()
|
return s.SyncTree.Close()
|
||||||
@ -221,7 +255,7 @@ func (s *settingsObject) DeleteObject(id string) (err error) {
|
|||||||
err = ErrDeleteSelf
|
err = ErrDeleteSelf
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if s.deletionState.Exists(id) {
|
if s.state.Exists(id) {
|
||||||
err = ErrAlreadyDeleted
|
err = ErrAlreadyDeleted
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -249,7 +283,7 @@ func (s *settingsObject) verifyDeleteSpace(raw *treechangeproto.RawTreeChangeWit
|
|||||||
|
|
||||||
func (s *settingsObject) addContent(data []byte, isSnapshot bool) (err error) {
|
func (s *settingsObject) addContent(data []byte, isSnapshot bool) (err error) {
|
||||||
accountData := s.account.Account()
|
accountData := s.account.Account()
|
||||||
_, err = s.AddContent(context.Background(), objecttree.SignableChangeContent{
|
res, err := s.AddContent(context.Background(), objecttree.SignableChangeContent{
|
||||||
Data: data,
|
Data: data,
|
||||||
Key: accountData.SignKey,
|
Key: accountData.SignKey,
|
||||||
IsSnapshot: isSnapshot,
|
IsSnapshot: isSnapshot,
|
||||||
@ -258,8 +292,11 @@ func (s *settingsObject) addContent(data []byte, isSnapshot bool) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if res.Mode == objecttree.Rebuild {
|
||||||
s.Update(s)
|
s.Rebuild(s)
|
||||||
|
} else {
|
||||||
|
s.Update(s)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/anytypeio/any-sync/accountservice/mock_accountservice"
|
"github.com/anytypeio/any-sync/accountservice/mock_accountservice"
|
||||||
"github.com/anytypeio/any-sync/commonspace/object/accountdata"
|
"github.com/anytypeio/any-sync/commonspace/object/accountdata"
|
||||||
"github.com/anytypeio/any-sync/commonspace/object/tree/objecttree"
|
"github.com/anytypeio/any-sync/commonspace/object/tree/objecttree"
|
||||||
|
"github.com/anytypeio/any-sync/commonspace/object/tree/objecttree/mock_objecttree"
|
||||||
"github.com/anytypeio/any-sync/commonspace/object/tree/synctree"
|
"github.com/anytypeio/any-sync/commonspace/object/tree/synctree"
|
||||||
"github.com/anytypeio/any-sync/commonspace/object/tree/synctree/mock_synctree"
|
"github.com/anytypeio/any-sync/commonspace/object/tree/synctree/mock_synctree"
|
||||||
"github.com/anytypeio/any-sync/commonspace/object/tree/synctree/updatelistener"
|
"github.com/anytypeio/any-sync/commonspace/object/tree/synctree/updatelistener"
|
||||||
@ -52,6 +53,7 @@ type settingsFixture struct {
|
|||||||
changeFactory *mock_settingsstate.MockChangeFactory
|
changeFactory *mock_settingsstate.MockChangeFactory
|
||||||
deleter *mock_settings.MockDeleter
|
deleter *mock_settings.MockDeleter
|
||||||
syncTree *mock_synctree.MockSyncTree
|
syncTree *mock_synctree.MockSyncTree
|
||||||
|
historyTree *mock_objecttree.MockObjectTree
|
||||||
delState *mock_settingsstate.MockObjectDeletionState
|
delState *mock_settingsstate.MockObjectDeletionState
|
||||||
account *mock_accountservice.MockService
|
account *mock_accountservice.MockService
|
||||||
}
|
}
|
||||||
@ -69,6 +71,7 @@ func newSettingsFixture(t *testing.T) *settingsFixture {
|
|||||||
stateBuilder := mock_settingsstate.NewMockStateBuilder(ctrl)
|
stateBuilder := mock_settingsstate.NewMockStateBuilder(ctrl)
|
||||||
changeFactory := mock_settingsstate.NewMockChangeFactory(ctrl)
|
changeFactory := mock_settingsstate.NewMockChangeFactory(ctrl)
|
||||||
syncTree := mock_synctree.NewMockSyncTree(ctrl)
|
syncTree := mock_synctree.NewMockSyncTree(ctrl)
|
||||||
|
historyTree := mock_objecttree.NewMockObjectTree(ctrl)
|
||||||
del := mock_settings.NewMockDeleter(ctrl)
|
del := mock_settings.NewMockDeleter(ctrl)
|
||||||
|
|
||||||
delState.EXPECT().AddObserver(gomock.Any())
|
delState.EXPECT().AddObserver(gomock.Any())
|
||||||
@ -77,6 +80,9 @@ func newSettingsFixture(t *testing.T) *settingsFixture {
|
|||||||
require.Equal(t, objectId, id)
|
require.Equal(t, objectId, id)
|
||||||
return newTestObjMock(syncTree), nil
|
return newTestObjMock(syncTree), nil
|
||||||
})
|
})
|
||||||
|
buildHistoryTree = func(objTree objecttree.ObjectTree) (objecttree.ReadableObjectTree, error) {
|
||||||
|
return historyTree, nil
|
||||||
|
}
|
||||||
|
|
||||||
deps := Deps{
|
deps := Deps{
|
||||||
BuildFunc: buildFunc,
|
BuildFunc: buildFunc,
|
||||||
@ -104,36 +110,40 @@ func newSettingsFixture(t *testing.T) *settingsFixture {
|
|||||||
syncTree: syncTree,
|
syncTree: syncTree,
|
||||||
account: acc,
|
account: acc,
|
||||||
delState: delState,
|
delState: delState,
|
||||||
|
historyTree: historyTree,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fx *settingsFixture) stop() {
|
func (fx *settingsFixture) init(t *testing.T) {
|
||||||
|
fx.spaceStorage.EXPECT().SpaceSettingsId().Return(fx.docId)
|
||||||
|
fx.deleter.EXPECT().Delete()
|
||||||
|
fx.stateBuilder.EXPECT().Build(fx.historyTree, nil).Return(&settingsstate.State{}, nil)
|
||||||
|
fx.doc.state = &settingsstate.State{}
|
||||||
|
|
||||||
|
err := fx.doc.Init(context.Background())
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fx *settingsFixture) stop(t *testing.T) {
|
||||||
|
fx.syncTree.EXPECT().Close().Return(nil)
|
||||||
|
|
||||||
|
err := fx.doc.Close()
|
||||||
|
require.NoError(t, err)
|
||||||
fx.ctrl.Finish()
|
fx.ctrl.Finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSettingsObject_Init(t *testing.T) {
|
func TestSettingsObject_Init(t *testing.T) {
|
||||||
fx := newSettingsFixture(t)
|
fx := newSettingsFixture(t)
|
||||||
defer fx.stop()
|
defer fx.stop(t)
|
||||||
|
|
||||||
fx.spaceStorage.EXPECT().SpaceSettingsId().Return(fx.docId)
|
fx.init(t)
|
||||||
fx.deleter.EXPECT().Delete()
|
|
||||||
fx.syncTree.EXPECT().Close().Return(nil)
|
|
||||||
|
|
||||||
err := fx.doc.Init(context.Background())
|
|
||||||
require.NoError(t, err)
|
|
||||||
err = fx.doc.Close()
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSettingsObject_DeleteObject_NoSnapshot(t *testing.T) {
|
func TestSettingsObject_DeleteObject_NoSnapshot(t *testing.T) {
|
||||||
fx := newSettingsFixture(t)
|
fx := newSettingsFixture(t)
|
||||||
defer fx.stop()
|
defer fx.stop(t)
|
||||||
|
|
||||||
fx.spaceStorage.EXPECT().SpaceSettingsId().Return(fx.docId)
|
fx.init(t)
|
||||||
fx.deleter.EXPECT().Delete()
|
|
||||||
|
|
||||||
err := fx.doc.Init(context.Background())
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
delId := "delId"
|
delId := "delId"
|
||||||
doSnapshot = func(len int) bool {
|
doSnapshot = func(len int) bool {
|
||||||
@ -142,7 +152,6 @@ func TestSettingsObject_DeleteObject_NoSnapshot(t *testing.T) {
|
|||||||
|
|
||||||
fx.syncTree.EXPECT().Id().Return("syncId")
|
fx.syncTree.EXPECT().Id().Return("syncId")
|
||||||
fx.syncTree.EXPECT().Len().Return(10)
|
fx.syncTree.EXPECT().Len().Return(10)
|
||||||
fx.delState.EXPECT().Exists(delId).Return(false)
|
|
||||||
fx.spaceStorage.EXPECT().TreeStorage(delId).Return(nil, nil)
|
fx.spaceStorage.EXPECT().TreeStorage(delId).Return(nil, nil)
|
||||||
res := []byte("settingsData")
|
res := []byte("settingsData")
|
||||||
fx.doc.state = &settingsstate.State{LastIteratedId: "someId"}
|
fx.doc.state = &settingsstate.State{LastIteratedId: "someId"}
|
||||||
@ -162,22 +171,13 @@ func TestSettingsObject_DeleteObject_NoSnapshot(t *testing.T) {
|
|||||||
fx.deletionManager.EXPECT().UpdateState(gomock.Any(), fx.doc.state).Return(nil)
|
fx.deletionManager.EXPECT().UpdateState(gomock.Any(), fx.doc.state).Return(nil)
|
||||||
err = fx.doc.DeleteObject(delId)
|
err = fx.doc.DeleteObject(delId)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
fx.syncTree.EXPECT().Close().Return(nil)
|
|
||||||
err = fx.doc.Close()
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSettingsObject_DeleteObject_WithSnapshot(t *testing.T) {
|
func TestSettingsObject_DeleteObject_WithSnapshot(t *testing.T) {
|
||||||
fx := newSettingsFixture(t)
|
fx := newSettingsFixture(t)
|
||||||
defer fx.stop()
|
defer fx.stop(t)
|
||||||
|
|
||||||
fx.spaceStorage.EXPECT().SpaceSettingsId().Return(fx.docId)
|
|
||||||
fx.deleter.EXPECT().Delete()
|
|
||||||
|
|
||||||
err := fx.doc.Init(context.Background())
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
|
fx.init(t)
|
||||||
delId := "delId"
|
delId := "delId"
|
||||||
doSnapshot = func(len int) bool {
|
doSnapshot = func(len int) bool {
|
||||||
return true
|
return true
|
||||||
@ -185,7 +185,6 @@ func TestSettingsObject_DeleteObject_WithSnapshot(t *testing.T) {
|
|||||||
|
|
||||||
fx.syncTree.EXPECT().Id().Return("syncId")
|
fx.syncTree.EXPECT().Id().Return("syncId")
|
||||||
fx.syncTree.EXPECT().Len().Return(10)
|
fx.syncTree.EXPECT().Len().Return(10)
|
||||||
fx.delState.EXPECT().Exists(delId).Return(false)
|
|
||||||
fx.spaceStorage.EXPECT().TreeStorage(delId).Return(nil, nil)
|
fx.spaceStorage.EXPECT().TreeStorage(delId).Return(nil, nil)
|
||||||
res := []byte("settingsData")
|
res := []byte("settingsData")
|
||||||
fx.doc.state = &settingsstate.State{LastIteratedId: "someId"}
|
fx.doc.state = &settingsstate.State{LastIteratedId: "someId"}
|
||||||
@ -199,27 +198,19 @@ func TestSettingsObject_DeleteObject_WithSnapshot(t *testing.T) {
|
|||||||
Key: accountData.SignKey,
|
Key: accountData.SignKey,
|
||||||
IsSnapshot: true,
|
IsSnapshot: true,
|
||||||
IsEncrypted: false,
|
IsEncrypted: false,
|
||||||
}).Return(objecttree.AddResult{}, nil)
|
}).Return(objecttree.AddResult{Mode: objecttree.Rebuild}, nil)
|
||||||
|
|
||||||
fx.stateBuilder.EXPECT().Build(fx.doc, fx.doc.state).Return(fx.doc.state, nil)
|
fx.stateBuilder.EXPECT().Build(fx.doc, nil).Return(fx.doc.state, nil)
|
||||||
fx.deletionManager.EXPECT().UpdateState(gomock.Any(), fx.doc.state).Return(nil)
|
fx.deletionManager.EXPECT().UpdateState(gomock.Any(), fx.doc.state).Return(nil)
|
||||||
err = fx.doc.DeleteObject(delId)
|
err = fx.doc.DeleteObject(delId)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
fx.syncTree.EXPECT().Close().Return(nil)
|
|
||||||
err = fx.doc.Close()
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSettingsObject_Rebuild(t *testing.T) {
|
func TestSettingsObject_Rebuild(t *testing.T) {
|
||||||
fx := newSettingsFixture(t)
|
fx := newSettingsFixture(t)
|
||||||
defer fx.stop()
|
defer fx.stop(t)
|
||||||
|
|
||||||
fx.spaceStorage.EXPECT().SpaceSettingsId().Return(fx.docId)
|
fx.init(t)
|
||||||
fx.deleter.EXPECT().Delete()
|
|
||||||
|
|
||||||
err := fx.doc.Init(context.Background())
|
|
||||||
require.NoError(t, err)
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
newSt := &settingsstate.State{}
|
newSt := &settingsstate.State{}
|
||||||
@ -232,13 +223,9 @@ func TestSettingsObject_Rebuild(t *testing.T) {
|
|||||||
|
|
||||||
func TestSettingsObject_Update(t *testing.T) {
|
func TestSettingsObject_Update(t *testing.T) {
|
||||||
fx := newSettingsFixture(t)
|
fx := newSettingsFixture(t)
|
||||||
defer fx.stop()
|
defer fx.stop(t)
|
||||||
|
|
||||||
fx.spaceStorage.EXPECT().SpaceSettingsId().Return(fx.docId)
|
fx.init(t)
|
||||||
fx.deleter.EXPECT().Delete()
|
|
||||||
|
|
||||||
err := fx.doc.Init(context.Background())
|
|
||||||
require.NoError(t, err)
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
fx.doc.state = &settingsstate.State{}
|
fx.doc.state = &settingsstate.State{}
|
||||||
@ -250,13 +237,9 @@ func TestSettingsObject_Update(t *testing.T) {
|
|||||||
|
|
||||||
func TestSettingsObject_DeleteSpace(t *testing.T) {
|
func TestSettingsObject_DeleteSpace(t *testing.T) {
|
||||||
fx := newSettingsFixture(t)
|
fx := newSettingsFixture(t)
|
||||||
defer fx.stop()
|
defer fx.stop(t)
|
||||||
|
|
||||||
fx.spaceStorage.EXPECT().SpaceSettingsId().Return(fx.docId)
|
fx.init(t)
|
||||||
fx.deleter.EXPECT().Delete()
|
|
||||||
|
|
||||||
err := fx.doc.Init(context.Background())
|
|
||||||
require.NoError(t, err)
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
deleterId := "delId"
|
deleterId := "delId"
|
||||||
@ -275,19 +258,15 @@ func TestSettingsObject_DeleteSpace(t *testing.T) {
|
|||||||
Heads: []string{rawCh.Id},
|
Heads: []string{rawCh.Id},
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
||||||
err = fx.doc.DeleteSpace(context.Background(), rawCh)
|
err := fx.doc.DeleteSpace(context.Background(), rawCh)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSettingsObject_DeleteSpaceIncorrectChange(t *testing.T) {
|
func TestSettingsObject_DeleteSpaceIncorrectChange(t *testing.T) {
|
||||||
fx := newSettingsFixture(t)
|
fx := newSettingsFixture(t)
|
||||||
defer fx.stop()
|
defer fx.stop(t)
|
||||||
|
|
||||||
fx.spaceStorage.EXPECT().SpaceSettingsId().Return(fx.docId)
|
fx.init(t)
|
||||||
fx.deleter.EXPECT().Delete()
|
|
||||||
|
|
||||||
err := fx.doc.Init(context.Background())
|
|
||||||
require.NoError(t, err)
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
t.Run("incorrect change type", func(t *testing.T) {
|
t.Run("incorrect change type", func(t *testing.T) {
|
||||||
@ -299,7 +278,7 @@ func TestSettingsObject_DeleteSpaceIncorrectChange(t *testing.T) {
|
|||||||
delChange, _ := changeFactory.CreateObjectDeleteChange("otherId", &settingsstate.State{}, false)
|
delChange, _ := changeFactory.CreateObjectDeleteChange("otherId", &settingsstate.State{}, false)
|
||||||
|
|
||||||
fx.syncTree.EXPECT().UnpackChange(rawCh).Return(delChange, nil)
|
fx.syncTree.EXPECT().UnpackChange(rawCh).Return(delChange, nil)
|
||||||
err = fx.doc.DeleteSpace(context.Background(), rawCh)
|
err := fx.doc.DeleteSpace(context.Background(), rawCh)
|
||||||
require.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -312,7 +291,7 @@ func TestSettingsObject_DeleteSpaceIncorrectChange(t *testing.T) {
|
|||||||
delChange, _ := changeFactory.CreateSpaceDeleteChange("", &settingsstate.State{}, false)
|
delChange, _ := changeFactory.CreateSpaceDeleteChange("", &settingsstate.State{}, false)
|
||||||
|
|
||||||
fx.syncTree.EXPECT().UnpackChange(rawCh).Return(delChange, nil)
|
fx.syncTree.EXPECT().UnpackChange(rawCh).Return(delChange, nil)
|
||||||
err = fx.doc.DeleteSpace(context.Background(), rawCh)
|
err := fx.doc.DeleteSpace(context.Background(), rawCh)
|
||||||
require.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,9 @@
|
|||||||
package settingsstate
|
package settingsstate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/anytypeio/any-sync/app/logger"
|
||||||
"github.com/anytypeio/any-sync/commonspace/spacestorage"
|
"github.com/anytypeio/any-sync/commonspace/spacestorage"
|
||||||
|
"go.uber.org/zap"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -10,7 +12,7 @@ type StateUpdateObserver func(ids []string)
|
|||||||
|
|
||||||
type ObjectDeletionState interface {
|
type ObjectDeletionState interface {
|
||||||
AddObserver(observer StateUpdateObserver)
|
AddObserver(observer StateUpdateObserver)
|
||||||
Add(ids []string) (err error)
|
Add(ids []string)
|
||||||
GetQueued() (ids []string)
|
GetQueued() (ids []string)
|
||||||
Delete(id string) (err error)
|
Delete(id string) (err error)
|
||||||
Exists(id string) bool
|
Exists(id string) bool
|
||||||
@ -19,14 +21,16 @@ type ObjectDeletionState interface {
|
|||||||
|
|
||||||
type objectDeletionState struct {
|
type objectDeletionState struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
|
log logger.CtxLogger
|
||||||
queued map[string]struct{}
|
queued map[string]struct{}
|
||||||
deleted map[string]struct{}
|
deleted map[string]struct{}
|
||||||
stateUpdateObservers []StateUpdateObserver
|
stateUpdateObservers []StateUpdateObserver
|
||||||
storage spacestorage.SpaceStorage
|
storage spacestorage.SpaceStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewObjectDeletionState(storage spacestorage.SpaceStorage) ObjectDeletionState {
|
func NewObjectDeletionState(log logger.CtxLogger, storage spacestorage.SpaceStorage) ObjectDeletionState {
|
||||||
return &objectDeletionState{
|
return &objectDeletionState{
|
||||||
|
log: log,
|
||||||
queued: map[string]struct{}{},
|
queued: map[string]struct{}{},
|
||||||
deleted: map[string]struct{}{},
|
deleted: map[string]struct{}{},
|
||||||
storage: storage,
|
storage: storage,
|
||||||
@ -39,15 +43,13 @@ func (st *objectDeletionState) AddObserver(observer StateUpdateObserver) {
|
|||||||
st.stateUpdateObservers = append(st.stateUpdateObservers, observer)
|
st.stateUpdateObservers = append(st.stateUpdateObservers, observer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *objectDeletionState) Add(ids []string) (err error) {
|
func (st *objectDeletionState) Add(ids []string) {
|
||||||
|
var added []string
|
||||||
st.Lock()
|
st.Lock()
|
||||||
defer func() {
|
defer func() {
|
||||||
st.Unlock()
|
st.Unlock()
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, ob := range st.stateUpdateObservers {
|
for _, ob := range st.stateUpdateObservers {
|
||||||
ob(ids)
|
ob(added)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -60,9 +62,10 @@ func (st *objectDeletionState) Add(ids []string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var status string
|
var status string
|
||||||
status, err = st.storage.TreeDeletedStatus(id)
|
status, err := st.storage.TreeDeletedStatus(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
st.log.Warn("failed to get deleted status", zap.String("treeId", id), zap.Error(err))
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
switch status {
|
switch status {
|
||||||
@ -71,14 +74,15 @@ func (st *objectDeletionState) Add(ids []string) (err error) {
|
|||||||
case spacestorage.TreeDeletedStatusDeleted:
|
case spacestorage.TreeDeletedStatusDeleted:
|
||||||
st.deleted[id] = struct{}{}
|
st.deleted[id] = struct{}{}
|
||||||
default:
|
default:
|
||||||
st.queued[id] = struct{}{}
|
err := st.storage.SetTreeDeletedStatus(id, spacestorage.TreeDeletedStatusQueued)
|
||||||
err = st.storage.SetTreeDeletedStatus(id, spacestorage.TreeDeletedStatusQueued)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
st.log.Warn("failed to set deleted status", zap.String("treeId", id), zap.Error(err))
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
st.queued[id] = struct{}{}
|
||||||
}
|
}
|
||||||
|
added = append(added, id)
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *objectDeletionState) GetQueued() (ids []string) {
|
func (st *objectDeletionState) GetQueued() (ids []string) {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package settingsstate
|
package settingsstate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/anytypeio/any-sync/app/logger"
|
||||||
"github.com/anytypeio/any-sync/commonspace/spacestorage"
|
"github.com/anytypeio/any-sync/commonspace/spacestorage"
|
||||||
"github.com/anytypeio/any-sync/commonspace/spacestorage/mock_spacestorage"
|
"github.com/anytypeio/any-sync/commonspace/spacestorage/mock_spacestorage"
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
@ -18,7 +19,7 @@ type fixture struct {
|
|||||||
func newFixture(t *testing.T) *fixture {
|
func newFixture(t *testing.T) *fixture {
|
||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
spaceStorage := mock_spacestorage.NewMockSpaceStorage(ctrl)
|
spaceStorage := mock_spacestorage.NewMockSpaceStorage(ctrl)
|
||||||
delState := NewObjectDeletionState(spaceStorage).(*objectDeletionState)
|
delState := NewObjectDeletionState(logger.NewNamed("test"), spaceStorage).(*objectDeletionState)
|
||||||
return &fixture{
|
return &fixture{
|
||||||
ctrl: ctrl,
|
ctrl: ctrl,
|
||||||
delState: delState,
|
delState: delState,
|
||||||
@ -37,8 +38,7 @@ func TestDeletionState_Add(t *testing.T) {
|
|||||||
id := "newId"
|
id := "newId"
|
||||||
fx.spaceStorage.EXPECT().TreeDeletedStatus(id).Return("", nil)
|
fx.spaceStorage.EXPECT().TreeDeletedStatus(id).Return("", nil)
|
||||||
fx.spaceStorage.EXPECT().SetTreeDeletedStatus(id, spacestorage.TreeDeletedStatusQueued).Return(nil)
|
fx.spaceStorage.EXPECT().SetTreeDeletedStatus(id, spacestorage.TreeDeletedStatusQueued).Return(nil)
|
||||||
err := fx.delState.Add([]string{id})
|
fx.delState.Add([]string{id})
|
||||||
require.NoError(t, err)
|
|
||||||
require.Contains(t, fx.delState.queued, id)
|
require.Contains(t, fx.delState.queued, id)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -47,8 +47,7 @@ func TestDeletionState_Add(t *testing.T) {
|
|||||||
defer fx.stop()
|
defer fx.stop()
|
||||||
id := "newId"
|
id := "newId"
|
||||||
fx.spaceStorage.EXPECT().TreeDeletedStatus(id).Return(spacestorage.TreeDeletedStatusQueued, nil)
|
fx.spaceStorage.EXPECT().TreeDeletedStatus(id).Return(spacestorage.TreeDeletedStatusQueued, nil)
|
||||||
err := fx.delState.Add([]string{id})
|
fx.delState.Add([]string{id})
|
||||||
require.NoError(t, err)
|
|
||||||
require.Contains(t, fx.delState.queued, id)
|
require.Contains(t, fx.delState.queued, id)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -57,8 +56,7 @@ func TestDeletionState_Add(t *testing.T) {
|
|||||||
defer fx.stop()
|
defer fx.stop()
|
||||||
id := "newId"
|
id := "newId"
|
||||||
fx.spaceStorage.EXPECT().TreeDeletedStatus(id).Return(spacestorage.TreeDeletedStatusDeleted, nil)
|
fx.spaceStorage.EXPECT().TreeDeletedStatus(id).Return(spacestorage.TreeDeletedStatusDeleted, nil)
|
||||||
err := fx.delState.Add([]string{id})
|
fx.delState.Add([]string{id})
|
||||||
require.NoError(t, err)
|
|
||||||
require.Contains(t, fx.delState.deleted, id)
|
require.Contains(t, fx.delState.deleted, id)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -98,8 +96,7 @@ func TestDeletionState_AddObserver(t *testing.T) {
|
|||||||
id := "newId"
|
id := "newId"
|
||||||
fx.spaceStorage.EXPECT().TreeDeletedStatus(id).Return("", nil)
|
fx.spaceStorage.EXPECT().TreeDeletedStatus(id).Return("", nil)
|
||||||
fx.spaceStorage.EXPECT().SetTreeDeletedStatus(id, spacestorage.TreeDeletedStatusQueued).Return(nil)
|
fx.spaceStorage.EXPECT().SetTreeDeletedStatus(id, spacestorage.TreeDeletedStatusQueued).Return(nil)
|
||||||
err := fx.delState.Add([]string{id})
|
fx.delState.Add([]string{id})
|
||||||
require.NoError(t, err)
|
|
||||||
require.Contains(t, fx.delState.queued, id)
|
require.Contains(t, fx.delState.queued, id)
|
||||||
require.Equal(t, []string{id}, queued)
|
require.Equal(t, []string{id}, queued)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,11 +36,9 @@ func (m *MockObjectDeletionState) EXPECT() *MockObjectDeletionStateMockRecorder
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add mocks base method.
|
// Add mocks base method.
|
||||||
func (m *MockObjectDeletionState) Add(arg0 []string) error {
|
func (m *MockObjectDeletionState) Add(arg0 []string) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "Add", arg0)
|
m.ctrl.Call(m, "Add", arg0)
|
||||||
ret0, _ := ret[0].(error)
|
|
||||||
return ret0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add indicates an expected call of Add.
|
// Add indicates an expected call of Add.
|
||||||
@ -145,7 +143,7 @@ func (m *MockStateBuilder) EXPECT() *MockStateBuilderMockRecorder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build mocks base method.
|
// Build mocks base method.
|
||||||
func (m *MockStateBuilder) Build(arg0 objecttree.ObjectTree, arg1 *settingsstate.State) (*settingsstate.State, error) {
|
func (m *MockStateBuilder) Build(arg0 objecttree.ReadableObjectTree, arg1 *settingsstate.State) (*settingsstate.State, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "Build", arg0, arg1)
|
ret := m.ctrl.Call(m, "Build", arg0, arg1)
|
||||||
ret0, _ := ret[0].(*settingsstate.State)
|
ret0, _ := ret[0].(*settingsstate.State)
|
||||||
|
|||||||
@ -1,7 +1,15 @@
|
|||||||
package settingsstate
|
package settingsstate
|
||||||
|
|
||||||
|
import "golang.org/x/exp/slices"
|
||||||
|
|
||||||
type State struct {
|
type State struct {
|
||||||
DeletedIds []string
|
DeletedIds []string
|
||||||
DeleterId string
|
DeleterId string
|
||||||
LastIteratedId string
|
LastIteratedId string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *State) Exists(id string) bool {
|
||||||
|
// using map here will not give a lot of benefit, because this thing should be called only
|
||||||
|
// when we are adding content, thus it doesn't matter
|
||||||
|
return slices.Contains(s.DeletedIds, id)
|
||||||
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type StateBuilder interface {
|
type StateBuilder interface {
|
||||||
Build(tree objecttree.ObjectTree, state *State) (*State, error)
|
Build(tree objecttree.ReadableObjectTree, state *State) (*State, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStateBuilder() StateBuilder {
|
func NewStateBuilder() StateBuilder {
|
||||||
@ -17,7 +17,7 @@ func NewStateBuilder() StateBuilder {
|
|||||||
type stateBuilder struct {
|
type stateBuilder struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stateBuilder) Build(tr objecttree.ObjectTree, oldState *State) (state *State, err error) {
|
func (s *stateBuilder) Build(tr objecttree.ReadableObjectTree, oldState *State) (state *State, err error) {
|
||||||
var (
|
var (
|
||||||
rootId = tr.Root().Id
|
rootId = tr.Root().Id
|
||||||
startId = rootId
|
startId = rootId
|
||||||
|
|||||||
@ -195,7 +195,7 @@ func (s *space) Init(ctx context.Context) (err error) {
|
|||||||
s.aclList = syncacl.NewSyncAcl(aclList, s.objectSync.MessagePool())
|
s.aclList = syncacl.NewSyncAcl(aclList, s.objectSync.MessagePool())
|
||||||
s.cache.AddObject(s.aclList)
|
s.cache.AddObject(s.aclList)
|
||||||
|
|
||||||
deletionState := settingsstate.NewObjectDeletionState(s.storage)
|
deletionState := settingsstate.NewObjectDeletionState(log, s.storage)
|
||||||
deps := settings.Deps{
|
deps := settings.Deps{
|
||||||
BuildFunc: func(ctx context.Context, id string, listener updatelistener.UpdateListener) (t synctree.SyncTree, err error) {
|
BuildFunc: func(ctx context.Context, id string, listener updatelistener.UpdateListener) (t synctree.SyncTree, err error) {
|
||||||
res, err := s.BuildTree(ctx, id, BuildTreeOpts{
|
res, err := s.BuildTree(ctx, id, BuildTreeOpts{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user