promql: fix stale matchedSigs maps breaking fill_left in range queries

resetMatchedSigs used clear() to recycle inner maps, but the fill-LHS
loop checked matchedSigs[sigOrd] \!= nil to decide whether an RHS sample
was already matched. A cleared but non-nil map from a previous timestep
caused a false positive, skipping the fill and producing missing samples
in range queries using group_left fill_left or group_right fill_right.

Fix by restoring clear() for map reuse and changing the check to
len(matchedSigs[sigOrd]) > 0, which correctly treats an empty map as
unmatched while preserving the allocation-reuse across timesteps.

Signed-off-by: Julien Pivotto <291750+roidelapluie@users.noreply.github.com>
This commit is contained in:
Julien Pivotto 2026-06-03 15:23:58 +02:00
parent f3d653fb5c
commit bb7ec495d2
2 changed files with 16 additions and 1 deletions

View file

@ -3221,7 +3221,7 @@ func (ev *evaluator) VectorBinop(op parser.ItemType, lhs, rhs Vector, matching *
sigOrd := rhsh[i].sigOrdinal
if (matching.Card == parser.CardOneToOne && matchedSigsPresent[sigOrd]) ||
(matching.Card != parser.CardOneToOne && matchedSigs[sigOrd] != nil) {
(matching.Card != parser.CardOneToOne && len(matchedSigs[sigOrd]) > 0) {
continue // Already matched.
}
ls := Sample{

View file

@ -309,6 +309,21 @@ eval range from 0 to 20m step 5m intermittent_left + fill_left(0) intermittent_r
{label="b"} 100 _ 300 _ 500
{label="c"} 1000 _ _ 4000 5000
# Regression test: group_left fill_left in a range query must apply fill values
# at every timestep, even when the RHS sigOrd was matched at a previous timestep.
# resetMatchedSigs previously used clear() which left non-nil empty maps, causing
# the fill-LHS path to incorrectly skip unmatched RHS samples on subsequent timesteps.
clear
load 5m
matched_lhs{key="a"} 1 _ 3
matched_rhs{key="a"} 10 20 30
matched_rhs{key="b"} 100 200 300
eval range from 0 to 10m step 5m matched_lhs + on(key) group_left fill_left(0) matched_rhs
{key="a"} 11 20 33
{key="b"} 100 200 300
# ---------- fill with vectors where one side is empty ----------
clear