Skip to content

Commit f051a1f

Browse files
committed
Isolation test
1 parent c7c3f9b commit f051a1f

4 files changed

Lines changed: 255 additions & 8 deletions

File tree

tsl/test/isolation/expected/cagg_cancel_kill_refresh.out

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ cagg_name|start_range|end_range
4949

5050
starting permutation: wp1_enable r1_register_pid r1_refresh s1_registered_ranges k1_cancel wp1_release s1_registered_ranges
5151
step wp1_enable:
52-
SELECT debug_waitpoint_enable('cagg_policy_batch_0_after_txn_1_wait');
52+
SELECT debug_waitpoint_enable('cagg_policy_batch_1_after_txn_1_wait');
5353

5454
debug_waitpoint_enable
5555
----------------------
@@ -77,7 +77,7 @@ step k1_cancel:
7777
step r1_refresh: <... completed>
7878
ERROR: canceling statement due to user request
7979
step wp1_release:
80-
SELECT debug_waitpoint_release('cagg_policy_batch_0_after_txn_1_wait');
80+
SELECT debug_waitpoint_release('cagg_policy_batch_1_after_txn_1_wait');
8181

8282
debug_waitpoint_release
8383
-----------------------
@@ -254,7 +254,7 @@ cagg_name|start_range|end_range
254254

255255
starting permutation: wp1_enable tr2_register_pid tr2_refresh s1_registered_ranges t1_terminate wp1_release s1_registered_ranges r2_refresh s1_registered_ranges
256256
step wp1_enable:
257-
SELECT debug_waitpoint_enable('cagg_policy_batch_0_after_txn_1_wait');
257+
SELECT debug_waitpoint_enable('cagg_policy_batch_1_after_txn_1_wait');
258258

259259
debug_waitpoint_enable
260260
----------------------
@@ -286,7 +286,7 @@ server closed the connection unexpectedly
286286
before or while processing the request.
287287

288288
step wp1_release:
289-
SELECT debug_waitpoint_release('cagg_policy_batch_0_after_txn_1_wait');
289+
SELECT debug_waitpoint_release('cagg_policy_batch_1_after_txn_1_wait');
290290

291291
debug_waitpoint_release
292292
-----------------------

tsl/test/isolation/expected/cagg_incremental_concurrent.out

Lines changed: 221 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Parsed test spec with 7 sessions
1+
Parsed test spec with 8 sessions
22

33
starting permutation: wp_enable r1_run s1_refresh_ranges s1_count r2_refresh wp_release s1_count s1_check_duplicates
44
step wp_enable:
@@ -113,6 +113,11 @@ R3: LOG: statement:
113113
SET SESSION client_min_messages = 'LOG';
114114
SET timescaledb.current_timestamp_mock TO '2026-04-01 00:30:00+00';
115115

116+
R4: LOG: statement:
117+
SET SESSION lock_timeout = '500ms';
118+
SET SESSION deadlock_timeout = '500ms';
119+
SET SESSION client_min_messages = 'LOG';
120+
116121
step wp_enable:
117122
SELECT debug_waitpoint_enable('cagg_policy_batch_2_after_txn_1_wait');
118123

@@ -241,6 +246,11 @@ R3: LOG: statement:
241246
SET SESSION client_min_messages = 'LOG';
242247
SET timescaledb.current_timestamp_mock TO '2026-04-01 00:30:00+00';
243248

249+
R4: LOG: statement:
250+
SET SESSION lock_timeout = '500ms';
251+
SET SESSION deadlock_timeout = '500ms';
252+
SET SESSION client_min_messages = 'LOG';
253+
244254
step wp_enable:
245255
SELECT debug_waitpoint_enable('cagg_policy_batch_2_after_txn_1_wait');
246256

@@ -357,6 +367,11 @@ R3: LOG: statement:
357367
SET SESSION client_min_messages = 'LOG';
358368
SET timescaledb.current_timestamp_mock TO '2026-04-01 00:30:00+00';
359369

370+
R4: LOG: statement:
371+
SET SESSION lock_timeout = '500ms';
372+
SET SESSION deadlock_timeout = '500ms';
373+
SET SESSION client_min_messages = 'LOG';
374+
360375
step wp_enable:
361376
SELECT debug_waitpoint_enable('cagg_policy_batch_2_after_txn_1_wait');
362377

