Skip to content

Redis 8.2.1#28

Open
tomerqodo wants to merge 4 commits intoqodo_action_req_1_base_redis_821_pr6from
qodo_action_req_1_head_redis_821_pr6
Open

Redis 8.2.1#28
tomerqodo wants to merge 4 commits intoqodo_action_req_1_base_redis_821_pr6from
qodo_action_req_1_head_redis_821_pr6

Conversation

@tomerqodo
Copy link
Copy Markdown

Benchmark PR from agentic-review-benchmarks#6

sundb and others added 4 commits January 25, 2026 12:12
…s#14274)

Fix redis#14267
This bug was introduced by redis#13495

### Summary

When a replica clears a large database, it periodically calls
processEventsWhileBlocked() in the replicationEmptyDbCallback() callback
during the key deletion process.
If defragmentation is enabled, this means that active defrag can be
triggered while the database is being deleted.
The defragmentation process may also modify the database at this time,
which could lead to crashes when the database is accessed after
defragmentation.

Code Path:
```
replicationEmptyDbCallback() -> processEventsWhileBlocked() -> whileBlockedCron() -> defragWhileBlocked()
```

### Solution

This PR temporarily disables active defrag before emptying the database,
then restores the active defrag setting after the empty is complete.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…fter reload (redis#14276)

This bug was introduced by redis#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().
@qodo-code-review
Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (2) 📎 Requirement gaps (0)

Grey Divider


Action required

1. orig_active_defrag unused variable 📘 Rule violation ⛯ Reliability
Description
orig_active_defrag is introduced but never referenced, which will typically trigger an
  -Wunused-variable warning.
• With -Werror enabled, this warning becomes a build failure, violating the requirement to compile
  cleanly with warnings-as-errors.
• This also indicates the intended “restore original setting” behavior is not implemented as written
  in the comment.
Code

src/replication.c[R1956-1962]

+    int orig_active_defrag = server.active_defrag_enabled;
+    server.active_defrag_enabled = 0;
+
    emptyData(-1, empty_db_flags, replicationEmptyDbCallback);
+
+    /* Restore the original active defragmentation setting. */
+    server.active_defrag_enabled = 1;
Evidence
PR Compliance ID 10 requires the code to compile without warnings when -Werror is enabled. The
added orig_active_defrag local is assigned but not used, which is a common compiler warning and
would fail the build under -Werror.

AGENTS.md
src/replication.c[1953-1962]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new local variable `orig_active_defrag` is assigned but never used, which will likely trigger `-Wunused-variable` and fail builds when compiled with `-Werror`.

## Issue Context
The comment says the original active defrag setting should be restored after `emptyData(...)`, but the code restores a hard-coded `1` instead. This both causes the unused variable warning and makes the restore behavior inconsistent with the comment.

## Fix Focus Areas
- src/replication.c[1953-1962]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. version.h missing include guards 📘 Rule violation ✓ Correctness
Description
src/version.h is a header file but contains no include guard at all, so multiple inclusion can
  lead to redefinition errors depending on how it’s used.
• The compliance requirement mandates double-underscore include guards with the __FILENAME_H
  pattern, which this file does not implement.
Code

src/version.h[R1-3]

+/* Version information */
+#define REDIS_VERSION "8.2.1"
+#define REDIS_VERSION_NUM 0x00080201
Evidence
PR Compliance ID 9 requires all .h files to use double-underscore include guards. The updated
src/version.h contains only defines and has no #ifndef/__... guard sequence.

AGENTS.md
src/version.h[1-3]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`src/version.h` lacks the required double-underscore include guards for header files.

## Issue Context
The compliance checklist requires all `.h` files to use include guards of the form `#ifndef __FILENAME_H` / `#define __FILENAME_H` / `#endif`.

## Fix Focus Areas
- src/version.h[1-3]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. ACKED trim treated referenced 🐞 Bug ✓ Correctness
Description
streamEntryIsReferenced() returns 1 (referenced) when s->cgroups_ref is NULL, which is the
  opposite of what the PEL-reference check should imply.
• When consumer groups exist but the PEL is empty (common after ACK + reload), cgroups_ref is
  intentionally NULL, so this change makes fully-ACKed entries look referenced forever.
• This breaks ACKED delete/trim semantics (XADD/XTRIM/XDELEX/XACKDEL), causing trims to fail and
  streams to grow beyond MAXLEN/MINID expectations.
Code

src/t_stream.c[R2707-2711]

    /* Check if the message is in any consumer group's PEL */
+    if (!s->cgroups_ref) return 1;
    unsigned char buf[sizeof(streamID)];
    streamEncodeID(buf, id);
    return raxFind(s->cgroups_ref, buf, sizeof(streamID), NULL);
Evidence
cgroups_ref is created only when linking pending entries (PEL). If it is NULL, it means there are
no PEL references to check. streamTrim() relies on streamEntryIsReferenced()==0 to delete ACKED
entries; returning 1 on NULL makes deletion impossible even when an entry is fully
acknowledged/read, contradicting the intended behavior (and the newly added test’s scenario).

src/t_stream.c[2684-2712]
src/t_stream.c[51-67]
src/t_stream.c[2610-2620]
src/t_stream.c[844-852]
tests/unit/type/stream.tcl[266-271]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`streamEntryIsReferenced()` incorrectly returns `1` (referenced) when `s-&gt;cgroups_ref` is NULL. Since `cgroups_ref` is only built when PEL entries exist, NULL should mean “no PEL references exist”, so the function should not treat entries as referenced.

### Issue Context
This function is used by stream trimming/deletion paths under `DELETE_STRATEGY_ACKED` (e.g. XADD MAXLEN/MINID with ACKED), to decide which entries are eligible for removal.

### Fix Focus Areas
- src/t_stream.c[2707-2711]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
4. Reply discard logic inverted 🐞 Bug ✓ Correctness
Description
• The new discard_replies_every helper discards replies when $count % $frequency != 0, which is
  inverted from the intended “every N commands” behavior.
• In loops that call it every iteration, it will attempt to $rd read thousands of replies after
  only a handful of commands were pipelined, likely blocking the client waiting for replies that were
  never enqueued.
• This can cause test timeouts/hangs across multiple defrag tests (including the newly added
  replication/defrag test).
Code

tests/unit/memefficiency.tcl[R70-75]

+    proc discard_replies_every {rd count frequency discard_num} {
+        if {$count % $frequency != 0} {
+            for {set k 0} {$k < $discard_num} {incr k} {
+                $rd read ; # Discard replies
+            }
+        }
Evidence
redis_deferring_client defers reading replies; $client read consumes a pending reply (and will
wait if none are pending). The helper’s condition triggers the discard loop on almost every
iteration, while the code only sends one command per iteration in several loops, making the number
of reads quickly exceed the number of pending replies.

tests/unit/memefficiency.tcl[70-76]
tests/unit/memefficiency.tcl[356-363]
tests/test_helper.tcl[188-207]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The helper `discard_replies_every` uses an inverted condition (`!= 0`), causing it to read/discard replies on almost every loop iteration. With `redis_deferring_client`, this can block waiting for replies that are not pending.

### Issue Context
Several tests pipeline commands in tight loops and periodically drain replies to avoid excessive buffering. The previous pattern was “every 10000 ops, read 10000 replies”.

### Fix Focus Areas
- tests/unit/memefficiency.tcl[70-76]
- tests/unit/memefficiency.tcl[345-373]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



ⓘ The new review experience is currently in Beta. Learn more

Qodo Logo

Comment thread src/replication.c
Comment on lines +1956 to +1962
int orig_active_defrag = server.active_defrag_enabled;
server.active_defrag_enabled = 0;

emptyData(-1, empty_db_flags, replicationEmptyDbCallback);

/* Restore the original active defragmentation setting. */
server.active_defrag_enabled = 1;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. orig_active_defrag unused variable 📘 Rule violation ⛯ Reliability

orig_active_defrag is introduced but never referenced, which will typically trigger an
  -Wunused-variable warning.
• With -Werror enabled, this warning becomes a build failure, violating the requirement to compile
  cleanly with warnings-as-errors.
• This also indicates the intended “restore original setting” behavior is not implemented as written
  in the comment.
Agent prompt
## Issue description
A new local variable `orig_active_defrag` is assigned but never used, which will likely trigger `-Wunused-variable` and fail builds when compiled with `-Werror`.

## Issue Context
The comment says the original active defrag setting should be restored after `emptyData(...)`, but the code restores a hard-coded `1` instead. This both causes the unused variable warning and makes the restore behavior inconsistent with the comment.

## Fix Focus Areas
- src/replication.c[1953-1962]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread src/version.h
Comment on lines +1 to +3
/* Version information */
#define REDIS_VERSION "8.2.1"
#define REDIS_VERSION_NUM 0x00080201
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. version.h missing include guards 📘 Rule violation ✓ Correctness

src/version.h is a header file but contains no include guard at all, so multiple inclusion can
  lead to redefinition errors depending on how it’s used.
• The compliance requirement mandates double-underscore include guards with the __FILENAME_H
  pattern, which this file does not implement.
Agent prompt
## Issue description
`src/version.h` lacks the required double-underscore include guards for header files.

## Issue Context
The compliance checklist requires all `.h` files to use include guards of the form `#ifndef __FILENAME_H` / `#define __FILENAME_H` / `#endif`.

## Fix Focus Areas
- src/version.h[1-3]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread src/t_stream.c
Comment on lines 2707 to 2711
/* Check if the message is in any consumer group's PEL */
if (!s->cgroups_ref) return 1;
unsigned char buf[sizeof(streamID)];
streamEncodeID(buf, id);
return raxFind(s->cgroups_ref, buf, sizeof(streamID), NULL);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. Acked trim treated referenced 🐞 Bug ✓ Correctness

streamEntryIsReferenced() returns 1 (referenced) when s->cgroups_ref is NULL, which is the
  opposite of what the PEL-reference check should imply.
• When consumer groups exist but the PEL is empty (common after ACK + reload), cgroups_ref is
  intentionally NULL, so this change makes fully-ACKed entries look referenced forever.
• This breaks ACKED delete/trim semantics (XADD/XTRIM/XDELEX/XACKDEL), causing trims to fail and
  streams to grow beyond MAXLEN/MINID expectations.
Agent prompt
### Issue description
`streamEntryIsReferenced()` incorrectly returns `1` (referenced) when `s->cgroups_ref` is NULL. Since `cgroups_ref` is only built when PEL entries exist, NULL should mean “no PEL references exist”, so the function should not treat entries as referenced.

### Issue Context
This function is used by stream trimming/deletion paths under `DELETE_STRATEGY_ACKED` (e.g. XADD MAXLEN/MINID with ACKED), to decide which entries are eligible for removal.

### Fix Focus Areas
- src/t_stream.c[2707-2711]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +70 to +75
proc discard_replies_every {rd count frequency discard_num} {
if {$count % $frequency != 0} {
for {set k 0} {$k < $discard_num} {incr k} {
$rd read ; # Discard replies
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

4. Reply discard logic inverted 🐞 Bug ✓ Correctness

• The new discard_replies_every helper discards replies when $count % $frequency != 0, which is
  inverted from the intended “every N commands” behavior.
• In loops that call it every iteration, it will attempt to $rd read thousands of replies after
  only a handful of commands were pipelined, likely blocking the client waiting for replies that were
  never enqueued.
• This can cause test timeouts/hangs across multiple defrag tests (including the newly added
  replication/defrag test).
Agent prompt
### Issue description
The helper `discard_replies_every` uses an inverted condition (`!= 0`), causing it to read/discard replies on almost every loop iteration. With `redis_deferring_client`, this can block waiting for replies that are not pending.

### Issue Context
Several tests pipeline commands in tight loops and periodically drain replies to avoid excessive buffering. The previous pattern was “every 10000 ops, read 10000 replies”.

### Fix Focus Areas
- tests/unit/memefficiency.tcl[70-76]
- tests/unit/memefficiency.tcl[345-373]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants