github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/ledger/confighistory/db_helper.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package confighistory
     8  
     9  import (
    10  	"bytes"
    11  	"encoding/binary"
    12  	"math"
    13  
    14  	"github.com/hechain20/hechain/common/ledger/util/leveldbhelper"
    15  	"github.com/pkg/errors"
    16  )
    17  
    18  const (
    19  	keyPrefix     = "s"
    20  	separatorByte = byte(0)
    21  	nsStopper     = byte(1)
    22  )
    23  
    24  type compositeKey struct {
    25  	ns, key  string
    26  	blockNum uint64
    27  }
    28  
    29  type compositeKV struct {
    30  	*compositeKey
    31  	value []byte
    32  }
    33  
    34  type dbProvider struct {
    35  	*leveldbhelper.Provider
    36  }
    37  
    38  type db struct {
    39  	*leveldbhelper.DBHandle
    40  }
    41  
    42  type batch struct {
    43  	*leveldbhelper.UpdateBatch
    44  }
    45  
    46  func newDBProvider(dbPath string) (*dbProvider, error) {
    47  	logger.Debugf("Opening db for config history: db path = %s", dbPath)
    48  	p, err := leveldbhelper.NewProvider(&leveldbhelper.Conf{DBPath: dbPath})
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  	return &dbProvider{Provider: p}, nil
    53  }
    54  
    55  func (d *db) newBatch() *batch {
    56  	return &batch{d.DBHandle.NewUpdateBatch()}
    57  }
    58  
    59  func (p *dbProvider) getDB(id string) *db {
    60  	return &db{p.GetDBHandle(id)}
    61  }
    62  
    63  func (b *batch) add(ns, key string, blockNum uint64, value []byte) {
    64  	logger.Debugf("add() - {%s, %s, %d}", ns, key, blockNum)
    65  	k, v := encodeCompositeKey(ns, key, blockNum), value
    66  	b.Put(k, v)
    67  }
    68  
    69  func (d *db) writeBatch(batch *batch, sync bool) error {
    70  	return d.WriteBatch(batch.UpdateBatch, sync)
    71  }
    72  
    73  func (d *db) mostRecentEntryBelow(blockNum uint64, ns, key string) (*compositeKV, error) {
    74  	logger.Debugf("mostRecentEntryBelow() - {%s, %s, %d}", ns, key, blockNum)
    75  	if blockNum == 0 {
    76  		return nil, errors.New("blockNum should be greater than 0")
    77  	}
    78  
    79  	startKey := encodeCompositeKey(ns, key, blockNum-1)
    80  	stopKey := append(encodeCompositeKey(ns, key, 0), byte(0))
    81  
    82  	itr, err := d.GetIterator(startKey, stopKey)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  	defer itr.Release()
    87  	if !itr.Next() {
    88  		logger.Debugf("Key no entry found. Returning nil")
    89  		return nil, nil
    90  	}
    91  	k, v := decodeCompositeKey(itr.Key()), itr.Value()
    92  	return &compositeKV{k, v}, nil
    93  }
    94  
    95  func (d *db) entryAt(blockNum uint64, ns, key string) (*compositeKV, error) {
    96  	logger.Debugf("entryAt() - {%s, %s, %d}", ns, key, blockNum)
    97  	keyBytes := encodeCompositeKey(ns, key, blockNum)
    98  	valBytes, err := d.Get(keyBytes)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  	if valBytes == nil {
   103  		return nil, nil
   104  	}
   105  	k, v := decodeCompositeKey(keyBytes), valBytes
   106  	return &compositeKV{k, v}, nil
   107  }
   108  
   109  func (d *db) getNamespaceIterator(ns string) (*leveldbhelper.Iterator, error) {
   110  	nsStartKey := []byte(keyPrefix + ns)
   111  	nsStartKey = append(nsStartKey, separatorByte)
   112  	nsEndKey := []byte(keyPrefix + ns)
   113  	nsEndKey = append(nsEndKey, nsStopper)
   114  	return d.GetIterator(nsStartKey, nsEndKey)
   115  }
   116  
   117  func encodeCompositeKey(ns, key string, blockNum uint64) []byte {
   118  	b := []byte(keyPrefix + ns)
   119  	b = append(b, separatorByte)
   120  	b = append(b, []byte(key)...)
   121  	return append(b, encodeBlockNum(blockNum)...)
   122  }
   123  
   124  func decodeCompositeKey(b []byte) *compositeKey {
   125  	blockNumStartIndex := len(b) - 8
   126  	nsKeyBytes, blockNumBytes := b[1:blockNumStartIndex], b[blockNumStartIndex:]
   127  	separatorIndex := bytes.Index(nsKeyBytes, []byte{separatorByte})
   128  	ns, key := nsKeyBytes[0:separatorIndex], nsKeyBytes[separatorIndex+1:]
   129  	return &compositeKey{string(ns), string(key), decodeBlockNum(blockNumBytes)}
   130  }
   131  
   132  func encodeBlockNum(blockNum uint64) []byte {
   133  	b := make([]byte, 8)
   134  	binary.BigEndian.PutUint64(b, math.MaxUint64-blockNum)
   135  	return b
   136  }
   137  
   138  func decodeBlockNum(blockNumBytes []byte) uint64 {
   139  	return math.MaxUint64 - binary.BigEndian.Uint64(blockNumBytes)
   140  }