Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion 27 src/t_stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -3810,8 +3810,33 @@ void xsetidCommand(client *c) {
}

s->last_id = id;
if (entries_added != -1)
if (entries_added != -1) {
Comment thread
sggeorgiev marked this conversation as resolved.
uint64_t prev_entries_added = s->entries_added;
s->entries_added = entries_added;
/* Lowering entries_added may leave a consumer group's entries_read
* greater than the stream's entries_added. That breaks the lag
* calculation (XINFO GROUPS would report a negative lag) and, on
* builds that validate this invariant, produces an RDB/RESTORE
* payload that fails to load. Clamp each group's counter down, just
* like XGROUP CREATE/SETID does when entries_read is set too high.
* Only needed when entries_added is actually lowered; otherwise the
* entries_read <= entries_added invariant already holds and the loop
* would be a no-op. */
if (s->entries_added < prev_entries_added && s->cgroups) {
raxIterator ri;
raxStart(&ri, s->cgroups);
raxSeek(&ri, "^", NULL, 0);
while (raxNext(&ri)) {
streamCG *cg = ri.data;
if (cg->entries_read != SCG_INVALID_ENTRIES_READ &&
(uint64_t)cg->entries_read > s->entries_added)
{
cg->entries_read = s->entries_added;
}
}
raxStop(&ri);
}
}
if (!streamIDEqZero(&max_xdel_id))
s->max_deleted_entry_id = max_xdel_id;
addReply(c,shared.ok);
Expand Down
45 changes: 45 additions & 0 deletions 45 tests/unit/type/stream-cgroups.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -4835,3 +4835,48 @@ start_server {tags {"repl external:skip" "stream"}} {
}
}

start_server {tags {"stream external:skip needs:debug"}} {
# XSETID ... ENTRIESADDED must not leave a consumer group's entries_read
# greater than the stream's entries_added. Otherwise XINFO GROUPS reports a
# negative lag, and the resulting RDB fails to load ("Stream cgroup
# entries_read inconsistent with entries_added"). XGROUP CREATE/SETID
# already clamp entries_read; XSETID must clamp it too.
test "XSETID ENTRIESADDED clamps group entries_read and never yields negative lag" {
r DEL mystream
for {set i 1} {$i <= 10} {incr i} { r XADD mystream * f v$i }
r XGROUP CREATE mystream grp 0
r XREADGROUP GROUP grp c COUNT 10 STREAMS mystream >
set top [dict get [r XINFO STREAM mystream] last-generated-id]

# Shrink the stream so entries_added can be lowered below entries_read.
r XTRIM mystream MAXLEN 2
r XSETID mystream $top ENTRIESADDED 2

set ginfo [lindex [r XINFO GROUPS mystream] 0]
assert_equal [dict get $ginfo entries-read] 2
assert {[dict get $ginfo lag] >= 0}
assert_equal [dict get $ginfo lag] 0
}

test "XSETID inconsistency does not produce an unloadable RDB" {
# Reuse the state from the previous test; a reload must succeed and
# keep the counters consistent.
r DEBUG RELOAD
assert_equal [r XLEN mystream] 2
set ginfo [lindex [r XINFO GROUPS mystream] 0]
assert {[dict get $ginfo lag] >= 0}
assert_equal [dict get $ginfo entries-read] 2
}

test "XSETID raising entries_added leaves group entries_read untouched" {
r DEL s2
for {set i 1} {$i <= 5} {incr i} { r XADD s2 * f v$i }
r XGROUP CREATE s2 g 0
r XREADGROUP GROUP g c COUNT 3 STREAMS s2 >
set top [dict get [r XINFO STREAM s2] last-generated-id]
r XSETID s2 $top ENTRIESADDED 100
set ginfo [lindex [r XINFO GROUPS s2] 0]
assert_equal [dict get $ginfo entries-read] 3
assert_equal [dict get $ginfo lag] 97
}
}
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.