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 }