-
Notifications
You must be signed in to change notification settings - Fork 0
/
cache.go
83 lines (68 loc) · 1.78 KB
/
cache.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package why
import (
"sync"
"github.com/cespare/xxhash"
"github.com/d5/tengo/script"
)
type (
cacheEntry struct {
base *script.Compiled
refs *sync.Pool
}
scriptSetupFunc func(sc *script.Script)
scriptCache struct {
mtx sync.RWMutex
cache map[uint64]cacheEntry
setupScript scriptSetupFunc
}
)
func newCache(setupFunc scriptSetupFunc) *scriptCache {
return &scriptCache{
cache: map[uint64]cacheEntry{},
setupScript: setupFunc,
}
}
func (sc *scriptCache) get(scriptSource []byte) (uint64, *script.Compiled, error) {
// Calculate a uint64 hash of the source. Map access with integers
// is faster than with strings so we use a hash algorithm that outputs
// uint64 values.
hashSum := xxhash.Sum64(scriptSource)
// Check if script is cached by looking up the hash
sc.mtx.RLock()
entry, ok := sc.cache[hashSum]
if ok {
// Script is cached and we can return a clone of the compiled script.
defer sc.mtx.RUnlock()
return hashSum, entry.refs.Get().(*script.Compiled), nil
}
sc.mtx.RUnlock()
// Script was never compiled before.
sc.mtx.Lock()
defer sc.mtx.Unlock()
// Create script and setup all the variables, imports etc.
s := script.New(scriptSource)
sc.setupScript(s)
// Compile the script and check for any errors.
compiled, err := s.Compile()
if err != nil {
return 0, nil, err
}
// Create a pool that will clone the compiled script to create
// new instances.
refs := &sync.Pool{
New: func() interface{} {
return compiled.Clone()
},
}
// Set the cache entry.
sc.cache[hashSum] = cacheEntry{
base: compiled,
refs: refs,
}
return hashSum, refs.Get().(*script.Compiled), nil
}
func (sc *scriptCache) put(hashSum uint64, compiled *script.Compiled) {
sc.mtx.RLock()
sc.cache[hashSum].refs.Put(compiled)
sc.mtx.RUnlock()
}