github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/common/ledger/blkstorage/blocks_itr_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package blkstorage 8 9 import ( 10 "sync" 11 "testing" 12 "time" 13 14 "github.com/hyperledger/fabric-protos-go/common" 15 "github.com/osdi23p228/fabric/common/ledger/testutil" 16 "github.com/stretchr/testify/require" 17 ) 18 19 func TestBlocksItrBlockingNext(t *testing.T) { 20 env := newTestEnv(t, NewConf(testPath(), 0)) 21 defer env.Cleanup() 22 blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger") 23 defer blkfileMgrWrapper.close() 24 blkfileMgr := blkfileMgrWrapper.blockfileMgr 25 26 blocks := testutil.ConstructTestBlocks(t, 10) 27 blkfileMgrWrapper.addBlocks(blocks[:5]) 28 29 itr, err := blkfileMgr.retrieveBlocks(1) 30 require.NoError(t, err) 31 defer itr.Close() 32 readyChan := make(chan struct{}) 33 doneChan := make(chan bool) 34 go testIterateAndVerify(t, itr, blocks[1:], 4, readyChan, doneChan) 35 <-readyChan 36 testAppendBlocks(blkfileMgrWrapper, blocks[5:7]) 37 blkfileMgr.moveToNextFile() 38 time.Sleep(time.Millisecond * 10) 39 testAppendBlocks(blkfileMgrWrapper, blocks[7:]) 40 <-doneChan 41 } 42 43 func TestBlockItrClose(t *testing.T) { 44 env := newTestEnv(t, NewConf(testPath(), 0)) 45 defer env.Cleanup() 46 blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger") 47 defer blkfileMgrWrapper.close() 48 blkfileMgr := blkfileMgrWrapper.blockfileMgr 49 50 blocks := testutil.ConstructTestBlocks(t, 5) 51 blkfileMgrWrapper.addBlocks(blocks) 52 53 itr, err := blkfileMgr.retrieveBlocks(1) 54 require.NoError(t, err) 55 56 bh, _ := itr.Next() 57 require.NotNil(t, bh) 58 itr.Close() 59 60 bh, err = itr.Next() 61 require.NoError(t, err) 62 require.Nil(t, bh) 63 } 64 65 func TestRaceToDeadlock(t *testing.T) { 66 env := newTestEnv(t, NewConf(testPath(), 0)) 67 defer env.Cleanup() 68 blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger") 69 defer blkfileMgrWrapper.close() 70 blkfileMgr := blkfileMgrWrapper.blockfileMgr 71 72 blocks := testutil.ConstructTestBlocks(t, 5) 73 blkfileMgrWrapper.addBlocks(blocks) 74 75 for i := 0; i < 1000; i++ { 76 itr, err := blkfileMgr.retrieveBlocks(5) 77 if err != nil { 78 panic(err) 79 } 80 go func() { 81 itr.Next() 82 }() 83 itr.Close() 84 } 85 86 for i := 0; i < 1000; i++ { 87 itr, err := blkfileMgr.retrieveBlocks(5) 88 if err != nil { 89 panic(err) 90 } 91 go func() { 92 itr.Close() 93 }() 94 itr.Next() 95 } 96 } 97 98 func TestBlockItrCloseWithoutRetrieve(t *testing.T) { 99 env := newTestEnv(t, NewConf(testPath(), 0)) 100 defer env.Cleanup() 101 blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger") 102 defer blkfileMgrWrapper.close() 103 blkfileMgr := blkfileMgrWrapper.blockfileMgr 104 blocks := testutil.ConstructTestBlocks(t, 5) 105 blkfileMgrWrapper.addBlocks(blocks) 106 107 itr, err := blkfileMgr.retrieveBlocks(2) 108 require.NoError(t, err) 109 itr.Close() 110 } 111 112 func TestCloseMultipleItrsWaitForFutureBlock(t *testing.T) { 113 env := newTestEnv(t, NewConf(testPath(), 0)) 114 defer env.Cleanup() 115 blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger") 116 defer blkfileMgrWrapper.close() 117 blkfileMgr := blkfileMgrWrapper.blockfileMgr 118 blocks := testutil.ConstructTestBlocks(t, 10) 119 blkfileMgrWrapper.addBlocks(blocks[:5]) 120 121 wg := &sync.WaitGroup{} 122 wg.Add(2) 123 itr1, err := blkfileMgr.retrieveBlocks(7) 124 require.NoError(t, err) 125 // itr1 does not retrieve any block because it closes before new blocks are added 126 go iterateInBackground(t, itr1, 9, wg, []uint64{}) 127 128 itr2, err := blkfileMgr.retrieveBlocks(8) 129 require.NoError(t, err) 130 // itr2 retrieves two blocks 8 and 9. Because it started waiting for 8 and quits at 9 131 go iterateInBackground(t, itr2, 9, wg, []uint64{8, 9}) 132 133 // sleep for the background iterators to get started 134 time.Sleep(2 * time.Second) 135 itr1.Close() 136 blkfileMgrWrapper.addBlocks(blocks[5:]) 137 wg.Wait() 138 } 139 140 func iterateInBackground(t *testing.T, itr *blocksItr, quitAfterBlkNum uint64, wg *sync.WaitGroup, expectedBlockNums []uint64) { 141 defer wg.Done() 142 retrievedBlkNums := []uint64{} 143 defer func() { require.Equal(t, expectedBlockNums, retrievedBlkNums) }() 144 145 for { 146 blk, err := itr.Next() 147 require.NoError(t, err) 148 if blk == nil { 149 return 150 } 151 blkNum := blk.(*common.Block).Header.Number 152 retrievedBlkNums = append(retrievedBlkNums, blkNum) 153 t.Logf("blk.Num=%d", blk.(*common.Block).Header.Number) 154 if blkNum == quitAfterBlkNum { 155 return 156 } 157 } 158 } 159 160 func testIterateAndVerify(t *testing.T, itr *blocksItr, blocks []*common.Block, readyAt int, readyChan chan<- struct{}, doneChan chan bool) { 161 blocksIterated := 0 162 for { 163 t.Logf("blocksIterated: %v", blocksIterated) 164 block, err := itr.Next() 165 require.NoError(t, err) 166 require.Equal(t, blocks[blocksIterated], block) 167 blocksIterated++ 168 if blocksIterated == readyAt { 169 close(readyChan) 170 } 171 if blocksIterated == len(blocks) { 172 break 173 } 174 } 175 doneChan <- true 176 } 177 178 func testAppendBlocks(blkfileMgrWrapper *testBlockfileMgrWrapper, blocks []*common.Block) { 179 blkfileMgrWrapper.addBlocks(blocks) 180 }