Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Catalog cache and Session update for async queries #1500

Merged
merged 5 commits into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions common/constants/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const SAVED_OBJECTS = '/saved_objects';
export const SAVED_QUERY = '/query';
export const SAVED_VISUALIZATION = '/vis';
export const CONSOLE_PROXY = '/api/console/proxy';
export const SECURITY_PLUGIN_ACCOUNT_API = '/api/v1/configuration/account';

// Server route
export const PPL_ENDPOINT = '/_plugins/_ppl';
Expand Down Expand Up @@ -256,6 +257,8 @@ export const VISUALIZATION_ERROR = {
export const S3_DATASOURCE_TYPE = 'S3_DATASOURCE';

export const ASYNC_QUERY_SESSION_ID = 'async-query-session-id';
export const ASYNC_QUERY_DATASOURCE_CACHE = 'async-query-catalog-cache';
export const ASYNC_QUERY_ACCELERATIONS_CACHE = 'async-query-acclerations-cache';

export const DIRECT_DUMMY_QUERY = 'select 1';

Expand Down
74 changes: 74 additions & 0 deletions common/types/data_connections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,77 @@
export type Role = EuiComboBoxOptionOption;

export type DatasourceType = 'S3GLUE' | 'PROMETHEUS';

interface AsyncApiDataResponse {
status: string;
schema?: Array<{ name: string; type: string }>;
datarows?: any;

Check warning on line 32 in common/types/data_connections.ts

View workflow job for this annotation

GitHub Actions / Lint

Unexpected any. Specify a different type
total?: number;
size?: number;
error?: string;
}

export interface AsyncApiResponse {
data: {
ok: boolean;
resp: AsyncApiDataResponse;
};
}

export type PollingCallback = (statusObj: AsyncApiResponse) => void;

export type AccelerationIndexType = 'skipping' | 'covering' | 'materialized';

export type LoadCacheType = 'databases' | 'tables' | 'accelerations';

export enum CachedDataSourceStatus {
Updated = 'Updated',
Failed = 'Failed',
Empty = 'Empty',
}

export interface CachedColumn {
name: string;
dataType: string;
}

export interface CachedTable {
name: string;
columns: CachedColumn[];
}

export interface CachedDatabase {
name: string;
tables: CachedTable[];
lastUpdated: string; // Assuming date string in UTC format
status: CachedDataSourceStatus;
}

export interface CachedDataSource {
name: string;
lastUpdated: string; // Assuming date string in UTC format
status: CachedDataSourceStatus;
databases: CachedDatabase[];
}

export interface DataSourceCacheData {
version: string;
dataSources: CachedDataSource[];
}

export interface CachedAccelerations {
flintIndexName: string;
type: AccelerationIndexType;
database: string;
table: string;
indexName: string;
autoRefresh: boolean;
status: string;
}

export interface AccelerationsCacheData {
version: string;
accelerations: CachedAccelerations[];
lastUpdated: string; // Assuming date string in UTC format
status: CachedDataSourceStatus;
}
8 changes: 4 additions & 4 deletions common/utils/query_session_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

import { ASYNC_QUERY_SESSION_ID } from '../constants/shared';

export const setAsyncSessionId = (value: string | null) => {
export const setAsyncSessionId = (dataSource: string, value: string | null) => {
if (value !== null) {
sessionStorage.setItem(ASYNC_QUERY_SESSION_ID, value);
sessionStorage.setItem(`${ASYNC_QUERY_SESSION_ID}_${dataSource}`, value);

Check warning on line 10 in common/utils/query_session_utils.ts

View check run for this annotation

Codecov / codecov/patch

common/utils/query_session_utils.ts#L10

Added line #L10 was not covered by tests
}
};

export const getAsyncSessionId = () => {
return sessionStorage.getItem(ASYNC_QUERY_SESSION_ID);
export const getAsyncSessionId = (dataSource: string) => {
return sessionStorage.getItem(`${ASYNC_QUERY_SESSION_ID}_${dataSource}`);

Check warning on line 15 in common/utils/query_session_utils.ts

View check run for this annotation

Codecov / codecov/patch

common/utils/query_session_utils.ts#L15

Added line #L15 was not covered by tests
};
27 changes: 27 additions & 0 deletions common/utils/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,33 @@
* SPDX-License-Identifier: Apache-2.0
*/

export function get<T = unknown>(obj: Record<string, any>, path: string, defaultValue?: T): T {

Check warning on line 6 in common/utils/shared.ts

View workflow job for this annotation

GitHub Actions / Lint

Unexpected any. Specify a different type
return path.split('.').reduce((acc: any, part: string) => acc && acc[part], obj) || defaultValue;

Check warning on line 7 in common/utils/shared.ts

View workflow job for this annotation

GitHub Actions / Lint

Unexpected any. Specify a different type
}

export function addBackticksIfNeeded(input: string): string {

Check warning on line 10 in common/utils/shared.ts

View check run for this annotation

Codecov / codecov/patch

common/utils/shared.ts#L10

Added line #L10 was not covered by tests
// Check if the string already has backticks
if (input.startsWith('`') && input.endsWith('`')) {
return input; // Return the string as it is
} else {

Check warning on line 14 in common/utils/shared.ts

View check run for this annotation

Codecov / codecov/patch

common/utils/shared.ts#L13-L14

Added lines #L13 - L14 were not covered by tests
// Add backticks to the string
return '`' + input + '`';

Check warning on line 16 in common/utils/shared.ts

View check run for this annotation

Codecov / codecov/patch

common/utils/shared.ts#L16

Added line #L16 was not covered by tests
}
}

export function combineSchemaAndDatarows(
schema: Array<{ name: string; type: string }>,
datarows: string[][]
): object[] {
const combinedData: object[] = [];

datarows.forEach((row) => {
const rowData: { [key: string]: string } = {};
schema.forEach((field, index) => {
rowData[field.name] = row[index];
});
combinedData.push(rowData);
});

return combinedData;
}
17 changes: 10 additions & 7 deletions public/components/common/search/direct_search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,26 @@
import { uiSettingsService } from '../../../../common/utils';
import { getAsyncSessionId, setAsyncSessionId } from '../../../../common/utils/query_session_utils';
import { get as getObjValue } from '../../../../common/utils/shared';
import { useFetchEvents } from '../../event_analytics/hooks';
import { changeQuery } from '../../event_analytics/redux/slices/query_slice';
import { usePolling } from '../../hooks/use_polling';
import { coreRefs } from '../../../framework/core_refs';
import { SQLService } from '../../../services/requests/sql';
import { SavePanel } from '../../event_analytics/explorer/save_panel';
import { useFetchEvents } from '../../event_analytics/hooks';
import { reset as resetResults } from '../../event_analytics/redux/slices/query_result_slice';
import { changeQuery } from '../../event_analytics/redux/slices/query_slice';
import {
selectSearchMetaData,
update as updateSearchMetaData,
} from '../../event_analytics/redux/slices/search_meta_data_slice';
import { reset as resetResults } from '../../event_analytics/redux/slices/query_result_slice';
import { formatError } from '../../event_analytics/utils';
import { usePolling } from '../../hooks/use_polling';
import { PPLReferenceFlyout } from '../helpers';
import { Autocomplete } from './autocomplete';
import { formatError } from '../../event_analytics/utils';
export interface IQueryBarProps {
query: string;
tempQuery: string;
handleQueryChange: (query: string) => void;
handleQuerySearch: () => void;
dslService: any;

Check warning on line 50 in public/components/common/search/direct_search.tsx

View workflow job for this annotation

GitHub Actions / Lint

Unexpected any. Specify a different type
}

export interface IDatePickerProps {
Expand All @@ -57,11 +57,11 @@
setEndTime: () => void;
setTimeRange: () => void;
setIsOutputStale: () => void;
handleTimePickerChange: (timeRange: string[]) => any;

Check warning on line 60 in public/components/common/search/direct_search.tsx

View workflow job for this annotation

GitHub Actions / Lint

Unexpected any. Specify a different type
handleTimeRangePickerRefresh: () => any;

Check warning on line 61 in public/components/common/search/direct_search.tsx

View workflow job for this annotation

GitHub Actions / Lint

Unexpected any. Specify a different type
}

export const DirectSearch = (props: any) => {

Check warning on line 64 in public/components/common/search/direct_search.tsx

View workflow job for this annotation

GitHub Actions / Lint

Unexpected any. Specify a different type
const {
query,
tempQuery,
Expand Down Expand Up @@ -102,7 +102,7 @@
error: pollingError,
startPolling,
stopPolling,
} = usePolling<any, any>((params) => {

Check warning on line 105 in public/components/common/search/direct_search.tsx

View workflow job for this annotation

GitHub Actions / Lint

Unexpected any. Specify a different type

Check warning on line 105 in public/components/common/search/direct_search.tsx

View workflow job for this annotation

GitHub Actions / Lint

Unexpected any. Specify a different type
return sqlService.fetchWithJobId(params);
}, ASYNC_POLLING_INTERVAL);

Expand Down Expand Up @@ -209,7 +209,7 @@
})
);
});
const sessionId = getAsyncSessionId();
const sessionId = getAsyncSessionId(explorerSearchMetadata.datasources[0].label);

