diff --git a/src/chunk.c b/src/chunk.c index d2c16aa0d..c5a92204f 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -1093,7 +1093,8 @@ chunk_create_table_constraints(const Chunk *chunk) ts_chunk_index_create_all(chunk->fd.hypertable_id, chunk->hypertable_relid, chunk->fd.id, - chunk->table_id); + chunk->table_id, + InvalidOid); } } diff --git a/src/chunk_index.c b/src/chunk_index.c index 87bbc56ff..a4a3fd768 100644 --- a/src/chunk_index.c +++ b/src/chunk_index.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -380,7 +381,7 @@ ts_chunk_index_create_from_constraint(int32 hypertable_id, Oid hypertable_constr */ static void chunk_index_create(Relation hypertable_rel, int32 hypertable_id, Relation hypertable_idxrel, - int32 chunk_id, Relation chunkrel, Oid constraint_oid) + int32 chunk_id, Relation chunkrel, Oid constraint_oid, Oid index_tblspc) { Oid chunk_indexrelid; @@ -393,8 +394,11 @@ chunk_index_create(Relation hypertable_rel, int32 hypertable_id, Relation hypert return; } - chunk_indexrelid = - chunk_relation_index_create(hypertable_rel, hypertable_idxrel, chunkrel, false, InvalidOid); + chunk_indexrelid = chunk_relation_index_create(hypertable_rel, + hypertable_idxrel, + chunkrel, + false, + index_tblspc); chunk_index_insert(chunk_id, get_rel_name(chunk_indexrelid), @@ -425,7 +429,8 @@ ts_chunk_index_create_from_adjusted_index_info(int32 hypertable_id, Relation hyp * hypertable. */ void -ts_chunk_index_create_all(int32 hypertable_id, Oid hypertable_relid, int32 chunk_id, Oid chunkrelid) +ts_chunk_index_create_all(int32 hypertable_id, Oid hypertable_relid, int32 chunk_id, Oid chunkrelid, + Oid index_tblspc) { Relation htrel; Relation chunkrel; @@ -467,7 +472,8 @@ ts_chunk_index_create_all(int32 hypertable_id, Oid hypertable_relid, int32 chunk hypertable_idxrel, chunk_id, chunkrel, - get_index_constraint(hypertable_idxoid)); + get_index_constraint(hypertable_idxoid), + index_tblspc); index_close(hypertable_idxrel, AccessShareLock); } @@ -1261,3 +1267,34 @@ ts_chunk_index_replace(PG_FUNCTION_ARGS) PG_RETURN_VOID(); } + +void +ts_chunk_index_move_all(Oid chunk_relid, Oid index_tblspc) +{ + Relation chunkrel; + List *indexlist; + ListCell *lc; + const char chunk_relkind = get_rel_relkind(chunk_relid); + + /* execute ALTER INDEX .. SET TABLESPACE for each index on the chunk */ + AlterTableCmd cmd = { .type = T_AlterTableCmd, + .subtype = AT_SetTableSpace, + .name = get_tablespace_name(index_tblspc) }; + + /* Foreign table chunks don't support indexes */ + if (chunk_relkind == RELKIND_FOREIGN_TABLE) + return; + + Assert(chunk_relkind == RELKIND_RELATION); + + chunkrel = table_open(chunk_relid, AccessShareLock); + + indexlist = RelationGetIndexList(chunkrel); + + foreach (lc, indexlist) + { + Oid chunk_idxoid = lfirst_oid(lc); + AlterTableInternal(chunk_idxoid, list_make1(&cmd), false); + } + table_close(chunkrel, AccessShareLock); +} diff --git a/src/chunk_index.h b/src/chunk_index.h index a9dc947b2..57f376d8c 100644 --- a/src/chunk_index.h +++ b/src/chunk_index.h @@ -35,7 +35,8 @@ extern void ts_chunk_index_create_from_adjusted_index_info(int32 hypertable_id, int32 chunk_id, Relation chunkrel, IndexInfo *indexinfo); extern TSDLLEXPORT void ts_chunk_index_create_all(int32 hypertable_id, Oid hypertable_relid, - int32 chunk_id, Oid chunkrelid); + int32 chunk_id, Oid chunkrelid, Oid index_tblspc); +extern TSDLLEXPORT void ts_chunk_index_move_all(Oid chunk_relid, Oid index_tblspc); extern int ts_chunk_index_delete(int32 chunk_id, const char *indexname, bool drop_index); extern int ts_chunk_index_delete_by_chunk_id(int32 chunk_id, bool drop_index); extern void ts_chunk_index_delete_by_name(const char *schema, const char *index_name, diff --git a/tsl/src/compression/create.c b/tsl/src/compression/create.c index ed705580e..e3ef8aa2f 100644 --- a/tsl/src/compression/create.c +++ b/tsl/src/compression/create.c @@ -587,6 +587,7 @@ create_compress_chunk_table(Hypertable *compress_ht, Chunk *src_chunk) CatalogSecurityContext sec_ctx; Chunk *compress_chunk; int namelen; + Oid tablespace_oid; const char *tablespace; /* Create a new chunk based on the hypercube */ @@ -632,16 +633,24 @@ create_compress_chunk_table(Hypertable *compress_ht, Chunk *src_chunk) * on which to base this decision. We simply pick the same tablespace as the uncompressed chunk * for now. */ - tablespace = get_tablespace_name(get_rel_tablespace(src_chunk->table_id)); + tablespace_oid = get_rel_tablespace(src_chunk->table_id); + tablespace = get_tablespace_name(tablespace_oid); compress_chunk->table_id = ts_chunk_create_table(compress_chunk, compress_ht, tablespace); if (!OidIsValid(compress_chunk->table_id)) elog(ERROR, "could not create compressed chunk table"); + /* if the src chunk is not in the default tablespace, the compressed indexes + * should also be in a non-default tablespace. IN the usual case, this is inferred + * from the hypertable's and chunk's tablespace info. We do not propagate + * attach_tablespace settings to the compressed hypertable. So we have to explicitly + * pass the tablespace information here + */ ts_chunk_index_create_all(compress_chunk->fd.hypertable_id, compress_chunk->hypertable_relid, compress_chunk->fd.id, - compress_chunk->table_id); + compress_chunk->table_id, + tablespace_oid); return compress_chunk; } diff --git a/tsl/src/reorder.c b/tsl/src/reorder.c index 2c42ef336..fa67be715 100644 --- a/tsl/src/reorder.c +++ b/tsl/src/reorder.c @@ -184,6 +184,9 @@ tsl_move_chunk(PG_FUNCTION_ARGS) AlterTableInternal(chunk_id, list_make1(&cmd), false); AlterTableInternal(compressed_chunk->table_id, list_make1(&cmd), false); + /* move indexes on original and compressed chunk */ + ts_chunk_index_move_all(chunk_id, index_destination_tablespace); + ts_chunk_index_move_all(compressed_chunk->table_id, index_destination_tablespace); } else { diff --git a/tsl/test/expected/compression_ddl.out b/tsl/test/expected/compression_ddl.out index 84eed0848..e8387956d 100644 --- a/tsl/test/expected/compression_ddl.out +++ b/tsl/test/expected/compression_ddl.out @@ -627,7 +627,6 @@ NOTICE: drop cascades to table _timescaledb_internal.compress_hyper_4_57_chunk NOTICE: drop cascades to 2 other objects NOTICE: drop cascades to table _timescaledb_internal._hyper_3_56_chunk DROP TABLESPACE tablespace1; -DROP TABLESPACE tablespace2; -- Triggers are NOT fired for compress/decompress CREATE TABLE test1 ("Time" timestamptz, i integer); SELECT table_name from create_hypertable('test1', 'Time', chunk_time_interval=> INTERVAL '1 day'); @@ -720,7 +719,7 @@ SELECT decompress_chunk(show_chunks, if_compressed => TRUE) AS decompressed_chun (2 rows) ALTER TABLE i2844 SET (timescaledb.compress = FALSE); --- compression alter schema tests +-- TEST compression alter schema tests \ir include/compression_alter.sql -- This file and its contents are licensed under the Timescale License. -- Please see the included NOTICE for copyright information and @@ -1134,3 +1133,52 @@ ORDER BY 1; c2 (1 row) +--TEST tablespaces for compressed chunks with attach_tablespace interface -- +CREATE TABLE test2 (timec timestamptz, i integer, t integer); +SELECT table_name from create_hypertable('test2', 'timec', chunk_time_interval=> INTERVAL '1 day'); +NOTICE: adding not-null constraint to column "timec" + table_name +------------ + test2 +(1 row) + +SELECT attach_tablespace('tablespace2', 'test2'); + attach_tablespace +------------------- + +(1 row) + +INSERT INTO test2 SELECT t, gen_rand_minstd(), 22 +FROM generate_series('2018-03-02 1:00'::TIMESTAMPTZ, '2018-03-02 13:00', '1 hour') t; +ALTER TABLE test2 set (timescaledb.compress, timescaledb.compress_segmentby = 'i', timescaledb.compress_orderby = 'timec'); +SELECT relname FROM pg_class +WHERE reltablespace in + ( SELECT oid from pg_tablespace WHERE spcname = 'tablespace2') ORDER BY 1; + relname +------------------------------------- + _hyper_16_103_chunk + _hyper_16_103_chunk_test2_timec_idx + test2 +(3 rows) + +SELECT compress_chunk(ch) FROM show_chunks('test2') ch; + compress_chunk +------------------------------------------- + _timescaledb_internal._hyper_16_103_chunk +(1 row) + +-- the chunk, compressed chunk + index + toast tables are in tablespace2 now . +-- toast table names differ across runs. So we use count to verify the results +-- instead of printing the table/index names +SELECT count(*) FROM ( +SELECT relname FROM pg_class +WHERE reltablespace in + ( SELECT oid from pg_tablespace WHERE spcname = 'tablespace2'))q; + count +------- + 7 +(1 row) + +DROP TABLE test2 CASCADE; +NOTICE: drop cascades to table _timescaledb_internal.compress_hyper_17_104_chunk +DROP TABLESPACE tablespace2; diff --git a/tsl/test/expected/move.out b/tsl/test/expected/move.out index 3b6a7463b..52aceba15 100644 --- a/tsl/test/expected/move.out +++ b/tsl/test/expected/move.out @@ -458,3 +458,40 @@ SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk'); _timescaledb_internal._hyper_1_2_chunk | _timescaledb_internal._hyper_1_2_chunk_cluster_test_location_idx | {location} | | f | f | f | tablespace2 (4 rows) +--TEST with compression bug 4000 +--compress chunk and then move chunk and index to different tablespaces +ALTER TABLE cluster_test SET (timescaledb.compress, timescaledb.compress_segmentby = 'location'); +SELECT compress_chunk('_timescaledb_internal._hyper_1_2_chunk') as ch; + ch +---------------------------------------- + _timescaledb_internal._hyper_1_2_chunk +(1 row) + +SELECT move_chunk(chunk=>'_timescaledb_internal._hyper_1_2_chunk', destination_tablespace=>'tablespace2', index_destination_tablespace=>'tablespace1', verbose=>TRUE); + move_chunk +------------ + +(1 row) + +SELECT * FROM test.show_subtables('cluster_test'); + Child | Tablespace +----------------------------------------+------------- + _timescaledb_internal._hyper_1_1_chunk | + _timescaledb_internal._hyper_1_2_chunk | tablespace2 +(2 rows) + +SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk'); + Table | Index | Columns | Expr | Unique | Primary | Exclusion | Tablespace +----------------------------------------+------------------------------------------------------------------+------------+------+--------+---------+-----------+------------- + _timescaledb_internal._hyper_1_1_chunk | _timescaledb_internal._hyper_1_1_chunk_cluster_test_time_idx | {time} | | f | f | f | + _timescaledb_internal._hyper_1_1_chunk | _timescaledb_internal._hyper_1_1_chunk_cluster_test_location_idx | {location} | | f | f | f | + _timescaledb_internal._hyper_1_2_chunk | _timescaledb_internal._hyper_1_2_chunk_cluster_test_time_idx | {time} | | f | f | f | tablespace1 + _timescaledb_internal._hyper_1_2_chunk | _timescaledb_internal._hyper_1_2_chunk_cluster_test_location_idx | {location} | | f | f | f | tablespace1 +(4 rows) + +SELECT * FROM test.show_indexesp('_timescaledb_internal.compress_hyper%_chunk'); + Table | Index | Columns | Expr | Unique | Primary | Exclusion | Tablespace +------------------------------------------------+---------------------------------------------------------------------------------------+----------------------------------+------+--------+---------+-----------+------------- + _timescaledb_internal.compress_hyper_2_3_chunk | _timescaledb_internal.compress_hyper_2_3_chunk__compressed_hypertable_2_location__ts_ | {location,_ts_meta_sequence_num} | | f | f | f | tablespace1 +(1 row) + diff --git a/tsl/test/sql/compression_ddl.sql b/tsl/test/sql/compression_ddl.sql index 14f35c52c..607b5387f 100644 --- a/tsl/test/sql/compression_ddl.sql +++ b/tsl/test/sql/compression_ddl.sql @@ -139,7 +139,6 @@ SELECT compress_chunk(:'UNCOMPRESSED_CHUNK_NAME'); SELECT count(*) FROM pg_tables WHERE tablespace = 'tablespace1'; - -- -- DROP CHUNKS -- @@ -404,7 +403,6 @@ AS sub; DROP TABLE test1 CASCADE; DROP TABLESPACE tablespace1; -DROP TABLESPACE tablespace2; -- Triggers are NOT fired for compress/decompress CREATE TABLE test1 ("Time" timestamptz, i integer); @@ -462,6 +460,33 @@ SELECT decompress_chunk(show_chunks, if_compressed => TRUE) AS decompressed_chun ALTER TABLE i2844 SET (timescaledb.compress = FALSE); --- compression alter schema tests +-- TEST compression alter schema tests \ir include/compression_alter.sql +--TEST tablespaces for compressed chunks with attach_tablespace interface -- +CREATE TABLE test2 (timec timestamptz, i integer, t integer); +SELECT table_name from create_hypertable('test2', 'timec', chunk_time_interval=> INTERVAL '1 day'); + +SELECT attach_tablespace('tablespace2', 'test2'); + +INSERT INTO test2 SELECT t, gen_rand_minstd(), 22 +FROM generate_series('2018-03-02 1:00'::TIMESTAMPTZ, '2018-03-02 13:00', '1 hour') t; + +ALTER TABLE test2 set (timescaledb.compress, timescaledb.compress_segmentby = 'i', timescaledb.compress_orderby = 'timec'); + +SELECT relname FROM pg_class +WHERE reltablespace in + ( SELECT oid from pg_tablespace WHERE spcname = 'tablespace2') ORDER BY 1; + +SELECT compress_chunk(ch) FROM show_chunks('test2') ch; + +-- the chunk, compressed chunk + index + toast tables are in tablespace2 now . +-- toast table names differ across runs. So we use count to verify the results +-- instead of printing the table/index names +SELECT count(*) FROM ( +SELECT relname FROM pg_class +WHERE reltablespace in + ( SELECT oid from pg_tablespace WHERE spcname = 'tablespace2'))q; + +DROP TABLE test2 CASCADE; +DROP TABLESPACE tablespace2; diff --git a/tsl/test/sql/move.sql b/tsl/test/sql/move.sql index a328f5780..35faca048 100644 --- a/tsl/test/sql/move.sql +++ b/tsl/test/sql/move.sql @@ -97,3 +97,12 @@ SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk'); SELECT move_chunk(chunk=>'_timescaledb_internal._hyper_1_2_chunk', destination_tablespace=>'pg_default', index_destination_tablespace=>'tablespace2', reorder_index=>'_timescaledb_internal._hyper_1_2_chunk_cluster_test_time_idx', verbose=>TRUE); SELECT * FROM test.show_subtables('cluster_test'); SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk'); + +--TEST with compression bug 4000 +--compress chunk and then move chunk and index to different tablespaces +ALTER TABLE cluster_test SET (timescaledb.compress, timescaledb.compress_segmentby = 'location'); +SELECT compress_chunk('_timescaledb_internal._hyper_1_2_chunk') as ch; +SELECT move_chunk(chunk=>'_timescaledb_internal._hyper_1_2_chunk', destination_tablespace=>'tablespace2', index_destination_tablespace=>'tablespace1', verbose=>TRUE); +SELECT * FROM test.show_subtables('cluster_test'); +SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk'); +SELECT * FROM test.show_indexesp('_timescaledb_internal.compress_hyper%_chunk');