Summary
ASAP’s precompute engine, store, and SQL half-open parsing all treat a time bucket/window as left-closed, right-open [start, end). Prometheus range-vector selectors use the opposite convention: left-open, right-closed (start, end].
The two systems therefore disagree on both endpoints for the same nominal interval. That can cause off-by-one-boundary skew when comparing sketchdb results to Prometheus baselines, aligning experiment query times, or mixing PromQL and precomputed tumbling windows.
This is separate from (but related to) the ClickHouse BETWEEN issue (#408): ClickHouse inclusive BETWEEN was addressed with half-open SQL time >= A AND time < B to match ASAP’s [A, B) model. Prometheus still uses a different convention.
ASAP behavior today: [start, end)
Precompute / tumbling windows
WindowManager documents and implements half-open windows:
// window_manager.rs
// Lines 46-47
/// A window `[start, start + window_size_ms)` is closed when
/// `current_wm >= start + window_size_ms`.
// window_manager.rs
// Lines 78-94
/// Return all window starts whose window `[start, start + window_size_ms)`
/// contains the given timestamp.
/// ...
/// Return the window `[start, end)` boundaries for a given window start.
pub fn window_bounds(&self, window_start: i64) -> (i64, i64) {
(window_start, window_start + self.window_size_ms)
}
Membership test: start + window_size_ms > timestamp → timestamp at start is included; at end is excluded.
SQL / ClickHouse alignment
Half-open SQL is parsed as [start, end) and treated as equivalent to ASAP window selection (see query_equivalence_tests.rs, issue #401). Netflow experiments use:
WHERE time >= DATEADD(s, -11, '<anchor>')
AND time < DATEADD(s, -10, '<anchor>')
Stored precomputes
Buckets are keyed by (start_timestamp, end_timestamp) with end exclusive in the tumbling-window model.
Prometheus behavior: (start, end]
Per Prometheus docs, a range vector selector like metric[5m] at evaluation time t uses samples with timestamps after t−5m and through t — i.e. open on the left, closed on the right.
Concrete mismatch (1-second example)
Nominal “the second ending at T”:
| System |
Interval notation |
Includes T−1s? |
Includes T? |
| ASAP |
[T−1s, T) |
Yes (left-closed) |
No (right-open) |
| Prometheus |
(T−1s, T] |
No (left-open) |
Yes (right-closed) |
Same label, opposite boundary treatment on both sides.
For a 1s tumbling precompute window stored as [13:10:08, 13:10:09):
- ASAP includes events at
13:10:08.000
- ASAP excludes events at
13:10:09.000
- Prometheus-style
(13:10:08, 13:10:09] would include 13:10:09.000 and exclude 13:10:08.000
Summary
ASAP’s precompute engine, store, and SQL half-open parsing all treat a time bucket/window as left-closed, right-open
[start, end). Prometheus range-vector selectors use the opposite convention: left-open, right-closed(start, end].The two systems therefore disagree on both endpoints for the same nominal interval. That can cause off-by-one-boundary skew when comparing sketchdb results to Prometheus baselines, aligning experiment query times, or mixing PromQL and precomputed tumbling windows.
This is separate from (but related to) the ClickHouse BETWEEN issue (#408): ClickHouse inclusive
BETWEENwas addressed with half-open SQLtime >= A AND time < Bto match ASAP’s[A, B)model. Prometheus still uses a different convention.ASAP behavior today:
[start, end)Precompute / tumbling windows
WindowManager documents and implements half-open windows:
Membership test:
start + window_size_ms > timestamp→ timestamp atstartis included; atendis excluded.SQL / ClickHouse alignment
Half-open SQL is parsed as
[start, end)and treated as equivalent to ASAP window selection (seequery_equivalence_tests.rs, issue #401). Netflow experiments use:Stored precomputes
Buckets are keyed by
(start_timestamp, end_timestamp)withendexclusive in the tumbling-window model.Prometheus behavior:
(start, end]Per Prometheus docs, a range vector selector like
metric[5m]at evaluation timetuses samples with timestamps aftert−5mand throught— i.e. open on the left, closed on the right.Concrete mismatch (1-second example)
Nominal “the second ending at T”:
[T−1s, T)(T−1s, T]Same label, opposite boundary treatment on both sides.
For a 1s tumbling precompute window stored as
[13:10:08, 13:10:09):13:10:08.00013:10:09.000(13:10:08, 13:10:09]would include13:10:09.000and exclude13:10:08.000