Check warning on line 212 in public/components/common/search/direct_search.tsx

View check run for this annotation

Codecov / codecov/patch

public/components/common/search/direct_search.tsx#L212

Added line #L212 was not covered by tests
const requestPayload = {
lang: lang.toLowerCase(),
query: tempQuery || query,
Expand All @@ -223,7 +223,10 @@
sqlService
.fetch(requestPayload)
.then((result) => {
setAsyncSessionId(getObjValue(result, 'sessionId', null));
setAsyncSessionId(

Check warning on line 226 in public/components/common/search/direct_search.tsx

View check run for this annotation

Codecov / codecov/patch

public/components/common/search/direct_search.tsx#L226

Added line #L226 was not covered by tests
explorerSearchMetadata.datasources[0].label,
getObjValue(result, 'sessionId', null)
);
if (result.queryId) {
dispatch(updateSearchMetaData({ tabId, data: { queryId: result.queryId } }));
startPolling({
Expand Down Expand Up @@ -276,7 +279,7 @@
})
);
}
}, [pollingResult, pollingError]);

Check warning on line 282 in public/components/common/search/direct_search.tsx

View workflow job for this annotation

GitHub Actions / Lint

React Hook useEffect has missing dependencies: 'dispatch', 'dispatchOnGettingHis', 'stopPollingWithStatus', and 'tabId'. Either include them or remove the dependency array

