mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-10-12 15:02:32 +00:00
fix(promql): return no point for zero-interval irate/idelta (#9455)
fix(promql): irate/idelta return no point for a zero-ms sample gap
Signed-off-by: Niladri Adhikary <niladrix719@gmail.com>
(cherry picked from commit 0dde3a7b70)
Signed-off-by: WenyXu <wenymedia@gmail.com>
This commit is contained in:
@@ -140,8 +140,13 @@ impl<const IS_RATE: bool> IDelta<IS_RATE> {
|
||||
|
||||
let last_offset = ts_offset + last_position;
|
||||
let prev_offset = ts_offset + prev_position;
|
||||
let sampled_interval =
|
||||
(ts_values[last_offset] - ts_values[prev_offset]) as f64 / 1000.0;
|
||||
let sampled_interval_ms = ts_values[last_offset] - ts_values[prev_offset];
|
||||
// Sub-millisecond samples round to the same ms; skip instead of dividing by zero.
|
||||
if sampled_interval_ms == 0 {
|
||||
result_builder.append_null();
|
||||
continue;
|
||||
}
|
||||
let sampled_interval = sampled_interval_ms as f64 / 1000.0;
|
||||
|
||||
let last_value = value_values[value_offset + last_position];
|
||||
let prev_value = value_values[value_offset + prev_position];
|
||||
@@ -263,4 +268,30 @@ mod test {
|
||||
vec![Some(3.0), None, None],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn idelta_skips_samples_in_same_millisecond() {
|
||||
// The last two samples of the first range share 999ms; the second range is 1ms apart.
|
||||
let ts_array = Arc::new(TimestampMillisecondArray::from_iter_values([
|
||||
999i64, 999, 999, 1000,
|
||||
]));
|
||||
let values_array = Arc::new(Float64Array::from_iter([10.0, 13.0, 999.0, 1000.0]));
|
||||
let ranges = [(0, 3), (2, 2)];
|
||||
|
||||
simple_range_udf_runner(
|
||||
IDelta::<false>::scalar_udf(),
|
||||
RangeArray::from_ranges(ts_array.clone(), ranges).unwrap(),
|
||||
RangeArray::from_ranges(values_array.clone(), ranges).unwrap(),
|
||||
vec![],
|
||||
vec![None, Some(1.0)],
|
||||
);
|
||||
|
||||
simple_range_udf_runner(
|
||||
IDelta::<true>::scalar_udf(),
|
||||
RangeArray::from_ranges(ts_array, ranges).unwrap(),
|
||||
RangeArray::from_ranges(values_array, ranges).unwrap(),
|
||||
vec![],
|
||||
vec![None, Some(1000.0)],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
-- The last two 'sub_ms' samples are 400ns apart and share one millisecond, which
|
||||
-- irate and idelta cannot resolve, so they return no point instead of inf.
|
||||
-- The 'one_ms' samples are 1ms apart and still produce a rate.
|
||||
CREATE TABLE sub_ms_interval (
|
||||
job STRING,
|
||||
`value` DOUBLE,
|
||||
ts TIMESTAMP(9) TIME INDEX,
|
||||
PRIMARY KEY(job)
|
||||
);
|
||||
|
||||
Affected Rows: 0
|
||||
|
||||
INSERT INTO sub_ms_interval VALUES
|
||||
('sub_ms', 999, 999999900),
|
||||
('sub_ms', 10, 999999100),
|
||||
('sub_ms', 13, 999999500),
|
||||
('one_ms', 10, 998000000),
|
||||
('one_ms', 13, 999000000);
|
||||
|
||||
Affected Rows: 5
|
||||
|
||||
SELECT * FROM sub_ms_interval ORDER BY job, ts;
|
||||
|
||||
+--------+-------+-------------------------------+
|
||||
| job | value | ts |
|
||||
+--------+-------+-------------------------------+
|
||||
| one_ms | 10.0 | 1970-01-01T00:00:00.998 |
|
||||
| one_ms | 13.0 | 1970-01-01T00:00:00.999 |
|
||||
| sub_ms | 10.0 | 1970-01-01T00:00:00.999999100 |
|
||||
| sub_ms | 13.0 | 1970-01-01T00:00:00.999999500 |
|
||||
| sub_ms | 999.0 | 1970-01-01T00:00:00.999999900 |
|
||||
+--------+-------+-------------------------------+
|
||||
|
||||
TQL EVAL (1, 1, '1s') irate(sub_ms_interval[5s]);
|
||||
|
||||
+---------------------+----------------------------+--------+
|
||||
| ts | prom_irate(ts_range,value) | job |
|
||||
+---------------------+----------------------------+--------+
|
||||
| 1970-01-01T00:00:01 | 3000.0 | one_ms |
|
||||
+---------------------+----------------------------+--------+
|
||||
|
||||
TQL EVAL (1, 1, '1s') idelta(sub_ms_interval[5s]);
|
||||
|
||||
+---------------------+-----------------------------+--------+
|
||||
| ts | prom_idelta(ts_range,value) | job |
|
||||
+---------------------+-----------------------------+--------+
|
||||
| 1970-01-01T00:00:01 | 3.0 | one_ms |
|
||||
+---------------------+-----------------------------+--------+
|
||||
|
||||
ADMIN FLUSH_TABLE('sub_ms_interval');
|
||||
|
||||
+--------------------------------------+
|
||||
| ADMIN FLUSH_TABLE('sub_ms_interval') |
|
||||
+--------------------------------------+
|
||||
| 0 |
|
||||
+--------------------------------------+
|
||||
|
||||
TQL EVAL (1, 1, '1s') irate(sub_ms_interval[5s]);
|
||||
|
||||
+---------------------+----------------------------+--------+
|
||||
| ts | prom_irate(ts_range,value) | job |
|
||||
+---------------------+----------------------------+--------+
|
||||
| 1970-01-01T00:00:01 | 3000.0 | one_ms |
|
||||
+---------------------+----------------------------+--------+
|
||||
|
||||
TQL EVAL (1, 1, '1s') idelta(sub_ms_interval[5s]);
|
||||
|
||||
+---------------------+-----------------------------+--------+
|
||||
| ts | prom_idelta(ts_range,value) | job |
|
||||
+---------------------+-----------------------------+--------+
|
||||
| 1970-01-01T00:00:01 | 3.0 | one_ms |
|
||||
+---------------------+-----------------------------+--------+
|
||||
|
||||
DROP TABLE sub_ms_interval;
|
||||
|
||||
Affected Rows: 0
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
-- The last two 'sub_ms' samples are 400ns apart and share one millisecond, which
|
||||
-- irate and idelta cannot resolve, so they return no point instead of inf.
|
||||
-- The 'one_ms' samples are 1ms apart and still produce a rate.
|
||||
CREATE TABLE sub_ms_interval (
|
||||
job STRING,
|
||||
`value` DOUBLE,
|
||||
ts TIMESTAMP(9) TIME INDEX,
|
||||
PRIMARY KEY(job)
|
||||
);
|
||||
|
||||
INSERT INTO sub_ms_interval VALUES
|
||||
('sub_ms', 999, 999999900),
|
||||
('sub_ms', 10, 999999100),
|
||||
('sub_ms', 13, 999999500),
|
||||
('one_ms', 10, 998000000),
|
||||
('one_ms', 13, 999000000);
|
||||
|
||||
SELECT * FROM sub_ms_interval ORDER BY job, ts;
|
||||
|
||||
TQL EVAL (1, 1, '1s') irate(sub_ms_interval[5s]);
|
||||
|
||||
TQL EVAL (1, 1, '1s') idelta(sub_ms_interval[5s]);
|
||||
|
||||
ADMIN FLUSH_TABLE('sub_ms_interval');
|
||||
|
||||
TQL EVAL (1, 1, '1s') irate(sub_ms_interval[5s]);
|
||||
|
||||
TQL EVAL (1, 1, '1s') idelta(sub_ms_interval[5s]);
|
||||
|
||||
DROP TABLE sub_ms_interval;
|
||||
Reference in New Issue
Block a user