Skip to content

Commit dc3586c

Browse files
manish-sethimastersingh24
authored andcommitted
[FAB-7290] Handle Nil pointer panic in blocks iterator
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 <[email protected]> Signed-off-by: Gari Singh <[email protected]>
1 parent ee63d58 commit dc3586c

File tree

2 files changed

+67
-1
lines changed

2 files changed

+67
-1
lines changed

common/ledger/blkstorage/fsblkstorage/blocks_itr.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ func (itr *blocksItr) Next() (ledger.QueryResult, error) {
7777
return nil, nil
7878
}
7979
if itr.stream == nil {
80+
logger.Debugf("Initializing block stream for iterator. itr.maxBlockNumAvailable=%d", itr.maxBlockNumAvailable)
8081
if err := itr.initStream(); err != nil {
8182
return nil, err
8283
}
@@ -97,5 +98,7 @@ func (itr *blocksItr) Close() {
9798
itr.mgr.cpInfoCond.L.Lock()
9899
defer itr.mgr.cpInfoCond.L.Unlock()
99100
itr.mgr.cpInfoCond.Broadcast()
100-
itr.stream.close()
101+
if itr.stream != nil {
102+
itr.stream.close()
103+
}
101104
}

common/ledger/blkstorage/fsblkstorage/blocks_itr_test.go

+63
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package fsblkstorage
1818

1919
import (
20+
"sync"
2021
"testing"
2122
"time"
2223

@@ -74,6 +75,68 @@ func TestBlockItrClose(t *testing.T) {
7475
testutil.AssertNil(t, bh)
7576
}
7677

78+
func TestBlockItrCloseWithoutRetrieve(t *testing.T) {
79+
env := newTestEnv(t, NewConf(testPath(), 0))
80+
defer env.Cleanup()
81+
blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger")
82+
defer blkfileMgrWrapper.close()
83+
blkfileMgr := blkfileMgrWrapper.blockfileMgr
84+
blocks := testutil.ConstructTestBlocks(t, 5)
85+
blkfileMgrWrapper.addBlocks(blocks)
86+
87+
itr, err := blkfileMgr.retrieveBlocks(2)
88+
testutil.AssertNoError(t, err, "")
89+
itr.Close()
90+
}
91+
92+
func TestCloseMultipleItrsWaitForFutureBlock(t *testing.T) {
93+
env := newTestEnv(t, NewConf(testPath(), 0))
94+
defer env.Cleanup()
95+
blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger")
96+
defer blkfileMgrWrapper.close()
97+
blkfileMgr := blkfileMgrWrapper.blockfileMgr
98+
blocks := testutil.ConstructTestBlocks(t, 10)
99+
blkfileMgrWrapper.addBlocks(blocks[:5])
100+
101+
wg := &sync.WaitGroup{}
102+
wg.Add(2)
103+
itr1, err := blkfileMgr.retrieveBlocks(7)
104+
testutil.AssertNoError(t, err, "")
105+
// itr1 does not retrieve any block because it closes before new blocks are added
106+
go iterateInBackground(t, itr1, 9, wg, []uint64{})
107+
108+
itr2, err := blkfileMgr.retrieveBlocks(8)
109+
testutil.AssertNoError(t, err, "")
110+
// itr2 retrieves two blocks 8 and 9. Because it started waiting for 8 and quits at 9
111+
go iterateInBackground(t, itr2, 9, wg, []uint64{8, 9})
112+
113+
// sleep for the background iterators to get started
114+
time.Sleep(2 * time.Second)
115+
itr1.Close()
116+
blkfileMgrWrapper.addBlocks(blocks[5:])
117+
wg.Wait()
118+
}
119+
120+
func iterateInBackground(t *testing.T, itr *blocksItr, quitAfterBlkNum uint64, wg *sync.WaitGroup, expectedBlockNums []uint64) {
121+
defer wg.Done()
122+
retrievedBlkNums := []uint64{}
123+
defer func() { testutil.AssertEquals(t, retrievedBlkNums, expectedBlockNums) }()
124+
125+
for {
126+
blk, err := itr.Next()
127+
testutil.AssertNoError(t, err, "")
128+
if blk == nil {
129+
return
130+
}
131+
blkNum := blk.(*common.Block).Header.Number
132+
retrievedBlkNums = append(retrievedBlkNums, blkNum)
133+
t.Logf("blk.Num=%d", blk.(*common.Block).Header.Number)
134+
if blkNum == quitAfterBlkNum {
135+
return
136+
}
137+
}
138+
}
139+
77140
func testIterateAndVerify(t *testing.T, itr *blocksItr, blocks []*common.Block, doneChan chan bool) {
78141
blocksIterated := 0
79142
for {

0 commit comments

Comments
 (0)