forked from gitter-badger/go-vnt
-
Notifications
You must be signed in to change notification settings - Fork 1
/
database.go
133 lines (119 loc) · 3.3 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
// Copyright 2019 The go-vnt Authors
// This file is part of the go-vnt library.
//
// The go-vnt library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-vnt library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-vnt library. If not, see <http://www.gnu.org/licenses/>.
package vntp2p
import (
"fmt"
ds "github.com/ipfs/go-datastore"
"github.com/ipfs/go-datastore/query"
"github.com/syndtr/goleveldb/leveldb"
)
// LevelDB vntdb object
type LevelDB struct {
path string
db *leveldb.DB
}
// 最好使用单例,因为leveldb只能有一个打开句柄,而且这个句柄是线程安全的。
var vntdb *LevelDB
// GetDatastore singleton design pattern
func GetDatastore(path string) (*LevelDB, error) {
if vntdb != nil && vntdb.path == path {
return vntdb, nil
}
vntdb, err := newDatastore(path)
if err != nil {
return nil, err
}
return vntdb, nil
}
func newDatastore(path string) (*LevelDB, error) {
db, err := leveldb.OpenFile(path, nil)
if err != nil {
return nil, err
}
return &LevelDB{
path: path,
db: db,
}, nil
}
// Put implement Put() of ds.Batching interface
func (d *LevelDB) Put(key ds.Key, value interface{}) (err error) {
byteKey := []byte(key.String())
byteVal, ok := value.([]byte)
if !ok {
return ds.ErrInvalidType
}
err = d.db.Put(byteKey, byteVal, nil)
if err != nil {
fmt.Printf("leveldb put error = %s\n", err)
return err
}
return nil
}
// Get implement Get() of ds.Batching interface
func (d *LevelDB) Get(key ds.Key) (value interface{}, err error) {
byteKey := []byte(key.String())
byteVal, err := d.db.Get(byteKey, nil)
if err == leveldb.ErrNotFound {
return nil, ds.ErrNotFound
}
if err != nil {
return nil, err
}
return byteVal, nil
}
// Has implement Has() of ds.Batching interface
func (d *LevelDB) Has(key ds.Key) (exists bool, err error) {
byteKey := []byte(key.String())
exists, err = d.db.Has(byteKey, nil)
if err != nil {
return false, err
}
return exists, nil
}
// Delete implement Delete() of ds.Batching interface
func (d *LevelDB) Delete(key ds.Key) (err error) {
byteKey := []byte(key.String())
err = d.db.Delete(byteKey, nil)
if err != nil {
return err
}
return nil
}
// Query implement Query() of ds.Batching interface
func (d *LevelDB) Query(q query.Query) (query.Results, error) {
var re []query.Entry
iter := d.db.NewIterator(nil, nil)
for iter.Next() {
keyByte := iter.Key()
valueByte := iter.Value()
re = append(re, query.Entry{Key: string(keyByte), Value: valueByte})
}
r := query.ResultsWithEntries(q, re)
r = query.NaiveQueryApply(q, r)
return r, nil
}
// Close implement Close() of ds.Batching interface
func (d *LevelDB) Close() error {
err := d.db.Close()
if err != nil {
return err
}
return nil
}
// Batch implement Batch() of ds.Batching interface
func (d *LevelDB) Batch() (ds.Batch, error) {
return ds.NewBasicBatch(d), nil
}