{"version":3,"file":"QueryCache.cjs","sources":["../../../src/querycache/QueryCache.ts"],"sourcesContent":["// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querycache/QueryCache.ts\nimport {\n  amendTable,\n  type DataFrame,\n  type DataQueryRequest,\n  dateTime,\n  durationToMilliseconds,\n  type Field,\n  incrRoundDn,\n  isValidDuration,\n  parseDuration,\n  rangeUtil,\n  type ScopedVars,\n  type Table,\n  trimTable,\n} from '@grafana/data';\n\nimport { type PromQuery } from '../types';\n\n// dashboardUID + panelId + refId\n// (must be stable across query changes, time range changes / interval changes / panel resizes / template variable changes)\ntype TargetIdent = string;\n\n// query + template variables + interval + raw time range\n// used for full target cache busting -> full range re-query\ntype TargetSignature = string;\ntype TimestampMs = number;\ntype SupportedQueryTypes = PromQuery;\ntype ApplyInterpolation = (str: string, scopedVars?: ScopedVars) => string;\n\n// string matching requirements defined in durationutil.ts\nexport const defaultPrometheusQueryOverlapWindow = '10m';\n\ninterface TargetCache {\n  signature: TargetSignature;\n  prevTo: TimestampMs;\n  frames: DataFrame[];\n}\n\nexport interface CacheRequestInfo<T extends SupportedQueryTypes> {\n  requests: Array<DataQueryRequest<T>>;\n  targetSignatures: Map<TargetIdent, TargetSignature>;\n  shouldCache: boolean;\n}\n\n/**\n * Get field identity\n * This is the string used to uniquely identify a field within a \"target\"\n * @param field\n */\nconst getFieldIdentity = (field: Field) => `${field.type}|${field.name}|${JSON.stringify(field.labels ?? '')}`;\n\n/**\n * NOMENCLATURE\n * Target: The request target (DataQueryRequest), i.e. a specific query reference within a panel\n * Identity: the string that is not expected to change\n * Signature: the string that is expected to change, upon which we wipe the cache fields\n */\nexport class QueryCache<T extends SupportedQueryTypes> {\n  private overlapWindowMs: number;\n  private getTargetSignature: (request: DataQueryRequest<T>, target: T) => string;\n  private applyInterpolation = (str: string, scopedVars?: ScopedVars) => str;\n\n  cache = new Map<TargetIdent, TargetCache>();\n\n  constructor(options: {\n    getTargetSignature: (request: DataQueryRequest<T>, target: T) => string;\n    overlapString: string;\n    applyInterpolation?: ApplyInterpolation;\n  }) {\n    const unverifiedOverlap = options.overlapString;\n    if (isValidDuration(unverifiedOverlap)) {\n      const duration = parseDuration(unverifiedOverlap);\n      this.overlapWindowMs = durationToMilliseconds(duration);\n    } else {\n      const duration = parseDuration(defaultPrometheusQueryOverlapWindow);\n      this.overlapWindowMs = durationToMilliseconds(duration);\n    }\n\n    this.getTargetSignature = options.getTargetSignature;\n    if (options.applyInterpolation) {\n      this.applyInterpolation = options.applyInterpolation;\n    }\n  }\n\n  // can be used to change full range request to partial, split into multiple requests\n  requestInfo(request: DataQueryRequest<T>): CacheRequestInfo<T> {\n    // TODO: align from/to to interval to increase probability of hitting backend cache\n\n    const newFrom = request.range.from.valueOf();\n    const newTo = request.range.to.valueOf();\n\n    // only cache 'now'-relative queries (that can benefit from a backfill cache)\n    const shouldCache = request.rangeRaw?.to?.toString() === 'now';\n\n    // all targets are queried together, so we check for any that causes group cache invalidation & full re-query\n    let doPartialQuery = shouldCache;\n    let prevTo: TimestampMs | undefined = undefined;\n\n    // pre-compute reqTargetSignatures\n    const reqTargetSignatures = new Map<TargetIdent, TargetSignature>();\n    request.targets.forEach((target) => {\n      let targetIdentity = `${request.dashboardUID}|${request.panelId}|${target.refId}`;\n      let targetSignature = this.getTargetSignature(request, target); // ${request.maxDataPoints} ?\n      reqTargetSignatures.set(targetIdentity, targetSignature);\n    });\n\n    // figure out if new query range or new target props trigger full cache invalidation & re-query\n    for (const [targetIdentity, targetSignature] of reqTargetSignatures) {\n      let cached = this.cache.get(targetIdentity);\n      let cachedSig = cached?.signature;\n\n      if (cachedSig !== targetSignature) {\n        doPartialQuery = false;\n      } else {\n        // only do partial queries when new request range follows prior request range (possibly with overlap)\n        // e.g. now-6h with refresh <= 6h\n        prevTo = cached?.prevTo ?? Infinity;\n\n        doPartialQuery = newTo > prevTo && newFrom <= prevTo;\n      }\n\n      if (!doPartialQuery) {\n        break;\n      }\n    }\n\n    if (doPartialQuery && prevTo) {\n      // clamp to make sure we don't re-query previous 10m when newFrom is ahead of it (e.g. 5min range, 30s refresh)\n      let newFromPartial = Math.max(prevTo - this.overlapWindowMs, newFrom);\n\n      const newToDate = dateTime(newTo);\n      const newFromPartialDate = dateTime(incrRoundDn(newFromPartial, request.intervalMs));\n\n      // modify to partial query\n      request = {\n        ...request,\n        range: {\n          ...request.range,\n          from: newFromPartialDate,\n          to: newToDate,\n        },\n      };\n    } else {\n      reqTargetSignatures.forEach((targSig, targIdent) => {\n        this.cache.delete(targIdent);\n      });\n    }\n\n    return {\n      requests: [request],\n      targetSignatures: reqTargetSignatures,\n      shouldCache,\n    };\n  }\n\n  // should amend existing cache with new frames and return full response\n  procFrames(\n    request: DataQueryRequest<T>,\n    requestInfo: CacheRequestInfo<T> | undefined,\n    respFrames: DataFrame[]\n  ): DataFrame[] {\n    if (requestInfo?.shouldCache) {\n      const newFrom = request.range.from.valueOf();\n      const newTo = request.range.to.valueOf();\n\n      // group frames by targets\n      const respByTarget = new Map<TargetIdent, DataFrame[]>();\n\n      respFrames.forEach((frame: DataFrame) => {\n        let targetIdent = `${request.dashboardUID}|${request.panelId}|${frame.refId}`;\n\n        let frames = respByTarget.get(targetIdent);\n\n        if (!frames) {\n          frames = [];\n          respByTarget.set(targetIdent, frames);\n        }\n\n        frames.push(frame);\n      });\n\n      let outFrames: DataFrame[] = [];\n\n      respByTarget.forEach((respFrames, targetIdentity) => {\n        let cachedFrames = (targetIdentity ? this.cache.get(targetIdentity)?.frames : null) ?? [];\n\n        respFrames.forEach((respFrame: DataFrame) => {\n          // skip empty frames\n          if (respFrame.length === 0 || respFrame.fields.length === 0) {\n            return;\n          }\n\n          // frames are identified by their second (non-time) field's name + labels\n          // TODO: maybe also frame.meta.type?\n          let respFrameIdentity = getFieldIdentity(respFrame.fields[1]);\n\n          let cachedFrame = cachedFrames.find((cached) => getFieldIdentity(cached.fields[1]) === respFrameIdentity);\n\n          if (!cachedFrame) {\n            // append new unknown frames\n            cachedFrames.push(respFrame);\n          } else {\n            // we assume that fields cannot appear/disappear and will all exist in same order\n\n            // amend & re-cache\n            // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n            let prevTable: Table = cachedFrame.fields.map((field) => field.values) as Table;\n            // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n            let nextTable: Table = respFrame.fields.map((field) => field.values) as Table;\n\n            let amendedTable = amendTable(prevTable, nextTable);\n            if (amendedTable) {\n              for (let i = 0; i < amendedTable.length; i++) {\n                cachedFrame.fields[i].values = amendedTable[i];\n                if (cachedFrame.fields[i].config.displayNameFromDS !== respFrame.fields[i].config.displayNameFromDS) {\n                  cachedFrame.fields[i].config.displayNameFromDS = respFrame.fields[i].config.displayNameFromDS;\n                }\n              }\n              cachedFrame.length = cachedFrame.fields[0].values.length;\n            }\n          }\n        });\n\n        // trim all frames to in-view range, evict those that end up with 0 length\n        let nonEmptyCachedFrames: DataFrame[] = [];\n\n        cachedFrames.forEach((frame) => {\n          // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n          let table: Table = frame.fields.map((field) => field.values) as Table;\n\n          const dataPointStep = findDatapointStep(request, respFrames, this.applyInterpolation);\n\n          // query interval is greater than request.intervalMs, use query interval to make sure we've always got one datapoint outside the panel viewport\n          let trimmed = trimTable(table, newFrom - dataPointStep, newTo);\n\n          if (trimmed[0].length > 0) {\n            for (let i = 0; i < trimmed.length; i++) {\n              frame.fields[i].values = trimmed[i];\n            }\n            nonEmptyCachedFrames.push(frame);\n          }\n        });\n\n        this.cache.set(targetIdentity, {\n          signature: requestInfo.targetSignatures.get(targetIdentity)!,\n          frames: nonEmptyCachedFrames,\n          prevTo: newTo,\n        });\n\n        outFrames.push(...nonEmptyCachedFrames);\n      });\n\n      // transformV2 mutates field values for heatmap de-accum, and modifies field order, so we gotta clone here, for now :(\n      respFrames = outFrames.map((frame) => ({\n        ...frame,\n        fields: frame.fields.map((field) => ({\n          ...field,\n          config: {\n            ...field.config, // prevents mutatative exemplars links (re)enrichment\n          },\n          values: field.values.slice(),\n        })),\n      }));\n    }\n\n    return respFrames;\n  }\n}\n\nexport function findDatapointStep(\n  request: DataQueryRequest<PromQuery>,\n  respFrames: DataFrame[],\n  applyInterpolation: ApplyInterpolation\n): number {\n  // Prometheus specific logic below\n  if (request.targets[0].datasource?.type !== 'prometheus') {\n    return 0;\n  }\n\n  const target = request.targets.find((t) => t.refId === respFrames[0].refId);\n\n  let dataPointStep = request.intervalMs;\n  if (target?.interval) {\n    const minStepMs =\n      respFrames[0].meta?.custom?.['calculatedMinStep'] ??\n      rangeUtil.intervalToMs(applyInterpolation(target.interval, request.scopedVars));\n    if (minStepMs > request.intervalMs) {\n      dataPointStep = minStepMs;\n    }\n  }\n  return dataPointStep;\n}\n"],"names":["isValidDuration","parseDuration","durationToMilliseconds","dateTime","incrRoundDn","respFrames","amendTable","trimTable","rangeUtil"],"mappings":"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"}