diff --git a/lib/events/dynamoevents/dynamoevents.go b/lib/events/dynamoevents/dynamoevents.go index 701ea5536602f..f2490d6e0464a 100644 --- a/lib/events/dynamoevents/dynamoevents.go +++ b/lib/events/dynamoevents/dynamoevents.go @@ -642,6 +642,17 @@ func (l *Log) searchEventsRaw(ctx context.Context, fromUTC, toUTC time.Time, nam return nil, "", trace.Wrap(err) } + if checkpoint.Date != "" { + if t, err := time.Parse(time.DateOnly, checkpoint.Date); err == nil { + d := fromUTC.Unix() + // if fromUTC at 00:00:00 is bigger than the cursor, + // reset the cursor and advance to next day. + if time.Unix(d-d%(24*3600), 0).After(t) { + checkpoint = checkpointKey{} + } + } + } + totalSize := 0 dates := daysBetween(fromUTC, toUTC) if order == types.EventOrderDescending { @@ -662,9 +673,15 @@ func (l *Log) searchEventsRaw(ctx context.Context, fromUTC, toUTC time.Time, nam // We need to perform a guard check on the length of `dates` here in case a query is submitted with // `toUTC` occurring before `fromUTC`. if checkpoint.Date != "" && len(dates) > 0 { - for dates[0] != checkpoint.Date { + for len(dates) > 0 && dates[0] != checkpoint.Date { dates = dates[1:] } + // if the initial data wasn't found in [fromUTC,toUTC] + // dates will be empty and we can return early since we + // won't find any events. + if len(dates) == 0 { + return nil, "", nil + } } foundStart := checkpoint.EventKey == "" diff --git a/lib/events/dynamoevents/dynamoevents_test.go b/lib/events/dynamoevents/dynamoevents_test.go index 4d77a1f4a1b47..54004a0f148f1 100644 --- a/lib/events/dynamoevents/dynamoevents_test.go +++ b/lib/events/dynamoevents/dynamoevents_test.go @@ -18,6 +18,7 @@ package dynamoevents import ( "context" + "encoding/json" "fmt" "math/rand" "net/url" @@ -114,6 +115,32 @@ func TestSearchSessionEvensBySessionID(t *testing.T) { tt.suite.SearchSessionEventsBySessionID(t) } +// TestCheckpointOutsideOfWindow tests if [Log] doesn't panic +// if checkpoint date is outside of the window [fromUTC,toUTC]. +func TestCheckpointOutsideOfWindow(t *testing.T) { + tt := &Log{} + + key := checkpointKey{ + Date: "2022-10-02", + } + keyB, err := json.Marshal(key) + require.NoError(t, err) + + results, nextKey, err := tt.SearchEvents( + context.Background(), + events.SearchEventsRequest{ + From: time.Date(2021, 10, 10, 0, 0, 0, 0, time.UTC), + To: time.Date(2021, 11, 10, 0, 0, 0, 0, time.UTC), + Limit: 100, + StartKey: string(keyB), + Order: types.EventOrderAscending, + }, + ) + require.NoError(t, err) + require.Empty(t, results) + require.Empty(t, nextKey) +} + func TestSizeBreak(t *testing.T) { tt := setupDynamoContext(t)