From 7afb4261d2c95c38efefffc92e02c9727039a8e8 Mon Sep 17 00:00:00 2001 From: JAESOL SHIN Date: Wed, 5 Aug 2026 16:57:03 +0900 Subject: [PATCH] perf(catalog): reuse resolved graph id in ensure_current_graph ensure_current_graph() resolves the selected graph, then calls current_catalog_state() -> read_catalog(), which resolves the same graph again through selected_or_default_graph_id_via_definer(). Every traversal call therefore pays for two definer SPI lookups of the same row. Add current_catalog_state_for_graph(graph_id) so the already-resolved id is reused. No behavior change: read_catalog_for_graph() is the same code path read_catalog() delegates to once it has resolved the id. Measured on PG 17.10, 1,308,553 nodes / 3,599,812 edges, pinned seed set, warmup applied, median of 40 runs: minimal-work expand() 5.179 ms -> 4.070 ms (-21.4%) expand() LIMIT 50 (Q2) 6.148 ms -> 4.923 ms (-19.9%) expand() LIMIT 50 (Q3) 4.980 ms -> 4.217 ms (-15.3%) graph.status() control 3.495 ms -> 3.683 ms (+5.4%) Row counts identical in all cases. graph.status() is a negative control on a path this change does not touch, putting run-to-run noise at +/-5%. Schema-drift behavior stays covered by the existing pg_tests catalog_drift_requires_rebuild and schema_drift_detects_live_ddl_changes. --- graph/src/catalog.rs | 4 ++-- graph/src/catalog/read.rs | 17 +++++++++++++++++ graph/src/sql_facade/runtime.rs | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/graph/src/catalog.rs b/graph/src/catalog.rs index 97e8cf69..10df7343 100644 --- a/graph/src/catalog.rs +++ b/graph/src/catalog.rs @@ -19,8 +19,8 @@ pub(crate) use graphs::{ GraphMetadata, GraphPrivilege, GraphQuota, GraphQuotaUsage, }; pub(crate) use read::{ - catalog_fingerprint, current_catalog_state, current_catalog_state_from_rows, read_catalog, - read_catalog_for_graph, + catalog_fingerprint, current_catalog_state, current_catalog_state_for_graph, + current_catalog_state_from_rows, read_catalog, read_catalog_for_graph, }; #[cfg(feature = "pg_test")] pub(crate) use validate::validate_numeric_column; diff --git a/graph/src/catalog/read.rs b/graph/src/catalog/read.rs index 97043cb8..85a2afad 100644 --- a/graph/src/catalog/read.rs +++ b/graph/src/catalog/read.rs @@ -429,6 +429,23 @@ pub(crate) fn current_catalog_state() -> safety::GraphResult<(u64, Option safety::GraphResult<(u64, Option)> { + let (tables, edges, filter_columns) = read_catalog_for_graph(graph_id)?; + current_catalog_state_from_rows(&tables, &edges, &filter_columns) +} + pub(crate) fn current_catalog_state_from_rows( tables: &[builder::RegisteredTable], edges: &[builder::RegisteredEdge], diff --git a/graph/src/sql_facade/runtime.rs b/graph/src/sql_facade/runtime.rs index 1fad8c73..3ebe43f2 100644 --- a/graph/src/sql_facade/runtime.rs +++ b/graph/src/sql_facade/runtime.rs @@ -580,7 +580,7 @@ pub(crate) fn ensure_current_graph() -> safety::GraphResult<()> { let sync_mode = current_sync_mode()?; let disabled = disabled_graph_trigger_count()?; - let catalog_state = current_catalog_state()?; + let catalog_state = catalog::current_catalog_state_for_graph(&graph.graph_id)?; let applied_sync_id = ENGINE.with(|e| e.borrow().applied_sync_id); let pending = pending_sync_rows(applied_sync_id)?; ENGINE.with(|e| {