Further wip badger

This commit is contained in:
mcrakhman 2022-10-16 16:41:01 +02:00 committed by Mikhail Iudin
parent 8a5b489c55
commit 8b45d698c2
No known key found for this signature in database
GPG Key ID: FAAAA8BAABDFF1C0
10 changed files with 215 additions and 369 deletions

View File

@ -7,16 +7,11 @@ import (
var ErrIncorrectKey = errors.New("the key is incorrect") var ErrIncorrectKey = errors.New("the key is incorrect")
func Has(db *badger.DB, key []byte) (has bool, err error) { func Has(db *badger.DB, key []byte) bool {
err = db.View(func(txn *badger.Txn) error { return db.View(func(txn *badger.Txn) error {
_, err := txn.Get(key) _, err := txn.Get(key)
return err return err
}) }) == nil
if err != nil {
return
}
has = true
return
} }
func Put(db *badger.DB, key, value []byte) (err error) { func Put(db *badger.DB, key, value []byte) (err error) {
@ -40,37 +35,10 @@ func Get(db *badger.DB, key []byte) (value []byte, err error) {
return return
} }
func GetKeySuffix(txn *badger.Txn, keyPrefix []byte) (suffix []byte, err error) { func GetAndCopy(txn *badger.Txn, key []byte) (value []byte, err error) {
iter := txn.NewIterator(badger.IteratorOptions{Prefix: keyPrefix}) item, err := txn.Get(key)
iter.Next() if err != nil {
if !iter.Valid() {
err = badger.ErrKeyNotFound
return return
} }
return item.ValueCopy(value)
suffix = iter.Item().Key()
if len(suffix) <= len(keyPrefix)+1 {
err = ErrIncorrectKey
return
}
suffix = suffix[len(keyPrefix)+1:]
return
}
func GetKeySuffixAndValue(txn *badger.Txn, keyPrefix []byte) (suffix []byte, value []byte, err error) {
iter := txn.NewIterator(badger.IteratorOptions{Prefix: keyPrefix})
iter.Next()
if !iter.Valid() {
err = badger.ErrKeyNotFound
return
}
suffix = iter.Item().Key()
if len(suffix) <= len(keyPrefix)+1 {
err = ErrIncorrectKey
return
}
suffix = suffix[len(keyPrefix)+1:]
value, err = iter.Item().ValueCopy(value)
return
} }

View File

@ -1,7 +1,7 @@
package storage package storage
import ( import (
"bytes" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage"
) )
type aclKeys struct { type aclKeys struct {
@ -13,8 +13,8 @@ type aclKeys struct {
func newACLKeys(spaceId string) aclKeys { func newACLKeys(spaceId string) aclKeys {
return aclKeys{ return aclKeys{
spaceId: spaceId, spaceId: spaceId,
rootKey: joinStringsToBytes("space", spaceId, "a", "rootId"), rootKey: storage.JoinStringsToBytes("space", spaceId, "a", "rootId"),
headKey: joinStringsToBytes("space", spaceId, "a", "headId"), headKey: storage.JoinStringsToBytes("space", spaceId, "a", "headId"),
} }
} }
@ -27,7 +27,7 @@ func (a aclKeys) RootIdKey() []byte {
} }
func (a aclKeys) RawRecordKey(id string) []byte { func (a aclKeys) RawRecordKey(id string) []byte {
return joinStringsToBytes("space", a.spaceId, "a", id) return storage.JoinStringsToBytes("space", a.spaceId, "a", id)
} }
type treeKeys struct { type treeKeys struct {
@ -41,8 +41,8 @@ func newTreeKeys(spaceId, id string) treeKeys {
return treeKeys{ return treeKeys{
id: id, id: id,
spaceId: spaceId, spaceId: spaceId,
headsKey: joinStringsToBytes("space", spaceId, "t", id, "heads"), headsKey: storage.JoinStringsToBytes("space", spaceId, "t", id, "heads"),
rootKey: joinStringsToBytes("space", spaceId, "t", id), rootKey: storage.JoinStringsToBytes("space", spaceId, "t", "rootId", id),
} }
} }
@ -55,37 +55,25 @@ func (t treeKeys) RootIdKey() []byte {
} }
func (t treeKeys) RawChangeKey(id string) []byte { func (t treeKeys) RawChangeKey(id string) []byte {
return joinStringsToBytes("space", t.spaceId, "t", t.id, id) return storage.JoinStringsToBytes("space", t.spaceId, "t", t.id, id)
} }
type spaceKeys struct { type spaceKeys struct {
headerKey []byte headerKey []byte
treePrefixKey []byte
} }
func newSpaceKeys(spaceId string) spaceKeys { func newSpaceKeys(spaceId string) spaceKeys {
return spaceKeys{headerKey: joinStringsToBytes("space", spaceId)} return spaceKeys{
headerKey: storage.JoinStringsToBytes("space", spaceId),
treePrefixKey: storage.JoinStringsToBytes("space", spaceId, "t", "rootId"),
}
} }
func (s spaceKeys) HeaderKey() []byte { func (s spaceKeys) HeaderKey() []byte {
return s.headerKey return s.headerKey
} }
func joinStringsToBytes(strs ...string) []byte { func (s spaceKeys) TreeRootPrefix() []byte {
var ( return s.treePrefixKey
b bytes.Buffer
totalLen int
)
for _, s := range strs {
totalLen += len(s)
}
// adding separators
totalLen += len(strs) - 1
b.Grow(totalLen)
for idx, s := range strs {
if idx > 0 {
b.WriteString("/")
}
b.WriteString(s)
}
return b.Bytes()
} }

View File

@ -20,23 +20,13 @@ type listStorage struct {
func newListStorage(spaceId string, db *badger.DB, txn *badger.Txn) (ls storage.ListStorage, err error) { func newListStorage(spaceId string, db *badger.DB, txn *badger.Txn) (ls storage.ListStorage, err error) {
keys := newACLKeys(spaceId) keys := newACLKeys(spaceId)
rootId, err := provider.GetKeySuffix(txn, keys.RootIdKey()) rootId, err := provider.GetAndCopy(txn, keys.RootIdKey())
if err != nil { if err != nil {
if err == badger.ErrKeyNotFound {
err = storage.ErrUnknownACLId
}
return return
} }
stringId := string(rootId) stringId := string(rootId)
rootItem, err := txn.Get(keys.RawRecordKey(stringId)) value, err := provider.GetAndCopy(txn, keys.RawRecordKey(stringId))
if err != nil {
if err == badger.ErrKeyNotFound {
err = storage.ErrUnknownACLId
}
return
}
var value []byte
value, err = rootItem.ValueCopy(value)
if err != nil { if err != nil {
return return
} }
@ -57,19 +47,11 @@ func newListStorage(spaceId string, db *badger.DB, txn *badger.Txn) (ls storage.
func createListStorage(spaceId string, db *badger.DB, txn *badger.Txn, root *aclrecordproto.RawACLRecordWithId) (ls storage.ListStorage, err error) { func createListStorage(spaceId string, db *badger.DB, txn *badger.Txn, root *aclrecordproto.RawACLRecordWithId) (ls storage.ListStorage, err error) {
keys := newACLKeys(spaceId) keys := newACLKeys(spaceId)
_, err = provider.GetKeySuffix(txn, keys.RootIdKey()) _, err = provider.GetAndCopy(txn, keys.RootIdKey())
if err != nil && err != badger.ErrKeyNotFound { if err != badger.ErrKeyNotFound {
return
}
if err == nil { if err == nil {
err = storage.ErrACLExists return newListStorage(spaceId, db, txn)
return
} }
aclRootKey := append(keys.RootIdKey(), '/')
aclRootKey = append(aclRootKey, []byte(root.Id)...)
err = txn.Set(aclRootKey, nil)
if err != nil {
return return
} }
@ -82,6 +64,10 @@ func createListStorage(spaceId string, db *badger.DB, txn *badger.Txn, root *acl
if err != nil { if err != nil {
return return
} }
err = txn.Set(keys.RootIdKey(), []byte(root.Id))
if err != nil {
return
}
ls = &listStorage{ ls = &listStorage{
db: db, db: db,
@ -110,12 +96,11 @@ func (l *listStorage) Head() (head string, err error) {
} }
func (l *listStorage) GetRawRecord(ctx context.Context, id string) (raw *aclrecordproto.RawACLRecordWithId, err error) { func (l *listStorage) GetRawRecord(ctx context.Context, id string) (raw *aclrecordproto.RawACLRecordWithId, err error) {
res, err := l.db.Get(l.keys.RawRecordKey(id)) res, err := provider.Get(l.db, l.keys.RawRecordKey(id))
if err != nil { if err != nil {
return if err == badger.ErrKeyNotFound {
}
if res == nil {
err = storage.ErrUnknownRecord err = storage.ErrUnknownRecord
}
return return
} }
@ -127,5 +112,5 @@ func (l *listStorage) GetRawRecord(ctx context.Context, id string) (raw *aclreco
} }
func (l *listStorage) AddRawRecord(ctx context.Context, rec *aclrecordproto.RawACLRecordWithId) error { func (l *listStorage) AddRawRecord(ctx context.Context, rec *aclrecordproto.RawACLRecordWithId) error {
return l.db.Put([]byte(rec.Id), rec.Payload) return provider.Put(l.db, []byte(rec.Id), rec.Payload)
} }

View File

@ -1,23 +1,17 @@
package storage package storage
import ( import (
"github.com/akrylysov/pogreb"
provider "github.com/anytypeio/go-anytype-infrastructure-experiments/client/badgerprovider" provider "github.com/anytypeio/go-anytype-infrastructure-experiments/client/badgerprovider"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
spacestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" spacestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage"
"github.com/dgraph-io/badger/v3" "github.com/dgraph-io/badger/v3"
"path"
"sync" "sync"
"time"
) )
var defPogrebOptions = &pogreb.Options{
BackgroundCompactionInterval: time.Minute * 5,
}
type spaceStorage struct { type spaceStorage struct {
objDb *pogreb.DB spaceId string
objDb *badger.DB
keys spaceKeys keys spaceKeys
aclStorage storage.ListStorage aclStorage storage.ListStorage
header *spacesyncproto.RawSpaceHeaderWithId header *spacesyncproto.RawSpaceHeaderWithId
@ -26,37 +20,19 @@ type spaceStorage struct {
func newSpaceStorage(objDb *badger.DB, spaceId string) (store spacestorage.SpaceStorage, err error) { func newSpaceStorage(objDb *badger.DB, spaceId string) (store spacestorage.SpaceStorage, err error) {
keys := newSpaceKeys(spaceId) keys := newSpaceKeys(spaceId)
err = objDb.Update(func(txn *badger.Txn) error { err = objDb.View(func(txn *badger.Txn) error {
header, err := txn.Get(keys.HeaderKey()) header, err := provider.GetAndCopy(txn, keys.HeaderKey())
if err != nil { if err != nil {
return err return err
} }
}) aclStorage, err := newListStorage(spaceId, objDb, txn)
has, err := provider.Has(obj)
if err != nil { if err != nil {
return return err
}
if !has {
err = spacestorage.ErrSpaceStorageMissing
return
}
header, err := objDb.Get(keys.HeaderKey())
if err != nil {
return
}
if header == nil {
err = spacestorage.ErrSpaceStorageMissing
return
}
aclStorage, err := newListStorage(objDb)
if err != nil {
return
} }
store = &spaceStorage{ store = &spaceStorage{
spaceId: spaceId,
objDb: objDb, objDb: objDb,
keys: keys, keys: keys,
header: &spacesyncproto.RawSpaceHeaderWithId{ header: &spacesyncproto.RawSpaceHeaderWithId{
@ -65,58 +41,45 @@ func newSpaceStorage(objDb *badger.DB, spaceId string) (store spacestorage.Space
}, },
aclStorage: aclStorage, aclStorage: aclStorage,
} }
return nil
})
if err == badger.ErrKeyNotFound {
err = spacesyncproto.ErrSpaceMissing
}
return return
} }
func createSpaceStorage(rootPath string, payload spacestorage.SpaceStorageCreatePayload) (store spacestorage.SpaceStorage, err error) { func createSpaceStorage(db *badger.DB, payload spacestorage.SpaceStorageCreatePayload) (store spacestorage.SpaceStorage, err error) {
dbPath := path.Join(rootPath, payload.SpaceHeaderWithId.Id)
db, err := pogreb.Open(dbPath, defPogrebOptions)
if err != nil {
return
}
defer func() {
if err != nil {
db.Close()
}
}()
keys := newSpaceKeys(payload.SpaceHeaderWithId.Id) keys := newSpaceKeys(payload.SpaceHeaderWithId.Id)
has, err := db.Has(keys.SpaceIdKey()) if provider.Has(db, keys.HeaderKey()) {
if err != nil {
return
}
if has {
err = spacesyncproto.ErrSpaceExists err = spacesyncproto.ErrSpaceExists
return return
} }
err = db.Update(func(txn *badger.Txn) error {
aclStorage, err := createListStorage(db, payload.RecWithId) aclStorage, err := createListStorage(payload.SpaceHeaderWithId.Id, db, txn, payload.RecWithId)
if err != nil { if err != nil {
return return err
} }
err = db.Put(keys.HeaderKey(), payload.SpaceHeaderWithId.RawHeader) err = txn.Set(keys.HeaderKey(), payload.SpaceHeaderWithId.RawHeader)
if err != nil { if err != nil {
return return err
}
err = db.Put(keys.SpaceIdKey(), []byte(payload.SpaceHeaderWithId.Id))
if err != nil {
return
} }
store = &spaceStorage{ store = &spaceStorage{
spaceId: payload.SpaceHeaderWithId.Id,
objDb: db, objDb: db,
keys: keys, keys: keys,
aclStorage: aclStorage, aclStorage: aclStorage,
header: payload.SpaceHeaderWithId, header: payload.SpaceHeaderWithId,
} }
return nil
})
return return
} }
func (s *spaceStorage) TreeStorage(id string) (storage.TreeStorage, error) { func (s *spaceStorage) TreeStorage(id string) (storage.TreeStorage, error) {
return newTreeStorage(s.objDb, id) return newTreeStorage(s.objDb, s.spaceId, id)
} }
func (s *spaceStorage) CreateTreeStorage(payload storage.TreeStorageCreatePayload) (ts storage.TreeStorage, err error) { func (s *spaceStorage) CreateTreeStorage(payload storage.TreeStorageCreatePayload) (ts storage.TreeStorage, err error) {
@ -124,7 +87,7 @@ func (s *spaceStorage) CreateTreeStorage(payload storage.TreeStorageCreatePayloa
s.mx.Lock() s.mx.Lock()
defer s.mx.Unlock() defer s.mx.Unlock()
return createTreeStorage(s.objDb, payload) return createTreeStorage(s.objDb, s.spaceId, payload)
} }
func (s *spaceStorage) ACLStorage() (storage.ListStorage, error) { func (s *spaceStorage) ACLStorage() (storage.ListStorage, error) {
@ -136,21 +99,25 @@ func (s *spaceStorage) SpaceHeader() (header *spacesyncproto.RawSpaceHeaderWithI
} }
func (s *spaceStorage) StoredIds() (ids []string, err error) { func (s *spaceStorage) StoredIds() (ids []string, err error) {
index := s.objDb.Items() err = s.objDb.View(func(txn *badger.Txn) error {
opts := badger.DefaultIteratorOptions
opts.PrefetchValues = false
opts.Prefix = s.keys.TreeRootPrefix()
key, val, err := index.Next() it := txn.NewIterator(opts)
for err == nil { defer it.Close()
strKey := string(key)
if isRootIdKey(strKey) {
ids = append(ids, string(val))
}
key, val, err = index.Next()
}
if err != pogreb.ErrIterationDone { for it.Rewind(); it.Valid(); it.Next() {
return item := it.Item()
id := item.Key()
if len(id) <= len(s.keys.TreeRootPrefix())+1 {
continue
} }
err = nil id = id[len(s.keys.TreeRootPrefix())+1:]
ids = append(ids, string(id))
}
return nil
})
return return
} }

View File

@ -26,9 +26,9 @@ func (s *storageService) Name() (name string) {
} }
func (s *storageService) SpaceStorage(id string) (storage.SpaceStorage, error) { func (s *storageService) SpaceStorage(id string) (storage.SpaceStorage, error) {
return newSpaceStorage(s.rootPath, id) return newSpaceStorage(s.db, id)
} }
func (s *storageService) CreateSpaceStorage(payload storage.SpaceStorageCreatePayload) (storage.SpaceStorage, error) { func (s *storageService) CreateSpaceStorage(payload storage.SpaceStorageCreatePayload) (storage.SpaceStorage, error) {
return createSpaceStorage(s.rootPath, payload) return createSpaceStorage(s.db, payload)
} }

View File

@ -1,57 +1,37 @@
package storage package storage
import ( import (
"bytes"
"context" "context"
"github.com/akrylysov/pogreb" provider "github.com/anytypeio/go-anytype-infrastructure-experiments/client/badgerprovider"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto"
"strings" "github.com/dgraph-io/badger/v3"
) )
type treeStorage struct { type treeStorage struct {
db *pogreb.DB db *badger.DB
keys treeKeys keys treeKeys
id string id string
root *treechangeproto.RawTreeChangeWithId root *treechangeproto.RawTreeChangeWithId
} }
func newTreeStorage(db *pogreb.DB, treeId string) (ts storage.TreeStorage, err error) { func newTreeStorage(db *badger.DB, spaceId, treeId string) (ts storage.TreeStorage, err error) {
keys := newTreeKeys(treeId) keys := newTreeKeys(spaceId, treeId)
has, err := db.Has(keys.RootIdKey()) err = db.View(func(txn *badger.Txn) error {
_, err := txn.Get(keys.RootIdKey())
if err != nil { if err != nil {
return return err
}
if !has {
err = storage.ErrUnknownTreeId
return
} }
heads, err := db.Get(keys.HeadsKey()) root, err := provider.GetAndCopy(txn, keys.RawChangeKey(treeId))
if err != nil { if err != nil {
return return err
}
if heads == nil {
err = storage.ErrUnknownTreeId
return
}
root, err := db.Get(keys.RawChangeKey(treeId))
if err != nil {
return
}
if root == nil {
err = storage.ErrUnknownTreeId
return
} }
rootWithId := &treechangeproto.RawTreeChangeWithId{ rootWithId := &treechangeproto.RawTreeChangeWithId{
RawChange: root, RawChange: root,
Id: treeId, Id: treeId,
} }
if err != nil {
return
}
ts = &treeStorage{ ts = &treeStorage{
db: db, db: db,
@ -59,42 +39,40 @@ func newTreeStorage(db *pogreb.DB, treeId string) (ts storage.TreeStorage, err e
id: treeId, id: treeId,
root: rootWithId, root: rootWithId,
} }
return nil
})
return return
} }
func createTreeStorage(db *pogreb.DB, payload storage.TreeStorageCreatePayload) (ts storage.TreeStorage, err error) { func createTreeStorage(db *badger.DB, spaceId string, payload storage.TreeStorageCreatePayload) (ts storage.TreeStorage, err error) {
keys := newTreeKeys(payload.TreeId) keys := newTreeKeys(spaceId, payload.TreeId)
has, err := db.Has(keys.RootIdKey()) if provider.Has(db, keys.RootIdKey()) {
if err != nil {
return
}
if has {
err = storage.ErrTreeExists err = storage.ErrTreeExists
return return
} }
err = db.Update(func(txn *badger.Txn) error {
heads := createHeadsPayload(payload.Heads) heads := storage.CreateHeadsPayload(payload.Heads)
for _, ch := range payload.Changes { for _, ch := range payload.Changes {
err = db.Put(keys.RawChangeKey(ch.Id), ch.GetRawChange()) err = txn.Set(keys.RawChangeKey(ch.Id), ch.GetRawChange())
if err != nil { if err != nil {
return return err
} }
} }
err = db.Put(keys.RawChangeKey(payload.RootRawChange.Id), payload.RootRawChange.GetRawChange()) err = txn.Set(keys.RawChangeKey(payload.RootRawChange.Id), payload.RootRawChange.GetRawChange())
if err != nil { if err != nil {
return return err
} }
err = db.Put(keys.HeadsKey(), heads) err = txn.Set(keys.HeadsKey(), heads)
if err != nil { if err != nil {
return return err
} }
err = db.Put(keys.RootIdKey(), []byte(payload.RootRawChange.Id)) err = txn.Set(keys.RootIdKey(), nil)
if err != nil { if err != nil {
return return err
} }
ts = &treeStorage{ ts = &treeStorage{
@ -103,6 +81,8 @@ func createTreeStorage(db *pogreb.DB, payload storage.TreeStorageCreatePayload)
id: payload.RootRawChange.Id, id: payload.RootRawChange.Id,
root: payload.RootRawChange, root: payload.RootRawChange,
} }
return nil
})
return return
} }
@ -115,34 +95,33 @@ func (t *treeStorage) Root() (raw *treechangeproto.RawTreeChangeWithId, err erro
} }
func (t *treeStorage) Heads() (heads []string, err error) { func (t *treeStorage) Heads() (heads []string, err error) {
headsBytes, err := t.db.Get(t.keys.HeadsKey()) headsBytes, err := provider.Get(t.db, t.keys.HeadsKey())
if err != nil { if err != nil {
return if err == badger.ErrKeyNotFound {
}
if heads == nil {
err = storage.ErrUnknownTreeId err = storage.ErrUnknownTreeId
}
return return
} }
heads = parseHeads(headsBytes) heads = storage.ParseHeads(headsBytes)
return return
} }
func (t *treeStorage) SetHeads(heads []string) (err error) { func (t *treeStorage) SetHeads(heads []string) (err error) {
payload := createHeadsPayload(heads) payload := storage.CreateHeadsPayload(heads)
return t.db.Put(t.keys.HeadsKey(), payload) return provider.Put(t.db, t.keys.HeadsKey(), payload)
} }
func (t *treeStorage) AddRawChange(change *treechangeproto.RawTreeChangeWithId) (err error) { func (t *treeStorage) AddRawChange(change *treechangeproto.RawTreeChangeWithId) (err error) {
return t.db.Put([]byte(change.Id), change.RawChange) return provider.Put(t.db, t.keys.RawChangeKey(change.Id), change.RawChange)
} }
func (t *treeStorage) GetRawChange(ctx context.Context, id string) (raw *treechangeproto.RawTreeChangeWithId, err error) { func (t *treeStorage) GetRawChange(ctx context.Context, id string) (raw *treechangeproto.RawTreeChangeWithId, err error) {
res, err := t.db.Get(t.keys.RawChangeKey(id)) res, err := provider.Get(t.db, t.keys.RawChangeKey(id))
if err != nil { if err != nil {
return if err == badger.ErrKeyNotFound {
err = storage.ErrUnknownTreeId
} }
if res == nil { return
err = storage.ErrUnkownChange
} }
raw = &treechangeproto.RawTreeChangeWithId{ raw = &treechangeproto.RawTreeChangeWithId{
@ -153,29 +132,5 @@ func (t *treeStorage) GetRawChange(ctx context.Context, id string) (raw *treecha
} }
func (t *treeStorage) HasChange(ctx context.Context, id string) (bool, error) { func (t *treeStorage) HasChange(ctx context.Context, id string) (bool, error) {
return t.db.Has(t.keys.RawChangeKey(id)) return provider.Has(t.db, t.keys.RawChangeKey(id)), nil
}
func parseHeads(headsPayload []byte) []string {
return strings.Split(string(headsPayload), "/")
}
func createHeadsPayload(heads []string) []byte {
var (
b bytes.Buffer
totalLen int
)
for _, s := range heads {
totalLen += len(s)
}
// adding separators
totalLen += len(heads) - 1
b.Grow(totalLen)
for idx, s := range heads {
if idx > 0 {
b.WriteString("/")
}
b.WriteString(s)
}
return b.Bytes()
} }

View File

@ -1,7 +1,7 @@
package storage package storage
import ( import (
"bytes" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage"
"strings" "strings"
) )
@ -20,7 +20,7 @@ func (a aclKeys) RootIdKey() []byte {
} }
func (a aclKeys) RawRecordKey(id string) []byte { func (a aclKeys) RawRecordKey(id string) []byte {
return joinStringsToBytes("a", id) return storage.JoinStringsToBytes("a", id)
} }
type treeKeys struct { type treeKeys struct {
@ -31,7 +31,7 @@ type treeKeys struct {
func newTreeKeys(id string) treeKeys { func newTreeKeys(id string) treeKeys {
return treeKeys{ return treeKeys{
id: id, id: id,
headsKey: joinStringsToBytes("t", id, "heads"), headsKey: storage.JoinStringsToBytes("t", id, "heads"),
} }
} }
@ -40,7 +40,7 @@ func (t treeKeys) HeadsKey() []byte {
} }
func (t treeKeys) RawChangeKey(id string) []byte { func (t treeKeys) RawChangeKey(id string) []byte {
return joinStringsToBytes("t", t.id, id) return storage.JoinStringsToBytes("t", t.id, id)
} }
type spaceKeys struct { type spaceKeys struct {
@ -48,7 +48,7 @@ type spaceKeys struct {
} }
func newSpaceKeys(spaceId string) spaceKeys { func newSpaceKeys(spaceId string) spaceKeys {
return spaceKeys{headerKey: joinStringsToBytes("s", spaceId)} return spaceKeys{headerKey: storage.JoinStringsToBytes("s", spaceId)}
} }
var spaceIdKey = []byte("spaceId") var spaceIdKey = []byte("spaceId")
@ -64,23 +64,3 @@ func (s spaceKeys) HeaderKey() []byte {
func isRootIdKey(key string) bool { func isRootIdKey(key string) bool {
return strings.HasPrefix(key, "t/") && strings.HasSuffix(key, "rootId") return strings.HasPrefix(key, "t/") && strings.HasSuffix(key, "rootId")
} }
func joinStringsToBytes(strs ...string) []byte {
var (
b bytes.Buffer
totalLen int
)
for _, s := range strs {
totalLen += len(s)
}
// adding separators
totalLen += len(strs) - 1
b.Grow(totalLen)
for idx, s := range strs {
if idx > 0 {
b.WriteString("/")
}
b.WriteString(s)
}
return b.Bytes()
}

View File

@ -55,8 +55,7 @@ func createListStorage(db *pogreb.DB, root *aclrecordproto.RawACLRecordWithId) (
return return
} }
if has { if has {
err = storage.ErrACLExists return newListStorage(db)
return
} }
err = db.Put(keys.HeadIdKey(), []byte(root.Id)) err = db.Put(keys.HeadIdKey(), []byte(root.Id))

View File

@ -1,12 +1,10 @@
package storage package storage
import ( import (
"bytes"
"context" "context"
"github.com/akrylysov/pogreb" "github.com/akrylysov/pogreb"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto"
"strings"
) )
type treeStorage struct { type treeStorage struct {
@ -40,10 +38,6 @@ func newTreeStorage(db *pogreb.DB, treeId string) (ts storage.TreeStorage, err e
RawChange: root, RawChange: root,
Id: treeId, Id: treeId,
} }
if err != nil {
return
}
ts = &treeStorage{ ts = &treeStorage{
db: db, db: db,
keys: keys, keys: keys,
@ -64,7 +58,7 @@ func createTreeStorage(db *pogreb.DB, payload storage.TreeStorageCreatePayload)
return return
} }
heads := createHeadsPayload(payload.Heads) heads := storage.CreateHeadsPayload(payload.Heads)
for _, ch := range payload.Changes { for _, ch := range payload.Changes {
err = db.Put(keys.RawChangeKey(ch.Id), ch.GetRawChange()) err = db.Put(keys.RawChangeKey(ch.Id), ch.GetRawChange())
@ -109,17 +103,17 @@ func (t *treeStorage) Heads() (heads []string, err error) {
err = storage.ErrUnknownTreeId err = storage.ErrUnknownTreeId
return return
} }
heads = parseHeads(headsBytes) heads = storage.ParseHeads(headsBytes)
return return
} }
func (t *treeStorage) SetHeads(heads []string) (err error) { func (t *treeStorage) SetHeads(heads []string) (err error) {
payload := createHeadsPayload(heads) payload := storage.CreateHeadsPayload(heads)
return t.db.Put(t.keys.HeadsKey(), payload) return t.db.Put(t.keys.HeadsKey(), payload)
} }
func (t *treeStorage) AddRawChange(change *treechangeproto.RawTreeChangeWithId) (err error) { func (t *treeStorage) AddRawChange(change *treechangeproto.RawTreeChangeWithId) (err error) {
return t.db.Put([]byte(change.Id), change.RawChange) return t.db.Put(t.keys.RawChangeKey(change.Id), change.RawChange)
} }
func (t *treeStorage) GetRawChange(ctx context.Context, id string) (raw *treechangeproto.RawTreeChangeWithId, err error) { func (t *treeStorage) GetRawChange(ctx context.Context, id string) (raw *treechangeproto.RawTreeChangeWithId, err error) {
@ -141,27 +135,3 @@ func (t *treeStorage) GetRawChange(ctx context.Context, id string) (raw *treecha
func (t *treeStorage) HasChange(ctx context.Context, id string) (bool, error) { func (t *treeStorage) HasChange(ctx context.Context, id string) (bool, error) {
return t.db.Has(t.keys.RawChangeKey(id)) return t.db.Has(t.keys.RawChangeKey(id))
} }
func parseHeads(headsPayload []byte) []string {
return strings.Split(string(headsPayload), "/")
}
func createHeadsPayload(heads []string) []byte {
var (
b bytes.Buffer
totalLen int
)
for _, s := range heads {
totalLen += len(s)
}
// adding separators
totalLen += len(heads) - 1
b.Grow(totalLen)
for idx, s := range heads {
if idx > 0 {
b.WriteString("/")
}
b.WriteString(s)
}
return b.Bytes()
}

View File

@ -0,0 +1,34 @@
package storage
import (
"bytes"
"strings"
)
func ParseHeads(headsPayload []byte) []string {
return strings.Split(string(headsPayload), "/")
}
func CreateHeadsPayload(heads []string) []byte {
return JoinStringsToBytes(heads...)
}
func JoinStringsToBytes(strs ...string) []byte {
var (
b bytes.Buffer
totalLen int
)
for _, s := range strs {
totalLen += len(s)
}
// adding separators
totalLen += len(strs) - 1
b.Grow(totalLen)
for idx, s := range strs {
if idx > 0 {
b.WriteString("/")
}
b.WriteString(s)
}
return b.Bytes()
}