/
qdb.go
138 lines (112 loc) · 2.71 KB
/
qdb.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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package main
import (
"fmt"
"log"
"os"
"strconv"
"sync"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/opt"
)
type QDB struct {
path string
wo opt.WriteOptions
db *leveldb.DB
mutex sync.Mutex
}
func NewQDB(path string, syncWrites bool) *QDB {
// Open
db, err := leveldb.OpenFile(path, nil)
if err != nil {
panic(fmt.Sprintf("goq: Unable to open db: %v", err))
}
log.Println("goq: Starting health check")
// Health check each record
iter := db.NewIterator(nil, nil)
defer iter.Release()
for iter.Next() {
_, err := strconv.Atoi(string(iter.Key()))
if err != nil {
panic(fmt.Sprintf("goq: Health check failure (key not int): %s, %s, %v", string(iter.Key()), string(iter.Value()), err))
}
}
// General
if iter.Error() != nil {
panic(fmt.Sprintf("goq: Error loading db: %v", err))
}
log.Println("goq: Health check successful")
return &QDB{
path: path,
wo: opt.WriteOptions{Sync: syncWrites},
db: db,
}
}
func (self *QDB) Get(id int64) (*QueuedItem, error) {
// Grab from level
value, err := self.db.Get(QDBKey(id), nil)
// Error retrieving key
if err != nil {
return nil, err
}
// Nil value, should never happen
if value == nil {
return nil, nil
}
return &QueuedItem{id, value}, nil
}
func (self *QDB) Put(qi *QueuedItem) error {
self.mutex.Lock()
defer self.mutex.Unlock()
// Put into level
return self.db.Put(QDBKey(qi.ID), qi.Data, &self.wo)
}
func (self *QDB) Remove(id int64) error {
self.mutex.Lock()
defer self.mutex.Unlock()
// Delete from level
return self.db.Delete(QDBKey(id), &self.wo)
}
func (self *QDB) Close() {
self.db.Close()
}
func (self *QDB) Drop() {
self.Close()
err := os.RemoveAll(self.path)
if err != nil {
panic(fmt.Sprintf("goq: Error removing db from disk: %v", err))
}
}
// Abstractions
func (self *QDB) Next(remove bool) *QueuedItem {
iter := self.db.NewIterator(nil, nil)
defer iter.Release()
for iter.Next() {
id, err := strconv.Atoi(string(iter.Key()))
if err != nil {
panic(fmt.Sprintf("goq: Key not int: %s, %s, %v", string(iter.Key()), string(iter.Value()), err))
}
if remove {
self.Remove(int64(id))
}
return &QueuedItem{int64(id), iter.Value()}
}
return nil
}
func (self *QDB) CacheFetch(maxBytes int) ([]*QueuedItem, int) {
iter := self.db.NewIterator(nil, nil)
defer iter.Release()
// Collect
items := make([]*QueuedItem, 0)
totalSize := 0
for iter.Next() {
id, err := strconv.Atoi(string(iter.Key()))
if err != nil {
panic(fmt.Sprintf("goq: Key not int: %s, %s, %v", string(iter.Key()), string(iter.Value()), err))
}
qi := QueuedItem{int64(id), iter.Value()}
if totalSize+qi.Size() < maxBytes {
items = append(items, &qi)
}
}
return items, totalSize
}