github.com/516108736/tendermint@v0.36.0/consensus/wal_test.go (about) 1 package consensus 2 3 import ( 4 "bytes" 5 "crypto/rand" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 10 // "sync" 11 "testing" 12 "time" 13 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 17 "github.com/tendermint/tendermint/consensus/types" 18 "github.com/tendermint/tendermint/crypto/merkle" 19 "github.com/tendermint/tendermint/libs/autofile" 20 "github.com/tendermint/tendermint/libs/log" 21 tmtypes "github.com/tendermint/tendermint/types" 22 tmtime "github.com/tendermint/tendermint/types/time" 23 ) 24 25 const ( 26 walTestFlushInterval = time.Duration(100) * time.Millisecond 27 ) 28 29 func TestWALTruncate(t *testing.T) { 30 walDir, err := ioutil.TempDir("", "wal") 31 require.NoError(t, err) 32 defer os.RemoveAll(walDir) 33 34 walFile := filepath.Join(walDir, "wal") 35 36 // this magic number 4K can truncate the content when RotateFile. 37 // defaultHeadSizeLimit(10M) is hard to simulate. 38 // this magic number 1 * time.Millisecond make RotateFile check frequently. 39 // defaultGroupCheckDuration(5s) is hard to simulate. 40 wal, err := NewWAL(walFile, 41 autofile.GroupHeadSizeLimit(4096), 42 autofile.GroupCheckDuration(1*time.Millisecond), 43 ) 44 require.NoError(t, err) 45 wal.SetLogger(log.TestingLogger()) 46 err = wal.Start() 47 require.NoError(t, err) 48 defer func() { 49 if err := wal.Stop(); err != nil { 50 t.Error(err) 51 } 52 // wait for the wal to finish shutting down so we 53 // can safely remove the directory 54 wal.Wait() 55 }() 56 57 // 60 block's size nearly 70K, greater than group's headBuf size(4096 * 10), 58 // when headBuf is full, truncate content will Flush to the file. at this 59 // time, RotateFile is called, truncate content exist in each file. 60 err = WALGenerateNBlocks(t, wal.Group(), 60) 61 require.NoError(t, err) 62 63 time.Sleep(1 * time.Millisecond) // wait groupCheckDuration, make sure RotateFile run 64 65 if err := wal.FlushAndSync(); err != nil { 66 t.Error(err) 67 } 68 69 h := int64(50) 70 gr, found, err := wal.SearchForEndHeight(h, &WALSearchOptions{}) 71 assert.NoError(t, err, "expected not to err on height %d", h) 72 assert.True(t, found, "expected to find end height for %d", h) 73 assert.NotNil(t, gr) 74 defer gr.Close() 75 76 dec := NewWALDecoder(gr) 77 msg, err := dec.Decode() 78 assert.NoError(t, err, "expected to decode a message") 79 rs, ok := msg.Msg.(tmtypes.EventDataRoundState) 80 assert.True(t, ok, "expected message of type EventDataRoundState") 81 assert.Equal(t, rs.Height, h+1, "wrong height") 82 } 83 84 func TestWALEncoderDecoder(t *testing.T) { 85 now := tmtime.Now() 86 msgs := []TimedWALMessage{ 87 {Time: now, Msg: EndHeightMessage{0}}, 88 {Time: now, Msg: timeoutInfo{Duration: time.Second, Height: 1, Round: 1, Step: types.RoundStepPropose}}, 89 {Time: now, Msg: tmtypes.EventDataRoundState{Height: 1, Round: 1, Step: ""}}, 90 } 91 92 b := new(bytes.Buffer) 93 94 for _, msg := range msgs { 95 msg := msg 96 97 b.Reset() 98 99 enc := NewWALEncoder(b) 100 err := enc.Encode(&msg) 101 require.NoError(t, err) 102 103 dec := NewWALDecoder(b) 104 decoded, err := dec.Decode() 105 require.NoError(t, err) 106 assert.Equal(t, msg.Time.UTC(), decoded.Time) 107 assert.Equal(t, msg.Msg, decoded.Msg) 108 } 109 } 110 111 func TestWALWrite(t *testing.T) { 112 walDir, err := ioutil.TempDir("", "wal") 113 require.NoError(t, err) 114 defer os.RemoveAll(walDir) 115 walFile := filepath.Join(walDir, "wal") 116 117 wal, err := NewWAL(walFile) 118 require.NoError(t, err) 119 err = wal.Start() 120 require.NoError(t, err) 121 defer func() { 122 if err := wal.Stop(); err != nil { 123 t.Error(err) 124 } 125 // wait for the wal to finish shutting down so we 126 // can safely remove the directory 127 wal.Wait() 128 }() 129 130 // 1) Write returns an error if msg is too big 131 msg := &BlockPartMessage{ 132 Height: 1, 133 Round: 1, 134 Part: &tmtypes.Part{ 135 Index: 1, 136 Bytes: make([]byte, 1), 137 Proof: merkle.Proof{ 138 Total: 1, 139 Index: 1, 140 LeafHash: make([]byte, maxMsgSizeBytes-30), 141 }, 142 }, 143 } 144 145 err = wal.Write(msgInfo{ 146 Msg: msg, 147 }) 148 if assert.Error(t, err) { 149 assert.Contains(t, err.Error(), "msg is too big") 150 } 151 } 152 153 func TestWALSearchForEndHeight(t *testing.T) { 154 walBody, err := WALWithNBlocks(t, 6) 155 if err != nil { 156 t.Fatal(err) 157 } 158 walFile := tempWALWithData(walBody) 159 160 wal, err := NewWAL(walFile) 161 require.NoError(t, err) 162 wal.SetLogger(log.TestingLogger()) 163 164 h := int64(3) 165 gr, found, err := wal.SearchForEndHeight(h, &WALSearchOptions{}) 166 assert.NoError(t, err, "expected not to err on height %d", h) 167 assert.True(t, found, "expected to find end height for %d", h) 168 assert.NotNil(t, gr) 169 defer gr.Close() 170 171 dec := NewWALDecoder(gr) 172 msg, err := dec.Decode() 173 assert.NoError(t, err, "expected to decode a message") 174 rs, ok := msg.Msg.(tmtypes.EventDataRoundState) 175 assert.True(t, ok, "expected message of type EventDataRoundState") 176 assert.Equal(t, rs.Height, h+1, "wrong height") 177 } 178 179 func TestWALPeriodicSync(t *testing.T) { 180 walDir, err := ioutil.TempDir("", "wal") 181 require.NoError(t, err) 182 defer os.RemoveAll(walDir) 183 184 walFile := filepath.Join(walDir, "wal") 185 wal, err := NewWAL(walFile, autofile.GroupCheckDuration(1*time.Millisecond)) 186 require.NoError(t, err) 187 188 wal.SetFlushInterval(walTestFlushInterval) 189 wal.SetLogger(log.TestingLogger()) 190 191 // Generate some data 192 err = WALGenerateNBlocks(t, wal.Group(), 5) 193 require.NoError(t, err) 194 195 // We should have data in the buffer now 196 assert.NotZero(t, wal.Group().Buffered()) 197 198 require.NoError(t, wal.Start()) 199 defer func() { 200 if err := wal.Stop(); err != nil { 201 t.Error(err) 202 } 203 wal.Wait() 204 }() 205 206 time.Sleep(walTestFlushInterval + (10 * time.Millisecond)) 207 208 // The data should have been flushed by the periodic sync 209 assert.Zero(t, wal.Group().Buffered()) 210 211 h := int64(4) 212 gr, found, err := wal.SearchForEndHeight(h, &WALSearchOptions{}) 213 assert.NoError(t, err, "expected not to err on height %d", h) 214 assert.True(t, found, "expected to find end height for %d", h) 215 assert.NotNil(t, gr) 216 if gr != nil { 217 gr.Close() 218 } 219 } 220 221 /* 222 var initOnce sync.Once 223 224 func registerInterfacesOnce() { 225 initOnce.Do(func() { 226 var _ = wire.RegisterInterface( 227 struct{ WALMessage }{}, 228 wire.ConcreteType{[]byte{}, 0x10}, 229 ) 230 }) 231 } 232 */ 233 234 func nBytes(n int) []byte { 235 buf := make([]byte, n) 236 n, _ = rand.Read(buf) 237 return buf[:n] 238 } 239 240 func benchmarkWalDecode(b *testing.B, n int) { 241 // registerInterfacesOnce() 242 243 buf := new(bytes.Buffer) 244 enc := NewWALEncoder(buf) 245 246 data := nBytes(n) 247 if err := enc.Encode(&TimedWALMessage{Msg: data, Time: time.Now().Round(time.Second).UTC()}); err != nil { 248 b.Error(err) 249 } 250 251 encoded := buf.Bytes() 252 253 b.ResetTimer() 254 for i := 0; i < b.N; i++ { 255 buf.Reset() 256 buf.Write(encoded) 257 dec := NewWALDecoder(buf) 258 if _, err := dec.Decode(); err != nil { 259 b.Fatal(err) 260 } 261 } 262 b.ReportAllocs() 263 } 264 265 func BenchmarkWalDecode512B(b *testing.B) { 266 benchmarkWalDecode(b, 512) 267 } 268 269 func BenchmarkWalDecode10KB(b *testing.B) { 270 benchmarkWalDecode(b, 10*1024) 271 } 272 func BenchmarkWalDecode100KB(b *testing.B) { 273 benchmarkWalDecode(b, 100*1024) 274 } 275 func BenchmarkWalDecode1MB(b *testing.B) { 276 benchmarkWalDecode(b, 1024*1024) 277 } 278 func BenchmarkWalDecode10MB(b *testing.B) { 279 benchmarkWalDecode(b, 10*1024*1024) 280 } 281 func BenchmarkWalDecode100MB(b *testing.B) { 282 benchmarkWalDecode(b, 100*1024*1024) 283 } 284 func BenchmarkWalDecode1GB(b *testing.B) { 285 benchmarkWalDecode(b, 1024*1024*1024) 286 }