Skip to content
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

Reduce index lock in segmentwise recompression #6558

Merged
merged 1 commit into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .unreleased/pr_6558
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixes: #6523 Reduce locking level on compressed chunk index during segmentwise recompression
2 changes: 1 addition & 1 deletion src/planner/expand_hypertable.c
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ ts_transform_time_bucket_comparison(Expr *node)
if (list_length(time_bucket->args) > 2 && !IsA(lthird(time_bucket->args), Const))
return NULL;

/* 5 args variants should have Const 4rd and 5th arg */
/* 5 args variants should have Const 4th and 5th arg */
if (list_length(time_bucket->args) == 5 &&
(!IsA(lfourth(time_bucket->args), Const) || !IsA(lfifth(time_bucket->args), Const)))
return NULL;
Expand Down
4 changes: 2 additions & 2 deletions tsl/src/compression/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -1229,7 +1229,7 @@ tsl_recompress_chunk_segmentwise(PG_FUNCTION_ARGS)
Snapshot snapshot = RegisterSnapshot(GetTransactionSnapshot());

/* Index scan */
Relation index_rel = index_open(row_compressor.index_oid, AccessExclusiveLock);
Relation index_rel = index_open(row_compressor.index_oid, ExclusiveLock);

index_scan = index_beginscan(compressed_chunk_rel, index_rel, snapshot, 0, 0);
TupleTableSlot *slot = table_slot_create(compressed_chunk_rel, NULL);
Expand Down Expand Up @@ -1385,7 +1385,7 @@ tsl_recompress_chunk_segmentwise(PG_FUNCTION_ARGS)
ExecDropSingleTupleTableSlot(slot);
index_endscan(index_scan);
UnregisterSnapshot(snapshot);
index_close(index_rel, AccessExclusiveLock);
index_close(index_rel, ExclusiveLock);
row_decompressor_close(&decompressor);

/* changed chunk status, so invalidate any plans involving this chunk */
Expand Down
37 changes: 37 additions & 0 deletions tsl/test/isolation/expected/compression_recompress.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
Parsed test spec with 2 sessions

starting permutation: s2_block_on_compressed_chunk_size s1_begin s1_recompress_chunk s2_select_from_compressed_chunk s2_wait_for_select_to_finish s2_unblock s1_rollback
step s2_block_on_compressed_chunk_size:
BEGIN;
LOCK TABLE _timescaledb_catalog.compression_chunk_size;

step s1_begin:
BEGIN;

step s1_recompress_chunk:
SELECT count(_timescaledb_functions.recompress_chunk_segmentwise(i)) AS recompress
FROM show_chunks('sensor_data') i
LIMIT 1;
<waiting ...>
step s2_select_from_compressed_chunk:
SELECT sum(temperature) > 1 FROM sensor_data WHERE sensor_id = 2;

?column?
--------
t
(1 row)

step s2_wait_for_select_to_finish:

step s2_unblock:
ROLLBACK;

step s1_recompress_chunk: <... completed>
recompress
----------
1
(1 row)

step s1_rollback:
ROLLBACK;

1 change: 1 addition & 0 deletions tsl/test/isolation/specs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ if(CMAKE_BUILD_TYPE MATCHES Debug)
compression_chunk_race.spec
compression_freeze.spec
compression_merge_race.spec
compression_recompress.spec
decompression_chunk_and_parallel_query_wo_idx.spec)
if(PG_VERSION VERSION_GREATER_EQUAL "14.0")
list(APPEND TEST_FILES freeze_chunk.spec compression_dml_iso.spec)
Expand Down
80 changes: 80 additions & 0 deletions tsl/test/isolation/specs/compression_recompress.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# This file and its contents are licensed under the Timescale License.
# Please see the included NOTICE for copyright information and
# LICENSE-TIMESCALE for a copy of the license.

###
# Test recompression doesn't block (or deadlock with) read operations
###

setup {
CREATE TABLE sensor_data (
time timestamptz not null,
sensor_id integer not null,
cpu double precision null,
temperature double precision null);

SELECT FROM create_hypertable('sensor_data','time', create_default_indexes => false);

INSERT INTO sensor_data
SELECT time + (INTERVAL '1 minute' * random()) AS time, sensor_id,
random() AS cpu,
random()* 100 AS temperature
FROM
generate_series('2022-01-01 00:00:00', '2022-01-01 23:59:59', INTERVAL '1 minute') AS g1(time),
generate_series(1, 5, 1) AS g2(sensor_id)
ORDER BY time;

ALTER TABLE sensor_data SET (
timescaledb.compress,
timescaledb.compress_segmentby = 'sensor_id',
timescaledb.compress_orderby = 'time');

SELECT compress_chunk(show_chunks('sensor_data'));

-- Create partially compressed chunk that we can recompress using segmentwise
INSERT INTO sensor_data
SELECT time + (INTERVAL '1 minute' * random()) AS time, sensor_id,
random() AS cpu,
random()* 100 AS temperature
FROM
generate_series('2022-01-01 00:00:00', '2022-01-01 23:59:59', INTERVAL '1 minute') AS g1(time),
generate_series(10, 15, 1) AS g2(sensor_id)
ORDER BY time;
}

teardown {
DROP TABLE sensor_data;
}

session "s1"
step "s1_begin" {
BEGIN;
}
step "s1_recompress_chunk" {
SELECT count(_timescaledb_functions.recompress_chunk_segmentwise(i)) AS recompress
FROM show_chunks('sensor_data') i
LIMIT 1;
}
step "s1_rollback" {
ROLLBACK;
}

session "s2"
## locking up the catalog table will block the recompression from releasing the index lock
## we should not be deadlocking since the index lock has been reduced to ExclusiveLock
step "s2_block_on_compressed_chunk_size" {
BEGIN;
LOCK TABLE _timescaledb_catalog.compression_chunk_size;
}
step "s2_unblock" {
ROLLBACK;
}
step "s2_select_from_compressed_chunk" {
SELECT sum(temperature) > 1 FROM sensor_data WHERE sensor_id = 2;
}
## select should not be blocked by the recompress_chunk_segmentwise in progress
step "s2_wait_for_select_to_finish" {
}


permutation "s2_block_on_compressed_chunk_size" "s1_begin" "s1_recompress_chunk" "s2_select_from_compressed_chunk" "s2_wait_for_select_to_finish" "s2_unblock" "s1_rollback"