From e52f0d3243a9a465a457385052df9dac8eaf43a4 Mon Sep 17 00:00:00 2001 From: Tobie Morgan Hitchcock Date: Fri, 28 Sep 2018 22:06:07 +0100 Subject: [PATCH] Implement basic executor caching layer --- db/cache.go | 48 +++++++++++++++++++++++ db/executor.go | 11 ++++-- db/fetch.go | 102 +++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 146 insertions(+), 15 deletions(-) create mode 100644 db/cache.go diff --git a/db/cache.go b/db/cache.go new file mode 100644 index 00000000..2919712f --- /dev/null +++ b/db/cache.go @@ -0,0 +1,48 @@ +// Copyright © 2016 Abcum Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package db + +import ( + "sync" +) + +type cache struct { + items sync.Map +} + +func (c *cache) Clr() { + c.items.Range(func(key interface{}, _ interface{}) bool { + c.items.Delete(key) + return true + }) +} + +func (c *cache) Del(key string) { + c.items.Delete(key) +} + +func (c *cache) Has(key string) bool { + _, ok := c.items.Load(key) + return ok +} + +func (c *cache) Get(key string) interface{} { + val, _ := c.items.Load(key) + return val +} + +func (c *cache) Put(key string, val interface{}) { + c.items.Store(key, val) +} diff --git a/db/executor.go b/db/executor.go index 392a950c..e5686215 100644 --- a/db/executor.go +++ b/db/executor.go @@ -29,10 +29,11 @@ import ( ) type executor struct { - dbo *mem.Cache - time int64 - lock *mutex - send chan *Response + dbo *mem.Cache + time int64 + lock *mutex + send chan *Response + cache *cache } func newExecutor() (e *executor) { @@ -43,6 +44,8 @@ func newExecutor() (e *executor) { e.send = make(chan *Response) + e.cache = new(cache) + return } diff --git a/db/fetch.go b/db/fetch.go index feddde18..7d4ff90f 100644 --- a/db/fetch.go +++ b/db/fetch.go @@ -16,6 +16,7 @@ package db import ( "context" + "fmt" "math" "reflect" "regexp" @@ -350,6 +351,12 @@ func (e *executor) fetchThing(ctx context.Context, val *sql.Thing, doc *data.Doc return nil, err } + key := fmt.Sprintf("%d %s", ver, val) + + if e.cache.Has(key) { + return e.cache.Get(key), nil + } + res, err := e.executeSelect(ctx, &sql.SelectStatement{ KV: cnf.Settings.DB.Base, NS: ctx.Value(ctxKeyNs).(string), @@ -365,6 +372,7 @@ func (e *executor) fetchThing(ctx context.Context, val *sql.Thing, doc *data.Doc } if len(res) > 0 { + e.cache.Put(key, res[0]) return res[0], nil } @@ -379,6 +387,12 @@ func (e *executor) fetchArray(ctx context.Context, val []interface{}, doc *data. return nil, err } + key := fmt.Sprintf("%d %s", ver, val) + + if e.cache.Has(key) { + return e.cache.Get(key), nil + } + res, err := e.executeSelect(ctx, &sql.SelectStatement{ KV: cnf.Settings.DB.Base, NS: ctx.Value(ctxKeyNs).(string), @@ -393,7 +407,12 @@ func (e *executor) fetchArray(ctx context.Context, val []interface{}, doc *data. return nil, err } - return res, nil + if len(res) > 0 { + e.cache.Put(key, res) + return res, nil + } + + return nil, nil } @@ -1063,17 +1082,17 @@ func chkArrayL(op sql.Token, a []interface{}, i interface{}) (val bool) { case sql.MAT: switch s := i.(type) { case string: - return chkSearch(op, a, s) + return chkSearchL(op, a, s) } case sql.NAT: switch s := i.(type) { case string: - return chkSearch(op, a, s) + return chkSearchL(op, a, s) } case sql.MAY: switch s := i.(type) { case string: - return chkSearch(op, a, s) + return chkSearchL(op, a, s) } } return negOp(op) @@ -1112,17 +1131,17 @@ func chkArrayR(op sql.Token, i interface{}, a []interface{}) (val bool) { case sql.MAT: switch s := i.(type) { case string: - return chkSearch(op, a, s) + return chkSearchR(op, a, s) } case sql.NAT: switch s := i.(type) { case string: - return chkSearch(op, a, s) + return chkSearchR(op, a, s) } case sql.MAY: switch s := i.(type) { case string: - return chkSearch(op, a, s) + return chkSearchR(op, a, s) } } return negOp(op) @@ -1250,7 +1269,7 @@ func chkMatch(op sql.Token, a []interface{}, r *regexp.Regexp) (val bool) { } -func chkSearch(op sql.Token, a []interface{}, r string) (val bool) { +func chkSearchL(op sql.Token, a []interface{}, p string) (val bool) { if len(a) == 0 { return op == sql.NAT @@ -1276,21 +1295,82 @@ func chkSearch(op sql.Token, a []interface{}, r string) (val bool) { } if op == sql.MAT { - b, e := search.New(language.Und, search.Loose).IndexString(s, r) + b, e := search.New(language.Und, search.Loose).IndexString(s, p) if b == -1 && e == -1 { return false } } if op == sql.NAT { - b, e := search.New(language.Und, search.Loose).IndexString(s, r) + b, e := search.New(language.Und, search.Loose).IndexString(s, p) if b == -1 && e == -1 { return true } } if op == sql.MAY { - b, e := search.New(language.Und, search.Loose).IndexString(s, r) + b, e := search.New(language.Und, search.Loose).IndexString(s, p) + if b != -1 && e != -1 { + return true + } + } + + } + + switch op { + case sql.MAT: + return true + case sql.NAT: + return false + case sql.MAY: + return false + } + + return + +} + +func chkSearchR(op sql.Token, a []interface{}, p string) (val bool) { + + if len(a) == 0 { + return op == sql.NAT + } + + for _, v := range a { + + var s string + + switch c := v.(type) { + default: + return false + case string: + s = c + case bool: + s = strconv.FormatBool(c) + case int64: + s = strconv.FormatInt(c, 10) + case float64: + s = strconv.FormatFloat(c, 'g', -1, 64) + case time.Time: + s = c.String() + } + + if op == sql.MAT { + b, e := search.New(language.Und, search.Loose).IndexString(p, s) + if b == -1 && e == -1 { + return false + } + } + + if op == sql.NAT { + b, e := search.New(language.Und, search.Loose).IndexString(p, s) + if b == -1 && e == -1 { + return true + } + } + + if op == sql.MAY { + b, e := search.New(language.Und, search.Loose).IndexString(p, s) if b != -1 && e != -1 { return true }