Further wip badger
This commit is contained in:
parent
8a5b489c55
commit
8b45d698c2
@ -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
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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()
|
|
||||||
}
|
|
||||||
|
|||||||
@ -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))
|
||||||
|
|||||||
@ -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()
|
|
||||||
}
|
|
||||||
|
|||||||
34
pkg/acl/storage/helpers.go
Normal file
34
pkg/acl/storage/helpers.go
Normal 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()
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user