/
database.go
233 lines (208 loc) · 6.21 KB
/
database.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
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
package database
import (
"fmt"
"errors"
)
var (
// ErrNotFound is the type returned on DB implementations if an item does not
// exist.
ErrNotFound = errors.New("not found")
// ErrOpNotSupported is the type returned on DB implementations if an operation
// is not supported.
ErrOpNotSupported = errors.New("operation not supported")
)
// IsErrNotFound returns true if the cause of the given error is ErrNotFound.
func IsErrNotFound(err error) bool {
return errors.Is(err, ErrNotFound)
}
// IsErrOpNotSupported returns true if the cause of the given error is ErrOpNotSupported.
func IsErrOpNotSupported(err error) bool {
return errors.Is(err, ErrOpNotSupported)
}
// Options are configuration options for the database.
type Options struct {
Database string
ValueDir string
BadgerFileLoadingMode string
}
// Option is the modifier type over Options.
type Option func(o *Options) error
// WithValueDir is a modifier that sets the ValueDir attribute of Options.
func WithValueDir(path string) Option {
return func(o *Options) error {
o.ValueDir = path
return nil
}
}
// WithDatabase is a modifier that sets the Database attribute of Options.
func WithDatabase(db string) Option {
return func(o *Options) error {
o.Database = db
return nil
}
}
// WithBadgerFileLoadingMode is a modifier that sets the ValueLogLoadingMode
// of Badger db.
func WithBadgerFileLoadingMode(mode string) Option {
return func(o *Options) error {
o.BadgerFileLoadingMode = mode
return nil
}
}
// DB is a interface to be implemented by the databases.
type DB interface {
// Open opens the database available with the given options.
Open(dataSourceName string, opt ...Option) error
// Close closes the current database.
Close() error
// Get returns the value stored in the given table/bucket and key.
Get(bucket, key []byte) (ret []byte, err error)
// Set sets the given value in the given table/bucket and key.
Set(bucket, key, value []byte) error
// CmpAndSwap swaps the value at the given bucket and key if the current
// value is equivalent to the oldValue input. Returns 'true' if the
// swap was successful and 'false' otherwise.
CmpAndSwap(bucket, key, oldValue, newValue []byte) ([]byte, bool, error)
// Del deletes the data in the given table/bucket and key.
Del(bucket, key []byte) error
// List returns a list of all the entries in a given table/bucket.
List(bucket []byte) ([]*Entry, error)
// Update performs a transaction with multiple read-write commands.
Update(tx *Tx) error
// CreateTable creates a table or a bucket in the database.
CreateTable(bucket []byte) error
// DeleteTable deletes a table or a bucket in the database.
DeleteTable(bucket []byte) error
}
// Badger FileLoadingMode constants.
const (
BadgerMemoryMap = "mmap"
BadgerFileIO = "fileio"
)
// TxCmd is the type used to represent database command and operations.
type TxCmd int
const (
// CreateTable on a TxEntry will represent the creation of a table or
// bucket on the database.
CreateTable TxCmd = iota
// DeleteTable on a TxEntry will represent the deletion of a table or
// bucket on the database.
DeleteTable
// Get on a TxEntry will represent a command to retrieve data from the
// database.
Get
// Set on a TxEntry will represent a command to write data on the
// database.
Set
// Delete on a TxEntry represent a command to delete data on the database.
Delete
// CmpAndSwap on a TxEntry will represent a compare and swap operation on
// the database. It will compare the value read and change it if it's
// different. The TxEntry will contain the value read.
CmpAndSwap
// CmpOrRollback on a TxEntry will represent a read transaction that will
// compare the values will the ones passed, and if they don't match the
// transaction will fail
CmpOrRollback
)
// String implements the fmt.Stringer interface on TxCmd.
func (o TxCmd) String() string {
switch o {
case CreateTable:
return "create-table"
case DeleteTable:
return "delete-table"
case Get:
return "read"
case Set:
return "write"
case Delete:
return "delete"
case CmpAndSwap:
return "compare-and-swap"
case CmpOrRollback:
return "compare-and-rollback"
default:
return fmt.Sprintf("unknown(%d)", o)
}
}
// Tx represents a transaction and it's list of multiple TxEntry. Each TxEntry
// represents a read or write operation on the database.
type Tx struct {
Operations []*TxEntry
}
// CreateTable adds a new create query to the transaction.
func (tx *Tx) CreateTable(bucket []byte) {
tx.Operations = append(tx.Operations, &TxEntry{
Bucket: bucket,
Cmd: CreateTable,
})
}
// DeleteTable adds a new create query to the transaction.
func (tx *Tx) DeleteTable(bucket []byte) {
tx.Operations = append(tx.Operations, &TxEntry{
Bucket: bucket,
Cmd: DeleteTable,
})
}
// Get adds a new read query to the transaction.
func (tx *Tx) Get(bucket, key []byte) {
tx.Operations = append(tx.Operations, &TxEntry{
Bucket: bucket,
Key: key,
Cmd: Get,
})
}
// Set adds a new write query to the transaction.
func (tx *Tx) Set(bucket, key, value []byte) {
tx.Operations = append(tx.Operations, &TxEntry{
Bucket: bucket,
Key: key,
Value: value,
Cmd: Set,
})
}
// Del adds a new delete query to the transaction.
func (tx *Tx) Del(bucket, key []byte) {
tx.Operations = append(tx.Operations, &TxEntry{
Bucket: bucket,
Key: key,
Cmd: Delete,
})
}
// Cas adds a new compare-and-swap query to the transaction.
func (tx *Tx) Cas(bucket, key, value []byte) {
tx.Operations = append(tx.Operations, &TxEntry{
Bucket: bucket,
Key: key,
Value: value,
Cmd: CmpAndSwap,
})
}
// Cmp adds a new compare-or-rollback query to the transaction.
func (tx *Tx) Cmp(bucket, key, value []byte) {
tx.Operations = append(tx.Operations, &TxEntry{
Bucket: bucket,
Key: key,
Value: value,
Cmd: CmpOrRollback,
})
}
// TxEntry is the base elements for the transactions, a TxEntry is a read or
// write operation on the database.
type TxEntry struct {
Bucket []byte
Key []byte
Value []byte
CmpValue []byte
// Where the result of Get or CmpAndSwap txns is stored.
Result []byte
Cmd TxCmd
Swapped bool
}
// Entry is the return value for list commands.
type Entry struct {
Bucket []byte
Key []byte
Value []byte
}