github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/ledger/kvledger/txmgmt/statedb/stateleveldb/stateleveldb.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package stateleveldb
     8  
     9  import (
    10  	"bytes"
    11  
    12  	"github.com/hechain20/hechain/common/flogging"
    13  	"github.com/hechain20/hechain/common/ledger/dataformat"
    14  	"github.com/hechain20/hechain/common/ledger/util/leveldbhelper"
    15  	"github.com/hechain20/hechain/core/ledger/internal/version"
    16  	"github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/statedb"
    17  	"github.com/pkg/errors"
    18  	"github.com/syndtr/goleveldb/leveldb/iterator"
    19  )
    20  
    21  var logger = flogging.MustGetLogger("stateleveldb")
    22  
    23  var (
    24  	dataKeyPrefix          = []byte{'d'}
    25  	dataKeyStopper         = []byte{'e'}
    26  	nsKeySep               = []byte{0x00}
    27  	lastKeyIndicator       = byte(0x01)
    28  	savePointKey           = []byte{'s'}
    29  	maxDataImportBatchSize = 4 * 1024 * 1024
    30  )
    31  
    32  // VersionedDBProvider implements interface VersionedDBProvider
    33  type VersionedDBProvider struct {
    34  	dbProvider *leveldbhelper.Provider
    35  }
    36  
    37  // NewVersionedDBProvider instantiates VersionedDBProvider
    38  func NewVersionedDBProvider(dbPath string) (*VersionedDBProvider, error) {
    39  	logger.Debugf("constructing VersionedDBProvider dbPath=%s", dbPath)
    40  	dbProvider, err := leveldbhelper.NewProvider(
    41  		&leveldbhelper.Conf{
    42  			DBPath:         dbPath,
    43  			ExpectedFormat: dataformat.CurrentFormat,
    44  		})
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  	return &VersionedDBProvider{dbProvider}, nil
    49  }
    50  
    51  // GetDBHandle gets the handle to a named database
    52  func (provider *VersionedDBProvider) GetDBHandle(dbName string, namespaceProvider statedb.NamespaceProvider) (statedb.VersionedDB, error) {
    53  	return newVersionedDB(provider.dbProvider.GetDBHandle(dbName), dbName), nil
    54  }
    55  
    56  // ImportFromSnapshot loads the public state and pvtdata hashes from the snapshot files previously generated
    57  func (provider *VersionedDBProvider) ImportFromSnapshot(
    58  	dbName string,
    59  	savepoint *version.Height,
    60  	itr statedb.FullScanIterator,
    61  ) error {
    62  	vdb := newVersionedDB(provider.dbProvider.GetDBHandle(dbName), dbName)
    63  	return vdb.importState(itr, savepoint)
    64  }
    65  
    66  // BytesKeySupported returns true if a db created supports bytes as a key
    67  func (provider *VersionedDBProvider) BytesKeySupported() bool {
    68  	return true
    69  }
    70  
    71  // Close closes the underlying db
    72  func (provider *VersionedDBProvider) Close() {
    73  	provider.dbProvider.Close()
    74  }
    75  
    76  // Drop drops channel-specific data from the state leveldb.
    77  // It is not an error if a database does not exist.
    78  func (provider *VersionedDBProvider) Drop(dbName string) error {
    79  	return provider.dbProvider.Drop(dbName)
    80  }
    81  
    82  // VersionedDB implements VersionedDB interface
    83  type versionedDB struct {
    84  	db     *leveldbhelper.DBHandle
    85  	dbName string
    86  }
    87  
    88  // newVersionedDB constructs an instance of VersionedDB
    89  func newVersionedDB(db *leveldbhelper.DBHandle, dbName string) *versionedDB {
    90  	return &versionedDB{db, dbName}
    91  }
    92  
    93  // Open implements method in VersionedDB interface
    94  func (vdb *versionedDB) Open() error {
    95  	// do nothing because shared db is used
    96  	return nil
    97  }
    98  
    99  // Close implements method in VersionedDB interface
   100  func (vdb *versionedDB) Close() {
   101  	// do nothing because shared db is used
   102  }
   103  
   104  // ValidateKeyValue implements method in VersionedDB interface
   105  func (vdb *versionedDB) ValidateKeyValue(key string, value []byte) error {
   106  	return nil
   107  }
   108  
   109  // BytesKeySupported implements method in VersionedDB interface
   110  func (vdb *versionedDB) BytesKeySupported() bool {
   111  	return true
   112  }
   113  
   114  // GetState implements method in VersionedDB interface
   115  func (vdb *versionedDB) GetState(namespace string, key string) (*statedb.VersionedValue, error) {
   116  	logger.Debugf("GetState(). ns=%s, key=%s", namespace, key)
   117  	dbVal, err := vdb.db.Get(encodeDataKey(namespace, key))
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  	if dbVal == nil {
   122  		return nil, nil
   123  	}
   124  	return decodeValue(dbVal)
   125  }
   126  
   127  // GetVersion implements method in VersionedDB interface
   128  func (vdb *versionedDB) GetVersion(namespace string, key string) (*version.Height, error) {
   129  	versionedValue, err := vdb.GetState(namespace, key)
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  	if versionedValue == nil {
   134  		return nil, nil
   135  	}
   136  	return versionedValue.Version, nil
   137  }
   138  
   139  // GetStateMultipleKeys implements method in VersionedDB interface
   140  func (vdb *versionedDB) GetStateMultipleKeys(namespace string, keys []string) ([]*statedb.VersionedValue, error) {
   141  	vals := make([]*statedb.VersionedValue, len(keys))
   142  	for i, key := range keys {
   143  		val, err := vdb.GetState(namespace, key)
   144  		if err != nil {
   145  			return nil, err
   146  		}
   147  		vals[i] = val
   148  	}
   149  	return vals, nil
   150  }
   151  
   152  // GetStateRangeScanIterator implements method in VersionedDB interface
   153  // startKey is inclusive
   154  // endKey is exclusive
   155  func (vdb *versionedDB) GetStateRangeScanIterator(namespace string, startKey string, endKey string) (statedb.ResultsIterator, error) {
   156  	// pageSize = 0 denotes unlimited page size
   157  	return vdb.GetStateRangeScanIteratorWithPagination(namespace, startKey, endKey, 0)
   158  }
   159  
   160  // GetStateRangeScanIteratorWithPagination implements method in VersionedDB interface
   161  func (vdb *versionedDB) GetStateRangeScanIteratorWithPagination(namespace string, startKey string, endKey string, pageSize int32) (statedb.QueryResultsIterator, error) {
   162  	dataStartKey := encodeDataKey(namespace, startKey)
   163  	dataEndKey := encodeDataKey(namespace, endKey)
   164  	if endKey == "" {
   165  		dataEndKey[len(dataEndKey)-1] = lastKeyIndicator
   166  	}
   167  	dbItr, err := vdb.db.GetIterator(dataStartKey, dataEndKey)
   168  	if err != nil {
   169  		return nil, err
   170  	}
   171  	return newKVScanner(namespace, dbItr, pageSize), nil
   172  }
   173  
   174  // ExecuteQuery implements method in VersionedDB interface
   175  func (vdb *versionedDB) ExecuteQuery(namespace, query string) (statedb.ResultsIterator, error) {
   176  	return nil, errors.New("ExecuteQuery not supported for leveldb")
   177  }
   178  
   179  // ExecuteQueryWithPagination implements method in VersionedDB interface
   180  func (vdb *versionedDB) ExecuteQueryWithPagination(namespace, query, bookmark string, pageSize int32) (statedb.QueryResultsIterator, error) {
   181  	return nil, errors.New("ExecuteQueryWithMetadata not supported for leveldb")
   182  }
   183  
   184  // ApplyUpdates implements method in VersionedDB interface
   185  func (vdb *versionedDB) ApplyUpdates(batch *statedb.UpdateBatch, height *version.Height) error {
   186  	dbBatch := vdb.db.NewUpdateBatch()
   187  	namespaces := batch.GetUpdatedNamespaces()
   188  	for _, ns := range namespaces {
   189  		updates := batch.GetUpdates(ns)
   190  		for k, vv := range updates {
   191  			dataKey := encodeDataKey(ns, k)
   192  			logger.Debugf("Channel [%s]: Applying key(string)=[%s] key(bytes)=[%#v]", vdb.dbName, string(dataKey), dataKey)
   193  
   194  			if vv.Value == nil {
   195  				dbBatch.Delete(dataKey)
   196  			} else {
   197  				encodedVal, err := encodeValue(vv)
   198  				if err != nil {
   199  					return err
   200  				}
   201  				dbBatch.Put(dataKey, encodedVal)
   202  			}
   203  		}
   204  	}
   205  	// Record a savepoint at a given height
   206  	// If a given height is nil, it denotes that we are committing pvt data of old blocks.
   207  	// In this case, we should not store a savepoint for recovery. The lastUpdatedOldBlockList
   208  	// in the pvtstore acts as a savepoint for pvt data.
   209  	if height != nil {
   210  		dbBatch.Put(savePointKey, height.ToBytes())
   211  	}
   212  	// Setting snyc to true as a precaution, false may be an ok optimization after further testing.
   213  	return vdb.db.WriteBatch(dbBatch, true)
   214  }
   215  
   216  // GetLatestSavePoint implements method in VersionedDB interface
   217  func (vdb *versionedDB) GetLatestSavePoint() (*version.Height, error) {
   218  	versionBytes, err := vdb.db.Get(savePointKey)
   219  	if err != nil {
   220  		return nil, err
   221  	}
   222  	if versionBytes == nil {
   223  		return nil, nil
   224  	}
   225  	version, _, err := version.NewHeightFromBytes(versionBytes)
   226  	if err != nil {
   227  		return nil, err
   228  	}
   229  	return version, nil
   230  }
   231  
   232  // GetFullScanIterator implements method in VersionedDB interface. 	This function returns a
   233  // FullScanIterator that can be used to iterate over entire data in the statedb for a channel.
   234  // `skipNamespace` parameter can be used to control if the consumer wants the FullScanIterator
   235  // to skip one or more namespaces from the returned results. The intended use of this iterator
   236  // is to generate the snapshot files for the stateleveldb
   237  func (vdb *versionedDB) GetFullScanIterator(skipNamespace func(string) bool) (statedb.FullScanIterator, error) {
   238  	return newFullDBScanner(vdb.db, skipNamespace)
   239  }
   240  
   241  // importState implements method in VersionedDB interface. The function is expected to be used
   242  // for importing the state from a previously snapshotted state. The parameter itr provides access to
   243  // the snapshotted state.
   244  func (vdb *versionedDB) importState(itr statedb.FullScanIterator, savepoint *version.Height) error {
   245  	if itr == nil {
   246  		return vdb.db.Put(savePointKey, savepoint.ToBytes(), true)
   247  	}
   248  	dbBatch := vdb.db.NewUpdateBatch()
   249  	batchSize := 0
   250  	for {
   251  		versionedKV, err := itr.Next()
   252  		if err != nil {
   253  			return err
   254  		}
   255  		if versionedKV == nil {
   256  			break
   257  		}
   258  		dbKey := encodeDataKey(versionedKV.Namespace, versionedKV.Key)
   259  		dbValue, err := encodeValue(versionedKV.VersionedValue)
   260  		if err != nil {
   261  			return err
   262  		}
   263  		batchSize += len(dbKey) + len(dbValue)
   264  		dbBatch.Put(dbKey, dbValue)
   265  		if batchSize >= maxDataImportBatchSize {
   266  			if err := vdb.db.WriteBatch(dbBatch, true); err != nil {
   267  				return err
   268  			}
   269  			batchSize = 0
   270  			dbBatch.Reset()
   271  		}
   272  	}
   273  	dbBatch.Put(savePointKey, savepoint.ToBytes())
   274  	return vdb.db.WriteBatch(dbBatch, true)
   275  }
   276  
   277  // IsEmpty return true if the statedb does not have any content
   278  func (vdb *versionedDB) IsEmpty() (bool, error) {
   279  	return vdb.db.IsEmpty()
   280  }
   281  
   282  func encodeDataKey(ns, key string) []byte {
   283  	k := append(dataKeyPrefix, []byte(ns)...)
   284  	k = append(k, nsKeySep...)
   285  	return append(k, []byte(key)...)
   286  }
   287  
   288  func decodeDataKey(encodedDataKey []byte) (string, string) {
   289  	split := bytes.SplitN(encodedDataKey, nsKeySep, 2)
   290  	return string(split[0][1:]), string(split[1])
   291  }
   292  
   293  func dataKeyStarterForNextNamespace(ns string) []byte {
   294  	k := append(dataKeyPrefix, []byte(ns)...)
   295  	return append(k, lastKeyIndicator)
   296  }
   297  
   298  type kvScanner struct {
   299  	namespace            string
   300  	dbItr                iterator.Iterator
   301  	requestedLimit       int32
   302  	totalRecordsReturned int32
   303  }
   304  
   305  func newKVScanner(namespace string, dbItr iterator.Iterator, requestedLimit int32) *kvScanner {
   306  	return &kvScanner{namespace, dbItr, requestedLimit, 0}
   307  }
   308  
   309  func (scanner *kvScanner) Next() (*statedb.VersionedKV, error) {
   310  	if scanner.requestedLimit > 0 && scanner.totalRecordsReturned >= scanner.requestedLimit {
   311  		return nil, nil
   312  	}
   313  	if !scanner.dbItr.Next() {
   314  		return nil, nil
   315  	}
   316  
   317  	dbKey := scanner.dbItr.Key()
   318  	dbVal := scanner.dbItr.Value()
   319  	dbValCopy := make([]byte, len(dbVal))
   320  	copy(dbValCopy, dbVal)
   321  	_, key := decodeDataKey(dbKey)
   322  	vv, err := decodeValue(dbValCopy)
   323  	if err != nil {
   324  		return nil, err
   325  	}
   326  
   327  	scanner.totalRecordsReturned++
   328  	return &statedb.VersionedKV{
   329  		CompositeKey: &statedb.CompositeKey{
   330  			Namespace: scanner.namespace,
   331  			Key:       key,
   332  		},
   333  		VersionedValue: vv,
   334  	}, nil
   335  }
   336  
   337  func (scanner *kvScanner) Close() {
   338  	scanner.dbItr.Release()
   339  }
   340  
   341  func (scanner *kvScanner) GetBookmarkAndClose() string {
   342  	retval := ""
   343  	if scanner.dbItr.Next() {
   344  		dbKey := scanner.dbItr.Key()
   345  		_, key := decodeDataKey(dbKey)
   346  		retval = key
   347  	}
   348  	scanner.Close()
   349  	return retval
   350  }
   351  
   352  type fullDBScanner struct {
   353  	db     *leveldbhelper.DBHandle
   354  	dbItr  iterator.Iterator
   355  	toSkip func(namespace string) bool
   356  }
   357  
   358  func newFullDBScanner(db *leveldbhelper.DBHandle, skipNamespace func(namespace string) bool) (*fullDBScanner, error) {
   359  	dbItr, err := db.GetIterator(dataKeyPrefix, dataKeyStopper)
   360  	if err != nil {
   361  		return nil, err
   362  	}
   363  	return &fullDBScanner{
   364  			db:     db,
   365  			dbItr:  dbItr,
   366  			toSkip: skipNamespace,
   367  		},
   368  		nil
   369  }
   370  
   371  // Next returns the key-values in the lexical order of <Namespace, key>
   372  func (s *fullDBScanner) Next() (*statedb.VersionedKV, error) {
   373  	for s.dbItr.Next() {
   374  		ns, key := decodeDataKey(s.dbItr.Key())
   375  		compositeKey := &statedb.CompositeKey{
   376  			Namespace: ns,
   377  			Key:       key,
   378  		}
   379  
   380  		versionedVal, err := decodeValue(s.dbItr.Value())
   381  		if err != nil {
   382  			return nil, err
   383  		}
   384  
   385  		switch {
   386  		case !s.toSkip(ns):
   387  			return &statedb.VersionedKV{
   388  				CompositeKey:   compositeKey,
   389  				VersionedValue: versionedVal,
   390  			}, nil
   391  		default:
   392  			s.dbItr.Seek(dataKeyStarterForNextNamespace(ns))
   393  			s.dbItr.Prev()
   394  		}
   395  	}
   396  	return nil, errors.Wrap(s.dbItr.Error(), "internal leveldb error while retrieving data from db iterator")
   397  }
   398  
   399  func (s *fullDBScanner) Close() {
   400  	if s == nil {
   401  		return
   402  	}
   403  	s.dbItr.Release()
   404  }