Skip to content

Commit

Permalink
Catalog cache and Session update for async queries (#1500)
Browse files Browse the repository at this point in the history
* init commit for cache

Signed-off-by: Shenoy Pratik <sgguruda@amazon.com>

* cache loader init

Signed-off-by: Shenoy Pratik <sgguruda@amazon.com>

* update cache with accelerations cache, add custom hooks

Signed-off-by: Shenoy Pratik <sgguruda@amazon.com>

* add session coupling and fix tests for cache

Signed-off-by: Shenoy Pratik <sgguruda@amazon.com>

* added polling result type, updated version constant

Signed-off-by: Shenoy Pratik <sgguruda@amazon.com>

---------

Signed-off-by: Shenoy Pratik <sgguruda@amazon.com>
(cherry picked from commit 943126f)
Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
github-actions[bot] committed Mar 8, 2024
1 parent 2e5dd64 commit 0477389
Show file tree
Hide file tree
Showing 15 changed files with 1,365 additions and 68 deletions.
2 changes: 2 additions & 0 deletions common/constants/data_sources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,5 @@ export enum DATA_SOURCE_TYPES {
S3Glue = 's3glue',
}
export const ASYNC_POLLING_INTERVAL = 2000;

export const CATALOG_CACHE_VERSION = '1.0';
3 changes: 3 additions & 0 deletions common/constants/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,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 @@ -254,6 +255,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
81 changes: 81 additions & 0 deletions common/types/data_connections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,84 @@ export interface AssociatedObject {
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;
}

export interface PollingSuccessResult {
schema: Array<{ name: string; type: string }>;
datarows: Array<Array<string | number | boolean>>;
}

export type AsyncPollingResult = PollingSuccessResult | null;
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 @@ -6,3 +6,30 @@
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: Array<Array<string | number | boolean>>
): object[] {
const combinedData: object[] = [];

datarows.forEach((row) => {
const rowData: { [key: string]: string | number | boolean } = {};
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,20 +28,20 @@ import { DirectQueryLoadingStatus, DirectQueryRequest } from '../../../../common
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;
Expand Down Expand Up @@ -209,7 +209,7 @@ export const DirectSearch = (props: any) => {
})
);
});
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 @@ export const DirectSearch = (props: any) => {
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
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

0 comments on commit 0477389

Please sign in to comment.