Skip to content

Fix IDMP cron expiration not working after RDB load#14869

Merged
sggeorgiev merged 4 commits intoredis:unstablefrom
sggeorgiev:register-idmp-streams
Mar 13, 2026
Merged

Fix IDMP cron expiration not working after RDB load#14869
sggeorgiev merged 4 commits intoredis:unstablefrom
sggeorgiev:register-idmp-streams

Conversation

@sggeorgiev
Copy link
Copy Markdown
Collaborator

@sggeorgiev sggeorgiev commented Mar 10, 2026

Summary

Registers streams with IDMP producers in db->stream_idmp_keys during RDB load, so that the periodic cron job can expire stale IDMP entries after a server restart. Without this fix, streams loaded from RDB were never registered, causing IDMP entries to accumulate indefinitely and never be cleaned up by the cron.

Changes

  • rdbLoadRioWithLoadingCtx (src/rdb.c): After loading each key-value pair, added a check for OBJ_STREAM type with a non-NULL idmp_producers rax. When found, creates a string object for the key and inserts it into db->stream_idmp_keys via dictAddRaw. If the key already exists (duplicate insert), the reference is decremented to avoid a leak.
  • Test XADD IDMP cron expiration works after RDB load (tests/unit/type/stream.tcl): Added an integration test that creates a stream with IDMP producers, sets a short IDMP-DURATION, saves and restarts the server, then verifies that the cron eventually expires the entries (pids-tracked and iids-tracked drop to 0) and that previously-expired IIDs can be re-added as new entries.

Benefits

  • Cron expiration works after restart: Streams with IDMP producers are now discoverable by the periodic cleanup cron after an RDB load, ensuring expired entries are reaped as expected.
  • No memory leak on stale entries: Without registration, IDMP entries that outlived their duration would persist in memory forever after a restart, growing unboundedly. This fix ensures they are cleaned up.
  • Consistency between runtime and post-load behavior: IDMP expiration now behaves identically whether the stream was created at runtime or restored from an RDB snapshot.

Note

Medium Risk
Touches the RDB loading path and stream bookkeeping, so mistakes could cause missed IDMP cleanup or reference-count/key-tracking issues after restart, but the change is small and covered by a new restart/cron integration test.

Overview
Fixes a restart-only bug where streams using IDMP could stop participating in the cron-based cleanup after being loaded from RDB.

During RDB load, streams that have idmp_producers are now added to db->stream_idmp_keys (with duplicate-safe refcount handling) so the periodic cron can expire and remove stale IDMP entries post-restart. Adds a unit test that saves/restarts, waits for XINFO STREAM tracked counts to drop to 0, and verifies expired IIDs can be added again.

Written by Cursor Bugbot for commit 0383f4f. This will update automatically on new commits. Configure here.

@sggeorgiev sggeorgiev requested a review from sundb March 10, 2026 13:35
@sundb sundb added the release-notes indication that this issue needs to be mentioned in the release notes label Mar 10, 2026
Comment thread tests/unit/type/stream.tcl Outdated
@sundb
Copy link
Copy Markdown
Collaborator

sundb commented Mar 11, 2026

one test failed: https://github.com/sundb/redis/actions/runs/22950671118/job/66614240728

*** [err]: XADD IDMP cron expiration works after RDB load in tests/unit/type/stream.tcl
Expected '2' to be equal to '0' (context: type eval line 22 cmd {assert_equal 2 [dict get $reply pids-tracked]} proc ::test)

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Comment thread tests/unit/type/stream.tcl Outdated
@sundb
Copy link
Copy Markdown
Collaborator

sundb commented Mar 13, 2026

@sggeorgiev sggeorgiev merged commit ee376cd into redis:unstable Mar 13, 2026
18 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in Redis 8.8 Mar 13, 2026
@YaacovHazan YaacovHazan moved this from Todo to In Progress in Redis 8.6 Backport Mar 19, 2026
YaacovHazan pushed a commit to YaacovHazan/redis that referenced this pull request Mar 19, 2026
**Summary**

Registers streams with IDMP producers in `db->stream_idmp_keys` during
RDB load, so that the periodic cron job can expire stale IDMP entries
after a server restart. Without this fix, streams loaded from RDB were
never registered, causing IDMP entries to accumulate indefinitely and
never be cleaned up by the cron.

**Changes**

- **`rdbLoadRioWithLoadingCtx` (src/rdb.c):** After loading each
key-value pair, added a check for `OBJ_STREAM` type with a non-NULL
`idmp_producers` rax. When found, creates a string object for the key
and inserts it into `db->stream_idmp_keys` via `dictAddRaw`. If the key
already exists (duplicate insert), the reference is decremented to avoid
a leak.
- **Test `XADD IDMP cron expiration works after RDB load`
(tests/unit/type/stream.tcl):** Added an integration test that creates a
stream with IDMP producers, sets a short `IDMP-DURATION`, saves and
restarts the server, then verifies that the cron eventually expires the
entries (pids-tracked and iids-tracked drop to 0) and that
previously-expired IIDs can be re-added as new entries.

**Benefits**

- **Cron expiration works after restart:** Streams with IDMP producers
are now discoverable by the periodic cleanup cron after an RDB load,
ensuring expired entries are reaped as expected.
- **No memory leak on stale entries:** Without registration, IDMP
entries that outlived their duration would persist in memory forever
after a restart, growing unboundedly. This fix ensures they are cleaned
up.
- **Consistency between runtime and post-load behavior:** IDMP
expiration now behaves identically whether the stream was created at
runtime or restored from an RDB snapshot.
YaacovHazan pushed a commit that referenced this pull request Mar 23, 2026
**Summary**

Registers streams with IDMP producers in `db->stream_idmp_keys` during
RDB load, so that the periodic cron job can expire stale IDMP entries
after a server restart. Without this fix, streams loaded from RDB were
never registered, causing IDMP entries to accumulate indefinitely and
never be cleaned up by the cron.

**Changes**

- **`rdbLoadRioWithLoadingCtx` (src/rdb.c):** After loading each
key-value pair, added a check for `OBJ_STREAM` type with a non-NULL
`idmp_producers` rax. When found, creates a string object for the key
and inserts it into `db->stream_idmp_keys` via `dictAddRaw`. If the key
already exists (duplicate insert), the reference is decremented to avoid
a leak.
- **Test `XADD IDMP cron expiration works after RDB load`
(tests/unit/type/stream.tcl):** Added an integration test that creates a
stream with IDMP producers, sets a short `IDMP-DURATION`, saves and
restarts the server, then verifies that the cron eventually expires the
entries (pids-tracked and iids-tracked drop to 0) and that
previously-expired IIDs can be re-added as new entries.

**Benefits**

- **Cron expiration works after restart:** Streams with IDMP producers
are now discoverable by the periodic cleanup cron after an RDB load,
ensuring expired entries are reaped as expected.
- **No memory leak on stale entries:** Without registration, IDMP
entries that outlived their duration would persist in memory forever
after a restart, growing unboundedly. This fix ensures they are cleaned
up.
- **Consistency between runtime and post-load behavior:** IDMP
expiration now behaves identically whether the stream was created at
runtime or restored from an RDB snapshot.
@YaacovHazan YaacovHazan mentioned this pull request Mar 24, 2026
@YaacovHazan YaacovHazan moved this from In Progress to Done in Redis 8.6 Backport Mar 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-notes indication that this issue needs to be mentioned in the release notes

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants