Skip to content

catalog: stop negative reachability counts from erroring queries - #40135

Open
antiguru wants to merge 2 commits into
MaterializeInc:mainfrom
antiguru:reachability-raw-rbac
Open

antiguru wants to merge 2 commits into
MaterializeInc:mainfrom
antiguru:reachability-raw-rbac

Conversation

@antiguru

@antiguru antiguru commented Oct 24, 2026 •

Copy link
Copy Markdown
Member

Motivation

mz_dataflow_operator_reachability_raw carries timely pointstamp count deltas in its diff. Progress updates arrive out of order across workers, so accumulations go negative, and on a multi-worker replica under steady traffic they nearly always are. Any distinct or fast-path peek over the relation then fails with an internal error and logs a customer-data error, which pages as potential data corruption. The public views fail the same way whenever a query ignores their count column, because projection pushdown removes the aggregate and leaves a distinct over the raw log.

Related: DB-23, database-issues#5387.

Description

  • mz_dataflow_operator_reachability_raw drops PUBLIC_SELECT. Builtin views keep reading it as the owner, following the mz_catalog_raw pattern.
  • mz_dataflow_operator_reachability_per_worker gains HAVING count(*) <> 0, so its accumulable count(*) survives projection pushdown. It accepts negative totals, and groups with a zero total emit no row. The negative counts stay visible in the views' count column.

This mitigates the errors without changing how the log encodes counts.

Verification

  • rbac_mcp_agent.slt asserts that an unprivileged role is denied on the raw relation and can read both views.
  • The new introspection/reachability.slt pins the accumulable count(*) in the plans of count-free queries on both views. It fails without the HAVING clause.
  • divergent-dataflow-cancellation.td checks the raw relation over the mz_system connection.
  • A local 4-worker reproduction with sustained traffic hit the errors on about 98% of probes before the change and on none after it.

Release notes

This release will restrict direct queries on mz_introspection.mz_dataflow_operator_reachability_raw to superusers. Query mz_dataflow_operator_reachability or mz_dataflow_operator_reachability_per_worker instead.

🤖 Generated with Claude Code

The reachability log puts timely pointstamp count deltas into the
differential diff. Progress updates arrive out of order across workers,
so the accumulated multiplicity of a row can be negative, and under
steady traffic it usually is. Operators that require positive
multiplicities fail on it: a distinct reports a non-positive
multiplicity, and a fast-path peek reports retractions for a row that
does not exist. Each failure also logs a customer-data error.

Remove PUBLIC_SELECT from mz_dataflow_operator_reachability_raw so that
users cannot query it directly. Builtin views read it as the owner.

The views over it aggregate with an accumulable count(*), which accepts
negative totals. Projection pushdown removes that aggregate when a query
ignores the count column, for example count(*) over the view, and the
remaining reduce renders as a distinct over the raw log. Add a HAVING
clause on the aggregate to mz_dataflow_operator_reachability_per_worker
so that the aggregate survives. Groups with a zero total emit no row, so
the filter does not change results.

Extend rbac_mcp_agent.slt to assert that an unprivileged role is denied
on the raw relation and can still read the views. Add
introspection/reachability.slt, which pins the accumulable count(*) in
the plans of count-free queries on both views. The cancellation
testdrive now checks the raw relation over the mz_system connection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@antiguru
antiguru marked this pull request as ready for review October 24, 2026 07:15
@antiguru
antiguru requested a review from a team as a code owner October 24, 2026 07:15
The leftover check on mz_dataflow_operator_reachability_raw ran over the
mz_system connection, which does not retry, and failed when the
cancelled dataflow's reachability rows were not yet retracted. Expose
the log through a view owned by mz_system and granted to the test user,
so the check is a retried fast-path query like its siblings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

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

LGTM, a few comments on the description and comment wording.

The Verification bullet for divergent-dataflow-cancellation.td still says it checks the raw relation over the mz_system connection. Since the second commit it reads through a view owned by mz_system. The PR body becomes the squash commit message, so this would land on main as written.

// The diff carries a timely pointstamp count, which can accumulate
// negative, so this is not a valid relation for direct queries. Builtin
// views read it as the owner.
access: vec![],

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.

Two groups can still query this relation: superusers, which in Cloud includes every organization admin (User::kind() maps is_external_admin() to Superuser), and everyone on deployments with RBAC checks off (a Materialize resource created without enableRbac: true, which is the CRD default, and the emulator). An admin running the incident's SELECT DISTINCT * still gets the error and still trips the alert. Could the PR description say which half covers whom (the HAVING clause fixes the views everywhere, the privilege change covers non-admins where RBAC checks are on)?

Comment on lines +139 to +140
# which can accumulate negative, so direct queries are limited to the system
# user. The views over it aggregate with an accumulable reduce and stay public.

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.

nit: superusers, not only the system user. In Cloud that includes organization admins.

$ postgres-execute connection=postgres://mz_system:materialize@${testdrive.materialize-internal-sql-addr}
ALTER SYSTEM SET enable_introspection_subscribes = false

# The raw reachability log is readable only by the system user. A view owned by

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.

nit: superusers, not only the system user. In Cloud that includes organization admins.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants