Introduce average resampler support

Fixes #526

Entire-Checkpoint: 893a1de325b5
This commit is contained in:
2026-03-19 21:16:48 +01:00
parent 10b4fa5a06
commit c0d2d65f96
17 changed files with 239 additions and 73 deletions

View File

@@ -51,14 +51,15 @@ type APIMetricData struct {
//
// The request can be customized with flags to include/exclude statistics, raw data, and padding.
type APIQueryRequest struct {
Cluster string `json:"cluster"`
Queries []APIQuery `json:"queries"`
ForAllNodes []string `json:"for-all-nodes"`
From int64 `json:"from"`
To int64 `json:"to"`
WithStats bool `json:"with-stats"`
WithData bool `json:"with-data"`
WithPadding bool `json:"with-padding"`
Cluster string `json:"cluster"`
Queries []APIQuery `json:"queries"`
ForAllNodes []string `json:"for-all-nodes"`
From int64 `json:"from"`
To int64 `json:"to"`
WithStats bool `json:"with-stats"`
WithData bool `json:"with-data"`
WithPadding bool `json:"with-padding"`
ResampleAlgo string `json:"resample-algo,omitempty"`
}
// APIQueryResponse represents the response to an APIQueryRequest.
@@ -279,7 +280,7 @@ func FetchData(req APIQueryRequest) (*APIQueryResponse, error) {
for _, sel := range sels {
data := APIMetricData{}
data.Data, data.From, data.To, data.Resolution, err = ms.Read(sel, query.Metric, req.From, req.To, query.Resolution)
data.Data, data.From, data.To, data.Resolution, err = ms.Read(sel, query.Metric, req.From, req.To, query.Resolution, req.ResampleAlgo)
if err != nil {
// Skip Error If Just Missing Host or Metric, Continue
// Empty Return For Metric Handled Gracefully By Frontend

View File

@@ -679,7 +679,7 @@ func (m *MemoryStore) WriteToLevel(l *Level, selector []string, ts int64, metric
// If the level does not hold the metric itself, the data will be aggregated recursively from the children.
// The second and third return value are the actual from/to for the data. Those can be different from
// the range asked for if no data was available.
func (m *MemoryStore) Read(selector util.Selector, metric string, from, to, resolution int64) ([]schema.Float, int64, int64, int64, error) {
func (m *MemoryStore) Read(selector util.Selector, metric string, from, to, resolution int64, resampleAlgo string) ([]schema.Float, int64, int64, int64, error) {
if from > to {
return nil, 0, 0, 0, errors.New("[METRICSTORE]> invalid time range")
}
@@ -737,7 +737,11 @@ func (m *MemoryStore) Read(selector util.Selector, metric string, from, to, reso
}
}
data, resolution, err = resampler.LargestTriangleThreeBucket(data, minfo.Frequency, resolution)
resampleFn, rfErr := resampler.GetResampler(resampleAlgo)
if rfErr != nil {
return nil, 0, 0, 0, rfErr
}
data, resolution, err = resampleFn(data, minfo.Frequency, resolution)
if err != nil {
return nil, 0, 0, 0, err
}

View File

@@ -621,6 +621,7 @@ func (ccms *InternalMetricStore) LoadNodeListData(
resolution int,
from, to time.Time,
ctx context.Context,
resampleAlgo string,
) (map[string]schema.JobData, error) {
// Note: Order of node data is not guaranteed after this point
queries, assignedScope, err := buildNodeQueries(cluster, subCluster, nodes, metrics, scopes, int64(resolution))
@@ -636,12 +637,13 @@ func (ccms *InternalMetricStore) LoadNodeListData(
}
req := APIQueryRequest{
Cluster: cluster,
Queries: queries,
From: from.Unix(),
To: to.Unix(),
WithStats: true,
WithData: true,
Cluster: cluster,
Queries: queries,
From: from.Unix(),
To: to.Unix(),
WithStats: true,
WithData: true,
ResampleAlgo: resampleAlgo,
}
resBody, err := FetchData(req)