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)
|
||||||
|
}
|
|
@ -33,6 +33,7 @@ type executor struct {
|
||||||
time int64
|
time int64
|
||||||
lock *mutex
|
lock *mutex
|
||||||
send chan *Response
|
send chan *Response
|
||||||
|
cache *cache
|
||||||
}
|
}
|
||||||
|
|
||||||
func newExecutor() (e *executor) {
|
func newExecutor() (e *executor) {
|
||||||
|
@ -43,6 +44,8 @@ func newExecutor() (e *executor) {
|
||||||
|
|
||||||
e.send = make(chan *Response)
|
e.send = make(chan *Response)
|
||||||
|
|
||||||
|
e.cache = new(cache)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
100
db/fetch.go
100
db/fetch.go
|
@ -16,6 +16,7 @@ package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
@ -350,6 +351,12 @@ func (e *executor) fetchThing(ctx context.Context, val *sql.Thing, doc *data.Doc
|
||||||
return nil, err
|
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{
|
res, err := e.executeSelect(ctx, &sql.SelectStatement{
|
||||||
KV: cnf.Settings.DB.Base,
|
KV: cnf.Settings.DB.Base,
|
||||||
NS: ctx.Value(ctxKeyNs).(string),
|
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 {
|
if len(res) > 0 {
|
||||||
|
e.cache.Put(key, res[0])
|
||||||
return res[0], nil
|
return res[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,6 +387,12 @@ func (e *executor) fetchArray(ctx context.Context, val []interface{}, doc *data.
|
||||||
return nil, err
|
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{
|
res, err := e.executeSelect(ctx, &sql.SelectStatement{
|
||||||
KV: cnf.Settings.DB.Base,
|
KV: cnf.Settings.DB.Base,
|
||||||
NS: ctx.Value(ctxKeyNs).(string),
|
NS: ctx.Value(ctxKeyNs).(string),
|
||||||
|
@ -393,7 +407,12 @@ func (e *executor) fetchArray(ctx context.Context, val []interface{}, doc *data.
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(res) > 0 {
|
||||||
|
e.cache.Put(key, res)
|
||||||
return res, nil
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1063,17 +1082,17 @@ func chkArrayL(op sql.Token, a []interface{}, i interface{}) (val bool) {
|
||||||
case sql.MAT:
|
case sql.MAT:
|
||||||
switch s := i.(type) {
|
switch s := i.(type) {
|
||||||
case string:
|
case string:
|
||||||
return chkSearch(op, a, s)
|
return chkSearchL(op, a, s)
|
||||||
}
|
}
|
||||||
case sql.NAT:
|
case sql.NAT:
|
||||||
switch s := i.(type) {
|
switch s := i.(type) {
|
||||||
case string:
|
case string:
|
||||||
return chkSearch(op, a, s)
|
return chkSearchL(op, a, s)
|
||||||
}
|
}
|
||||||
case sql.MAY:
|
case sql.MAY:
|
||||||
switch s := i.(type) {
|
switch s := i.(type) {
|
||||||
case string:
|
case string:
|
||||||
return chkSearch(op, a, s)
|
return chkSearchL(op, a, s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return negOp(op)
|
return negOp(op)
|
||||||
|
@ -1112,17 +1131,17 @@ func chkArrayR(op sql.Token, i interface{}, a []interface{}) (val bool) {
|
||||||
case sql.MAT:
|
case sql.MAT:
|
||||||
switch s := i.(type) {
|
switch s := i.(type) {
|
||||||
case string:
|
case string:
|
||||||
return chkSearch(op, a, s)
|
return chkSearchR(op, a, s)
|
||||||
}
|
}
|
||||||
case sql.NAT:
|
case sql.NAT:
|
||||||
switch s := i.(type) {
|
switch s := i.(type) {
|
||||||
case string:
|
case string:
|
||||||
return chkSearch(op, a, s)
|
return chkSearchR(op, a, s)
|
||||||
}
|
}
|
||||||
case sql.MAY:
|
case sql.MAY:
|
||||||
switch s := i.(type) {
|
switch s := i.(type) {
|
||||||
case string:
|
case string:
|
||||||
return chkSearch(op, a, s)
|
return chkSearchR(op, a, s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return negOp(op)
|
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 {
|
if len(a) == 0 {
|
||||||
return op == sql.NAT
|
return op == sql.NAT
|
||||||
|
@ -1276,21 +1295,82 @@ func chkSearch(op sql.Token, a []interface{}, r string) (val bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if op == sql.MAT {
|
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 {
|
if b == -1 && e == -1 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if op == sql.NAT {
|
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 {
|
if b == -1 && e == -1 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if op == sql.MAY {
|
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 {
|
if b != -1 && e != -1 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue