diff --git a/src/test/modules/injection_points/expected/repack_toast.out b/src/test/modules/injection_points/expected/repack_toast.out index b56dde1..0eefc88 100644 --- a/src/test/modules/injection_points/expected/repack_toast.out +++ b/src/test/modules/injection_points/expected/repack_toast.out @@ -63,3 +63,60 @@ injection_points_detach (1 row) + +starting permutation: repack_compressed compressed_update wakeup_before_lock verify_compressed +injection_points_attach +----------------------- + +(1 row) + +step repack_compressed: + REPACK (CONCURRENTLY) repack_ctest; + +step compressed_update: + UPDATE repack_ctest SET j = gen_compressible(99) WHERE i = 2; + +step wakeup_before_lock: + SELECT injection_points_wakeup('repack-concurrently-before-lock'); + +injection_points_wakeup +----------------------- + +(1 row) + +step repack_compressed: <... completed> +step verify_compressed: + INSERT INTO post_repack_data + SELECT i, j FROM repack_ctest ORDER BY i; + + SELECT e.i, + length(e.j) AS expect_len, + length(p.j) AS actual_len, + (length(e.j) = length(p.j)) AS len_ok, + (md5(e.j) = md5(p.j)) AS hash_ok + FROM expected_data e + JOIN post_repack_data p USING (i) + ORDER BY e.i; + + SELECT count(*) AS mismatches + FROM expected_data e + JOIN post_repack_data p USING (i) + WHERE length(e.j) != length(p.j) OR md5(e.j) != md5(p.j); + +i|expect_len|actual_len|len_ok|hash_ok +-+----------+----------+------+------- +1| 16000| 16000|t |t +2| 16000| 16000|t |t +3| 16000| 16000|t |t +(3 rows) + +mismatches +---------- + 0 +(1 row) + +injection_points_detach +----------------------- + +(1 row) + diff --git a/src/test/modules/injection_points/specs/repack_toast.spec b/src/test/modules/injection_points/specs/repack_toast.spec index b878b19..fb8a557 100644 --- a/src/test/modules/injection_points/specs/repack_toast.spec +++ b/src/test/modules/injection_points/specs/repack_toast.spec @@ -13,6 +13,14 @@ setup FROM generate_series(1, 2048) s(x); $$; + -- 500 concatenated md5 hashes = 16000 hex chars; compresses but stays > 2KB. + CREATE FUNCTION gen_compressible(seed int) + RETURNS text + LANGUAGE sql IMMUTABLE as $$ + SELECT string_agg(md5((seed * 1000 + x)::text), '') + FROM generate_series(1, 500) x; + $$; + CREATE TABLE repack_test(i int PRIMARY KEY, j text); INSERT INTO repack_test(i, j) VALUES (1, get_long_string()), (2, get_long_string()), (3, get_long_string()); @@ -21,13 +29,30 @@ setup CREATE TABLE data_s1(i int, j text); CREATE TABLE data_s2(i int, j text); + + CREATE TABLE repack_ctest(i int PRIMARY KEY, j text); + INSERT INTO repack_ctest(i, j) + VALUES (1, gen_compressible(1)), + (2, gen_compressible(2)), + (3, gen_compressible(3)); + + CREATE TABLE expected_data AS + SELECT 1 AS i, gen_compressible(1) AS j + UNION ALL SELECT 2, gen_compressible(99) + UNION ALL SELECT 3, gen_compressible(3); + + CREATE TABLE post_repack_data(i int, j text); } teardown { DROP TABLE repack_test; + DROP TABLE repack_ctest; + DROP TABLE expected_data; + DROP TABLE post_repack_data; DROP EXTENSION injection_points; DROP FUNCTION get_long_string(); + DROP FUNCTION gen_compressible(int); DROP TABLE relfilenodes; DROP TABLE data_s1; @@ -67,6 +92,29 @@ step check1 FROM data_s1 d1 FULL JOIN data_s2 d2 USING (i, j) WHERE d1.i ISNULL OR d2.i ISNULL; } +step repack_compressed +{ + REPACK (CONCURRENTLY) repack_ctest; +} +step verify_compressed +{ + INSERT INTO post_repack_data + SELECT i, j FROM repack_ctest ORDER BY i; + + SELECT e.i, + length(e.j) AS expect_len, + length(p.j) AS actual_len, + (length(e.j) = length(p.j)) AS len_ok, + (md5(e.j) = md5(p.j)) AS hash_ok + FROM expected_data e + JOIN post_repack_data p USING (i) + ORDER BY e.i; + + SELECT count(*) AS mismatches + FROM expected_data e + JOIN post_repack_data p USING (i) + WHERE length(e.j) != length(p.j) OR md5(e.j) != md5(p.j); +} teardown { SELECT injection_points_detach('repack-concurrently-before-lock'); @@ -101,6 +149,10 @@ step wakeup_before_lock { SELECT injection_points_wakeup('repack-concurrently-before-lock'); } +step compressed_update +{ + UPDATE repack_ctest SET j = gen_compressible(99) WHERE i = 2; +} # Test if data changes introduced while one session is performing REPACK # CONCURRENTLY find their way into the table. @@ -110,3 +162,10 @@ permutation check2 wakeup_before_lock check1 + +# Test that compressed TOAST values survive REPACK CONCURRENTLY. +permutation + repack_compressed + compressed_update + wakeup_before_lock + verify_compressed