This repository has been archived by the owner on Apr 23, 2020. It is now read-only.
/
leveldb.go
124 lines (114 loc) · 3.3 KB
/
leveldb.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
package obox
/*
#include <leveldb/c.h>
#include <stdlib.h>
#cgo LDFLAGS: -lleveldb
*/
import "C"
import (
"unsafe"
"errors"
"fmt"
"bytes"
"reflect"
)
const (
levelFalse = C.uchar(0)
levelCacheCap = C.size_t(10240)
)
type Leveldb struct {
cdb *C.leveldb_t
read_options *C.leveldb_readoptions_t
write_options *C.leveldb_writeoptions_t
cache *C.leveldb_cache_t
}
func OpenLeveldb(dir string) (*Leveldb, error) {
options := C.leveldb_options_create()
C.leveldb_options_set_create_if_missing(options, C.uchar(1))
cache := C.leveldb_cache_create_lru(levelCacheCap)
C.leveldb_options_set_cache(options, cache)
cDir := C.CString(dir)
defer C.free(unsafe.Pointer(cDir))
var err *C.char
db := C.leveldb_open(options, cDir, &err)
if err != nil {
return nil, errors.New(fmt.Sprintf("%s: %s", err, dir))
}
C.leveldb_free(unsafe.Pointer(err)); err = nil
leveldb := &Leveldb{
cdb: db,
read_options: C.leveldb_readoptions_create(),
write_options: C.leveldb_writeoptions_create(),
cache: cache,
}
return leveldb, nil
}
func (self *Leveldb) Close() error {
C.leveldb_close(self.cdb)
C.leveldb_readoptions_destroy(self.read_options)
C.leveldb_writeoptions_destroy(self.write_options)
C.leveldb_cache_destroy(self.cache)
return nil
}
func (self *Leveldb) Count() (n int64) {
self.Iter(func(string, Getter) bool {
n++
return true
})
return
}
func (self *Leveldb) Iter(fun func(string, Getter) bool) {
iterator := C.leveldb_create_iterator(self.cdb, self.read_options)
defer C.leveldb_iter_destroy(iterator)
var keyLen C.size_t
var keyValue *C.char
var valueLen C.size_t
var valueValue *C.char
var ret bool
for C.leveldb_iter_seek_to_first(iterator); C.leveldb_iter_valid(iterator) != levelFalse; C.leveldb_iter_next(iterator) {
keyValue = C.leveldb_iter_key(iterator, &keyLen)
key := string(C.GoBytes(unsafe.Pointer(keyValue), C.int(keyLen)))
valueValue = C.leveldb_iter_value(iterator, &valueLen)
value := C.GoBytes(unsafe.Pointer(valueValue), C.int(valueLen))
r := bytes.NewReader(value)
ret = fun(key, func(e interface{}) error {
return decode(r, e)
})
if ret == false {
break
}
}
}
func (self *Leveldb) Get(key string, obj interface{}) error {
cKey := C.CString(key)
defer C.free(unsafe.Pointer(cKey))
var valueLen C.size_t
var cerr *C.char
valueValue := C.leveldb_get(self.cdb, self.read_options, cKey, C.size_t(len(key)), &valueLen, &cerr)
if cerr != nil {
return errors.New(fmt.Sprintf("%s", cerr))
}
bs := C.GoBytes(unsafe.Pointer(valueValue), C.int(valueLen))
r := bytes.NewReader(bs)
err := decode(r, obj)
if err != nil { return err }
return nil
}
func (self *Leveldb) Set(key string, obj interface{}) error {
buf := new(bytes.Buffer)
err := encode(buf, obj)
if err != nil { return err }
value := buf.Bytes()
cKey := C.CString(key)
defer C.free(unsafe.Pointer(cKey))
header := (*reflect.SliceHeader)(unsafe.Pointer(&value))
var cerr *C.char
C.leveldb_put(self.cdb, self.write_options, cKey, C.size_t(len(key)), (*C.char)(unsafe.Pointer(header.Data)), C.size_t(header.Len), &cerr)
if cerr != nil {
return errors.New(fmt.Sprintf("%s", cerr))
}
return nil
}
func (self *Leveldb) SetDefault(key string, obj interface{}) (bool, error) {
return false, nil //TODO
}