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  }