Add ability to turn off compression

Since enabling compression creates limits on the hypertable
(e.g. types of constraints allowed) even if there are no
compressed chunks, we add the ability to turn off compression.
This is only possible if there are no compressed chunks.
This commit is contained in:
Matvey Arye 2019-10-13 18:56:06 -04:00 committed by Matvey Arye
parent 887d0271e8
commit 85d30e404d
7 changed files with 142 additions and 53 deletions

View File

@ -2032,55 +2032,22 @@ ts_hypertable_set_integer_now_func(PG_FUNCTION_ARGS)
PG_RETURN_NULL();
}
static ScanTupleResult
hypertable_set_compressed_id_in_tuple(TupleInfo *ti, void *data)
{
bool nulls[Natts_hypertable];
Datum values[Natts_hypertable];
bool repl[Natts_hypertable] = { false };
CatalogSecurityContext sec_ctx;
HeapTuple tuple;
int32 compressed_hypertable_id = *((int32 *) data);
heap_deform_tuple(ti->tuple, ti->desc, values, nulls);
Assert(DatumGetBool(values[AttrNumberGetAttrOffset(Anum_hypertable_compressed)]) == false);
nulls[AttrNumberGetAttrOffset(Anum_hypertable_compressed_hypertable_id)] = false;
values[AttrNumberGetAttrOffset(Anum_hypertable_compressed_hypertable_id)] =
Int32GetDatum(compressed_hypertable_id);
repl[AttrNumberGetAttrOffset(Anum_hypertable_compressed_hypertable_id)] = true;
ts_catalog_database_info_become_owner(ts_catalog_database_info_get(), &sec_ctx);
tuple = heap_modify_tuple(ti->tuple, ti->desc, values, nulls, repl);
ts_catalog_update(ti->scanrel, tuple);
heap_freetuple(tuple);
ts_catalog_restore_user(&sec_ctx);
return SCAN_DONE;
}
/*Assume permissions are already checked */
bool
ts_hypertable_set_compressed_id(Hypertable *ht, int32 compressed_hypertable_id)
{
int32 compress_id;
ScanKeyData scankey[1];
ScanKeyInit(&scankey[0],
Anum_hypertable_pkey_idx_id,
BTEqualStrategyNumber,
F_INT4EQ,
Int32GetDatum(ht->fd.id));
compress_id = compressed_hypertable_id;
return hypertable_scan_limit_internal(scankey,
1,
HYPERTABLE_ID_INDEX,
hypertable_set_compressed_id_in_tuple,
&compress_id,
1,
RowExclusiveLock,
false,
CurrentMemoryContext) > 0;
Assert(!ht->fd.compressed);
ht->fd.compressed_hypertable_id = compressed_hypertable_id;
return ts_hypertable_update(ht) > 0;
}
bool
ts_hypertable_unset_compressed_id(Hypertable *ht)
{
Assert(!ht->fd.compressed);
ht->fd.compressed_hypertable_id = INVALID_HYPERTABLE_ID;
return ts_hypertable_update(ht) > 0;
}
/* create a compressed hypertable

View File

@ -112,6 +112,7 @@ extern List *ts_hypertable_get_all_by_name(Name schema_name, Name table_name, Me
extern bool ts_is_partitioning_column(Hypertable *ht, Index column_attno);
extern TSDLLEXPORT bool ts_hypertable_set_compressed_id(Hypertable *ht,
int32 compressed_hypertable_id);
extern TSDLLEXPORT bool ts_hypertable_unset_compressed_id(Hypertable *ht);
extern TSDLLEXPORT bool ts_hypertable_is_compressed_internal(int32 compressed_hypertable_id);
extern TSDLLEXPORT void ts_hypertable_clone_constraints_to_compressed(Hypertable *ht,
List *constraint_list);

View File

@ -811,12 +811,16 @@ tsl_process_compress_table(AlterTableCmd *cmd, Hypertable *ht,
if (!compress_enable)
{
if (compression_already_enabled)
if (!with_clause_options[CompressOrderBy].is_default ||
!with_clause_options[CompressSegmentBy].is_default)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("disabling compression is not yet supported")));
/* compression is not enabled, so just return */
return false;
errmsg(
"cannot set additional compression options when disabling compression")));
if (!compression_already_enabled)
/* compression is not enabled, so just return */
return false;
}
if (compressed_chunks_exist)
@ -828,7 +832,7 @@ tsl_process_compress_table(AlterTableCmd *cmd, Hypertable *ht,
/* Require both order by and segment by when altering if they were previously set because
* otherwise it's not clear what the default value means: does it mean leave as-is or is it an
* empty list. */
if (compression_already_enabled)
if (compress_enable && compression_already_enabled)
{
List *info = ts_hypertable_compression_get(ht->fd.id);
ListCell *lc;
@ -869,7 +873,7 @@ tsl_process_compress_table(AlterTableCmd *cmd, Hypertable *ht,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("compression cannot be used on table with row security")));
if (compression_already_enabled)
if (compression_already_enabled || !compress_enable)
{
Hypertable *compressed = ts_hypertable_get_by_id(ht->fd.compressed_hypertable_id);
if (compressed == NULL)
@ -880,6 +884,12 @@ tsl_process_compress_table(AlterTableCmd *cmd, Hypertable *ht,
ts_hypertable_compression_delete_by_hypertable_id(ht->fd.id);
}
if (!compress_enable)
{
ts_hypertable_unset_compressed_id(ht);
return true;
}
compress_htid = create_compression_table(ownerid, &compress_cols);
ts_hypertable_set_compressed_id(ht, compress_htid);

View File

@ -477,6 +477,71 @@ SELECT a.rolname from pg_class c INNER JOIN pg_authid a ON(c.relowner = a.oid) W
default_perm_user_2
(1 row)
--
-- turn off compression
--
SELECT COUNT(*) AS count_compressed
FROM
(
SELECT decompress_chunk(chunk.schema_name|| '.' || chunk.table_name)
FROM _timescaledb_catalog.chunk chunk
INNER JOIN _timescaledb_catalog.hypertable hypertable ON (chunk.hypertable_id = hypertable.id)
WHERE hypertable.table_name like 'test1' and chunk.compressed_chunk_id IS NOT NULL ORDER BY chunk.id
)
AS sub;
count_compressed
------------------
1
(1 row)
ALTER table test1 set (timescaledb.compress='f');
--only one hypertable left
SELECT count(*) = 1 FROM _timescaledb_catalog.hypertable hypertable;
?column?
----------
t
(1 row)
SELECT compressed_hypertable_id IS NULL FROM _timescaledb_catalog.hypertable hypertable WHERE hypertable.table_name like 'test1' ;
?column?
----------
t
(1 row)
--no hypertable compression entries left
SELECT count(*) = 0 FROM _timescaledb_catalog.hypertable_compression;
?column?
----------
t
(1 row)
--make sure there are no orphaned _timescaledb_catalog.compression_chunk_size entries (should be 0)
SELECT count(*) as orphaned_compression_chunk_size
FROM _timescaledb_catalog.compression_chunk_size size
LEFT JOIN _timescaledb_catalog.chunk chunk ON (chunk.id = size.chunk_id)
WHERE chunk.id IS NULL;
orphaned_compression_chunk_size
---------------------------------
0
(1 row)
--can turn compression back on
ALTER TABLE test1 set (timescaledb.compress, timescaledb.compress_segmentby = 'b', timescaledb.compress_orderby = '"Time" DESC');
NOTICE: adding index _compressed_hypertable_3_b__ts_meta_sequence_num_idx ON _timescaledb_internal._compressed_hypertable_3 USING BTREE(b, _ts_meta_sequence_num)
SELECT COUNT(*) AS count_compressed
FROM
(
SELECT compress_chunk(chunk.schema_name|| '.' || chunk.table_name)
FROM _timescaledb_catalog.chunk chunk
INNER JOIN _timescaledb_catalog.hypertable hypertable ON (chunk.hypertable_id = hypertable.id)
WHERE hypertable.table_name like 'test1' and chunk.compressed_chunk_id IS NULL ORDER BY chunk.id
)
AS sub;
count_compressed
------------------
1
(1 row)
DROP TABLE test1;
DROP TABLESPACE tablespace1;
DROP TABLESPACE tablespace2;

View File

@ -79,8 +79,6 @@ NOTICE: adding index _compressed_hypertable_10_c__ts_meta_sequence_num_idx ON _
-- Negative test cases ---
ALTER TABLE foo2 set (timescaledb.compress, timescaledb.compress_segmentby = '"bacB toD",c');
ERROR: need to specify compress_orderby if it was previously set
ALTER TABLE foo2 set (timescaledb.compress='f');
ERROR: disabling compression is not yet supported
create table reserved_column_prefix (a integer, _ts_meta_foo integer, "bacB toD" integer, c integer, d integer);
select table_name from create_hypertable('reserved_column_prefix', 'a', chunk_time_interval=> 10);
NOTICE: adding not-null constraint to column "a"
@ -229,6 +227,10 @@ FROM _timescaledb_catalog.chunk ch1, _timescaledb_catalog.hypertable ht where ch
ERROR: chunks can be compressed only if compression property is set on the hypertable
ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_orderby = 'a', timescaledb.compress_segmentby = 'c');
ERROR: cannot change compression options as compressed chunks already exist for this table
ALTER TABLE foo set (timescaledb.compress='f');
ERROR: cannot change compression options as compressed chunks already exist for this table
ALTER TABLE foo reset (timescaledb.compress);
ERROR: compression options cannot be reset
select decompress_chunk(ch1.schema_name|| '.' || ch1.table_name)
FROM _timescaledb_catalog.chunk ch1, _timescaledb_catalog.hypertable ht where ch1.hypertable_id = ht.id and ht.table_name like 'non_compressed' ORDER BY ch1.id limit 1;
ERROR: missing compressed hypertable

View File

@ -332,6 +332,49 @@ SELECT a.rolname from pg_class c INNER JOIN pg_authid a ON(c.relowner = a.oid) W
SELECT a.rolname from pg_class c INNER JOIN pg_authid a ON(c.relowner = a.oid) WHERE c.oid = :'COMPRESSED_HYPER_NAME'::regclass;
SELECT a.rolname from pg_class c INNER JOIN pg_authid a ON(c.relowner = a.oid) WHERE c.oid = :'COMPRESSED_CHUNK_NAME'::regclass;
--
-- turn off compression
--
SELECT COUNT(*) AS count_compressed
FROM
(
SELECT decompress_chunk(chunk.schema_name|| '.' || chunk.table_name)
FROM _timescaledb_catalog.chunk chunk
INNER JOIN _timescaledb_catalog.hypertable hypertable ON (chunk.hypertable_id = hypertable.id)
WHERE hypertable.table_name like 'test1' and chunk.compressed_chunk_id IS NOT NULL ORDER BY chunk.id
)
AS sub;
ALTER table test1 set (timescaledb.compress='f');
--only one hypertable left
SELECT count(*) = 1 FROM _timescaledb_catalog.hypertable hypertable;
SELECT compressed_hypertable_id IS NULL FROM _timescaledb_catalog.hypertable hypertable WHERE hypertable.table_name like 'test1' ;
--no hypertable compression entries left
SELECT count(*) = 0 FROM _timescaledb_catalog.hypertable_compression;
--make sure there are no orphaned _timescaledb_catalog.compression_chunk_size entries (should be 0)
SELECT count(*) as orphaned_compression_chunk_size
FROM _timescaledb_catalog.compression_chunk_size size
LEFT JOIN _timescaledb_catalog.chunk chunk ON (chunk.id = size.chunk_id)
WHERE chunk.id IS NULL;
--can turn compression back on
ALTER TABLE test1 set (timescaledb.compress, timescaledb.compress_segmentby = 'b', timescaledb.compress_orderby = '"Time" DESC');
SELECT COUNT(*) AS count_compressed
FROM
(
SELECT compress_chunk(chunk.schema_name|| '.' || chunk.table_name)
FROM _timescaledb_catalog.chunk chunk
INNER JOIN _timescaledb_catalog.hypertable hypertable ON (chunk.hypertable_id = hypertable.id)
WHERE hypertable.table_name like 'test1' and chunk.compressed_chunk_id IS NULL ORDER BY chunk.id
)
AS sub;
DROP TABLE test1;
DROP TABLESPACE tablespace1;
DROP TABLESPACE tablespace2;

View File

@ -41,7 +41,6 @@ ALTER TABLE foo3 set (timescaledb.compress, timescaledb.compress_segmentby = '"b
-- Negative test cases ---
ALTER TABLE foo2 set (timescaledb.compress, timescaledb.compress_segmentby = '"bacB toD",c');
ALTER TABLE foo2 set (timescaledb.compress='f');
create table reserved_column_prefix (a integer, _ts_meta_foo integer, "bacB toD" integer, c integer, d integer);
@ -127,6 +126,8 @@ select compress_chunk(ch1.schema_name|| '.' || ch1.table_name)
FROM _timescaledb_catalog.chunk ch1, _timescaledb_catalog.hypertable ht where ch1.hypertable_id = ht.id and ht.table_name like 'non_compressed' ORDER BY ch1.id limit 1;
ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_orderby = 'a', timescaledb.compress_segmentby = 'c');
ALTER TABLE foo set (timescaledb.compress='f');
ALTER TABLE foo reset (timescaledb.compress);
select decompress_chunk(ch1.schema_name|| '.' || ch1.table_name)
FROM _timescaledb_catalog.chunk ch1, _timescaledb_catalog.hypertable ht where ch1.hypertable_id = ht.id and ht.table_name like 'non_compressed' ORDER BY ch1.id limit 1;