Skip to content

Ensure zero token nodes are handled properly - #261

Merged
dkropachev merged 3 commits into
scylladb:masterfrom
sylwiaszunejko:ensure-zero-token
Jul 29, 2026
Merged

Ensure zero token nodes are handled properly#261
dkropachev merged 3 commits into
scylladb:masterfrom
sylwiaszunejko:ensure-zero-token

Conversation

@sylwiaszunejko

@sylwiaszunejko sylwiaszunejko commented Jul 27, 2026

Copy link
Copy Markdown

Support zero-token nodes

Adds coverage for zero-token nodes (ScyllaDB nodes started with join_ring: false, which report
tokens = null in system.peers) and fixes a replica-placement bug found while writing it.

Expected semantics, aligned with the Rust driver: a zero-token node is an ordinary routable host —
discovered, kept in load balancing plans, usable as a coordinator and as a contact point — but it
never owns data, so it must never be returned as a replica. Processing one must not warn or error.

Bug fix

TokenMap.Build registered every host in its per-datacenter host count and rack set, including
hosts that own no tokens. NetworkTopologyStrategy uses that rack set to decide whether racks are
still missing, so a zero-token node on its own rack inflated Racks.Count, kept racksMissing
true forever and caused real token owners to be skipped — leaving the replication factor
unsatisfied. The inflated host count also made dcRf too large, forcing a full ring scan per token.

The fix registers a datacenter only for hosts that actually own tokens. A datacenter made up
exclusively of zero-token nodes is therefore absent from the map and its replication factor is
treated as trivially satisfied. HostLength/Racks are consumed only by
NetworkTopologyStrategy, so the blast radius is limited to it.

Fixes: https://scylladb.atlassian.net/browse/DRIVER-191

Copilot AI review requested due to automatic review settings July 27, 2026 09:47
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d3ff164d-9e67-4541-a5ef-dbea694d6917

📥 Commits

Reviewing files that changed from the base of the PR and between c04050d and 4790a4b.

📒 Files selected for processing (3)
  • src/Cassandra.IntegrationTests/Core/ZeroTokenNodeTests.cs
  • src/Cassandra.Tests/ZeroTokenNodeUnitTests.cs
  • src/Cassandra/TokenMap.cs
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/Cassandra/TokenMap.cs
  • src/Cassandra.IntegrationTests/Core/ZeroTokenNodeTests.cs

📝 Walkthrough

Walkthrough

TokenMap.Build now excludes hosts without tokens from datacenter and rack accounting. New unit tests cover routing, replica selection, replacement nodes, empty token initialization, build safety, and trace output. A topology refresher test validates zero-token peer metadata without warnings. Integration tests cover discovery, schema refresh, connectivity, node restarts, replication factors exceeding token owners, and replacement of a zero-token node with a token-owning node.

Possibly related PRs

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main change: adding support for zero-token nodes.
Description check ✅ Passed The description directly explains the zero-token node support and the replica-placement fix.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds regression coverage and a manual Scylla harness for zero-token coordinator nodes.

Changes:

  • Adds unit tests for topology, routing, and logging behavior.
  • Adds a CCM-based manual verification workflow.
  • Adds a Make target for running the workflow.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
Makefile Adds the manual-test target.
ci/run-zero-token-manual-test.sh Creates and exercises a zero-token Scylla node.
tests/ZeroTokenManualTest/ZeroTokenManualTest.csproj Defines the manual harness project.
tests/ZeroTokenManualTest/Program.cs Implements routing and topology checks.
src/Cassandra.Tests/ZeroTokenNodeTests.cs Adds zero-token routing tests.
src/Cassandra.Tests/Connections/Control/TopologyRefresherTests.cs Tests zero-token topology discovery.
Comments suppressed due to low confidence (2)

ci/run-zero-token-manual-test.sh:90

  • With set -e, a nonzero watch result exits the script at wait, so WATCH_RC is never captured, the watch log is never printed, and the contact-point phase is skipped. Run wait as an if condition so the script can preserve the status and finish the remaining diagnostics.
wait "${WATCH_PID}"
WATCH_RC=$?

tests/ZeroTokenManualTest/Program.cs:277

  • The watch phase passes whenever queries do not throw, even if no zero-token DOWN/UP transition was observed and warnings/errors were captured. That lets the topology scenario pass without exercising its stated behavior; include both expected transitions and the listener result in the success condition.
            var queryErrors = events.Count(e => e.Contains("QUERY-ERROR") || e.Contains("EXCEPTION"));
            var ok = queryErrors == 0;

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/ZeroTokenManualTest/Program.cs Outdated
Comment thread ci/run-zero-token-manual-test.sh Outdated

@dkropachev dkropachev left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Also make sure all the cases covered - including node being loaded with zero-token neds and then upgraded to the regular node.

Comment thread ci/run-zero-token-manual-test.sh Outdated
Comment thread tests/ZeroTokenManualTest/Program.cs Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

src/Cassandra.Tests/ZeroTokenNodeTests.cs:87

  • DCAwareRoundRobinPolicy must also exclude a discovered zero-token peer from query plans. Keeping it local and routable conflicts with the zero-token driver requirements and with the Rust-driver behavior this fixture claims to follow. Update the policy implementation and make these assertions expect Ignored/absence from the plan while retaining the host in metadata.
            Assert.AreEqual(HostDistance.Local, policy.Distance(zeroToken));

            var plan = policy.NewQueryPlan(null, new SimpleStatement()).Select(h => h.Host).ToList();
            CollectionAssert.Contains(plan, zeroToken);

