-
Notifications
You must be signed in to change notification settings - Fork 82
/
iterator.go
150 lines (135 loc) · 4.68 KB
/
iterator.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
package levigo
// #cgo LDFLAGS: -lleveldb
// #include <stdlib.h>
// #include "leveldb/c.h"
import "C"
import (
"unsafe"
)
// IteratorError wraps general internal LevelDB iterator errors for user consumption.
type IteratorError string
func (e IteratorError) Error() string {
return "levigo: " + string(e)
}
// Iterator is a read-only iterator through a LevelDB database. It provides a
// way to seek to specific keys and iterate through the keyspace from that
// point, as well as access the values of those keys.
//
// Care must be taken when using an Iterator. If the method Valid returns
// false, calls to Key, Value, Next, and Prev will result in panics. However,
// Seek, SeekToFirst, SeekToLast, GetError, Valid, and Close will still be
// safe to call.
//
// GetError will only return an error in the event of a LevelDB error. It will
// return a nil on iterators that are simply invalid. Given that behavior,
// GetError is not a replacement for a Valid.
//
// A typical use looks like:
//
// db := levigo.Open(...)
//
// it := db.NewIterator(readOpts)
// defer it.Close()
// for it.Seek(mykey); it.Valid(); it.Next() {
// useKeyAndValue(it.Key(), it.Value())
// }
// if err := it.GetError() {
// ...
// }
//
// To prevent memory leaks, an Iterator must have Close called on it when it
// is no longer needed by the program.
type Iterator struct {
Iter *C.leveldb_iterator_t
}
// Valid returns false only when an Iterator has iterated past either the
// first or the last key in the database.
func (it *Iterator) Valid() bool {
return ucharToBool(C.leveldb_iter_valid(it.Iter))
}
// Key returns a copy the key in the database the iterator currently holds.
//
// If Valid returns false, this method will panic.
func (it *Iterator) Key() []byte {
var klen C.size_t
kdata := C.leveldb_iter_key(it.Iter, &klen)
if kdata == nil {
return nil
}
// Unlike DB.Get, the key, kdata, returned is not meant to be freed by the
// client. It's a direct reference to data managed by the iterator_t
// instead of a copy. So, we must not free it here but simply copy it
// with GoBytes.
return C.GoBytes(unsafe.Pointer(kdata), C.int(klen))
}
// Value returns a copy of the value in the database the iterator currently
// holds.
//
// If Valid returns false, this method will panic.
func (it *Iterator) Value() []byte {
var vlen C.size_t
vdata := C.leveldb_iter_value(it.Iter, &vlen)
if vdata == nil {
return nil
}
// Unlike DB.Get, the value, vdata, returned is not meant to be freed by
// the client. It's a direct reference to data managed by the iterator_t
// instead of a copy. So, we must not free it here but simply copy it with
// GoBytes.
return C.GoBytes(unsafe.Pointer(vdata), C.int(vlen))
}
// Next moves the iterator to the next sequential key in the database, as
// defined by the Comparator in the ReadOptions used to create this Iterator.
//
// If Valid returns false, this method will panic.
func (it *Iterator) Next() {
C.leveldb_iter_next(it.Iter)
}
// Prev moves the iterator to the previous sequential key in the database, as
// defined by the Comparator in the ReadOptions used to create this Iterator.
//
// If Valid returns false, this method will panic.
func (it *Iterator) Prev() {
C.leveldb_iter_prev(it.Iter)
}
// SeekToFirst moves the iterator to the first key in the database, as defined
// by the Comparator in the ReadOptions used to create this Iterator.
//
// This method is safe to call when Valid returns false.
func (it *Iterator) SeekToFirst() {
C.leveldb_iter_seek_to_first(it.Iter)
}
// SeekToLast moves the iterator to the last key in the database, as defined
// by the Comparator in the ReadOptions used to create this Iterator.
//
// This method is safe to call when Valid returns false.
func (it *Iterator) SeekToLast() {
C.leveldb_iter_seek_to_last(it.Iter)
}
// Seek moves the iterator the position of the key given or, if the key
// doesn't exist, the next key that does exist in the database. If the key
// doesn't exist, and there is no next key, the Iterator becomes invalid.
//
// This method is safe to call when Valid returns false.
func (it *Iterator) Seek(key []byte) {
C.leveldb_iter_seek(it.Iter, (*C.char)(unsafe.Pointer(&key[0])), C.size_t(len(key)))
}
// GetError returns an IteratorError from LevelDB if it had one during
// iteration.
//
// This method is safe to call when Valid returns false.
func (it *Iterator) GetError() error {
var errStr *C.char
C.leveldb_iter_get_error(it.Iter, &errStr)
if errStr != nil {
gs := C.GoString(errStr)
C.leveldb_free(unsafe.Pointer(errStr))
return IteratorError(gs)
}
return nil
}
// Close deallocates the given Iterator, freeing the underlying C struct.
func (it *Iterator) Close() {
C.leveldb_iter_destroy(it.Iter)
it.Iter = nil
}