1
0
Fork 0
mirror of https://github.com/anyproto/any-sync.git synced 2025-06-09 17:45:03 +09:00

Use headstorage in objecttree tests

This commit is contained in:
mcrakhman 2024-12-03 20:48:56 +01:00
parent 5492a43920
commit 7600889730
No known key found for this signature in database
GPG key ID: DED12CFEF5B8396B
5 changed files with 89 additions and 63 deletions

View file

@ -38,6 +38,7 @@ type EntryIterator func(entry HeadsEntry) (bool, error)
type HeadStorage interface {
IterateEntries(ctx context.Context, iter EntryIterator) error
GetEntry(ctx context.Context, id string) (HeadsEntry, error)
DeleteEntryTx(txCtx context.Context, id string) error
UpdateEntryTx(txCtx context.Context, update HeadsUpdate) error
}
@ -105,6 +106,10 @@ func (h *headStorage) UpdateEntryTx(ctx context.Context, update HeadsUpdate) (er
return
}
func (h *headStorage) DeleteEntryTx(ctx context.Context, id string) error {
return h.headsColl.DeleteId(ctx, id)
}
func (h *headStorage) entryFromDoc(doc anystore.Doc) HeadsEntry {
return HeadsEntry{
Id: doc.Value().GetString(idKey),

View file

@ -18,6 +18,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/anyproto/any-sync/commonspace/headsync/headstorage"
"github.com/anyproto/any-sync/commonspace/object/accountdata"
"github.com/anyproto/any-sync/commonspace/object/acl/list"
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
@ -308,7 +309,9 @@ func TestObjectTree(t *testing.T) {
IsEncrypted: true,
}, aAccount.Acl)
require.NoError(t, err)
aStore, err := CreateStorage(ctx, root, store)
aHeadsStorage, err := headstorage.New(ctx, store)
require.NoError(t, err)
aStore, err := CreateStorage(ctx, root, aHeadsStorage, store)
require.NoError(t, err)
aTree, err := BuildKeyFilterableObjectTree(aStore, aAccount.Acl)
require.NoError(t, err)
@ -359,7 +362,9 @@ func TestObjectTree(t *testing.T) {
IsEncrypted: true,
}, aAccount.Acl)
require.NoError(t, err)
aStore, err := CreateStorage(ctx, root, storeA)
aHeadsStorage, err := headstorage.New(ctx, storeA)
require.NoError(t, err)
aStore, err := CreateStorage(ctx, root, aHeadsStorage, storeA)
require.NoError(t, err)
aTree, err := BuildKeyFilterableObjectTree(aStore, aAccount.Acl)
require.NoError(t, err)
@ -372,7 +377,9 @@ func TestObjectTree(t *testing.T) {
})
require.NoError(t, err)
storeB := copyStore(ctx, t, storeA.(testStore), "b")
bStore, err := NewStorage(ctx, root.Id, storeB)
bHeadsStorage, err := headstorage.New(ctx, storeB)
require.NoError(t, err)
bStore, err := NewStorage(ctx, root.Id, bHeadsStorage, storeB)
require.NoError(t, err)
bTree, err := BuildKeyFilterableObjectTree(bStore, bAccount.Acl)
require.NoError(t, err)
@ -447,7 +454,9 @@ func TestObjectTree(t *testing.T) {
IsEncrypted: true,
}, aAccount.Acl)
require.NoError(t, err)
aStore, err := CreateStorage(ctx, root, storeA)
aHeadsStorage, err := headstorage.New(ctx, storeA)
require.NoError(t, err)
aStore, err := CreateStorage(ctx, root, aHeadsStorage, storeA)
require.NoError(t, err)
aTree, err := BuildKeyFilterableObjectTree(aStore, aAccount.Acl)
require.NoError(t, err)
@ -460,7 +469,9 @@ func TestObjectTree(t *testing.T) {
})
require.NoError(t, err)
storeB := copyStore(ctx, t, storeA.(testStore), "b")
bStore, err := NewStorage(ctx, root.Id, storeB)
bHeadsStorage, err := headstorage.New(ctx, storeB)
require.NoError(t, err)
bStore, err := NewStorage(ctx, root.Id, bHeadsStorage, storeB)
require.NoError(t, err)
// copying old version of storage
prevAclRecs, err := bAccount.Acl.RecordsAfter(ctx, "")
@ -512,7 +523,10 @@ func TestObjectTree(t *testing.T) {
}, aclList)
require.NoError(t, err)
store := createStore(ctx, t)
storage, _ := CreateStorage(ctx, root, store)
headsStorage, err := headstorage.New(ctx, store)
require.NoError(t, err)
storage, err := CreateStorage(ctx, root, headsStorage, store)
require.NoError(t, err)
oTree, err := BuildObjectTree(storage, aclList)
require.NoError(t, err)
@ -582,7 +596,10 @@ func TestObjectTree(t *testing.T) {
}, aclList)
require.NoError(t, err)
store := createStore(ctx, t)
storage, _ := CreateStorage(ctx, root, store)
headsStorage, err := headstorage.New(ctx, store)
require.NoError(t, err)
storage, err := CreateStorage(ctx, root, headsStorage, store)
require.NoError(t, err)
oTree, err := BuildObjectTree(storage, aclList)
require.NoError(t, err)
emptyDataTreeDeps = nonVerifiableTreeDeps
@ -604,7 +621,10 @@ func TestObjectTree(t *testing.T) {
}, aclList)
require.NoError(t, err)
store := createStore(ctx, t)
storage, _ := CreateStorage(ctx, root, store)
headsStorage, err := headstorage.New(ctx, store)
require.NoError(t, err)
storage, err := CreateStorage(ctx, root, headsStorage, store)
require.NoError(t, err)
oTree, err := BuildObjectTree(storage, aclList)
require.NoError(t, err)
validateStore := createStore(ctx, t)
@ -638,7 +658,10 @@ func TestObjectTree(t *testing.T) {
}, aclList)
require.NoError(t, err)
store := createStore(ctx, t)
storage, _ := CreateStorage(ctx, root, store)
headsStorage, err := headstorage.New(ctx, store)
require.NoError(t, err)
storage, err := CreateStorage(ctx, root, headsStorage, store)
require.NoError(t, err)
oTree, err := BuildObjectTree(storage, aclList)
require.NoError(t, err)
_, err = oTree.AddContent(ctx, SignableChangeContent{
@ -685,7 +708,10 @@ func TestObjectTree(t *testing.T) {
require.NoError(t, err)
emptyDataTreeDeps = nonVerifiableTreeDeps
store := createStore(ctx, t)
storage, _ := CreateStorage(ctx, root, store)
headsStorage, err := headstorage.New(ctx, store)
require.NoError(t, err)
storage, err := CreateStorage(ctx, root, headsStorage, store)
require.NoError(t, err)
oTree, err := BuildObjectTree(storage, aclList)
require.NoError(t, err)
_, err = oTree.AddContent(ctx, SignableChangeContent{

View file

@ -6,6 +6,7 @@ import (
anystore "github.com/anyproto/any-store"
"github.com/anyproto/any-sync/commonspace/headsync/headstorage"
"github.com/anyproto/any-sync/commonspace/object/acl/list"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/anyproto/any-sync/util/slice"
@ -20,7 +21,12 @@ type tempTreeStorageCreator struct {
}
func (t *tempTreeStorageCreator) CreateTreeStorage(payload treestorage.TreeStorageCreatePayload) (Storage, error) {
return CreateStorage(context.Background(), payload.RootRawChange, t.store)
ctx := context.Background()
headStorage, err := headstorage.New(ctx, t.store)
if err != nil {
return nil, err
}
return CreateStorage(ctx, payload.RootRawChange, headStorage, t.store)
}
type ValidatorFunc func(payload treestorage.TreeStorageCreatePayload, storageCreator TreeStorageCreator, aclList list.AclList) (ret ObjectTree, err error)

View file

@ -9,22 +9,20 @@ import (
"github.com/anyproto/any-store/anyenc"
"github.com/anyproto/any-store/query"
"github.com/anyproto/any-sync/commonspace/headsync/headstorage"
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anyproto/any-sync/util/crypto"
"github.com/anyproto/any-sync/util/storeutil"
)
const (
orderKey = "o"
headsKey = "h"
commonSnapshotKey = "s"
idKey = "id"
rawChangeKey = "r"
snapshotCounterKey = "sc"
changeSizeKey = "sz"
snapshotIdKey = "i"
prevIdsKey = "p"
headsCollectionName = "heads"
orderKey = "o"
idKey = "id"
rawChangeKey = "r"
snapshotCounterKey = "sc"
changeSizeKey = "sz"
snapshotIdKey = "i"
prevIdsKey = "p"
)
type StorageChange struct {
@ -62,17 +60,18 @@ type Storage interface {
type storage struct {
id string
store anystore.DB
headsColl anystore.Collection
headStorage headstorage.HeadStorage
changesColl anystore.Collection
arena *anyenc.Arena
}
var storageChangeBuilder = NewChangeBuilder
func CreateStorage(ctx context.Context, root *treechangeproto.RawTreeChangeWithId, store anystore.DB) (Storage, error) {
func CreateStorage(ctx context.Context, root *treechangeproto.RawTreeChangeWithId, headStorage headstorage.HeadStorage, store anystore.DB) (Storage, error) {
st := &storage{
id: root.Id,
store: store,
id: root.Id,
store: store,
headStorage: headStorage,
}
builder := storageChangeBuilder(crypto.NewKeyStorage(), root)
_, err := builder.Unmarshall(root, true)
@ -88,11 +87,6 @@ func CreateStorage(ctx context.Context, root *treechangeproto.RawTreeChangeWithI
OrderId: firstOrder,
ChangeSize: len(root.RawChange),
}
headsColl, err := store.Collection(ctx, headsCollectionName)
if err != nil {
return nil, err
}
st.headsColl = headsColl
changesColl, err := store.Collection(ctx, root.Id)
if err != nil {
return nil, err
@ -119,11 +113,11 @@ func CreateStorage(ctx context.Context, root *treechangeproto.RawTreeChangeWithI
tx.Rollback()
return nil, err
}
headsDoc := st.arena.NewObject()
headsDoc.Set(headsKey, storeutil.NewStringArrayValue([]string{root.Id}, st.arena))
headsDoc.Set(commonSnapshotKey, st.arena.NewString(root.Id))
headsDoc.Set(idKey, st.arena.NewString(root.Id))
err = st.headsColl.Insert(tx.Context(), headsDoc)
err = st.headStorage.UpdateEntryTx(tx.Context(), headstorage.HeadsUpdate{
Id: root.Id,
Heads: []string{root.Id},
CommonSnapshot: &root.Id,
})
if err != nil {
tx.Rollback()
return nil, err
@ -131,17 +125,12 @@ func CreateStorage(ctx context.Context, root *treechangeproto.RawTreeChangeWithI
return st, tx.Commit()
}
func NewStorage(ctx context.Context, id string, store anystore.DB) (Storage, error) {
// TODO: use spacestorage to set heads
func NewStorage(ctx context.Context, id string, headStorage headstorage.HeadStorage, store anystore.DB) (Storage, error) {
st := &storage{
id: id,
store: store,
id: id,
store: store,
headStorage: headStorage,
}
headsColl, err := store.Collection(ctx, headsCollectionName)
if err != nil {
return nil, err
}
st.headsColl = headsColl
changesColl, err := store.Collection(ctx, id)
if err != nil {
return nil, err
@ -161,20 +150,15 @@ func NewStorage(ctx context.Context, id string, store anystore.DB) (Storage, err
}
func (s *storage) Heads(ctx context.Context) (res []string, err error) {
doc, err := s.headsColl.FindId(ctx, s.id)
headsEntry, err := s.headStorage.GetEntry(ctx, s.id)
if err != nil {
return nil, err
return
}
res = make([]string, 0, len(res))
heads := doc.Value().GetArray(headsKey)
for _, h := range heads {
res = append(res, h.GetString())
}
return
return headsEntry.Heads, nil
}
func (s *storage) Has(ctx context.Context, id string) (bool, error) {
_, err := s.headsColl.FindId(ctx, s.id)
_, err := s.changesColl.FindId(ctx, id)
if err != nil {
if errors.Is(err, anystore.ErrDocNotFound) {
return false, nil
@ -226,12 +210,12 @@ func (s *storage) AddAll(ctx context.Context, changes []StorageChange, heads []s
tx.Rollback()
return nil
}
mod := query.ModifyFunc(func(a *anyenc.Arena, v *anyenc.Value) (result *anyenc.Value, modified bool, err error) {
v.Set(headsKey, storeutil.NewStringArrayValue(heads, a))
v.Set(commonSnapshotKey, a.NewString(commonSnapshot))
return v, true, nil
})
_, err = s.headsColl.UpsertId(tx.Context(), s.id, mod)
update := headstorage.HeadsUpdate{
Id: s.id,
Heads: heads,
CommonSnapshot: &commonSnapshot,
}
err = s.headStorage.UpdateEntryTx(tx.Context(), update)
if err != nil {
tx.Rollback()
return nil
@ -249,7 +233,7 @@ func (s *storage) Delete(ctx context.Context) error {
tx.Rollback()
return fmt.Errorf("failed to delete changes collection: %w", err)
}
err = s.headsColl.DeleteId(tx.Context(), s.id)
err = s.headStorage.DeleteEntryTx(tx.Context(), s.id)
if err != nil {
tx.Rollback()
return fmt.Errorf("failed to remove document from heads collection: %w", err)
@ -271,11 +255,11 @@ func (s *storage) Root(ctx context.Context) (StorageChange, error) {
func (s *storage) CommonSnapshot(ctx context.Context) (string, error) {
// TODO: cache this in memory if needed
doc, err := s.headsColl.FindId(ctx, s.id)
entry, err := s.headStorage.GetEntry(ctx, s.id)
if err != nil {
return "", err
}
return doc.Value().GetString(commonSnapshotKey), nil
return entry.CommonSnapshot, nil
}
func (s *storage) Get(ctx context.Context, id string) (StorageChange, error) {

View file

@ -9,6 +9,7 @@ import (
libcrypto "github.com/libp2p/go-libp2p/core/crypto"
"github.com/stretchr/testify/require"
"github.com/anyproto/any-sync/commonspace/headsync/headstorage"
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anyproto/any-sync/util/crypto"
)
@ -164,7 +165,11 @@ func (c *MockChangeCreator) CreateNewTreeStorage(t *testing.T, treeId, aclHeadId
ChangeBuilder: NewChangeBuilder(newMockKeyStorage(), rootChange),
}
}
storage, err := CreateStorage(context.Background(), root, c.storeCreator())
ctx := context.Background()
store := c.storeCreator()
headStorage, err := headstorage.New(ctx, store)
require.NoError(t, err)
storage, err := CreateStorage(ctx, root, headStorage, store)
require.NoError(t, err)
return &testStorage{
Storage: storage,