Merge pull request #32 from safing/feature/improve-storage-put

Improve database storage put method
This commit is contained in:
Patrick Pacher 2020-04-15 17:59:33 +02:00 committed by GitHub
commit c58d6a0f30
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 59 additions and 48 deletions

View file

@ -36,26 +36,30 @@ func (s *StorageInterface) Get(key string) (record.Record, error) {
} }
// Put stores a record in the database. // Put stores a record in the database.
func (s *StorageInterface) Put(r record.Record) error { func (s *StorageInterface) Put(r record.Record) (record.Record, error) {
if r.Meta().Deleted > 0 { if r.Meta().Deleted > 0 {
return setConfigOption(r.DatabaseKey(), nil, false) return r, setConfigOption(r.DatabaseKey(), nil, false)
} }
acc := r.GetAccessor(r) acc := r.GetAccessor(r)
if acc == nil { if acc == nil {
return errors.New("invalid data") return nil, errors.New("invalid data")
} }
val, ok := acc.Get("Value") val, ok := acc.Get("Value")
if !ok || val == nil { if !ok || val == nil {
return setConfigOption(r.DatabaseKey(), nil, false) err := setConfigOption(r.DatabaseKey(), nil, false)
if err != nil {
return nil, err
}
return s.Get(r.DatabaseKey())
} }
optionsLock.RLock() optionsLock.RLock()
option, ok := options[r.DatabaseKey()] option, ok := options[r.DatabaseKey()]
optionsLock.RUnlock() optionsLock.RUnlock()
if !ok { if !ok {
return errors.New("config option does not exist") return nil, errors.New("config option does not exist")
} }
var value interface{} var value interface{}
@ -70,14 +74,14 @@ func (s *StorageInterface) Put(r record.Record) error {
value, ok = acc.GetBool("Value") value, ok = acc.GetBool("Value")
} }
if !ok { if !ok {
return errors.New("received invalid value in \"Value\"") return nil, errors.New("received invalid value in \"Value\"")
} }
err := setConfigOption(r.DatabaseKey(), value, false) err := setConfigOption(r.DatabaseKey(), value, false)
if err != nil { if err != nil {
return err return nil, err
} }
return nil return option.Export()
} }
// Delete deletes a record from the database. // Delete deletes a record from the database.

View file

