Compare commits

...

1 commit

Author SHA1 Message Date
e47a874711 initial db refactoring 2019-09-09 08:27:51 +02:00
5 changed files with 192 additions and 57 deletions

View file

@ -16,82 +16,131 @@ const (
) )
func (db *DB) GetPaths(res core.Results) { func (db *DB) GetPaths(res core.Results) {
db.store.Tx(false, func(tx store.KVStore) error {
for i, v := range res { for i, v := range res {
err := db.store.Get(pathPrefix+v.ID, &res[i].Path) err := tx.Get(pathPrefix+v.ID, &res[i].Path)
if err != nil { if err != nil {
res[i].Path = err.Error() res[i].Path = err.Error()
} }
} }
})
} }
func (db *DB) GetIndexed(p core.Paths) { func (db *DB) GetIndexed(p core.Paths) {
db.store.Tx(false, func(tx store.KVStore) error {
for i, v := range p { for i, v := range p {
p[i].Flag = db.IsIndexed(v.Abs) p[i].Flag = db.IsIndexed(tx, v.Abs)
p[i].Tags, _ = db.GetTag(v.Abs) p[i].Tags, _ = db.GetTag(tx, v.Abs)
} }
})
} }
func (db *DB) IsIndexed(path string) bool { func (db *DB) IsIndexed(tx store.KVStore, path string) bool {
return db.store.Get(idPrefix+path, nil) == nil f := func(tx store.KVStore) error {
return tx.Get(idPrefix+path, nil)
}
if tx != nil {
return f(tx) == nil
}
return f(db.store) == nil
} }
func (db *DB) GetPath(id string) (path string, err error) { func (db *DB) GetPath(tx store.KVStore, id string) (path string, err error) {
err = db.store.Get(pathPrefix+id, &path) f := func(tx store.KVStore) error {
return tx.Get(pathPrefix+id, &path)
}
if tx != nil {
err = f(tx)
return
}
err = f(db.store)
return return
} }
func (db *DB) GetID(path string) (id string, err error) { func (db *DB) GetID(tx store.KVStore, path string) (id string, err error) {
err = db.store.Get(idPrefix+path, &id) f := func(tx store.KVStore) error {
return tx.Get(idPrefix+path, &id)
}
if tx != nil {
err = f(tx)
return
}
err = f(db.store)
return return
} }
func (db *DB) DeletePath(id string) error { func (db *DB) DeletePath(tx store.KVStore, id string) error {
return db.store.Delete(pathPrefix + id) f := func(tx store.KVStore) error {
return tx.Delete(pathPrefix + id)
}
if tx != nil {
return f(tx)
}
return f(db.store)
} }
func (db *DB) DeleteID(path string) error { func (db *DB) DeleteID(tx store.KVStore, path string) error {
return db.store.Delete(idPrefix + path) f := func(tx store.KVStore) error {
return tx.Delete(idPrefix + path)
}
if tx != nil {
return f(tx)
}
return f(db.store)
} }
func (db *DB) NewFile(id, path string, tag []string) (err error) { func (db *DB) NewFile(tx store.KVStore, id, path string, tag []string) (err error) {
err = db.store.Set(idPrefix+path, id) f := func(tx store.KVStore) error {
err = tx.Set(idPrefix+path, id)
if err != nil { if err != nil {
return return
} }
err = db.store.Set(pathPrefix+id, path) err = tx.Set(pathPrefix+id, path)
if err != nil { if err != nil {
return return
} }
return db.SetTag(path, tag) return tx.Set(tagPrefix+path, tag)
}
if tx != nil {
return f(tx)
}
return db.store.Tx(true, f)
} }
func (db *DB) MoveFile(op, np string) (err error) { func (db *DB) MoveFile(op, np string) (err error) {
if !db.IsIndexed(op) { return db.store.Tx(true, func(tx store.KVStore) error {
return nil id, tag, err := db.DeleteFile(tx, op)
}
id, tag, err := db.DeleteFile(op)
if err != nil { if err != nil {
return return
} }
return db.NewFile(id, np, tag) return db.NewFile(tx, id, np, tag)
})
} }
func (db *DB) DeleteFile(path string) (id string, tag []string, err error) { func (db *DB) DeleteFile(tx store.KVStore, path string) (id string, tags []string, err error) {
if !db.IsIndexed(path) { f := func(tx store.KVStore) error {
return err = tx.Get(idPrefix+path, &id)
}
id, err = db.GetID(path)
if err != nil { if err != nil {
return return
} }
err = db.DeleteID(path) err = tx.Delete(idPrefix + path)
if err != nil { if err != nil {
return return
} }
tag, err = db.UnsetTag(path) err = tx.Get(tagPrefix+path, &tags)
if err != nil { if err != nil {
return return
} }
err = db.DeletePath(id) err = tx.Delete(tagPrefix + path)
if err != nil {
return
}
return tx.Delete(pathPrefix + id)
}
if tx != nil {
err = f(tx)
return
}
err = db.store.Tx(true, f)
return return
} }

