github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/common/ledger/util/leveldbhelper/leveldb_helper.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package leveldbhelper 18 19 import ( 20 "fmt" 21 "sync" 22 23 "github.com/hyperledger/fabric/common/flogging" 24 "github.com/hyperledger/fabric/common/ledger/util" 25 "github.com/syndtr/goleveldb/leveldb" 26 "github.com/syndtr/goleveldb/leveldb/iterator" 27 "github.com/syndtr/goleveldb/leveldb/opt" 28 goleveldbutil "github.com/syndtr/goleveldb/leveldb/util" 29 ) 30 31 var logger = flogging.MustGetLogger("leveldbhelper") 32 33 type dbState int32 34 35 const ( 36 closed dbState = iota 37 opened 38 ) 39 40 // Conf configuration for `DB` 41 type Conf struct { 42 DBPath string 43 } 44 45 // DB - a wrapper on an actual store 46 type DB struct { 47 conf *Conf 48 db *leveldb.DB 49 dbState dbState 50 mux sync.Mutex 51 52 readOpts *opt.ReadOptions 53 writeOptsNoSync *opt.WriteOptions 54 writeOptsSync *opt.WriteOptions 55 } 56 57 // CreateDB constructs a `DB` 58 func CreateDB(conf *Conf) *DB { 59 readOpts := &opt.ReadOptions{} 60 writeOptsNoSync := &opt.WriteOptions{} 61 writeOptsSync := &opt.WriteOptions{} 62 writeOptsSync.Sync = true 63 64 return &DB{ 65 conf: conf, 66 dbState: closed, 67 readOpts: readOpts, 68 writeOptsNoSync: writeOptsNoSync, 69 writeOptsSync: writeOptsSync} 70 } 71 72 // Open opens the underlying db 73 func (dbInst *DB) Open() { 74 dbInst.mux.Lock() 75 defer dbInst.mux.Unlock() 76 if dbInst.dbState == opened { 77 return 78 } 79 dbOpts := &opt.Options{} 80 dbPath := dbInst.conf.DBPath 81 var err error 82 var dirEmpty bool 83 if dirEmpty, err = util.CreateDirIfMissing(dbPath); err != nil { 84 panic(fmt.Sprintf("Error while trying to create dir if missing: %s", err)) 85 } 86 dbOpts.ErrorIfMissing = !dirEmpty 87 if dbInst.db, err = leveldb.OpenFile(dbPath, dbOpts); err != nil { 88 panic(fmt.Sprintf("Error while trying to open DB: %s", err)) 89 } 90 dbInst.dbState = opened 91 } 92 93 // Close closes the underlying db 94 func (dbInst *DB) Close() { 95 dbInst.mux.Lock() 96 defer dbInst.mux.Unlock() 97 if dbInst.dbState == closed { 98 return 99 } 100 if err := dbInst.db.Close(); err != nil { 101 logger.Errorf("Error while closing DB: %s", err) 102 } 103 dbInst.dbState = closed 104 } 105 106 func (dbInst *DB) isOpen() bool { 107 dbInst.mux.Lock() 108 defer dbInst.mux.Unlock() 109 return dbInst.dbState == opened 110 } 111 112 // Get returns the value for the given key 113 func (dbInst *DB) Get(key []byte) ([]byte, error) { 114 value, err := dbInst.db.Get(key, dbInst.readOpts) 115 if err == leveldb.ErrNotFound { 116 value = nil 117 err = nil 118 } 119 if err != nil { 120 logger.Errorf("Error while trying to retrieve key [%#v]: %s", key, err) 121 return nil, err 122 } 123 return value, nil 124 } 125 126 // Put saves the key/value 127 func (dbInst *DB) Put(key []byte, value []byte, sync bool) error { 128 wo := dbInst.writeOptsNoSync 129 if sync { 130 wo = dbInst.writeOptsSync 131 } 132 err := dbInst.db.Put(key, value, wo) 133 if err != nil { 134 logger.Errorf("Error while trying to write key [%#v]", key) 135 return err 136 } 137 return nil 138 } 139 140 // Delete deletes the given key 141 func (dbInst *DB) Delete(key []byte, sync bool) error { 142 wo := dbInst.writeOptsNoSync 143 if sync { 144 wo = dbInst.writeOptsSync 145 } 146 err := dbInst.db.Delete(key, wo) 147 if err != nil { 148 logger.Errorf("Error while trying to delete key [%#v]", key) 149 return err 150 } 151 return nil 152 } 153 154 // GetIterator returns an iterator over key-value store. The iterator should be released after the use. 155 // The resultset contains all the keys that are present in the db between the startKey (inclusive) and the endKey (exclusive). 156 // A nil startKey represents the first available key and a nil endKey represent a logical key after the last available key 157 func (dbInst *DB) GetIterator(startKey []byte, endKey []byte) iterator.Iterator { 158 return dbInst.db.NewIterator(&goleveldbutil.Range{Start: startKey, Limit: endKey}, dbInst.readOpts) 159 } 160 161 // WriteBatch writes a batch 162 func (dbInst *DB) WriteBatch(batch *leveldb.Batch, sync bool) error { 163 wo := dbInst.writeOptsNoSync 164 if sync { 165 wo = dbInst.writeOptsSync 166 } 167 if err := dbInst.db.Write(batch, wo); err != nil { 168 return err 169 } 170 return nil 171 }