Skip to content

Commit 684fa8b

Browse files
antiguruclaude
andcommitted
benchmarks: guard the interactive runtime's read paths
Feature-benchmark scenarios for the four read shapes the interactive runtime changes, each in an `Interactive` and a `Solo` leaf so the report carries the cost of the second runtime side by side with each leaf's regression against the other build: 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. Each leaf pins the flag and provisions its own cluster, which the benchmark's fresh instance per scenario makes safe. 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 81d228a commit 684fa8b

6 files changed

Lines changed: 652 additions & 13 deletions

File tree

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
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 on a replica with and without the interactive compute runtime.
11+
12+
Every scenario here comes in two leaves. The `Interactive` leaf provisions its cluster with
13+
`enable_compute_interactive_runtime` on, so peeks and peek dataflows run on the second runtime and
14+
read the maintenance runtime's published arrangements. The `Solo` leaf provisions the same cluster
15+
with the flag off, which is a single-runtime replica. Both leaves run in every benchmark, so the
16+
report carries the cost of the second runtime for each shape side by side with the regression of
17+
each leaf against the other build.
18+
19+
The flag is read when a replica is provisioned, and the benchmark boots a fresh instance per
20+
scenario, so `init` sets it before creating the cluster and nothing else observes the setting.
21+
"""
22+
23+
from materialize.feature_benchmark.action import Action, TdAction
24+
from materialize.feature_benchmark.measurement_source import MeasurementSource, Td
25+
from materialize.feature_benchmark.scenario import Scenario
26+
27+
28+
class InteractiveRuntime(Scenario):
29+
"""Reads whose placement the interactive runtime changes. Group parent."""
30+
31+
INTERACTIVE: bool
32+
33+
def cluster(self) -> TdAction:
34+
"""Provisions cluster `ir` with the interactive runtime on or off."""
35+
flag = "true" if self.INTERACTIVE else "false"
36+
return TdAction(f"""
37+
$ postgres-execute connection=mz_system
38+
ALTER SYSTEM SET enable_compute_interactive_runtime = {flag};
39+
40+
> CREATE CLUSTER ir SIZE 'scale={self._default_size},workers=1', REPLICATION FACTOR 1
41+
""")
42+
43+
44+
class PeekDataflowJoin(InteractiveRuntime):
45+
"""A join over two indexed views, repeated. Neither input can take the fast path, so each
46+
query builds a peek dataflow that imports both indexes, which is the cost of a temporary
47+
dataflow on the runtime that serves it."""
48+
49+
SCALE = 5
50+
REPEAT = 10
51+
52+
def init(self) -> list[Action]:
53+
return [
54+
self.cluster(),
55+
self.table_ten(),
56+
TdAction(f"""
57+
> SET cluster = ir
58+
59+
> CREATE MATERIALIZED VIEW v1 AS SELECT {self.unique_values()} AS f1 FROM {self.join()}
60+
61+
> CREATE MATERIALIZED VIEW v2 AS SELECT {self.unique_values()} AS f1 FROM {self.join()}
62+
63+
> CREATE DEFAULT INDEX ON v1
64+
65+
> CREATE DEFAULT INDEX ON v2
66+
67+
> SELECT count(*) FROM v1 JOIN v2 USING (f1)
68+
{self.n()}
69+
"""),
70+
]
71+
72+
def benchmark(self) -> MeasurementSource:
73+
joins = "\n".join(
74+
f"> SELECT count(*) FROM v1 JOIN v2 USING (f1)\n{self.n()}\n"
75+
for _ in range(self.REPEAT)
76+
)
77+
return Td(f"""
78+
> SET cluster = ir
79+
80+
> SELECT 1
81+
/* A */
82+
1
83+
84+
{joins}
85+
86+
> SELECT 1
87+
/* B */
88+
1
89+
""")
90+
91+
92+
class PeekDataflowJoinInteractive(PeekDataflowJoin):
93+
INTERACTIVE = True
94+
95+
96+
class PeekDataflowJoinSolo(PeekDataflowJoin):
97+
INTERACTIVE = False
98+
99+
100+
class PointLookup(InteractiveRuntime):
101+
"""A literal lookup on an indexed view, repeated. On the interactive runtime the walk reads
102+
the arrangement the maintenance runtime published rather than a local trace."""
103+
104+
REPEAT = 1000
105+
106+
def init(self) -> list[Action]:
107+
return [
108+
self.cluster(),
109+
self.table_ten(),
110+
TdAction(f"""
111+
> SET cluster = ir
112+
113+
> CREATE MATERIALIZED VIEW v1 AS SELECT {self.unique_values()} AS f1 FROM {self.join()}
114+
115+
> CREATE DEFAULT INDEX ON v1
116+
117+
> SELECT count(*) = {self.n()} FROM v1
118+
true
119+
"""),
120+
]
121+
122+
def benchmark(self) -> MeasurementSource:
123+
lookups = "\n".join(
124+
"> SELECT * FROM v1 WHERE f1 = 1\n1\n" for _ in range(self.REPEAT)
125+
)
126+
return Td(f"""
127+
> SET cluster = ir
128+
129+
> SET auto_route_introspection_queries TO false
130+
131+
> BEGIN
132+
133+
> SELECT 1
134+
/* A */
135+
1
136+
137+
{lookups}
138+
139+
> SELECT 1
140+
/* B */
141+
1
142+
""")
143+
144+
145+
class PointLookupInteractive(PointLookup):
146+
INTERACTIVE = True
147+
148+
149+
class PointLookupSolo(PointLookup):
150+
INTERACTIVE = False
151+
152+
153+
class CreateIndexPublish(InteractiveRuntime):
154+
"""CREATE INDEX plus the first read that uses it. A publishing runtime installs a publisher
155+
per arrangement, and the first read on the interactive runtime waits for its publication.
156+
"""
157+
158+
def init(self) -> list[Action]:
159+
return [
160+
self.cluster(),
161+
self.table_ten(),
162+
TdAction(f"""
163+
> SET cluster = ir
164+
165+
> CREATE TABLE t1 (f1 INTEGER, f2 INTEGER)
166+
167+
> INSERT INTO t1 (f1) SELECT {self.unique_values()} FROM {self.join()}
168+
169+
> SELECT 1 FROM t1 WHERE f1 = 0
170+
1
171+
"""),
172+
]
173+
174+
def benchmark(self) -> MeasurementSource:
175+
return Td("""
176+
> SET cluster = ir
177+
178+
> DROP INDEX IF EXISTS i1
179+
/* A */
180+
181+
> CREATE INDEX i1 ON t1(f1)
182+
183+
> SELECT count(*) FROM t1 AS a1, t1 AS a2 WHERE a1.f1 = a2.f1 AND a1.f1 = 0 AND a2.f1 = 0
184+
/* B */
185+
1
186+
""")
187+
188+
189+
class CreateIndexPublishInteractive(CreateIndexPublish):
190+
INTERACTIVE = True
191+
192+
193+
class CreateIndexPublishSolo(CreateIndexPublish):
194+
INTERACTIVE = False
195+
196+
197+
class IntrospectionRead(InteractiveRuntime):
198+
"""A read of a per-replica introspection relation, repeated. The interactive runtime serves it
199+
from the maintenance runtime's published logging index."""
200+
201+
REPEAT = 100
202+
203+
def init(self) -> list[Action]:
204+
return [
205+
self.cluster(),
206+
self.table_ten(),
207+
TdAction(f"""
208+
> SET cluster = ir
209+
210+
> CREATE MATERIALIZED VIEW v1 AS SELECT {self.unique_values()} AS f1 FROM {self.join()}
211+
212+
> CREATE DEFAULT INDEX ON v1
213+
214+
> SELECT count(*) = {self.n()} FROM v1
215+
true
216+
"""),
217+
]
218+
219+
def benchmark(self) -> MeasurementSource:
220+
reads = "\n".join(
221+
"> SELECT count(*) > 0 FROM mz_introspection.mz_dataflow_arrangement_sizes\ntrue\n"
222+
for _ in range(self.REPEAT)
223+
)
224+
return Td(f"""
225+
> SET cluster = ir
226+
227+
> SELECT 1
228+
/* A */
229+
1
230+
231+
{reads}
232+
233+
> SELECT 1
234+
/* B */
235+
1
236+
""")
237+
238+
239+
class IntrospectionReadInteractive(IntrospectionRead):
240+
INTERACTIVE = True
241+
242+
243+
class IntrospectionReadSolo(IntrospectionRead):
244+
INTERACTIVE = False

0 commit comments

Comments
 (0)