diff --git a/tsl/test/isolation/expected/cagg_concurrent_register.out b/tsl/test/isolation/expected/cagg_concurrent_register.out index 62f10d43e54..652de451bee 100644 --- a/tsl/test/isolation/expected/cagg_concurrent_register.out +++ b/tsl/test/isolation/expected/cagg_concurrent_register.out @@ -13,10 +13,10 @@ step s3_lock_before_register: BEGIN; LOCK TABLE _timescaledb_catalog.continuous_aggs_jobs_refresh_ranges; step s1_run_cagg1_refresh: - CALL refresh_continuous_aggregate('cagg_1', '2020-01-01 00:00:00+00', '2020-01-03 00:00:00+00'); + CALL refresh_continuous_aggregate('cagg_1', '2020-01-01 00:00:00+00', '2020-01-03 00:00:00+00', options => jsonb_build_object('buckets_per_batch', 0)); step s2_run_cagg2_overlap_refresh: - CALL refresh_continuous_aggregate('cagg_2', '2020-01-03 00:00:00+00', '2020-01-05 00:00:00+00'); + CALL refresh_continuous_aggregate('cagg_2', '2020-01-03 00:00:00+00', '2020-01-05 00:00:00+00', options => jsonb_build_object('buckets_per_batch', 0)); step s4_enable_before_process_cagg_invalidations: SELECT debug_waitpoint_enable('before_process_cagg_invalidations_for_refresh_lock'); @@ -39,8 +39,8 @@ step s5_show_running_jobs: cagg_name| start_range| end_range|start_ts_utc |end_ts_utc ---------+----------------+----------------+------------------------+------------------------ -cagg_1 |1577980800000000|1578009600000000|Thu Jan 02 16:00:00 2020|Fri Jan 03 00:00:00 2020 -cagg_2 |1578153600000000|1578182400000000|Sat Jan 04 16:00:00 2020|Sun Jan 05 00:00:00 2020 +cagg_1 |1577836800000000|1578009600000000|Wed Jan 01 00:00:00 2020|Fri Jan 03 00:00:00 2020 +cagg_2 |1578009600000000|1578182400000000|Fri Jan 03 00:00:00 2020|Sun Jan 05 00:00:00 2020 step s4_release_before_process_cagg_invalidations: SELECT debug_waitpoint_release('before_process_cagg_invalidations_for_refresh_lock'); @@ -66,10 +66,10 @@ step s3_lock_before_register: BEGIN; LOCK TABLE _timescaledb_catalog.continuous_aggs_jobs_refresh_ranges; step s1_run_cagg2_overlap_refresh: - CALL refresh_continuous_aggregate('cagg_2', '2020-01-01 00:00:00+00', '2020-01-07 00:00:00+00'); + CALL refresh_continuous_aggregate('cagg_2', '2020-01-01 00:00:00+00', '2020-01-07 00:00:00+00', options => jsonb_build_object('buckets_per_batch', 0)); step s2_run_cagg2_overlap_refresh: - CALL refresh_continuous_aggregate('cagg_2', '2020-01-03 00:00:00+00', '2020-01-05 00:00:00+00'); + CALL refresh_continuous_aggregate('cagg_2', '2020-01-03 00:00:00+00', '2020-01-05 00:00:00+00', options => jsonb_build_object('buckets_per_batch', 0)); step s4_enable_before_process_cagg_invalidations: SELECT debug_waitpoint_enable('before_process_cagg_invalidations_for_refresh_lock'); @@ -92,15 +92,14 @@ step s5_show_running_jobs: cagg_name| start_range| end_range|start_ts_utc |end_ts_utc ---------+----------------+----------------+------------------------+------------------------ -cagg_2 |1578153600000000|1578182400000000|Sat Jan 04 16:00:00 2020|Sun Jan 05 00:00:00 2020 -cagg_2 |1578268800000000|1578355200000000|Mon Jan 06 00:00:00 2020|Tue Jan 07 00:00:00 2020 +cagg_2 |1577836800000000|1578355200000000|Wed Jan 01 00:00:00 2020|Tue Jan 07 00:00:00 2020 step s4_release_before_process_cagg_invalidations: SELECT debug_waitpoint_release('before_process_cagg_invalidations_for_refresh_lock'); step s1_run_cagg2_overlap_refresh: <... completed> -ERROR: could not refresh continuous aggregate "cagg_2" due to a concurrent refresh step s2_run_cagg2_overlap_refresh: <... completed> +ERROR: could not refresh continuous aggregate "cagg_2" due to a concurrent refresh step s4_release_before_process_cagg_invalidations: <... completed> debug_waitpoint_release ----------------------- @@ -123,7 +122,7 @@ step s1_run_cagg2_nonoverlap_refresh: CALL refresh_continuous_aggregate('cagg_2', '2020-01-01 00:00:00+00', '2020-01-02 00:00:00+00'); step s2_run_cagg2_overlap_refresh: - CALL refresh_continuous_aggregate('cagg_2', '2020-01-03 00:00:00+00', '2020-01-05 00:00:00+00'); + CALL refresh_continuous_aggregate('cagg_2', '2020-01-03 00:00:00+00', '2020-01-05 00:00:00+00', options => jsonb_build_object('buckets_per_batch', 0)); step s4_enable_before_process_cagg_invalidations: SELECT debug_waitpoint_enable('before_process_cagg_invalidations_for_refresh_lock'); @@ -147,7 +146,7 @@ step s5_show_running_jobs: cagg_name| start_range| end_range|start_ts_utc |end_ts_utc ---------+----------------+----------------+------------------------+------------------------ cagg_2 |1577836800000000|1577923200000000|Wed Jan 01 00:00:00 2020|Thu Jan 02 00:00:00 2020 -cagg_2 |1578153600000000|1578182400000000|Sat Jan 04 16:00:00 2020|Sun Jan 05 00:00:00 2020 +cagg_2 |1578009600000000|1578182400000000|Fri Jan 03 00:00:00 2020|Sun Jan 05 00:00:00 2020 step s4_release_before_process_cagg_invalidations: SELECT debug_waitpoint_release('before_process_cagg_invalidations_for_refresh_lock'); diff --git a/tsl/test/isolation/expected/cagg_refresh_cleanup_register.out b/tsl/test/isolation/expected/cagg_refresh_cleanup_register.out index b6c33f62735..22e263543cb 100644 --- a/tsl/test/isolation/expected/cagg_refresh_cleanup_register.out +++ b/tsl/test/isolation/expected/cagg_refresh_cleanup_register.out @@ -7,7 +7,7 @@ debug_waitpoint_enable step R2_refresh: - CALL refresh_continuous_aggregate('cond_daily', '2026-01-05', '2026-02-15'); + CALL refresh_continuous_aggregate('cond_daily', '2026-01-05', '2026-02-15', options => jsonb_build_object('buckets_per_batch', 0)); step L1_lock: BEGIN; @@ -20,10 +20,10 @@ debug_waitpoint_release step R3_refresh: - CALL refresh_continuous_aggregate('cond_daily', '2026-02-15', '2026-03-15'); + CALL refresh_continuous_aggregate('cond_daily', '2026-02-15', '2026-03-15', options => jsonb_build_object('buckets_per_batch', 0)); step R4_refresh: - CALL refresh_continuous_aggregate('cond_daily', '2026-03-15', '2026-03-30'); + CALL refresh_continuous_aggregate('cond_daily', '2026-03-15', '2026-03-30', options => jsonb_build_object('buckets_per_batch', 0)); step check_locks: SELECT l.mode, l.granted @@ -50,7 +50,7 @@ step check_jobs: user_view_name|start_time |end_time --------------+----------------------------+---------------------------- -cond_daily |Sun Feb 08 16:00:00 2026 PST|Sat Feb 14 16:00:00 2026 PST +cond_daily |Mon Jan 05 16:00:00 2026 PST|Sat Feb 14 16:00:00 2026 PST step L1_unlock: COMMIT; @@ -89,7 +89,7 @@ debug_waitpoint_enable step R2_refresh: - CALL refresh_continuous_aggregate('cond_daily', '2026-01-05', '2026-02-15'); + CALL refresh_continuous_aggregate('cond_daily', '2026-01-05', '2026-02-15', options => jsonb_build_object('buckets_per_batch', 0)); step L1_lock: BEGIN; @@ -102,10 +102,10 @@ debug_waitpoint_release step R3_refresh: - CALL refresh_continuous_aggregate('cond_daily', '2026-02-15', '2026-03-15'); + CALL refresh_continuous_aggregate('cond_daily', '2026-02-15', '2026-03-15', options => jsonb_build_object('buckets_per_batch', 0)); step R4_overlapping_refresh: - CALL refresh_continuous_aggregate('cond_daily', '2026-03-01', '2026-03-15'); + CALL refresh_continuous_aggregate('cond_daily', '2026-03-01', '2026-03-15', options => jsonb_build_object('buckets_per_batch', 0)); step check_locks: SELECT l.mode, l.granted @@ -132,7 +132,7 @@ step check_jobs: user_view_name|start_time |end_time --------------+----------------------------+---------------------------- -cond_daily |Sun Feb 08 16:00:00 2026 PST|Sat Feb 14 16:00:00 2026 PST +cond_daily |Mon Jan 05 16:00:00 2026 PST|Sat Feb 14 16:00:00 2026 PST step L1_unlock: COMMIT; @@ -172,7 +172,7 @@ debug_waitpoint_enable step R3_refresh: - CALL refresh_continuous_aggregate('cond_daily', '2026-02-15', '2026-03-15'); + CALL refresh_continuous_aggregate('cond_daily', '2026-02-15', '2026-03-15', options => jsonb_build_object('buckets_per_batch', 0)); step check_jobs: SELECT ca.user_view_name, @@ -185,7 +185,7 @@ step check_jobs: user_view_name|start_time |end_time --------------+----------------------------+---------------------------- -cond_daily |Sat Mar 07 16:00:00 2026 PST|Sat Mar 14 17:00:00 2026 PDT +cond_daily |Sun Feb 15 16:00:00 2026 PST|Sat Mar 14 17:00:00 2026 PDT step A1_revoke_perm: REVOKE SELECT on conditions FROM cagg_user; @@ -217,7 +217,7 @@ debug_waitpoint_enable step R3_refresh: - CALL refresh_continuous_aggregate('cond_daily', '2026-02-15', '2026-03-15'); + CALL refresh_continuous_aggregate('cond_daily', '2026-02-15', '2026-03-15', options => jsonb_build_object('buckets_per_batch', 0)); step check_jobs: SELECT ca.user_view_name, @@ -230,7 +230,7 @@ step check_jobs: user_view_name|start_time |end_time --------------+----------------------------+---------------------------- -cond_daily |Sat Mar 07 16:00:00 2026 PST|Sat Mar 14 17:00:00 2026 PDT +cond_daily |Sun Feb 15 16:00:00 2026 PST|Sat Mar 14 17:00:00 2026 PDT step A1_revoke_mat_perm: DO $$ @@ -273,7 +273,7 @@ debug_waitpoint_enable step R2_refresh: - CALL refresh_continuous_aggregate('cond_daily', '2026-01-05', '2026-02-15'); + CALL refresh_continuous_aggregate('cond_daily', '2026-01-05', '2026-02-15', options => jsonb_build_object('buckets_per_batch', 0)); step check_jobs_metadata_manual: SELECT ca.user_view_name, @@ -352,7 +352,7 @@ debug_waitpoint_enable step R1_refresh: - CALL refresh_continuous_aggregate('cond_daily', '2026-01-05', '2026-03-15'); + CALL refresh_continuous_aggregate('cond_daily', '2026-01-05', '2026-03-15', options => jsonb_build_object('buckets_per_batch', 0)); step check_jobs: SELECT ca.user_view_name, @@ -365,24 +365,11 @@ step check_jobs: user_view_name|start_time |end_time --------------+----------------------------+---------------------------- -cond_daily |Tue Mar 10 17:00:00 2026 PDT|Sat Mar 14 17:00:00 2026 PDT +cond_daily |Mon Jan 05 16:00:00 2026 PST|Sat Mar 14 17:00:00 2026 PDT step K1_terminate: - DO $$ - DECLARE - target_pid int; - BEGIN - SELECT pid INTO target_pid FROM cancelpid; - PERFORM pg_terminate_backend(target_pid); - LOOP - EXIT WHEN NOT EXISTS ( - SELECT 1 FROM pg_stat_activity WHERE pid = target_pid - ); - PERFORM pg_sleep(0.05); - END LOOP; - END; - $$; - + CALL terminate_r1(); + step R1_refresh: <... completed> FATAL: terminating connection due to administrator command server closed the connection unexpectedly @@ -394,16 +381,17 @@ debug_waitpoint_release ----------------------- +step K1_terminate: <... completed> step L1_lock: BEGIN; LOCK TABLE _timescaledb_catalog.continuous_aggs_jobs_refresh_ranges IN ACCESS EXCLUSIVE MODE; step R2_refresh: - CALL refresh_continuous_aggregate('cond_daily', '2026-01-05', '2026-02-15'); + CALL refresh_continuous_aggregate('cond_daily', '2026-01-05', '2026-02-15', options => jsonb_build_object('buckets_per_batch', 0)); step R3_refresh: - CALL refresh_continuous_aggregate('cond_daily', '2026-02-15', '2026-03-15'); + CALL refresh_continuous_aggregate('cond_daily', '2026-02-15', '2026-03-15', options => jsonb_build_object('buckets_per_batch', 0)); step L1_unlock: COMMIT; diff --git a/tsl/test/isolation/specs/cagg_concurrent_register.spec b/tsl/test/isolation/specs/cagg_concurrent_register.spec index 477df6559fd..35ea6264c0c 100644 --- a/tsl/test/isolation/specs/cagg_concurrent_register.spec +++ b/tsl/test/isolation/specs/cagg_concurrent_register.spec @@ -64,10 +64,10 @@ teardown { session "S1" step "s1_run_cagg1_refresh" { - CALL refresh_continuous_aggregate('cagg_1', '2020-01-01 00:00:00+00', '2020-01-03 00:00:00+00'); + CALL refresh_continuous_aggregate('cagg_1', '2020-01-01 00:00:00+00', '2020-01-03 00:00:00+00', options => jsonb_build_object('buckets_per_batch', 0)); } step "s1_run_cagg2_overlap_refresh" { - CALL refresh_continuous_aggregate('cagg_2', '2020-01-01 00:00:00+00', '2020-01-07 00:00:00+00'); + CALL refresh_continuous_aggregate('cagg_2', '2020-01-01 00:00:00+00', '2020-01-07 00:00:00+00', options => jsonb_build_object('buckets_per_batch', 0)); } step "s1_run_cagg2_nonoverlap_refresh" { CALL refresh_continuous_aggregate('cagg_2', '2020-01-01 00:00:00+00', '2020-01-02 00:00:00+00'); @@ -76,7 +76,7 @@ step "s1_run_cagg2_nonoverlap_refresh" { session "S2" step "s2_run_cagg2_overlap_refresh" { - CALL refresh_continuous_aggregate('cagg_2', '2020-01-03 00:00:00+00', '2020-01-05 00:00:00+00'); + CALL refresh_continuous_aggregate('cagg_2', '2020-01-03 00:00:00+00', '2020-01-05 00:00:00+00', options => jsonb_build_object('buckets_per_batch', 0)); } step "s2_insert_new_data_2020" { diff --git a/tsl/test/isolation/specs/cagg_refresh_cleanup_register.spec b/tsl/test/isolation/specs/cagg_refresh_cleanup_register.spec index 858b226548d..3cb96edc1ac 100644 --- a/tsl/test/isolation/specs/cagg_refresh_cleanup_register.spec +++ b/tsl/test/isolation/specs/cagg_refresh_cleanup_register.spec @@ -18,6 +18,16 @@ setup -- Table used to pass R1's backend PID to the terminator session CREATE TABLE cancelpid (pid int); + -- Terminate R1's backend. Wrapped in a void-returning procedure (as in + -- cagg_cancel_kill_refresh.spec) so isolationtester's native blocked-step + -- synchronization can be used instead of polling pg_stat_activity. + CREATE OR REPLACE PROCEDURE terminate_r1() AS + $$ + BEGIN + PERFORM pg_terminate_backend(pid) FROM cancelpid; + END; + $$ LANGUAGE plpgsql; + CREATE MATERIALIZED VIEW cond_daily WITH (timescaledb.continuous, timescaledb.materialized_only = true) AS SELECT time_bucket('1 day', time) AS bucket, avg(value) AS avg_val @@ -59,7 +69,7 @@ setup { INSERT INTO cancelpid SELECT pg_backend_pid(); } step "R1_refresh" { - CALL refresh_continuous_aggregate('cond_daily', '2026-01-05', '2026-03-15'); + CALL refresh_continuous_aggregate('cond_daily', '2026-01-05', '2026-03-15', options => jsonb_build_object('buckets_per_batch', 0)); } # Session WP: enables / disables waitpoints @@ -76,23 +86,12 @@ step "WP_after_register_enable" { SELECT debug_waitpoint_enable('cagg_refresh_a step "WP_after_register_disable" { SELECT debug_waitpoint_release('cagg_refresh_after_register'); } # Session K1: terminate R1's backend so its PID becomes dead in the -# registration table, then wait until the process is gone. +# registration table. Relies on isolationtester's native blocked-step +# synchronization (see the "K1_terminate"("R1_refresh") annotation below) +# rather than polling pg_stat_activity for the pid to disappear. session "K1" step "K1_terminate" { - DO $$ - DECLARE - target_pid int; - BEGIN - SELECT pid INTO target_pid FROM cancelpid; - PERFORM pg_terminate_backend(target_pid); - LOOP - EXIT WHEN NOT EXISTS ( - SELECT 1 FROM pg_stat_activity WHERE pid = target_pid - ); - PERFORM pg_sleep(0.05); - END LOOP; - END; - $$; + CALL terminate_r1(); } # Refresh sessions @@ -102,7 +101,7 @@ setup { SET SESSION lock_timeout = '2s'; } step "R2_refresh" { - CALL refresh_continuous_aggregate('cond_daily', '2026-01-05', '2026-02-15'); + CALL refresh_continuous_aggregate('cond_daily', '2026-01-05', '2026-02-15', options => jsonb_build_object('buckets_per_batch', 0)); } session "R3" @@ -111,7 +110,7 @@ setup { SET SESSION lock_timeout = '2s'; } step "R3_refresh" { - CALL refresh_continuous_aggregate('cond_daily', '2026-02-15', '2026-03-15'); + CALL refresh_continuous_aggregate('cond_daily', '2026-02-15', '2026-03-15', options => jsonb_build_object('buckets_per_batch', 0)); } session "R4" @@ -120,10 +119,10 @@ setup { SET SESSION lock_timeout = '2s'; } step "R4_refresh" { - CALL refresh_continuous_aggregate('cond_daily', '2026-03-15', '2026-03-30'); + CALL refresh_continuous_aggregate('cond_daily', '2026-03-15', '2026-03-30', options => jsonb_build_object('buckets_per_batch', 0)); } step "R4_overlapping_refresh" { - CALL refresh_continuous_aggregate('cond_daily', '2026-03-01', '2026-03-15'); + CALL refresh_continuous_aggregate('cond_daily', '2026-03-01', '2026-03-15', options => jsonb_build_object('buckets_per_batch', 0)); } session "A1" @@ -241,4 +240,4 @@ permutation "P1_add_policy" "WP_after_register_enable" "P1_run_policy" "check_jo # Stale registration cleanup by concurrent refreshes. # Kill a backend during refresh to end up with a pid left behind. Later two concurrent refreshes run, only one removes the stale pid. # backend R1 is killed, we can no longer use this for later permutations -permutation "WP_before_txn2_commit_enable" "R1_refresh" "check_jobs" "K1_terminate"("check_jobs") "WP_before_txn2_commit_disable" "L1_lock" "R2_refresh"("L1_lock") "R3_refresh"("R2_refresh") "L1_unlock"(R2_refresh, R3_refresh) "check_jobs" +permutation "WP_before_txn2_commit_enable" "R1_refresh" "check_jobs" "K1_terminate"("R1_refresh") "WP_before_txn2_commit_disable" "L1_lock" "R2_refresh"("L1_lock") "R3_refresh"("R2_refresh") "L1_unlock"(R2_refresh, R3_refresh) "check_jobs"