github.com/defanghe/fabric@v2.1.1+incompatible/core/ledger/ledgerstorage/store.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package ledgerstorage 8 9 import ( 10 "sync" 11 "sync/atomic" 12 13 "github.com/hyperledger/fabric-protos-go/common" 14 "github.com/hyperledger/fabric/common/flogging" 15 "github.com/hyperledger/fabric/common/ledger/blkstorage" 16 "github.com/hyperledger/fabric/common/ledger/blkstorage/fsblkstorage" 17 "github.com/hyperledger/fabric/common/metrics" 18 "github.com/hyperledger/fabric/core/ledger" 19 "github.com/hyperledger/fabric/core/ledger/pvtdatapolicy" 20 "github.com/hyperledger/fabric/core/ledger/pvtdatastorage" 21 ) 22 23 const maxBlockFileSize = 64 * 1024 * 1024 24 25 var logger = flogging.MustGetLogger("ledgerstorage") 26 27 // Provider encapsulates two providers 1) block store provider and 2) and pvt data store provider 28 type Provider struct { 29 blkStoreProvider blkstorage.BlockStoreProvider 30 pvtdataStoreProvider pvtdatastorage.Provider 31 } 32 33 // Store encapsulates two stores 1) block store and pvt data store 34 type Store struct { 35 blkstorage.BlockStore 36 pvtdataStore pvtdatastorage.Store 37 rwlock sync.RWMutex 38 isPvtstoreAheadOfBlockstore atomic.Value 39 } 40 41 var attrsToIndex = []blkstorage.IndexableAttr{ 42 blkstorage.IndexableAttrBlockHash, 43 blkstorage.IndexableAttrBlockNum, 44 blkstorage.IndexableAttrTxID, 45 blkstorage.IndexableAttrBlockNumTranNum, 46 } 47 48 // NewProvider returns the handle to the provider 49 func NewProvider(blockStoreDir string, conf *pvtdatastorage.PrivateDataConfig, metricsProvider metrics.Provider) (*Provider, error) { 50 // Initialize the block storage 51 indexConfig := &blkstorage.IndexConfig{AttrsToIndex: attrsToIndex} 52 blockStoreProvider, err := fsblkstorage.NewProvider( 53 fsblkstorage.NewConf( 54 blockStoreDir, 55 maxBlockFileSize, 56 ), 57 indexConfig, 58 metricsProvider, 59 ) 60 if err != nil { 61 return nil, err 62 } 63 pvtStoreProvider, err := pvtdatastorage.NewProvider(conf) 64 if err != nil { 65 return nil, err 66 } 67 return &Provider{blockStoreProvider, pvtStoreProvider}, nil 68 } 69 70 // Open opens the store 71 func (p *Provider) Open(ledgerid string) (*Store, error) { 72 var blockStore blkstorage.BlockStore 73 var pvtdataStore pvtdatastorage.Store 74 var err error 75 76 if blockStore, err = p.blkStoreProvider.OpenBlockStore(ledgerid); err != nil { 77 return nil, err 78 } 79 if pvtdataStore, err = p.pvtdataStoreProvider.OpenStore(ledgerid); err != nil { 80 return nil, err 81 } 82 store := &Store{ 83 BlockStore: blockStore, 84 pvtdataStore: pvtdataStore, 85 } 86 87 info, err := blockStore.GetBlockchainInfo() 88 if err != nil { 89 return nil, err 90 } 91 pvtstoreHeight, err := pvtdataStore.LastCommittedBlockHeight() 92 if err != nil { 93 return nil, err 94 } 95 store.isPvtstoreAheadOfBlockstore.Store(pvtstoreHeight > info.Height) 96 97 return store, nil 98 } 99 100 // Close closes the provider 101 func (p *Provider) Close() { 102 p.blkStoreProvider.Close() 103 p.pvtdataStoreProvider.Close() 104 } 105 106 // Exists checks whether the ledgerID already presents 107 func (p *Provider) Exists(ledgerID string) (bool, error) { 108 return p.blkStoreProvider.Exists(ledgerID) 109 } 110 111 // Init initializes store with essential configurations 112 func (s *Store) Init(btlPolicy pvtdatapolicy.BTLPolicy) { 113 s.pvtdataStore.Init(btlPolicy) 114 } 115 116 // CommitWithPvtData commits the block and the corresponding pvt data in an atomic operation 117 func (s *Store) CommitWithPvtData(blockAndPvtdata *ledger.BlockAndPvtData) error { 118 blockNum := blockAndPvtdata.Block.Header.Number 119 s.rwlock.Lock() 120 defer s.rwlock.Unlock() 121 122 pvtBlkStoreHt, err := s.pvtdataStore.LastCommittedBlockHeight() 123 if err != nil { 124 return err 125 } 126 127 if pvtBlkStoreHt < blockNum+1 { // The pvt data store sanity check does not allow rewriting the pvt data. 128 // when re-processing blocks (rejoin the channel or re-fetching last few block), 129 // skip the pvt data commit to the pvtdata blockstore 130 logger.Debugf("Writing block [%d] to pvt block store", blockNum) 131 // If a state fork occurs during a regular block commit, 132 // we have a mechanism to drop all blocks followed by refetching of blocks 133 // and re-processing them. In the current way of doing this, we only drop 134 // the block files (and related artifacts) but we do not drop/overwrite the 135 // pvtdatastorage as it might leads to data loss. 136 // During block reprocessing, as there is a possibility of an invalid pvtdata 137 // transaction to become valid, we store the pvtdata of invalid transactions 138 // too in the pvtdataStore as we do for the publicdata in the case of blockStore. 139 pvtData, missingPvtData := constructPvtDataAndMissingData(blockAndPvtdata) 140 if err := s.pvtdataStore.Commit(blockAndPvtdata.Block.Header.Number, pvtData, missingPvtData); err != nil { 141 return err 142 } 143 } else { 144 logger.Debugf("Skipping writing block [%d] to pvt block store as the store height is [%d]", blockNum, pvtBlkStoreHt) 145 } 146 147 if err := s.AddBlock(blockAndPvtdata.Block); err != nil { 148 return err 149 } 150 151 if pvtBlkStoreHt == blockNum+1 { 152 // we reach here only when the pvtdataStore was ahead 153 // of blockStore during the store opening time (would 154 // occur after a peer rollback/reset). 155 s.isPvtstoreAheadOfBlockstore.Store(false) 156 } 157 158 return nil 159 } 160 161 func constructPvtDataAndMissingData(blockAndPvtData *ledger.BlockAndPvtData) ([]*ledger.TxPvtData, 162 ledger.TxMissingPvtDataMap) { 163 164 var pvtData []*ledger.TxPvtData 165 missingPvtData := make(ledger.TxMissingPvtDataMap) 166 167 numTxs := uint64(len(blockAndPvtData.Block.Data.Data)) 168 169 // for all tx, construct pvtdata and missing pvtdata list 170 for txNum := uint64(0); txNum < numTxs; txNum++ { 171 if pvtdata, ok := blockAndPvtData.PvtData[txNum]; ok { 172 pvtData = append(pvtData, pvtdata) 173 } 174 175 if missingData, ok := blockAndPvtData.MissingPvtData[txNum]; ok { 176 for _, missing := range missingData { 177 missingPvtData.Add(txNum, missing.Namespace, 178 missing.Collection, missing.IsEligible) 179 } 180 } 181 } 182 return pvtData, missingPvtData 183 } 184 185 // CommitPvtDataOfOldBlocks commits the pvtData of old blocks 186 func (s *Store) CommitPvtDataOfOldBlocks(blocksPvtData map[uint64][]*ledger.TxPvtData) error { 187 err := s.pvtdataStore.CommitPvtDataOfOldBlocks(blocksPvtData) 188 if err != nil { 189 return err 190 } 191 return nil 192 } 193 194 // GetPvtDataAndBlockByNum returns the block and the corresponding pvt data. 195 // The pvt data is filtered by the list of 'collections' supplied 196 func (s *Store) GetPvtDataAndBlockByNum(blockNum uint64, filter ledger.PvtNsCollFilter) (*ledger.BlockAndPvtData, error) { 197 s.rwlock.RLock() 198 defer s.rwlock.RUnlock() 199 200 var block *common.Block 201 var pvtdata []*ledger.TxPvtData 202 var err error 203 if block, err = s.RetrieveBlockByNumber(blockNum); err != nil { 204 return nil, err 205 } 206 if pvtdata, err = s.getPvtDataByNumWithoutLock(blockNum, filter); err != nil { 207 return nil, err 208 } 209 return &ledger.BlockAndPvtData{Block: block, PvtData: constructPvtdataMap(pvtdata)}, nil 210 } 211 212 // GetPvtDataByNum returns only the pvt data corresponding to the given block number 213 // The pvt data is filtered by the list of 'ns/collections' supplied in the filter 214 // A nil filter does not filter any results 215 func (s *Store) GetPvtDataByNum(blockNum uint64, filter ledger.PvtNsCollFilter) ([]*ledger.TxPvtData, error) { 216 s.rwlock.RLock() 217 defer s.rwlock.RUnlock() 218 return s.getPvtDataByNumWithoutLock(blockNum, filter) 219 } 220 221 // getPvtDataByNumWithoutLock returns only the pvt data corresponding to the given block number. 222 // This function does not acquire a readlock and it is expected that in most of the circumstances, the caller 223 // possesses a read lock on `s.rwlock` 224 func (s *Store) getPvtDataByNumWithoutLock(blockNum uint64, filter ledger.PvtNsCollFilter) ([]*ledger.TxPvtData, error) { 225 var pvtdata []*ledger.TxPvtData 226 var err error 227 if pvtdata, err = s.pvtdataStore.GetPvtDataByBlockNum(blockNum, filter); err != nil { 228 return nil, err 229 } 230 return pvtdata, nil 231 } 232 233 // DoesPvtDataInfoExist returns true when 234 // (1) the ledger has pvtdata associated with the given block number (or) 235 // (2) a few or all pvtdata associated with the given block number is missing but the 236 // missing info is recorded in the ledger (or) 237 // (3) the block is committed does not contain any pvtData. 238 func (s *Store) DoesPvtDataInfoExist(blockNum uint64) (bool, error) { 239 pvtStoreHt, err := s.pvtdataStore.LastCommittedBlockHeight() 240 if err != nil { 241 return false, err 242 } 243 return blockNum+1 <= pvtStoreHt, nil 244 } 245 246 // GetMissingPvtDataInfoForMostRecentBlocks invokes the function on underlying pvtdata store 247 func (s *Store) GetMissingPvtDataInfoForMostRecentBlocks(maxBlock int) (ledger.MissingPvtDataInfo, error) { 248 // it is safe to not acquire a read lock on s.rwlock. Without a lock, the value of 249 // lastCommittedBlock can change due to a new block commit. As a result, we may not 250 // be able to fetch the missing data info of truly the most recent blocks. This 251 // decision was made to ensure that the regular block commit rate is not affected. 252 return s.pvtdataStore.GetMissingPvtDataInfoForMostRecentBlocks(maxBlock) 253 } 254 255 // ProcessCollsEligibilityEnabled invokes the function on underlying pvtdata store 256 func (s *Store) ProcessCollsEligibilityEnabled(committingBlk uint64, nsCollMap map[string][]string) error { 257 return s.pvtdataStore.ProcessCollsEligibilityEnabled(committingBlk, nsCollMap) 258 } 259 260 // GetLastUpdatedOldBlocksPvtData invokes the function on underlying pvtdata store 261 func (s *Store) GetLastUpdatedOldBlocksPvtData() (map[uint64][]*ledger.TxPvtData, error) { 262 return s.pvtdataStore.GetLastUpdatedOldBlocksPvtData() 263 } 264 265 // ResetLastUpdatedOldBlocksList invokes the function on underlying pvtdata store 266 func (s *Store) ResetLastUpdatedOldBlocksList() error { 267 return s.pvtdataStore.ResetLastUpdatedOldBlocksList() 268 } 269 270 // IsPvtStoreAheadOfBlockStore returns true when the pvtStore height is 271 // greater than the blockstore height. Otherwise, it returns false. 272 func (s *Store) IsPvtStoreAheadOfBlockStore() bool { 273 return s.isPvtstoreAheadOfBlockstore.Load().(bool) 274 } 275 276 func constructPvtdataMap(pvtdata []*ledger.TxPvtData) ledger.TxPvtDataMap { 277 if pvtdata == nil { 278 return nil 279 } 280 m := make(map[uint64]*ledger.TxPvtData) 281 for _, pvtdatum := range pvtdata { 282 m[pvtdatum.SeqInBlock] = pvtdatum 283 } 284 return m 285 } 286 287 // LoadPreResetHeight returns the pre reset height for the specified ledgers. 288 func LoadPreResetHeight(blockstorePath string, ledgerIDs []string) (map[string]uint64, error) { 289 return fsblkstorage.LoadPreResetHeight(blockstorePath, ledgerIDs) 290 } 291 292 // ResetBlockStore resets all ledgers to the genesis block. 293 func ResetBlockStore(blockstorePath string) error { 294 return fsblkstorage.ResetBlockStore(blockstorePath) 295 } 296 297 // ValidateRollbackParams performs necessary validation on the input given for 298 // the rollback operation. 299 func ValidateRollbackParams(blockstorePath, ledgerID string, blockNum uint64) error { 300 return fsblkstorage.ValidateRollbackParams(blockstorePath, ledgerID, blockNum) 301 } 302 303 // Rollback reverts changes made to the block store beyond a given block number. 304 func Rollback(blockstorePath, ledgerID string, blockNum uint64) error { 305 indexConfig := &blkstorage.IndexConfig{AttrsToIndex: attrsToIndex} 306 return fsblkstorage.Rollback(blockstorePath, ledgerID, blockNum, indexConfig) 307 }