github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/core/ledger/kvledger/txmgmt/statedb/stateleveldb/stateleveldb.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 stateleveldb
    18  
    19  import (
    20  	"bytes"
    21  	"errors"
    22  
    23  	"github.com/hyperledger/fabric/common/flogging"
    24  	"github.com/hyperledger/fabric/common/ledger/util/leveldbhelper"
    25  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/statedb"
    26  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version"
    27  	"github.com/hyperledger/fabric/core/ledger/ledgerconfig"
    28  	"github.com/syndtr/goleveldb/leveldb/iterator"
    29  )
    30  
    31  var logger = flogging.MustGetLogger("stateleveldb")
    32  
    33  var compositeKeySep = []byte{0x00}
    34  var lastKeyIndicator = byte(0x01)
    35  var savePointKey = []byte{0x00}
    36  
    37  // VersionedDBProvider implements interface VersionedDBProvider
    38  type VersionedDBProvider struct {
    39  	dbProvider *leveldbhelper.Provider
    40  }
    41  
    42  // NewVersionedDBProvider instantiates VersionedDBProvider
    43  func NewVersionedDBProvider() *VersionedDBProvider {
    44  	dbPath := ledgerconfig.GetStateLevelDBPath()
    45  	logger.Debugf("constructing VersionedDBProvider dbPath=%s", dbPath)
    46  	dbProvider := leveldbhelper.NewProvider(&leveldbhelper.Conf{DBPath: dbPath})
    47  	return &VersionedDBProvider{dbProvider}
    48  }
    49  
    50  // GetDBHandle gets the handle to a named database
    51  func (provider *VersionedDBProvider) GetDBHandle(dbName string) (statedb.VersionedDB, error) {
    52  	return newVersionedDB(provider.dbProvider.GetDBHandle(dbName), dbName), nil
    53  }
    54  
    55  // Close closes the underlying db
    56  func (provider *VersionedDBProvider) Close() {
    57  	provider.dbProvider.Close()
    58  }
    59  
    60  // VersionedDB implements VersionedDB interface
    61  type versionedDB struct {
    62  	db     *leveldbhelper.DBHandle
    63  	dbName string
    64  }
    65  
    66  // newVersionedDB constructs an instance of VersionedDB
    67  func newVersionedDB(db *leveldbhelper.DBHandle, dbName string) *versionedDB {
    68  	return &versionedDB{db, dbName}
    69  }
    70  
    71  // Open implements method in VersionedDB interface
    72  func (vdb *versionedDB) Open() error {
    73  	// do nothing because shared db is used
    74  	return nil
    75  }
    76  
    77  // Close implements method in VersionedDB interface
    78  func (vdb *versionedDB) Close() {
    79  	// do nothing because shared db is used
    80  }
    81  
    82  // GetState implements method in VersionedDB interface
    83  func (vdb *versionedDB) GetState(namespace string, key string) (*statedb.VersionedValue, error) {
    84  	logger.Debugf("GetState(). ns=%s, key=%s", namespace, key)
    85  	compositeKey := constructCompositeKey(namespace, key)
    86  	dbVal, err := vdb.db.Get(compositeKey)
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  	if dbVal == nil {
    91  		return nil, nil
    92  	}
    93  	val, ver := statedb.DecodeValue(dbVal)
    94  	return &statedb.VersionedValue{Value: val, Version: ver}, nil
    95  }
    96  
    97  // GetStateMultipleKeys implements method in VersionedDB interface
    98  func (vdb *versionedDB) GetStateMultipleKeys(namespace string, keys []string) ([]*statedb.VersionedValue, error) {
    99  	vals := make([]*statedb.VersionedValue, len(keys))
   100  	for i, key := range keys {
   101  		val, err := vdb.GetState(namespace, key)
   102  		if err != nil {
   103  			return nil, err
   104  		}
   105  		vals[i] = val
   106  	}
   107  	return vals, nil
   108  }
   109  
   110  // GetStateRangeScanIterator implements method in VersionedDB interface
   111  // startKey is inclusive
   112  // endKey is exclusive
   113  func (vdb *versionedDB) GetStateRangeScanIterator(namespace string, startKey string, endKey string) (statedb.ResultsIterator, error) {
   114  	compositeStartKey := constructCompositeKey(namespace, startKey)
   115  	compositeEndKey := constructCompositeKey(namespace, endKey)
   116  	if endKey == "" {
   117  		compositeEndKey[len(compositeEndKey)-1] = lastKeyIndicator
   118  	}
   119  	dbItr := vdb.db.GetIterator(compositeStartKey, compositeEndKey)
   120  	return newKVScanner(namespace, dbItr), nil
   121  }
   122  
   123  // ExecuteQuery implements method in VersionedDB interface
   124  func (vdb *versionedDB) ExecuteQuery(namespace, query string) (statedb.ResultsIterator, error) {
   125  	return nil, errors.New("ExecuteQuery not supported for leveldb")
   126  }
   127  
   128  // ApplyUpdates implements method in VersionedDB interface
   129  func (vdb *versionedDB) ApplyUpdates(batch *statedb.UpdateBatch, height *version.Height) error {
   130  	dbBatch := leveldbhelper.NewUpdateBatch()
   131  	namespaces := batch.GetUpdatedNamespaces()
   132  	for _, ns := range namespaces {
   133  		updates := batch.GetUpdates(ns)
   134  		for k, vv := range updates {
   135  			compositeKey := constructCompositeKey(ns, k)
   136  			logger.Debugf("Channel [%s]: Applying key=[%#v]", vdb.dbName, compositeKey)
   137  
   138  			if vv.Value == nil {
   139  				dbBatch.Delete(compositeKey)
   140  			} else {
   141  				dbBatch.Put(compositeKey, statedb.EncodeValue(vv.Value, vv.Version))
   142  			}
   143  		}
   144  	}
   145  	dbBatch.Put(savePointKey, height.ToBytes())
   146  	if err := vdb.db.WriteBatch(dbBatch, false); err != nil {
   147  		return err
   148  	}
   149  	return nil
   150  }
   151  
   152  // GetLatestSavePoint implements method in VersionedDB interface
   153  func (vdb *versionedDB) GetLatestSavePoint() (*version.Height, error) {
   154  	versionBytes, err := vdb.db.Get(savePointKey)
   155  	if err != nil {
   156  		return nil, err
   157  	}
   158  	if versionBytes == nil {
   159  		return nil, nil
   160  	}
   161  	version, _ := version.NewHeightFromBytes(versionBytes)
   162  	return version, nil
   163  }
   164  
   165  func constructCompositeKey(ns string, key string) []byte {
   166  	return append(append([]byte(ns), compositeKeySep...), []byte(key)...)
   167  }
   168  
   169  func splitCompositeKey(compositeKey []byte) (string, string) {
   170  	split := bytes.SplitN(compositeKey, compositeKeySep, 2)
   171  	return string(split[0]), string(split[1])
   172  }
   173  
   174  type kvScanner struct {
   175  	namespace string
   176  	dbItr     iterator.Iterator
   177  }
   178  
   179  func newKVScanner(namespace string, dbItr iterator.Iterator) *kvScanner {
   180  	return &kvScanner{namespace, dbItr}
   181  }
   182  
   183  func (scanner *kvScanner) Next() (statedb.QueryResult, error) {
   184  	if !scanner.dbItr.Next() {
   185  		return nil, nil
   186  	}
   187  	dbKey := scanner.dbItr.Key()
   188  	dbVal := scanner.dbItr.Value()
   189  	dbValCopy := make([]byte, len(dbVal))
   190  	copy(dbValCopy, dbVal)
   191  	_, key := splitCompositeKey(dbKey)
   192  	value, version := statedb.DecodeValue(dbValCopy)
   193  	return &statedb.VersionedKV{
   194  		CompositeKey:   statedb.CompositeKey{Namespace: scanner.namespace, Key: key},
   195  		VersionedValue: statedb.VersionedValue{Value: value, Version: version}}, nil
   196  }
   197  
   198  func (scanner *kvScanner) Close() {
   199  	scanner.dbItr.Release()
   200  }