useEffect(() => {
return () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,52 +3,52 @@
* SPDX-License-Identifier: Apache-2.0
*/

import React, { useCallback, useContext, useEffect, useState, useMemo } from 'react';
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { batch, useDispatch, useSelector } from 'react-redux';
import { LogExplorerRouterContext } from '../..';
import {
DataSourceGroup,
DataSourceSelectable,
DataSourceType,
} from '../../../../../../../src/plugins/data/public';
import { coreRefs } from '../../../../framework/core_refs';
import {
selectSearchMetaData,
update as updateSearchMetaData,
} from '../../../event_analytics/redux/slices/search_meta_data_slice';
import { reset as resetCountDistribution } from '../../redux/slices/count_distribution_slice';
import { reset as resetFields } from '../../redux/slices/field_slice';
import { reset as resetPatterns } from '../../redux/slices/patterns_slice';
import { reset as resetQueryResults } from '../../redux/slices/query_result_slice';
import { changeData, reset as resetQuery } from '../../redux/slices/query_slice';
import { reset as resetVisualization } from '../../redux/slices/visualization_slice';
import { reset as resetVisConfig } from '../../redux/slices/viualization_config_slice';
import { DirectQueryRequest, SelectedDataSource } from '../../../../../common/types/explorer';
import { ObservabilityDefaultDataSource } from '../../../../framework/datasources/obs_opensearch_datasource';
import {
DATA_SOURCE_TYPE_URL_PARAM_KEY,
DATA_SOURCE_NAME_URL_PARAM_KEY,
DATA_SOURCE_TYPES,
DATA_SOURCE_TYPE_URL_PARAM_KEY,
DEFAULT_DATA_SOURCE_NAME,
DEFAULT_DATA_SOURCE_OBSERVABILITY_DISPLAY_NAME,
DEFAULT_DATA_SOURCE_TYPE,
DEFAULT_DATA_SOURCE_TYPE_NAME,
DEFAULT_DATA_SOURCE_OBSERVABILITY_DISPLAY_NAME,
DATA_SOURCE_TYPES,
QUERY_LANGUAGE,
OLLY_QUESTION_URL_PARAM_KEY,
INDEX_URL_PARAM_KEY,
OLLY_QUESTION_URL_PARAM_KEY,
QUERY_LANGUAGE,
} from '../../../../../common/constants/data_sources';
import { SQLService } from '../../../../services/requests/sql';
import { get as getObjValue } from '../../../../../common/utils/shared';
import {
setAsyncSessionId,
getAsyncSessionId,
} from '../../../../../common/utils/query_session_utils';
import { DIRECT_DUMMY_QUERY } from '../../../../../common/constants/shared';
import {
INDEX,
OLLY_QUERY_ASSISTANT,
SELECTED_TIMESTAMP,
} from '../../../../../common/constants/explorer';
import { DIRECT_DUMMY_QUERY } from '../../../../../common/constants/shared';
import { DirectQueryRequest, SelectedDataSource } from '../../../../../common/types/explorer';
import {
getAsyncSessionId,
setAsyncSessionId,
} from '../../../../../common/utils/query_session_utils';
import { get as getObjValue } from '../../../../../common/utils/shared';
import { coreRefs } from '../../../../framework/core_refs';
import { ObservabilityDefaultDataSource } from '../../../../framework/datasources/obs_opensearch_datasource';
import { SQLService } from '../../../../services/requests/sql';
import {
selectSearchMetaData,
update as updateSearchMetaData,
} from '../../../event_analytics/redux/slices/search_meta_data_slice';
import { reset as resetCountDistribution } from '../../redux/slices/count_distribution_slice';
import { reset as resetFields } from '../../redux/slices/field_slice';
import { reset as resetPatterns } from '../../redux/slices/patterns_slice';
import { reset as resetQueryResults } from '../../redux/slices/query_result_slice';
import { changeData, reset as resetQuery } from '../../redux/slices/query_slice';
import { reset as resetVisualization } from '../../redux/slices/visualization_slice';
import { reset as resetVisConfig } from '../../redux/slices/viualization_config_slice';

const DATA_SOURCE_SELECTOR_CONFIGS = { customGroupTitleExtension: '' };

Expand Down Expand Up @@ -141,7 +141,7 @@ export const DataSourceSelection = ({ tabId }: { tabId: string }) => {
sqlService
.fetch(requestPayload)
.then((result) => {
setAsyncSessionId(getObjValue(result, 'sessionId', null));
setAsyncSessionId(dataSource, getObjValue(result, 'sessionId', null));
})
.catch((e) => {
console.error(e);
Expand Down Expand Up @@ -226,7 +226,7 @@ export const DataSourceSelection = ({ tabId }: { tabId: string }) => {
const dsType = explorerSearchMetadata.datasources?.[0]?.type;
const dsName = explorerSearchMetadata.datasources?.[0]?.label;
if (
!getAsyncSessionId() &&
!getAsyncSessionId(dsName) &&
[DATA_SOURCE_TYPES.SPARK, DATA_SOURCE_TYPES.S3Glue].includes(dsType) &&
dsName
) {
Expand Down
24 changes: 24 additions & 0 deletions public/framework/catalog_cache/cache_intercept.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import {
HttpInterceptorResponseError,
IHttpInterceptController,
} from '../../../../../src/core/public';
import { SECURITY_PLUGIN_ACCOUNT_API } from '../../../common/constants/shared';
import { CatalogCacheManager } from './cache_manager';

export function catalogCacheInterceptError(): any {
return (httpErrorResponse: HttpInterceptorResponseError, _: IHttpInterceptController) => {

Check warning on line 14 in public/framework/catalog_cache/cache_intercept.ts

View check run for this annotation

Codecov / codecov/patch

public/framework/catalog_cache/cache_intercept.ts#L13-L14

Added lines #L13 - L14 were not covered by tests
if (
httpErrorResponse.response?.status === 401 &&
httpErrorResponse.fetchOptions.path === SECURITY_PLUGIN_ACCOUNT_API

Check warning on line 17 in public/framework/catalog_cache/cache_intercept.ts

View check run for this annotation

Codecov / codecov/patch

public/framework/catalog_cache/cache_intercept.ts#L17

Added line #L17 was not covered by tests
) {
// Clears all user catalog cache details
CatalogCacheManager.clearDataSourceCache();
CatalogCacheManager.clearAccelerationsCache();

Check warning on line 21 in public/framework/catalog_cache/cache_intercept.ts

View check run for this annotation

Codecov / codecov/patch

public/framework/catalog_cache/cache_intercept.ts#L20-L21

Added lines #L20 - L21 were not covered by tests
}
};
}
Loading
Loading