mirror of https://github.com/redis/redis.git
Prevent crash when cgroups_ref is null in streamEntryIsReferenced() after reload (#14276)
This bug was introduced by https://github.com/redis/redis/pull/14130 found by @oranagra ### Summary Because `s->cgroup_ref` is created at runtime the first time a consumer group is linked with a message, but it is not released when all references are removed. However, after `debug reload` or restart, if the PEL is empty (meaning no consumer group is referencing any message), `s->cgroup_ref` will not be recreated. As a result, when executing XADD or XTRIM with `ACKED` option and checking whether a message that is being read but has not been ACKed can be deleted, the cgroup_ref being NULL will cause a crash. ### Code Path ``` xaddCommand -> streamTrim -> streamEntryIsReferenced ``` ### Solution Check if `s->cgroup_ref` is NULL in streamEntryIsReferenced().
This commit is contained in:
parent
46a3efa750
commit
b9d9d4000b
|
@ -2705,6 +2705,7 @@ int streamEntryIsReferenced(stream *s, streamID *id) {
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* Check if the message is in any consumer group's PEL */
|
/* Check if the message is in any consumer group's PEL */
|
||||||
|
if (!s->cgroups_ref) return 0;
|
||||||
unsigned char buf[sizeof(streamID)];
|
unsigned char buf[sizeof(streamID)];
|
||||||
streamEncodeID(buf, id);
|
streamEncodeID(buf, id);
|
||||||
return raxFind(s->cgroups_ref, buf, sizeof(streamID), NULL);
|
return raxFind(s->cgroups_ref, buf, sizeof(streamID), NULL);
|
||||||
|
|
|
@ -244,6 +244,33 @@ start_server {
|
||||||
assert {[r XLEN mystream] == 1} ;# Successfully trimmed to 1 entries
|
assert {[r XLEN mystream] == 1} ;# Successfully trimmed to 1 entries
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test {XADD with ACKED option doesn't crash after DEBUG RELOAD} {
|
||||||
|
r DEL mystream
|
||||||
|
r XADD mystream 1-0 f v
|
||||||
|
|
||||||
|
# Create a consumer group and read one message
|
||||||
|
r XGROUP CREATE mystream mygroup 0
|
||||||
|
set records [r XREADGROUP GROUP mygroup consumer1 COUNT 1 STREAMS mystream >]
|
||||||
|
assert_equal [lindex [r XPENDING mystream mygroup] 0] 1
|
||||||
|
|
||||||
|
# After reload, the reference relationship between consumer groups and messages
|
||||||
|
# is correctly rebuilt, so the previously read but unacked message still cannot be deleted.
|
||||||
|
r DEBUG RELOAD
|
||||||
|
r XADD mystream MAXLEN = 1 ACKED 2-0 f v
|
||||||
|
assert_equal [r XLEN mystream] 2
|
||||||
|
|
||||||
|
# Acknowledge the read message so the PEL becomes empty
|
||||||
|
r XACK mystream mygroup [lindex [lindex [lindex [lindex $records 0] 1] 0] 0]
|
||||||
|
assert {[lindex [r XPENDING mystream mygroup] 0] == 0}
|
||||||
|
|
||||||
|
# After reload, since PEL is empty, no cgroup references will be recreated.
|
||||||
|
r DEBUG RELOAD
|
||||||
|
|
||||||
|
# ACKED option should work correctly even without cgroup references.
|
||||||
|
r XADD mystream MAXLEN = 1 ACKED 3-0 f v
|
||||||
|
assert_equal [r XLEN mystream] 2
|
||||||
|
} {} {needs:debug}
|
||||||
|
|
||||||
test {XADD with MAXLEN option and DELREF option} {
|
test {XADD with MAXLEN option and DELREF option} {
|
||||||
r DEL mystream
|
r DEL mystream
|
||||||
r XADD mystream 1-0 f v
|
r XADD mystream 1-0 f v
|
||||||
|
|
Loading…
Reference in New Issue