Skip to content

Commit

Permalink
[FAB-7290] Handle Nil pointer panic in blocks iterator
Browse files Browse the repository at this point in the history
This CR add a simple nil check before calling close function
on blockfile stream instance. In addition, a couple of tests
are added.

Change-Id: I053b289b32c5dfeab5824eb866a954dc4aa5cfa9
Signed-off-by: manish <manish.sethi@gmail.com>
  • Loading branch information
manish-sethi committed Dec 4, 2017
1 parent 8becdf0 commit bb27f42
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 1 deletion.
5 changes: 4 additions & 1 deletion common/ledger/blkstorage/fsblkstorage/blocks_itr.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ func (itr *blocksItr) Next() (ledger.QueryResult, error) {
return nil, nil
}
if itr.stream == nil {
logger.Debugf("Initializing block stream for iterator. itr.maxBlockNumAvailable=%d", itr.maxBlockNumAvailable)
if err := itr.initStream(); err != nil {
return nil, err
}
Expand All @@ -97,5 +98,7 @@ func (itr *blocksItr) Close() {
itr.mgr.cpInfoCond.L.Lock()
defer itr.mgr.cpInfoCond.L.Unlock()
itr.mgr.cpInfoCond.Broadcast()
itr.stream.close()
if itr.stream != nil {
itr.stream.close()
}
}
63 changes: 63 additions & 0 deletions common/ledger/blkstorage/fsblkstorage/blocks_itr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package fsblkstorage

import (
"sync"
"testing"
"time"

Expand Down Expand Up @@ -74,6 +75,68 @@ func TestBlockItrClose(t *testing.T) {
testutil.AssertNil(t, bh)
}

func TestBlockItrCloseWithoutRetrieve(t *testing.T) {
env := newTestEnv(t, NewConf(testPath(), 0))
defer env.Cleanup()
blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger")
defer blkfileMgrWrapper.close()
blkfileMgr := blkfileMgrWrapper.blockfileMgr
blocks := testutil.ConstructTestBlocks(t, 5)
blkfileMgrWrapper.addBlocks(blocks)

itr, err := blkfileMgr.retrieveBlocks(2)
testutil.AssertNoError(t, err, "")
itr.Close()
}

func TestCloseMultipleItrsWaitForFutureBlock(t *testing.T) {
env := newTestEnv(t, NewConf(testPath(), 0))
defer env.Cleanup()
blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger")
defer blkfileMgrWrapper.close()
blkfileMgr := blkfileMgrWrapper.blockfileMgr
blocks := testutil.ConstructTestBlocks(t, 10)
blkfileMgrWrapper.addBlocks(blocks[:5])

wg := &sync.WaitGroup{}
wg.Add(2)
itr1, err := blkfileMgr.retrieveBlocks(7)
testutil.AssertNoError(t, err, "")
// itr1 does not retrieve any block because it closes before new blocks are added
go iterateInBackground(t, itr1, 9, wg, []uint64{})

itr2, err := blkfileMgr.retrieveBlocks(8)
testutil.AssertNoError(t, err, "")
// itr2 retrieves two blocks 8 and 9. Because it started waiting for 8 and quits at 9
go iterateInBackground(t, itr2, 9, wg, []uint64{8, 9})

// sleep for the background iterators to get started
time.Sleep(2 * time.Second)
itr1.Close()
blkfileMgrWrapper.addBlocks(blocks[5:])
wg.Wait()
}

func iterateInBackground(t *testing.T, itr *blocksItr, quitAfterBlkNum uint64, wg *sync.WaitGroup, expectedBlockNums []uint64) {
defer wg.Done()
retrievedBlkNums := []uint64{}
defer func() { testutil.AssertEquals(t, retrievedBlkNums, expectedBlockNums) }()

for {
blk, err := itr.Next()
testutil.AssertNoError(t, err, "")
if blk == nil {
return
}
blkNum := blk.(*common.Block).Header.Number
retrievedBlkNums = append(retrievedBlkNums, blkNum)
t.Logf("blk.Num=%d", blk.(*common.Block).Header.Number)
if blkNum == quitAfterBlkNum {
return
}
}
}

func testIterateAndVerify(t *testing.T, itr *blocksItr, blocks []*common.Block, doneChan chan bool) {
blocksIterated := 0
for {
Expand Down

0 comments on commit bb27f42

Please sign in to comment.