Skip to content

improvement: maintain token-aware routing even when schema metadata refresh is disabled - #977

Open
mykaul wants to merge 2 commits into
scylladb:masterfrom
mykaul:feature/token-aware-routing-no-schema-metadata
Open

improvement: maintain token-aware routing even when schema metadata refresh is disabled#977
mykaul wants to merge 2 commits into
scylladb:masterfrom
mykaul:feature/token-aware-routing-no-schema-metadata

Conversation

@mykaul

@mykaul mykaul commented Aug 11, 2026

Copy link
Copy Markdown

Motivation

With schema_metadata_enabled=False, the driver skipped all schema refresh, so the token map never had keyspace replica information and token-aware routing was silently given away — even though it was the stated cost of disabling schema metadata.

Change

Fetch keyspace replication strategies from the lightweight system_schema.keyspaces table on connect and on keyspace schema change events, and use them for token-aware routing when full keyspace metadata is unavailable. Tablet metadata is invalidated for dropped tables and keyspaces, and for keyspace replication changes. No change to token-aware routing behavior when schema metadata is enabled.

Tests

Added unit tests covering replica lookup, token map rebuild, strategy add/remove/change, keyspace metadata sync, control connection event handling, and graceful degradation on fetch failure; added an integration test verifying token-aware routing with schema metadata disabled. Full unit suite passes (783 tests).

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The driver preserves token-aware routing when schema_metadata_enabled is disabled. It loads replication strategies from system_schema.keyspaces, caches them separately from full schema metadata, and rebuilds affected token maps. Schema events update strategies and remove stale tablet metadata. Unit and integration tests cover these paths.

Sequence Diagram(s)

sequenceDiagram
  participant Driver
  participant SystemSchema
  participant Metadata
  participant TokenMap
  Driver->>SystemSchema: Query keyspace replication strategies
  SystemSchema-->>Driver: Return strategy rows
  Driver->>Metadata: Apply strategy updates
  Metadata->>TokenMap: Rebuild affected mappings
  TokenMap-->>Driver: Provide replicas for token-aware routing
Loading

Possibly related PRs

Suggested labels: area/Driver_-_python-driver

Suggested reviewers: lorak-mmk, sylwiaszunejko

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely identifies the main change: preserving token-aware routing when schema metadata refresh is disabled.
Description check ✅ Passed The description clearly covers motivation, implementation, affected behavior, and tests, so it is sufficiently complete and on-topic.
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.

@mykaul mykaul changed the title Maintain token-aware routing when schema metadata is disabled improvement: maintain token-aware routing even when schema metadata refresh is disabled Aug 11, 2026
@mykaul

mykaul commented Aug 11, 2026

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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.

Note

Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.

🟡 Other comments (2)
tests/unit/test_metadata.py-474-474 (1)

474-474: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove unused unpacked values.

Line 474 triggers RUF059. Replace tokens and hosts with _.

🤖 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 `@tests/unit/test_metadata.py` at line 474, Update the unpacking assignment in
the test method around _build_metadata so the unused tokens and hosts values are
assigned to _ while retaining metadata for subsequent use.

Sources: Coding guidelines, Linters/SAST tools

tests/integration/standard/test_metadata.py-182-197 (1)

182-197: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Release the cluster when an assertion fails.

Wrap the test body in try/finally. A failed assertion currently skips no_schema.shutdown() and can affect later tests.

🤖 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 `@tests/integration/standard/test_metadata.py` around lines 182 - 197, Wrap the
no-schema cluster setup and assertions in the test body with a try/finally
block, keeping no_schema.shutdown() in the finally clause so it executes even
when an assertion fails. Preserve the existing metadata, token-aware routing,
and query assertions unchanged.
🤖 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.

Other comments:
In `@tests/integration/standard/test_metadata.py`:
- Around line 182-197: Wrap the no-schema cluster setup and assertions in the
test body with a try/finally block, keeping no_schema.shutdown() in the finally
clause so it executes even when an assertion fails. Preserve the existing
metadata, token-aware routing, and query assertions unchanged.

In `@tests/unit/test_metadata.py`:
- Line 474: Update the unpacking assignment in the test method around
_build_metadata so the unused tokens and hosts values are assigned to _ while
retaining metadata for subsequent use.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: QUIET

