Skip to content

catalog: Hook up expression cache into startup #30227

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Nov 13, 2024

Conversation

jkosh44
Copy link
Contributor

@jkosh44 jkosh44 commented Oct 28, 2024

This commit hooks up the expression cache into the startup process.
During startup if an expression is found in the cache, then we use that
expression instead of re-optimizing an item. If an expression is not
found in the cache, then we optimize the item and insert the
optimized expression into the cache.

The insertion into the cache happens in bulk as a single operation at
the end of startup instead of once for each object. The reason is that
inserting new expressions may need to invalidate old expressions.
Inserting all expressions in bulk allows us to easily figure out what
should be invalidated vs what shouldn't be invalidated. If we update
the expressions one at a time, then we may accidentally invalidate new
expressions.

Much of the code in this commit involves plumbing things around and
keeping track of what is and isn't cached.

After startup we do not cache newly created items, this is left for
future work. As a result, if environmentd crashes in-between releases
then recovery may be slow if there are many new objects. However,
read-only instances should fully populate the cache during a release.

Works towards resolving #MaterializeInc/database-issues/8384

Motivation

This PR adds a known-desirable feature.

Checklist

  • This PR has adequate test coverage / QA involvement has been duly considered. (trigger-ci for additional test/nightly runs)
  • This PR has an associated up-to-date design doc, is a design doc (template), or is sufficiently small to not require a design.
  • If this PR evolves an existing $T ⇔ Proto$T mapping (possibly in a backwards-incompatible way), then it is tagged with a T-proto label.
  • If this PR will require changes to cloud orchestration or tests, there is a companion cloud PR to account for those changes that is tagged with the release-blocker label (example).
  • If this PR includes major user-facing behavior changes, I have pinged the relevant PM to schedule a changelog post.

@jkosh44 jkosh44 force-pushed the hook-up-expr-cache branch 3 times, most recently from e8d3a28 to 350f435 Compare November 1, 2024 15:06
@jkosh44 jkosh44 force-pushed the hook-up-expr-cache branch 26 times, most recently from 87d3275 to 9fbaec2 Compare November 8, 2024 20:19
@jkosh44 jkosh44 changed the title [WIP] Hook up expr cache catalog: Hook up expression cache into startup Nov 8, 2024
@jkosh44 jkosh44 requested review from aljoscha and def- November 8, 2024 21:43
Copy link
Contributor

@def- def- left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The nightly panics look related: https://buildkite.com/materialize/nightly/builds/10328

Since the cache is supposed to improve performance, can we create a simple feature-benchmark scenario to show that it performs faster now?

One thing I'm worried about here is that the expression cache might hide optimization being slow in other benchmarks. If so, we could disable it in ADDITIONAL_BENCHMARKING_SYSTEM_PARAMETERS in misc/python/materialize/mzcompose/init.py

How does the expression cache work with upgrades? What if the previous optimization led to a wrong plan, do we still keep using the wrong plan after the upgrade?

@jkosh44 jkosh44 force-pushed the hook-up-expr-cache branch 2 times, most recently from 3fc0ed5 to 5402c2f Compare November 11, 2024 01:06
Copy link

shepherdlybot bot commented Nov 11, 2024

Risk Score:83 / 100 Bug Hotspots:3 Resilience Coverage:50%

Mitigations

Completing required mitigations increases Resilience Coverage.

  • (Required) Code Review 🔍 Detected
  • (Required) Feature Flag
  • (Required) Integration Test
  • (Required) Observability 🔍 Detected
  • (Required) QA Review 🔍 Detected
  • (Required) Run Nightly Tests
  • Unit Test
Risk Summary:

The pull request has a high-risk score of 83, driven by predictors such as the average line count in files and executable lines within files. Historically, pull requests with these predictors are 155% more likely to introduce bugs compared to the repository baseline. Additionally, three modified files are identified as hotspots with elevated levels of recent bug fixes. Although the observed bug trend in the repository is increasing, this does not directly impact the risk score.

Note: The risk score is not based on semantic analysis but on historical predictors of bug occurrence in the repository. The attributes above were deemed the strongest predictors based on that history. Predictors and the score may change as the PR evolves in code, time, and review activity.

