materialized-view-refresh-options.td 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  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. $ set-sql-timeout duration=60s
  10. $ postgres-execute connection=postgres://mz_system@${testdrive.materialize-internal-sql-addr}/materialize
  11. ALTER SYSTEM SET enable_refresh_every_mvs = true
  12. ALTER SYSTEM SET enable_cluster_schedule_refresh = true
  13. ALTER SYSTEM SET unsafe_enable_unstable_dependencies = true
  14. ALTER SYSTEM SET cluster_refresh_mv_compaction_estimate = 0
  15. > CREATE DATABASE materialized_view_refresh_options;
  16. > SET DATABASE = materialized_view_refresh_options;
  17. > CREATE TABLE t1(x int);
  18. > INSERT INTO t1 VALUES (1);
  19. # This refresh interval needs to be not too small and not too big. See the constraints in comments below.
  20. > CREATE MATERIALIZED VIEW mv1
  21. WITH (REFRESH EVERY '8sec')
  22. AS SELECT x+x as x2 FROM t1;
  23. > INSERT INTO t1 VALUES (3);
  24. # The following will not immediately return the recently inserted values, but Testdrive will wait.
  25. # Warning: This test assumes that Testdrive's timeout is greater than the above refresh interval.
  26. > SELECT * FROM mv1;
  27. 2
  28. 6
  29. > INSERT INTO t1 VALUES (4);
  30. # What we just inserted shouldn't be in the mv yet, because we are just after a refresh (because the previous SELECT
  31. # returned correct results only after a refresh).
  32. # Warning: this test assumes that the above INSERT completes within the above refresh interval. If we have some
  33. # transient infrastructure problem that makes the INSERT really slow, then this test will fail.
  34. > SELECT * FROM mv1;
  35. 2
  36. 6
  37. > SELECT * FROM mv1;
  38. 2
  39. 6
  40. 8
  41. # Check that I can query it together with other objects, even between refreshes, and that data added later than the last
  42. # refresh in other objects is reflected in the result.
  43. > CREATE MATERIALIZED VIEW mv2
  44. WITH (REFRESH = EVERY '10000sec')
  45. AS SELECT x+x as x2 FROM t1;
  46. > CREATE TABLE t2(y int);
  47. > INSERT INTO t2 VALUES (100);
  48. > (SELECT * from mv2) UNION (SELECT * FROM t2);
  49. 2
  50. 6
  51. 8
  52. 100
  53. # The following DELETE shouldn't affect mv2, because mv2 has a very large refresh interval.
  54. > DELETE FROM t1;
  55. > (SELECT * from mv2) UNION (SELECT * FROM t2);
  56. 2
  57. 6
  58. 8
  59. 100
  60. # Check that there is an implicit refresh immediately at the creation of the MV, even if it's REFRESH EVERY.
  61. > CREATE MATERIALIZED VIEW mv3
  62. WITH (REFRESH EVERY '10000sec')
  63. AS SELECT y+y as y2 FROM t2;
  64. > SELECT * FROM mv3;
  65. 200
  66. # Check that mz_now() occurring in the original statement works. This tests that after we purify away `mz_now()`, we
  67. # also remove it from `resolved_ids`. Importantly, this has to be a Testdrive test, and not an slt test, because slt
  68. # doesn't do the "the in-memory state of the catalog does not match its on-disk state" check.
  69. #
  70. # Also tests that planning uses `cast_to` with `CastContext::Implicit` (instead of `type_as`) when planning the
  71. # REFRESH AT.
  72. > CREATE MATERIALIZED VIEW mv4
  73. WITH (REFRESH AT mz_now()::string::int8 + 2000)
  74. AS SELECT y*y as y2 FROM t2;
  75. > SELECT * FROM mv4;
  76. 10000
  77. ## Test turning replicas off and on, part 1:
  78. ## First, we check the following two things:
  79. ## - 1a. Turn the replica off just after a refresh, and then turn the replica back on immediately.
  80. ## - 1b. Turn the replica off just after a refresh, and then turn the replica back on only after the next refresh time
  81. ## has passed.
  82. > CREATE CLUSTER refresh_cluster SIZE = '1', REPLICATION FACTOR = 1;
  83. > SET cluster = refresh_cluster;
  84. > CREATE MATERIALIZED VIEW mv5
  85. WITH (REFRESH EVERY '8 sec' ALIGNED TO mz_now()::text::int8 + 5000)
  86. AS SELECT 3*y as y2 FROM t2;
  87. > SET cluster = default;
  88. > SELECT * FROM mv5;
  89. 300
  90. > INSERT INTO t2 VALUES (102);
  91. # Wait until the insert is reflected, so that we are just after a refresh. This is important, because otherwise the
  92. # below `SET (REPLICATION FACTOR 0)` and the `SELECT` after that might straddle a refresh, in which case the `SELECT`
  93. # would hang forever.
  94. > SELECT * FROM mv5;
  95. 300
  96. 306
  97. > ALTER CLUSTER refresh_cluster SET (REPLICATION FACTOR 0);
  98. # We should be able to query the MV even if there is no replica.
  99. > SELECT * FROM mv5;
  100. 300
  101. 306
  102. > ALTER CLUSTER refresh_cluster SET (REPLICATION FACTOR 1);
  103. > SELECT * FROM mv5;
  104. 300
  105. 306
  106. > INSERT INTO t2 VALUES (110);
  107. # Wait until the insert is reflected, so we are just after a refresh.
  108. > SELECT * FROM mv5;
  109. 300
  110. 306
  111. 330
  112. # Turn off the cluster, and insert something, and then sleep through a scheduled refresh. (1b.)
  113. > ALTER CLUSTER refresh_cluster SET (REPLICATION FACTOR 0);
  114. > INSERT INTO t2 VALUES (120);
  115. # (See the explanation for the `+2` in materialized_views.slt at a similar `mz_sleep`.)
  116. > SELECT mz_unsafe.mz_sleep(8+2);
  117. <null>
  118. # Turn it back on, and check that we recover. Data that were added while we slept should be visible now.
  119. > ALTER CLUSTER refresh_cluster SET (REPLICATION FACTOR 1);
  120. > SELECT * FROM mv5;
  121. 300
  122. 306
  123. 330
  124. 360
  125. ## Test turning replicas off and on, part 2:
  126. ## No replica during MV creation.
  127. > ALTER CLUSTER refresh_cluster SET (REPLICATION FACTOR 0);
  128. > CREATE MATERIALIZED VIEW mv_no_rep
  129. IN CLUSTER refresh_cluster
  130. WITH (REFRESH EVERY '8 sec')
  131. AS SELECT 10*y as y2 FROM t2;
  132. > ALTER CLUSTER refresh_cluster SET (REPLICATION FACTOR 1);
  133. > SELECT * FROM mv_no_rep;
  134. 1000
  135. 1020
  136. 1100
  137. 1200
  138. ## Test turning replicas off and on, part 3:
  139. ## Turn the replica off _during_ the first refresh, and then turn the replica back on immediately.
  140. > CREATE TABLE tg (a int);
  141. > INSERT INTO tg VALUES (1000000);
  142. # Refreshing this will take a non-trivial amount of time.
  143. # The `*2/2` stuff is to make it take more CPU time without increasing memory consumption.
  144. > CREATE MATERIALIZED VIEW mv_gs
  145. IN CLUSTER refresh_cluster
  146. WITH (REFRESH AT CREATION) AS
  147. SELECT sum(x*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2)
  148. FROM (SELECT generate_series(1,a) as x FROM tg);
  149. > ALTER CLUSTER refresh_cluster SET (REPLICATION FACTOR 0);
  150. > ALTER CLUSTER refresh_cluster SET (REPLICATION FACTOR 1);
  151. > SELECT * FROM mv_gs;
  152. 500000500000
  153. # `mv_gs` consumes a non-trivial amount of memory because of the big `generate_series`, so let's drop it.
  154. > DROP MATERIALIZED VIEW mv_gs;
  155. > SELECT mz_unsafe.mz_sleep(1);
  156. <null>
  157. ## Test turning replicas off and on, part 4:
  158. ## - Turn the replica off while it's in a non-caught-up state after an input change.
  159. ## - Turn the replica off while it's still rehydrating after turning a replica on.
  160. ## - More than 1 replicas.
  161. ## - MV that reads from an index.
  162. > DELETE FROM tg;
  163. > INSERT INTO tg VALUES (100);
  164. > CREATE MATERIALIZED VIEW mv_gs2
  165. IN CLUSTER refresh_cluster
  166. WITH (REFRESH EVERY '4 sec') AS
  167. SELECT sum(x*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2)
  168. FROM (SELECT generate_series(1,a) as x FROM tg);
  169. > CREATE DEFAULT INDEX
  170. IN CLUSTER refresh_cluster
  171. ON tg;
  172. > CREATE MATERIALIZED VIEW mv_gs2_index
  173. IN CLUSTER refresh_cluster
  174. WITH (REFRESH EVERY '4 sec') AS
  175. SELECT sum(x*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2*2/2)
  176. FROM (SELECT generate_series(1,a) as x FROM tg);
  177. # Wait for the first refresh.
  178. > SELECT * FROM mv_gs2;
  179. 5050
  180. > SELECT * FROM mv_gs2_index;
  181. 5050
  182. > INSERT INTO tg VALUES (1000000);
  183. # Mess with the replicas before the MV could catch up with the above insert.
  184. > ALTER CLUSTER refresh_cluster SET (REPLICATION FACTOR 0);
  185. > ALTER CLUSTER refresh_cluster SET (REPLICATION FACTOR 2);
  186. > SELECT mz_unsafe.mz_sleep(0.5);
  187. <null>
  188. > ALTER CLUSTER refresh_cluster SET (REPLICATION FACTOR 0);
  189. > ALTER CLUSTER refresh_cluster SET (REPLICATION FACTOR 2);
  190. # Check that we recover.
  191. > SELECT * FROM mv_gs2;
  192. 500000505050
  193. > SELECT * FROM mv_gs2_index;
  194. 500000505050
  195. > DROP MATERIALIZED VIEW mv_gs2;
  196. > DROP MATERIALIZED VIEW mv_gs2_index;
  197. ## REFRESH AT + REFRESH EVERY
  198. > CREATE TABLE t3(x int);
  199. > INSERT INTO t3 VALUES (1);
  200. > CREATE MATERIALIZED VIEW mv6 WITH (REFRESH AT mz_now()::text::int8 + 6000, REFRESH EVERY '8 seconds') AS SELECT * FROM t3;
  201. > SELECT * FROM mv6
  202. 1
  203. > INSERT INTO t3 VALUES (2);
  204. > SELECT * FROM mv6
  205. 1
  206. 2
  207. > SELECT mz_unsafe.mz_sleep(8+2);
  208. <null>
  209. > INSERT INTO t3 VALUES (3);
  210. > SELECT * FROM mv6
  211. 1
  212. 2
  213. 3
  214. # Test that MVs that advance to the empty frontier do not retain read holds on
  215. # their inputs. Regression test for database-issues#7308.
  216. > CREATE TABLE t4 (x int)
  217. > CREATE MATERIALIZED VIEW mv7 WITH (REFRESH AT CREATION) AS SELECT * FROM t4
  218. > SELECT * FROM mv7
  219. > SELECT f.write_frontier
  220. FROM mz_internal.mz_frontiers f
  221. JOIN mz_materialized_views m ON (m.id = f.object_id)
  222. WHERE m.name = 'mv7'
  223. <null>
  224. # Verify that `t4`'s read frontier advances past the read frontier of `mv7`.
  225. > SELECT ft.read_frontier > fm.read_frontier
  226. FROM mz_internal.mz_frontiers fm
  227. JOIN mz_materialized_views m ON (m.id = fm.object_id)
  228. JOIN mz_internal.mz_frontiers ft ON (true)
  229. JOIN mz_tables t ON (t.id = ft.object_id)
  230. WHERE m.name = 'mv7' AND t.name = 't4'
  231. true
  232. # Test the same thing with multiple replicas.
  233. > DROP MATERIALIZED VIEW mv7
  234. > ALTER CLUSTER refresh_cluster SET (REPLICATION FACTOR 2);
  235. > CREATE MATERIALIZED VIEW mv7
  236. IN CLUSTER refresh_cluster
  237. WITH (REFRESH AT CREATION)
  238. AS SELECT * FROM t4
  239. > SELECT * FROM mv7
  240. > SELECT f.write_frontier
  241. FROM mz_internal.mz_frontiers f
  242. JOIN mz_materialized_views m ON (m.id = f.object_id)
  243. WHERE m.name = 'mv7'
  244. <null>
  245. > SELECT ft.read_frontier > fm.read_frontier
  246. FROM mz_internal.mz_frontiers fm
  247. JOIN mz_materialized_views m ON (m.id = fm.object_id)
  248. JOIN mz_internal.mz_frontiers ft ON (true)
  249. JOIN mz_tables t ON (t.id = ft.object_id)
  250. WHERE m.name = 'mv7' AND t.name = 't4'
  251. true
  252. # Test the same thing with initially zero replicas.
  253. > DROP MATERIALIZED VIEW mv7
  254. > ALTER CLUSTER refresh_cluster SET (REPLICATION FACTOR 0);
  255. > CREATE MATERIALIZED VIEW mv7
  256. IN CLUSTER refresh_cluster
  257. WITH (REFRESH AT CREATION)
  258. AS SELECT * FROM t4
  259. > ALTER CLUSTER refresh_cluster SET (REPLICATION FACTOR 1);
  260. > SELECT * FROM mv7
  261. > SELECT f.write_frontier
  262. FROM mz_internal.mz_frontiers f
  263. JOIN mz_materialized_views m ON (m.id = f.object_id)
  264. WHERE m.name = 'mv7'
  265. <null>
  266. > SELECT ft.read_frontier > fm.read_frontier
  267. FROM mz_internal.mz_frontiers fm
  268. JOIN mz_materialized_views m ON (m.id = fm.object_id)
  269. JOIN mz_internal.mz_frontiers ft ON (true)
  270. JOIN mz_tables t ON (t.id = ft.object_id)
  271. WHERE m.name = 'mv7' AND t.name = 't4'
  272. true
  273. # Test that the warmup optimization works, i.e. a REFRESH MV can hydrate prior
  274. # to the next refresh time.
  275. > CREATE TABLE t5 (x int)
  276. > CREATE MATERIALIZED VIEW mv8
  277. IN CLUSTER refresh_cluster
  278. WITH (REFRESH AT CREATION, REFRESH AT mz_now()::string::int8 + 1000000)
  279. AS SELECT * FROM t5
  280. > SELECT * FROM mv8
  281. > ALTER CLUSTER refresh_cluster SET (REPLICATION FACTOR 2)
  282. > SELECT r.name, h.hydrated
  283. FROM mz_internal.mz_hydration_statuses h
  284. JOIN mz_materialized_views m ON (m.id = h.object_id)
  285. JOIN mz_cluster_replicas r ON (r.id = h.replica_id)
  286. WHERE m.name = 'mv8'
  287. r1 true
  288. r2 true
  289. ## Warmup before the first refresh
  290. # MV with a first refresh in the far future
  291. > CREATE MATERIALIZED VIEW mv9 WITH (REFRESH AT mz_now()::text::int8 + 1000000) AS
  292. SELECT x*x FROM t3;
  293. # Check that all operators have hydrated.
  294. > SELECT DISTINCT hydrated
  295. FROM mz_internal.mz_hydration_statuses h JOIN mz_objects o ON (h.object_id = o.id)
  296. WHERE name = 'mv9';
  297. true
  298. # Try the same with a less trivial MV. (In particular, hydration behaves differently when we have a pipeline breaker,
  299. # such as an arrangement.)
  300. > CREATE MATERIALIZED VIEW mv10 WITH (REFRESH AT mz_now()::text::int8 + 1000000) AS
  301. SELECT DISTINCT x, y FROM t2, t3;
  302. > SELECT DISTINCT hydrated
  303. FROM mz_internal.mz_hydration_statuses h JOIN mz_objects o ON (h.object_id = o.id)
  304. WHERE name = 'mv10';
  305. true
  306. # ----------------------------------------
  307. # Automated cluster scheduling for REFRESH
  308. # ----------------------------------------
  309. > CREATE CLUSTER scheduled_cluster (SIZE = '1', SCHEDULE = ON REFRESH);
  310. # No MV yet, so the cluster should be turned off.
  311. > SELECT replication_factor FROM mz_catalog.mz_clusters WHERE name = 'scheduled_cluster';
  312. 0
  313. > CREATE MATERIALIZED VIEW mv11
  314. IN CLUSTER scheduled_cluster
  315. WITH (REFRESH = EVERY '8 sec')
  316. AS SELECT count(*) FROM t2;
  317. # The cluster should be turned on at some point.
  318. > SELECT replication_factor FROM mz_catalog.mz_clusters WHERE name = 'scheduled_cluster';
  319. 1
  320. # And then the cluster should compute MV results.
  321. > SELECT * FROM mv11;
  322. 4
  323. # Seems to take a while in k8s
  324. $ set-max-tries max-tries=5000
  325. # The cluster should be turned off at some point.
  326. > SELECT replication_factor FROM mz_catalog.mz_clusters WHERE name = 'scheduled_cluster';
  327. 0
  328. # We should have a "drop" in `mz_audit_events`
  329. > SELECT count(*) > 0
  330. FROM mz_audit_events
  331. WHERE
  332. event_type = 'drop' AND
  333. object_type = 'cluster-replica' AND
  334. (details->'cluster_name')::text = '"scheduled_cluster"' AND
  335. user IS NULL;
  336. true
  337. > DELETE FROM t2;
  338. # The cluster should be turned on at some point again.
  339. > SELECT replication_factor FROM mz_catalog.mz_clusters WHERE name = 'scheduled_cluster';
  340. 1
  341. # And then the cluster should compute MV results again.
  342. > SELECT * FROM mv11;
  343. 0
  344. # We should have a "create" in `mz_audit_events`
  345. > SELECT count(*) > 0
  346. FROM mz_audit_events
  347. WHERE
  348. event_type = 'create' AND
  349. object_type = 'cluster-replica' AND
  350. (details->'cluster_name')::text = '"scheduled_cluster"' AND
  351. user IS NULL;
  352. true
  353. # Things should keep working if we switch from managed to unmanaged cluster and then back.
  354. > ALTER CLUSTER scheduled_cluster SET (MANAGED = false, SCHEDULE = MANUAL);
  355. > ALTER CLUSTER scheduled_cluster SET (MANAGED = true, SIZE = '1', SCHEDULE = ON REFRESH);
  356. > INSERT INTO t2 VALUES (64);
  357. > SELECT * FROM mv11;
  358. 1
  359. ## When we create an MV whose first refresh is in the far future, we should immediately turn on the cluster briefly, so
  360. ## that the Persist shard's write frontier moves from 0 to the first refresh time.
  361. > CREATE CLUSTER scheduled_cluster_2 (SIZE = '1', SCHEDULE = ON REFRESH);
  362. > SELECT replication_factor FROM mz_catalog.mz_clusters WHERE name = 'scheduled_cluster_2';
  363. 0
  364. > CREATE MATERIALIZED VIEW mv12
  365. IN CLUSTER scheduled_cluster_2
  366. WITH (REFRESH AT '3000-01-01 23:59')
  367. AS SELECT sum(y) FROM t2;
  368. # The MV's write frontier should move away from 0.
  369. > SELECT f.write_frontier > 0
  370. FROM mz_internal.mz_frontiers f
  371. JOIN mz_materialized_views m ON (m.id = f.object_id)
  372. WHERE m.name = 'mv12'
  373. true
  374. # But then the cluster should turn off.
  375. > SELECT replication_factor FROM mz_catalog.mz_clusters WHERE name = 'scheduled_cluster_2';
  376. 0
  377. ## Unbilled replicas.
  378. ## - The auto scheduling won't create or drop unbilled replicas.
  379. ## - But unbilled replicas can affect the auto scheduling: If a cluster has an unbilled replica at the moment when a
  380. ## refresh should happen, the unbilled replica might complete the refresh before the auto scheduling has a chance to
  381. ## create a replica. (However, it's not guaranteed that an unbilled replica will prevent the auto scheduling from
  382. ## creating a replica.)
  383. # Creating an unbilled replica on a `SCHEDULE = ON REFRESH` cluster shouldn't blow things up.
  384. $ postgres-connect name=mz_system url=postgres://mz_system:materialize@${testdrive.materialize-internal-sql-addr}
  385. $ postgres-execute connection=mz_system
  386. CREATE CLUSTER REPLICA scheduled_cluster.unbilled SIZE '2-2', BILLED AS 'free', INTERNAL;
  387. > INSERT INTO t2 VALUES (200);
  388. > SELECT * FROM mv11;
  389. 2
  390. # Unbilled is not auto-dropped.
  391. > SELECT r.name
  392. FROM mz_catalog.mz_cluster_replicas r, mz_catalog.mz_clusters c
  393. WHERE c.id = r.cluster_id AND c.name = 'scheduled_cluster';
  394. unbilled
  395. > SELECT mz_unsafe.mz_sleep(3);
  396. <null>
  397. > SELECT r.name
  398. FROM mz_catalog.mz_cluster_replicas r, mz_catalog.mz_clusters c
  399. WHERE c.id = r.cluster_id AND c.name = 'scheduled_cluster';
  400. unbilled
  401. # Things continue normally after the unbilled is (manually) dropped.
  402. $ postgres-execute connection=mz_system
  403. DROP CLUSTER REPLICA scheduled_cluster.unbilled;
  404. > INSERT INTO t2 VALUES (99);
  405. > SELECT * FROM mv11;
  406. 3
  407. ## HYDRATION TIME ESTIMATE
  408. > CREATE CLUSTER c_schedule_6 (SIZE = '1', SCHEDULE = ON REFRESH (HYDRATION TIME ESTIMATE = '995 seconds'));
  409. > CREATE CLUSTER c_schedule_7 (SIZE = '1');
  410. > ALTER CLUSTER c_schedule_7 SET (SCHEDULE = ON REFRESH (HYDRATION TIME ESTIMATE = '995 seconds'));
  411. # Create MVs whose first refresh is 1000 seconds from now.
  412. > CREATE MATERIALIZED VIEW mv13
  413. IN CLUSTER c_schedule_6
  414. WITH (REFRESH AT mz_now()::string::int8 + 1000 * 1000)
  415. AS SELECT count(*) FROM t2;
  416. > CREATE MATERIALIZED VIEW mv14
  417. IN CLUSTER c_schedule_7
  418. WITH (REFRESH AT mz_now()::string::int8 + 1000 * 1000)
  419. AS SELECT count(*) FROM t2;
  420. # Should be turned on soon due to the HYDRATION TIME ESTIMATE.
  421. > SELECT replication_factor FROM mz_catalog.mz_clusters WHERE name = 'c_schedule_6';
  422. 1
  423. > SELECT replication_factor FROM mz_catalog.mz_clusters WHERE name = 'c_schedule_7';
  424. 1
  425. # ----------------------------------------
  426. # Introspection
  427. # ----------------------------------------
  428. > SET cluster = refresh_cluster;
  429. ## Create MVs for checking `mz_materialized_view_refreshes`.
  430. # Const MVs, only REFRESH ATs
  431. > CREATE MATERIALIZED VIEW mv14_at_const
  432. WITH (REFRESH AT '3000-01-01 23:59')
  433. AS SELECT 1;
  434. > CREATE MATERIALIZED VIEW mv15_ats_const
  435. WITH (REFRESH AT '2500-01-01 23:59', REFRESH AT '3000-01-01 23:59')
  436. AS SELECT 1;
  437. > CREATE MATERIALIZED VIEW mv_at_creation
  438. WITH (REFRESH AT CREATION)
  439. AS SELECT 1;
  440. # Const MV, with REFRESH EVERY
  441. > CREATE MATERIALIZED VIEW mv16_every_const
  442. WITH (REFRESH AT '2500-01-01 23:59', REFRESH AT '3000-01-01 23:59', REFRESH EVERY '1 minutes')
  443. AS SELECT 1;
  444. # MV is before the first refresh
  445. > CREATE MATERIALIZED VIEW mv17_before_first
  446. WITH (REFRESH AT mz_now()::string::int8 + 1000 * 1000)
  447. AS SELECT count(*) FROM t2;
  448. # Cluster doesn't have a replica at the moment of creating an MV.
  449. > CREATE CLUSTER cluster_no_replica SIZE = '2', REPLICATION FACTOR = 0;
  450. > CREATE MATERIALIZED VIEW mv18_no_replica
  451. IN CLUSTER cluster_no_replica
  452. WITH (REFRESH EVERY '2 seconds')
  453. AS SELECT DISTINCT * FROM t2;
  454. # MV between two refreshes
  455. > CREATE MATERIALIZED VIEW mv19
  456. WITH (REFRESH EVERY '2 seconds')
  457. AS SELECT DISTINCT * FROM t2;
  458. ## Check the above MVs in `mz_materialized_view_refreshes`.
  459. > SELECT last_completed_refresh, next_refresh
  460. FROM mz_internal.mz_materialized_view_refreshes mvr, mz_catalog.mz_materialized_views mv
  461. WHERE mv.id = mvr.materialized_view_id AND (name = 'mv14_at_const' OR name = 'mv15_ats_const');
  462. 32503766340000 <null>
  463. 32503766340000 <null>
  464. > SELECT last_completed_refresh < mz_now(), next_refresh
  465. FROM mz_internal.mz_materialized_view_refreshes mvr, mz_catalog.mz_materialized_views mv
  466. WHERE mv.id = mvr.materialized_view_id AND name = 'mv_at_creation';
  467. true <null>
  468. > SELECT last_completed_refresh, next_refresh
  469. FROM mz_internal.mz_materialized_view_refreshes mvr, mz_catalog.mz_materialized_views mv
  470. WHERE mv.id = mvr.materialized_view_id AND name = 'mv16_every_const';
  471. 18446744073709551615 <null>
  472. > SELECT last_completed_refresh, next_refresh > mz_now()
  473. FROM mz_internal.mz_materialized_view_refreshes mvr, mz_catalog.mz_materialized_views mv
  474. WHERE mv.id = mvr.materialized_view_id AND name = 'mv17_before_first';
  475. <null> true
  476. > SELECT last_completed_refresh, next_refresh < mz_now()
  477. FROM mz_internal.mz_materialized_view_refreshes mvr, mz_catalog.mz_materialized_views mv
  478. WHERE mv.id = mvr.materialized_view_id AND name = 'mv18_no_replica';
  479. <null> true
  480. > SELECT next_refresh::string::int8 - last_completed_refresh::string::int8
  481. FROM mz_internal.mz_materialized_view_refreshes mvr, mz_catalog.mz_materialized_views mv
  482. WHERE mv.id = mvr.materialized_view_id AND name = 'mv19';
  483. 2000
  484. # Also check an old MV.
  485. > SELECT next_refresh::string::int8 - last_completed_refresh::string::int8
  486. FROM mz_internal.mz_materialized_view_refreshes mvr, mz_catalog.mz_materialized_views mv
  487. WHERE mv.id = mvr.materialized_view_id AND name = 'mv1';
  488. 8000
  489. # Negative test for `mz_hydration_statuses`, a regression test for database-issues#7621.
  490. #
  491. # It's hard to observe the bug before the first hydration, so we make the first
  492. # hydration quick to just get it over with, and then we make the next hydration
  493. # slow, and try to catch the bug there.
  494. > CREATE CLUSTER cluster_to_be_bricked SIZE = '1', REPLICATION FACTOR = 1;
  495. > CREATE TABLE t6 (a int);
  496. > INSERT INTO t6 VALUES (1);
  497. > CREATE MATERIALIZED VIEW mv_long_hydration
  498. IN CLUSTER cluster_to_be_bricked
  499. WITH (REFRESH EVERY '1 day') AS
  500. SELECT mz_unsafe.mz_sleep(a)
  501. FROM t6;
  502. # Wait for the first hydration to complete
  503. > SELECT * FROM mv_long_hydration;
  504. <null>
  505. > SELECT hydrated
  506. FROM mz_internal.mz_hydration_statuses JOIN mz_materialized_views ON (object_id = id)
  507. WHERE name = 'mv_long_hydration';
  508. true
  509. # Make the next hydration take 1000000 ms.
  510. > INSERT INTO t6 VALUES (1000000);
  511. # Restart the cluster to force a hydration.
  512. > ALTER CLUSTER cluster_to_be_bricked SET (REPLICATION FACTOR 0);
  513. > ALTER CLUSTER cluster_to_be_bricked SET (REPLICATION FACTOR 1);
  514. # Give the following hydration status query some time to wrongly turn to true if there is a bug.
  515. > SELECT mz_unsafe.mz_sleep(3);
  516. <null>
  517. > SELECT hydrated
  518. FROM mz_internal.mz_hydration_statuses JOIN mz_materialized_views ON (object_id = id)
  519. WHERE name = 'mv_long_hydration';
  520. false
  521. > DROP MATERIALIZED VIEW mv_long_hydration;
  522. > SELECT
  523. name,
  524. now() - INTERVAL '30 minutes' < last_completed_refresh,
  525. next_refresh > now() - INTERVAL '6 seconds'
  526. FROM mz_internal.mz_materialized_view_refreshes mvr, mz_catalog.mz_materialized_views mv
  527. WHERE
  528. mv.id = mvr.materialized_view_id
  529. ORDER BY name;
  530. mv1 true true
  531. mv10 <null> true
  532. mv11 true true
  533. mv12 <null> true
  534. mv13 <null> true
  535. mv14 <null> true
  536. mv14_at_const true <null>
  537. mv15_ats_const true <null>
  538. mv16_every_const true <null>
  539. mv17_before_first <null> true
  540. mv18_no_replica <null> false
  541. mv19 true true
  542. mv2 true true
  543. mv3 true true
  544. mv4 true <null>
  545. mv5 true true
  546. mv6 true true
  547. mv7 true <null>
  548. mv8 true true
  549. mv9 <null> true
  550. mv_at_creation true <null>
  551. mv_no_rep true true
  552. # ----------------------------------------
  553. # Cleanup
  554. # ----------------------------------------
  555. > DROP DATABASE materialized_view_refresh_options;
  556. > DROP CLUSTER refresh_cluster;
  557. > DROP CLUSTER scheduled_cluster;
  558. > DROP CLUSTER scheduled_cluster_2;
  559. > DROP CLUSTER c_schedule_6;
  560. > DROP CLUSTER c_schedule_7;
  561. > DROP CLUSTER cluster_no_replica;
  562. > DROP CLUSTER cluster_to_be_bricked;