github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/log_recycler_test.go (about) 1 // Copyright 2019 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package pebble 6 7 import ( 8 "testing" 9 10 "github.com/petermattis/pebble/vfs" 11 "github.com/stretchr/testify/require" 12 ) 13 14 func (r *logRecycler) logNums() []uint64 { 15 r.mu.Lock() 16 defer r.mu.Unlock() 17 return append([]uint64(nil), r.mu.logNums...) 18 } 19 20 func (r *logRecycler) maxLogNum() uint64 { 21 r.mu.Lock() 22 defer r.mu.Unlock() 23 return r.mu.maxLogNum 24 } 25 26 func TestLogRecycler(t *testing.T) { 27 r := logRecycler{limit: 3} 28 29 // Logs are recycled up to the limit. 30 require.True(t, r.add(1)) 31 require.EqualValues(t, []uint64{1}, r.logNums()) 32 require.EqualValues(t, 1, r.maxLogNum()) 33 require.EqualValues(t, 1, r.peek()) 34 require.True(t, r.add(2)) 35 require.EqualValues(t, []uint64{1, 2}, r.logNums()) 36 require.EqualValues(t, 2, r.maxLogNum()) 37 require.True(t, r.add(3)) 38 require.EqualValues(t, []uint64{1, 2, 3}, r.logNums()) 39 require.EqualValues(t, 3, r.maxLogNum()) 40 41 // Trying to add a file past the limit fails. 42 require.False(t, r.add(4)) 43 require.EqualValues(t, []uint64{1, 2, 3}, r.logNums()) 44 require.EqualValues(t, 4, r.maxLogNum()) 45 46 // Trying to add a previously recycled file returns success, but the internal 47 // state is unchanged. 48 require.True(t, r.add(1)) 49 require.EqualValues(t, []uint64{1, 2, 3}, r.logNums()) 50 require.EqualValues(t, 4, r.maxLogNum()) 51 52 // An error is returned if we try to pop an element other than the first. 53 require.Regexp(t, `invalid 2 vs \[1 2 3\]`, r.pop(2)) 54 55 require.NoError(t, r.pop(1)) 56 require.EqualValues(t, []uint64{2, 3}, r.logNums()) 57 58 // Log number 4 was already considered, so it won't be recycled. 59 require.True(t, r.add(4)) 60 require.EqualValues(t, []uint64{2, 3}, r.logNums()) 61 62 require.True(t, r.add(5)) 63 require.EqualValues(t, []uint64{2, 3, 5}, r.logNums()) 64 require.EqualValues(t, 5, r.maxLogNum()) 65 66 require.NoError(t, r.pop(2)) 67 require.EqualValues(t, []uint64{3, 5}, r.logNums()) 68 require.NoError(t, r.pop(3)) 69 require.EqualValues(t, []uint64{5}, r.logNums()) 70 require.NoError(t, r.pop(5)) 71 require.EqualValues(t, []uint64(nil), r.logNums()) 72 73 require.Regexp(t, `empty`, r.pop(6)) 74 } 75 76 func TestRecycleLogs(t *testing.T) { 77 mem := vfs.NewMem() 78 d, err := Open("", &Options{ 79 FS: mem, 80 }) 81 if err != nil { 82 t.Fatal(err) 83 } 84 85 logNum := func() uint64 { 86 d.mu.Lock() 87 defer d.mu.Unlock() 88 return d.mu.log.queue[len(d.mu.log.queue)-1] 89 } 90 logCount := func() int { 91 d.mu.Lock() 92 defer d.mu.Unlock() 93 return len(d.mu.log.queue) 94 } 95 96 // Flush the memtable a few times, forcing rotation of the WAL. We should see 97 // the recycled logs change as expected. 98 require.EqualValues(t, []uint64(nil), d.logRecycler.logNums()) 99 curLog := logNum() 100 101 if err := d.Flush(); err != nil { 102 t.Fatal(err) 103 } 104 105 require.EqualValues(t, []uint64{curLog}, d.logRecycler.logNums()) 106 curLog = logNum() 107 108 if err := d.Flush(); err != nil { 109 t.Fatal(err) 110 } 111 112 require.EqualValues(t, []uint64{curLog}, d.logRecycler.logNums()) 113 114 if err := d.Close(); err != nil { 115 t.Fatal(err) 116 } 117 118 d, err = Open("", &Options{ 119 FS: mem, 120 }) 121 if err != nil { 122 t.Fatal(err) 123 } 124 metrics := d.Metrics() 125 if n := logCount(); n != int(metrics.WAL.Files) { 126 t.Fatalf("expected %d WAL files, but found %d", n, metrics.WAL.Files) 127 } 128 if n := d.logRecycler.count(); n != int(metrics.WAL.ObsoleteFiles) { 129 t.Fatalf("expected %d obsolete WAL files, but found %d", n, metrics.WAL.ObsoleteFiles) 130 } 131 if err := d.Close(); err != nil { 132 t.Fatal(err) 133 } 134 }