diff --git a/src/chunk.c b/src/chunk.c index 9835600ba..918a0f6f5 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -580,7 +580,7 @@ create_toast_table(CreateStmt *stmt, Oid chunk_oid) * instead needs the proper permissions on the database to create the schema. */ Oid -ts_chunk_create_table(Chunk *chunk, Hypertable *ht) +ts_chunk_create_table(Chunk *chunk, Hypertable *ht, char *tablespacename) { Relation rel; ObjectAddress objaddr; @@ -590,7 +590,7 @@ ts_chunk_create_table(Chunk *chunk, Hypertable *ht) .relation = makeRangeVar(NameStr(chunk->fd.schema_name), NameStr(chunk->fd.table_name), 0), .inhRelations = list_make1(makeRangeVar(NameStr(ht->fd.schema_name), NameStr(ht->fd.table_name), 0)), - .tablespacename = ts_hypertable_select_tablespace_name(ht, chunk), + .tablespacename = tablespacename, .options = get_reloptions(ht->main_table_relid), }; Oid uid, saved_uid; @@ -679,7 +679,8 @@ chunk_create_after_lock(Hypertable *ht, Point *p, const char *schema, const char ts_chunk_add_constraints(chunk); /* Create the actual table relation for the chunk */ - chunk->table_id = ts_chunk_create_table(chunk, ht); + chunk->table_id = + ts_chunk_create_table(chunk, ht, ts_hypertable_select_tablespace_name(ht, chunk)); if (!OidIsValid(chunk->table_id)) elog(ERROR, "could not create chunk table"); diff --git a/src/chunk.h b/src/chunk.h index 966aa173b..956ad2356 100644 --- a/src/chunk.h +++ b/src/chunk.h @@ -95,7 +95,7 @@ extern Chunk *ts_chunk_get_by_name_with_memory_context(const char *schema_name, bool fail_if_not_found); extern TSDLLEXPORT void ts_chunk_insert_lock(Chunk *chunk, LOCKMODE lock); -extern TSDLLEXPORT Oid ts_chunk_create_table(Chunk *chunk, Hypertable *ht); +extern TSDLLEXPORT Oid ts_chunk_create_table(Chunk *chunk, Hypertable *ht, char *tablespacename); extern TSDLLEXPORT Chunk *ts_chunk_get_by_id(int32 id, int16 num_constraints, bool fail_if_not_found); extern TSDLLEXPORT Chunk *ts_chunk_get_by_relid(Oid relid, int16 num_constraints, diff --git a/tsl/src/compression/create.c b/tsl/src/compression/create.c index a89df5c9d..c3e4eaf4c 100644 --- a/tsl/src/compression/create.c +++ b/tsl/src/compression/create.c @@ -562,6 +562,8 @@ create_compress_chunk_table(Hypertable *compress_ht, Chunk *src_chunk) NameStr(compress_ht->fd.associated_table_prefix), compress_chunk->fd.id); + ; + /* Insert chunk */ ts_chunk_insert_lock(compress_chunk, RowExclusiveLock); @@ -570,8 +572,15 @@ create_compress_chunk_table(Hypertable *compress_ht, Chunk *src_chunk) compress_chunk->fd.id, compress_chunk->hypertable_relid); - /* Create the actual table relation for the chunk */ - compress_chunk->table_id = ts_chunk_create_table(compress_chunk, compress_ht); + /* Create the actual table relation for the chunk + * Note that we have to pick the tablespace here as the compressed ht doesn't have dimensions + * on which to base this decision. We simply pick the same tablespace as the uncompressed chunk + * for now. + */ + compress_chunk->table_id = + ts_chunk_create_table(compress_chunk, + compress_ht, + get_tablespace_name(get_rel_tablespace(src_chunk->table_id))); if (!OidIsValid(compress_chunk->table_id)) elog(ERROR, "could not create compress chunk table"); diff --git a/tsl/src/reorder.c b/tsl/src/reorder.c index a7ebe62f6..30859cf5d 100644 --- a/tsl/src/reorder.c +++ b/tsl/src/reorder.c @@ -174,6 +174,11 @@ reorder_chunk(Oid chunk_id, Oid index_id, bool verbose, Oid wait_id, Oid destina (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("\"%s\" is not a chunk", get_rel_name(chunk_id)))); + if (chunk->fd.compressed_chunk_id != INVALID_CHUNK_ID) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("\"%s\" is a compressed chunk", get_rel_name(chunk_id)))); + hcache = ts_hypertable_cache_pin(); ht = ts_hypertable_cache_get_entry(hcache, chunk->hypertable_relid); if (NULL == ht) diff --git a/tsl/test/expected/compression_ddl.out b/tsl/test/expected/compression_ddl.out index 8bc92ea7a..858d654b0 100644 --- a/tsl/test/expected/compression_ddl.out +++ b/tsl/test/expected/compression_ddl.out @@ -44,7 +44,8 @@ NOTICE: adding not-null constraint to column "Time" (1 row) INSERT INTO test1 SELECT t, gen_rand_minstd(), gen_rand_minstd(), gen_rand_minstd()::text FROM generate_series('2018-03-02 1:00'::TIMESTAMPTZ, '2018-03-28 1:00', '1 hour') t; -ALTER TABLE test1 set (timescaledb.compress, timescaledb.compress_segmentby = '', timescaledb.compress_orderby = '"Time" DESC'); +ALTER TABLE test1 set (timescaledb.compress, timescaledb.compress_segmentby = 'b', timescaledb.compress_orderby = '"Time" DESC'); +NOTICE: adding index _compressed_hypertable_2_b__ts_meta_sequence_num_idx ON _timescaledb_internal._compressed_hypertable_2 USING BTREE(b, _ts_meta_sequence_num) SELECT COUNT(*) AS count_compressed FROM ( @@ -67,6 +68,19 @@ DROP INDEX new_index; ALTER TABLE test1 SET (fillfactor=100); ALTER TABLE test1 RESET (fillfactor); ALTER TABLE test1 ALTER COLUMN b SET STATISTICS 10; +-- TABLESPACES +-- For tablepaces with compressed chunks the semantics are the following: +-- - compressed chunks get put into the same tablespace as the +-- uncommpressed chunk on compression. +-- - set tablespace on uncompressed hypertable cascades to compressed hypertable+chunks +-- - set tablespace on all chunks is blocked (same as w/o compression) +-- - move chunks on a uncompressed chunk errors +-- - move chunks on compressed chunk works +--In the future we will: +-- - add tablespace option to compress_chunk function and policy (this will override the setting +-- of the uncompressed chunk). This will allow changing tablespaces upon compression +-- - Note: The current plan is to never listen to the setting on compressed hypertable. In fact, +-- we will block setting tablespace on compressed hypertables SELECT count(*) as "COUNT_CHUNKS_UNCOMPRESSED" FROM _timescaledb_catalog.chunk chunk INNER JOIN _timescaledb_catalog.hypertable hypertable ON (chunk.hypertable_id = hypertable.id) @@ -93,6 +107,79 @@ FROM pg_tables WHERE tablespace = 'tablespace2'; t (1 row) +SELECT + comp_chunk.schema_name|| '.' || comp_chunk.table_name as "COMPRESSED_CHUNK_NAME", + uncomp_chunk.schema_name|| '.' || uncomp_chunk.table_name as "UNCOMPRESSED_CHUNK_NAME" +FROM _timescaledb_catalog.chunk comp_chunk +INNER JOIN _timescaledb_catalog.hypertable comp_hyper ON (comp_chunk.hypertable_id = comp_hyper.id) +INNER JOIN _timescaledb_catalog.hypertable uncomp_hyper ON (comp_hyper.id = uncomp_hyper.compressed_hypertable_id) +INNER JOIN _timescaledb_catalog.chunk uncomp_chunk ON (uncomp_chunk.compressed_chunk_id = comp_chunk.id) +WHERE uncomp_hyper.table_name like 'test1' ORDER BY comp_chunk.id LIMIT 1\gset +\set ON_ERROR_STOP 0 +--set tablespace is blocked on chunks for now; if this ever changes we need +--to test that path to make sure it passes down the tablespace. +ALTER TABLE :UNCOMPRESSED_CHUNK_NAME SET TABLESPACE tablespace1; +ERROR: operation not supported on chunk tables +SELECT move_chunk(chunk=>:'UNCOMPRESSED_CHUNK_NAME', destination_tablespace=>'tablespace1', index_destination_tablespace=>'tablespace1', reorder_index=>'_timescaledb_internal."_hyper_1_1_chunk_test1_Time_idx"'); +WARNING: Timescale License expired +ERROR: "_hyper_1_1_chunk" is a compressed chunk +\set ON_ERROR_STOP 1 +SELECT move_chunk(chunk=>:'COMPRESSED_CHUNK_NAME', destination_tablespace=>'tablespace1', index_destination_tablespace=>'tablespace1', reorder_index=>'_timescaledb_internal."compress_hyper_2_28_chunk__compressed_hypertable_2_b__ts_meta_s"'); + move_chunk +------------ + +(1 row) + +-- the compressed chunk is in here now +SELECT count(*) +FROM pg_tables WHERE tablespace = 'tablespace1'; + count +------- + 1 +(1 row) + +SELECT decompress_chunk(:'UNCOMPRESSED_CHUNK_NAME'); + decompress_chunk +------------------ + +(1 row) + +--the compresse chunk was dropped by decompression +SELECT count(*) +FROM pg_tables WHERE tablespace = 'tablespace1'; + count +------- + 0 +(1 row) + +SELECT move_chunk(chunk=>:'UNCOMPRESSED_CHUNK_NAME', destination_tablespace=>'tablespace1', index_destination_tablespace=>'tablespace1', reorder_index=>'_timescaledb_internal."_hyper_1_1_chunk_test1_Time_idx"'); + move_chunk +------------ + +(1 row) + +--the uncompressed chunks has now been moved +SELECT count(*) +FROM pg_tables WHERE tablespace = 'tablespace1'; + count +------- + 1 +(1 row) + +SELECT compress_chunk(:'UNCOMPRESSED_CHUNK_NAME'); + compress_chunk +---------------- + +(1 row) + +--the compressed chunk is now in the same tablespace as the uncompressed one +SELECT count(*) +FROM pg_tables WHERE tablespace = 'tablespace1'; + count +------- + 2 +(1 row) + -- -- DROP CHUNKS -- diff --git a/tsl/test/sql/compression_ddl.sql b/tsl/test/sql/compression_ddl.sql index d2fb9662e..b22eef98f 100644 --- a/tsl/test/sql/compression_ddl.sql +++ b/tsl/test/sql/compression_ddl.sql @@ -22,8 +22,7 @@ SELECT table_name from create_hypertable('test1', 'Time', chunk_time_interval=> INSERT INTO test1 SELECT t, gen_rand_minstd(), gen_rand_minstd(), gen_rand_minstd()::text FROM generate_series('2018-03-02 1:00'::TIMESTAMPTZ, '2018-03-28 1:00', '1 hour') t; -ALTER TABLE test1 set (timescaledb.compress, timescaledb.compress_segmentby = '', timescaledb.compress_orderby = '"Time" DESC'); - +ALTER TABLE test1 set (timescaledb.compress, timescaledb.compress_segmentby = 'b', timescaledb.compress_orderby = '"Time" DESC'); SELECT COUNT(*) AS count_compressed FROM @@ -46,6 +45,22 @@ ALTER TABLE test1 RESET (fillfactor); ALTER TABLE test1 ALTER COLUMN b SET STATISTICS 10; +-- TABLESPACES +-- For tablepaces with compressed chunks the semantics are the following: +-- - compressed chunks get put into the same tablespace as the +-- uncommpressed chunk on compression. +-- - set tablespace on uncompressed hypertable cascades to compressed hypertable+chunks +-- - set tablespace on all chunks is blocked (same as w/o compression) +-- - move chunks on a uncompressed chunk errors +-- - move chunks on compressed chunk works + +--In the future we will: +-- - add tablespace option to compress_chunk function and policy (this will override the setting +-- of the uncompressed chunk). This will allow changing tablespaces upon compression +-- - Note: The current plan is to never listen to the setting on compressed hypertable. In fact, +-- we will block setting tablespace on compressed hypertables + + SELECT count(*) as "COUNT_CHUNKS_UNCOMPRESSED" FROM _timescaledb_catalog.chunk chunk INNER JOIN _timescaledb_catalog.hypertable hypertable ON (chunk.hypertable_id = hypertable.id) @@ -67,6 +82,46 @@ ALTER TABLE test1 SET TABLESPACE tablespace2; SELECT count(*) = (:COUNT_CHUNKS_UNCOMPRESSED +:COUNT_CHUNKS_COMPRESSED + 2) FROM pg_tables WHERE tablespace = 'tablespace2'; +SELECT + comp_chunk.schema_name|| '.' || comp_chunk.table_name as "COMPRESSED_CHUNK_NAME", + uncomp_chunk.schema_name|| '.' || uncomp_chunk.table_name as "UNCOMPRESSED_CHUNK_NAME" +FROM _timescaledb_catalog.chunk comp_chunk +INNER JOIN _timescaledb_catalog.hypertable comp_hyper ON (comp_chunk.hypertable_id = comp_hyper.id) +INNER JOIN _timescaledb_catalog.hypertable uncomp_hyper ON (comp_hyper.id = uncomp_hyper.compressed_hypertable_id) +INNER JOIN _timescaledb_catalog.chunk uncomp_chunk ON (uncomp_chunk.compressed_chunk_id = comp_chunk.id) +WHERE uncomp_hyper.table_name like 'test1' ORDER BY comp_chunk.id LIMIT 1\gset + +\set ON_ERROR_STOP 0 +--set tablespace is blocked on chunks for now; if this ever changes we need +--to test that path to make sure it passes down the tablespace. +ALTER TABLE :UNCOMPRESSED_CHUNK_NAME SET TABLESPACE tablespace1; + +SELECT move_chunk(chunk=>:'UNCOMPRESSED_CHUNK_NAME', destination_tablespace=>'tablespace1', index_destination_tablespace=>'tablespace1', reorder_index=>'_timescaledb_internal."_hyper_1_1_chunk_test1_Time_idx"'); +\set ON_ERROR_STOP 1 + +SELECT move_chunk(chunk=>:'COMPRESSED_CHUNK_NAME', destination_tablespace=>'tablespace1', index_destination_tablespace=>'tablespace1', reorder_index=>'_timescaledb_internal."compress_hyper_2_28_chunk__compressed_hypertable_2_b__ts_meta_s"'); + +-- the compressed chunk is in here now +SELECT count(*) +FROM pg_tables WHERE tablespace = 'tablespace1'; + +SELECT decompress_chunk(:'UNCOMPRESSED_CHUNK_NAME'); + +--the compresse chunk was dropped by decompression +SELECT count(*) +FROM pg_tables WHERE tablespace = 'tablespace1'; + +SELECT move_chunk(chunk=>:'UNCOMPRESSED_CHUNK_NAME', destination_tablespace=>'tablespace1', index_destination_tablespace=>'tablespace1', reorder_index=>'_timescaledb_internal."_hyper_1_1_chunk_test1_Time_idx"'); + +--the uncompressed chunks has now been moved +SELECT count(*) +FROM pg_tables WHERE tablespace = 'tablespace1'; + +SELECT compress_chunk(:'UNCOMPRESSED_CHUNK_NAME'); + +--the compressed chunk is now in the same tablespace as the uncompressed one +SELECT count(*) +FROM pg_tables WHERE tablespace = 'tablespace1'; --