Implement basic executor caching layer
This commit is contained in:
parent
1a0c8b018f
commit
e52f0d3243
3 changed files with 146 additions and 15 deletions
48
db/cache.go
Normal file
48
db/cache.go
Normal file
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
|
||||
}
|
||||
|
|
102
db/fetch.go
102
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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue