github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/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  // ValidateKey implements method in VersionedDB interface
    83  func (vdb *versionedDB) ValidateKey(key string) error {
    84  	return nil
    85  }
    86  
    87  // GetState implements method in VersionedDB interface
    88  func (vdb *versionedDB) GetState(namespace string, key string) (*statedb.VersionedValue, error) {
    89  	logger.Debugf("GetState(). ns=%s, key=%s", namespace, key)
    90  	compositeKey := constructCompositeKey(namespace, key)
    91  	dbVal, err := vdb.db.Get(compositeKey)
    92  	if err != nil {
    93  		return nil, err
    94  	}
    95  	if dbVal == nil {
    96  		return nil, nil
    97  	}
    98  	val, ver := statedb.DecodeValue(dbVal)
    99  	return &statedb.VersionedValue{Value: val, Version: ver}, nil
   100  }
   101  
   102  // GetStateMultipleKeys implements method in VersionedDB interface
   103  func (vdb *versionedDB) GetStateMultipleKeys(namespace string, keys []string) ([]*statedb.VersionedValue, error) {
   104  	vals := make([]*statedb.VersionedValue, len(keys))
   105  	for i, key := range keys {
   106  		val, err := vdb.GetState(namespace, key)
   107  		if err != nil {
   108  			return nil, err
   109  		}
   110  		vals[i] = val
   111  	}
   112  	return vals, nil
   113  }
   114  
   115  // GetStateRangeScanIterator implements method in VersionedDB interface
   116  // startKey is inclusive
   117  // endKey is exclusive
   118  func (vdb *versionedDB) GetStateRangeScanIterator(namespace string, startKey string, endKey string) (statedb.ResultsIterator, error) {
   119  	compositeStartKey := constructCompositeKey(namespace, startKey)
   120  	compositeEndKey := constructCompositeKey(namespace, endKey)
   121  	if endKey == "" {
   122  		compositeEndKey[len(compositeEndKey)-1] = lastKeyIndicator
   123  	}
   124  	dbItr := vdb.db.GetIterator(compositeStartKey, compositeEndKey)
   125  	return newKVScanner(namespace, dbItr), nil
   126  }
   127  
   128  // ExecuteQuery implements method in VersionedDB interface
   129  func (vdb *versionedDB) ExecuteQuery(namespace, query string) (statedb.ResultsIterator, error) {
   130  	return nil, errors.New("ExecuteQuery not supported for leveldb")
   131  }
   132  
   133  // ApplyUpdates implements method in VersionedDB interface
   134  func (vdb *versionedDB) ApplyUpdates(batch *statedb.UpdateBatch, height *version.Height) error {
   135  	dbBatch := leveldbhelper.NewUpdateBatch()
   136  	namespaces := batch.GetUpdatedNamespaces()
   137  	for _, ns := range namespaces {
   138  		updates := batch.GetUpdates(ns)
   139  		for k, vv := range updates {
   140  			compositeKey := constructCompositeKey(ns, k)
   141  			logger.Debugf("Channel [%s]: Applying key=[%#v]", vdb.dbName, compositeKey)
   142  
   143  			if vv.Value == nil {
   144  				dbBatch.Delete(compositeKey)
   145  			} else {
   146  				dbBatch.Put(compositeKey, statedb.EncodeValue(vv.Value, vv.Version))
   147  			}
   148  		}
   149  	}
   150  	dbBatch.Put(savePointKey, height.ToBytes())
   151  	// Setting snyc to true as a precaution, false may be an ok optimization after further testing.
   152  	if err := vdb.db.WriteBatch(dbBatch, true); err != nil {
   153  		return err
   154  	}
   155  	return nil
   156  }
   157  
   158  // GetLatestSavePoint implements method in VersionedDB interface
   159  func (vdb *versionedDB) GetLatestSavePoint() (*version.Height, error) {
   160  	versionBytes, err := vdb.db.Get(savePointKey)
   161  	if err != nil {
   162  		return nil, err
   163  	}
   164  	if versionBytes == nil {
   165  		return nil, nil
   166  	}
   167  	version, _ := version.NewHeightFromBytes(versionBytes)
   168  	return version, nil
   169  }
   170  
   171  func constructCompositeKey(ns string, key string) []byte {
   172  	return append(append([]byte(ns), compositeKeySep...), []byte(key)...)
   173  }
   174  
   175  func splitCompositeKey(compositeKey []byte) (string, string) {
   176  	split := bytes.SplitN(compositeKey, compositeKeySep, 2)
   177  	return string(split[0]), string(split[1])
   178  }
   179  
   180  type kvScanner struct {
   181  	namespace string
   182  	dbItr     iterator.Iterator
   183  }
   184  
   185  func newKVScanner(namespace string, dbItr iterator.Iterator) *kvScanner {
   186  	return &kvScanner{namespace, dbItr}
   187  }
   188  
   189  func (scanner *kvScanner) Next() (statedb.QueryResult, error) {
   190  	if !scanner.dbItr.Next() {
   191  		return nil, nil
   192  	}
   193  	dbKey := scanner.dbItr.Key()
   194  	dbVal := scanner.dbItr.Value()
   195  	dbValCopy := make([]byte, len(dbVal))
   196  	copy(dbValCopy, dbVal)
   197  	_, key := splitCompositeKey(dbKey)
   198  	value, version := statedb.DecodeValue(dbValCopy)
   199  	return &statedb.VersionedKV{
   200  		CompositeKey:   statedb.CompositeKey{Namespace: scanner.namespace, Key: key},
   201  		VersionedValue: statedb.VersionedValue{Value: value, Version: version}}, nil
   202  }
   203  
   204  func (scanner *kvScanner) Close() {
   205  	scanner.dbItr.Release()
   206  }