From 0c9265f59b1bccdbb1bfeae373b5053e532ff0e3 Mon Sep 17 00:00:00 2001 From: Matias Chomicki Date: Mon, 22 Jan 2024 12:42:18 +0100 Subject: [PATCH] Infinite scroll: update deduplication method and only run log queries when scrolling (#80821) * Logs deduplication: replace array lookup with map * runLoadMoreLogs: only execute log queries * Formatting * Rename variable --- public/app/features/explore/state/query.ts | 21 +++++++++-------- public/app/features/logs/logsModel.ts | 5 ++-- public/app/features/logs/utils.test.ts | 27 +++++++++++++--------- public/app/features/logs/utils.ts | 17 +++++++------- 4 files changed, 40 insertions(+), 30 deletions(-) diff --git a/public/app/features/explore/state/query.ts b/public/app/features/explore/state/query.ts index 731e9e2a4b8..51749cbca8c 100644 --- a/public/app/features/explore/state/query.ts +++ b/public/app/features/explore/state/query.ts @@ -724,14 +724,17 @@ export const runLoadMoreLogsQueries = createAsyncThunk; - const logQueries = queryResponse.logsResult?.queries || []; - const queries = logQueries.map((query: DataQuery) => ({ - ...query, - datasource: query.datasource || datasourceInstance?.getRef(), - refId: `${infiniteScrollRefId}${query.refId}`, - })); + const queries = queryResponse.logsResult?.queries || []; + const logRefIds = queryResponse.logsFrames.map((frame) => frame.refId); + const logQueries = queries + .filter((query) => logRefIds.includes(query.refId)) + .map((query: DataQuery) => ({ + ...query, + datasource: query.datasource || datasourceInstance?.getRef(), + refId: `${infiniteScrollRefId}${query.refId}`, + })); - if (!hasNonEmptyQuery(queries) || !datasourceInstance) { + if (!hasNonEmptyQuery(logQueries) || !datasourceInstance) { return; } @@ -749,7 +752,7 @@ export const runLoadMoreLogsQueries = createAsyncThunk { describe('findMatchingRow', () => { function setup(frames: DataFrame[]) { - return logSeriesToLogsModel(frames); + const logsModel = logSeriesToLogsModel(frames); + const rows = logsModel?.rows || []; + const findMatchingRow = createLogRowsMap(); + for (const row of rows) { + expect(findMatchingRow(row)).toBeFalsy(); + } + return { rows, findMatchingRow }; } it('ignores rows from different queries', () => { const { logFrameA, logFrameB } = getMockFrames(); logFrameA.refId = 'A'; logFrameB.refId = 'B'; - const logsModel = setup([logFrameA, logFrameB]); - const rows = logsModel?.rows || []; + const { rows, findMatchingRow } = setup([logFrameA, logFrameB]); for (const row of rows) { const targetRow = { ...row, dataFrame: { ...logFrameA, refId: 'Z' } }; - expect(findMatchingRow(targetRow, rows)).toBe(undefined); + expect(findMatchingRow(targetRow)).toBeFalsy(); } }); it('matches rows by rowId', () => { const { logFrameA, logFrameB } = getMockFrames(); - const logsModel = setup([logFrameA, logFrameB]); - const rows = logsModel?.rows || []; + const { rows, findMatchingRow } = setup([logFrameA, logFrameB]); for (const row of rows) { const targetRow = { ...row, entry: `${Math.random()}`, timeEpochNs: `${Math.ceil(Math.random() * 1000000)}` }; - expect(findMatchingRow(targetRow, rows)).toBeDefined(); + expect(findMatchingRow(targetRow)).toBeTruthy(); } }); it('matches rows by entry and nanosecond time', () => { const { logFrameA, logFrameB } = getMockFrames(); - const logsModel = setup([logFrameA, logFrameB]); - const rows = logsModel?.rows || []; + logFrameA.fields[4].values = []; + logFrameB.fields[4].values = []; + const { rows, findMatchingRow } = setup([logFrameA, logFrameB]); for (const row of rows) { const targetRow = { ...row, rowId: undefined }; - expect(findMatchingRow(targetRow, rows)).toBeDefined(); + expect(findMatchingRow(targetRow)).toBeTruthy(); } }); }); diff --git a/public/app/features/logs/utils.ts b/public/app/features/logs/utils.ts index 0404ee68943..56b138920fa 100644 --- a/public/app/features/logs/utils.ts +++ b/public/app/features/logs/utils.ts @@ -298,13 +298,14 @@ export function targetIsElement(target: EventTarget | null): target is Element { return target instanceof Element; } -export function findMatchingRow(target: LogRowModel, rows: LogRowModel[]) { - return rows.find((row) => { - if (target.dataFrame.refId !== row.dataFrame.refId) { - return false; +export function createLogRowsMap() { + const logRowsSet = new Set(); + return function (target: LogRowModel): boolean { + let id = `${target.dataFrame.refId}_${target.rowId ? target.rowId : `${target.timeEpochNs}_${target.entry}`}`; + if (logRowsSet.has(id)) { + return true; } - const sameId = target.rowId && row.rowId && target.rowId === row.rowId; - const sameSignature = row.entry === target.entry && row.timeEpochNs === target.timeEpochNs; - return sameId || sameSignature; - }); + logRowsSet.add(id); + return false; + }; }