github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/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 // Get returns the value for the given key 107 func (dbInst *DB) Get(key []byte) ([]byte, error) { 108 value, err := dbInst.db.Get(key, dbInst.readOpts) 109 if err == leveldb.ErrNotFound { 110 value = nil 111 err = nil 112 } 113 if err != nil { 114 logger.Errorf("Error while trying to retrieve key [%#v]: %s", key, err) 115 return nil, err 116 } 117 return value, nil 118 } 119 120 // Put saves the key/value 121 func (dbInst *DB) Put(key []byte, value []byte, sync bool) error { 122 wo := dbInst.writeOptsNoSync 123 if sync { 124 wo = dbInst.writeOptsSync 125 } 126 err := dbInst.db.Put(key, value, wo) 127 if err != nil { 128 logger.Errorf("Error while trying to write key [%#v]", key) 129 return err 130 } 131 return nil 132 } 133 134 // Delete deletes the given key 135 func (dbInst *DB) Delete(key []byte, sync bool) error { 136 wo := dbInst.writeOptsNoSync 137 if sync { 138 wo = dbInst.writeOptsSync 139 } 140 err := dbInst.db.Delete(key, wo) 141 if err != nil { 142 logger.Errorf("Error while trying to delete key [%#v]", key) 143 return err 144 } 145 return nil 146 } 147 148 // GetIterator returns an iterator over key-value store. The iterator should be released after the use. 149 // The resultset contains all the keys that are present in the db between the startKey (inclusive) and the endKey (exclusive). 150 // A nil startKey represents the first available key and a nil endKey represent a logical key after the last available key 151 func (dbInst *DB) GetIterator(startKey []byte, endKey []byte) iterator.Iterator { 152 return dbInst.db.NewIterator(&goleveldbutil.Range{Start: startKey, Limit: endKey}, dbInst.readOpts) 153 } 154 155 // WriteBatch writes a batch 156 func (dbInst *DB) WriteBatch(batch *leveldb.Batch, sync bool) error { 157 wo := dbInst.writeOptsNoSync 158 if sync { 159 wo = dbInst.writeOptsSync 160 } 161 if err := dbInst.db.Write(batch, wo); err != nil { 162 return err 163 } 164 return nil 165 }