From 5e23680b366c80ca5a0d4eca52ff56fd8e4ae951 Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Sun, 15 Jan 2023 15:49:09 +0100 Subject: [PATCH] Transactional add in object tree --- commonspace/headsync/diffsyncer_test.go | 3 +- .../object/tree/objecttree/objecttree.go | 18 +-- .../tree/objecttree/objecttreefactory.go | 18 --- .../object/tree/treestorage/inmemory.go | 17 ++- .../{mock_storage.go => mock_treestorage.go} | 131 +++--------------- .../object/tree/treestorage/treestorage.go | 4 +- nodeconf/mock_nodeconf/mock_nodeconf.go | 14 ++ 7 files changed, 50 insertions(+), 155 deletions(-) rename commonspace/object/tree/treestorage/mock_treestorage/{mock_storage.go => mock_treestorage.go} (55%) diff --git a/commonspace/headsync/diffsyncer_test.go b/commonspace/headsync/diffsyncer_test.go index c74afd8e..51192e9f 100644 --- a/commonspace/headsync/diffsyncer_test.go +++ b/commonspace/headsync/diffsyncer_test.go @@ -8,6 +8,7 @@ import ( "github.com/anytypeio/any-sync/app/logger" "github.com/anytypeio/any-sync/commonspace/confconnector/mock_confconnector" "github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto" + "github.com/anytypeio/any-sync/commonspace/object/acl/liststorage/mock_liststorage" "github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto" mock_treestorage "github.com/anytypeio/any-sync/commonspace/object/tree/treestorage/mock_treestorage" "github.com/anytypeio/any-sync/commonspace/object/treegetter/mock_treegetter" @@ -160,7 +161,7 @@ func TestDiffSyncer_Sync(t *testing.T) { }) t.Run("diff syncer sync space missing", func(t *testing.T) { - aclStorageMock := mock_treestorage.NewMockListStorage(ctrl) + aclStorageMock := mock_liststorage.NewMockListStorage(ctrl) settingsStorage := mock_treestorage.NewMockTreeStorage(ctrl) settingsId := "settingsId" aclRoot := &aclrecordproto.RawAclRecordWithId{ diff --git a/commonspace/object/tree/objecttree/objecttree.go b/commonspace/object/tree/objecttree/objecttree.go index ac449de5..176d7192 100644 --- a/commonspace/object/tree/objecttree/objecttree.go +++ b/commonspace/object/tree/objecttree/objecttree.go @@ -175,12 +175,7 @@ func (ot *objectTree) AddContent(ctx context.Context, content SignableChangeCont panic(err) } - err = ot.treeStorage.AddRawChange(rawChange) - if err != nil { - return - } - - err = ot.treeStorage.SetHeads([]string{objChange.Id}) + err = ot.treeStorage.TransactionAdd([]*treechangeproto.RawTreeChangeWithId{rawChange}, []string{objChange.Id}) if err != nil { return } @@ -253,16 +248,7 @@ func (ot *objectTree) AddRawChanges(ctx context.Context, changesPayload RawChang addResult.Mode = Rebuild } - // adding to database all the added changes only after they are good - for _, ch := range addResult.Added { - err = ot.treeStorage.AddRawChange(ch) - if err != nil { - return - } - } - - // setting heads - err = ot.treeStorage.SetHeads(ot.tree.Heads()) + err = ot.treeStorage.TransactionAdd(addResult.Added, addResult.Heads) return } diff --git a/commonspace/object/tree/objecttree/objecttreefactory.go b/commonspace/object/tree/objecttree/objecttreefactory.go index ed34a91a..1bd5a885 100644 --- a/commonspace/object/tree/objecttree/objecttreefactory.go +++ b/commonspace/object/tree/objecttree/objecttreefactory.go @@ -7,8 +7,6 @@ import ( "github.com/anytypeio/any-sync/commonspace/object/tree/treestorage" "github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey" "github.com/anytypeio/any-sync/util/keys/symmetric" - "github.com/anytypeio/any-sync/util/slice" - "go.uber.org/zap" "math/rand" "time" ) @@ -132,22 +130,6 @@ func buildObjectTree(deps objectTreeDeps) (ObjectTree, error) { if err != nil { return nil, err } - storageHeads, err := objTree.treeStorage.Heads() - if err != nil { - return nil, err - } - - // comparing rebuilt heads with heads in storage - // in theory it can happen that we didn't set heads because the process has crashed - // therefore we want to set them later - if !slice.UnsortedEquals(storageHeads, objTree.tree.Heads()) { - log.With(zap.Strings("storage", storageHeads), zap.Strings("rebuilt", objTree.tree.Heads())). - Errorf("the heads in storage and objTree are different") - err = objTree.treeStorage.SetHeads(objTree.tree.Heads()) - if err != nil { - return nil, err - } - } objTree.id = objTree.treeStorage.Id() objTree.rawRoot, err = objTree.treeStorage.Root() diff --git a/commonspace/object/tree/treestorage/inmemory.go b/commonspace/object/tree/treestorage/inmemory.go index 29db6f6e..c5c5a5cc 100644 --- a/commonspace/object/tree/treestorage/inmemory.go +++ b/commonspace/object/tree/treestorage/inmemory.go @@ -16,6 +16,17 @@ type inMemoryTreeStorage struct { sync.RWMutex } +func (t *inMemoryTreeStorage) TransactionAdd(changes []*treechangeproto.RawTreeChangeWithId, heads []string) error { + t.RLock() + defer t.RUnlock() + + for _, ch := range changes { + t.changes[ch.Id] = ch + } + t.heads = append(t.heads[:0], heads...) + return nil +} + func NewInMemoryTreeStorage( root *treechangeproto.RawTreeChangeWithId, heads []string, @@ -61,11 +72,7 @@ func (t *inMemoryTreeStorage) Heads() ([]string, error) { func (t *inMemoryTreeStorage) SetHeads(heads []string) error { t.Lock() defer t.Unlock() - t.heads = t.heads[:0] - - for _, h := range heads { - t.heads = append(t.heads, h) - } + t.heads = append(t.heads[:0], heads...) return nil } diff --git a/commonspace/object/tree/treestorage/mock_treestorage/mock_storage.go b/commonspace/object/tree/treestorage/mock_treestorage/mock_treestorage.go similarity index 55% rename from commonspace/object/tree/treestorage/mock_treestorage/mock_storage.go rename to commonspace/object/tree/treestorage/mock_treestorage/mock_treestorage.go index 20a62933..2fe6029f 100644 --- a/commonspace/object/tree/treestorage/mock_treestorage/mock_storage.go +++ b/commonspace/object/tree/treestorage/mock_treestorage/mock_treestorage.go @@ -1,128 +1,17 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/anytypeio/any-sync/pkg/acl/storage (interfaces: ListStorage,TreeStorage) +// Source: github.com/anytypeio/any-sync/commonspace/object/tree/treestorage (interfaces: TreeStorage) -// Package mock_storage is a generated GoMock package. +// Package mock_treestorage is a generated GoMock package. package mock_treestorage import ( context "context" - "github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto" - "github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto" reflect "reflect" + treechangeproto "github.com/anytypeio/any-sync/commonspace/object/tree/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() (string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Head") - ret0, _ := ret[0].(string) - 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 { - 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 *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)) -} - -// SetHead mocks base method. -func (m *MockListStorage) SetHead(arg0 string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SetHead", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// SetHead indicates an expected call of SetHead. -func (mr *MockListStorageMockRecorder) SetHead(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetHead", reflect.TypeOf((*MockListStorage)(nil).SetHead), arg0) -} - // MockTreeStorage is a mock of TreeStorage interface. type MockTreeStorage struct { ctrl *gomock.Controller @@ -261,3 +150,17 @@ 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) } + +// TransactionAdd mocks base method. +func (m *MockTreeStorage) TransactionAdd(arg0 []*treechangeproto.RawTreeChangeWithId, arg1 []string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TransactionAdd", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// TransactionAdd indicates an expected call of TransactionAdd. +func (mr *MockTreeStorageMockRecorder) TransactionAdd(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionAdd", reflect.TypeOf((*MockTreeStorage)(nil).TransactionAdd), arg0, arg1) +} diff --git a/commonspace/object/tree/treestorage/treestorage.go b/commonspace/object/tree/treestorage/treestorage.go index 10c6cf70..b0051d76 100644 --- a/commonspace/object/tree/treestorage/treestorage.go +++ b/commonspace/object/tree/treestorage/treestorage.go @@ -1,3 +1,4 @@ +//go:generate mockgen -destination mock_treestorage/mock_treestorage.go github.com/anytypeio/any-sync/commonspace/object/tree/treestorage TreeStorage package treestorage import ( @@ -25,8 +26,9 @@ type TreeStorage interface { Root() (*treechangeproto.RawTreeChangeWithId, error) Heads() ([]string, error) SetHeads(heads []string) error - AddRawChange(change *treechangeproto.RawTreeChangeWithId) error + TransactionAdd(changes []*treechangeproto.RawTreeChangeWithId, heads []string) error + GetRawChange(ctx context.Context, id string) (*treechangeproto.RawTreeChangeWithId, error) HasChange(ctx context.Context, id string) (bool, error) Delete() error diff --git a/nodeconf/mock_nodeconf/mock_nodeconf.go b/nodeconf/mock_nodeconf/mock_nodeconf.go index 9e0bd4f4..5d9e65e2 100644 --- a/nodeconf/mock_nodeconf/mock_nodeconf.go +++ b/nodeconf/mock_nodeconf/mock_nodeconf.go @@ -212,3 +212,17 @@ 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) } + +// Partition mocks base method. +func (m *MockConfiguration) Partition(arg0 string) int { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Partition", arg0) + ret0, _ := ret[0].(int) + return ret0 +} + +// Partition indicates an expected call of Partition. +func (mr *MockConfigurationMockRecorder) Partition(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Partition", reflect.TypeOf((*MockConfiguration)(nil).Partition), arg0) +}