-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlocketdb.go
199 lines (159 loc) · 6.44 KB
/
locketdb.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
package locketdb
import (
"errors"
"fmt"
"strings"
)
var (
// ErrBatchClosed is returned when a closed or written batch is used.
ErrBatchClosed = errors.New("batch has been written or closed")
// ErrKeyEmpty is returned when attempting to use an empty or nil key.
ErrKeyEmpty = errors.New("key cannot be empty")
// ErrKeyNotFound is returned when 农田 found to use an empty or nil key.
ErrKeyNotFound = errors.New("key not found")
// ErrValueNil is returned when attempting to set a nil value.
ErrValueNil = errors.New("value cannot be nil")
)
// DB is the main interface for all database backends. DBs are concurrency-safe. Callers must call
// Close on the database when done.
//
// Keys cannot be nil or empty, while values cannot be nil. Keys and values should be considered
// read-only, both when returned and when given, and must be copied before they are modified.
type DB interface {
// Get fetches the value of the given key, or nil if it does not exist.
// CONTRACT: key, value readonly []byte
Get([]byte) ([]byte, error)
// Has checks if a key exists.
// CONTRACT: key, value readonly []byte
Has(key []byte) (bool, error)
// Set sets the value for the given key, replacing it if it already exists.
// CONTRACT: key, value readonly []byte
Set([]byte, []byte) error
// SetSync sets the value for the given key, and flushes it to storage before returning.
SetSync([]byte, []byte) error
// Delete deletes the key, or does nothing if the key does not exist.
// CONTRACT: key readonly []byte
Delete([]byte) error
// DeleteSync deletes the key, and flushes the delete to storage before returning.
DeleteSync([]byte) error
// Iterator returns an iterator over a domain of keys, in ascending order. The caller must call
// Close when done. End is exclusive, and start must be less than end. A nil start iterates
// from the first key, and a nil end iterates to the last key (inclusive). Empty keys are not
// valid.
// CONTRACT: No writes may happen within a domain while an iterator exists over it.
// CONTRACT: start, end readonly []byte
Iterator(start, end []byte) (Iterator, error)
// ReverseIterator returns an iterator over a domain of keys, in descending order. The caller
// must call Close when done. End is exclusive, and start must be less than end. A nil end
// iterates from the last key (inclusive), and a nil start iterates to the first key (inclusive).
// Empty keys are not valid.
// CONTRACT: No writes may happen within a domain while an iterator exists over it.
// CONTRACT: start, end readonly []byte
ReverseIterator(start, end []byte) (Iterator, error)
// Close closes the database connection.
Close() error
// NewBatch creates a batch for atomic updates. The caller must call Batch.Close.
NewBatch() Batch
// Print is used for debugging.
Print() error
// Stats returns a map of property values for all keys and the size of the cache.
Stats() map[string]string
}
// Batch represents a group of writes. They may or may not be written atomically depending on the
// backend. Callers must call Close on the batch when done.
//
// As with DB, given keys and values should be considered read-only, and must not be modified after
// passing them to the batch.
type Batch interface {
// Set sets a key/value pair.
// CONTRACT: key, value readonly []byte
Set(key, value []byte) error
// Delete deletes a key/value pair.
// CONTRACT: key readonly []byte
Delete(key []byte) error
// Write writes the batch, possibly without flushing to disk. Only Close() can be called after,
// other methods will error.
Write() error
// WriteSync writes the batch and flushes it to disk. Only Close() can be called after, other
// methods will error.
WriteSync() error
// Close closes the batch. It is idempotent, but calls to other methods afterwards will error.
Close() error
}
// Iterator represents an iterator over a domain of keys. Callers must call Close when done.
// No writes can happen to a domain while there exists an iterator over it, some backends may take
// out database locks to ensure this will not happen.
//
// Callers must make sure the iterator is valid before calling any methods on it, otherwise
// these methods will panic. This is in part caused by most backend databases using this convention.
//
// As with DB, keys and values should be considered read-only, and must be copied before they are
// modified.
//
// Typical usage:
//
// var itr Iterator = ...
// defer itr.Close()
//
// for ; itr.Valid(); itr.Next() {
// k, v := itr.Key(); itr.Value()
// ...
// }
// if err := itr.Error(); err != nil {
// ...
// }
type Iterator interface {
// Domain returns the start (inclusive) and end (exclusive) limits of the iterator.
// CONTRACT: start, end readonly []byte
Domain() (start []byte, end []byte)
// Valid returns whether the current iterator is valid. Once invalid, the Iterator remains
// invalid forever.
Valid() bool
// Next moves the iterator to the next key in the database, as defined by order of iteration.
// If Valid returns false, this method will panic.
Next()
// Key returns the key at the current position. Panics if the iterator is invalid.
// CONTRACT: key readonly []byte
Key() (key []byte)
// Value returns the value at the current position. Panics if the iterator is invalid.
// CONTRACT: value readonly []byte
Value() (value []byte)
// Error returns the last error encountered by the iterator, if any.
Error() error
// Close closes the iterator, relasing any allocated resources.
Close() error
}
type KVType string
// These are valid backend types.
const (
// goleveldb github.com/syndtr/goleveldb
GoLevelDB KVType = "golevel"
// boltdb go.etcd.io/bbolt
BoltDB KVType = "bbolt"
// badgerdb github.com/dgraph-io/badger/v3
BadgerDB KVType = "badger"
// goleveldb github.com/cockroachdb/pebble
Pebble KVType = "pebble"
)
type Engine func(name string, dir string) (DB, error)
var engines = map[KVType]Engine{}
func RegisterEngine(backend KVType, engine Engine) {
engines[backend] = engine
}
// NewDB creates a new database of type backend with the given name.
func NewDB(name string, kvType KVType, dir string) (DB, error) {
creator, ok := engines[kvType]
if ok {
db, err := creator(name, dir)
if err != nil {
return nil, fmt.Errorf("failed to initialize database: %w", err)
}
return db, nil
}
keys := make([]string, 0, len(engines))
for k := range engines {
keys = append(keys, string(k))
}
return nil, fmt.Errorf("unknown kvType %s, expected one of %v",
kvType, strings.Join(keys, ","))
}