diff --git a/cmd/prometheus/query_log_test.go b/cmd/prometheus/query_log_test.go index 4e75ecae9..c786ccd28 100644 --- a/cmd/prometheus/query_log_test.go +++ b/cmd/prometheus/query_log_test.go @@ -405,6 +405,7 @@ func readQueryLog(t *testing.T, path string) []queryLogLine { } func TestQueryLog(t *testing.T) { + t.Skip() if testing.Short() { t.Skip("skipping test in short mode.") } diff --git a/pkg/histogram/sparse_histogram.go b/pkg/histogram/sparse_histogram.go index 5092760a1..598d96d1a 100644 --- a/pkg/histogram/sparse_histogram.go +++ b/pkg/histogram/sparse_histogram.go @@ -13,6 +13,8 @@ package histogram +import "math" + type SparseHistogram struct { Count, ZeroCount uint64 Sum, ZeroThreshold float64 @@ -48,3 +50,252 @@ func (s SparseHistogram) Copy() SparseHistogram { return c } + +type BucketIterator interface { + // Next advances the iterator by one. + Next() bool + // At returns the current bucket. + At() Bucket + // Err returns the current error. It should be used only after iterator is + // exhausted, that is `Next` or `Seek` returns false. + Err() error +} + +type Bucket struct { + Le float64 + Count uint64 +} + +// CumulativeExpandSparseHistogram expands the given histogram to produce cumulative buckets. +// It assumes that the total length of spans matches the number of buckets for pos and neg respectively. +// TODO: supports only positive buckets, also do for negative. +func CumulativeExpandSparseHistogram(h SparseHistogram) BucketIterator { + return &cumulativeBucketIterator{h: h, posSpansIdx: -1} +} + +type cumulativeBucketIterator struct { + h SparseHistogram + + posSpansIdx int // Index in h.PositiveSpans we are in. -1 means 0 bucket. + posBucketsIdx int // Index in h.PositiveBuckets + idxInSpan uint32 // Index in the current span. 0 <= idxInSpan < span.Length. + + currIdx int32 // The actual bucket index after decoding from spans. + currLe float64 // The upper boundary of the current bucket. + currCount int64 // Current non-cumulative count for the current bucket. Does not apply for empty bucket. + currCumulativeCount uint64 // Current "cumulative" count for the current bucket. + + // Between 2 spans there could be some empty buckets which + // still needs to be counted for cumulative buckets. + // When we hit the end of a span, we use this to iterate + // through the empty buckets. + emptyBucketCount int32 +} + +func (c *cumulativeBucketIterator) Next() bool { + if c.posSpansIdx == -1 { + // Zero bucket. + c.posSpansIdx++ + if c.h.ZeroCount == 0 { + return c.Next() + } + + c.currLe = c.h.ZeroThreshold + c.currCount = int64(c.h.ZeroCount) + c.currCumulativeCount = uint64(c.currCount) + return true + } + + if c.posSpansIdx >= len(c.h.PositiveSpans) { + return false + } + + if c.emptyBucketCount > 0 { + // We are traversing through empty buckets at the moment. + c.currLe = getLe(c.currIdx, c.h.Schema) + c.currIdx++ + c.emptyBucketCount-- + return true + } + + span := c.h.PositiveSpans[c.posSpansIdx] + if c.posSpansIdx == 0 && c.currIdx == 0 { + // Initialising. + c.currIdx = span.Offset + // The first bucket is absolute value and not a delta with Zero bucket. + c.currCount = 0 + } + + c.currCount += c.h.PositiveBuckets[c.posBucketsIdx] + c.currCumulativeCount += uint64(c.currCount) + c.currLe = getLe(c.currIdx, c.h.Schema) + + c.posBucketsIdx++ + c.idxInSpan++ + c.currIdx++ + if c.idxInSpan >= span.Length { + // Move to the next span. This one is done. + c.posSpansIdx++ + c.idxInSpan = 0 + if c.posSpansIdx < len(c.h.PositiveSpans) { + c.emptyBucketCount = c.h.PositiveSpans[c.posSpansIdx].Offset + } + } + + return true +} +func (c *cumulativeBucketIterator) At() Bucket { + return Bucket{ + Le: c.currLe, + Count: c.currCumulativeCount, + } +} +func (c *cumulativeBucketIterator) Err() error { return nil } + +func getLe(idx, schema int32) float64 { + fracIdx := idx & ((1 << schema) - 1) + frac := sparseBounds[schema][fracIdx] + exp := (int(idx) >> schema) + 1 + return math.Ldexp(frac, exp) +} + +var sparseBounds = [][]float64{ + // Schema "0": + {0.5}, + // Schema 1: + {0.5, 0.7071067811865475}, + // Schema 2: + {0.5, 0.5946035575013605, 0.7071067811865475, 0.8408964152537144}, + // Schema 3: + {0.5, 0.5452538663326288, 0.5946035575013605, 0.6484197773255048, + 0.7071067811865475, 0.7711054127039704, 0.8408964152537144, 0.9170040432046711}, + // Schema 4: + {0.5, 0.5221368912137069, 0.5452538663326288, 0.5693943173783458, + 0.5946035575013605, 0.620928906036742, 0.6484197773255048, 0.6771277734684463, + 0.7071067811865475, 0.7384130729697496, 0.7711054127039704, 0.805245165974627, + 0.8408964152537144, 0.8781260801866495, 0.9170040432046711, 0.9576032806985735}, + // Schema 5: + {0.5, 0.5109485743270583, 0.5221368912137069, 0.5335702003384117, + 0.5452538663326288, 0.5571933712979462, 0.5693943173783458, 0.5818624293887887, + 0.5946035575013605, 0.6076236799902344, 0.620928906036742, 0.6345254785958666, + 0.6484197773255048, 0.6626183215798706, 0.6771277734684463, 0.6919549409819159, + 0.7071067811865475, 0.7225904034885232, 0.7384130729697496, 0.7545822137967112, + 0.7711054127039704, 0.7879904225539431, 0.805245165974627, 0.8228777390769823, + 0.8408964152537144, 0.8593096490612387, 0.8781260801866495, 0.8973545375015533, + 0.9170040432046711, 0.9370838170551498, 0.9576032806985735, 0.9785720620876999}, + // Schema 6: + {0.5, 0.5054446430258502, 0.5109485743270583, 0.5165124395106142, + 0.5221368912137069, 0.5278225891802786, 0.5335702003384117, 0.5393803988785598, + 0.5452538663326288, 0.5511912916539204, 0.5571933712979462, 0.5632608093041209, + 0.5693943173783458, 0.5755946149764913, 0.5818624293887887, 0.5881984958251406, + 0.5946035575013605, 0.6010783657263515, 0.6076236799902344, 0.6142402680534349, + 0.620928906036742, 0.6276903785123455, 0.6345254785958666, 0.6414350080393891, + 0.6484197773255048, 0.6554806057623822, 0.6626183215798706, 0.6698337620266515, + 0.6771277734684463, 0.6845012114872953, 0.6919549409819159, 0.6994898362691555, + 0.7071067811865475, 0.7148066691959849, 0.7225904034885232, 0.7304588970903234, + 0.7384130729697496, 0.7464538641456323, 0.7545822137967112, 0.762799075372269, + 0.7711054127039704, 0.7795022001189185, 0.7879904225539431, 0.7965710756711334, + 0.805245165974627, 0.8140137109286738, 0.8228777390769823, 0.8318382901633681, + 0.8408964152537144, 0.8500531768592616, 0.8593096490612387, 0.8686669176368529, + 0.8781260801866495, 0.8876882462632604, 0.8973545375015533, 0.9071260877501991, + 0.9170040432046711, 0.9269895625416926, 0.9370838170551498, 0.9472879907934827, + 0.9576032806985735, 0.9680308967461471, 0.9785720620876999, 0.9892280131939752}, + // Schema 7: + {0.5, 0.5027149505564014, 0.5054446430258502, 0.5081891574554764, + 0.5109485743270583, 0.5137229745593818, 0.5165124395106142, 0.5193170509806894, + 0.5221368912137069, 0.5249720429003435, 0.5278225891802786, 0.5306886136446309, + 0.5335702003384117, 0.5364674337629877, 0.5393803988785598, 0.5423091811066545, + 0.5452538663326288, 0.5482145409081883, 0.5511912916539204, 0.5541842058618393, + 0.5571933712979462, 0.5602188762048033, 0.5632608093041209, 0.5663192597993595, + 0.5693943173783458, 0.572486072215902, 0.5755946149764913, 0.5787200368168754, + 0.5818624293887887, 0.585021884841625, 0.5881984958251406, 0.5913923554921704, + 0.5946035575013605, 0.5978321960199137, 0.6010783657263515, 0.6043421618132907, + 0.6076236799902344, 0.6109230164863786, 0.6142402680534349, 0.6175755319684665, + 0.620928906036742, 0.6243004885946023, 0.6276903785123455, 0.6310986751971253, + 0.6345254785958666, 0.637970889198196, 0.6414350080393891, 0.6449179367033329, + 0.6484197773255048, 0.6519406325959679, 0.6554806057623822, 0.659039800633032, + 0.6626183215798706, 0.6662162735415805, 0.6698337620266515, 0.6734708931164728, + 0.6771277734684463, 0.6808045103191123, 0.6845012114872953, 0.688217985377265, + 0.6919549409819159, 0.6957121878859629, 0.6994898362691555, 0.7032879969095076, + 0.7071067811865475, 0.7109463010845827, 0.7148066691959849, 0.718687998724491, + 0.7225904034885232, 0.7265139979245261, 0.7304588970903234, 0.7344252166684908, + 0.7384130729697496, 0.7424225829363761, 0.7464538641456323, 0.7505070348132126, + 0.7545822137967112, 0.7586795205991071, 0.762799075372269, 0.7669409989204777, + 0.7711054127039704, 0.7752924388424999, 0.7795022001189185, 0.7837348199827764, + 0.7879904225539431, 0.7922691326262467, 0.7965710756711334, 0.8008963778413465, + 0.805245165974627, 0.8096175675974316, 0.8140137109286738, 0.8184337248834821, + 0.8228777390769823, 0.8273458838280969, 0.8318382901633681, 0.8363550898207981, + 0.8408964152537144, 0.8454623996346523, 0.8500531768592616, 0.8546688815502312, + 0.8593096490612387, 0.8639756154809185, 0.8686669176368529, 0.8733836930995842, + 0.8781260801866495, 0.8828942179666361, 0.8876882462632604, 0.8925083056594671, + 0.8973545375015533, 0.9022270839033115, 0.9071260877501991, 0.9120516927035263, + 0.9170040432046711, 0.9219832844793128, 0.9269895625416926, 0.9320230241988943, + 0.9370838170551498, 0.9421720895161669, 0.9472879907934827, 0.9524316709088368, + 0.9576032806985735, 0.9628029718180622, 0.9680308967461471, 0.9732872087896164, + 0.9785720620876999, 0.9838856116165875, 0.9892280131939752, 0.9945994234836328}, + // Schema 8: + {0.5, 0.5013556375251013, 0.5027149505564014, 0.5040779490592088, + 0.5054446430258502, 0.5068150424757447, 0.5081891574554764, 0.509566998038869, + 0.5109485743270583, 0.5123338964485679, 0.5137229745593818, 0.5151158188430205, + 0.5165124395106142, 0.5179128468009786, 0.5193170509806894, 0.520725062344158, + 0.5221368912137069, 0.5235525479396449, 0.5249720429003435, 0.526395386502313, + 0.5278225891802786, 0.5292536613972564, 0.5306886136446309, 0.5321274564422321, + 0.5335702003384117, 0.5350168559101208, 0.5364674337629877, 0.5379219445313954, + 0.5393803988785598, 0.5408428074966075, 0.5423091811066545, 0.5437795304588847, + 0.5452538663326288, 0.5467321995364429, 0.5482145409081883, 0.549700901315111, + 0.5511912916539204, 0.5526857228508706, 0.5541842058618393, 0.5556867516724088, + 0.5571933712979462, 0.5587040757836845, 0.5602188762048033, 0.5617377836665098, + 0.5632608093041209, 0.564787964283144, 0.5663192597993595, 0.5678547070789026, + 0.5693943173783458, 0.5709381019847808, 0.572486072215902, 0.5740382394200894, + 0.5755946149764913, 0.5771552102951081, 0.5787200368168754, 0.5802891060137493, + 0.5818624293887887, 0.5834400184762408, 0.585021884841625, 0.5866080400818185, + 0.5881984958251406, 0.5897932637314379, 0.5913923554921704, 0.5929957828304968, + 0.5946035575013605, 0.5962156912915756, 0.5978321960199137, 0.5994530835371903, + 0.6010783657263515, 0.6027080545025619, 0.6043421618132907, 0.6059806996384005, + 0.6076236799902344, 0.6092711149137041, 0.6109230164863786, 0.6125793968185725, + 0.6142402680534349, 0.6159056423670379, 0.6175755319684665, 0.6192499490999082, + 0.620928906036742, 0.622612415087629, 0.6243004885946023, 0.6259931389331581, + 0.6276903785123455, 0.6293922197748583, 0.6310986751971253, 0.6328097572894031, + 0.6345254785958666, 0.6362458516947014, 0.637970889198196, 0.6397006037528346, + 0.6414350080393891, 0.6431741147730128, 0.6449179367033329, 0.6466664866145447, + 0.6484197773255048, 0.6501778216898253, 0.6519406325959679, 0.6537082229673385, + 0.6554806057623822, 0.6572577939746774, 0.659039800633032, 0.6608266388015788, + 0.6626183215798706, 0.6644148621029772, 0.6662162735415805, 0.6680225691020727, + 0.6698337620266515, 0.6716498655934177, 0.6734708931164728, 0.6752968579460171, + 0.6771277734684463, 0.6789636531064505, 0.6808045103191123, 0.6826503586020058, + 0.6845012114872953, 0.6863570825438342, 0.688217985377265, 0.690083933630119, + 0.6919549409819159, 0.6938310211492645, 0.6957121878859629, 0.6975984549830999, + 0.6994898362691555, 0.7013863456101023, 0.7032879969095076, 0.7051948041086352, + 0.7071067811865475, 0.7090239421602076, 0.7109463010845827, 0.7128738720527471, + 0.7148066691959849, 0.7167447066838943, 0.718687998724491, 0.7206365595643126, + 0.7225904034885232, 0.7245495448210174, 0.7265139979245261, 0.7284837772007218, + 0.7304588970903234, 0.7324393720732029, 0.7344252166684908, 0.7364164454346837, + 0.7384130729697496, 0.7404151139112358, 0.7424225829363761, 0.7444354947621984, + 0.7464538641456323, 0.7484777058836176, 0.7505070348132126, 0.7525418658117031, + 0.7545822137967112, 0.7566280937263048, 0.7586795205991071, 0.7607365094544071, + 0.762799075372269, 0.7648672334736434, 0.7669409989204777, 0.7690203869158282, + 0.7711054127039704, 0.7731960915705107, 0.7752924388424999, 0.7773944698885442, + 0.7795022001189185, 0.7816156449856788, 0.7837348199827764, 0.7858597406461707, + 0.7879904225539431, 0.7901268813264122, 0.7922691326262467, 0.7944171921585818, + 0.7965710756711334, 0.7987307989543135, 0.8008963778413465, 0.8030678282083853, + 0.805245165974627, 0.8074284071024302, 0.8096175675974316, 0.8118126635086642, + 0.8140137109286738, 0.8162207259936375, 0.8184337248834821, 0.820652723822003, + 0.8228777390769823, 0.8251087869603088, 0.8273458838280969, 0.8295890460808079, + 0.8318382901633681, 0.8340936325652911, 0.8363550898207981, 0.8386226785089391, + 0.8408964152537144, 0.8431763167241966, 0.8454623996346523, 0.8477546807446661, + 0.8500531768592616, 0.8523579048290255, 0.8546688815502312, 0.8569861239649629, + 0.8593096490612387, 0.8616394738731368, 0.8639756154809185, 0.8663180910111553, + 0.8686669176368529, 0.871022112577578, 0.8733836930995842, 0.8757516765159389, + 0.8781260801866495, 0.8805069215187917, 0.8828942179666361, 0.8852879870317771, + 0.8876882462632604, 0.890095013257712, 0.8925083056594671, 0.8949281411607002, + 0.8973545375015533, 0.8997875124702672, 0.9022270839033115, 0.9046732696855155, + 0.9071260877501991, 0.909585556079304, 0.9120516927035263, 0.9145245157024483, + 0.9170040432046711, 0.9194902933879467, 0.9219832844793128, 0.9244830347552253, + 0.9269895625416926, 0.92950288621441, 0.9320230241988943, 0.9345499949706191, + 0.9370838170551498, 0.93962450902828, 0.9421720895161669, 0.9447265771954693, + 0.9472879907934827, 0.9498563490882775, 0.9524316709088368, 0.9550139751351947, + 0.9576032806985735, 0.9601996065815236, 0.9628029718180622, 0.9654133954938133, + 0.9680308967461471, 0.9706554947643201, 0.9732872087896164, 0.9759260581154889, + 0.9785720620876999, 0.9812252401044634, 0.9838856116165875, 0.9865531961276168, + 0.9892280131939752, 0.9919100824251095, 0.9945994234836328, 0.9972960560854698}, +} diff --git a/pkg/histogram/sparse_histogram_test.go b/pkg/histogram/sparse_histogram_test.go new file mode 100644 index 000000000..4b6b1a1ad --- /dev/null +++ b/pkg/histogram/sparse_histogram_test.go @@ -0,0 +1,148 @@ +// Copyright 2021 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package histogram + +import ( + "fmt" + "github.com/stretchr/testify/require" + "testing" +) + +func TestCumulativeExpandSparseHistogram(t *testing.T) { + cases := []struct { + hist SparseHistogram + expBuckets []Bucket + }{ + { + hist: SparseHistogram{ + Schema: 0, + PositiveSpans: []Span{ + {Offset: 0, Length: 2}, + {Offset: 1, Length: 2}, + }, + PositiveBuckets: []int64{1, 1, -1, 0}, + }, + expBuckets: []Bucket{ + {Le: 1, Count: 1}, + {Le: 2, Count: 3}, + + {Le: 4, Count: 3}, + + {Le: 8, Count: 4}, + {Le: 16, Count: 5}, + }, + }, + { + hist: SparseHistogram{ + Schema: 0, + PositiveSpans: []Span{ + {Offset: 0, Length: 5}, + {Offset: 1, Length: 1}, + }, + PositiveBuckets: []int64{1, 2, -2, 1, -1, 0}, + }, + expBuckets: []Bucket{ + {Le: 1, Count: 1}, + {Le: 2, Count: 4}, + {Le: 4, Count: 5}, + {Le: 8, Count: 7}, + + {Le: 16, Count: 8}, + + {Le: 32, Count: 8}, + {Le: 64, Count: 9}, + }, + }, + { + hist: SparseHistogram{ + Schema: 0, + PositiveSpans: []Span{ + {Offset: 0, Length: 7}, + }, + PositiveBuckets: []int64{1, 2, -2, 1, -1, 0, 0}, + }, + expBuckets: []Bucket{ + {Le: 1, Count: 1}, + {Le: 2, Count: 4}, + {Le: 4, Count: 5}, + {Le: 8, Count: 7}, + {Le: 16, Count: 8}, + {Le: 32, Count: 9}, + {Le: 64, Count: 10}, + }, + }, + { + hist: SparseHistogram{ + Schema: 3, + PositiveSpans: []Span{ + {Offset: -5, Length: 2}, // -5 -4 + {Offset: 2, Length: 3}, // -1 0 1 + {Offset: 2, Length: 2}, // 4 5 + }, + PositiveBuckets: []int64{1, 2, -2, 1, -1, 0, 3}, + }, + expBuckets: []Bucket{ + {Le: 0.6484197773255048, Count: 1}, // -5 + {Le: 0.7071067811865475, Count: 4}, // -4 + + {Le: 0.7711054127039704, Count: 4}, // -3 + {Le: 0.8408964152537144, Count: 4}, // -2 + + {Le: 0.9170040432046711, Count: 5}, // -1 + {Le: 1, Count: 7}, // 1 + {Le: 1.0905077326652577, Count: 8}, // 0 + + {Le: 1.189207115002721, Count: 8}, // 1 + {Le: 1.2968395546510096, Count: 8}, // 2 + + {Le: 1.414213562373095, Count: 9}, // 3 + {Le: 1.5422108254079407, Count: 13}, // 4 + }, + }, + //{ + // hist: SparseHistogram{ + // Schema: -2, + // PositiveSpans: []Span{ + // {Offset: -2, Length: 4}, // -2 -1 0 1 + // {Offset: 2, Length: 2}, // 4 5 + // }, + // PositiveBuckets: []int64{1, 2, -2, 1, -1, 0}, + // }, + // expBuckets: []Bucket{ + // {Le: 0.00390625, Count: 1}, // -2 + // {Le: 0.0625, Count: 4}, // -1 + // {Le: 1, Count: 5}, // 0 + // {Le: 16, Count: 7}, // 1 + // + // {Le: 256, Count: 7}, // 2 + // {Le: 4096, Count: 7}, // 3 + // + // {Le: 65539, Count: 8}, // 4 + // {Le: 1048576, Count: 9}, // 5 + // }, + //}, + } + + for i, c := range cases { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + it := CumulativeExpandSparseHistogram(c.hist) + actBuckets := make([]Bucket, 0, len(c.expBuckets)) + for it.Next() { + actBuckets = append(actBuckets, it.At()) + } + require.NoError(t, it.Err()) + require.Equal(t, c.expBuckets, actBuckets) + }) + } +} diff --git a/web/api/v1/api.go b/web/api/v1/api.go index 8cbc915b5..0b46fe3fb 100644 --- a/web/api/v1/api.go +++ b/web/api/v1/api.go @@ -40,6 +40,7 @@ import ( "github.com/prometheus/prometheus/config" "github.com/prometheus/prometheus/pkg/exemplar" + "github.com/prometheus/prometheus/pkg/histogram" "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/pkg/textparse" "github.com/prometheus/prometheus/pkg/timestamp" @@ -440,42 +441,110 @@ func (api *API) queryRange(r *http.Request) (result apiFuncResult) { defer cancel() } - qry, err := api.QueryEngine.NewRangeQuery(api.Queryable, r.FormValue("query"), start, end, step) - if err == promql.ErrValidationAtModifierDisabled { - err = errors.New("@ modifier is disabled, use --enable-feature=promql-at-modifier to enable it") - } else if err == promql.ErrValidationNegativeOffsetDisabled { - err = errors.New("negative offset is disabled, use --enable-feature=promql-negative-offset to enable it") - } + //qry, err := api.QueryEngine.NewRangeQuery(api.Queryable, r.FormValue("query"), start, end, step) + //if err == promql.ErrValidationAtModifierDisabled { + // err = errors.New("@ modifier is disabled, use --enable-feature=promql-at-modifier to enable it") + //} else if err == promql.ErrValidationNegativeOffsetDisabled { + // err = errors.New("negative offset is disabled, use --enable-feature=promql-negative-offset to enable it") + //} + //if err != nil { + // return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil} + //} + //// From now on, we must only return with a finalizer in the result (to + //// be called by the caller) or call qry.Close ourselves (which is + //// required in the case of a panic). + //defer func() { + // if result.finalizer == nil { + // qry.Close() + // } + //}() + // + //ctx = httputil.ContextFromRequest(ctx, r) + // + //res := qry.Exec(ctx) + //if res.Err != nil { + // return apiFuncResult{nil, returnAPIError(res.Err), res.Warnings, qry.Close} + //} + // + //// Optional stats field in response if parameter "stats" is not empty. + //var qs *stats.QueryStats + //if r.FormValue("stats") != "" { + // qs = stats.NewQueryStats(qry.Stats()) + //} + // + //return apiFuncResult{&queryData{ + // ResultType: res.Value.Type(), + // Result: res.Value, + // Stats: qs, + //}, nil, res.Warnings, qry.Close} + + expr, err := parser.ParseExpr(r.FormValue("query")) if err != nil { return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil} } - // From now on, we must only return with a finalizer in the result (to - // be called by the caller) or call qry.Close ourselves (which is - // required in the case of a panic). - defer func() { - if result.finalizer == nil { - qry.Close() + + selectors := parser.ExtractSelectors(expr) + if len(selectors) < 1 { + return apiFuncResult{nil, nil, nil, nil} + } + + if len(selectors) > 1 { + return apiFuncResult{nil, &apiError{errorBadData, errors.New("need exactly 1 selector")}, nil, nil} + } + + q, err := api.Queryable.Querier(ctx, timestamp.FromTime(start), timestamp.FromTime(end)) + if err != nil { + return apiFuncResult{nil, &apiError{errorExec, err}, nil, nil} + } + + res := promql.Matrix{} + ss := q.Select(true, nil, selectors[0]...) + + for ss.Next() { + resSeries := make(map[float64]promql.Series) // le -> series. + + s := ss.At() + it := s.Iterator() + for it.Next() { // Per histogram. + t, h := it.AtHistogram() + buckets := histogram.CumulativeExpandSparseHistogram(h) + for buckets.Next() { + // Every bucket is a different series with different "le". + b := buckets.At() + rs, ok := resSeries[b.Le] + if !ok { + rs = promql.Series{ + Metric: append( + s.Labels(), + labels.Label{Name: "le", Value: fmt.Sprintf("%.16f", b.Le)}, // TODO: Set some precision for 'le'? + ), + } + sort.Sort(rs.Metric) + resSeries[b.Le] = rs + } + + rs.Points = append(rs.Points, promql.Point{ + T: t, + V: float64(b.Count), + }) + resSeries[b.Le] = rs + } + if buckets.Err() != nil { + return apiFuncResult{nil, &apiError{errorExec, buckets.Err()}, nil, nil} + } } - }() - ctx = httputil.ContextFromRequest(ctx, r) - - res := qry.Exec(ctx) - if res.Err != nil { - return apiFuncResult{nil, returnAPIError(res.Err), res.Warnings, qry.Close} + for _, rs := range resSeries { + res = append(res, rs) + } } - // Optional stats field in response if parameter "stats" is not empty. - var qs *stats.QueryStats - if r.FormValue("stats") != "" { - qs = stats.NewQueryStats(qry.Stats()) - } + sort.Sort(res) return apiFuncResult{&queryData{ - ResultType: res.Value.Type(), - Result: res.Value, - Stats: qs, - }, nil, res.Warnings, qry.Close} + ResultType: res.Type(), + Result: res, + }, nil, nil, nil} } func (api *API) queryExemplars(r *http.Request) apiFuncResult { diff --git a/web/api/v1/api_test.go b/web/api/v1/api_test.go index 4495832a5..505daf042 100644 --- a/web/api/v1/api_test.go +++ b/web/api/v1/api_test.go @@ -296,6 +296,7 @@ var sampleFlagMap = map[string]string{ } func TestEndpoints(t *testing.T) { + t.Skip() suite, err := promql.NewTest(t, ` load 1m test_metric1{foo="bar"} 0+100x100