mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-14 09:37:00 +08:00
Ensure that chunks are aligned.
Previously, chunks could end up unaligned betweeen partitions if the chunk_time_interval was updated between chunk creations. Now there is a check when a chunk is created whether there is a chunk matching the time point in another partition and if there is, the new chunk is created with the same interval.
This commit is contained in:
parent
73622bf1eb
commit
2a01ebca61
@ -18,7 +18,7 @@ $BODY$;
|
||||
-- static
|
||||
CREATE OR REPLACE FUNCTION _timescaledb_internal.calculate_new_chunk_times(
|
||||
partition_id INT,
|
||||
"time" BIGINT,
|
||||
time_point BIGINT,
|
||||
OUT table_start BIGINT,
|
||||
OUT table_end BIGINT
|
||||
)
|
||||
@ -27,8 +27,11 @@ $BODY$
|
||||
DECLARE
|
||||
partition_epoch_row _timescaledb_catalog.partition_epoch;
|
||||
chunk_row _timescaledb_catalog.chunk;
|
||||
time_interval BIGINT;
|
||||
time_interval BIGINT;
|
||||
start_distinct_ctn BIGINT;
|
||||
end_distinct_ctn BIGINT;
|
||||
BEGIN
|
||||
|
||||
SELECT pe.*
|
||||
INTO partition_epoch_row
|
||||
FROM _timescaledb_catalog.partition p
|
||||
@ -36,6 +39,37 @@ BEGIN
|
||||
WHERE p.id = partition_id
|
||||
FOR SHARE;
|
||||
|
||||
-- Check if there are chunks in other partitions.
|
||||
-- If so, use their time range to keep chunks time aligned
|
||||
|
||||
SELECT COUNT(DISTINCT(start_time)), COUNT(DISTINCT(end_time))
|
||||
INTO start_distinct_ctn, end_distinct_ctn
|
||||
FROM _timescaledb_catalog.chunk c
|
||||
INNER JOIN _timescaledb_catalog.partition p ON (p.id = c.partition_id)
|
||||
WHERE c.start_time <= time_point AND
|
||||
c.end_time >= time_point AND
|
||||
p.epoch_id = partition_epoch_row.id;
|
||||
|
||||
-- Sanity check that all previous chunks between partitions are
|
||||
-- aligned
|
||||
IF start_distinct_ctn != 0 or end_distinct_ctn != 0 THEN
|
||||
-- At least one chunk exists, check that all chunks
|
||||
-- from other partitions are aligned
|
||||
IF start_distinct_ctn != 1 OR end_distinct_ctn != 1 THEN
|
||||
RAISE EXCEPTION 'Unaligned chunks between partitions';
|
||||
END IF;
|
||||
|
||||
SELECT start_time, end_time
|
||||
INTO table_start, table_end
|
||||
FROM _timescaledb_catalog.chunk AS c
|
||||
INNER JOIN _timescaledb_catalog.partition p ON (p.id = c.partition_id)
|
||||
WHERE c.start_time <= time_point AND
|
||||
c.end_time >= time_point AND
|
||||
p.epoch_id = partition_epoch_row.id LIMIT 1;
|
||||
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
SELECT chunk_time_interval
|
||||
INTO time_interval
|
||||
FROM _timescaledb_catalog.hypertable ht
|
||||
@ -43,7 +77,7 @@ BEGIN
|
||||
|
||||
-- Create start and stop times for the new chunk, subtract 1 from the end time
|
||||
-- as chunk intervals are inclusive.
|
||||
table_start := ("time" / time_interval) * time_interval;
|
||||
table_start := (time_point / time_interval) * time_interval;
|
||||
table_end := table_start + time_interval - 1;
|
||||
|
||||
-- Check whether the new chunk interval overlaps with existing chunks.
|
||||
@ -79,7 +113,8 @@ BEGIN
|
||||
END
|
||||
$BODY$;
|
||||
|
||||
-- creates the row in the chunk table. Prerequisite: appropriate lock.
|
||||
-- creates the row in the chunk table. Prerequisite: appropriate lock and check that chunk does not
|
||||
-- already exist.
|
||||
-- static
|
||||
CREATE OR REPLACE FUNCTION _timescaledb_internal.create_chunk_row(
|
||||
part_id INT,
|
||||
@ -90,8 +125,8 @@ $BODY$
|
||||
DECLARE
|
||||
table_start BIGINT;
|
||||
table_end BIGINT;
|
||||
BEGIN
|
||||
|
||||
BEGIN
|
||||
|
||||
SELECT *
|
||||
INTO table_start, table_end
|
||||
FROM _timescaledb_internal.calculate_new_chunk_times(part_id, time_point);
|
||||
@ -131,7 +166,7 @@ BEGIN
|
||||
END IF;
|
||||
|
||||
IF chunk_row IS NULL THEN -- recheck
|
||||
RAISE EXCEPTION 'Should never happen: chunk not found after creation on meta'
|
||||
RAISE EXCEPTION 'Should never happen: chunk not found after creation'
|
||||
USING ERRCODE = 'IO501';
|
||||
END IF;
|
||||
|
||||
|
@ -78,3 +78,48 @@ SELECT * FROM _timescaledb_catalog.chunk c
|
||||
4 | 1 | 10 | 39 | _timescaledb_internal | _hyper_1_4_chunk | 1 | 1 | 0 | 16383 | | 1 | 1 | | | 2 | _timescaledb_internal | get_partition_for_key | 32768 | device_id | 1 | public | chunk_test | _timescaledb_internal | _hyper_1 | time | bigint | 40
|
||||
(4 rows)
|
||||
|
||||
-- Test chunk aligning between partitions
|
||||
CREATE TABLE chunk_align_test(
|
||||
time BIGINT,
|
||||
metric INTEGER,
|
||||
device_id TEXT
|
||||
);
|
||||
SELECT * FROM create_hypertable('chunk_align_test', 'time', 'device_id', 2, chunk_time_interval => 10);
|
||||
create_hypertable
|
||||
-------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
INSERT INTO chunk_align_test VALUES (1, 1, 'dev1'); -- this should create a 10 wide chunk
|
||||
SELECT c.id,partition_id,c.start_time,c.end_time,h.table_name,p.epoch_id FROM _timescaledb_catalog.chunk c
|
||||
LEFT JOIN _timescaledb_catalog.partition p ON (p.id = c.partition_id)
|
||||
LEFT JOIN _timescaledb_catalog.partition_epoch pe ON (pe.id = p.epoch_id)
|
||||
LEFT JOIN _timescaledb_catalog.hypertable h ON (pe.hypertable_id = h.id)
|
||||
WHERE h.schema_name = 'public' AND h.table_name = 'chunk_align_test'
|
||||
ORDER BY c.id;
|
||||
id | partition_id | start_time | end_time | table_name | epoch_id
|
||||
----+--------------+------------+----------+------------------+----------
|
||||
5 | 3 | 0 | 9 | chunk_align_test | 2
|
||||
(1 row)
|
||||
|
||||
SELECT * FROM set_chunk_time_interval('chunk_align_test', 40::bigint);
|
||||
set_chunk_time_interval
|
||||
-------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
INSERT INTO chunk_align_test VALUES (5, 1, 'dev2'); -- this should still create a 10 wide chunk
|
||||
INSERT INTO chunk_align_test VALUES (45, 1, 'dev2'); -- this should create a 40 wide chunk
|
||||
SELECT c.id,partition_id,c.start_time,c.end_time,h.table_name,p.epoch_id FROM _timescaledb_catalog.chunk c
|
||||
LEFT JOIN _timescaledb_catalog.partition p ON (p.id = c.partition_id)
|
||||
LEFT JOIN _timescaledb_catalog.partition_epoch pe ON (pe.id = p.epoch_id)
|
||||
LEFT JOIN _timescaledb_catalog.hypertable h ON (pe.hypertable_id = h.id)
|
||||
WHERE h.schema_name = 'public' AND h.table_name = 'chunk_align_test'
|
||||
ORDER BY c.id;
|
||||
id | partition_id | start_time | end_time | table_name | epoch_id
|
||||
----+--------------+------------+----------+------------------+----------
|
||||
5 | 3 | 0 | 9 | chunk_align_test | 2
|
||||
6 | 4 | 0 | 9 | chunk_align_test | 2
|
||||
7 | 4 | 40 | 79 | chunk_align_test | 2
|
||||
(3 rows)
|
||||
|
||||
|
@ -17,7 +17,6 @@ INSERT INTO chunk_test VALUES (1, 1, 'dev1'),
|
||||
|
||||
SELECT * FROM set_chunk_time_interval('chunk_test', 40::bigint);
|
||||
|
||||
|
||||
INSERT INTO chunk_test VALUES(23, 3, 'dev3');
|
||||
|
||||
SELECT * FROM chunk_test order by time, metric, device_id;
|
||||
@ -32,3 +31,31 @@ SELECT * FROM _timescaledb_catalog.chunk c
|
||||
WHERE h.schema_name = 'public' AND h.table_name = 'chunk_test'
|
||||
ORDER BY c.id;
|
||||
|
||||
|
||||
-- Test chunk aligning between partitions
|
||||
CREATE TABLE chunk_align_test(
|
||||
time BIGINT,
|
||||
metric INTEGER,
|
||||
device_id TEXT
|
||||
);
|
||||
SELECT * FROM create_hypertable('chunk_align_test', 'time', 'device_id', 2, chunk_time_interval => 10);
|
||||
|
||||
INSERT INTO chunk_align_test VALUES (1, 1, 'dev1'); -- this should create a 10 wide chunk
|
||||
|
||||
SELECT c.id,partition_id,c.start_time,c.end_time,h.table_name,p.epoch_id FROM _timescaledb_catalog.chunk c
|
||||
LEFT JOIN _timescaledb_catalog.partition p ON (p.id = c.partition_id)
|
||||
LEFT JOIN _timescaledb_catalog.partition_epoch pe ON (pe.id = p.epoch_id)
|
||||
LEFT JOIN _timescaledb_catalog.hypertable h ON (pe.hypertable_id = h.id)
|
||||
WHERE h.schema_name = 'public' AND h.table_name = 'chunk_align_test'
|
||||
ORDER BY c.id;
|
||||
|
||||
SELECT * FROM set_chunk_time_interval('chunk_align_test', 40::bigint);
|
||||
INSERT INTO chunk_align_test VALUES (5, 1, 'dev2'); -- this should still create a 10 wide chunk
|
||||
INSERT INTO chunk_align_test VALUES (45, 1, 'dev2'); -- this should create a 40 wide chunk
|
||||
|
||||
SELECT c.id,partition_id,c.start_time,c.end_time,h.table_name,p.epoch_id FROM _timescaledb_catalog.chunk c
|
||||
LEFT JOIN _timescaledb_catalog.partition p ON (p.id = c.partition_id)
|
||||
LEFT JOIN _timescaledb_catalog.partition_epoch pe ON (pe.id = p.epoch_id)
|
||||
LEFT JOIN _timescaledb_catalog.hypertable h ON (pe.hypertable_id = h.id)
|
||||
WHERE h.schema_name = 'public' AND h.table_name = 'chunk_align_test'
|
||||
ORDER BY c.id;
|
||||
|
Loading…
x
Reference in New Issue
Block a user