From 3d604313768adab49a8fa8f2fb7a31afea6b2070 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 7 Sep 2018 19:15:40 +0200 Subject: [PATCH] Work on datbase controller --- database/controller.go | 59 ++++++++++++++++++++ database/database.go | 5 +- database/query/fetcher.go | 78 --------------------------- database/storage/badger/badger.go | 17 +++--- database/storage/interface.go | 1 + database/storage/sinkhole/sinkhole.go | 7 ++- 6 files changed, 77 insertions(+), 90 deletions(-) delete mode 100644 database/query/fetcher.go diff --git a/database/controller.go b/database/controller.go index 428f319..7a967d4 100644 --- a/database/controller.go +++ b/database/controller.go @@ -1,6 +1,7 @@ package database import ( + "errors" "sync" "time" @@ -35,6 +36,9 @@ func (c *Controller) Get(key string) (record.Record, error) { return nil, err } + r.Lock() + defer r.Unlock() + if !r.Meta().CheckValidity(time.Now().Unix()) { return nil, ErrNotFound } @@ -44,14 +48,27 @@ func (c *Controller) Get(key string) (record.Record, error) { // Put saves a record in the database. func (c *Controller) Put(r record.Record) error { + if c.storage.ReadOnly() { + return ErrReadOnly + } + return c.storage.Put(r) } +// Delete a record from the database. func (c *Controller) Delete(key string) error { + if c.storage.ReadOnly() { + return ErrReadOnly + } + r, err := c.Get(key) if err != nil { return err } + + r.Lock() + defer r.Unlock() + r.Meta().Deleted = time.Now().Unix() return c.Put(r) } @@ -59,10 +76,36 @@ func (c *Controller) Delete(key string) error { // Partial // What happens if I mutate a value that does not yet exist? How would I know its type? func (c *Controller) InsertPartial(key string, partialObject interface{}) error { + if c.storage.ReadOnly() { + return ErrReadOnly + } + return nil } func (c *Controller) InsertValue(key string, attribute string, value interface{}) error { + if c.storage.ReadOnly() { + return ErrReadOnly + } + + r, err := c.Get(key) + if err != nil { + return err + } + + r.Lock() + defer r.Unlock() + + if r.IsWrapped() { + wrapper, ok := r.(*record.Wrapper) + if !ok { + return errors.New("record is malformed") + } + + } else { + + } + return nil } @@ -73,17 +116,33 @@ func (c *Controller) Query(q *query.Query, local, internal bool) (*iterator.Iter // Meta func (c *Controller) SetAbsoluteExpiry(key string, time int64) error { + if c.storage.ReadOnly() { + return ErrReadOnly + } + return nil } func (c *Controller) SetRelativateExpiry(key string, duration int64) error { + if c.storage.ReadOnly() { + return ErrReadOnly + } + return nil } func (c *Controller) MakeCrownJewel(key string) error { + if c.storage.ReadOnly() { + return ErrReadOnly + } + return nil } func (c *Controller) MakeSecret(key string) error { + if c.storage.ReadOnly() { + return ErrReadOnly + } + return nil } diff --git a/database/database.go b/database/database.go index 78373f4..890c391 100644 --- a/database/database.go +++ b/database/database.go @@ -8,8 +8,9 @@ import ( // Errors var ( - ErrNotFound = errors.New("database: entry could not be found") - ErrPermissionDenied = errors.New("database: access to record denied") + ErrNotFound = errors.New("database entry could not be found") + ErrPermissionDenied = errors.New("access to database record denied") + ErrReadOnly = errors.New("database is read only") ) func init() { diff --git a/database/query/fetcher.go b/database/query/fetcher.go deleted file mode 100644 index c2004bd..0000000 --- a/database/query/fetcher.go +++ /dev/null @@ -1,78 +0,0 @@ -package query - -import ( - "github.com/tidwall/gjson" -) - -const ( - emptyString = "" -) - -// Fetcher provides an interface to supply the query matcher a method to retrieve values from an object. -type Fetcher interface { - GetString(key string) (value string, ok bool) - GetInt(key string) (value int64, ok bool) - GetFloat(key string) (value float64, ok bool) - GetBool(key string) (value bool, ok bool) - Exists(key string) bool -} - -// JSONFetcher is a json string with get functions. -type JSONFetcher struct { - json string -} - -// NewJSONFetcher adds the Fetcher interface to a JSON string. -func NewJSONFetcher(json string) *JSONFetcher { - return &JSONFetcher{ - json: json, - } -} - -// GetString returns the string found by the given json key and whether it could be successfully extracted. -func (jf *JSONFetcher) GetString(key string) (value string, ok bool) { - result := gjson.Get(jf.json, key) - if !result.Exists() || result.Type != gjson.String { - return emptyString, false - } - return result.String(), true -} - -// GetInt returns the int found by the given json key and whether it could be successfully extracted. -func (jf *JSONFetcher) GetInt(key string) (value int64, ok bool) { - result := gjson.Get(jf.json, key) - if !result.Exists() || result.Type != gjson.Number { - return 0, false - } - return result.Int(), true -} - -// GetFloat returns the float found by the given json key and whether it could be successfully extracted. -func (jf *JSONFetcher) GetFloat(key string) (value float64, ok bool) { - result := gjson.Get(jf.json, key) - if !result.Exists() || result.Type != gjson.Number { - return 0, false - } - return result.Float(), true -} - -// GetBool returns the bool found by the given json key and whether it could be successfully extracted. -func (jf *JSONFetcher) GetBool(key string) (value bool, ok bool) { - result := gjson.Get(jf.json, key) - switch { - case !result.Exists(): - return false, false - case result.Type == gjson.True: - return true, true - case result.Type == gjson.False: - return false, true - default: - return false, false - } -} - -// Exists returns the whether the given key exists. -func (jf *JSONFetcher) Exists(key string) bool { - result := gjson.Get(jf.json, key) - return result.Exists() -} diff --git a/database/storage/badger/badger.go b/database/storage/badger/badger.go index 21f75b9..af04bf4 100644 --- a/database/storage/badger/badger.go +++ b/database/storage/badger/badger.go @@ -2,13 +2,12 @@ package badger import ( "errors" - "time" "github.com/dgraph-io/badger" "github.com/Safing/portbase/database/iterator" - "github.com/Safing/portbase/database/record" "github.com/Safing/portbase/database/query" + "github.com/Safing/portbase/database/record" "github.com/Safing/portbase/database/storage" ) @@ -85,7 +84,7 @@ func (b *Badger) Get(key string) (record.Record, error) { return nil, err } - m, err := model.NewRawWrapper(b.name, string(item.Key()), data) + m, err := record.NewRawWrapper(b.name, string(item.Key()), data) if err != nil { return nil, err } @@ -100,12 +99,7 @@ func (b *Badger) Put(m record.Record) error { } err = b.db.Update(func(txn *badger.Txn) error { - if m.Meta().GetAbsoluteExpiry() > 0 { - txn.SetWithTTL([]byte(m.DatabaseKey()), data, time.Duration(m.Meta().GetRelativeExpiry())) - } else { - txn.Set([]byte(m.DatabaseKey()), data) - } - return nil + return txn.Set([]byte(m.DatabaseKey()), data) }) return err } @@ -126,6 +120,11 @@ func (b *Badger) Query(q *query.Query) (*iterator.Iterator, error) { return nil, errors.New("query not implemented by badger") } +// ReadOnly returns whether the database is read only. +func (b *Badger) ReadOnly() bool { + return false +} + // Maintain runs a light maintenance operation on the database. func (b *Badger) Maintain() error { b.db.RunValueLogGC(0.7) diff --git a/database/storage/interface.go b/database/storage/interface.go index 3832ca4..a94b32f 100644 --- a/database/storage/interface.go +++ b/database/storage/interface.go @@ -13,6 +13,7 @@ type Interface interface { Delete(key string) error Query(q *query.Query) (*iterator.Iterator, error) + ReadOnly() bool Maintain() error MaintainThorough() error Shutdown() error diff --git a/database/storage/sinkhole/sinkhole.go b/database/storage/sinkhole/sinkhole.go index 5a5189e..b1447a7 100644 --- a/database/storage/sinkhole/sinkhole.go +++ b/database/storage/sinkhole/sinkhole.go @@ -4,8 +4,8 @@ import ( "errors" "github.com/Safing/portbase/database/iterator" - "github.com/Safing/portbase/database/record" "github.com/Safing/portbase/database/query" + "github.com/Safing/portbase/database/record" "github.com/Safing/portbase/database/storage" ) @@ -50,6 +50,11 @@ func (s *Sinkhole) Query(q *query.Query) (*iterator.Iterator, error) { return nil, errors.New("query not implemented by sinkhole") } +// ReadOnly returns whether the database is read only. +func (s *Sinkhole) ReadOnly() bool { + return false +} + // Maintain runs a light maintenance operation on the database. func (s *Sinkhole) Maintain() error { return nil