@@ -448,6 +463,11 @@ R3: LOG: statement:
448463
SET SESSION client_min_messages = 'LOG';
449464
SET timescaledb.current_timestamp_mock TO '2026-04-01 00:30:00+00';
450465

466+
R4: LOG: statement:
467+
SET SESSION lock_timeout = '500ms';
468+
SET SESSION deadlock_timeout = '500ms';
469+
SET SESSION client_min_messages = 'LOG';
470+
451471
step wp_enable:
452472
SELECT debug_waitpoint_enable('cagg_policy_batch_2_after_txn_1_wait');
453473

@@ -521,3 +541,203 @@ R3: LOG: continuous aggregate refresh (individual invalidation) on "sensor_hour
521541
R3: LOG: deleted 2 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_X"
522542
R3: LOG: inserted 2 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_X"
523543
step r3_run_oldest_first: <... completed>
544+
545+
starting permutation: wp_enable r4_run s1_refresh_ranges s1_count r2_refresh wp_release s1_count s1_check_duplicates
546+
R1: LOG: statement:
547+
SET SESSION lock_timeout = '500ms';
548+
SET SESSION deadlock_timeout = '500ms';
549+
SET SESSION client_min_messages = 'LOG';
550+
551+
R2: LOG: statement:
552+
SET SESSION lock_timeout = '500ms';
553+
SET SESSION deadlock_timeout = '500ms';
554+
SET SESSION client_min_messages = 'LOG';
555+
556+
R3: LOG: statement:
557+
SET SESSION lock_timeout = '500ms';
558+
SET SESSION deadlock_timeout = '500ms';
559+
SET SESSION client_min_messages = 'LOG';
560+
SET timescaledb.current_timestamp_mock TO '2026-04-01 00:30:00+00';
561+
562+
R4: LOG: statement:
563+
SET SESSION lock_timeout = '500ms';
564+
SET SESSION deadlock_timeout = '500ms';
565+
SET SESSION client_min_messages = 'LOG';
566+
567+
step wp_enable:
568+
SELECT debug_waitpoint_enable('cagg_policy_batch_2_after_txn_1_wait');
569+
570+
debug_waitpoint_enable
571+
----------------------
572+
573+
574+
R4: LOG: statement:
575+
CALL refresh_continuous_aggregate(
576+
'cond_10', NULL, NULL,
577+
options => jsonb_build_object('buckets_per_batch', 1));
578+
579+
R4: LOG: deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_X"
580+
R4: LOG: inserted 3 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_X"
581+
step r4_run:
582+
CALL refresh_continuous_aggregate(
583+
'cond_10', NULL, NULL,
584+
options => jsonb_build_object('buckets_per_batch', 1));
585+
<waiting ...>
586+
step s1_refresh_ranges:
587+
SELECT ca.user_view_name AS cagg_name, r.start_range, r.end_range
588+
FROM _timescaledb_catalog.continuous_aggs_jobs_refresh_ranges r
589+
JOIN _timescaledb_catalog.continuous_agg ca ON r.materialization_id = ca.mat_hypertable_id
590+
ORDER BY ca.user_view_name;
591+
592+
cagg_name|start_range|end_range
593+
---------+-----------+---------
594+
cond_10 | 50| 60
595+
596+
step s1_count:
597+
SELECT count(*) AS row_count FROM cond_10;
598+
599+
row_count
600+
---------
601+
18
602+
603+
R2: LOG: statement:
604+
-- Non-overlapping with R1's registered batch range [50, 60)
605+
CALL refresh_continuous_aggregate('cond_10', 1, 50);
606+
607+
R2: LOG: deleted 12 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_X"
608+
R2: LOG: inserted 12 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_X"
609+
step r2_refresh:
610+
-- Non-overlapping with R1's registered batch range [50, 60)
611+
CALL refresh_continuous_aggregate('cond_10', 1, 50);
612+
613+
step wp_release:
614+
SELECT debug_waitpoint_release('cagg_policy_batch_2_after_txn_1_wait');
615+
616+
debug_waitpoint_release
617+
-----------------------
618+
619+
620+
R4: LOG: deleted 3 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_X"
621+
R4: LOG: inserted 3 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_X"
622+
R4: LOG: deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_X"
623+
R4: LOG: inserted 3 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_X"
624+
step r4_run: <... completed>
625+
step s1_count:
626+
SELECT count(*) AS row_count FROM cond_10;
627+
628+
row_count
629+
---------
630+
21
631+
632+
step s1_check_duplicates:
633+
-- Check for duplicate (bucket, device_id) rows in the materialization hypertable.
634+
-- If duplicates exist, the same range was materialized twice without proper cleanup.
635+
SELECT bucket, device_id, count(*) AS copies
636+
FROM cond_10
637+
GROUP BY bucket, device_id
638+
HAVING count(*) > 1
639+
ORDER BY bucket, device_id;
640+
641+
bucket|device_id|copies
642+
------+---------+------
643+
644+
645+
starting permutation: wp_enable r4_run s1_refresh_ranges r2_refresh_overlap wp_release s1_count s1_check_duplicates
646+
R1: LOG: statement:
647+
SET SESSION lock_timeout = '500ms';
648+
SET SESSION deadlock_timeout = '500ms';
649+
SET SESSION client_min_messages = 'LOG';
650+
651+
R2: LOG: statement:
652+
SET SESSION lock_timeout = '500ms';
653+
SET SESSION deadlock_timeout = '500ms';
654+
SET SESSION client_min_messages = 'LOG';
655+
656+
R3: LOG: statement:
657+
SET SESSION lock_timeout = '500ms';
658+
SET SESSION deadlock_timeout = '500ms';
659+
SET SESSION client_min_messages = 'LOG';
660+
SET timescaledb.current_timestamp_mock TO '2026-04-01 00:30:00+00';
661+
662+
R4: LOG: statement:
663+
SET SESSION lock_timeout = '500ms';
664+
SET SESSION deadlock_timeout = '500ms';
665+
SET SESSION client_min_messages = 'LOG';
666+
667+
step wp_enable:
668+
SELECT debug_waitpoint_enable('cagg_policy_batch_2_after_txn_1_wait');
669+
670+
debug_waitpoint_enable
671+
----------------------
672+
673+
674+
R4: LOG: statement:
675+
CALL refresh_continuous_aggregate(
676+
'cond_10', NULL, NULL,
677+
options => jsonb_build_object('buckets_per_batch', 1));
678+
679+
R4: LOG: deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_X"
680+
R4: LOG: inserted 3 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_X"
681+
step r4_run:
682+
CALL refresh_continuous_aggregate(
683+
'cond_10', NULL, NULL,
684+
options => jsonb_build_object('buckets_per_batch', 1));
685+
<waiting ...>
686+
step s1_refresh_ranges:
687+
SELECT ca.user_view_name AS cagg_name, r.start_range, r.end_range
688+
FROM _timescaledb_catalog.continuous_aggs_jobs_refresh_ranges r
689+
JOIN _timescaledb_catalog.continuous_agg ca ON r.materialization_id = ca.mat_hypertable_id
690+
ORDER BY ca.user_view_name;
691+
692+
cagg_name|start_range|end_range
693+
---------+-----------+---------
694+
cond_10 | 50| 60
695+
696+
R2: LOG: statement:
697+
-- Overlapping with R1's registered batch range [50, 60)
698+
CALL refresh_continuous_aggregate('cond_10', 40, 60);
699+
700+
step r2_refresh_overlap:
701+
-- Overlapping with R1's registered batch range [50, 60)
702+
CALL refresh_continuous_aggregate('cond_10', 40, 60);
703+
704+
ERROR: could not refresh continuous aggregate "cond_10" due to a concurrent refresh
705+
step wp_release:
706+
SELECT debug_waitpoint_release('cagg_policy_batch_2_after_txn_1_wait');
707+
708+
debug_waitpoint_release
709+
-----------------------
710+
711+
712+
R4: LOG: deleted 3 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_X"
713+
R4: LOG: inserted 3 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_X"
714+
R4: LOG: deleted 3 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_X"
715+
R4: LOG: inserted 3 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_X"
716+
R4: LOG: deleted 3 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_X"
717+
R4: LOG: inserted 3 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_X"
718+
R4: LOG: deleted 3 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_X"
719+
R4: LOG: inserted 3 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_X"
720+
R4: LOG: deleted 3 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_X"
721+
R4: LOG: inserted 3 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_X"
722+
R4: LOG: deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_X"
723+
R4: LOG: inserted 3 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_X"
724+
step r4_run: <... completed>
725+
step s1_count:
726+
SELECT count(*) AS row_count FROM cond_10;
727+
728+
row_count
729+
---------
730+
21
731+
732+
step s1_check_duplicates:
733+
-- Check for duplicate (bucket, device_id) rows in the materialization hypertable.
734+
-- If duplicates exist, the same range was materialized twice without proper cleanup.
735+
SELECT bucket, device_id, count(*) AS copies
736+
FROM cond_10
737+
GROUP BY bucket, device_id
738+
HAVING count(*) > 1
739+
ORDER BY bucket, device_id;
740+
741+
bucket|device_id|copies
742+
------+---------+------
743+

