2014-06-19 13:19:40 +04:00
|
|
|
package leveldb
|
|
|
|
|
|
|
|
// #cgo LDFLAGS: -lleveldb
|
|
|
|
// #include <stdlib.h>
|
|
|
|
// #include "leveldb/c.h"
|
2014-07-07 08:37:16 +04:00
|
|
|
// #include "leveldb_ext.h"
|
2014-06-19 13:19:40 +04:00
|
|
|
import "C"
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"unsafe"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
IteratorForward uint8 = 0
|
|
|
|
IteratorBackward uint8 = 1
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
RangeClose uint8 = 0x00
|
|
|
|
RangeLOpen uint8 = 0x01
|
|
|
|
RangeROpen uint8 = 0x10
|
|
|
|
RangeOpen uint8 = 0x11
|
|
|
|
)
|
|
|
|
|
|
|
|
//min must less or equal than max
|
|
|
|
//range type:
|
|
|
|
//close: [min, max]
|
|
|
|
//open: (min, max)
|
|
|
|
//lopen: (min, max]
|
|
|
|
//ropen: [min, max)
|
|
|
|
type Range struct {
|
|
|
|
Min []byte
|
|
|
|
Max []byte
|
|
|
|
|
|
|
|
Type uint8
|
|
|
|
}
|
|
|
|
|
2014-07-04 09:27:57 +04:00
|
|
|
type Limit struct {
|
|
|
|
Offset int
|
|
|
|
Count int
|
|
|
|
}
|
|
|
|
|
2014-06-19 13:19:40 +04:00
|
|
|
type Iterator struct {
|
2014-07-07 08:37:16 +04:00
|
|
|
it *C.leveldb_iterator_t
|
|
|
|
isValid C.uchar
|
2014-06-19 13:19:40 +04:00
|
|
|
}
|
|
|
|
|
2014-07-07 08:37:16 +04:00
|
|
|
//Returns a copy of key.
|
2014-06-19 13:19:40 +04:00
|
|
|
func (it *Iterator) Key() []byte {
|
|
|
|
var klen C.size_t
|
|
|
|
kdata := C.leveldb_iter_key(it.it, &klen)
|
|
|
|
if kdata == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return C.GoBytes(unsafe.Pointer(kdata), C.int(klen))
|
|
|
|
}
|
|
|
|
|
2014-07-07 08:37:16 +04:00
|
|
|
//Returns a copy of value.
|
2014-06-19 13:19:40 +04:00
|
|
|
func (it *Iterator) Value() []byte {
|
|
|
|
var vlen C.size_t
|
|
|
|
vdata := C.leveldb_iter_value(it.it, &vlen)
|
|
|
|
if vdata == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return C.GoBytes(unsafe.Pointer(vdata), C.int(vlen))
|
|
|
|
}
|
|
|
|
|
2014-07-07 08:37:16 +04:00
|
|
|
//Returns a reference of key.
|
|
|
|
//you must be careful that it will be changed after next iterate.
|
|
|
|
func (it *Iterator) RawKey() []byte {
|
|
|
|
var klen C.size_t
|
|
|
|
kdata := C.leveldb_iter_key(it.it, &klen)
|
|
|
|
if kdata == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return slice(unsafe.Pointer(kdata), int(C.int(klen)))
|
|
|
|
}
|
|
|
|
|
|
|
|
//Returns a reference of value.
|
|
|
|
//you must be careful that it will be changed after next iterate.
|
|
|
|
func (it *Iterator) RawValue() []byte {
|
|
|
|
var vlen C.size_t
|
|
|
|
vdata := C.leveldb_iter_value(it.it, &vlen)
|
|
|
|
if vdata == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return slice(unsafe.Pointer(vdata), int(C.int(vlen)))
|
|
|
|
}
|
|
|
|
|
|
|
|
//Copy key to b, if b len is small or nil, returns a new one
|
|
|
|
func (it *Iterator) BufKey(b []byte) []byte {
|
|
|
|
k := it.RawKey()
|
|
|
|
if k == nil {
|
|
|
|
return nil
|
|
|
|
}
|
2014-07-07 11:36:16 +04:00
|
|
|
if b == nil {
|
|
|
|
b = []byte{}
|
2014-07-07 08:37:16 +04:00
|
|
|
}
|
|
|
|
|
2014-07-07 11:36:16 +04:00
|
|
|
b = b[0:0]
|
|
|
|
return append(b, k...)
|
2014-07-07 08:37:16 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
//Copy value to b, if b len is small or nil, returns a new one
|
|
|
|
func (it *Iterator) BufValue(b []byte) []byte {
|
|
|
|
v := it.RawValue()
|
|
|
|
if v == nil {
|
|
|
|
return nil
|
|
|
|
}
|
2014-07-07 11:36:16 +04:00
|
|
|
|
|
|
|
if b == nil {
|
|
|
|
b = []byte{}
|
2014-07-07 08:37:16 +04:00
|
|
|
}
|
|
|
|
|
2014-07-07 11:36:16 +04:00
|
|
|
b = b[0:0]
|
|
|
|
return append(b, v...)
|
2014-07-07 08:37:16 +04:00
|
|
|
}
|
|
|
|
|
2014-06-19 13:19:40 +04:00
|
|
|
func (it *Iterator) Close() {
|
|
|
|
C.leveldb_iter_destroy(it.it)
|
|
|
|
it.it = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (it *Iterator) Valid() bool {
|
2014-07-07 08:37:16 +04:00
|
|
|
return ucharToBool(it.isValid)
|
2014-06-19 13:19:40 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (it *Iterator) Next() {
|
2014-07-07 08:37:16 +04:00
|
|
|
it.isValid = C.leveldb_iter_next_ext(it.it)
|
2014-06-19 13:19:40 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (it *Iterator) Prev() {
|
2014-07-07 08:37:16 +04:00
|
|
|
it.isValid = C.leveldb_iter_prev_ext(it.it)
|
2014-06-19 13:19:40 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (it *Iterator) SeekToFirst() {
|
2014-07-07 08:37:16 +04:00
|
|
|
it.isValid = C.leveldb_iter_seek_to_first_ext(it.it)
|
2014-06-19 13:19:40 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (it *Iterator) SeekToLast() {
|
2014-07-07 08:37:16 +04:00
|
|
|
it.isValid = C.leveldb_iter_seek_to_last_ext(it.it)
|
2014-06-19 13:19:40 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (it *Iterator) Seek(key []byte) {
|
2014-07-07 08:37:16 +04:00
|
|
|
it.isValid = C.leveldb_iter_seek_ext(it.it, (*C.char)(unsafe.Pointer(&key[0])), C.size_t(len(key)))
|
2014-06-19 13:19:40 +04:00
|
|
|
}
|
|
|
|
|
2014-07-07 08:37:16 +04:00
|
|
|
//Finds by key, if not found, nil returns
|
2014-06-19 13:19:40 +04:00
|
|
|
func (it *Iterator) Find(key []byte) []byte {
|
|
|
|
it.Seek(key)
|
2014-06-19 13:45:52 +04:00
|
|
|
if it.Valid() {
|
2014-07-07 08:37:16 +04:00
|
|
|
k := it.RawKey()
|
|
|
|
if k == nil {
|
2014-06-19 13:45:52 +04:00
|
|
|
return nil
|
2014-07-07 08:37:16 +04:00
|
|
|
} else if bytes.Equal(k, key) {
|
2014-06-19 13:45:52 +04:00
|
|
|
return it.Value()
|
|
|
|
}
|
2014-06-19 13:19:40 +04:00
|
|
|
}
|
2014-06-19 13:45:52 +04:00
|
|
|
|
|
|
|
return nil
|
2014-06-19 13:19:40 +04:00
|
|
|
}
|
|
|
|
|
2014-07-07 08:37:16 +04:00
|
|
|
//Finds by key, if not found, nil returns, else a reference of value returns
|
|
|
|
//you must be careful that it will be changed after next iterate.
|
|
|
|
func (it *Iterator) RawFind(key []byte) []byte {
|
|
|
|
it.Seek(key)
|
|
|
|
if it.Valid() {
|
|
|
|
k := it.RawKey()
|
|
|
|
if k == nil {
|
|
|
|
return nil
|
|
|
|
} else if bytes.Equal(k, key) {
|
|
|
|
return it.RawValue()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-06-19 13:19:40 +04:00
|
|
|
type RangeLimitIterator struct {
|
|
|
|
it *Iterator
|
|
|
|
|
|
|
|
r *Range
|
2014-07-04 09:27:57 +04:00
|
|
|
l *Limit
|
2014-06-19 13:19:40 +04:00
|
|
|
|
|
|
|
step int
|
|
|
|
|
|
|
|
//0 for IteratorForward, 1 for IteratorBackward
|
|
|
|
direction uint8
|
|
|
|
}
|
|
|
|
|
|
|
|
func (it *RangeLimitIterator) Key() []byte {
|
|
|
|
return it.it.Key()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (it *RangeLimitIterator) Value() []byte {
|
|
|
|
return it.it.Value()
|
|
|
|
}
|
|
|
|
|
2014-07-07 08:37:16 +04:00
|
|
|
func (it *RangeLimitIterator) RawKey() []byte {
|
|
|
|
return it.it.RawKey()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (it *RangeLimitIterator) RawValue() []byte {
|
|
|
|
return it.it.RawValue()
|
|
|
|
}
|
|
|
|
|
2014-07-07 10:50:58 +04:00
|
|
|
func (it *RangeLimitIterator) BufKey(b []byte) []byte {
|
|
|
|
return it.it.BufKey(b)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (it *RangeLimitIterator) BufValue(b []byte) []byte {
|
|
|
|
return it.it.BufValue(b)
|
|
|
|
}
|
|
|
|
|
2014-06-19 13:19:40 +04:00
|
|
|
func (it *RangeLimitIterator) Valid() bool {
|
2014-07-04 09:27:57 +04:00
|
|
|
if it.l.Offset < 0 {
|
2014-06-19 13:19:40 +04:00
|
|
|
return false
|
|
|
|
} else if !it.it.Valid() {
|
|
|
|
return false
|
2014-07-04 09:27:57 +04:00
|
|
|
} else if it.l.Count >= 0 && it.step >= it.l.Count {
|
2014-06-19 13:19:40 +04:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if it.direction == IteratorForward {
|
|
|
|
if it.r.Max != nil {
|
2014-07-07 08:37:16 +04:00
|
|
|
r := bytes.Compare(it.it.RawKey(), it.r.Max)
|
2014-06-19 13:19:40 +04:00
|
|
|
if it.r.Type&RangeROpen > 0 {
|
|
|
|
return !(r >= 0)
|
|
|
|
} else {
|
|
|
|
return !(r > 0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if it.r.Min != nil {
|
2014-07-07 08:37:16 +04:00
|
|
|
r := bytes.Compare(it.it.RawKey(), it.r.Min)
|
2014-06-19 13:19:40 +04:00
|
|
|
if it.r.Type&RangeLOpen > 0 {
|
|
|
|
return !(r <= 0)
|
|
|
|
} else {
|
|
|
|
return !(r < 0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (it *RangeLimitIterator) Next() {
|
|
|
|
it.step++
|
|
|
|
|
|
|
|
if it.direction == IteratorForward {
|
|
|
|
it.it.Next()
|
|
|
|
} else {
|
|
|
|
it.it.Prev()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (it *RangeLimitIterator) Close() {
|
|
|
|
it.it.Close()
|
|
|
|
}
|
|
|
|
|
2014-07-04 09:27:57 +04:00
|
|
|
func NewRangeLimitIterator(i *Iterator, r *Range, l *Limit) *RangeLimitIterator {
|
|
|
|
return rangeLimitIterator(i, r, l, IteratorForward)
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewRevRangeLimitIterator(i *Iterator, r *Range, l *Limit) *RangeLimitIterator {
|
|
|
|
return rangeLimitIterator(i, r, l, IteratorBackward)
|
|
|
|
}
|
|
|
|
|
|
|
|
func rangeLimitIterator(i *Iterator, r *Range, l *Limit, direction uint8) *RangeLimitIterator {
|
2014-06-19 13:19:40 +04:00
|
|
|
it := new(RangeLimitIterator)
|
|
|
|
|
|
|
|
it.it = i
|
|
|
|
|
|
|
|
it.r = r
|
2014-07-04 09:27:57 +04:00
|
|
|
it.l = l
|
2014-06-19 13:19:40 +04:00
|
|
|
it.direction = direction
|
|
|
|
|
|
|
|
it.step = 0
|
|
|
|
|
2014-07-04 09:27:57 +04:00
|
|
|
if l.Offset < 0 {
|
2014-06-19 13:19:40 +04:00
|
|
|
return it
|
|
|
|
}
|
|
|
|
|
|
|
|
if direction == IteratorForward {
|
|
|
|
if r.Min == nil {
|
|
|
|
it.it.SeekToFirst()
|
|
|
|
} else {
|
|
|
|
it.it.Seek(r.Min)
|
|
|
|
|
|
|
|
if r.Type&RangeLOpen > 0 {
|
2014-07-07 08:37:16 +04:00
|
|
|
if it.it.Valid() && bytes.Equal(it.it.RawKey(), r.Min) {
|
2014-06-19 13:19:40 +04:00
|
|
|
it.it.Next()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if r.Max == nil {
|
|
|
|
it.it.SeekToLast()
|
|
|
|
} else {
|
|
|
|
it.it.Seek(r.Max)
|
|
|
|
|
|
|
|
if !it.it.Valid() {
|
|
|
|
it.it.SeekToLast()
|
|
|
|
} else {
|
2014-07-07 08:37:16 +04:00
|
|
|
if !bytes.Equal(it.it.RawKey(), r.Max) {
|
2014-06-19 13:19:40 +04:00
|
|
|
it.it.Prev()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if r.Type&RangeROpen > 0 {
|
2014-07-07 08:37:16 +04:00
|
|
|
if it.it.Valid() && bytes.Equal(it.it.RawKey(), r.Max) {
|
2014-06-19 13:19:40 +04:00
|
|
|
it.it.Prev()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-04 09:27:57 +04:00
|
|
|
for i := 0; i < l.Offset; i++ {
|
2014-06-19 13:19:40 +04:00
|
|
|
if it.it.Valid() {
|
|
|
|
if it.direction == IteratorForward {
|
|
|
|
it.it.Next()
|
|
|
|
} else {
|
|
|
|
it.it.Prev()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return it
|
|
|
|
}
|