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  }