mirror of
https://github.com/anyproto/any-sync.git
synced 2025-06-10 18:10:54 +09:00
Update any-sync new deletion logic
This commit is contained in:
parent
8a38d54192
commit
73b27c7dac
9 changed files with 243 additions and 165 deletions
|
@ -3,6 +3,7 @@ package settings
|
|||
import (
|
||||
"github.com/anytypeio/any-sync/commonspace/object/treegetter"
|
||||
"github.com/anytypeio/any-sync/commonspace/settings/settingsstate"
|
||||
"github.com/anytypeio/any-sync/util/slice"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -20,12 +21,16 @@ type DeletionManager interface {
|
|||
|
||||
func newDeletionManager(
|
||||
spaceId string,
|
||||
settingsId string,
|
||||
isResponsible bool,
|
||||
deletionInterval time.Duration,
|
||||
deletionState settingsstate.ObjectDeletionState,
|
||||
provider SpaceIdsProvider,
|
||||
onSpaceDelete func()) DeletionManager {
|
||||
return &deletionManager{
|
||||
isResponsible: isResponsible,
|
||||
spaceId: spaceId,
|
||||
settingsId: settingsId,
|
||||
deletionState: deletionState,
|
||||
provider: provider,
|
||||
deletionInterval: deletionInterval,
|
||||
|
@ -39,6 +44,8 @@ type deletionManager struct {
|
|||
treeGetter treegetter.TreeGetter
|
||||
deletionInterval time.Duration
|
||||
spaceId string
|
||||
settingsId string
|
||||
isResponsible bool
|
||||
onSpaceDelete func()
|
||||
}
|
||||
|
||||
|
@ -47,15 +54,18 @@ func (d *deletionManager) UpdateState(state *settingsstate.State) (err error) {
|
|||
if err != nil {
|
||||
log.Warn("failed to add deleted ids to deletion state")
|
||||
}
|
||||
if !state.SpaceDeletionDate.IsZero() {
|
||||
|
||||
if state.DeleterId != "" {
|
||||
spaceDeleter, ok := d.treeGetter.(SpaceDeleter)
|
||||
if ok {
|
||||
spaceDeleter.DeleteSpace(d.spaceId)
|
||||
}
|
||||
if state.SpaceDeletionDate.Add(d.deletionInterval).Before(time.Now()) {
|
||||
err = d.deletionState.Add(d.provider.AllIds()) // todo: except deletion tree
|
||||
// todo: compaction in pogreb
|
||||
d.onSpaceDelete()
|
||||
d.onSpaceDelete()
|
||||
if d.isResponsible {
|
||||
allIds := slice.DiscardFromSlice(d.provider.AllIds(), func(s string) bool {
|
||||
return s == d.settingsId
|
||||
})
|
||||
err = d.deletionState.Add(allIds)
|
||||
}
|
||||
}
|
||||
return
|
||||
|
|
|
@ -9,10 +9,15 @@ import (
|
|||
"github.com/anytypeio/any-sync/commonspace/object/tree/objecttree"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/tree/synctree"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/tree/synctree/updatelistener"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/treegetter"
|
||||
"github.com/anytypeio/any-sync/commonspace/settings/settingsstate"
|
||||
spacestorage "github.com/anytypeio/any-sync/commonspace/spacestorage"
|
||||
"github.com/anytypeio/any-sync/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/any-sync/nodeconf"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/exp/slices"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -24,16 +29,16 @@ type SettingsObject interface {
|
|||
synctree.SyncTree
|
||||
Init(ctx context.Context) (err error)
|
||||
DeleteObject(id string) (err error)
|
||||
DeleteSpace(t time.Time) (err error)
|
||||
RestoreSpace() (err error)
|
||||
DeleteSpace(ctx context.Context, deleterId string, raw *treechangeproto.RawTreeChangeWithId) (err error)
|
||||
SpaceDeleteRawChange(deleterId string) (raw *treechangeproto.RawTreeChangeWithId, err error)
|
||||
}
|
||||
|
||||
var (
|
||||
ErrDeleteSelf = errors.New("cannot delete self")
|
||||
ErrAlreadyDeleted = errors.New("the object is already deleted")
|
||||
ErrObjDoesNotExist = errors.New("the object does not exist")
|
||||
ErrMarkedDeleted = errors.New("this space is already marked deleted")
|
||||
ErrMarkedNotDeleted = errors.New("this space is not marked not deleted")
|
||||
ErrDeleteSelf = errors.New("cannot delete self")
|
||||
ErrAlreadyDeleted = errors.New("the object is already deleted")
|
||||
ErrObjDoesNotExist = errors.New("the object does not exist")
|
||||
ErrCantDeleteSpace = errors.New("not able to delete space")
|
||||
ErrIncorrectDeleteChange = errors.New("incorrect delete change")
|
||||
)
|
||||
|
||||
type BuildTreeFunc func(ctx context.Context, id string, listener updatelistener.UpdateListener) (t synctree.SyncTree, err error)
|
||||
|
@ -43,6 +48,7 @@ type Deps struct {
|
|||
Account accountservice.Service
|
||||
TreeGetter treegetter.TreeGetter
|
||||
Store spacestorage.SpaceStorage
|
||||
Configuration nodeconf.Configuration
|
||||
DeletionState settingsstate.ObjectDeletionState
|
||||
Provider SpaceIdsProvider
|
||||
OnSpaceDelete func()
|
||||
|
@ -82,7 +88,14 @@ func NewSettingsObject(deps Deps, spaceId string) (obj SettingsObject) {
|
|||
deleter = deps.del
|
||||
}
|
||||
if deps.delManager == nil {
|
||||
deletionManager = newDeletionManager(spaceId, spaceDeletionInterval, deps.DeletionState, deps.Provider, deps.OnSpaceDelete)
|
||||
deletionManager = newDeletionManager(
|
||||
spaceId,
|
||||
deps.Store.SpaceSettingsId(),
|
||||
deps.Configuration.IsResponsible(spaceId),
|
||||
spaceDeletionInterval,
|
||||
deps.DeletionState,
|
||||
deps.Provider,
|
||||
deps.OnSpaceDelete)
|
||||
} else {
|
||||
deletionManager = deps.delManager
|
||||
}
|
||||
|
@ -160,36 +173,39 @@ func (s *settingsObject) Close() error {
|
|||
return s.SyncTree.Close()
|
||||
}
|
||||
|
||||
func (s *settingsObject) DeleteSpace(t time.Time) (err error) {
|
||||
func (s *settingsObject) DeleteSpace(ctx context.Context, deleterId string, raw *treechangeproto.RawTreeChangeWithId) (err error) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
if !s.state.SpaceDeletionDate.IsZero() {
|
||||
return ErrMarkedDeleted
|
||||
}
|
||||
|
||||
// TODO: add snapshot logic
|
||||
res, err := s.changeFactory.CreateSpaceDeleteChange(t, s.state, false)
|
||||
err = s.verifyDeleteSpace(deleterId, raw)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return s.addContent(res)
|
||||
res, err := s.AddRawChanges(ctx, objecttree.RawChangesPayload{
|
||||
NewHeads: []string{raw.Id},
|
||||
RawChanges: []*treechangeproto.RawTreeChangeWithId{raw},
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !slices.Contains(res.Heads, raw.Id) {
|
||||
return ErrCantDeleteSpace
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *settingsObject) RestoreSpace() (err error) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
if s.state.SpaceDeletionDate.IsZero() {
|
||||
return ErrMarkedNotDeleted
|
||||
}
|
||||
|
||||
// TODO: add snapshot logic
|
||||
res, err := s.changeFactory.CreateSpaceRestoreChange(s.state, false)
|
||||
func (s *settingsObject) SpaceDeleteRawChange(deleterId string) (raw *treechangeproto.RawTreeChangeWithId, err error) {
|
||||
data, err := s.changeFactory.CreateSpaceDeleteChange(deleterId, s.state, false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return s.addContent(res)
|
||||
accountData := s.account.Account()
|
||||
return s.PrepareChange(objecttree.SignableChangeContent{
|
||||
Data: data,
|
||||
Key: accountData.SignKey,
|
||||
Identity: accountData.Identity,
|
||||
IsSnapshot: false,
|
||||
IsEncrypted: false,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *settingsObject) DeleteObject(id string) (err error) {
|
||||
|
@ -218,6 +234,24 @@ func (s *settingsObject) DeleteObject(id string) (err error) {
|
|||
return s.addContent(res)
|
||||
}
|
||||
|
||||
func (s *settingsObject) verifyDeleteSpace(peerId string, raw *treechangeproto.RawTreeChangeWithId) (err error) {
|
||||
data, err := s.UnpackChange(raw)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
content := &spacesyncproto.SettingsData{}
|
||||
err = proto.Unmarshal(data, content)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(content.GetContent()) != 1 ||
|
||||
content.GetContent()[0].GetSpaceDelete() == nil ||
|
||||
content.GetContent()[0].GetSpaceDelete().GetDeleterPeerId() != peerId {
|
||||
return ErrIncorrectDeleteChange
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *settingsObject) addContent(data []byte) (err error) {
|
||||
accountData := s.account.Account()
|
||||
_, err = s.AddContent(context.Background(), objecttree.SignableChangeContent{
|
||||
|
|
|
@ -2,13 +2,11 @@ package settingsstate
|
|||
|
||||
import (
|
||||
"github.com/anytypeio/any-sync/commonspace/spacesyncproto"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ChangeFactory interface {
|
||||
CreateObjectDeleteChange(id string, state *State, isSnapshot bool) (res []byte, err error)
|
||||
CreateSpaceDeleteChange(t time.Time, state *State, isSnapshot bool) (res []byte, err error)
|
||||
CreateSpaceRestoreChange(state *State, isSnapshot bool) (res []byte, err error)
|
||||
CreateSpaceDeleteChange(peerId string, state *State, isSnapshot bool) (res []byte, err error)
|
||||
}
|
||||
|
||||
func NewChangeFactory() ChangeFactory {
|
||||
|
@ -33,24 +31,9 @@ func (c *changeFactory) CreateObjectDeleteChange(id string, state *State, isSnap
|
|||
return
|
||||
}
|
||||
|
||||
func (c *changeFactory) CreateSpaceDeleteChange(t time.Time, state *State, isSnapshot bool) (res []byte, err error) {
|
||||
func (c *changeFactory) CreateSpaceDeleteChange(peerId string, state *State, isSnapshot bool) (res []byte, err error) {
|
||||
content := &spacesyncproto.SpaceSettingsContent_SpaceDelete{
|
||||
SpaceDelete: &spacesyncproto.SpaceDelete{Timestamp: t.UnixNano()},
|
||||
}
|
||||
change := &spacesyncproto.SettingsData{
|
||||
Content: []*spacesyncproto.SpaceSettingsContent{
|
||||
{Value: content},
|
||||
},
|
||||
Snapshot: nil,
|
||||
}
|
||||
// TODO: add snapshot logic
|
||||
res, err = change.Marshal()
|
||||
return
|
||||
}
|
||||
|
||||
func (c *changeFactory) CreateSpaceRestoreChange(state *State, isSnapshot bool) (res []byte, err error) {
|
||||
content := &spacesyncproto.SpaceSettingsContent_SpaceDelete{
|
||||
SpaceDelete: &spacesyncproto.SpaceDelete{},
|
||||
SpaceDelete: &spacesyncproto.SpaceDelete{DeleterPeerId: peerId},
|
||||
}
|
||||
change := &spacesyncproto.SettingsData{
|
||||
Content: []*spacesyncproto.SpaceSettingsContent{
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package settingsstate
|
||||
|
||||
import "time"
|
||||
|
||||
type State struct {
|
||||
DeletedIds []string
|
||||
SpaceDeletionDate time.Time
|
||||
LastIteratedId string
|
||||
DeletedIds []string
|
||||
DeleterId string
|
||||
LastIteratedId string
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"github.com/anytypeio/any-sync/commonspace/object/tree/objecttree"
|
||||
"github.com/anytypeio/any-sync/commonspace/spacesyncproto"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"time"
|
||||
)
|
||||
|
||||
type StateBuilder interface {
|
||||
|
@ -59,9 +58,9 @@ func (s *stateBuilder) processChange(change *objecttree.Change, rootId, startId
|
|||
// getting data from snapshot if we start from it
|
||||
if change.Id == rootId {
|
||||
state = &State{
|
||||
DeletedIds: deleteChange.Snapshot.DeletedIds,
|
||||
SpaceDeletionDate: time.Unix(0, deleteChange.Snapshot.SpaceDeletionTimestamp),
|
||||
LastIteratedId: rootId,
|
||||
DeletedIds: deleteChange.Snapshot.DeletedIds,
|
||||
DeleterId: deleteChange.Snapshot.DeleterPeerId,
|
||||
LastIteratedId: rootId,
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
@ -72,7 +71,7 @@ func (s *stateBuilder) processChange(change *objecttree.Change, rootId, startId
|
|||
case cnt.GetObjectDelete() != nil:
|
||||
state.DeletedIds = append(state.DeletedIds, cnt.GetObjectDelete().GetId())
|
||||
case cnt.GetSpaceDelete() != nil:
|
||||
state.SpaceDeletionDate = time.Unix(0, cnt.GetSpaceDelete().GetTimestamp())
|
||||
state.DeleterId = cnt.GetSpaceDelete().GetDeleterPeerId()
|
||||
}
|
||||
}
|
||||
return state
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue