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

feat(cache-cell-results): added cell result caching to reduce cell configuration querying on loads #18581

Merged
merged 18 commits into from
Jun 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
eaa62a4
feat(data-reducer): setting file data once a dashboard query is resol…
asalem1 Jun 17, 2020
2d4c896
feat(view_action): reorganized the actions, combined the reducers and…
asalem1 Jun 17, 2020
0c1116e
feat(conditionally-query-cell): Added cache clearing when the compone…
asalem1 Jun 17, 2020
0d40fbd
chore(CHANGELOG): updated changelog
asalem1 Jun 17, 2020
c93801e
chore(lint): removed async to resolve lint issues
asalem1 Jun 17, 2020
b6c0887
chore(PR-suggestions): made suggested PR changes by
asalem1 Jun 18, 2020
120dd94
chore(comment): removed unnecessary comment
asalem1 Jun 18, 2020
3965a0c
fix(hashcode-placement): fixed where the queryID is being generated b…
asalem1 Jun 18, 2020
4370a04
fix(multiple_queries): handling the case where multiple queries resul…
asalem1 Jun 18, 2020
9a4c885
feat(data-reducer): setting file data once a dashboard query is resol…
asalem1 Jun 17, 2020
c1e7bce
feat(view_action): reorganized the actions, combined the reducers and…
asalem1 Jun 17, 2020
69bfb40
feat(conditionally-query-cell): Added cache clearing when the compone…
asalem1 Jun 17, 2020
5d6d1cd
chore(CHANGELOG): updated changelog
asalem1 Jun 17, 2020
fc2db5b
chore(PR-suggestions): made suggested PR changes by
asalem1 Jun 18, 2020
6e5a19e
fix(pr): merging suggested PR change
asalem1 Jun 22, 2020
014ec9e
chore(rename-func): renamed func for greater accuracy and updated fun…
asalem1 Jun 22, 2020
a7e46d8
fix(branch-weirdness): fixed weirdness on the branch
asalem1 Jun 22, 2020
655d5de
chore(lint): fixed linter error
asalem1 Jun 22, 2020
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
1. [18623](https://github.com/influxdata/influxdb/pull/18623): Drop support for --local flag within influx CLI
1. [18632](https://github.com/influxdata/influxdb/pull/18632): Prevents undefined queries in cells from erroring out in dashboards
1. [18658](https://github.com/influxdata/influxdb/pull/18658): Add support for 'd' day time identifier in the CLI for bucket and setup commands
1. [18581](https://github.com/influxdata/influxdb/pull/18581): Cache dashboard cell query results to use as a reference for cell configurations

## v2.0.0-beta.12 [2020-06-12]

Expand Down
21 changes: 17 additions & 4 deletions ui/src/dashboards/components/DashboardPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,18 @@ import RateLimitAlert from 'src/cloud/components/RateLimitAlert'
// Utils
import {pageTitleSuffixer} from 'src/shared/utils/pageTitles'

// Selectors
// Selectors & Actions
import {resetCachedQueryResults} from 'src/queryCache/actions'
import {getByID} from 'src/resources/selectors'

// Types
import {AppState, AutoRefresh, ResourceType, Dashboard} from 'src/types'
import {ManualRefreshProps} from 'src/shared/components/ManualRefresh'

interface DispatchProps {
resetCachedQueryResults: typeof resetCachedQueryResults
}

interface StateProps {
dashboard: Dashboard
}
Expand All @@ -31,10 +36,14 @@ interface OwnProps {
autoRefresh: AutoRefresh
}

type Props = OwnProps & StateProps & ManualRefreshProps
type Props = OwnProps & StateProps & ManualRefreshProps & DispatchProps

@ErrorHandling
class DashboardPage extends Component<Props> {
public componentWillUnmount() {
this.props.resetCachedQueryResults()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 thinking about cache invalidation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't take any credit for it, it was all @ebb-tide 's idea

}

public render() {
const {autoRefresh, manualRefresh, onManualRefresh, children} = this.props

Expand Down Expand Up @@ -76,7 +85,11 @@ const mstp = (state: AppState): StateProps => {
}
}

export default connect<StateProps, {}>(
const mdtp = {
resetCachedQueryResults: resetCachedQueryResults,
}

export default connect<StateProps, DispatchProps>(
mstp,
null
mdtp
)(ManualRefresh<OwnProps>(DashboardPage))
13 changes: 6 additions & 7 deletions ui/src/dashboards/components/EditVEO.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import VEOHeader from 'src/dashboards/components/VEOHeader'
// Actions
import {setName} from 'src/timeMachine/actions'
import {saveVEOView} from 'src/dashboards/actions/thunks'
import {getViewForTimeMachine} from 'src/views/actions/thunks'
import {getViewAndResultsForVEO} from 'src/views/actions/thunks'

// Utils
import {getActiveTimeMachine} from 'src/timeMachine/selectors'
Expand All @@ -21,21 +21,21 @@ import {getActiveTimeMachine} from 'src/timeMachine/selectors'
import {AppState, RemoteDataState, QueryView, TimeMachineID} from 'src/types'

interface DispatchProps {
getViewAndResultsForVEO: typeof getViewAndResultsForVEO
onSetName: typeof setName
onSaveView: typeof saveVEOView
getViewForTimeMachine: typeof getViewForTimeMachine
}

interface StateProps {
view: QueryView | null
activeTimeMachineID: TimeMachineID
view: QueryView | null
}

type Props = DispatchProps & StateProps & WithRouterProps

const EditViewVEO: FunctionComponent<Props> = ({
getViewForTimeMachine,
activeTimeMachineID,
getViewAndResultsForVEO,
onSaveView,
onSetName,
params: {orgID, cellID, dashboardID},
Expand All @@ -46,7 +46,7 @@ const EditViewVEO: FunctionComponent<Props> = ({
// TODO split this up into "loadView" "setActiveTimeMachine"
// and something to tell the component to pull from the context
// of the dashboardID
getViewForTimeMachine(dashboardID, cellID, 'veo')
getViewAndResultsForVEO(dashboardID, cellID, 'veo')
}, [])

const handleClose = () => {
Expand Down Expand Up @@ -92,16 +92,15 @@ const EditViewVEO: FunctionComponent<Props> = ({

const mstp = (state: AppState): StateProps => {
const {activeTimeMachineID} = state.timeMachines

const {view} = getActiveTimeMachine(state)

return {view, activeTimeMachineID}
}

const mdtp: DispatchProps = {
getViewAndResultsForVEO: getViewAndResultsForVEO,
onSetName: setName,
onSaveView: saveVEOView,
getViewForTimeMachine: getViewForTimeMachine,
}

export default connect<StateProps, DispatchProps, {}>(
Expand Down
33 changes: 33 additions & 0 deletions ui/src/queryCache/actions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
export type Action =
| ReturnType<typeof resetCachedQueryResults>
| ReturnType<typeof setQueryResultsByQueryID>

// Hashing function found here:
// https://jsperf.com/hashcodelordvlad
// Through this thread:
// https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript
export const hashCode = (queryText: string): string => {
let hash = 0,
char
if (!queryText) {
return `${hash}`
}
for (let i = 0; i < queryText.length; i++) {
char = queryText.charCodeAt(i)
hash = (hash << 5) - hash + char
hash |= 0 // Convert to 32bit integer
}
return `${hash}`
}

export const setQueryResultsByQueryID = (queryID: string, files: string[]) =>
({
type: 'SET_QUERY_RESULTS_BY_QUERY',
queryID,
files,
} as const)

export const resetCachedQueryResults = () =>
({
type: 'RESET_CACHED_QUERY_RESULTS',
} as const)
33 changes: 33 additions & 0 deletions ui/src/queryCache/reducers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Libraries
import {produce} from 'immer'

// Actions
import {Action} from 'src/queryCache/actions'

export interface QueryCacheState {
queryResultsByQueryID: {[queryID: string]: string[]}
}

export const initialState: QueryCacheState = {
queryResultsByQueryID: {},
}

export const queryCacheReducer = (
state: QueryCacheState = initialState,
action: Action
): QueryCacheState => {
switch (action.type) {
case 'SET_QUERY_RESULTS_BY_QUERY': {
return produce(state, draftState => {
const {queryID, files} = action
draftState.queryResultsByQueryID[queryID] = files
})
}

case 'RESET_CACHED_QUERY_RESULTS': {
return {queryResultsByQueryID: {}}
}
}

return state
}
17 changes: 16 additions & 1 deletion ui/src/shared/components/TimeSeries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
isDemoDataAvailabilityError,
demoDataError,
} from 'src/cloud/utils/demoDataErrors'
import {hashCode} from 'src/queryCache/actions'

// Constants
import {
Expand All @@ -43,6 +44,7 @@ import {TIME_RANGE_START, TIME_RANGE_STOP} from 'src/variables/constants'

// Actions
import {notify as notifyAction} from 'src/shared/actions/notifications'
import {setQueryResultsByQueryID} from 'src/queryCache/actions'

// Types
import {
Expand Down Expand Up @@ -87,6 +89,7 @@ interface OwnProps {

interface DispatchProps {
notify: typeof notifyAction
onSetQueryResultsByQueryID: typeof setQueryResultsByQueryID
}

type Props = StateProps & OwnProps & DispatchProps
Expand Down Expand Up @@ -181,7 +184,13 @@ class TimeSeries extends Component<Props & WithRouterProps, State> {
}

private reload = async () => {
const {variables, notify, check, buckets} = this.props
const {
buckets,
check,
notify,
onSetQueryResultsByQueryID,
variables,
} = this.props
const queries = this.props.queries.filter(({text}) => !!text.trim())

if (!queries.length) {
Expand Down Expand Up @@ -270,6 +279,11 @@ class TimeSeries extends Component<Props & WithRouterProps, State> {
}

this.pendingReload = false
const queryText = queries.map(({text}) => text).join('')
const queryID = hashCode(queryText)
if (queryID && files.length) {
onSetQueryResultsByQueryID(queryID, files)
}

this.setState({
giraffeResult,
Expand Down Expand Up @@ -346,6 +360,7 @@ const mstp = (state: AppState, props: OwnProps): StateProps => {

const mdtp: DispatchProps = {
notify: notifyAction,
onSetQueryResultsByQueryID: setQueryResultsByQueryID,
}

export default connect<StateProps, {}, OwnProps>(
Expand Down
2 changes: 2 additions & 0 deletions ui/src/store/configureStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import alertBuilderReducer from 'src/alerting/reducers/alertBuilder'

// Types
import {AppState, LocalStorage} from 'src/types'
import {queryCacheReducer} from 'src/queryCache/reducers'

type ReducerState = Pick<AppState, Exclude<keyof AppState, 'timeRange'>>

Expand All @@ -81,6 +82,7 @@ export const rootReducer = combineReducers<ReducerState>({
overlays: overlaysReducer,
plugins: pluginsResourceReducer,
predicates: predicatesReducer,
queryCache: queryCacheReducer,
ranges: rangesReducer,
resources: combineReducers({
buckets: bucketsReducer,
Expand Down
9 changes: 5 additions & 4 deletions ui/src/timeMachine/actions/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ interface SetQueryResults {
}
}

const setQueryResults = (
export const setQueryResults = (
status: RemoteDataState,
files?: string[],
fetchDuration?: number,
Expand Down Expand Up @@ -125,9 +125,6 @@ export const executeQueries = (abortController?: AbortController) => async (
const queries = activeTimeMachine.view.properties.queries.filter(
({text}) => !!text.trim()
)
const {
alertBuilder: {id: checkID},
} = state

if (!queries.length) {
dispatch(setQueryResults(RemoteDataState.Done, [], null))
Expand Down Expand Up @@ -177,6 +174,10 @@ export const executeQueries = (abortController?: AbortController) => async (
)

let statuses = [[]] as StatusRow[][]
const {
alertBuilder: {id: checkID},
} = state

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this down so it would be place a little closer to the source of where checkID is being used

if (checkID) {
const extern = buildVarsOption(variableAssignments)
pendingCheckStatuses = runStatusesQuery(getOrg(state).id, checkID, extern)
Expand Down
16 changes: 10 additions & 6 deletions ui/src/types/stores.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import {Links} from 'src/types/links'
import {Notification} from 'src/types'
import {TimeRange} from 'src/types/queries'
import {TimeMachinesState} from 'src/timeMachine/reducers'
import {AppState as AppPresentationState} from 'src/shared/reducers/app'
import {RouterState} from 'react-router-redux'
Expand All @@ -10,7 +7,14 @@ import {CurrentDashboardState} from 'src/shared/reducers/currentDashboard'
import {NoteEditorState} from 'src/dashboards/reducers/notes'
import {DataLoadingState} from 'src/dataLoaders/reducers'
import {OnboardingState} from 'src/onboarding/reducers'
import {PredicatesState, VariableEditorState} from 'src/types'
import {
Links,
Notification,
PredicatesState,
ResourceState,
TimeRange,
VariableEditorState,
} from 'src/types'
import {
TelegrafEditorPluginState,
PluginResourceState,
Expand All @@ -26,8 +30,7 @@ import {AlertBuilderState} from 'src/alerting/reducers/alertBuilder'
import {CurrentPage} from 'src/shared/reducers/currentPage'
import {DemoDataState} from 'src/cloud/reducers/demodata'
import {OrgSettingsState} from 'src/cloud/reducers/orgsettings'

import {ResourceState} from 'src/types'
import {QueryCacheState} from 'src/queryCache/reducers'

export interface AppState {
alertBuilder: AlertBuilderState
Expand All @@ -40,6 +43,7 @@ export interface AppState {
}
currentPage: CurrentPage
currentDashboard: CurrentDashboardState
queryCache: QueryCacheState
dataLoading: DataLoadingState
links: Links
me: MeState
Expand Down
22 changes: 20 additions & 2 deletions ui/src/views/actions/thunks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Libraries
import {normalize} from 'normalizr'

import {get} from 'lodash'
// APIs
import {
getView as getViewAJAX,
Expand All @@ -16,6 +16,8 @@ import {notify} from 'src/shared/actions/notifications'
import {setActiveTimeMachine} from 'src/timeMachine/actions'
import {executeQueries} from 'src/timeMachine/actions/queries'
import {setView, Action} from 'src/views/actions/creators'
import {hashCode} from 'src/queryCache/actions'
import {setQueryResults} from 'src/timeMachine/actions/queries'

// Selectors
import {getViewsForDashboard} from 'src/views/selectors'
Expand Down Expand Up @@ -96,7 +98,7 @@ export const updateViewAndVariables = (
}
}

export const getViewForTimeMachine = (
export const getViewAndResultsForVEO = (
dashboardID: string,
cellID: string,
timeMachineID: TimeMachineID
Expand All @@ -116,8 +118,24 @@ export const getViewForTimeMachine = (
view,
})
)
const queries = view.properties.queries.filter(({text}) => !!text.trim())
if (!queries.length) {
dispatch(setQueryResults(RemoteDataState.Done, [], null))
}
const queryText = queries.map(({text}) => text).join('')
const queryID = hashCode(queryText)
const files = get(
state,
['queryCache', 'queryResultsByQueryID', queryID],
undefined
)
if (files) {
dispatch(setQueryResults(RemoteDataState.Done, files, null, null))
return
}
dispatch(executeQueries())
} catch (error) {
console.error(error)
dispatch(notify(copy.getViewFailed(error.message)))
dispatch(setView(cellID, RemoteDataState.Error))
}
Expand Down