Comment thread src/Cassandra.Tests/ZeroTokenNodeUnitTests.cs
Comment thread src/Cassandra.Tests/ZeroTokenNodeUnitTests.cs
Comment thread src/Cassandra.IntegrationTests/Core/ZeroTokenNodeTests.cs
Copilot AI review requested due to automatic review settings July 27, 2026 16:58

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings July 27, 2026 18:23

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings July 28, 2026 17:35
@sylwiaszunejko
sylwiaszunejko marked this pull request as ready for review July 28, 2026 17:36

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
Makefile (1)

60-60: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prefer category-based exclusion over appending test names to this filter.

Should_KeepServingQueries_When_ZeroTokenNodeGoesDownAndUp and ZeroTokenNodeReplacementTests are both already tagged RealClusterLong. Excluding them by name means every future long-running test has to be added to this line manually and silently runs if forgotten. TestCategory!=RealClusterLong would cover them declaratively.

♻️ Suggested direction
-... & FullyQualifiedName!~RetryPolicyTests & FullyQualifiedName!~ZeroTokenNodeReplacementTests & FullyQualifiedName!~Should_KeepServingQueries_When_ZeroTokenNodeGoesDownAndUp)
+... & FullyQualifiedName!~RetryPolicyTests) & TestCategory!=realclusterlong

Verify the exact category string emitted by TestCategory.RealClusterLong before applying.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` at line 60, Update TEST_INTEGRATION_SCYLLA_FILTER to exclude the
RealClusterLong category using the exact emitted TestCategory.RealClusterLong
string, rather than listing ZeroTokenNodeReplacementTests and
Should_KeepServingQueries_When_ZeroTokenNodeGoesDownAndUp by name. Remove those
individual name filters while preserving the remaining exclusions.
src/Cassandra.Tests/ZeroTokenNodeUnitTests.cs (1)

183-194: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Rename the test to match the exercised helper path.

TestHelper.CreateHost already calls Host.SetInfo, so this does exercise the production token normalization path. Rename SetInfo_Should_YieldEmptyTokens_When_TokensAreNullOrEmpty to avoid implying the test directly invokes Host.SetInfo.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Cassandra.Tests/ZeroTokenNodeUnitTests.cs` around lines 183 - 194, Rename
the test method SetInfo_Should_YieldEmptyTokens_When_TokensAreNullOrEmpty to
reflect that it exercises the path through TestHelper.CreateHost rather than
directly invoking Host.SetInfo, while preserving the test logic and assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@Makefile`:
- Line 60: Update TEST_INTEGRATION_SCYLLA_FILTER to exclude the RealClusterLong
category using the exact emitted TestCategory.RealClusterLong string, rather
than listing ZeroTokenNodeReplacementTests and
Should_KeepServingQueries_When_ZeroTokenNodeGoesDownAndUp by name. Remove those
individual name filters while preserving the remaining exclusions.

In `@src/Cassandra.Tests/ZeroTokenNodeUnitTests.cs`:
- Around line 183-194: Rename the test method
SetInfo_Should_YieldEmptyTokens_When_TokensAreNullOrEmpty to reflect that it
exercises the path through TestHelper.CreateHost rather than directly invoking
Host.SetInfo, while preserving the test logic and assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: fdc71c6d-a6fa-4aa5-bd20-f57e9e9621e2

📥 Commits

Reviewing files that changed from the base of the PR and between 8c2627a and c04050d.

📒 Files selected for processing (5)
  • Makefile
  • src/Cassandra.IntegrationTests/Core/ZeroTokenNodeTests.cs
  • src/Cassandra.Tests/Connections/Control/TopologyRefresherTests.cs
  • src/Cassandra.Tests/ZeroTokenNodeUnitTests.cs
  • src/Cassandra/TokenMap.cs

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

src/Cassandra.IntegrationTests/Core/ZeroTokenNodeTests.cs:148

  • The NeverUse name promises behavior this test and TokenAwarePolicy do not provide: the test only verifies that healthy token owners are prioritized, while the policy can later fall back to the zero-token host through its child plan. Rename the test to describe the behavior it actually checks.
        public void Should_NeverUseZeroTokenNode_As_Coordinator_When_TokenAware()

src/Cassandra.IntegrationTests/Core/ZeroTokenNodeTests.cs:95

  • This overstates the token-aware routing contract. TokenAwarePolicy yields replicas first, then appends every remaining host from its child policy (src/Cassandra/Policies/TokenAwarePolicy.cs:141-151), so a zero-token host can still coordinate after replica failures. Document that it is not returned or prioritized as a replica rather than saying token-aware routing can never target it.

This issue also appears on line 148 of the same file.

    /// <item>a zero-token node never owns data, so it must never be returned as a replica by the
    /// token map, and consequently token aware routing must never target it.</item>

Comment thread Makefile Outdated
Comment thread Makefile Outdated
Comment thread src/Cassandra.Tests/ZeroTokenNodeUnitTests.cs
Copilot AI review requested due to automatic review settings July 29, 2026 07:22

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

src/Cassandra/TokenMap.cs:130

  • hasTokens only checks whether token strings were advertised, not whether any token parsed successfully. Since parse failures are caught below, a host whose tokens are all malformed still inflates HostLength and Racks; on a distinct rack this reproduces the unsatisfied-RF bug this change fixes. Register datacenters only after a host has produced at least one parsed token, or derive the datacenter metadata from the distinct hosts in primaryReplicas.
                var hasTokens = host.Tokens.Any();
                if (hasTokens && host.Datacenter != null)

@sylwiaszunejko

Copy link
Copy Markdown
Author

CI failures unrelated to the changes made, most likely a flaky test

@dkropachev
dkropachev merged commit 531cd59 into scylladb:master Jul 29, 2026
7 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants