github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/common/ledger/util/leveldbhelper/leveldb_provider.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package leveldbhelper
     8  
     9  import (
    10  	"bytes"
    11  	"fmt"
    12  	"sync"
    13  
    14  	"github.com/hechain20/hechain/common/ledger/dataformat"
    15  	"github.com/pkg/errors"
    16  	"github.com/syndtr/goleveldb/leveldb"
    17  	"github.com/syndtr/goleveldb/leveldb/iterator"
    18  )
    19  
    20  const (
    21  	// internalDBName is used to keep track of data related to internals such as data format
    22  	// _ is used as name because this is not allowed as a channelname
    23  	internalDBName = "_"
    24  	// maxBatchSize limits the memory usage (1MB) for a batch. It is measured by the total number of bytes
    25  	// of all the keys in a batch.
    26  	maxBatchSize = 1000000
    27  )
    28  
    29  var (
    30  	dbNameKeySep     = []byte{0x00}
    31  	lastKeyIndicator = byte(0x01)
    32  	formatVersionKey = []byte{'f'} // a single key in db whose value indicates the version of the data format
    33  )
    34  
    35  // closeFunc closes the db handle
    36  type closeFunc func()
    37  
    38  // Conf configuration for `Provider`
    39  //
    40  // `ExpectedFormat` is the expected value of the format key in the internal database.
    41  // At the time of opening the db, A check is performed that
    42  // either the db is empty (i.e., opening for the first time) or the value
    43  // of the formatVersionKey is equal to `ExpectedFormat`. Otherwise, an error is returned.
    44  // A nil value for ExpectedFormat indicates that the format is never set and hence there is no such record.
    45  type Conf struct {
    46  	DBPath         string
    47  	ExpectedFormat string
    48  }
    49  
    50  // Provider enables to use a single leveldb as multiple logical leveldbs
    51  type Provider struct {
    52  	db *DB
    53  
    54  	mux       sync.Mutex
    55  	dbHandles map[string]*DBHandle
    56  }
    57  
    58  // NewProvider constructs a Provider
    59  func NewProvider(conf *Conf) (*Provider, error) {
    60  	db, err := openDBAndCheckFormat(conf)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  	return &Provider{
    65  		db:        db,
    66  		dbHandles: make(map[string]*DBHandle),
    67  	}, nil
    68  }
    69  
    70  func openDBAndCheckFormat(conf *Conf) (d *DB, e error) {
    71  	db := CreateDB(conf)
    72  	db.Open()
    73  
    74  	defer func() {
    75  		if e != nil {
    76  			db.Close()
    77  		}
    78  	}()
    79  
    80  	internalDB := &DBHandle{
    81  		db:     db,
    82  		dbName: internalDBName,
    83  	}
    84  
    85  	dbEmpty, err := db.IsEmpty()
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  
    90  	if dbEmpty && conf.ExpectedFormat != "" {
    91  		logger.Infof("DB is empty Setting db format as %s", conf.ExpectedFormat)
    92  		if err := internalDB.Put(formatVersionKey, []byte(conf.ExpectedFormat), true); err != nil {
    93  			return nil, err
    94  		}
    95  		return db, nil
    96  	}
    97  
    98  	formatVersion, err := internalDB.Get(formatVersionKey)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  	logger.Debugf("Checking for db format at path [%s]", conf.DBPath)
   103  
   104  	if !bytes.Equal(formatVersion, []byte(conf.ExpectedFormat)) {
   105  		logger.Errorf("The db at path [%s] contains data in unexpected format. expected data format = [%s] (%#v), data format = [%s] (%#v).",
   106  			conf.DBPath, conf.ExpectedFormat, []byte(conf.ExpectedFormat), formatVersion, formatVersion)
   107  		return nil, &dataformat.ErrFormatMismatch{
   108  			ExpectedFormat: conf.ExpectedFormat,
   109  			Format:         string(formatVersion),
   110  			DBInfo:         fmt.Sprintf("leveldb at [%s]", conf.DBPath),
   111  		}
   112  	}
   113  	logger.Debug("format is latest, nothing to do")
   114  	return db, nil
   115  }
   116  
   117  // GetDataFormat returns the format of the data
   118  func (p *Provider) GetDataFormat() (string, error) {
   119  	f, err := p.GetDBHandle(internalDBName).Get(formatVersionKey)
   120  	return string(f), err
   121  }
   122  
   123  // GetDBHandle returns a handle to a named db
   124  func (p *Provider) GetDBHandle(dbName string) *DBHandle {
   125  	p.mux.Lock()
   126  	defer p.mux.Unlock()
   127  	dbHandle := p.dbHandles[dbName]
   128  	if dbHandle == nil {
   129  		closeFunc := func() {
   130  			p.mux.Lock()
   131  			defer p.mux.Unlock()
   132  			delete(p.dbHandles, dbName)
   133  		}
   134  		dbHandle = &DBHandle{dbName, p.db, closeFunc}
   135  		p.dbHandles[dbName] = dbHandle
   136  	}
   137  	return dbHandle
   138  }
   139  
   140  // Close closes the underlying leveldb
   141  func (p *Provider) Close() {
   142  	p.db.Close()
   143  }
   144  
   145  // Drop drops all the data for the given dbName
   146  func (p *Provider) Drop(dbName string) error {
   147  	dbHandle := p.GetDBHandle(dbName)
   148  	defer dbHandle.Close()
   149  	return dbHandle.deleteAll()
   150  }
   151  
   152  // DBHandle is an handle to a named db
   153  type DBHandle struct {
   154  	dbName    string
   155  	db        *DB
   156  	closeFunc closeFunc
   157  }
   158  
   159  // Get returns the value for the given key
   160  func (h *DBHandle) Get(key []byte) ([]byte, error) {
   161  	return h.db.Get(constructLevelKey(h.dbName, key))
   162  }
   163  
   164  // Put saves the key/value
   165  func (h *DBHandle) Put(key []byte, value []byte, sync bool) error {
   166  	return h.db.Put(constructLevelKey(h.dbName, key), value, sync)
   167  }
   168  
   169  // Delete deletes the given key
   170  func (h *DBHandle) Delete(key []byte, sync bool) error {
   171  	return h.db.Delete(constructLevelKey(h.dbName, key), sync)
   172  }
   173  
   174  // DeleteAll deletes all the keys that belong to the channel (dbName).
   175  func (h *DBHandle) deleteAll() error {
   176  	iter, err := h.GetIterator(nil, nil)
   177  	if err != nil {
   178  		return err
   179  	}
   180  	defer iter.Release()
   181  
   182  	// use leveldb iterator directly to be more efficient
   183  	dbIter := iter.Iterator
   184  
   185  	// This is common code shared by all the leveldb instances. Because each leveldb has its own key size pattern,
   186  	// each batch is limited by memory usage instead of number of keys. Once the batch memory usage reaches maxBatchSize,
   187  	// the batch will be committed.
   188  	numKeys := 0
   189  	batchSize := 0
   190  	batch := &leveldb.Batch{}
   191  	for dbIter.Next() {
   192  		if err := dbIter.Error(); err != nil {
   193  			return errors.Wrap(err, "internal leveldb error while retrieving data from db iterator")
   194  		}
   195  		key := dbIter.Key()
   196  		numKeys++
   197  		batchSize = batchSize + len(key)
   198  		batch.Delete(key)
   199  		if batchSize >= maxBatchSize {
   200  			if err := h.db.WriteBatch(batch, true); err != nil {
   201  				return err
   202  			}
   203  			logger.Infof("Have removed %d entries for channel %s in leveldb %s", numKeys, h.dbName, h.db.conf.DBPath)
   204  			batchSize = 0
   205  			batch.Reset()
   206  		}
   207  	}
   208  	if batch.Len() > 0 {
   209  		return h.db.WriteBatch(batch, true)
   210  	}
   211  	return nil
   212  }
   213  
   214  // IsEmpty returns true if no data exists for the DBHandle
   215  func (h *DBHandle) IsEmpty() (bool, error) {
   216  	itr, err := h.GetIterator(nil, nil)
   217  	if err != nil {
   218  		return false, err
   219  	}
   220  	defer itr.Release()
   221  
   222  	if err := itr.Error(); err != nil {
   223  		return false, errors.WithMessagef(itr.Error(), "internal leveldb error while obtaining next entry from iterator")
   224  	}
   225  
   226  	return !itr.Next(), nil
   227  }
   228  
   229  // NewUpdateBatch returns a new UpdateBatch that can be used to update the db
   230  func (h *DBHandle) NewUpdateBatch() *UpdateBatch {
   231  	return &UpdateBatch{
   232  		dbName: h.dbName,
   233  		Batch:  &leveldb.Batch{},
   234  	}
   235  }
   236  
   237  // WriteBatch writes a batch in an atomic way
   238  func (h *DBHandle) WriteBatch(batch *UpdateBatch, sync bool) error {
   239  	if batch == nil || batch.Len() == 0 {
   240  		return nil
   241  	}
   242  	if err := h.db.WriteBatch(batch.Batch, sync); err != nil {
   243  		return err
   244  	}
   245  	return nil
   246  }
   247  
   248  // GetIterator gets an handle to iterator. The iterator should be released after the use.
   249  // The resultset contains all the keys that are present in the db between the startKey (inclusive) and the endKey (exclusive).
   250  // A nil startKey represents the first available key and a nil endKey represent a logical key after the last available key
   251  func (h *DBHandle) GetIterator(startKey []byte, endKey []byte) (*Iterator, error) {
   252  	sKey := constructLevelKey(h.dbName, startKey)
   253  	eKey := constructLevelKey(h.dbName, endKey)
   254  	if endKey == nil {
   255  		// replace the last byte 'dbNameKeySep' by 'lastKeyIndicator'
   256  		eKey[len(eKey)-1] = lastKeyIndicator
   257  	}
   258  	logger.Debugf("Getting iterator for range [%#v] - [%#v]", sKey, eKey)
   259  	itr := h.db.GetIterator(sKey, eKey)
   260  	if err := itr.Error(); err != nil {
   261  		itr.Release()
   262  		return nil, errors.Wrapf(err, "internal leveldb error while obtaining db iterator")
   263  	}
   264  	return &Iterator{h.dbName, itr}, nil
   265  }
   266  
   267  // Close closes the DBHandle after its db data have been deleted
   268  func (h *DBHandle) Close() {
   269  	if h.closeFunc != nil {
   270  		h.closeFunc()
   271  	}
   272  }
   273  
   274  // UpdateBatch encloses the details of multiple `updates`
   275  type UpdateBatch struct {
   276  	*leveldb.Batch
   277  	dbName string
   278  }
   279  
   280  // Put adds a KV
   281  func (b *UpdateBatch) Put(key []byte, value []byte) {
   282  	if value == nil {
   283  		panic("Nil value not allowed")
   284  	}
   285  	b.Batch.Put(constructLevelKey(b.dbName, key), value)
   286  }
   287  
   288  // Delete deletes a Key and associated value
   289  func (b *UpdateBatch) Delete(key []byte) {
   290  	b.Batch.Delete(constructLevelKey(b.dbName, key))
   291  }
   292  
   293  // Iterator extends actual leveldb iterator
   294  type Iterator struct {
   295  	dbName string
   296  	iterator.Iterator
   297  }
   298  
   299  // Key wraps actual leveldb iterator method
   300  func (itr *Iterator) Key() []byte {
   301  	return retrieveAppKey(itr.Iterator.Key())
   302  }
   303  
   304  // Seek moves the iterator to the first key/value pair
   305  // whose key is greater than or equal to the given key.
   306  // It returns whether such pair exist.
   307  func (itr *Iterator) Seek(key []byte) bool {
   308  	levelKey := constructLevelKey(itr.dbName, key)
   309  	return itr.Iterator.Seek(levelKey)
   310  }
   311  
   312  func constructLevelKey(dbName string, key []byte) []byte {
   313  	return append(append([]byte(dbName), dbNameKeySep...), key...)
   314  }
   315  
   316  func retrieveAppKey(levelKey []byte) []byte {
   317  	return bytes.SplitN(levelKey, dbNameKeySep, 2)[1]
   318  }