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

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package pvtdatastorage
     8  
     9  import (
    10  	"github.com/hechain20/hechain/common/ledger/util/leveldbhelper"
    11  	"github.com/hechain20/hechain/core/ledger"
    12  	"github.com/hyperledger/fabric-protos-go/ledger/rwset"
    13  	"github.com/pkg/errors"
    14  	"github.com/willf/bitset"
    15  )
    16  
    17  // CommitPvtDataOfOldBlocks commits the pvtData (i.e., previously missing data) of old blockp.
    18  // The parameter `blocksPvtData` refers a list of old block's pvtdata which are missing in the pvtstore.
    19  // Given a list of old block's pvtData, `CommitPvtDataOfOldBlocks` performs the following three
    20  // operations
    21  // (1) construct update entries (i.e., dataEntries, expiryEntries, missingDataEntries)
    22  //     from the above created data entries
    23  // (2) create a db update batch from the update entries
    24  // (3) commit the update batch to the pvtStore
    25  func (s *Store) CommitPvtDataOfOldBlocks(
    26  	blocksPvtData map[uint64][]*ledger.TxPvtData,
    27  	unreconciledMissingData ledger.MissingPvtDataInfo,
    28  ) error {
    29  	s.purgerLock.Lock()
    30  	defer s.purgerLock.Unlock()
    31  
    32  	deprioritizedMissingData := unreconciledMissingData
    33  
    34  	if s.isLastUpdatedOldBlocksSet {
    35  		return errors.New("the lastUpdatedOldBlocksList is set. It means that the stateDB may not be in sync with the pvtStore")
    36  	}
    37  
    38  	p := &oldBlockDataProcessor{
    39  		Store: s,
    40  		entries: &entriesForPvtDataOfOldBlocks{
    41  			dataEntries:                     make(map[dataKey]*rwset.CollectionPvtReadWriteSet),
    42  			expiryEntries:                   make(map[expiryKey]*ExpiryData),
    43  			prioritizedMissingDataEntries:   make(map[nsCollBlk]*bitset.BitSet),
    44  			deprioritizedMissingDataEntries: make(map[nsCollBlk]*bitset.BitSet),
    45  		},
    46  	}
    47  
    48  	if err := p.prepareDataAndExpiryEntries(blocksPvtData); err != nil {
    49  		return err
    50  	}
    51  
    52  	if err := p.prepareMissingDataEntriesToReflectReconciledData(); err != nil {
    53  		return err
    54  	}
    55  
    56  	if err := p.prepareMissingDataEntriesToReflectPriority(deprioritizedMissingData); err != nil {
    57  		return err
    58  	}
    59  
    60  	p.prepareBootKVHashesDeletions()
    61  
    62  	batch, err := p.constructDBUpdateBatch()
    63  	if err != nil {
    64  		return err
    65  	}
    66  	return s.db.WriteBatch(batch, true)
    67  }
    68  
    69  type oldBlockDataProcessor struct {
    70  	*Store
    71  	entries *entriesForPvtDataOfOldBlocks
    72  }
    73  
    74  func (p *oldBlockDataProcessor) prepareDataAndExpiryEntries(blocksPvtData map[uint64][]*ledger.TxPvtData) error {
    75  	var dataEntries []*dataEntry
    76  	var expData *ExpiryData
    77  
    78  	for blkNum, pvtData := range blocksPvtData {
    79  		dataEntries = append(dataEntries, prepareDataEntries(blkNum, pvtData)...)
    80  	}
    81  
    82  	for _, dataEntry := range dataEntries {
    83  		nsCollBlk := dataEntry.key.nsCollBlk
    84  		txNum := dataEntry.key.txNum
    85  
    86  		expKey, err := p.constructExpiryKey(dataEntry)
    87  		if err != nil {
    88  			return err
    89  		}
    90  
    91  		if neverExpires(expKey.expiringBlk) {
    92  			p.entries.dataEntries[*dataEntry.key] = dataEntry.value
    93  			continue
    94  		}
    95  
    96  		if expData, err = p.getExpiryDataFromEntriesOrStore(expKey); err != nil {
    97  			return err
    98  		}
    99  		if expData == nil {
   100  			// if expiryData is not available, it means that
   101  			// the pruge scheduler removed these entries and the
   102  			// associated data entry is no longer needed. Note
   103  			// that the associated missingData entry would also
   104  			// be not present. Hence, we can skip this data entry.
   105  			continue
   106  		}
   107  		expData.addPresentData(nsCollBlk.ns, nsCollBlk.coll, txNum)
   108  
   109  		p.entries.dataEntries[*dataEntry.key] = dataEntry.value
   110  		p.entries.expiryEntries[expKey] = expData
   111  	}
   112  	return nil
   113  }
   114  
   115  func (p *oldBlockDataProcessor) prepareMissingDataEntriesToReflectReconciledData() error {
   116  	for dataKey := range p.entries.dataEntries {
   117  		key := dataKey.nsCollBlk
   118  		txNum := uint(dataKey.txNum)
   119  
   120  		prioMissingData, err := p.getPrioMissingDataFromEntriesOrStore(key)
   121  		if err != nil {
   122  			return err
   123  		}
   124  		if prioMissingData != nil && prioMissingData.Test(txNum) {
   125  			p.entries.prioritizedMissingDataEntries[key] = prioMissingData.Clear(txNum)
   126  			continue
   127  		}
   128  
   129  		deprioMissingData, err := p.getDeprioMissingDataFromEntriesOrStore(key)
   130  		if err != nil {
   131  			return err
   132  		}
   133  		if deprioMissingData != nil && deprioMissingData.Test(txNum) {
   134  			p.entries.deprioritizedMissingDataEntries[key] = deprioMissingData.Clear(txNum)
   135  		}
   136  	}
   137  
   138  	return nil
   139  }
   140  
   141  func (p *oldBlockDataProcessor) prepareMissingDataEntriesToReflectPriority(deprioritizedList ledger.MissingPvtDataInfo) error {
   142  	for blkNum, blkMissingData := range deprioritizedList {
   143  		for txNum, txMissingData := range blkMissingData {
   144  			for _, nsColl := range txMissingData {
   145  				key := nsCollBlk{
   146  					ns:     nsColl.Namespace,
   147  					coll:   nsColl.Collection,
   148  					blkNum: blkNum,
   149  				}
   150  				txNum := uint(txNum)
   151  
   152  				prioMissingData, err := p.getPrioMissingDataFromEntriesOrStore(key)
   153  				if err != nil {
   154  					return err
   155  				}
   156  				if prioMissingData == nil {
   157  					// we would reach here when either of the following happens:
   158  					//   (1) when the purge scheduler already removed the respective
   159  					//       missing data entry.
   160  					//   (2) when the missing data info is already persistent in the
   161  					//       deprioritized list. Currently, we do not have different
   162  					//       levels of deprioritized list.
   163  					// In both of the above case, we can continue to the next entry.
   164  					continue
   165  				}
   166  				p.entries.prioritizedMissingDataEntries[key] = prioMissingData.Clear(txNum)
   167  
   168  				deprioMissingData, err := p.getDeprioMissingDataFromEntriesOrStore(key)
   169  				if err != nil {
   170  					return err
   171  				}
   172  				if deprioMissingData == nil {
   173  					deprioMissingData = &bitset.BitSet{}
   174  				}
   175  				p.entries.deprioritizedMissingDataEntries[key] = deprioMissingData.Set(txNum)
   176  			}
   177  		}
   178  	}
   179  
   180  	return nil
   181  }
   182  
   183  func (p *oldBlockDataProcessor) prepareBootKVHashesDeletions() {
   184  	if !p.bootsnapshotInfo.createdFromSnapshot {
   185  		return
   186  	}
   187  	for dataKey := range p.entries.dataEntries {
   188  		if dataKey.blkNum <= p.bootsnapshotInfo.lastBlockInSnapshot {
   189  			p.entries.bootKVHashesDeletions = append(p.entries.bootKVHashesDeletions,
   190  				&bootKVHashesKey{
   191  					blkNum: dataKey.blkNum,
   192  					txNum:  dataKey.txNum,
   193  					ns:     dataKey.ns,
   194  					coll:   dataKey.coll,
   195  				},
   196  			)
   197  		}
   198  	}
   199  }
   200  
   201  func (p *oldBlockDataProcessor) constructExpiryKey(dataEntry *dataEntry) (expiryKey, error) {
   202  	// get the expiryBlk number to construct the expiryKey
   203  	nsCollBlk := dataEntry.key.nsCollBlk
   204  	expiringBlk, err := p.btlPolicy.GetExpiringBlock(nsCollBlk.ns, nsCollBlk.coll, nsCollBlk.blkNum)
   205  	if err != nil {
   206  		return expiryKey{}, errors.WithMessagef(err, "error while constructing expiry data key")
   207  	}
   208  
   209  	return expiryKey{
   210  		expiringBlk:   expiringBlk,
   211  		committingBlk: nsCollBlk.blkNum,
   212  	}, nil
   213  }
   214  
   215  func (p *oldBlockDataProcessor) getExpiryDataFromEntriesOrStore(expKey expiryKey) (*ExpiryData, error) {
   216  	if expiryData, ok := p.entries.expiryEntries[expKey]; ok {
   217  		return expiryData, nil
   218  	}
   219  
   220  	expData, err := p.db.Get(encodeExpiryKey(&expKey))
   221  	if err != nil {
   222  		return nil, err
   223  	}
   224  	if expData == nil {
   225  		return nil, nil
   226  	}
   227  
   228  	return decodeExpiryValue(expData)
   229  }
   230  
   231  func (p *oldBlockDataProcessor) getPrioMissingDataFromEntriesOrStore(nsCollBlk nsCollBlk) (*bitset.BitSet, error) {
   232  	missingData, ok := p.entries.prioritizedMissingDataEntries[nsCollBlk]
   233  	if ok {
   234  		return missingData, nil
   235  	}
   236  
   237  	missingKey := &missingDataKey{
   238  		nsCollBlk: nsCollBlk,
   239  	}
   240  	key := encodeElgPrioMissingDataKey(missingKey)
   241  
   242  	encMissingData, err := p.db.Get(key)
   243  	if err != nil {
   244  		return nil, errors.Wrap(err, "error while getting missing data bitmap from the store")
   245  	}
   246  	if encMissingData == nil {
   247  		return nil, nil
   248  	}
   249  
   250  	return decodeMissingDataValue(encMissingData)
   251  }
   252  
   253  func (p *oldBlockDataProcessor) getDeprioMissingDataFromEntriesOrStore(nsCollBlk nsCollBlk) (*bitset.BitSet, error) {
   254  	missingData, ok := p.entries.deprioritizedMissingDataEntries[nsCollBlk]
   255  	if ok {
   256  		return missingData, nil
   257  	}
   258  
   259  	missingKey := &missingDataKey{
   260  		nsCollBlk: nsCollBlk,
   261  	}
   262  	key := encodeElgDeprioMissingDataKey(missingKey)
   263  
   264  	encMissingData, err := p.db.Get(key)
   265  	if err != nil {
   266  		return nil, errors.Wrap(err, "error while getting missing data bitmap from the store")
   267  	}
   268  	if encMissingData == nil {
   269  		return nil, nil
   270  	}
   271  
   272  	return decodeMissingDataValue(encMissingData)
   273  }
   274  
   275  func (p *oldBlockDataProcessor) constructDBUpdateBatch() (*leveldbhelper.UpdateBatch, error) {
   276  	batch := p.db.NewUpdateBatch()
   277  
   278  	if err := p.entries.addDataEntriesTo(batch); err != nil {
   279  		return nil, errors.WithMessage(err, "error while adding data entries to the update batch")
   280  	}
   281  
   282  	if err := p.entries.addExpiryEntriesTo(batch); err != nil {
   283  		return nil, errors.WithMessage(err, "error while adding expiry entries to the update batch")
   284  	}
   285  
   286  	if err := p.entries.addElgPrioMissingDataEntriesTo(batch); err != nil {
   287  		return nil, errors.WithMessage(err, "error while adding eligible prioritized missing data entries to the update batch")
   288  	}
   289  
   290  	if err := p.entries.addElgDeprioMissingDataEntriesTo(batch); err != nil {
   291  		return nil, errors.WithMessage(err, "error while adding eligible deprioritized missing data entries to the update batch")
   292  	}
   293  
   294  	p.entries.addBootKVHashDeletionsTo(batch)
   295  
   296  	return batch, nil
   297  }
   298  
   299  type entriesForPvtDataOfOldBlocks struct {
   300  	dataEntries                     map[dataKey]*rwset.CollectionPvtReadWriteSet
   301  	expiryEntries                   map[expiryKey]*ExpiryData
   302  	prioritizedMissingDataEntries   map[nsCollBlk]*bitset.BitSet
   303  	deprioritizedMissingDataEntries map[nsCollBlk]*bitset.BitSet
   304  	bootKVHashesDeletions           []*bootKVHashesKey
   305  }
   306  
   307  func (e *entriesForPvtDataOfOldBlocks) addDataEntriesTo(batch *leveldbhelper.UpdateBatch) error {
   308  	var key, val []byte
   309  	var err error
   310  
   311  	for dataKey, pvtData := range e.dataEntries {
   312  		key = encodeDataKey(&dataKey)
   313  		if val, err = encodeDataValue(pvtData); err != nil {
   314  			return errors.Wrap(err, "error while encoding data value")
   315  		}
   316  		batch.Put(key, val)
   317  	}
   318  	return nil
   319  }
   320  
   321  func (e *entriesForPvtDataOfOldBlocks) addExpiryEntriesTo(batch *leveldbhelper.UpdateBatch) error {
   322  	var key, val []byte
   323  	var err error
   324  
   325  	for expiryKey, expiryData := range e.expiryEntries {
   326  		key = encodeExpiryKey(&expiryKey)
   327  		if val, err = encodeExpiryValue(expiryData); err != nil {
   328  			return errors.Wrap(err, "error while encoding expiry value")
   329  		}
   330  		batch.Put(key, val)
   331  	}
   332  	return nil
   333  }
   334  
   335  func (e *entriesForPvtDataOfOldBlocks) addElgPrioMissingDataEntriesTo(batch *leveldbhelper.UpdateBatch) error {
   336  	var key, val []byte
   337  	var err error
   338  
   339  	for nsCollBlk, missingData := range e.prioritizedMissingDataEntries {
   340  		missingKey := &missingDataKey{
   341  			nsCollBlk: nsCollBlk,
   342  		}
   343  		key = encodeElgPrioMissingDataKey(missingKey)
   344  
   345  		if missingData.None() {
   346  			batch.Delete(key)
   347  			continue
   348  		}
   349  
   350  		if val, err = encodeMissingDataValue(missingData); err != nil {
   351  			return errors.Wrap(err, "error while encoding missing data bitmap")
   352  		}
   353  		batch.Put(key, val)
   354  	}
   355  	return nil
   356  }
   357  
   358  func (e *entriesForPvtDataOfOldBlocks) addElgDeprioMissingDataEntriesTo(batch *leveldbhelper.UpdateBatch) error {
   359  	var key, val []byte
   360  	var err error
   361  
   362  	for nsCollBlk, missingData := range e.deprioritizedMissingDataEntries {
   363  		missingKey := &missingDataKey{
   364  			nsCollBlk: nsCollBlk,
   365  		}
   366  		key = encodeElgDeprioMissingDataKey(missingKey)
   367  
   368  		if missingData.None() {
   369  			batch.Delete(key)
   370  			continue
   371  		}
   372  
   373  		if val, err = encodeMissingDataValue(missingData); err != nil {
   374  			return errors.Wrap(err, "error while encoding missing data bitmap")
   375  		}
   376  		batch.Put(key, val)
   377  	}
   378  	return nil
   379  }
   380  
   381  func (e *entriesForPvtDataOfOldBlocks) addBootKVHashDeletionsTo(batch *leveldbhelper.UpdateBatch) {
   382  	for _, k := range e.bootKVHashesDeletions {
   383  		batch.Delete(encodeBootKVHashesKey(k))
   384  	}
   385  }