@ -70,14 +70,14 @@ func (option *Option) Export() (record.Record, error) {
} }
if option.activeValue != nil { if option.activeValue != nil {
data, err = sjson.SetBytes(data, "Value", option.activeValue) data, err = sjson.SetBytes(data, "Value", option.activeValue.getData(option))
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
if option.activeDefaultValue != nil { if option.activeDefaultValue != nil {
data, err = sjson.SetBytes(data, "DefaultValue", option.activeDefaultValue) data, err = sjson.SetBytes(data, "DefaultValue", option.activeDefaultValue.getData(option))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -1,6 +1,7 @@
package database package database
import ( import (
"errors"
"sync" "sync"
"github.com/tevino/abool" "github.com/tevino/abool"
@ -119,10 +120,13 @@ func (c *Controller) Put(r record.Record) (err error) {
} }
} }
err = c.storage.Put(r) r, err = c.storage.Put(r)
if err != nil { if err != nil {
return err return err
} }
if r == nil {
return errors.New("storage returned nil record after successful put operation")
}
// process subscriptions // process subscriptions
for _, sub := range c.subscriptions { for _, sub := range c.subscriptions {

View file

@ -82,16 +82,19 @@ func (b *Badger) Get(key string) (record.Record, error) {
} }
// Put stores a record in the database. // Put stores a record in the database.
func (b *Badger) Put(r record.Record) error { func (b *Badger) Put(r record.Record) (record.Record, error) {
data, err := r.MarshalRecord(r) data, err := r.MarshalRecord(r)
if err != nil { if err != nil {
return err return nil, err
} }
err = b.db.Update(func(txn *badger.Txn) error { err = b.db.Update(func(txn *badger.Txn) error {
return txn.Set([]byte(r.DatabaseKey()), data) return txn.Set([]byte(r.DatabaseKey()), data)
}) })
return err if err != nil {
return nil, err
}
return r, nil
} }
// Delete deletes a record from the database. // Delete deletes a record from the database.

View file

@ -65,7 +65,7 @@ func TestBadger(t *testing.T) {
a.SetKey("test:A") a.SetKey("test:A")
// put record // put record
err = db.Put(a) _, err = db.Put(a)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View file

@ -86,10 +86,10 @@ func (b *BBolt) Get(key string) (record.Record, error) {
} }
// Put stores a record in the database. // Put stores a record in the database.
func (b *BBolt) Put(r record.Record) error { func (b *BBolt) Put(r record.Record) (record.Record, error) {
data, err := r.MarshalRecord(r) data, err := r.MarshalRecord(r)
if err != nil { if err != nil {
return err return nil, err
} }
err = b.db.Update(func(tx *bbolt.Tx) error { err = b.db.Update(func(tx *bbolt.Tx) error {
@ -100,9 +100,9 @@ func (b *BBolt) Put(r record.Record) error {
return nil return nil
}) })
if err != nil { if err != nil {
return err return nil, err
} }
return nil return r, nil
} }
// PutMany stores many records in the database. // PutMany stores many records in the database.

View file

@ -65,7 +65,7 @@ func TestBBolt(t *testing.T) {
a.SetKey("test:A") a.SetKey("test:A")
// put record // put record
err = db.Put(a) _, err = db.Put(a)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -100,15 +100,15 @@ func TestBBolt(t *testing.T) {
qZ.SetKey("test:z") qZ.SetKey("test:z")
qZ.CreateMeta() qZ.CreateMeta()
// put // put
err = db.Put(qA) _, err = db.Put(qA)
if err == nil { if err == nil {
err = db.Put(qB) _, err = db.Put(qB)
} }
if err == nil { if err == nil {
err = db.Put(qC) _, err = db.Put(qC)
} }
if err == nil { if err == nil {
err = db.Put(qZ) _, err = db.Put(qZ)
} }
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View file

@ -104,15 +104,15 @@ func (fst *FSTree) Get(key string) (record.Record, error) {
} }
// Put stores a record in the database. // Put stores a record in the database.
func (fst *FSTree) Put(r record.Record) error { func (fst *FSTree) Put(r record.Record) (record.Record, error) {
dstPath, err := fst.buildFilePath(r.DatabaseKey(), true) dstPath, err := fst.buildFilePath(r.DatabaseKey(), true)
if err != nil { if err != nil {
return err return nil, err
} }
data, err := r.MarshalRecord(r) data, err := r.MarshalRecord(r)
if err != nil { if err != nil {
return err return nil, err
} }
err = writeFile(dstPath, data, defaultFileMode) err = writeFile(dstPath, data, defaultFileMode)
@ -120,15 +120,15 @@ func (fst *FSTree) Put(r record.Record) error {
// create dir and try again // create dir and try again
err = os.MkdirAll(filepath.Dir(dstPath), defaultDirMode) err = os.MkdirAll(filepath.Dir(dstPath), defaultDirMode)
if err != nil { if err != nil {
return fmt.Errorf("fstree: failed to create directory %s: %s", filepath.Dir(dstPath), err) return nil, fmt.Errorf("fstree: failed to create directory %s: %s", filepath.Dir(dstPath), err)
} }
err = writeFile(dstPath, data, defaultFileMode) err = writeFile(dstPath, data, defaultFileMode)
if err != nil { if err != nil {
return fmt.Errorf("fstree: could not write file %s: %s", dstPath, err) return nil, fmt.Errorf("fstree: could not write file %s: %s", dstPath, err)
} }
} }
return nil return r, nil
} }
// Delete deletes a record from the database. // Delete deletes a record from the database.

View file

@ -44,12 +44,12 @@ func (hm *HashMap) Get(key string) (record.Record, error) {
} }
// Put stores a record in the database. // Put stores a record in the database.
func (hm *HashMap) Put(r record.Record) error { func (hm *HashMap) Put(r record.Record) (record.Record, error) {
hm.dbLock.Lock() hm.dbLock.Lock()
defer hm.dbLock.Unlock() defer hm.dbLock.Unlock()
hm.db[r.DatabaseKey()] = r hm.db[r.DatabaseKey()] = r
return nil return r, nil
} }
// PutMany stores many records in the database. // PutMany stores many records in the database.

View file

@ -57,7 +57,7 @@ func TestHashMap(t *testing.T) {
a.SetKey("test:A") a.SetKey("test:A")
// put record // put record
err = db.Put(a) _, err = db.Put(a)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -86,15 +86,15 @@ func TestHashMap(t *testing.T) {
qZ.SetKey("test:z") qZ.SetKey("test:z")
qZ.CreateMeta() qZ.CreateMeta()
// put // put
err = db.Put(qA) _, err = db.Put(qA)
if err == nil { if err == nil {
err = db.Put(qB) _, err = db.Put(qB)
} }
if err == nil { if err == nil {
err = db.Put(qC) _, err = db.Put(qC)
} }
if err == nil { if err == nil {
err = db.Put(qZ) _, err = db.Put(qZ)
} }
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View file

@ -21,8 +21,8 @@ func (i *InjectBase) Get(key string) (record.Record, error) {
} }
// Put stores a record in the database. // Put stores a record in the database.
func (i *InjectBase) Put(m record.Record) error { func (i *InjectBase) Put(m record.Record) (record.Record, error) {
return errNotImplemented return nil, errNotImplemented
} }
// PutMany stores many records in the database. // PutMany stores many records in the database.

View file

@ -9,7 +9,7 @@ import (
// Interface defines the database storage API. // Interface defines the database storage API.
type Interface interface { type Interface interface {
Get(key string) (record.Record, error) Get(key string) (record.Record, error)
Put(m record.Record) error Put(m record.Record) (record.Record, error)
Delete(key string) error Delete(key string) error
Query(q *query.Query, local, internal bool) (*iterator.Iterator, error) Query(q *query.Query, local, internal bool) (*iterator.Iterator, error)

View file

@ -36,8 +36,8 @@ func (s *Sinkhole) Get(key string) (record.Record, error) {
} }
// Put stores a record in the database. // Put stores a record in the database.
func (s *Sinkhole) Put(m record.Record) error { func (s *Sinkhole) Put(r record.Record) (record.Record, error) {
return nil return r, nil
} }
// PutMany stores many records in the database. // PutMany stores many records in the database.

View file

@ -41,7 +41,7 @@ func writeLine(line *logLine, duplicates uint64) {
} }
func startWriter() { func startWriter() {
fmt.Println(fmt.Sprintf("%s%s %s BOF%s", InfoLevel.color(), time.Now().Format(timeFormat), rightArrow, endColor())) fmt.Printf("%s%s %s BOF%s\n", InfoLevel.color(), time.Now().Format(timeFormat), rightArrow, endColor())
shutdownWaitGroup.Add(1) shutdownWaitGroup.Add(1)
go writerManager() go writerManager()
@ -168,7 +168,7 @@ func finalizeWriting() {
case line := <-logBuffer: case line := <-logBuffer:
writeLine(line, 0) writeLine(line, 0)
case <-time.After(10 * time.Millisecond): case <-time.After(10 * time.Millisecond):
fmt.Println(fmt.Sprintf("%s%s %s EOF%s", InfoLevel.color(), time.Now().Format(timeFormat), leftArrow, endColor())) fmt.Printf("%s%s %s EOF%s\n", InfoLevel.color(), time.Now().Format(timeFormat), leftArrow, endColor())
return return
} }
} }

View file

@ -111,26 +111,26 @@ func (s *StorageInterface) processQuery(q *query.Query, it *iterator.Iterator) {
} }
// Put stores a record in the database. // Put stores a record in the database.
func (s *StorageInterface) Put(r record.Record) error { func (s *StorageInterface) Put(r record.Record) (record.Record, error) {
// record is already locked! // record is already locked!
key := r.DatabaseKey() key := r.DatabaseKey()
n, err := EnsureNotification(r) n, err := EnsureNotification(r)
if err != nil { if err != nil {
return ErrInvalidData return nil, ErrInvalidData
} }
// transform key // transform key
if strings.HasPrefix(key, "all/") { if strings.HasPrefix(key, "all/") {
key = strings.TrimPrefix(key, "all/") key = strings.TrimPrefix(key, "all/")
} else { } else {
return ErrInvalidPath return nil, ErrInvalidPath
} }
// continue in goroutine // continue in goroutine
go UpdateNotification(n, key) go UpdateNotification(n, key)
return nil return n, nil
} }
// UpdateNotification updates a notification with input from a database action. Notification will not be saved/propagated if there is no valid change. // UpdateNotification updates a notification with input from a database action. Notification will not be saved/propagated if there is no valid change.