feat: WAIT command and CONFIG SET live-apply (maxmemory, maxmemory-policy) - #312
Merged
Conversation
adds update_memory_config to Keyspace so the eviction policy and memory limit can be changed in-place without restarting. a new UpdateMemoryConfig ShardRequest broadcasts the new config to every shard when CONFIG SET maxmemory or maxmemory-policy is issued. server.rs gains a max_memory_limit AtomicU64 that INFO reads from directly, keeping it accurate after live changes. config.rs adds memory_limit() and eviction_policy() helpers plus validation for both new mutable params.
adds ReplicaTracker to track how many records each replica has applied. the primary assigns each replica a unique ID on connect, splits the TCP stream so a background task reads MSG_ACK frames while the foreground task writes records, and increments write_offset after each flush. replicas send a 9-byte MSG_ACK (tag + u64 offset) after applying every record. WAIT numreplicas timeout-ms polls count_at_or_above(target) with a 25ms tick until enough replicas have caught up or the deadline passes, then returns the ack count as an integer. zero overhead on the GET/SET path: the tracker is only touched inside the replication background tasks and by the WAIT handler.
the config_registry_set_immutable_rejected test was asserting that maxmemory could not be set via CONFIG SET — now that maxmemory is mutable at runtime, replace it with two tests: one confirming the new mutable behavior (including validation), and one confirming that genuinely immutable params (bind, port) are still rejected.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
summary
two features that close important operational gaps before public preview: live memory reconfiguration without a server restart, and the WAIT command for replication-aware write operations.
what changed
config set live-apply
CONFIG SET maxmemoryandCONFIG SET maxmemory-policynow take effect immediately across all shards. previously they were stored in the config registry but never applied.KeyspaceStats::update_memory_config()— O(1) field update on each shard's keyspace. syncstrack_accesswith the new eviction policy so LRU sampling stays consistent.ShardRequest::UpdateMemoryConfig { max_memory, eviction_policy }— new variant in the shard request enum. handled in the shard main loop with no hot-path overhead: only executed when an operator runs CONFIG SET.ConfigRegistry::memory_limit()andConfigRegistry::eviction_policy()— new helpers for reading the live parsed values.ServerContext::max_memory_limit: AtomicU64— replaces the immutablemax_memory: Option<usize>for INFO display. reads are lock-free; updated atomically on CONFIG SET.CONFIG SET maxmemoryvalidates the memory string (e.g.256M,1G) and rejects invalid input before storing.WAIT command
WAIT numreplicas timeout-msblocks untilnumreplicasreplicas have acknowledged all writes processed before the WAIT, or untiltimeout_msms elapse. returns the count of replicas that acknowledged in time.protocol extension:
MSG_ACK = 6— new message type in the replication wire protocol. replicas send it after applying each record, carrying their current local offset.primary side (
ReplicationServer):ReplicaTracker— new struct trackingwrite_offset: AtomicU64(incremented when a record is successfully flushed to the replica's TCP buffer) and per-replica acknowledged offsets in aMutex<HashMap<u64, u64>>.tokio::io::split. a background task reads MSG_ACK frames and callstracker.update(); the main task drivesstream_records().replica side (
ReplicationClient):WAIT handler:
write_offsetis only touched inside the replication background task, never by GET/SET processing.what was tested
cargo check --workspaceandcargo clippy --workspace -- -D warningsboth cleancargo fmt --checkcleanconfig_registry_set_immutable_rejectedtest to reflect that maxmemory is now mutable. added a new test covering the validation path.design considerations
why
AtomicU64for max_memory_limit instead of updatingctx.max_memory:ctx.max_memoryisOption<usize>and is read by multiple places. changing its type would require modifying many call sites.AtomicU64(0 = unlimited) is a clean, lock-free addition that lets INFO always show the live value.why 25ms polling for WAIT: tight enough for sub-second replication lag scenarios, not so tight that it burns CPU under heavy load. matches the Redis approach of periodic polling rather than condition variables (which would require more synchronization across the replication boundary).
why
Mutex<HashMap>for replica offsets: this lock is only touched by the replication background task (writes) and by WAIT callers (reads). it is never touched on the GET/SET hot path. aDashMapwould be heavier for this low-contention use case.