From 9d5a97c20baaa3bc5918061ed068e690eb84a230 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 22 Oct 2018 17:06:49 +0200 Subject: [PATCH] Add caching option for database interface --- database/interface.go | 58 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/database/interface.go b/database/interface.go index 2f5ad4d..e4422e5 100644 --- a/database/interface.go +++ b/database/interface.go @@ -3,6 +3,9 @@ package database import ( "errors" "fmt" + "time" + + "github.com/bluele/gcache" "github.com/Safing/portbase/database/accessor" "github.com/Safing/portbase/database/iterator" @@ -17,14 +20,18 @@ const ( // Interface provides a method to access the database with attached options. type Interface struct { options *Options + cache gcache.Cache } // Options holds options that may be set for an Interface instance. type Options struct { - Local bool - Internal bool - AlwaysMakeSecret bool - AlwaysMakeCrownjewel bool + Local bool + Internal bool + AlwaysMakeSecret bool + AlwaysMakeCrownjewel bool + AlwaysSetRelativateExpiry int64 + AlwaysSetAbsoluteExpiry int64 + CacheSize int } // Apply applies options to the record metadata. @@ -38,6 +45,11 @@ func (o *Options) Apply(r record.Record) { if o.AlwaysMakeCrownjewel { r.Meta().MakeCrownJewel() } + if o.AlwaysSetAbsoluteExpiry > 0 { + r.Meta().SetAbsoluteExpiry(o.AlwaysSetAbsoluteExpiry) + } else if o.AlwaysSetRelativateExpiry > 0 { + r.Meta().SetRelativateExpiry(o.AlwaysSetRelativateExpiry) + } } // NewInterface returns a new Interface to the database. @@ -46,9 +58,32 @@ func NewInterface(opts *Options) *Interface { opts = &Options{} } - return &Interface{ + new := &Interface{ options: opts, } + if opts.CacheSize > 0 { + new.cache = gcache.New(opts.CacheSize).ARC().Expiration(time.Hour).Build() + } + return new +} + +func (i *Interface) checkCache(key string) (record.Record, bool) { + if i.cache != nil { + cacheVal, err := i.cache.Get(key) + if err == nil { + r, ok := cacheVal.(record.Record) + if ok { + return r, true + } + } + } + return nil, false +} + +func (i *Interface) updateCache(r record.Record) { + if i.cache != nil { + i.cache.Set(r.Key(), r) + } } // Exists return whether a record with the given key exists. @@ -65,6 +100,14 @@ func (i *Interface) Exists(key string) (bool, error) { // Get return the record with the given key. func (i *Interface) Get(key string) (record.Record, error) { + r, ok := i.checkCache(key) + if ok { + if !r.Meta().CheckPermission(i.options.Local, i.options.Internal) { + return nil, ErrPermissionDenied + } + return r, nil + } + r, _, err := i.getRecord(getDBFromKey, key, true, false) return r, err } @@ -136,6 +179,8 @@ func (i *Interface) Put(r record.Record) error { } i.options.Apply(r) + + i.updateCache(r) return db.Put(r) } @@ -146,8 +191,9 @@ func (i *Interface) PutNew(r record.Record) error { return err } - i.options.Apply(r) r.Meta().Reset() + i.options.Apply(r) + i.updateCache(r) return db.Put(r) }