Plan: Pro Plus

Run ID: a92165a5-a7d9-41fc-8c1d-528c5710a44f

📥 Commits

Reviewing files that changed from the base of the PR and between e9773cd and 601d0e0.

📒 Files selected for processing (6)
  • CHANGELOG.rst
  • cassandra/cluster.py
  • cassandra/metadata.py
  • tests/integration/standard/test_metadata.py
  • tests/unit/test_control_connection.py
  • tests/unit/test_metadata.py

@mykaul
mykaul force-pushed the feature/token-aware-routing-no-schema-metadata branch from 601d0e0 to b8d6342 Compare August 11, 2026 15:11
@coderabbitai
coderabbitai Bot requested a review from sylwiaszunejko August 11, 2026 15:12

@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.

Note

Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.

🟡 Other comments (2)
tests/unit/test_metadata.py-545-552 (1)

545-552: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Verify the no-rebuild contract.

Assert that TokenMap.rebuild_keyspace is not called. The copied mapping can compare equal after a rebuild, so Line 552 cannot detect the claimed no-rebuild behavior.

🤖 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 `@tests/unit/test_metadata.py` around lines 545 - 552, Update the test around
_update_replication_strategies to mock or spy on TokenMap.rebuild_keyspace
before invoking it, then assert that the method was not called. Retain the
existing tablet and token mapping assertions, but do not rely on mapping
equality alone to verify the no-rebuild contract.
tests/integration/standard/test_metadata.py-190-197 (1)

190-197: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Exercise token-aware host selection.

Execute a statement for self.ks_name with a routing key. Assert that its query plan or coordinator is a resolved replica. The system.local query does not use self.ks_name or a routing key, so it does not test token-aware routing.

🤖 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 `@tests/integration/standard/test_metadata.py` around lines 190 - 197, Replace
the `system.local` query in the token-aware routing test with a statement
executed against `self.ks_name` using a routing key. Assert that the resulting
query plan or coordinator resolves to one of the replicas returned by
`token_map.get_replicas`, preserving the existing replica lookup and validation.
🤖 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.

Other comments:
In `@tests/integration/standard/test_metadata.py`:
- Around line 190-197: Replace the `system.local` query in the token-aware
routing test with a statement executed against `self.ks_name` using a routing
key. Assert that the resulting query plan or coordinator resolves to one of the
replicas returned by `token_map.get_replicas`, preserving the existing replica
lookup and validation.

In `@tests/unit/test_metadata.py`:
- Around line 545-552: Update the test around _update_replication_strategies to
mock or spy on TokenMap.rebuild_keyspace before invoking it, then assert that
the method was not called. Retain the existing tablet and token mapping
assertions, but do not rely on mapping equality alone to verify the no-rebuild
contract.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: QUIET

Plan: Pro Plus

Run ID: ab2b0a17-e305-4a14-bbc5-ab7a6214aeef

📥 Commits

Reviewing files that changed from the base of the PR and between 601d0e0 and b8d6342.

📒 Files selected for processing (2)
  • tests/integration/standard/test_metadata.py
  • tests/unit/test_metadata.py

@mykaul
mykaul force-pushed the feature/token-aware-routing-no-schema-metadata branch 2 times, most recently from 2acb9bf to 8d6940c Compare August 11, 2026 15:47

@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.

Actionable comments posted: 1

Note

Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.

🟡 Other comments (1)
tests/integration/standard/test_metadata.py-202-203 (1)

202-203: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

_current_host can be a non-replica after a retry.

_current_host holds the last host attempted, not the first host the query plan produced. If the first replica fails and the retry policy moves to the next host, the assertion fails on a healthy cluster. Assert on rs.response_future.attempted_hosts[0] instead.

💚 Proposed fix
             replicas = set(no_schema.metadata.get_replicas(self.ks_name, statement.routing_key))
-            assert rs.response_future._current_host in replicas
+            assert rs.response_future.attempted_hosts[0] in replicas
🤖 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 `@tests/integration/standard/test_metadata.py` around lines 202 - 203, Update
the assertion in the metadata replica test to check
rs.response_future.attempted_hosts[0] against replicas instead of _current_host,
preserving the existing replica set calculation.
🧹 Nitpick comments (3)
tests/unit/test_metadata.py (1)

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