View file

@ -84,6 +84,19 @@ func (bs *BoltStore) Restore(r io.Reader) (err error) {
}) })
} }
func (bs *BoltStore) Tx(writeable bool, f func(tx KVStore) error) error {
tx, err := db.db.Begin(writeable)
if err != nil {
return err
}
err = f(&BoltStoreTx{tx, bs})
if err != nil {
tx.Rollback()
return err
}
return tx.Commit()
}
func (bs *BoltStore) Get(key string, v interface{}) (err error) { func (bs *BoltStore) Get(key string, v interface{}) (err error) {
err = bs.db.View(func(tx *bolt.Tx) error { err = bs.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(defaultBoltBucket)).Get([]byte(key)) b := tx.Bucket([]byte(defaultBoltBucket)).Get([]byte(key))
@ -120,12 +133,23 @@ func (bs *BoltStore) ForEach(f func(string, []byte) error) error {
} }
func (bs *BoltStore) ForEachPrefix(prefix string, f func(string, []byte) error) error { func (bs *BoltStore) ForEachPrefix(prefix string, f func(string, []byte) error) error {
return bs.ForEach(func(k string, v []byte) error { return bs.db.View(func(tx *bolt.Tx) error {
if trim, ok := hasTrimPrefix(k, prefix); ok { c := tx.Bucket([]byte(defaultBoltBucket)).Cursor()
return f(trim, v) p := []byte(prefix)
for k, v := c.Seek(p); k != nil && bytes.HasPrefix(k, p); k, v = c.Next() {
err := f(trimPrefix(k, p), v)
if err != nil {
return err
}
} }
return nil return nil
}) })
//return bs.ForEach(func(k string, v []byte) error {
// if trim, ok := hasTrimPrefix(k, prefix); ok {
// return f(trim, v)
// }
// return nil
//})
} }
func (bs *BoltStore) Delete(key string) error { func (bs *BoltStore) Delete(key string) error {
@ -137,3 +161,52 @@ func (bs *BoltStore) Delete(key string) error {
func (bs *BoltStore) Close() error { func (bs *BoltStore) Close() error {
return bs.db.Close() return bs.db.Close()
} }
type BoltStoreTx struct {
tx *bolt.Tx
bs *BoltStore
}
func (tx *BoltStoreTx) Get(key string, v interface{}) (err error) {
b := tx.tx.Bucket([]byte(defaultBoltBucket)).Get([]byte(key))
if b == nil {
return ErrKeyNotFound
}
if v != nil {
return tx.bs.Unmarshal(b, v)
}
return nil
}
func (tx *BoltStoreTx) Set(key string, v interface{}) error {
var b []byte
if v != nil {
b, err = tx.bs.Marshal(v)
if err != nil {
return
}
}
return tx.tx.Bucket([]byte(defaultBoltBucket)).Put([]byte(key), b)
}
func (tx *BoltStoreTx) ForEach(f func(string, []byte) error) error {
return tx.tx.Bucket([]byte(defaultBoltBucket)).ForEach(func(k, v []byte) error {
return f(string(k), v)
})
}
func (tx *BoltStoreTx) ForEachPrefix(prefix string, f func(string, []byte) error) error {
c := tx.tx.Bucket([]byte(defaultBoltBucket)).Cursor()
p := []byte(prefix)
for k, v := c.Seek(p); k != nil && bytes.HasPrefix(k, p); k, v = c.Next() {
err := f(trimPrefix(k, p), v)
if err != nil {
return err
}
}
return nil
}
func (tx *BoltStoreTx) Delete(key string) error {
return tx.tx.Bucket([]byte(defaultBoltBucket)).Delete([]byte(key))
}

View file

@ -9,3 +9,8 @@ func hasTrimPrefix(s, prefix string) (string, bool) {
} }
return s, false return s, false
} }
// Parts taken from bytes.TrimPrefix
func trimPrefix(b, prefix []byte) string {
return string(b[len(prefix):])
}

11
pkg/store/kvstore.go Normal file
View file

@ -0,0 +1,11 @@
// Copyright (C) 2019 Marius Schellenberger
package store
type KVStore interface {
Get(string, interface{}) error
Set(string, interface{}) error
ForEach(func(string, []byte) error) error
ForEachPrefix(string, func(string, []byte) error) error
Delete(string) error
}

View file

@ -14,10 +14,7 @@ type Store interface {
Marshaler Marshaler
Dumper Dumper
Restorer Restorer
Get(string, interface{}) error KVStore
Set(string, interface{}) error Tx(writeable bool, f func(tx KVStore) error) error
ForEach(func(string, []byte) error) error
ForEachPrefix(string, func(string, []byte) error) error
Delete(string) error
Close() error Close() error
} }