github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/server/server_systemlog_gc_test.go (about) 1 // Copyright 2018 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package server 12 13 import ( 14 "context" 15 gosql "database/sql" 16 "fmt" 17 "testing" 18 "time" 19 20 "github.com/cockroachdb/cockroach/pkg/base" 21 "github.com/cockroachdb/cockroach/pkg/kv/kvserver" 22 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/kvserverpb" 23 "github.com/cockroachdb/cockroach/pkg/settings" 24 "github.com/cockroachdb/cockroach/pkg/testutils/serverutils" 25 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 26 "github.com/cockroachdb/cockroach/pkg/util/timeutil" 27 "github.com/stretchr/testify/assert" 28 ) 29 30 func TestLogGC(t *testing.T) { 31 defer leaktest.AfterTest(t)() 32 a := assert.New(t) 33 s, db, _ := serverutils.StartServer(t, base.TestServerArgs{}) 34 ts := s.(*TestServer) 35 ctx := context.Background() 36 defer s.Stopper().Stop(ctx) 37 const testRangeID = 10001 38 const table = "rangelog" 39 40 rangeLogRowCount := func() int { 41 var count int 42 err := db.QueryRowContext(ctx, 43 `SELECT count(*) FROM system.rangelog WHERE "rangeID" = $1`, 44 testRangeID, 45 ).Scan(&count) 46 if err != nil { 47 t.Fatal(err) 48 } 49 return count 50 } 51 52 logEvents := func(count int, timestamp time.Time) { 53 for i := 0; i < count; i++ { 54 _, err := db.Exec( 55 `INSERT INTO system.rangelog ( 56 timestamp, "rangeID", "storeID", "eventType" 57 ) VALUES ( 58 $1, $2, $3, $4 59 )`, 60 timestamp, 61 testRangeID, 62 1, // storeID 63 kvserverpb.RangeLogEventType_add.String(), 64 ) 65 a.NoError(err) 66 } 67 } 68 maxTS1 := timeutil.Now() 69 maxTS2 := maxTS1.Add(time.Second) 70 maxTS3 := maxTS2.Add(time.Second) 71 maxTS4 := maxTS3.Add(time.Second) 72 maxTS5 := maxTS4.Add(time.Hour) 73 maxTS6 := maxTS5.Add(time.Hour) 74 75 // Assert 0 rows before inserting any events. 76 a.Equal(0, rangeLogRowCount()) 77 // Insert 100 events with timestamp of up to maxTS1. 78 logEvents(100, maxTS1) 79 a.Equal(100, rangeLogRowCount()) 80 // Insert 1 event with timestamp of up to maxTS2. 81 logEvents(1, maxTS2) 82 // Insert 49 event with timestamp of up to maxTS3. 83 logEvents(49, maxTS3) 84 a.Equal(150, rangeLogRowCount()) 85 // Insert 25 events with timestamp of up to maxTS4. 86 logEvents(25, maxTS4) 87 a.Equal(175, rangeLogRowCount()) 88 89 // GC up to maxTS1. 90 tm, rowsGCd, err := ts.GCSystemLog(ctx, table, timeutil.Unix(0, 0), maxTS1) 91 a.NoError(err) 92 a.Equal(maxTS1, tm) 93 a.True(rowsGCd >= 100, "Expected rowsGCd >= 100, found %d", rowsGCd) 94 a.Equal(75, rangeLogRowCount()) 95 96 // GC exactly maxTS2. 97 tm, rowsGCd, err = ts.GCSystemLog(ctx, table, maxTS2, maxTS2) 98 a.NoError(err) 99 a.Equal(maxTS2, tm) 100 a.True(rowsGCd >= 1, "Expected rowsGCd >= 1, found %d", rowsGCd) 101 a.Equal(74, rangeLogRowCount()) 102 103 // GC upto maxTS2. 104 tm, rowsGCd, err = ts.GCSystemLog(ctx, table, maxTS1, maxTS3) 105 a.NoError(err) 106 a.Equal(maxTS3, tm) 107 a.True(rowsGCd >= 49, "Expected rowsGCd >= 49, found %d", rowsGCd) 108 a.Equal(25, rangeLogRowCount()) 109 // Insert 2000 more events. 110 logEvents(2000, maxTS5) 111 a.Equal(2025, rangeLogRowCount()) 112 113 // GC up to maxTS4. 114 tm, rowsGCd, err = ts.GCSystemLog(ctx, table, maxTS2, maxTS4) 115 a.NoError(err) 116 a.Equal(maxTS4, tm) 117 a.True(rowsGCd >= 25, "Expected rowsGCd >= 25, found %d", rowsGCd) 118 a.Equal(2000, rangeLogRowCount()) 119 120 // GC everything. 121 tm, rowsGCd, err = ts.GCSystemLog(ctx, table, maxTS4, maxTS5) 122 a.NoError(err) 123 a.Equal(maxTS5, tm) 124 a.True(rowsGCd >= 2000, "Expected rowsGCd >= 2000, found %d", rowsGCd) 125 a.Equal(0, rangeLogRowCount()) 126 127 // Ensure no errors when lowerBound > upperBound. 128 logEvents(5, maxTS6) 129 tm, rowsGCd, err = ts.GCSystemLog(ctx, table, maxTS6.Add(time.Hour), maxTS6) 130 a.NoError(err) 131 a.Equal(maxTS6, tm) 132 a.Equal(int64(0), rowsGCd) 133 a.Equal(5, rangeLogRowCount()) 134 } 135 136 func TestLogGCTrigger(t *testing.T) { 137 defer leaktest.AfterTest(t)() 138 systemLogRowCount := func(ctx context.Context, db *gosql.DB, table string, ts time.Time) int { 139 var count int 140 err := db.QueryRowContext(ctx, 141 fmt.Sprintf(`SELECT count(*) FROM system.%s WHERE timestamp <= $1`, table), 142 ts, 143 ).Scan(&count) 144 if err != nil { 145 t.Fatal(err) 146 } 147 return count 148 } 149 150 systemLogMaxTS := func(ctx context.Context, db *gosql.DB, table string) (time.Time, error) { 151 var ts time.Time 152 err := db.QueryRowContext(ctx, 153 fmt.Sprintf(`SELECT timestamp FROM system.%s ORDER by timestamp DESC LIMIT 1`, table), 154 ).Scan(&ts) 155 if err != nil { 156 return time.Time{}, err 157 } 158 return ts, nil 159 } 160 161 testCases := []struct { 162 table string 163 setting *settings.DurationSetting 164 }{ 165 { 166 table: "rangelog", 167 setting: rangeLogTTL, 168 }, 169 { 170 table: "eventlog", 171 setting: eventLogTTL, 172 }, 173 } 174 175 gcDone := make(chan struct{}) 176 177 params := base.TestServerArgs{ 178 Knobs: base.TestingKnobs{ 179 Store: &kvserver.StoreTestingKnobs{ 180 SystemLogsGCGCDone: gcDone, 181 SystemLogsGCPeriod: time.Nanosecond, 182 }, 183 }, 184 } 185 186 s, db, _ := serverutils.StartServer(t, params) 187 ctx := context.Background() 188 189 // Insert something in the rangelog table, otherwise it's empty for new 190 // clusters. 191 if _, err := db.Exec( 192 `INSERT INTO system.rangelog ( 193 timestamp, "rangeID", "storeID", "eventType" 194 ) VALUES ( 195 cast(now() - interval '10s' as timestamp), -- cast from timestamptz 196 100, 1, $1 197 )`, 198 kvserverpb.RangeLogEventType_add.String(), 199 ); err != nil { 200 t.Fatal(err) 201 } 202 203 defer s.Stopper().Stop(ctx) 204 205 for _, tc := range testCases { 206 t.Run(tc.table, func(t *testing.T) { 207 a := assert.New(t) 208 maxTS, err := systemLogMaxTS(ctx, db, tc.table) 209 if err != nil { 210 t.Fatal(err) 211 } 212 213 // Reading gcDone once ensures that the previous gc is done 214 // (it could have been done long back and is waiting to send on this channel), 215 // and the next gc has started. 216 // Reading it twice guarantees that the next gc has also completed. 217 // Before running the assertions below one gc run has to be guaranteed. 218 <-gcDone 219 <-gcDone 220 a.NotEqual( 221 systemLogRowCount(ctx, db, tc.table, maxTS), 222 0, 223 "Expected non zero number of events before %v as gc is not enabled", 224 maxTS, 225 ) 226 227 _, err = db.Exec(fmt.Sprintf("SET CLUSTER SETTING server.%s.ttl='1us'", tc.table)) 228 a.NoError(err) 229 230 <-gcDone 231 <-gcDone 232 a.Equal(0, systemLogRowCount(ctx, db, tc.table, maxTS), "Expected zero events before %v after gc", maxTS) 233 }) 234 } 235 }