These two tests do not exercise driver code.

test_consistency_modes_are_mapped_from_rows rebuilds the dict comprehension from _aggregate_results inside the test. test_keyspace_absent_from_the_map_is_eventual only asserts dict.get default behavior. Both pass even if SchemaParserV3 breaks. Call parser._aggregate_results() and assert on parser.keyspace_consistency_modes instead.

🤖 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 `@tests/unit/test_metadata.py` around lines 789 - 812, Update
test_consistency_modes_are_mapped_from_rows to invoke
parser._aggregate_results() and assert the resulting
parser.keyspace_consistency_modes values, rather than recreating the mapping
with _consistency_mode_from_string. Update
test_keyspace_absent_from_the_map_is_eventual to exercise _aggregate_results()
with the relevant empty or missing-row setup, then assert the parser’s resulting
map fallback behavior so both tests fail if SchemaParserV3 aggregation breaks.
cassandra/cluster.py (1)

4168-4190: 🚀 Performance & Scalability | 🔵 Trivial

A keyspace event triggers a full-table read.

_refresh_replication_strategies reads all of system_schema.keyspaces for every keyspace event, even when kwargs["keyspace"] names one keyspace. The full read is required to detect dropped keyspaces, so the cost is justified. Confirm that the event rate on clusters with frequent DDL stays acceptable, and consider a filtered read for CREATED/UPDATED with the full read reserved for DROPPED.

🤖 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 `@cassandra/cluster.py` around lines 4168 - 4190, Update _refresh_schema and
_refresh_replication_strategies so CREATED or UPDATED keyspace events use a
keyspace-filtered metadata read based on kwargs["keyspace"], while DROPPED
events retain the full system_schema.keyspaces read needed to detect removals.
Preserve token-aware routing updates and verify the filtered path is used for
frequent keyspace DDL events without changing schema-disabled behavior.
cassandra/metadata.py (1)

1887-1897: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove or deprecate TokenMap.replica_map_for_keyspace.

No in-repository callers remain. Remove it if it is not part of the supported public API; otherwise mark it deprecated.

🤖 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 `@cassandra/metadata.py` around lines 1887 - 1897, The TokenMap
replica_map_for_keyspace API is unused in the repository; remove it if
unsupported, or mark it deprecated while preserving behavior if it is public.
Update the TokenMap definition and any related documentation or exports
consistently.
🤖 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.

Inline comments:
In `@cassandra/cluster.py`:
- Around line 4151-4166: Update the strategy-fetching flow around
ReplicationStrategy.create so failures parsing an individual row are handled per
row, logged, and do not prevent valid rows from being added or
_update_replication_strategies from being called. Keep the connection wait/query
failure as a separate guard that returns, but log that fetch failure at warning
instead of debug.

---

Other comments:
In `@tests/integration/standard/test_metadata.py`:
- Around line 202-203: Update the assertion in the metadata replica test to
check rs.response_future.attempted_hosts[0] against replicas instead of
_current_host, preserving the existing replica set calculation.

---

Nitpick comments:
In `@cassandra/cluster.py`:
- Around line 4168-4190: Update _refresh_schema and
_refresh_replication_strategies so CREATED or UPDATED keyspace events use a
keyspace-filtered metadata read based on kwargs["keyspace"], while DROPPED
events retain the full system_schema.keyspaces read needed to detect removals.
Preserve token-aware routing updates and verify the filtered path is used for
frequent keyspace DDL events without changing schema-disabled behavior.

In `@cassandra/metadata.py`:
- Around line 1887-1897: The TokenMap replica_map_for_keyspace API is unused in
the repository; remove it if unsupported, or mark it deprecated while preserving
behavior if it is public. Update the TokenMap definition and any related
documentation or exports consistently.