tsl/test/isolation/specs/cagg_cancel_kill_refresh.spec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,11 @@ step "wp0_release"
101101
session "WP1"
102102
step "wp1_enable"
103103
{
104-
SELECT debug_waitpoint_enable('cagg_policy_batch_0_after_txn_1_wait');
104+
SELECT debug_waitpoint_enable('cagg_policy_batch_1_after_txn_1_wait');
105105
}
106106
step "wp1_release"
107107
{
108-
SELECT debug_waitpoint_release('cagg_policy_batch_0_after_txn_1_wait');
108+
SELECT debug_waitpoint_release('cagg_policy_batch_1_after_txn_1_wait');
109109
}
110110

111111
# Waitpoint after txn 2 (cagg invalidations processed)

tsl/test/isolation/specs/cagg_incremental_concurrent.spec

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,23 @@ step "r3_run_oldest_first"
295295
$$;
296296
}
297297

298+
# Session for batched manual refresh via JSONB options. Goes through the same
299+
# continuous_agg_refresh_single_window path as the policy, so it pauses at the
300+
# same waitpoint.
301+
session "R4"
302+
setup
303+
{
304+
SET SESSION lock_timeout = '500ms';
305+
SET SESSION deadlock_timeout = '500ms';
306+
SET SESSION client_min_messages = 'LOG';
307+
}
308+
step "r4_run"
309+
{
310+
CALL refresh_continuous_aggregate(
311+
'cond_10', NULL, NULL,
312+
options => jsonb_build_object('buckets_per_batch', 1));
313+
}
314+
298315
#insert data to create invalidations when refresh is stopped after batch 1
299316
session "I2"
300317
step "i2_insert"
@@ -325,4 +342,14 @@ permutation "wp_enable" "r1_run"("wp_enable") "s1_refresh_ranges" "r2_refresh_ov
325342
permutation "wp_enable" "r3_run"("wp_enable") "i2_insert" "wp_release"
326343

327344
# Test 5: Same as test 5, but the policy refreshes oldest batch first
328-
permutation "wp_enable" "r3_run_oldest_first"("wp_enable") "i2_insert" "wp_release"
345+
permutation "wp_enable" "r3_run_oldest_first"("wp_enable") "i2_insert" "wp_release"
346+
347+
# Test 6: Manual incremental refresh pauses after batch 1.
348+
# A non-overlapping atomic manual refresh proceeds successfully
349+
# Mirrors test 1 but with batched manual refresh on the paused side instead of policy.
350+
permutation "wp_enable" "r4_run"("wp_enable") "s1_refresh_ranges" "s1_count" "r2_refresh" "wp_release" "s1_count" "s1_check_duplicates"
351+
352+
# Test 7: Manual incremental refresh pauses after batch 1.
353+
# An overlapping atomic manual refresh must error with "concurrent refresh".
354+
# Mirrors test 3 with batched manual refresh on the paused side.
355+
permutation "wp_enable" "r4_run"("wp_enable") "s1_refresh_ranges" "r2_refresh_overlap" "wp_release" "s1_count" "s1_check_duplicates"

0 commit comments

Comments
 (0)