From a99118bc7e88f1e70030fe1a440f1a001e29e546 Mon Sep 17 00:00:00 2001 From: Taewoon Kim Date: Sat, 24 Oct 2026 23:51:51 +0900 Subject: [PATCH] Example 21: query the graph analytical view once after a reopen, then wait for its counts After a reopen, a graph analytical view restored from its persisted CSR is lazy: schema:graphAnalyticalViews reports READY with nodeCount 0 and edgeCount 0 until the first query that uses the view (ArcadeData/arcadedb#10575). Example 21 polled the row until READY and then required the full counts, so on current engines it failed intermittently. The example now runs one query through the view after the reopen and then polls with a new wait_for_gav_counts helper until the row is READY with the expected counts. Port of humemai/arcadedb-embedded-python#469. Co-Authored-By: Claude Sonnet 5.5 --- examples/21_graph_analytical_view_sql.py | 49 ++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/examples/21_graph_analytical_view_sql.py b/examples/21_graph_analytical_view_sql.py index 475803c..4ac5403 100644 --- a/examples/21_graph_analytical_view_sql.py +++ b/examples/21_graph_analytical_view_sql.py @@ -19,7 +19,8 @@ results against the expanded graph - alter update mode and compaction threshold through SQL - add another growth wave under SYNCHRONOUS mode and verify live counts -- reopen the database and confirm persisted GAV restoration +- reopen the database and confirm persisted GAV restoration (the restore is lazy: one + query through the view first, then poll the metadata row) Requirements: - A packaged ArcadeDB runtime with Graph Analytical View SQL support @@ -534,6 +535,40 @@ def wait_for_gav_status( time.sleep(0.25) +def wait_for_gav_counts( + db, + name: str, + expected_nodes: int, + expected_edges: int, + timeout_sec: float = 180.0, +) -> dict: + """Poll schema:graphAnalyticalViews until the view is READY with real counts. + + A view restored when the database opens is restored lazily: the row answers + READY with nodeCount 0 and edgeCount 0 until the first query that uses the + view. Run one such query before calling this, or the 0 stays. + """ + start = time.perf_counter() + last_metadata = None + while True: + metadata = fetch_gav_metadata(db, name) + if metadata is not None: + last_metadata = metadata + if ( + metadata["status"] == "READY" + and metadata["nodeCount"] == expected_nodes + and metadata["edgeCount"] == expected_edges + ): + return metadata + if time.perf_counter() - start > timeout_sec: + raise RuntimeError( + f"Timed out waiting for GAV {name} to report " + f"{expected_nodes} nodes and {expected_edges} edges. " + f"Last metadata: {last_metadata}" + ) + time.sleep(0.25) + + def query_direct_neighbor_sample( db, origin_code: str, @@ -866,7 +901,15 @@ def main() -> int: print("Phase 6: Reopen the database and confirm persisted GAV restoration") with arcadedb.open_database(str(db_path)) as reopened_db: - restored_metadata = wait_for_gav_status(reopened_db, GAV_NAME, {"READY"}) + # The restore on open is lazy: until a query uses the view, the schema row + # can say READY with nodeCount 0 and edgeCount 0. Run one query first, then + # poll the row for the real counts. + direct_neighbors = query_direct_neighbor_sample( + reopened_db, anchor_code, args.sample_limit + ) + restored_metadata = wait_for_gav_counts( + reopened_db, GAV_NAME, expected_sync_nodes, expected_sync_edges + ) require( restored_metadata["nodeCount"] == expected_sync_nodes, f"Expected restored GAV nodeCount = {expected_sync_nodes}", @@ -878,7 +921,7 @@ def main() -> int: print_gav_metadata("Metadata after reopen:", restored_metadata) print_rows( "Sample direct neighbors after reopen:", - query_direct_neighbor_sample(reopened_db, anchor_code, args.sample_limit), + direct_neighbors, ) print_rows( "Region sample after reopen:",