Fix tablespace for compressed chunk's index

When a hypertable uses a non default tablespace, based
on attach_tablespace settings, the compressed chunk's
index is still created in the default tablespace.
This PR fixes this behavior and creates the compressed
chunk and its indexes in the same tablespace.

When move_chunk is executed on a compressed chunk,
move the indexes to the specified destination tablespace.

Fixes #4000
This commit is contained in:
gayyappan 2022-02-07 13:59:37 -05:00 committed by gayyappan
parent 72d03e6f7d
commit 264540610e
9 changed files with 184 additions and 14 deletions

View File

@ -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);
}
}

View File

@ -17,6 +17,7 @@
#include <commands/cluster.h>
#include <commands/defrem.h>
#include <commands/tablecmds.h>
#include <commands/tablespace.h>
#include <miscadmin.h>
#include <nodes/parsenodes.h>
#include <optimizer/optimizer.h>
@ -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);
}

View File

@ -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,

View File

@ -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;
}

View File

@ -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
{

View File

@ -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;

View File

@ -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)

View File

@ -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;

View File

@ -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');