github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/common/ledger/blkstorage/blocks_itr.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package blkstorage 8 9 import ( 10 "sync" 11 12 "github.com/hechain20/hechain/common/ledger" 13 ) 14 15 // blocksItr - an iterator for iterating over a sequence of blocks 16 type blocksItr struct { 17 mgr *blockfileMgr 18 maxBlockNumAvailable uint64 19 blockNumToRetrieve uint64 20 stream *blockStream 21 closeMarker bool 22 closeMarkerLock *sync.Mutex 23 } 24 25 func newBlockItr(mgr *blockfileMgr, startBlockNum uint64) *blocksItr { 26 mgr.blkfilesInfoCond.L.Lock() 27 defer mgr.blkfilesInfoCond.L.Unlock() 28 return &blocksItr{mgr, mgr.blockfilesInfo.lastPersistedBlock, startBlockNum, nil, false, &sync.Mutex{}} 29 } 30 31 func (itr *blocksItr) waitForBlock(blockNum uint64) uint64 { 32 itr.mgr.blkfilesInfoCond.L.Lock() 33 defer itr.mgr.blkfilesInfoCond.L.Unlock() 34 for itr.mgr.blockfilesInfo.lastPersistedBlock < blockNum && !itr.shouldClose() { 35 logger.Debugf("Going to wait for newer blocks. maxAvailaBlockNumber=[%d], waitForBlockNum=[%d]", 36 itr.mgr.blockfilesInfo.lastPersistedBlock, blockNum) 37 itr.mgr.blkfilesInfoCond.Wait() 38 logger.Debugf("Came out of wait. maxAvailaBlockNumber=[%d]", itr.mgr.blockfilesInfo.lastPersistedBlock) 39 } 40 return itr.mgr.blockfilesInfo.lastPersistedBlock 41 } 42 43 func (itr *blocksItr) initStream() error { 44 var lp *fileLocPointer 45 var err error 46 if lp, err = itr.mgr.index.getBlockLocByBlockNum(itr.blockNumToRetrieve); err != nil { 47 return err 48 } 49 if itr.stream, err = newBlockStream(itr.mgr.rootDir, lp.fileSuffixNum, int64(lp.offset), -1); err != nil { 50 return err 51 } 52 return nil 53 } 54 55 func (itr *blocksItr) shouldClose() bool { 56 itr.closeMarkerLock.Lock() 57 defer itr.closeMarkerLock.Unlock() 58 return itr.closeMarker 59 } 60 61 // Next moves the cursor to next block and returns true iff the iterator is not exhausted 62 func (itr *blocksItr) Next() (ledger.QueryResult, error) { 63 if itr.maxBlockNumAvailable < itr.blockNumToRetrieve { 64 itr.maxBlockNumAvailable = itr.waitForBlock(itr.blockNumToRetrieve) 65 } 66 itr.closeMarkerLock.Lock() 67 defer itr.closeMarkerLock.Unlock() 68 if itr.closeMarker { 69 return nil, nil 70 } 71 if itr.stream == nil { 72 logger.Debugf("Initializing block stream for iterator. itr.maxBlockNumAvailable=%d", itr.maxBlockNumAvailable) 73 if err := itr.initStream(); err != nil { 74 return nil, err 75 } 76 } 77 nextBlockBytes, err := itr.stream.nextBlockBytes() 78 if err != nil { 79 return nil, err 80 } 81 itr.blockNumToRetrieve++ 82 return deserializeBlock(nextBlockBytes) 83 } 84 85 // Close releases any resources held by the iterator 86 func (itr *blocksItr) Close() { 87 itr.mgr.blkfilesInfoCond.L.Lock() 88 defer itr.mgr.blkfilesInfoCond.L.Unlock() 89 itr.closeMarkerLock.Lock() 90 defer itr.closeMarkerLock.Unlock() 91 itr.closeMarker = true 92 itr.mgr.blkfilesInfoCond.Broadcast() 93 if itr.stream != nil { 94 itr.stream.close() 95 } 96 }