From cb2f64f0d58c7cd7f2ad35b8d29b5702ca6f1338 Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Sun, 13 Nov 2022 09:35:47 +0100 Subject: [PATCH] Change deletion logic --- .../settingsdocument/settingsdocument.go | 77 ++++++++----------- .../settingsdocument/settingsqueue.go | 69 +++++++++++++++++ 2 files changed, 101 insertions(+), 45 deletions(-) create mode 100644 common/commonspace/settingsdocument/settingsqueue.go diff --git a/common/commonspace/settingsdocument/settingsdocument.go b/common/commonspace/settingsdocument/settingsdocument.go index 54995af2..1971e00f 100644 --- a/common/commonspace/settingsdocument/settingsdocument.go +++ b/common/commonspace/settingsdocument/settingsdocument.go @@ -8,14 +8,6 @@ import ( "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/pkg/acl/tree" - "sync" -) - -type DeletionState int - -const ( - DeletionStateQueued DeletionState = iota - DeletionStateDeleted ) type SettingsDocument interface { @@ -41,23 +33,24 @@ type Deps struct { type settingsDocument struct { tree.ObjectTree - account account.Service - spaceId string - deletionState map[string]DeletionState - treeGetter treegetter.TreeGetter - store spacestorage.SpaceStorage - lastChangeId string - prov deletedIdsProvider - removeNotifyFunc RemoveObjectsFunc - buildFunc BuildTreeFunc - deletionStateLock sync.Mutex + account account.Service + spaceId string + treeGetter treegetter.TreeGetter + store spacestorage.SpaceStorage + prov deletedIdsProvider + removeNotifyFunc RemoveObjectsFunc + buildFunc BuildTreeFunc + + queue *settingsQueue + documentIds []string + lastChangeId string } func NewSettingsDocument(deps Deps, spaceId string) (doc SettingsDocument, err error) { s := &settingsDocument{ account: deps.Account, spaceId: spaceId, - deletionState: map[string]DeletionState{}, + queue: newSettingsQueue(), treeGetter: deps.TreeGetter, store: deps.Store, removeNotifyFunc: deps.RemoveFunc, @@ -73,12 +66,7 @@ func NewSettingsDocument(deps Deps, spaceId string) (doc SettingsDocument, err e } func (s *settingsDocument) NotifyObjectUpdate(id string) { - s.deletionStateLock.Lock() - if state, exists := s.deletionState[id]; exists && state == DeletionStateDeleted { - // marking the document as queued, that means that document appeared later than we checked the storage for deletion - s.deletionState[id] = DeletionStateQueued - } - s.deletionStateLock.Unlock() + s.queue.queueIfDeleted(id) } func (s *settingsDocument) Update(tr tree.ObjectTree) { @@ -86,8 +74,10 @@ func (s *settingsDocument) Update(tr tree.ObjectTree) { if err != nil { return } + s.documentIds = append(s.documentIds, ids...) s.lastChangeId = lastId - s.toBeDeleted(ids) + s.queue.add(ids) + s.deleteQueued() } func (s *settingsDocument) Rebuild(tr tree.ObjectTree) { @@ -95,8 +85,10 @@ func (s *settingsDocument) Rebuild(tr tree.ObjectTree) { if err != nil { return } + s.documentIds = ids s.lastChangeId = lastId - s.toBeDeleted(ids) + s.queue.add(ids) + s.deleteQueued() } func (s *settingsDocument) Init(ctx context.Context) (err error) { @@ -107,40 +99,35 @@ func (s *settingsDocument) Init(ctx context.Context) (err error) { func (s *settingsDocument) Refresh() { s.Lock() defer s.Unlock() - s.Rebuild(s) + if s.lastChangeId == "" { + s.Rebuild(s) + } else { + s.deleteQueued() + } } -func (s *settingsDocument) toBeDeleted(ids []string) { - for _, id := range ids { - s.deletionStateLock.Lock() - if state, exists := s.deletionState[id]; exists && state == DeletionStateDeleted { - s.deletionStateLock.Unlock() - continue - } - // if the document is not in storage it can happen that it will appear later, for that we have NotifyObjectUpdate method +func (s *settingsDocument) deleteQueued() { + allQueued := s.queue.getQueued() + for _, id := range allQueued { if _, err := s.store.TreeStorage(id); err == nil { - s.deletionState[id] = DeletionStateQueued - s.deletionStateLock.Unlock() - // doing this without lock err := s.treeGetter.DeleteTree(context.Background(), s.spaceId, id) if err != nil { // TODO: some errors may tell us that the tree is actually deleted, so we should have more checks here // TODO: add logging continue } - s.deletionStateLock.Lock() } - - s.deletionState[id] = DeletionStateDeleted - s.deletionStateLock.Unlock() + s.queue.delete(id) } - // notifying diff service that the ids should not be synced anymore - s.removeNotifyFunc(ids) } func (s *settingsDocument) DeleteObject(id string) (err error) { s.Lock() defer s.Unlock() + if s.queue.exists(id) { + return nil + } + content := &spacesyncproto.SpaceSettingsContent_ObjectDelete{ ObjectDelete: &spacesyncproto.ObjectDelete{Id: id}, } diff --git a/common/commonspace/settingsdocument/settingsqueue.go b/common/commonspace/settingsdocument/settingsqueue.go new file mode 100644 index 00000000..52a7329f --- /dev/null +++ b/common/commonspace/settingsdocument/settingsqueue.go @@ -0,0 +1,69 @@ +package settingsdocument + +import "sync" + +type settingsQueue struct { + sync.Mutex + queued map[string]struct{} + deleted map[string]struct{} +} + +func newSettingsQueue() *settingsQueue { + return &settingsQueue{ + Mutex: sync.Mutex{}, + queued: map[string]struct{}{}, + deleted: map[string]struct{}{}, + } +} + +func (q *settingsQueue) add(ids []string) { + q.Lock() + defer q.Unlock() + for _, id := range ids { + if _, exists := q.deleted[id]; exists { + continue + } + if _, exists := q.queued[id]; exists { + continue + } + q.queued[id] = struct{}{} + } +} + +func (q *settingsQueue) getQueued() (ids []string) { + q.Lock() + defer q.Unlock() + ids = make([]string, 0, len(q.queued)) + for id := range q.queued { + ids = append(ids, id) + } + return +} + +func (q *settingsQueue) delete(id string) { + q.Lock() + defer q.Unlock() + delete(q.queued, id) + q.deleted[id] = struct{}{} +} + +func (q *settingsQueue) queueIfDeleted(id string) { + q.Lock() + defer q.Unlock() + if _, exists := q.deleted[id]; exists { + delete(q.deleted, id) + q.queued[id] = struct{}{} + } +} + +func (q *settingsQueue) exists(id string) bool { + q.Lock() + defer q.Unlock() + if _, exists := q.deleted[id]; exists { + return true + } + if _, exists := q.queued[id]; exists { + return true + } + return false +}