Use memoize one to cache transformation output

pull/4563/head
Iris Scholten 2018-10-08 09:55:12 -07:00
parent 5e9e859a3a
commit fb1b460322
8 changed files with 157 additions and 57 deletions

View File

@ -56,9 +56,9 @@ const filterTables = (tables: FluxTable[]): FluxTable[] => {
})
}
const filteredTablesMemoized = memoizeOne(filterTables)
class TimeMachineTables extends PureComponent<Props, State> {
private filteredTablesMemoized = memoizeOne(filterTables)
constructor(props) {
super(props)
@ -183,9 +183,12 @@ class TimeMachineTables extends PureComponent<Props, State> {
}
private get selectedResult(): FluxTable {
const filteredTables = filteredTablesMemoized(this.props.data)
const filteredTables = this.filteredTablesMemoized(this.props.data)
const table = filteredTables.find(
d => d.name === this.state.selectedResultID
)
return filteredTables.find(d => d.name === this.state.selectedResultID)
return table
}
}

View File

@ -1,6 +1,7 @@
// Libraries
import React, {PureComponent} from 'react'
import _ from 'lodash'
import memoizeOne from 'memoize-one'
// Components
import Gauge from 'src/shared/components/Gauge'
@ -8,7 +9,12 @@ import InvalidData from 'src/shared/components/InvalidData'
// Utils
import {manager} from 'src/worker/JobManager'
import {getDataUUID, hasDataChanged} from 'src/shared/graphs/helpers'
import {
getDataUUID,
hasDataPropsChanged,
isFluxDataEqual,
isInluxQLDataEqual,
} from 'src/shared/graphs/helpers'
import getLastValues from 'src/shared/parsing/lastValues'
import {ErrorHandling} from 'src/shared/decorators/errors'
@ -52,6 +58,14 @@ class GaugeChart extends PureComponent<Props, State> {
private isComponentMounted: boolean
private lastUUID: string
private memoizedTimeSeriesToSingleStat = memoizeOne(
getLastValues,
isInluxQLDataEqual
)
private memoizedFluxTablesToSingleStat = memoizeOne(
manager.fluxTablesToSingleStat,
isFluxDataEqual
)
constructor(props: Props) {
super(props)
@ -67,7 +81,7 @@ class GaugeChart extends PureComponent<Props, State> {
}
public async componentDidUpdate(prevProps: Props) {
const isDataChanged = hasDataChanged(prevProps, this.props)
const isDataChanged = hasDataPropsChanged(prevProps, this.props)
this.lastUUID = getDataUUID(this.props.data, this.props.dataType)
@ -139,9 +153,13 @@ class GaugeChart extends PureComponent<Props, State> {
let isValidData = true
try {
if (dataType === DataType.flux) {
lastValues = await manager.fluxTablesToSingleStat(data as FluxTable[])
lastValues = await this.memoizedFluxTablesToSingleStat(
data as FluxTable[]
)
} else if (dataType === DataType.influxQL) {
lastValues = getLastValues(data as TimeSeriesServerResponse[])
lastValues = this.memoizedTimeSeriesToSingleStat(
data as TimeSeriesServerResponse[]
)
}
if (

View File

@ -3,6 +3,7 @@ import React, {PureComponent, CSSProperties} from 'react'
import _ from 'lodash'
import Dygraph from 'src/shared/components/Dygraph'
import {withRouter, RouteComponentProps} from 'react-router'
import memoizeOne from 'memoize-one'
// Components
import SingleStat from 'src/shared/components/SingleStat'
@ -16,7 +17,12 @@ import {
} from 'src/utils/timeSeriesTransformers'
import {manager} from 'src/worker/JobManager'
import {fluxTablesToDygraph} from 'src/shared/parsing/flux/dygraph'
import {getDataUUID, hasDataChanged} from 'src/shared/graphs/helpers'
import {
getDataUUID,
hasDataPropsChanged,
isFluxDataEqual,
isInluxQLDataEqual,
} from 'src/shared/graphs/helpers'
// Types
import {ColorString} from 'src/types/colors'
@ -66,6 +72,15 @@ class LineGraph extends PureComponent<LineGraphProps, State> {
private isComponentMounted: boolean = false
private isValidData: boolean = true
private memoizedTimeSeriesToDygraph = memoizeOne(
timeSeriesToDygraph,
isInluxQLDataEqual
)
private memoizedFluxTablesToDygraph = memoizeOne(
fluxTablesToDygraph,
isFluxDataEqual
)
constructor(props: LineGraphProps) {
super(props)
@ -108,7 +123,7 @@ class LineGraph extends PureComponent<LineGraphProps, State> {
}
public componentDidUpdate(prevProps: LineGraphProps) {
const isDataChanged = hasDataChanged(prevProps, this.props)
const isDataChanged = hasDataPropsChanged(prevProps, this.props)
if (this.props.loading === RemoteDataState.Done && isDataChanged) {
this.parseTimeSeries(this.props.data, this.props.dataType)
@ -245,14 +260,14 @@ class LineGraph extends PureComponent<LineGraphProps, State> {
let result: TimeSeriesToDyGraphReturnType
if (dataType === DataType.influxQL) {
result = await timeSeriesToDygraph(
result = await this.memoizedTimeSeriesToDygraph(
data as TimeSeriesServerResponse[],
location.pathname
)
}
if (dataType === DataType.flux) {
result = await fluxTablesToDygraph(data as FluxTable[])
result = await this.memoizedFluxTablesToDygraph(data as FluxTable[])
}
return {result, uuid: getDataUUID(data, dataType)}

View File

@ -2,6 +2,7 @@
import React, {PureComponent, CSSProperties} from 'react'
import classnames from 'classnames'
import _ from 'lodash'
import memoizeOne from 'memoize-one'
// Components
import InvalidData from 'src/shared/components/InvalidData'
@ -11,7 +12,9 @@ import {manager} from 'src/worker/JobManager'
import {
SMALL_CELL_HEIGHT,
getDataUUID,
hasDataChanged,
hasDataPropsChanged,
isFluxDataEqual,
isInluxQLDataEqual,
} from 'src/shared/graphs/helpers'
import getLastValues from 'src/shared/parsing/lastValues'
import {ErrorHandling} from 'src/shared/decorators/errors'
@ -60,6 +63,14 @@ class SingleStat extends PureComponent<Props, State> {
private isComponentMounted: boolean
private lastUUID: string
private memoizedTimeSeriesToSingleStat = memoizeOne(
getLastValues,
isInluxQLDataEqual
)
private memoizedFluxTablesToSingleStat = memoizeOne(
manager.fluxTablesToSingleStat,
isFluxDataEqual
)
constructor(props: Props) {
super(props)
@ -76,7 +87,7 @@ class SingleStat extends PureComponent<Props, State> {
public async componentDidUpdate(prevProps: Props) {
this.lastUUID = getDataUUID(this.props.data, this.props.dataType)
const isDataChanged = hasDataChanged(prevProps, this.props)
const isDataChanged = hasDataPropsChanged(prevProps, this.props)
if (isDataChanged) {
await this.dataToLastValues()
@ -246,9 +257,13 @@ class SingleStat extends PureComponent<Props, State> {
let isValidData = true
try {
if (dataType === DataType.flux) {
lastValues = await manager.fluxTablesToSingleStat(data as FluxTable[])
lastValues = await this.memoizedFluxTablesToSingleStat(
data as FluxTable[]
)
} else if (dataType === DataType.influxQL) {
lastValues = getLastValues(data as TimeSeriesServerResponse[])
lastValues = this.memoizedTimeSeriesToSingleStat(
data as TimeSeriesServerResponse[]
)
}
if (

View File

@ -1,6 +1,7 @@
// Libraries
import React, {PureComponent} from 'react'
import _ from 'lodash'
import memoizeOne from 'memoize-one'
// Utils
import {manager} from 'src/worker/JobManager'
@ -64,8 +65,39 @@ interface State {
invalidDataError: ErrorTypes
}
interface FormatProperties {
sort?: Sort
fieldOptions: FieldOption[]
tableOptions: TableOptions
timeFormat: string
decimalPlaces: DecimalPlaces
uuid: string
}
const areFormatPropertiesEqual = (
prevProperties: FormatProperties,
newProperties: FormatProperties
) => {
const formatProps = [
'uuid',
'tableOptions',
'fieldOptions',
'timeFormat',
'sort',
]
const areEqual = formatProps.every(k =>
_.isEqual(prevProperties[k], newProperties[k])
)
return areEqual
}
class TableGraphFormat extends PureComponent<Props, State> {
private isComponentMounted: boolean
private memoizedTableTransform = memoizeOne(
manager.tableTransform,
areFormatPropertiesEqual
)
constructor(props: Props) {
super(props)
@ -116,16 +148,7 @@ class TableGraphFormat extends PureComponent<Props, State> {
}
public componentDidUpdate(prevProps: Props) {
const updatedProps = _.keys(_.omit(prevProps, 'data')).filter(
k => !_.isEqual(this.props[k], prevProps[k])
)
if (
this.props.uuid !== prevProps.uuid ||
_.includes(updatedProps, 'tableOptions') ||
_.includes(updatedProps, 'fieldOptions') ||
_.includes(updatedProps, 'timeFormat')
) {
if (!areFormatPropertiesEqual(prevProps, this.props)) {
this.formatData()
}
}
@ -140,7 +163,7 @@ class TableGraphFormat extends PureComponent<Props, State> {
decimalPlaces,
} = this.props
const {sort} = this.state
const sort = {...this.state.sort}
if (sortField === sort.field) {
sort.direction = sort.direction === ASCENDING ? DESCENDING : ASCENDING
@ -159,14 +182,15 @@ class TableGraphFormat extends PureComponent<Props, State> {
)
try {
const formattedData = await manager.tableTransform(
this.props.data.data,
const formattedData = await this.memoizedTableTransform({
data: this.props.data.data,
sort,
computedFieldOptions,
fieldOptions: computedFieldOptions,
tableOptions,
timeFormat,
decimalPlaces
)
decimalPlaces,
uuid: latestUUID,
})
if (!this.isComponentMounted) {
return
@ -184,6 +208,7 @@ class TableGraphFormat extends PureComponent<Props, State> {
if (!this.isComponentMounted) {
return
}
console.error(err)
this.setState({invalidDataError: ErrorTypes.GeneralError})
}

View File

@ -2,6 +2,7 @@
import React, {PureComponent} from 'react'
import _ from 'lodash'
import uuid from 'uuid'
import memoizeOne from 'memoize-one'
// Components
import InvalidData from 'src/shared/components/InvalidData'
@ -12,6 +13,7 @@ import {
ErrorTypes,
getInvalidDataMessage,
} from 'src/dashboards/utils/tableGraph'
import {isInluxQLDataEqual} from 'src/shared/graphs/helpers'
// Types
import {
@ -40,6 +42,10 @@ interface State {
class TableGraphTransform extends PureComponent<Props, State> {
private isComponentMounted: boolean
private memoizedTimeSeriesToTableGraph = memoizeOne(
timeSeriesToTableGraph,
isInluxQLDataEqual
)
constructor(props: Props) {
super(props)
@ -83,7 +89,7 @@ class TableGraphTransform extends PureComponent<Props, State> {
if (dataType === DataType.influxQL) {
try {
const influxQLData = await timeSeriesToTableGraph(
const influxQLData = await this.memoizedTimeSeriesToTableGraph(
data as TimeSeriesServerResponse[]
)

View File

@ -187,27 +187,47 @@ export const getDataUUID = (
dataType: DataType
): string => {
if (dataType === DataType.influxQL) {
return getDeep(data, '0.response.uuid', '')
return getInfluxQLDataUUID(data as TimeSeriesServerResponse[])
} else {
return getDeep(data, '0.id', '')
return getFluxDataUUID(data as FluxTable[])
}
}
const getInfluxQLDataUUID = (data: TimeSeriesServerResponse[]): string => {
return getDeep(data, '0.response.uuid', '')
}
const getFluxDataUUID = (data: FluxTable[]): string => {
return getDeep(data, '0.id', '')
}
export const isFluxDataEqual = (
prevData: FluxTable[],
newData: FluxTable[]
): boolean => {
return getFluxDataUUID(prevData) === getFluxDataUUID(newData)
}
export const isInluxQLDataEqual = (
prevData: TimeSeriesServerResponse[],
newData: TimeSeriesServerResponse[]
): boolean => {
return getInfluxQLDataUUID(prevData) === getInfluxQLDataUUID(newData)
}
interface DataProps {
data: TimeSeriesServerResponse[] | FluxTable[]
dataType: DataType
timeRange?: TimeRange
}
export const hasDataChanged = (
export const hasDataPropsChanged = (
prevProps: DataProps,
newProps: DataProps
): boolean => {
const isDataTypeChanged = prevProps.dataType !== newProps.dataType
const isDataIDsChanged = !_.isEqual(
getDataUUID(prevProps.data, prevProps.dataType),
const isDataIDsChanged =
getDataUUID(prevProps.data, prevProps.dataType) !==
getDataUUID(newProps.data, newProps.dataType)
)
const isTimeRangeChanged = !_.isEqual(
_.get(prevProps, 'timeRange'),
_.get(newProps, 'timeRange')

View File

@ -7,6 +7,13 @@ import {
TimeSeriesToTableGraphReturnType,
} from 'src/types/series'
import {DygraphValue, FluxTable} from 'src/types'
import {
Sort,
FieldOption,
TableOptions,
DecimalPlaces,
TimeSeriesValue,
} from 'src/types/dashboards'
import {getBasepath} from 'src/utils/basepath'
import {TimeSeriesToDyGraphReturnType} from 'src/worker/jobs/timeSeriesToDygraph'
import {FluxTablesToDygraphResult} from 'src/worker/jobs/fluxTablesToDygraph'
@ -36,23 +43,14 @@ class JobManager {
})
}
public async tableTransform(
data,
sort,
fieldOptions,
tableOptions,
timeFormat,
decimalPlaces
): Promise<any> {
const payload = {
data,
sort,
fieldOptions,
tableOptions,
timeFormat,
decimalPlaces,
}
public tableTransform = async (payload: {
data: TimeSeriesValue[][]
sort: Sort
fieldOptions: FieldOption[]
tableOptions: TableOptions
timeFormat: string
decimalPlaces: DecimalPlaces
}): Promise<any> => {
return this.publishDBJob('TABLETRANSFORM', payload)
}