In `@tests/unit/test_metadata.py`:
- Around line 789-812: Update test_consistency_modes_are_mapped_from_rows to
invoke parser._aggregate_results() and assert the resulting
parser.keyspace_consistency_modes values, rather than recreating the mapping
with _consistency_mode_from_string. Update
test_keyspace_absent_from_the_map_is_eventual to exercise _aggregate_results()
with the relevant empty or missing-row setup, then assert the parser’s resulting
map fallback behavior so both tests fail if SchemaParserV3 aggregation breaks.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: QUIET

Plan: Pro Plus

Run ID: 1d512260-c276-4bea-8dc0-e6fc118bc42c

📥 Commits

Reviewing files that changed from the base of the PR and between b8d6342 and 8d6940c.

📒 Files selected for processing (4)
  • cassandra/cluster.py
  • cassandra/metadata.py
  • tests/integration/standard/test_metadata.py
  • tests/unit/test_metadata.py

Comment thread cassandra/cluster.py
With schema_metadata_enabled=False the driver skipped all schema refresh,
so the token map never had keyspace replica information and token-aware
routing was silently given away.

Fetch keyspace replication strategies from the lightweight
system_schema.keyspaces table on connect and on keyspace schema change
events, keep them in Metadata._keyspace_replication_strategies, and have
TokenMap fall back to them when keyspace metadata is unavailable. Dropped
table events are also processed so tablet metadata stays up to date.

Schema keyspace events are still ignored as before.
@mykaul
mykaul force-pushed the feature/token-aware-routing-no-schema-metadata branch from 8d6940c to e393697 Compare August 11, 2026 16:19

@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.

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@cassandra/cluster.py`:
- Around line 4178-4195: Move the _wait_for_schema_agreement call ahead of the
not self._schema_meta_enabled and not force branch so
_refresh_replication_strategies uses post-agreement schema data. Preserve
schema_agreement_wait=-1 for the initial connection path, and add a regression
test covering stale pre-agreement replication results to verify token-aware
routing refreshes correctly.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: QUIET

Plan: Pro Plus

Run ID: 63c83f51-c10c-4037-8195-e1e886f53429

📥 Commits

Reviewing files that changed from the base of the PR and between 8d6940c and e393697.

📒 Files selected for processing (2)
  • cassandra/cluster.py
  • tests/unit/test_control_connection.py

Comment thread cassandra/cluster.py Outdated
- Wait for schema agreement before the disabled-metadata branch so the
  CL.ONE replication read cannot return pre-agreement data
- Filter the keyspace read to the changed keyspace on keyspace events,
  merging the result into the known strategies (a missing row drops it)
- Deprecate the now-unused TokenMap.replica_map_for_keyspace
- Assert on the first attempted host in the integration test, exercise
  the real _aggregate_results in the consistency-mode unit tests, and
  add regression tests for the agreement-first behavior

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@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.

♻️ Duplicate comments (1)
cassandra/cluster.py (1)

4163-4174: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Handle strategy-construction failures per row.

ReplicationStrategy.create() is outside the guard. A SimpleStrategy row without replication_factor can raise KeyError and abort the refresh. Keep the existing strategy for that keyspace and continue processing other rows. Add a regression case for this malformed options map.

🤖 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 `@cassandra/cluster.py` around lines 4163 - 4174, Update the per-row processing
around ReplicationStrategy.create so strategy-construction exceptions, including
missing SimpleStrategy replication_factor, are caught without aborting the
refresh. Preserve the existing strategy for the affected keyspace and continue
processing subsequent rows, and add a regression test covering this malformed
options map.
🤖 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.

Duplicate comments:
In `@cassandra/cluster.py`:
- Around line 4163-4174: Update the per-row processing around
ReplicationStrategy.create so strategy-construction exceptions, including
missing SimpleStrategy replication_factor, are caught without aborting the
refresh. Preserve the existing strategy for the affected keyspace and continue
processing subsequent rows, and add a regression test covering this malformed
options map.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: QUIET

Plan: Pro Plus

Run ID: f1015cda-1df5-4aa1-a56d-0c7b83107ceb

📥 Commits

Reviewing files that changed from the base of the PR and between e393697 and 430445f.

📒 Files selected for processing (5)
  • cassandra/cluster.py
  • cassandra/metadata.py
  • tests/integration/standard/test_metadata.py
  • tests/unit/test_control_connection.py
  • tests/unit/test_metadata.py

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.

1 participant