github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/common/ledger/blkstorage/fsblkstorage/blocks_itr.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package fsblkstorage 18 19 import ( 20 "sync" 21 22 "github.com/hyperledger/fabric/common/ledger" 23 ) 24 25 // blocksItr - an iterator for iterating over a sequence of blocks 26 type blocksItr struct { 27 mgr *blockfileMgr 28 maxBlockNumAvailable uint64 29 blockNumToRetrieve uint64 30 stream *blockStream 31 closeMarker bool 32 closeMarkerLock *sync.Mutex 33 } 34 35 func newBlockItr(mgr *blockfileMgr, startBlockNum uint64) *blocksItr { 36 mgr.cpInfoCond.L.Lock() 37 defer mgr.cpInfoCond.L.Unlock() 38 return &blocksItr{mgr, mgr.cpInfo.lastBlockNumber, startBlockNum, nil, false, &sync.Mutex{}} 39 } 40 41 func (itr *blocksItr) waitForBlock(blockNum uint64) uint64 { 42 itr.mgr.cpInfoCond.L.Lock() 43 defer itr.mgr.cpInfoCond.L.Unlock() 44 for itr.mgr.cpInfo.lastBlockNumber < blockNum && !itr.shouldClose() { 45 logger.Debugf("Going to wait for newer blocks. maxAvailaBlockNumber=[%d], waitForBlockNum=[%d]", 46 itr.mgr.cpInfo.lastBlockNumber, blockNum) 47 itr.mgr.cpInfoCond.Wait() 48 logger.Debugf("Came out of wait. maxAvailaBlockNumber=[%d]", itr.mgr.cpInfo.lastBlockNumber) 49 } 50 return itr.mgr.cpInfo.lastBlockNumber 51 } 52 53 func (itr *blocksItr) initStream() error { 54 var lp *fileLocPointer 55 var err error 56 if lp, err = itr.mgr.index.getBlockLocByBlockNum(itr.blockNumToRetrieve); err != nil { 57 return err 58 } 59 if itr.stream, err = newBlockStream(itr.mgr.rootDir, lp.fileSuffixNum, int64(lp.offset), -1); err != nil { 60 return err 61 } 62 return nil 63 } 64 65 func (itr *blocksItr) shouldClose() bool { 66 itr.closeMarkerLock.Lock() 67 defer itr.closeMarkerLock.Unlock() 68 return itr.closeMarker 69 } 70 71 // Next moves the cursor to next block and returns true iff the iterator is not exhausted 72 func (itr *blocksItr) Next() (ledger.QueryResult, error) { 73 if itr.maxBlockNumAvailable < itr.blockNumToRetrieve { 74 itr.maxBlockNumAvailable = itr.waitForBlock(itr.blockNumToRetrieve) 75 } 76 itr.closeMarkerLock.Lock() 77 defer itr.closeMarkerLock.Unlock() 78 if itr.closeMarker { 79 return nil, nil 80 } 81 if itr.stream == nil { 82 logger.Debugf("Initializing block stream for iterator. itr.maxBlockNumAvailable=%d", itr.maxBlockNumAvailable) 83 if err := itr.initStream(); err != nil { 84 return nil, err 85 } 86 } 87 nextBlockBytes, err := itr.stream.nextBlockBytes() 88 if err != nil { 89 return nil, err 90 } 91 itr.blockNumToRetrieve++ 92 return deserializeBlock(nextBlockBytes) 93 } 94 95 // Close releases any resources held by the iterator 96 func (itr *blocksItr) Close() { 97 itr.mgr.cpInfoCond.L.Lock() 98 defer itr.mgr.cpInfoCond.L.Unlock() 99 itr.closeMarkerLock.Lock() 100 defer itr.closeMarkerLock.Unlock() 101 itr.closeMarker = true 102 itr.mgr.cpInfoCond.Broadcast() 103 if itr.stream != nil { 104 itr.stream.close() 105 } 106 }