Skip to content

Commit 7d7df7c

Browse files
antiguruclaude
andcommitted
benchmarks: guard the interactive runtime's read paths
Feature-benchmark scenarios for the four read shapes the interactive runtime changes: a peek dataflow joining two indexes, a fast-path point lookup, `CREATE INDEX` plus the first read that uses it, and a per-replica introspection read. The benchmark's replica is an unmanaged one backed by the composition's clusterd container, which the system parameter never reaches, so the container is configured with the second runtime directly. An image without the option ignores it, so the scenarios run against a two-runtime replica on this build and against whatever the other build's image provides, which is the comparison the nightly should report. Parallel-benchmark scenarios for what the second runtime is meant to buy: the temporary-dataflow floor on a quiet replica, introspection latency under hydration, and how far expensive peek walks hold back a written index's frontier, measured as the latency of a strict serializable read after a write. The two existing isolation scenarios now report regressions on their measured loops, with looser thresholds for contended tails. A sqllogictest pins the flag on a two-worker replica and covers same-key duplicate indexes across drops, error results on the fast path and through a peek dataflow, strict serializable reads over shared arrangements, and cluster re-provisioning. The clusterd-test-driver two-runtime workflow also runs with two workers, so the registry's worker pairing is exercised. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VDm7opomJLxbNUEP3r9BLk
1 parent 67d7101 commit 7d7df7c

6 files changed

Lines changed: 591 additions & 14 deletions

File tree

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
# Copyright Materialize, Inc. and contributors. All rights reserved.
2+
#
3+
# Use of this software is governed by the Business Source License
4+
# included in the LICENSE file at the root of this repository.
5+
#
6+
# As of the Change Date specified in that file, in accordance with
7+
# the Business Source License, use of this software will be governed
8+
# by the Apache License, Version 2.0.
9+
10+
"""Reads whose placement the interactive compute runtime changes.
11+
12+
The benchmark's clusterd container runs two runtimes when its image supports the option, so
13+
these run against a two-runtime replica on this build and against whatever the other build's
14+
image provides, which is what the comparison should measure.
15+
"""
16+
17+
from materialize.feature_benchmark.action import Action, TdAction
18+
from materialize.feature_benchmark.measurement_source import MeasurementSource, Td
19+
from materialize.feature_benchmark.scenario import Scenario
20+
21+
22+
class InteractiveRuntime(Scenario):
23+
"""Group parent."""
24+
25+
26+
class PeekDataflowJoin(InteractiveRuntime):
27+
"""A join over two indexed views, repeated. Neither input can take the fast path, so each
28+
query builds a peek dataflow that imports both indexes, which is the cost of a temporary
29+
dataflow on the runtime that serves it."""
30+
31+
SCALE = 5
32+
REPEAT = 10
33+
34+
def init(self) -> list[Action]:
35+
return [
36+
self.table_ten(),
37+
TdAction(f"""
38+
> CREATE MATERIALIZED VIEW v1 AS SELECT {self.unique_values()} AS f1 FROM {self.join()}
39+
40+
> CREATE MATERIALIZED VIEW v2 AS SELECT {self.unique_values()} AS f1 FROM {self.join()}
41+
42+
> CREATE DEFAULT INDEX ON v1
43+
44+
> CREATE DEFAULT INDEX ON v2
45+
46+
> SELECT count(*) FROM v1 JOIN v2 USING (f1)
47+
{self.n()}
48+
"""),
49+
]
50+
51+
def benchmark(self) -> MeasurementSource:
52+
joins = "\n".join(
53+
f"> SELECT count(*) FROM v1 JOIN v2 USING (f1)\n{self.n()}\n"
54+
for _ in range(self.REPEAT)
55+
)
56+
return Td(f"""
57+
> SELECT 1
58+
/* A */
59+
1
60+
61+
{joins}
62+
63+
> SELECT 1
64+
/* B */
65+
1
66+
""")
67+
68+
69+
class PointLookup(InteractiveRuntime):
70+
"""A literal lookup on an indexed view, repeated. On the interactive runtime the walk reads
71+
the arrangement the maintenance runtime published rather than a local trace."""
72+
73+
REPEAT = 1000
74+
75+
def init(self) -> list[Action]:
76+
return [
77+
self.table_ten(),
78+
TdAction(f"""
79+
> CREATE MATERIALIZED VIEW v1 AS SELECT {self.unique_values()} AS f1 FROM {self.join()}
80+
81+
> CREATE DEFAULT INDEX ON v1
82+
83+
> SELECT count(*) = {self.n()} FROM v1
84+
true
85+
"""),
86+
]
87+
88+
def benchmark(self) -> MeasurementSource:
89+
lookups = "\n".join(
90+
"> SELECT * FROM v1 WHERE f1 = 1\n1\n" for _ in range(self.REPEAT)
91+
)
92+
return Td(f"""
93+
> SET auto_route_introspection_queries TO false
94+
95+
> BEGIN
96+
97+
> SELECT 1
98+
/* A */
99+
1
100+
101+
{lookups}
102+
103+
> SELECT 1
104+
/* B */
105+
1
106+
""")
107+
108+
109+
class CreateIndexPublish(InteractiveRuntime):
110+
"""CREATE INDEX plus the first read that uses it. A publishing runtime installs a publisher
111+
per arrangement, and the first read on the interactive runtime waits for its publication.
112+
"""
113+
114+
def init(self) -> list[Action]:
115+
return [
116+
self.table_ten(),
117+
TdAction(f"""
118+
> CREATE TABLE t1 (f1 INTEGER, f2 INTEGER)
119+
120+
> INSERT INTO t1 (f1) SELECT {self.unique_values()} FROM {self.join()}
121+
122+
> SELECT 1 FROM t1 WHERE f1 = 0
123+
1
124+
"""),
125+
]
126+
127+
def benchmark(self) -> MeasurementSource:
128+
return Td("""
129+
> DROP INDEX IF EXISTS i1
130+
/* A */
131+
132+
> CREATE INDEX i1 ON t1(f1)
133+
134+
> SELECT count(*) FROM t1 AS a1, t1 AS a2 WHERE a1.f1 = a2.f1 AND a1.f1 = 0 AND a2.f1 = 0
135+
/* B */
136+
1
137+
""")
138+
139+
140+
class IntrospectionRead(InteractiveRuntime):
141+
"""A read of a per-replica introspection relation, repeated. The interactive runtime serves it
142+
from the maintenance runtime's published logging index."""
143+
144+
REPEAT = 100
145+
146+
def init(self) -> list[Action]:
147+
return [
148+
self.table_ten(),
149+
TdAction(f"""
150+
> CREATE MATERIALIZED VIEW v1 AS SELECT {self.unique_values()} AS f1 FROM {self.join()}
151+
152+
> CREATE DEFAULT INDEX ON v1
153+
154+
> SELECT count(*) = {self.n()} FROM v1
155+
true
156+
"""),
157+
]
158+
159+
def benchmark(self) -> MeasurementSource:
160+
reads = "\n".join(
161+
"> SELECT count(*) > 0 FROM mz_introspection.mz_dataflow_arrangement_sizes\ntrue\n"
162+
for _ in range(self.REPEAT)
163+
)
164+
return Td(f"""
165+
> SELECT 1
166+
/* A */
167+
1
168+
169+
{reads}
170+
171+
> SELECT 1
172+
/* B */
173+
1
174+
""")

0 commit comments

Comments
 (0)