mirror of
https://github.com/safing/portbase
synced 2025-09-02 10:40:39 +00:00
Merge pull request #32 from safing/feature/improve-storage-put
Improve database storage put method
This commit is contained in:
commit
c58d6a0f30
15 changed files with 59 additions and 48 deletions
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Add table
Reference in a new issue