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  }