Skip to content

Dismiss dict bucket arrays in fork child to reduce CoW#14979

Merged
ShooterIT merged 3 commits intoredis:unstablefrom
ShooterIT:dismiss-buckets
Apr 15, 2026
Merged

Dismiss dict bucket arrays in fork child to reduce CoW#14979
ShooterIT merged 3 commits intoredis:unstablefrom
ShooterIT:dismiss-buckets

Conversation

@ShooterIT
Copy link
Copy Markdown
Member

@ShooterIT ShooterIT commented Apr 3, 2026

During RDB saving and AOF rewriting, the fork child already dismisses
(madvise(MADV_DONTNEED)) individual key-value objects after serializing them.
However, the hash table bucket arrays of each dict were never dismissed,
leaving large contiguous allocations subject to CoW when the parent modifies them.

This PR extends the dismiss mechanism to cover dict bucket arrays, reducing CoW
memory overhead.

  • Expires kvstore — dismissed upfront before saving starts, since the
    child never accesses expires directly, after embeding expire time in the
    key object.
  • Slot dicts (cluster mode) — dismissed per-slot as the iterator moves
    to the next slot during RDB saving or AOF rewriting.
  • DB keys kvstore (standalone mode) — dismissed per-DB after each DB is
    fully serialized during RDB saving or AOF rewriting.

Note

Medium Risk
Changes fork-child memory dismissal behavior during RDB save and AOF rewrite to proactively madvise dict bucket arrays and to skip dismissing small serialized objects; mistakes here could impact snapshot/rewrite stability or CoW memory characteristics under load.

Overview
Reduces fork-time copy-on-write memory overhead by extending the child-process dismiss mechanism to include dict hash table bucket arrays, not just individual key/value objects.

During RDB saves and AOF rewrites, the child now dismisses key-space bucket arrays per-slot in cluster mode (as iteration moves to a new slot) and per-DB in standalone mode (after a DB is fully serialized). It also dismisses expires kvstore bucket arrays up-front for RDB/AOF children since they’re not read during serialization.

Additionally, dismissObject() calls during RDB/AOF serialization are now gated to only run for large serialized payloads (dump_size > server.page_size/2), and the integration test suite is expanded to cover both AOF rewrite paths (with/without RDB preamble) plus new standalone multi-DB and cluster slot bucket dismissal scenarios.

Reviewed by Cursor Bugbot for commit a2a37ad. Bugbot is set up for automated code reviews on this repo. Configure here.

Comment thread src/object.c
@augmentcode
Copy link
Copy Markdown

augmentcode Bot commented Apr 3, 2026

🤖 Augment PR Summary

Summary: Reduces fork-time CoW during RDB saves and AOF rewrites by extending the fork-child “dismiss” mechanism to also drop dict bucket arrays.
Changes:

  • Dismiss dict bucket arrays per-slot in cluster mode and per-DB/kvstore in standalone mode
  • Dismiss expires kvstore bucket arrays up-front in the fork child
  • Extend integration coverage for both AOF preamble modes, standalone multi-DB, and cluster slots
Technical Notes: Adds shared helpers (`dismissDictBucketsMemory`, `dismissKvstoreBucketsMemory`) and uses `madvise(MADV_DONTNEED)` via existing `dismissMemory()` plumbing.

🤖 Was this summary useful? React with 👍 or 👎

Copy link
Copy Markdown

@augmentcode augmentcode Bot left a comment

Choose a reason for hiding this comment

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

Review completed. 1 suggestion posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

Comment thread src/server.c Outdated
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.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

Reviewed by Cursor Bugbot for commit eaa4c3e. Configure here.

Comment thread src/server.c
@ShooterIT
Copy link
Copy Markdown
Member Author

ShooterIT commented Apr 9, 2026

in cluster mode, benchmark uses the following command, all keys will be changed during benchmarking

memtier_benchmark --key-minimum 1 --data-size 32 --key-maximum 40000000 --ratio 1:1  --random-data
--key-pattern P:P --hide-histogram -t 2 -c 50 --pipeline 50 -p 30001 --test-time 90 --expiry-range=600-1200

before

13024:M 09 Apr 2026 20:30:41.399 * Background saving started by pid 13456
13456:C 09 Apr 2026 20:32:08.899 * BGSAVE done, 40000000 keys saved, 0 keys skipped, 2389003653 bytes written.
13456:C 09 Apr 2026 20:32:08.902 * DB saved on disk
13456:C 09 Apr 2026 20:32:08.954 * Fork CoW for RDB: current 4776 MB, peak 4776 MB, average 3729 MB
13024:M 09 Apr 2026 20:32:09.240 * Background saving terminated with success

now

14256:M 09 Apr 2026 20:41:04.606 * Background saving started by pid 14598
14598:C 09 Apr 2026 20:42:29.923 * BGSAVE done, 40000000 keys saved, 0 keys skipped, 2389003653 bytes written.
14598:C 09 Apr 2026 20:42:29.926 * DB saved on disk
14598:C 09 Apr 2026 20:42:29.972 * Fork CoW for RDB: current 3987 MB, peak 4195 MB, average 3080 MB
14256:M 09 Apr 2026 20:42:30.249 * Background saving terminated with success

this PR can reduce about 700 MB CoW memory.

@ShooterIT ShooterIT requested review from oranagra and tezc April 10, 2026 09:44
Comment thread src/rdb.c
@ShooterIT ShooterIT merged commit 2f1a8b2 into redis:unstable Apr 15, 2026
18 checks passed
@ShooterIT ShooterIT deleted the dismiss-buckets branch April 15, 2026 12:34
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.

2 participants