github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/common/ledger/util/leveldbhelper/leveldb_provider.go (about)

     1  /*
     2  Copyright IBM Corp. 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/osdi23p228/fabric/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  // DBHandle is an handle to a named db
   146  type DBHandle struct {
   147  	dbName    string
   148  	db        *DB
   149  	closeFunc closeFunc
   150  }
   151  
   152  // Get returns the value for the given key
   153  func (h *DBHandle) Get(key []byte) ([]byte, error) {
   154  	return h.db.Get(constructLevelKey(h.dbName, key))
   155  }
   156  
   157  // Put saves the key/value
   158  func (h *DBHandle) Put(key []byte, value []byte, sync bool) error {
   159  	return h.db.Put(constructLevelKey(h.dbName, key), value, sync)
   160  }
   161  
   162  // Delete deletes the given key
   163  func (h *DBHandle) Delete(key []byte, sync bool) error {
   164  	return h.db.Delete(constructLevelKey(h.dbName, key), sync)
   165  }
   166  
   167  // DeleteAll deletes all the keys that belong to the channel (dbName).
   168  func (h *DBHandle) DeleteAll() error {
   169  	iter, err := h.GetIterator(nil, nil)
   170  	if err != nil {
   171  		return err
   172  	}
   173  	defer iter.Release()
   174  
   175  	// use leveldb iterator directly to be more efficient
   176  	dbIter := iter.Iterator
   177  
   178  	// This is common code shared by all the leveldb instances. Because each leveldb has its own key size pattern,
   179  	// each batch is limited by memory usage instead of number of keys. Once the batch memory usage reaches maxBatchSize,
   180  	// the batch will be committed.
   181  	numKeys := 0
   182  	batchSize := 0
   183  	batch := &leveldb.Batch{}
   184  	for dbIter.Next() {
   185  		if err := dbIter.Error(); err != nil {
   186  			return errors.Wrap(err, "internal leveldb error while retrieving data from db iterator")
   187  		}
   188  		key := dbIter.Key()
   189  		numKeys++
   190  		batchSize = batchSize + len(key)
   191  		batch.Delete(key)
   192  		if batchSize >= maxBatchSize {
   193  			if err := h.db.WriteBatch(batch, true); err != nil {
   194  				return err
   195  			}
   196  			logger.Infof("Have removed %d entries for channel %s in leveldb %s", numKeys, h.dbName, h.db.conf.DBPath)
   197  			batchSize = 0
   198  			batch = &leveldb.Batch{}
   199  		}
   200  	}
   201  	if batch.Len() > 0 {
   202  		return h.db.WriteBatch(batch, true)
   203  	}
   204  	return nil
   205  }
   206  
   207  // NewUpdateBatch returns a new UpdateBatch that can be used to update the db
   208  func (h *DBHandle) NewUpdateBatch() *UpdateBatch {
   209  	return &UpdateBatch{
   210  		dbName: h.dbName,
   211  		Batch:  &leveldb.Batch{},
   212  	}
   213  }
   214  
   215  // WriteBatch writes a batch in an atomic way
   216  func (h *DBHandle) WriteBatch(batch *UpdateBatch, sync bool) error {
   217  	if batch == nil || batch.Len() == 0 {
   218  		return nil
   219  	}
   220  	if err := h.db.WriteBatch(batch.Batch, sync); err != nil {
   221  		return err
   222  	}
   223  	return nil
   224  }
   225  
   226  // GetIterator gets an handle to iterator. The iterator should be released after the use.
   227  // The resultset contains all the keys that are present in the db between the startKey (inclusive) and the endKey (exclusive).
   228  // A nil startKey represents the first available key and a nil endKey represent a logical key after the last available key
   229  func (h *DBHandle) GetIterator(startKey []byte, endKey []byte) (*Iterator, error) {
   230  	sKey := constructLevelKey(h.dbName, startKey)
   231  	eKey := constructLevelKey(h.dbName, endKey)
   232  	if endKey == nil {
   233  		// replace the last byte 'dbNameKeySep' by 'lastKeyIndicator'
   234  		eKey[len(eKey)-1] = lastKeyIndicator
   235  	}
   236  	logger.Debugf("Getting iterator for range [%#v] - [%#v]", sKey, eKey)
   237  	itr := h.db.GetIterator(sKey, eKey)
   238  	if err := itr.Error(); err != nil {
   239  		itr.Release()
   240  		return nil, errors.Wrapf(err, "internal leveldb error while obtaining db iterator")
   241  	}
   242  	return &Iterator{h.dbName, itr}, nil
   243  }
   244  
   245  // Close closes the DBHandle after its db data have been deleted
   246  func (h *DBHandle) Close() {
   247  	if h.closeFunc != nil {
   248  		h.closeFunc()
   249  	}
   250  }
   251  
   252  // UpdateBatch encloses the details of multiple `updates`
   253  type UpdateBatch struct {
   254  	*leveldb.Batch
   255  	dbName string
   256  }
   257  
   258  // Put adds a KV
   259  func (b *UpdateBatch) Put(key []byte, value []byte) {
   260  	if value == nil {
   261  		panic("Nil value not allowed")
   262  	}
   263  	b.Batch.Put(constructLevelKey(b.dbName, key), value)
   264  }
   265  
   266  // Delete deletes a Key and associated value
   267  func (b *UpdateBatch) Delete(key []byte) {
   268  	b.Batch.Delete(constructLevelKey(b.dbName, key))
   269  }
   270  
   271  // Iterator extends actual leveldb iterator
   272  type Iterator struct {
   273  	dbName string
   274  	iterator.Iterator
   275  }
   276  
   277  // Key wraps actual leveldb iterator method
   278  func (itr *Iterator) Key() []byte {
   279  	return retrieveAppKey(itr.Iterator.Key())
   280  }
   281  
   282  // Seek moves the iterator to the first key/value pair
   283  // whose key is greater than or equal to the given key.
   284  // It returns whether such pair exist.
   285  func (itr *Iterator) Seek(key []byte) bool {
   286  	levelKey := constructLevelKey(itr.dbName, key)
   287  	return itr.Iterator.Seek(levelKey)
   288  }
   289  
   290  func constructLevelKey(dbName string, key []byte) []byte {
   291  	return append(append([]byte(dbName), dbNameKeySep...), key...)
   292  }
   293  
   294  func retrieveAppKey(levelKey []byte) []byte {
   295  	return bytes.SplitN(levelKey, dbNameKeySep, 2)[1]
   296  }