mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-16 18:43:18 +08:00
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:
parent
72d03e6f7d
commit
264540610e
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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');
|
||||
|
Loading…
x
Reference in New Issue
Block a user