Skip to content

Commit

Permalink
Add table mappings to compression settings
Browse files Browse the repository at this point in the history
Refactor the compression settings metadata table to include a mapping
from a chunk's relid to its compressed chunk's relid.

This simplifies the code that looks up compression metadata as it no
longer requires first looking up the corresponding compressed chunk in
the "chunk" metadata table. Instead, given the non-compressed chunk's
relid, the corresponding compressed chunk's relid can easily be looked
up via the compression settings.

The refactoring is a step towards removing a chunk's compression table
from the chunk metadata. In other words, the "compressed chunk" will
no longer be a chunk, just a relation associated with the regular
chunk via compression settings. However, this requires further
refactoring that is left for follow-up changes.
  • Loading branch information
erimatnor committed Jan 29, 2025
1 parent 06ccc50 commit ada1790
Show file tree
Hide file tree
Showing 37 changed files with 560 additions and 334 deletions.
4 changes: 3 additions & 1 deletion sql/pre_install/tables.sql
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,8 @@ CREATE TABLE _timescaledb_catalog.compression_algorithm (
);

CREATE TABLE _timescaledb_catalog.compression_settings (
relid regclass NOT NULL,
relid regclass NOT NULL,
compress_relid regclass NULL,
segmentby text[],
orderby text[],
orderby_desc bool[],
Expand All @@ -483,6 +484,7 @@ CREATE TABLE _timescaledb_catalog.compression_settings (
);

SELECT pg_catalog.pg_extension_config_dump('_timescaledb_catalog.compression_settings', '');
CREATE INDEX compression_settings_compress_relid_idx ON _timescaledb_catalog.compression_settings (compress_relid);

CREATE TABLE _timescaledb_catalog.compression_chunk_size (
chunk_id integer NOT NULL,
Expand Down
54 changes: 54 additions & 0 deletions sql/updates/latest-dev.sql
Original file line number Diff line number Diff line change
@@ -1 +1,55 @@
-------------------------------
-- Update compression settings
-------------------------------
CREATE TABLE _timescaledb_catalog.tempsettings (LIKE _timescaledb_catalog.compression_settings);
INSERT INTO _timescaledb_catalog.tempsettings SELECT * FROM _timescaledb_catalog.compression_settings;
ALTER EXTENSION timescaledb DROP TABLE _timescaledb_catalog.compression_settings;
DROP TABLE _timescaledb_catalog.compression_settings CASCADE;

CREATE TABLE _timescaledb_catalog.compression_settings (
relid regclass NOT NULL,
compress_relid regclass NULL,
segmentby text[],
orderby text[],
orderby_desc bool[],
orderby_nullsfirst bool[],
CONSTRAINT compression_settings_pkey PRIMARY KEY (relid),
CONSTRAINT compression_settings_check_segmentby CHECK (array_ndims(segmentby) = 1),
CONSTRAINT compression_settings_check_orderby_null CHECK ((orderby IS NULL AND orderby_desc IS NULL AND orderby_nullsfirst IS NULL) OR (orderby IS NOT NULL AND orderby_desc IS NOT NULL AND orderby_nullsfirst IS NOT NULL)),
CONSTRAINT compression_settings_check_orderby_cardinality CHECK (array_ndims(orderby) = 1 AND array_ndims(orderby_desc) = 1 AND array_ndims(orderby_nullsfirst) = 1 AND cardinality(orderby) = cardinality(orderby_desc) AND cardinality(orderby) = cardinality(orderby_nullsfirst))
);

-- Insert updated settings
INSERT INTO _timescaledb_catalog.compression_settings
SELECT
CASE
WHEN h.schema_name IS NOT NULL THEN
cs.relid
WHEN cch.table_name IS NOT NULL THEN
format('%I.%I', ch.schema_name, ch.table_name)::regclass
END AS relid,
CASE
WHEN h.schema_name IS NOT NULL THEN
NULL
ELSE
cs.relid
END AS compress_relid,
cs.segmentby,
cs.orderby,
cs.orderby_desc,
cs.orderby_nullsfirst
FROM
_timescaledb_catalog.tempsettings cs
LEFT JOIN
_timescaledb_catalog.hypertable h ON (cs.relid = format('%I.%I', h.schema_name, h.table_name)::regclass)
LEFT JOIN
_timescaledb_catalog.chunk cch ON (cs.relid = format('%I.%I', cch.schema_name, cch.table_name)::regclass)
LEFT JOIN
_timescaledb_catalog.chunk ch ON (cch.id = ch.compressed_chunk_id);

-- Add index on secondary compressed relid key
CREATE INDEX compression_settings_compress_relid_idx ON _timescaledb_catalog.compression_settings (compress_relid);

DROP TABLE _timescaledb_catalog.tempsettings CASCADE;
GRANT SELECT ON _timescaledb_catalog.compression_settings TO PUBLIC;
SELECT pg_catalog.pg_extension_config_dump('_timescaledb_catalog.compression_settings', '');
37 changes: 37 additions & 0 deletions sql/updates/reverse-dev.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
-- Update compression settings
CREATE TABLE _timescaledb_catalog.tempsettings (LIKE _timescaledb_catalog.compression_settings);
INSERT INTO _timescaledb_catalog.tempsettings SELECT * FROM _timescaledb_catalog.compression_settings;
ALTER EXTENSION timescaledb DROP TABLE _timescaledb_catalog.compression_settings;
DROP TABLE _timescaledb_catalog.compression_settings CASCADE;

CREATE TABLE _timescaledb_catalog.compression_settings (
relid regclass NOT NULL,
segmentby text[],
orderby text[],
orderby_desc bool[],
orderby_nullsfirst bool[],
CONSTRAINT compression_settings_pkey PRIMARY KEY (relid),
CONSTRAINT compression_settings_check_segmentby CHECK (array_ndims(segmentby) = 1),
CONSTRAINT compression_settings_check_orderby_null CHECK ((orderby IS NULL AND orderby_desc IS NULL AND orderby_nullsfirst IS NULL) OR (orderby IS NOT NULL AND orderby_desc IS NOT NULL AND orderby_nullsfirst IS NOT NULL)),
CONSTRAINT compression_settings_check_orderby_cardinality CHECK (array_ndims(orderby) = 1 AND array_ndims(orderby_desc) = 1 AND array_ndims(orderby_nullsfirst) = 1 AND cardinality(orderby) = cardinality(orderby_desc) AND cardinality(orderby) = cardinality(orderby_nullsfirst))
);

-- Revert information in compression settings
INSERT INTO _timescaledb_catalog.compression_settings
SELECT
CASE
WHEN cs.compress_relid IS NULL THEN
cs.relid
ELSE
cs.compress_relid
END as relid,
cs.segmentby,
cs.orderby,
cs.orderby_desc,
cs.orderby_nullsfirst
FROM
_timescaledb_catalog.tempsettings cs;

DROP TABLE _timescaledb_catalog.tempsettings CASCADE;
GRANT SELECT ON _timescaledb_catalog.compression_settings TO PUBLIC;
SELECT pg_catalog.pg_extension_config_dump('_timescaledb_catalog.compression_settings', '');
3 changes: 1 addition & 2 deletions sql/views.sql
Original file line number Diff line number Diff line change
Expand Up @@ -390,8 +390,7 @@ CREATE OR REPLACE VIEW timescaledb_information.chunk_compression_settings AS
un.orderby
FROM _timescaledb_catalog.hypertable ht
INNER JOIN _timescaledb_catalog.chunk ch ON ch.hypertable_id = ht.id
INNER JOIN _timescaledb_catalog.chunk ch2 ON ch2.id = ch.compressed_chunk_id
LEFT JOIN _timescaledb_catalog.compression_settings s ON format('%I.%I',ch2.schema_name,ch2.table_name)::regclass = s.relid
INNER JOIN _timescaledb_catalog.compression_settings s ON (format('%I.%I',ch.schema_name,ch.table_name)::regclass = s.relid AND format('%I.%I',ch.schema_name,ch.table_name)::regclass != s.compress_relid)
LEFT JOIN LATERAL (
SELECT
string_agg(
Expand Down
62 changes: 48 additions & 14 deletions src/chunk.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <access/reloptions.h>
#include <access/tupdesc.h>
#include <access/xact.h>
#include <c.h>
#include <catalog/indexing.h>
#include <catalog/namespace.h>
#include <catalog/pg_class.h>
Expand Down Expand Up @@ -2807,6 +2808,10 @@ typedef enum ChunkDeleteResult
} ChunkDeleteResult;

/* Delete the chunk tuple.
*
* relid: Required when deleting via an event trigger hook, because at that
* point the relation is gone and it is no longer possible to resolve the Oid
* from the PG catalog.
*
* preserve_chunk_catalog_row - instead of deleting the row, mark it as dropped.
* this is used when we need to preserve catalog information about the chunk
Expand All @@ -2824,7 +2829,7 @@ typedef enum ChunkDeleteResult
* of tuples to process.
*/
static ChunkDeleteResult
chunk_tuple_delete(TupleInfo *ti, DropBehavior behavior, bool preserve_chunk_catalog_row)
chunk_tuple_delete(TupleInfo *ti, Oid relid, DropBehavior behavior, bool preserve_chunk_catalog_row)
{
FormData_chunk form;
CatalogSecurityContext sec_ctx;
Expand Down Expand Up @@ -2910,19 +2915,39 @@ chunk_tuple_delete(TupleInfo *ti, DropBehavior behavior, bool preserve_chunk_cat
/* Delete any rows in _timescaledb_catalog.chunk_column_stats corresponding to this chunk */
ts_chunk_column_stats_delete_by_chunk_id(form.id);

if (!OidIsValid(relid))
{
/*
* If the chunk is deleted as a result of deleting the Hypertable, and
* it is cleaned up in the DROP eventtrigger hook, it might not be
* possible to resolve the relid because the relation is already gone
* in pg_catalog. But that's OK, because compression settings will be
* cleaned up when processing the eventtrigger.
*/
relid = ts_get_relation_relid(NameStr(form.schema_name), NameStr(form.table_name), true);
}

if (form.compressed_chunk_id != INVALID_CHUNK_ID)
{
Chunk *compressed_chunk = ts_chunk_get_by_id(form.compressed_chunk_id, false);

/* The chunk may have been delete by a CASCADE */
if (OidIsValid(relid))
ts_compression_settings_delete(relid);

/* The chunk may have been deleted by a CASCADE */
if (compressed_chunk != NULL)
{
/* Plain drop without preserving catalog row because this is the compressed
* chunk */
ts_compression_settings_delete(compressed_chunk->table_id);
ts_chunk_drop(compressed_chunk, behavior, DEBUG1);
}
}
else if (OidIsValid(relid))
{
/* If there is no compressed chunk ID, this might be the actual
* compressed chunk */
ts_compression_settings_delete_by_compress_relid(relid);
}

ts_catalog_database_info_become_owner(ts_catalog_database_info_get(), &sec_ctx);

Expand Down Expand Up @@ -2973,7 +2998,8 @@ init_scan_by_qualified_table_name(ScanIterator *iterator, const char *schema_nam
}

static int
chunk_delete(ScanIterator *iterator, DropBehavior behavior, bool preserve_chunk_catalog_row)
chunk_delete(ScanIterator *iterator, Oid relid, DropBehavior behavior,
bool preserve_chunk_catalog_row)
{
int count = 0;

Expand All @@ -2982,6 +3008,7 @@ chunk_delete(ScanIterator *iterator, DropBehavior behavior, bool preserve_chunk_
ChunkDeleteResult res;

res = chunk_tuple_delete(ts_scan_iterator_tuple_info(iterator),
relid,
behavior,
preserve_chunk_catalog_row);

Expand All @@ -3001,14 +3028,14 @@ chunk_delete(ScanIterator *iterator, DropBehavior behavior, bool preserve_chunk_
}

static int
ts_chunk_delete_by_name_internal(const char *schema, const char *table, DropBehavior behavior,
bool preserve_chunk_catalog_row)
ts_chunk_delete_by_name_internal(const char *schema, const char *table, Oid relid,
DropBehavior behavior, bool preserve_chunk_catalog_row)
{
ScanIterator iterator = ts_scan_iterator_create(CHUNK, RowExclusiveLock, CurrentMemoryContext);
int count;

init_scan_by_qualified_table_name(&iterator, schema, table);
count = chunk_delete(&iterator, behavior, preserve_chunk_catalog_row);
count = chunk_delete(&iterator, relid, behavior, preserve_chunk_catalog_row);

/* (schema,table) names and (hypertable_id) are unique so should only have
* dropped one chunk or none (if not found) */
Expand All @@ -3020,17 +3047,20 @@ ts_chunk_delete_by_name_internal(const char *schema, const char *table, DropBeha
int
ts_chunk_delete_by_name(const char *schema, const char *table, DropBehavior behavior)
{
return ts_chunk_delete_by_name_internal(schema, table, behavior, false);
Oid relid = ts_get_relation_relid(schema, table, false);
return ts_chunk_delete_by_name_internal(schema, table, relid, behavior, false);
}

static int
ts_chunk_delete_by_relid(Oid relid, DropBehavior behavior, bool preserve_chunk_catalog_row)
int
ts_chunk_delete_by_relid_and_relname(Oid relid, const char *schemaname, const char *tablename,
DropBehavior behavior, bool preserve_chunk_catalog_row)
{
if (!OidIsValid(relid))
return 0;

return ts_chunk_delete_by_name_internal(get_namespace_name(get_rel_namespace(relid)),
get_rel_name(relid),
return ts_chunk_delete_by_name_internal(schemaname,
tablename,
relid,
behavior,
preserve_chunk_catalog_row);
}
Expand All @@ -3053,7 +3083,7 @@ ts_chunk_delete_by_hypertable_id(int32 hypertable_id)

init_scan_by_hypertable_id(&iterator, hypertable_id);

return chunk_delete(&iterator, DROP_RESTRICT, false);
return chunk_delete(&iterator, InvalidOid, DROP_RESTRICT, false);
}

bool
Expand Down Expand Up @@ -3738,7 +3768,11 @@ ts_chunk_drop_internal(const Chunk *chunk, DropBehavior behavior, int32 log_leve
NameStr(chunk->fd.table_name));

/* Remove the chunk from the chunk table */
ts_chunk_delete_by_relid(chunk->table_id, behavior, preserve_catalog_row);
ts_chunk_delete_by_relid_and_relname(chunk->table_id,
NameStr(chunk->fd.schema_name),
NameStr(chunk->fd.table_name),
behavior,
preserve_catalog_row);

/* Drop the table */
performDeletion(&objaddr, behavior, 0);
Expand Down
3 changes: 3 additions & 0 deletions src/chunk.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,9 @@ extern void ts_chunk_recreate_all_constraints_for_dimension(Hypertable *ht, int3
extern int ts_chunk_delete_by_hypertable_id(int32 hypertable_id);
extern TSDLLEXPORT int ts_chunk_delete_by_name(const char *schema, const char *table,
DropBehavior behavior);
extern int ts_chunk_delete_by_relid_and_relname(Oid relid, const char *schemaname,
const char *tablename, DropBehavior behavior,
bool preserve_chunk_catalog_row);
extern bool ts_chunk_set_name(Chunk *chunk, const char *newname);
extern bool ts_chunk_set_schema(Chunk *chunk, const char *newschema);
extern TSDLLEXPORT List *ts_chunk_get_window(int32 dimension_id, int64 point, int count,
Expand Down
1 change: 1 addition & 0 deletions src/dimension.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <utils/timestamp.h>

#include "compat/compat.h"
#include "chunk.h"
#include "cross_module_fn.h"
#include "debug_point.h"
#include "dimension.h"
Expand Down
21 changes: 18 additions & 3 deletions src/process_utility.c
Original file line number Diff line number Diff line change
Expand Up @@ -2247,7 +2247,9 @@ process_rename_column(ProcessUtilityArgs *args, Cache *hcache, Oid relid, Rename
* */
if (ht)
{
ts_compression_settings_rename_column_hypertable(ht, stmt->subname, stmt->newname);
ts_compression_settings_rename_column_cascade(ht->main_table_relid,
stmt->subname,
stmt->newname);
add_hypertable_to_process_args(args, ht);
dim = ts_hyperspace_get_mutable_dimension_by_name(ht->space,
DIMENSION_TYPE_ANY,
Expand Down Expand Up @@ -4959,9 +4961,22 @@ process_drop_table(EventTriggerDropObject *obj)
EventTriggerDropRelation *table = (EventTriggerDropRelation *) obj;

Assert(obj->type == EVENT_TRIGGER_DROP_TABLE || obj->type == EVENT_TRIGGER_DROP_FOREIGN_TABLE);
ts_chunk_delete_by_relid_and_relname(table->relid,
table->schema,
table->name,
DROP_RESTRICT,
false);
ts_hypertable_delete_by_name(table->schema, table->name);
ts_chunk_delete_by_name(table->schema, table->name, DROP_RESTRICT);
ts_compression_settings_delete(table->relid);
/*
* Normally, compression settings are cleaned up when deleting the
* hypertable or chunk. However, in some cases, e.g., when a hypertable
* delete cascades to chunks, the chunk relids cannot be resolved from the
* schema and name because the chunk relations are already dropped by
* PostgreSQL when the "drop eventtrigger" is called. Therefore, also try
* to delete compression settings here since the eventtrigger gives us the
* relid of dropped objects.
*/
ts_compression_settings_delete_any(table->relid);
}

static void
Expand Down
1 change: 1 addition & 0 deletions src/ts_catalog/catalog.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ static const TableIndexDef catalog_table_index_definitions[_MAX_CATALOG_TABLES]
.length = _MAX_COMPRESSION_SETTINGS_INDEX,
.names = (char *[]) {
[COMPRESSION_SETTINGS_PKEY] = "compression_settings_pkey",
[COMPRESSION_SETTINGS_COMPRESS_RELID_IDX] = "compression_settings_compress_relid_idx",
},
},
[COMPRESSION_CHUNK_SIZE] = {
Expand Down
12 changes: 12 additions & 0 deletions src/ts_catalog/catalog.h
Original file line number Diff line number Diff line change
Expand Up @@ -1155,6 +1155,7 @@ typedef enum Anum_continuous_aggs_watermark_pkey
typedef enum Anum_compression_settings
{
Anum_compression_settings_relid = 1,
Anum_compression_settings_compress_relid,
Anum_compression_settings_segmentby,
Anum_compression_settings_orderby,
Anum_compression_settings_orderby_desc,
Expand All @@ -1167,6 +1168,7 @@ typedef enum Anum_compression_settings
typedef struct FormData_compression_settings
{
Oid relid;
Oid compress_relid;
ArrayType *segmentby;
ArrayType *orderby;
ArrayType *orderby_desc;
Expand All @@ -1178,6 +1180,7 @@ typedef FormData_compression_settings *Form_compression_settings;
enum
{
COMPRESSION_SETTINGS_PKEY = 0,
COMPRESSION_SETTINGS_COMPRESS_RELID_IDX,
_MAX_COMPRESSION_SETTINGS_INDEX,
};

Expand All @@ -1189,6 +1192,15 @@ typedef enum Anum_compression_settings_pkey

#define Natts_compression_chunk_size_pkey (_Anum_compression_chunk_size_pkey_max - 1)

typedef enum Anum_compression_settings_compress_relid_idx
{
Anum_compression_settings_compress_relid_idx_relid = 1,
_Anum_compression_settings_compress_relid_idx_max,
} Anum_compression_settings_compress_relid_idx;

#define Natts_compression_settings_compress_relid_idx \
(_Anum_compression_settings_compress_relid_idx_max - 1)

#define COMPRESSION_CHUNK_SIZE_TABLE_NAME "compression_chunk_size"
typedef enum Anum_compression_chunk_size
{
Expand Down
Loading

0 comments on commit ada1790

Please sign in to comment.