github.com/kchristidis/fabric@v1.0.4-0.20171028114726-837acd08cde1/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 return &blocksItr{mgr, mgr.cpInfo.lastBlockNumber, startBlockNum, nil, false, &sync.Mutex{}} 37 } 38 39 func (itr *blocksItr) waitForBlock(blockNum uint64) uint64 { 40 itr.mgr.cpInfoCond.L.Lock() 41 defer itr.mgr.cpInfoCond.L.Unlock() 42 for itr.mgr.cpInfo.lastBlockNumber < blockNum && !itr.shouldClose() { 43 logger.Debugf("Going to wait for newer blocks. maxAvailaBlockNumber=[%d], waitForBlockNum=[%d]", 44 itr.mgr.cpInfo.lastBlockNumber, blockNum) 45 itr.mgr.cpInfoCond.Wait() 46 logger.Debugf("Came out of wait. maxAvailaBlockNumber=[%d]", itr.mgr.cpInfo.lastBlockNumber) 47 } 48 return itr.mgr.cpInfo.lastBlockNumber 49 } 50 51 func (itr *blocksItr) initStream() error { 52 var lp *fileLocPointer 53 var err error 54 if lp, err = itr.mgr.index.getBlockLocByBlockNum(itr.blockNumToRetrieve); err != nil { 55 return err 56 } 57 if itr.stream, err = newBlockStream(itr.mgr.rootDir, lp.fileSuffixNum, int64(lp.offset), -1); err != nil { 58 return err 59 } 60 return nil 61 } 62 63 func (itr *blocksItr) shouldClose() bool { 64 itr.closeMarkerLock.Lock() 65 defer itr.closeMarkerLock.Unlock() 66 return itr.closeMarker 67 } 68 69 // Next moves the cursor to next block and returns true iff the iterator is not exhausted 70 func (itr *blocksItr) Next() (ledger.QueryResult, error) { 71 if itr.maxBlockNumAvailable < itr.blockNumToRetrieve { 72 itr.maxBlockNumAvailable = itr.waitForBlock(itr.blockNumToRetrieve) 73 } 74 itr.closeMarkerLock.Lock() 75 defer itr.closeMarkerLock.Unlock() 76 if itr.closeMarker { 77 return nil, nil 78 } 79 if itr.stream == nil { 80 if err := itr.initStream(); err != nil { 81 return nil, err 82 } 83 } 84 nextBlockBytes, err := itr.stream.nextBlockBytes() 85 if err != nil { 86 return nil, err 87 } 88 itr.blockNumToRetrieve++ 89 return deserializeBlock(nextBlockBytes) 90 } 91 92 // Close releases any resources held by the iterator 93 func (itr *blocksItr) Close() { 94 itr.closeMarkerLock.Lock() 95 defer itr.closeMarkerLock.Unlock() 96 itr.closeMarker = true 97 itr.mgr.cpInfoCond.L.Lock() 98 defer itr.mgr.cpInfoCond.L.Unlock() 99 itr.mgr.cpInfoCond.Broadcast() 100 itr.stream.close() 101 }