Skip to content

fix(consensus): keep a client's dedup fence across capacity eviction - #3934

Open
numinnex wants to merge 2 commits into
masterfrom
fix_client_table_adverserial_test
Open

fix(consensus): keep a client's dedup fence across capacity eviction#3934
numinnex wants to merge 2 commits into
masterfrom
fix_client_table_adverserial_test

Conversation

@numinnex

Copy link
Copy Markdown
Contributor

No description provided.

@numinnex

Copy link
Copy Markdown
Contributor Author

Merge after #3931

@github-actions github-actions Bot added the S-waiting-on-review PR is waiting on a reviewer label Aug 20, 2026
@codecov

codecov Bot commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.02488% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.56%. Comparing base (c0c7493) to head (76460a1).
⚠️ Report is 9 commits behind head on master.

Files with missing lines Patch % Lines
core/consensus/src/client_table.rs 96.59% 3 Missing and 2 partials ⚠️
core/shard/src/router.rs 62.50% 3 Missing ⚠️
core/server_common/src/consensus_message.rs 85.71% 0 Missing and 2 partials ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master    #3934      +/-   ##
============================================
- Coverage     83.87%   83.56%   -0.31%     
  Complexity     1358     1358              
============================================
  Files          1212     1212              
  Lines        166843   166741     -102     
  Branches     134306   134329      +23     
============================================
- Hits         139937   139345     -592     
- Misses        23266    23614     +348     
- Partials       3640     3782     +142     
Components Coverage Δ
Rust Core 84.52% <95.02%> (-0.13%) ⬇️
Java SDK 66.67% <ø> (ø)
C# SDK 74.89% <ø> (-1.66%) ⬇️
Python SDK 90.13% <ø> (ø)
PHP SDK 84.48% <ø> (ø)
Node SDK 94.03% <ø> (-1.82%) ⬇️
Go SDK 68.37% <ø> (+0.04%) ⬆️
Files with missing lines Coverage Δ
core/binary_protocol/src/consensus/header.rs 81.56% <ø> (ø)
core/binary_protocol/src/consensus/operation.rs 97.54% <100.00%> (+0.06%) ⬆️
core/server/src/partition_reconciler.rs 97.80% <100.00%> (+0.03%) ⬆️
core/shard/src/metrics.rs 86.55% <ø> (ø)
core/server_common/src/consensus_message.rs 81.80% <85.71%> (+0.50%) ⬆️
core/shard/src/router.rs 80.28% <62.50%> (+7.58%) ⬆️
core/consensus/src/client_table.rs 89.87% <96.59%> (+1.03%) ⬆️

... and 74 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

/// state machine ran the operation a second time.
#[iggy_harness(cluster_nodes = 1, server(metadata.clients_table_max = "2"))]
async fn given_a_low_client_table_cap_when_connects_churn_should_erase_a_live_dedup_watermark(
async fn given_a_low_client_table_cap_when_connects_churn_should_keep_a_live_dedup_watermark(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This test currently fails with the original duplicate-name rejection, proving request 1 was re-executed. The PR should not unignore this spec until it passes end to end.

@@ -830,6 +907,13 @@ impl ClientTable {
///
/// [`Operation::Register`]: iggy_binary_protocol::Operation
pub fn remove_client(&mut self, client_id: u128) -> bool {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This removes every fence sharing client_id, including fences belonging to another user. It also erases the evicted client’s fence when disconnect cleanup commits Logout before resume, which is why the integration test fails. Fence removal needs the owning user_id and must distinguish explicit session termination from reconnect cleanup.

/// most, the watermark request's own reply, so it costs a fraction of the
/// entry it replaces. Trimmed oldest-first.
///
/// Replica-local best-effort, NOT replicated state: the bound is

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The watermark is safety state, not a volatile reply cache. Dropping these fences on checkpoint or state transfer restores the original re-execution bug after restart or failover and lets replicas derive different watermarks from the same register commit. Please include fences in snapshot and state-transfer encoding.

watermark_checksum: entry.watermark_checksum,
latest: entry.find_cached(entry.watermark).cloned(),
});
while self.evicted_fences.len() > self.slots.len() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Silently trimming the oldest fence after slots.len() active-client evictions only postpones the at-most-once failure. Please define and test the retention guarantee, or use durable bounded tombstones with explicit expiry rather than silently restoring watermark zero.

// Reclaim the replies, keep the fence: the evicted client's own resume
// must not read as a first-time register, or the retry of a committed
// request re-executes.
self.remember_fence(&entry);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This snapshots the watermark at eviction time. If an already-prepared request commits afterward, commit_reply finds no entry and cannot advance this fence. A later resume restores the older watermark and may re-execute that committed request. Please add this ordering test and update the retained fence when the late commit lands.

@spetz spetz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Previous comments

@github-actions github-actions Bot added S-waiting-on-author PR is waiting on author response and removed S-waiting-on-review PR is waiting on a reviewer labels Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-author PR is waiting on author response

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants