Skip to content

Commit 7ffdd07

Browse files
committed
Reduce locking on decompress_chunk to allow reads
With a recent change, we updated the lock on decompress_chunk to take an AccessExclusiveLock on the uncompressed chunk at the start of this potentially long running operation. Reducing this lock to ExclusiveLock would enable reads to execute while we are decompressing the chunk. AccessExclusive lock will be taken on the compressed chunk at the end of the operation, during its removal.
1 parent 626975f commit 7ffdd07

File tree

4 files changed

+136
-4
lines changed

4 files changed

+136
-4
lines changed

tsl/src/compression/api.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -607,12 +607,14 @@ decompress_chunk_impl(Chunk *uncompressed_chunk, bool if_compressed)
607607
/*
608608
* Lock the compressed chunk that is going to be deleted. At this point,
609609
* the reference to the compressed chunk is already removed from the
610-
* catalog. So, new readers do not include it in their operations.
610+
* catalog but we need to block readers from accessing this chunk
611+
* until the catalog changes are visible to them.
611612
*
612613
* Note: Calling performMultipleDeletions in chunk_index_tuple_delete
613614
* also requests an AccessExclusiveLock on the compressed_chunk. However,
614615
* this call makes the lock on the chunk explicit.
615616
*/
617+
LockRelationOid(uncompressed_chunk->table_id, AccessExclusiveLock);
616618
LockRelationOid(compressed_chunk->table_id, AccessExclusiveLock);
617619
ts_chunk_drop(compressed_chunk, DROP_RESTRICT, -1);
618620
ts_cache_release(hcache);

tsl/src/compression/compression.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -1498,9 +1498,9 @@ decompress_chunk(Oid in_table, Oid out_table)
14981498
* We want to prevent other decompressors from decompressing this table,
14991499
* and we want to prevent INSERTs or UPDATEs which could mess up our decompression.
15001500
* We may as well allow readers to keep reading the compressed data while
1501-
* we are compressing, so we only take an ExclusiveLock instead of AccessExclusive.
1501+
* we are decompressing, so we only take an ExclusiveLock instead of AccessExclusive.
15021502
*/
1503-
Relation out_rel = table_open(out_table, AccessExclusiveLock);
1503+
Relation out_rel = table_open(out_table, ExclusiveLock);
15041504
Relation in_rel = table_open(in_table, ExclusiveLock);
15051505
int64 nrows_processed = 0;
15061506

tsl/test/isolation/expected/compression_conflicts_iso.out

+106-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Parsed test spec with 9 sessions
1+
Parsed test spec with 10 sessions
22

33
starting permutation: LockChunk1 IB I1 C1 UnlockChunk Ic Cc SC1 S1 SChunkStat
44
step LockChunk1:
@@ -2954,3 +2954,108 @@ time|device|location|value
29542954
1| 1| 100| 99
29552955
(1 row)
29562956

2957+
2958+
starting permutation: CA1 CAc LockChunkTuple DA1 SA SF UnlockChunkTuple DAc
2959+
step CA1:
2960+
BEGIN;
2961+
SELECT
2962+
CASE WHEN compress_chunk(ch) IS NOT NULL THEN true ELSE false END AS compress
2963+
FROM show_chunks('ts_device_table') AS ch
2964+
ORDER BY ch::text;
2965+
2966+
compress
2967+
--------
2968+
t
2969+
(1 row)
2970+
2971+
step CAc: COMMIT;
2972+
step LockChunkTuple:
2973+
BEGIN;
2974+
SELECT status as chunk_status from _timescaledb_catalog.chunk
2975+
WHERE id = ( select min(ch.id) FROM _timescaledb_catalog.hypertable ht, _timescaledb_catalog.chunk ch WHERE ch.hypertable_id = ht.id AND ht.table_name like 'ts_device_table') FOR UPDATE;
2976+
2977+
chunk_status
2978+
------------
2979+
1
2980+
(1 row)
2981+
2982+
step DA1:
2983+
BEGIN;
2984+
SELECT
2985+
CASE WHEN decompress_chunk(ch) IS NOT NULL THEN true ELSE false END AS compress
2986+
FROM show_chunks('ts_device_table') AS ch
2987+
ORDER BY ch::text;
2988+
<waiting ...>
2989+
step SA: SELECT * FROM ts_device_table;
2990+
time|device|location|value
2991+
----+------+--------+-----
2992+
0| 1| 100| 20
2993+
1| 1| 100| 20
2994+
2| 1| 100| 20
2995+
3| 1| 100| 20
2996+
4| 1| 100| 20
2997+
5| 1| 100| 20
2998+
6| 1| 100| 20
2999+
7| 1| 100| 20
3000+
8| 1| 100| 20
3001+
9| 1| 100| 20
3002+
(10 rows)
3003+
3004+
step SF:
3005+
step UnlockChunkTuple: ROLLBACK;
3006+
step DA1: <... completed>
3007+
compress
3008+
--------
3009+
t
3010+
(1 row)
3011+
3012+
step DAc: COMMIT;
3013+
3014+
starting permutation: SB SA CA1 SA SF SR CAc
3015+
step SB: BEGIN;
3016+
step SA: SELECT * FROM ts_device_table;
3017+
time|device|location|value
3018+
----+------+--------+-----
3019+
0| 1| 100| 20
3020+
1| 1| 100| 20
3021+
2| 1| 100| 20
3022+
3| 1| 100| 20
3023+
4| 1| 100| 20
3024+
5| 1| 100| 20
3025+
6| 1| 100| 20
3026+
7| 1| 100| 20
3027+
8| 1| 100| 20
3028+
9| 1| 100| 20
3029+
(10 rows)
3030+
3031+
step CA1:
3032+
BEGIN;
3033+
SELECT
3034+
CASE WHEN compress_chunk(ch) IS NOT NULL THEN true ELSE false END AS compress
3035+
FROM show_chunks('ts_device_table') AS ch
3036+
ORDER BY ch::text;
3037+
<waiting ...>
3038+
step SA: SELECT * FROM ts_device_table;
3039+
time|device|location|value
3040+
----+------+--------+-----
3041+
0| 1| 100| 20
3042+
1| 1| 100| 20
3043+
2| 1| 100| 20
3044+
3| 1| 100| 20
3045+
4| 1| 100| 20
3046+
5| 1| 100| 20
3047+
6| 1| 100| 20
3048+
7| 1| 100| 20
3049+
8| 1| 100| 20
3050+
9| 1| 100| 20
3051+
(10 rows)
3052+
3053+
step SF:
3054+
step SR: ROLLBACK;
3055+
step CA1: <... completed>
3056+
compress
3057+
--------
3058+
t
3059+
(1 row)
3060+
3061+
step CAc: COMMIT;

tsl/test/isolation/specs/compression_conflicts_iso.spec

+25
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,15 @@ step "SChunkStat" { SELECT status from _timescaledb_catalog.chunk
4949
WHERE id = ( select min(ch.id) FROM _timescaledb_catalog.hypertable ht, _timescaledb_catalog.chunk ch WHERE ch.hypertable_id = ht.id AND ht.table_name like 'ts_device_table'); }
5050

5151
session "S"
52+
step "SB" { BEGIN; }
53+
step "SR" { ROLLBACK; }
5254
step "S1" { SELECT count(*) from ts_device_table; }
5355
step "SC1" { SELECT (count_chunktable(ch)).* FROM show_chunks('ts_device_table') AS ch LIMIT 1; }
5456
step "SH" { SELECT total_chunks, number_compressed_chunks from hypertable_compression_stats('ts_device_table'); }
5557
step "SA" { SELECT * FROM ts_device_table; }
5658
step "SU" { SELECT * FROM ts_device_table WHERE value IN (98,99); }
59+
# Step to confirm previous step finished
60+
step "SF" {}
5761

5862

5963
session "LCT"
@@ -98,6 +102,16 @@ step "CA1" {
98102
}
99103
step "CAc" { COMMIT; }
100104

105+
session "DecompressAll"
106+
step "DA1" {
107+
BEGIN;
108+
SELECT
109+
CASE WHEN decompress_chunk(ch) IS NOT NULL THEN true ELSE false END AS compress
110+
FROM show_chunks('ts_device_table') AS ch
111+
ORDER BY ch::text;
112+
}
113+
step "DAc" { COMMIT; }
114+
101115
session "RecompressChunk"
102116
step "RC" {
103117
DO $$
@@ -167,3 +181,14 @@ permutation "CA1" "CAc" "I1" "SChunkStat" "LockChunk1" "IBRR" "Iu1" "RC" "Unloc
167181
permutation "CA1" "CAc" "I1" "SChunkStat" "LockChunk1" "IBS" "Iu1" "RC" "UnlockChunk" "Ic" "SH" "SA" "SChunkStat" "SU"
168182
permutation "CA1" "CAc" "I1" "SChunkStat" "LockChunk1" "IN1" "RC" "UnlockChunk" "INc" "SH" "SA" "SChunkStat"
169183
permutation "CA1" "CAc" "I1" "SChunkStat" "LockChunk1" "INu1" "RC" "UnlockChunk" "INc" "SH" "SA" "SChunkStat" "SU"
184+
185+
# Decompressing a chunk should not stop any reads
186+
# until the end when we drop the compressed chunk
187+
# which happens after updates to the chunk catalog tuple
188+
permutation "CA1" "CAc" "LockChunkTuple" "DA1" "SA" "SF" "UnlockChunkTuple" "DAc"
189+
190+
# Compressing a chunk should not stop any reads
191+
# until it comes to truncating the uncompressed chunk
192+
# which happens at the end of the operations along with
193+
# catalog updates.
194+
permutation "SB" "SA" "CA1" "SA" "SF" "SR" "CAc"

0 commit comments

Comments
 (0)