Bug Hotspots:
What's This?

File Percentile
../catalog/apply.rs 90
../src/coord.rs 98
../catalog/open.rs 92

This commit hooks up the expression cache into the startup process.
During startup if an expression is found in the cache, then we use that
expression instead of re-optimizing an item. If an expression is not
found in the cache, then we optimize the item and insert the
optimized expression into the cache.

The insertion into the cache happens in bulk as a single operation at
the end of startup instead of once for each object. The reason is that
inserting new expressions may need to invalidate old expressions.
Inserting all expressions in bulk allows us to easily figure out what
should be invalidated vs what shouldn't be invalidated. If we update
the expressions one at a time, then we may accidentally invalidate new
expressions.

Much of the code in this commit involves plumbing things around and
keeping track of what is and isn't cached.

After startup we do not cache newly created items, this is left for
future work. As a result, if environmentd crashes in-between releases
then recovery may be slow if there are many new objects. However,
read-only instances should fully populate the cache during a release.

Works towards resolving #MaterializeInc/database-issues/8384
Copy link
Contributor

@aljoscha aljoscha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think all's good but I had one question about a method, see inline, and some questions to check my understanding. Very happy to approve quickly once we sort these out!

@@ -1289,10 +1313,18 @@ impl CatalogState {
let span = info_span!(parent: None, "parse builtin view", name = view.name);
OpenTelemetryContext::obtain().attach_as_parent_to(&span);
let task_state = Arc::clone(&spawn_state);
let cached_expr = local_expression_cache.remove_cached_expression(&id);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are the expressions removed from the cache? Because we expect each one to be used at most once?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes and I didn't want to clone every expression.

let entry = self.get_entry(&on);
let uses = entry.uses();
queue.extend(uses.clone());
seen.extend(uses);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My brain might be too smooth already, but I don't get how this one works. When we start out, queue == seen, so won't the check on seen.insert(cur) always be false, so we don't do anything?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I believe that it is my brain that is the smooth one. This line shouldn't be here. I've pushed a fix.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok(item) => {
Ok((item, uncached_expr)) => {
if let Some((uncached_expr, optimizer_features)) = uncached_expr {
local_expression_cache.insert_uncached_expression(id, uncached_expr, optimizer_features);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this business of cached and uncached expressions? Might be easier to quickly huddle once you're online.

Aha! Now that I read further, it's: uncached expressions = expressions that were not cached but should be added to the cache once we update it. When I first read this, I thought these might be expressions that we don't want to cache or something... 🙈

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that's correct. This was one of the most painful parts of this PR, plumbing everything around to various parts of startup. I've added a doc-comment to this method to try and make it clearer.

| BootstrapStateUpdateKind::IntrospectionSourceIndex(_)
| BootstrapStateUpdateKind::ClusterReplica(_)
| BootstrapStateUpdateKind::SystemObjectMapping(_) => {
| BootstrapStateUpdateKind::ClusterReplica(_) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this re-shuffling needed? Is it because of how we measure/report timings below, for pre_item_updates and sytem_item_updates?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want to open the cache until we've loaded SystemConfiguration, because that contains the dyncfg that tells us whether or not the cache is enabled. However we want to use the cache to load IntrospectionSourceIndex and SystemObjectMapping because those contain system items that sometimes need to be optimized.

So splitting these up into two separate collections allows us to use the cache on system items.

if !current_ids.contains(&key.id)
|| expressions.optimizer_features != *optimizer_features
{
if !current_ids.contains(&key.id) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why'd you move the check for optimizer features out to call-sites?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It turns out that during startup, depending on the context, we fiddle around with the optimizer features. So there's no single OptimizerFeatures that can be used for all expressions.

ListenEvent::Updates(x) => {
ListenEvent::Updates(mut x) => {
consolidate_updates(&mut x);
x.sort_by(|(_, ts1, d1), (_, ts2, d2)| ts1.cmp(ts2).then(d1.cmp(d2)));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why's this now needed? You noticed that something doesn't work right without it?

Copy link
Contributor Author

@jkosh44 jkosh44 Nov 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the panic below on line 158 was triggered in a Nightly test.

assert_eq!(val, prev, "removed val does not match expected val");

We have to process retractions before inserts or else we may retract the wrong value.

@jkosh44
Copy link
Contributor Author

jkosh44 commented Nov 11, 2024

@def-

The nightly panics look related: https://buildkite.com/materialize/nightly/builds/10328

Those should be resolved, but there's still another CI panic that I'm looking into.

Since the cache is supposed to improve performance, can we create a simple feature-benchmark scenario to show that it performs faster now?

I'm hoping that the existing StartupLoaded and StartupTpch benchmarks already show us some speedup. This is what I see in the Nightly logs

t=1731106347294 StartupLoaded                       | wallclock       |           3.735 |           1.798 |   s    |    10%     |    !!YES!!    | worse:   2.1 TIMES slower
t=1731106347294 StartupLoaded                       | memory_mz       |        2443.314 |        2513.885 |   MB   |    20%     |      no       | better:  2.8% less
t=1731106347294 StartupLoaded                       | memory_clusterd |          90.399 |          88.520 |   MB   |    50%     |      no       | worse:   2.1% more
t=1731106347294 StartupTpch                         | wallclock       |           0.782 |           1.594 |   s    |    10%     |      no       | better:  2.0 times faster
t=1731106347294 StartupTpch                         | memory_mz       |         695.229 |         715.351 |   MB   |    20%     |      no       | better:  2.8% less
t=1731106347294 StartupTpch                         | memory_clusterd |         129.032 |         127.316 |   MB   |    50%     |      no       | worse:   1.3% more

t=1731109386350 StartupLoaded                       | wallclock       |           2.198 |           2.603 |   s    |    10%     |      no       | better: 15.6% faster
t=1731109386350 StartupLoaded                       | memory_mz       |        2503.395 |        2514.839 |   MB   |    20%     |      no       | better:  0.5% less
t=1731109386350 StartupLoaded                       | memory_clusterd |          87.700 |          88.863 |   MB   |    50%     |      no       | better:  1.3% less
t=1731109386350 StartupTpch                         | wallclock       |           0.759 |           1.586 |   s    |    10%     |      no       | better:  2.1 times faster
t=1731109386350 StartupTpch                         | memory_mz       |         704.956 |         711.536 |   MB   |    20%     |      no       | better:  0.9% less
t=1731109386350 StartupTpch                         | memory_clusterd |         127.506 |         127.792 |   MB   |    50%     |      no       | better:  0.2% less

t=1731112176371 StartupLoaded                       | wallclock       |           2.234 |           1.774 |   s    |    10%     |    !!YES!!    | worse:  25.9% slower
t=1731112176371 StartupLoaded                       | memory_mz       |        2506.256 |        2501.488 |   MB   |    20%     |      no       | worse:   0.2% more
t=1731112176371 StartupLoaded                       | memory_clusterd |          91.410 |          88.902 |   MB   |    50%     |      no       | worse:   2.8% more
t=1731112176371 StartupTpch                         | wallclock       |           0.791 |           1.695 |   s    |    10%     |      no       | better:  2.1 times faster
t=1731112176371 StartupTpch                         | memory_mz       |         700.951 |         717.354 |   MB   |    20%     |      no       | better:  2.3% less
t=1731112176372 StartupTpch                         | memory_clusterd |         126.266 |         127.411 |   MB   |    50%     |      no       | better:  0.9% less

t=1731115646627 StartupLoaded                       | wallclock       |           0.983 |           1.890 |   s    |    10%     |      no       | better: 48.0% faster
t=1731115646627 StartupLoaded                       | memory_mz       |        2472.878 |        2497.673 |   MB   |    20%     |      no       | better:  1.0% less
t=1731115646627 StartupLoaded                       | memory_clusterd |          90.332 |          88.844 |   MB   |    50%     |      no       | worse:   1.7% more
t=1731115646627 StartupTpch                         | wallclock       |           0.812 |           1.660 |   s    |    10%     |      no       | better:  2.0 times faster
t=1731115646627 StartupTpch                         | memory_mz       |         701.141 |         720.692 |   MB   |    20%     |      no       | better:  2.7% less
t=1731115646627 StartupTpch                         | memory_clusterd |         128.078 |         127.983 |   MB   |    50%     |      no       | worse:   0.1% more

t=1731118496491 StartupLoaded                       | wallclock       |           2.198 |           1.778 |   s    |    10%     |    !!YES!!    | worse:  23.6% slower
t=1731118496491 StartupLoaded                       | memory_mz       |        2490.997 |        2500.534 |   MB   |    20%     |      no       | better:  0.4% less
t=1731118496491 StartupLoaded                       | memory_clusterd |          88.177 |          87.051 |   MB   |    50%     |      no       | worse:   1.3% more
t=1731118496491 StartupTpch                         | wallclock       |           0.795 |           1.786 |   s    |    10%     |      no       | better:  2.2 times faster
t=1731118496491 StartupTpch                         | memory_mz       |         709.724 |         723.362 |   MB   |    20%     |      no       | better:  1.9% less
t=1731118496491 StartupTpch                         | memory_clusterd |         126.934 |         127.983 |   MB   |    50%     |      no       | better:  0.8% less

The results seem all over the place so it's hard to tell what's going on. I'll look into it and make sure that the expression cache is even being used here.

One thing I'm worried about here is that the expression cache might hide optimization being slow in other benchmarks. If so, we could disable it in ADDITIONAL_BENCHMARKING_SYSTEM_PARAMETERS in misc/python/materialize/mzcompose/init.py

The cache is ONLY used during startup, so it shouldn't hide the latency when creating new objects or when running SELECT, which is what I'm assuming the other benchmarks do.

How does the expression cache work with upgrades?

Each optimized expression is tagged with the deploy generation that it was created in. An environmentd process will only look at expressions with the same deploy generation. So when a new version starts for the first time it not use any cached expressions and create them all from scratch.

What if the previous optimization led to a wrong plan, do we still keep using the wrong plan after the upgrade?

No, due to the deploy generation described above.

@jkosh44
Copy link
Contributor Author

jkosh44 commented Nov 11, 2024

Here's a more recent benchmark run, still sort of all over the place.

t=1731297998330 StartupLoaded                       | wallclock       |           1.165 |           1.729 |   s    |    10%     |      no       | better: 32.6% faster 
t=1731297998330 StartupLoaded                       | memory_mz       |        2521.515 |        2489.090 |   MB   |    20%     |      no       | worse:   1.3% more 
t=1731297998330 StartupLoaded                       | memory_clusterd |          89.016 |          88.167 |   MB   |    50%     |      no       | worse:   1.0% more 
t=1731297998330 StartupTpch                         | wallclock       |           0.851 |           1.722 |   s    |    10%     |      no       | better:  2.0 times faster 
t=1731297998330 StartupTpch                         | memory_mz       |         712.204 |         709.438 |   MB   |    20%     |      no       | worse:   0.4% more 
t=1731297998330 StartupTpch                         | memory_clusterd |         128.555 |         129.509 |   MB   |    50%     |      no       | better:  0.7% less 

t=1731300976186 StartupLoaded                       | wallclock       |           1.224 |           1.606 |   s    |    10%     |      no       | better: 23.8% faster 
t=1731300976186 StartupLoaded                       | memory_mz       |        2502.441 |        2493.858 |   MB   |    20%     |      no       | worse:   0.3% more 
t=1731300976186 StartupLoaded                       | memory_clusterd |          88.654 |          89.130 |   MB   |    50%     |      no       | better:  0.5% less 
t=1731300976186 StartupTpch                         | wallclock       |           0.864 |           1.693 |   s    |    10%     |      no       | better: 49.0% faster 
t=1731300976186 StartupTpch                         | memory_mz       |         692.844 |         725.937 |   MB   |    20%     |      no       | better:  4.6% less 
t=1731300976186 StartupTpch                         | memory_clusterd |         128.174 |         127.220 |   MB   |    50%     |      no       | worse:   0.7% more 

t=1731303977127 StartupLoaded                       | wallclock       |           1.281 |           1.707 |   s    |    10%     |      no       | better: 25.0% faster 
t=1731303977127 StartupLoaded                       | memory_mz       |        2431.870 |        2508.163 |   MB   |    20%     |      no       | better:  3.0% less 
t=1731303977127 StartupLoaded                       | memory_clusterd |          88.453 |          89.760 |   MB   |    50%     |      no       | better:  1.5% less 
t=1731303977127 StartupTpch                         | wallclock       |           0.844 |           1.721 |   s    |    10%     |      no       | better:  2.0 times faster 
t=1731303977127 StartupTpch                         | memory_mz       |         695.896 |         712.109 |   MB   |    20%     |      no       | better:  2.3% less 

t=1731307216286 StartupLoaded                       | wallclock       |           2.169 |           1.644 |   s    |    10%     |    !!YES!!    | worse:  32.0% slower 
t=1731307216286 StartupLoaded                       | memory_mz       |        2521.515 |        2533.913 |   MB   |    20%     |      no       | better:  0.5% less 
t=1731307216286 StartupLoaded                       | memory_clusterd |          91.467 |          86.546 |   MB   |    50%     |      no       | worse:   5.7% more 
t=1731307216286 StartupTpch                         | wallclock       |           0.848 |           1.709 |   s    |    10%     |      no       | better:  2.0 times faster 
t=1731307216286 StartupTpch                         | memory_mz       |         704.861 |         723.171 |   MB   |    20%     |      no       | better:  2.5% less 
t=1731307216286 StartupTpch                         | memory_clusterd |         128.174 |         127.029 |   MB   |    50%     |      no       | worse:   0.9% more 

t=1731310059290 StartupLoaded                       | wallclock       |           3.195 |           1.654 |   s    |    10%     |    !!YES!!    | worse:  93.1% slower 
t=1731310059290 StartupLoaded                       | memory_mz       |        2497.673 |        2524.376 |   MB   |    20%     |      no       | better:  1.1% less 
t=1731310059290 StartupLoaded                       | memory_clusterd |          87.690 |          87.700 |   MB   |    50%     |      no       | better:  0.0% less 
t=1731310059290 StartupTpch                         | wallclock       |           0.846 |           1.777 |   s    |    10%     |      no       | better:  2.1 times faster 
t=1731310059290 StartupTpch                         | memory_mz       |         698.662 |         722.599 |   MB   |    20%     |      no       | better:  3.3% less 
t=1731310059290 StartupTpch                         | memory_clusterd |         127.697 |         129.318 |   MB   |    50%     |      no       | better:  1.3% less 

@jkosh44
Copy link
Contributor Author

jkosh44 commented Nov 11, 2024

@def-

return TdAction(
f"""
$ postgres-connect name=mz_system url=postgres://mz_system:materialize@${{testdrive.materialize-internal-sql-addr}}
$ postgres-execute connection=mz_system
ALTER SYSTEM SET max_objects_per_schema = {self.n() * 10};
ALTER SYSTEM SET max_materialized_views = {self.n() * 2};
ALTER SYSTEM SET max_sources = {self.n() * 2};
ALTER SYSTEM SET max_sinks = {self.n() * 2};
ALTER SYSTEM SET max_tables = {self.n() * 2};
ALTER SYSTEM SET max_clusters = {self.n() * 6};
> DROP OWNED BY materialize CASCADE;
>[version<7800] CREATE CONNECTION IF NOT EXISTS s1_kafka_conn TO KAFKA (BROKER '${{testdrive.kafka-addr}}');
>[version>=7800] CREATE CONNECTION IF NOT EXISTS s1_kafka_conn TO KAFKA (BROKER '${{testdrive.kafka-addr}}', SECURITY PROTOCOL PLAINTEXT);
> CREATE CONNECTION IF NOT EXISTS s1_csr_conn
FOR CONFLUENT SCHEMA REGISTRY
URL '${{testdrive.schema-registry-url}}';
{create_tables}
{create_sources}
{create_views}
{create_sinks}
"""
)

If I wanted to restart Materialize here BEFORE we start timing for the benchmark, how would I do that?

Comment on lines 218 to 227
// Remove dropped IDs and expressions that rely on dropped indexes.
let index_dependencies: BTreeSet<_> = expressions
.global_mir
.index_imports
.keys()
.chain(expressions.physical_plan.index_imports.keys())
.cloned()
.collect();
if !current_ids.contains(&key.id)
|| expressions.optimizer_features != *optimizer_features
|| !index_dependencies.is_subset(current_ids)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ggevay does this make sense in terms of the calls to index_imports?

This is called during startup. I have a set of all the items in the catalog, current_ids. I'm trying to remove any expression from the cache that may rely on an index that no longer exists, i.e. doesn't exist in current_ids. Should I also be looking in other places inside of expressions?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at index_imports should be enough: A dataflow can use an index only if the index is imported.

(Note that, currently, the index_imports of MIR and LIR plan are the same, so strictly speaking it would be enough to look at only one of them. But I think it's good practice if you check both here (as it is currently done in your PR), so that your code is future-proof against possible changes where the MIR and LIR index_imports maybe drift apart.)

@def-
Copy link
Contributor

def- commented Nov 11, 2024

@def-

return TdAction(
f"""
$ postgres-connect name=mz_system url=postgres://mz_system:materialize@${{testdrive.materialize-internal-sql-addr}}
$ postgres-execute connection=mz_system
ALTER SYSTEM SET max_objects_per_schema = {self.n() * 10};
ALTER SYSTEM SET max_materialized_views = {self.n() * 2};
ALTER SYSTEM SET max_sources = {self.n() * 2};
ALTER SYSTEM SET max_sinks = {self.n() * 2};
ALTER SYSTEM SET max_tables = {self.n() * 2};
ALTER SYSTEM SET max_clusters = {self.n() * 6};
> DROP OWNED BY materialize CASCADE;
>[version<7800] CREATE CONNECTION IF NOT EXISTS s1_kafka_conn TO KAFKA (BROKER '${{testdrive.kafka-addr}}');
>[version>=7800] CREATE CONNECTION IF NOT EXISTS s1_kafka_conn TO KAFKA (BROKER '${{testdrive.kafka-addr}}', SECURITY PROTOCOL PLAINTEXT);
> CREATE CONNECTION IF NOT EXISTS s1_csr_conn
FOR CONFLUENT SCHEMA REGISTRY
URL '${{testdrive.schema-registry-url}}';
{create_tables}
{create_sources}
{create_views}
{create_sinks}
"""
)

If I wanted to restart Materialize here BEFORE we start timing for the benchmark, how would I do that?

Simply add a /* A */ part in the beginning of the Testdrive fragment, that marks the beginning of the time measurement when it exists, something like this:

diff --git a/misc/python/materialize/feature_benchmark/scenarios/benchmark_main.py b/misc/python/materialize/feature_benchmark/scenarios/benchmark_main.py
index 3c2f4a5a40..b631a2eaf8 100644
--- a/misc/python/materialize/feature_benchmark/scenarios/benchmark_main.py
+++ b/misc/python/materialize/feature_benchmark/scenarios/benchmark_main.py
@@ -1966,6 +1966,9 @@ ALTER SYSTEM SET max_clusters = {self.n() * 6};
             Lambda(lambda e: e.RestartMzClusterd()),
             Td(
                 f"""
+> SELECT 1;
+  /* A */
+1
 {check_views}
 {check_sources}
 {check_tables}

@jkosh44
Copy link
Contributor Author

jkosh44 commented Nov 11, 2024

I want to include the restart time in the time measurements of each iteration. I just also want to restart Materialize once at the very beginning of the test before we start measuring the other restarts.

@def-
Copy link
Contributor

def- commented Nov 12, 2024

The first measurement is disregarded anyway, so this should already do what you want by default?

@jkosh44
Copy link
Contributor Author

jkosh44 commented Nov 12, 2024

The first measurement is disregarded anyway, so this should already do what you want by default?

Ah ok, yeah so it should already be doing exactly what I want.

…k-up-expr-cache

# Conflicts:
#	src/adapter/src/catalog.rs
#	src/adapter/src/catalog/apply.rs
#	src/adapter/src/catalog/open/builtin_item_migration.rs
#	src/adapter/src/catalog/state.rs
#	src/adapter/src/coord.rs
@jkosh44 jkosh44 merged commit ef09718 into MaterializeInc:main Nov 13, 2024
210 of 220 checks passed
@jkosh44 jkosh44 deleted the hook-up-expr-cache branch November 13, 2024 21:49
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.

4 participants