-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathboltcache.go
120 lines (111 loc) · 2.82 KB
/
boltcache.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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package lru
import (
"bytes"
"github.com/boltdb/bolt"
)
// openBoltDB opens the boltDB database and assigns it to the LRU as "db".
func (l *LRU) openBoltDB() error {
db, err := bolt.Open(l.dbPath, 0666, nil)
if err != nil {
return err
}
l.db = db
return l.fillCacheFromBolt()
}
// fillCacheFromBolt fills the cache with all of the values currently in the
// bolt database. If the cache reaches its capacity, subsequent values are
// deleted.
func (l *LRU) fillCacheFromBolt() error {
// fill the LRU with existing data
return l.db.Update(func(tx *bolt.Tx) error {
// create the bucket if it doesn't exist
b, err := tx.CreateBucketIfNotExists(l.bName)
if err != nil {
return err
}
// cycle through all entries and add them to the LRU
c := b.Cursor()
l.mu.Lock()
defer l.mu.Unlock()
for k, v := c.First(); k != nil; k, v = c.Next() {
key := make([]byte, len(k))
copy(key, k)
if !l.lru.PutOnStartup(key, int64(len(v))) {
// avoid rolling back the entire transaction
// for a single delete failure
_ = c.Delete()
}
}
return nil
})
}
// getFromBolt returns the value corresponding to the provided key from the
// bolt database, or nil if the key doesn't exist.
func (l *LRU) getFromBolt(key []byte) []byte {
var buf []byte
err := l.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket(l.bName)
v := b.Get(key)
if v == nil {
return nil
}
buf = make([]byte, len(v))
copy(buf, v)
return nil
})
if err != nil {
return nil
}
return buf
}
// getBufFromBolt returns a buffer corresponding to the provided key from the
// bolt database, or nil if the key doesn't exist.
func (l *LRU) getBufFromBolt(key []byte) *bytes.Buffer {
var buf *bytes.Buffer
err := l.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket(l.bName)
v := b.Get(key)
if v == nil {
return nil
}
buf = getBuf()
buf.Write(v)
return nil
})
if err != nil {
return nil
}
return buf
}
// putIntoBolt writes the provided key and value into the bolt database and
// returns any error encountered.
func (l *LRU) putIntoBolt(key, val []byte) error {
return l.db.Batch(func(tx *bolt.Tx) error {
b := tx.Bucket(l.bName)
return b.Put(key, val)
})
}
// emptyBolt completely empties the bolt database and returns any error
// encountered.
func (l *LRU) emptyBolt() error {
return l.db.Update(func(tx *bolt.Tx) error {
if err := tx.DeleteBucket(l.bName); err != nil {
return err
}
_, err := tx.CreateBucket(l.bName)
return err
})
}
// deleteFromBolt deletes the provided slice of keys from the bolt database and
// returns any error encountered.
func (l *LRU) deleteFromBolt(keys [][]byte) error {
return l.db.Update(func(tx *bolt.Tx) error {
b := tx.Bucket(l.bName)
for _, key := range keys {
// ignore a delete error to avoid having the entire
// transaction fail.
_ = b.Delete(key)
}
return nil
})
}