Add comments to multi-user defrag pubsub test

Annotate each phase of the test to explain the purpose, the
interleaving strategy for creating fragmentation, and the data
integrity verification step.
This commit is contained in:
Hristo Staykov 2026-05-26 10:22:40 +03:00
parent 5c42ef0912
commit 3c680f96fc

View file

@ -583,6 +583,12 @@ run_solo {defrag} {
}
test "Active defrag pubsub multi-user subscriptions: $type" {
# This test verifies that active defrag correctly handles the
# two-level pubsub_subscriptions dict (outer dict keyed by user*,
# inner dicts for channels/patterns/shard_channels). Two clients
# subscribe under different ACL users so the outer dict has
# multiple entries, exercising the full defrag iteration path.
r flushdb
r config set hz 100
r config set activedefrag no
@ -594,6 +600,8 @@ run_solo {defrag} {
r config set active-defrag-ignore-bytes 1500kb
r config set maxmemory 0
# Create a second ACL user so we have two distinct user* keys
# in each client's pubsub_subscriptions dict.
r ACL SETUSER defraguser on nopass ~* &* +@all
set n 25000
@ -603,6 +611,11 @@ run_solo {defrag} {
$rd_extra AUTH defraguser defraguser
$rd_extra read
# Subscribe to 25k channels, alternating between the two clients.
# After each subscription, create a filler key of similar size via
# SETBIT. This interleaves subscription allocations with filler
# allocations in memory, which is needed to create fragmentation
# when the fillers are deleted later.
set rd_filler [redis_deferring_client]
for {set j 0} {$j < $n} {incr j} {
set channel_name "$dummy_channel[format "%06d" $j]"
@ -613,13 +626,17 @@ run_solo {defrag} {
$rd_extra subscribe $channel_name
$rd_extra read
}
# Create a ~400 byte filler key interleaved with subscription allocs
$rd_filler setbit k$j [expr {[string length $channel_name] * 8}] 1
$rd_filler read
}
after 120
# Sanity: fragmentation should be low right after populating
after 120 ;# serverCron only updates the info once in 100ms
assert_lessthan [s allocator_frag_ratio] 1.1
# Delete all filler keys to punch holes in memory and create
# fragmentation. Use batching to avoid TCP deadlock.
set batch_size 1000
for {set j 0} {$j < $n} {incr j} {
$rd_filler del k$j
@ -636,11 +653,15 @@ run_solo {defrag} {
$rd_filler read
}
$rd_filler close
after 120
# Verify fragmentation is high enough for defrag to kick in
after 120 ;# serverCron only updates the info once in 100ms
assert_morethan [s allocator_frag_ratio] 1.35
# Enable active defrag and wait for it to compact memory
catch {r config set activedefrag yes} e
if {[r config get activedefrag] eq "activedefrag yes"} {
# Wait for defrag to start working (decision once a second)
wait_for_condition 50 100 {
[s total_active_defrag_time] ne 0
} else {
@ -651,11 +672,16 @@ run_solo {defrag} {
fail "defrag not started."
}
# Wait for defrag to finish and verify fragmentation dropped
wait_for_defrag_stop 500 100 1.1
after 120
after 120 ;# serverCron only updates the info once in 100ms
}
# Verify data integrity: publish to every channel and confirm the
# correct client receives the message. If defrag corrupted any
# channel name, dict pointer, or subscription structure, this will
# fail or crash the server.
for {set j 0} {$j < $n} {incr j} {
set channel "$dummy_channel[format "%06d" $j]"
r publish $channel "hello"