mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-14 17:43:34 +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
|
-- static
|
||||||
CREATE OR REPLACE FUNCTION _timescaledb_internal.calculate_new_chunk_times(
|
CREATE OR REPLACE FUNCTION _timescaledb_internal.calculate_new_chunk_times(
|
||||||
partition_id INT,
|
partition_id INT,
|
||||||
"time" BIGINT,
|
time_point BIGINT,
|
||||||
OUT table_start BIGINT,
|
OUT table_start BIGINT,
|
||||||
OUT table_end BIGINT
|
OUT table_end BIGINT
|
||||||
)
|
)
|
||||||
@ -27,8 +27,11 @@ $BODY$
|
|||||||
DECLARE
|
DECLARE
|
||||||
partition_epoch_row _timescaledb_catalog.partition_epoch;
|
partition_epoch_row _timescaledb_catalog.partition_epoch;
|
||||||
chunk_row _timescaledb_catalog.chunk;
|
chunk_row _timescaledb_catalog.chunk;
|
||||||
time_interval BIGINT;
|
time_interval BIGINT;
|
||||||
|
start_distinct_ctn BIGINT;
|
||||||
|
end_distinct_ctn BIGINT;
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
||||||
SELECT pe.*
|
SELECT pe.*
|
||||||
INTO partition_epoch_row
|
INTO partition_epoch_row
|
||||||
FROM _timescaledb_catalog.partition p
|
FROM _timescaledb_catalog.partition p
|
||||||
@ -36,6 +39,37 @@ BEGIN
|
|||||||
WHERE p.id = partition_id
|
WHERE p.id = partition_id
|
||||||
FOR SHARE;
|
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
|
SELECT chunk_time_interval
|
||||||
INTO time_interval
|
INTO time_interval
|
||||||
FROM _timescaledb_catalog.hypertable ht
|
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
|
-- Create start and stop times for the new chunk, subtract 1 from the end time
|
||||||
-- as chunk intervals are inclusive.
|
-- 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;
|
table_end := table_start + time_interval - 1;
|
||||||
|
|
||||||
-- Check whether the new chunk interval overlaps with existing chunks.
|
-- Check whether the new chunk interval overlaps with existing chunks.
|
||||||
@ -79,7 +113,8 @@ BEGIN
|
|||||||
END
|
END
|
||||||
$BODY$;
|
$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
|
-- static
|
||||||
CREATE OR REPLACE FUNCTION _timescaledb_internal.create_chunk_row(
|
CREATE OR REPLACE FUNCTION _timescaledb_internal.create_chunk_row(
|
||||||
part_id INT,
|
part_id INT,
|
||||||
@ -90,8 +125,8 @@ $BODY$
|
|||||||
DECLARE
|
DECLARE
|
||||||
table_start BIGINT;
|
table_start BIGINT;
|
||||||
table_end BIGINT;
|
table_end BIGINT;
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
||||||
SELECT *
|
SELECT *
|
||||||
INTO table_start, table_end
|
INTO table_start, table_end
|
||||||
FROM _timescaledb_internal.calculate_new_chunk_times(part_id, time_point);
|
FROM _timescaledb_internal.calculate_new_chunk_times(part_id, time_point);
|
||||||
@ -131,7 +166,7 @@ BEGIN
|
|||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
IF chunk_row IS NULL THEN -- recheck
|
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';
|
USING ERRCODE = 'IO501';
|
||||||
END IF;
|
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 | 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)
|
(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);
|
SELECT * FROM set_chunk_time_interval('chunk_test', 40::bigint);
|
||||||
|
|
||||||
|
|
||||||
INSERT INTO chunk_test VALUES(23, 3, 'dev3');
|
INSERT INTO chunk_test VALUES(23, 3, 'dev3');
|
||||||
|
|
||||||
SELECT * FROM chunk_test order by time, metric, device_id;
|
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'
|
WHERE h.schema_name = 'public' AND h.table_name = 'chunk_test'
|
||||||
ORDER BY c.id;
|
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