Add repartition option on detach/delete_data_node

This change adds a new parameter to the detach_data_node and
delete_data_node functions that will allow the user to automatically
shrink their space dimension to match the number of nodes.
This commit is contained in:
Brian Rowe 2020-01-15 16:33:51 -08:00 committed by Erik Nordström
parent 32f3d17cde
commit d49e9a5739
7 changed files with 136 additions and 18 deletions

View File

@ -173,7 +173,8 @@ AS '@MODULE_PATHNAME@', 'ts_data_node_add' LANGUAGE C VOLATILE;
CREATE OR REPLACE FUNCTION delete_data_node(
node_name NAME,
if_exists BOOLEAN = FALSE,
force BOOLEAN = FALSE
force BOOLEAN = FALSE,
repartition BOOLEAN = TRUE
) RETURNS BOOLEAN AS '@MODULE_PATHNAME@', 'ts_data_node_delete' LANGUAGE C VOLATILE;
-- Attach a data node to a distributed hypertable
@ -186,7 +187,12 @@ CREATE OR REPLACE FUNCTION attach_data_node(
AS '@MODULE_PATHNAME@', 'ts_data_node_attach' LANGUAGE C VOLATILE;
-- Detach a data node from a distributed hypertable. NULL hypertable means it will detach from all distributed hypertables
CREATE OR REPLACE FUNCTION detach_data_node(node_name NAME, hypertable REGCLASS = NULL, force BOOLEAN = FALSE) RETURNS INTEGER
CREATE OR REPLACE FUNCTION detach_data_node(
node_name NAME,
hypertable REGCLASS = NULL,
force BOOLEAN = FALSE,
repartition BOOLEAN = TRUE
) RETURNS INTEGER
AS '@MODULE_PATHNAME@', 'ts_data_node_detach' LANGUAGE C VOLATILE;
-- Block new chunk creation on a data node for a distributed hypertable. NULL hypertable means it will block

View File

@ -809,18 +809,18 @@ data_node_attach(PG_FUNCTION_ARGS)
num_nodes = list_length(ht->data_nodes) + 1;
if (num_nodes > MAX_NUM_HYPERTABLE_DATA_NODES)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("max number of data nodes already attached"),
errdetail("The number of data nodes in a hypertable cannot exceed %d",
MAX_NUM_HYPERTABLE_DATA_NODES)));
/* If there are less slices (partitions) in the space dimension than there
* are data nodesx, we'd like to expand the number of slices to be able to
* are data nodes, we'd like to expand the number of slices to be able to
* make use of the new data node. */
if (NULL != dim && num_nodes > dim->fd.num_slices)
{
if (num_nodes > MAX_NUM_HYPERTABLE_DATA_NODES)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("max number of data nodes already attached"),
errdetail("The number of data nodes in a hypertable cannot exceed %d",
MAX_NUM_HYPERTABLE_DATA_NODES)));
if (repartition)
{
ts_dimension_set_number_of_slices(dim, num_nodes & 0xFFFF);
@ -975,7 +975,7 @@ data_node_detach_validate(const char *node_name, Hypertable *ht, bool force, Ope
static int
data_node_modify_hypertable_data_nodes(const char *node_name, List *hypertable_data_nodes,
bool all_hypertables, OperationType op_type,
bool block_chunks, bool force)
bool block_chunks, bool force, bool repartition)
{
Cache *hcache = ts_hypertable_cache_pin();
ListCell *lc;
@ -1028,6 +1028,26 @@ data_node_modify_hypertable_data_nodes(const char *node_name, List *hypertable_d
/* delete hypertable mapping */
removed +=
ts_hypertable_data_node_delete_by_node_name_and_hypertable_id(node_name, ht->fd.id);
if (repartition)
{
Dimension *dim = hyperspace_get_closed_dimension(ht->space, 0);
int num_nodes = list_length(ht->data_nodes) - 1;
if (dim != NULL && num_nodes < dim->fd.num_slices && num_nodes > 0)
{
ts_dimension_set_number_of_slices(dim, num_nodes & 0xFFFF);
ereport(NOTICE,
(errmsg("the number of partitions in dimension \"%s\" was decreased to "
"%u",
NameStr(dim->fd.column_name),
num_nodes),
errdetail(
"To make efficient use of all attached data nodes, the number of "
"space partitions was set to match the number of data nodes.")));
}
}
}
else
{
@ -1065,19 +1085,22 @@ data_node_block_hypertable_data_nodes(const char *node_name, List *hypertable_da
all_hypertables,
OP_BLOCK,
block_chunks,
force);
force,
false);
}
static int
data_node_detach_hypertable_data_nodes(const char *node_name, List *hypertable_data_nodes,
bool all_hypertables, bool force, OperationType op_type)
bool all_hypertables, bool force, bool repartition,
OperationType op_type)
{
return data_node_modify_hypertable_data_nodes(node_name,
hypertable_data_nodes,
all_hypertables,
op_type,
false,
force);
force,
repartition);
}
static HypertableDataNode *
@ -1171,6 +1194,7 @@ data_node_detach(PG_FUNCTION_ARGS)
Oid table_id = PG_ARGISNULL(1) ? InvalidOid : PG_GETARG_OID(1);
bool all_hypertables = PG_ARGISNULL(1);
bool force = PG_ARGISNULL(2) ? InvalidOid : PG_GETARG_OID(2);
bool repartition = PG_ARGISNULL(3) ? false : PG_GETARG_BOOL(3);
int removed = 0;
List *hypertable_data_nodes = NIL;
ForeignServer *server = data_node_get_foreign_server(node_name, ACL_USAGE, true, false);
@ -1197,6 +1221,7 @@ data_node_detach(PG_FUNCTION_ARGS)
hypertable_data_nodes,
all_hypertables,
force,
repartition,
OP_DETACH);
PG_RETURN_INT32(removed);
@ -1208,6 +1233,7 @@ data_node_delete(PG_FUNCTION_ARGS)
const char *node_name = PG_ARGISNULL(0) ? NULL : PG_GETARG_CSTRING(0);
bool if_exists = PG_ARGISNULL(1) ? false : PG_GETARG_BOOL(1);
bool force = PG_ARGISNULL(2) ? false : PG_GETARG_BOOL(2);
bool repartition = PG_ARGISNULL(3) ? false : PG_GETARG_BOOL(3);
List *hypertable_data_nodes = NIL;
DropStmt stmt;
ObjectAddress address;
@ -1247,6 +1273,7 @@ data_node_delete(PG_FUNCTION_ARGS)
hypertable_data_nodes,
true,
force,
repartition,
OP_DELETE);
stmt = (DropStmt){

View File

@ -458,6 +458,7 @@ RESET ROLE;
TRUNCATE disttable;
TRUNCATE costtable;
SELECT * FROM delete_data_node('data_node_1', force => true);
NOTICE: the number of partitions in dimension "device" was decreased to 1
delete_data_node
------------------
t

View File

@ -1016,6 +1016,7 @@ ERROR: table "devices" is not a hypertable
-- force detach data node to become under-replicated for new data
SELECT * FROM detach_data_node('data_node_3', 'disttable_2', force => true);
WARNING: new data for hypertable "disttable_2" will be under-replicated due to detaching data node "data_node_3"
NOTICE: the number of partitions in dimension "device" was decreased to 1
detach_data_node
------------------
1
@ -1108,6 +1109,7 @@ ORDER BY foreign_table_name;
SELECT * FROM detach_data_node('data_node_2', 'disttable', true);
WARNING: new data for hypertable "disttable" will be under-replicated due to detaching data node "data_node_2"
NOTICE: the number of partitions in dimension "device" was decreased to 1
detach_data_node
------------------
1

View File

@ -1909,6 +1909,41 @@ ts_insert_blocker| 7|_timescaledb_internal.insert_blocker
(1 row)
-- Verify that repartitioning works as expected on detach_data_node
SELECT * FROM detach_data_node('data_node_1', '"Table\\Schema"."Param_Table"', repartition => true);
NOTICE: the number of partitions in dimension "__region" was decreased to 2
detach_data_node
------------------
1
(1 row)
SELECT h.table_name, d.column_name, d.num_slices
FROM _timescaledb_catalog.hypertable h, _timescaledb_catalog.dimension d
WHERE h.id = d.hypertable_id
AND h.table_name = 'Param_Table';
table_name | column_name | num_slices
-------------+------------------+------------
Param_Table | __region | 2
Param_Table | time Col %#^#@$# |
(2 rows)
SELECT * FROM detach_data_node('data_node_2', '"Table\\Schema"."Param_Table"', force => true, repartition => false);
WARNING: new data for hypertable "Param_Table" will be under-replicated due to detaching data node "data_node_2"
detach_data_node
------------------
1
(1 row)
SELECT h.table_name, d.column_name, d.num_slices
FROM _timescaledb_catalog.hypertable h, _timescaledb_catalog.dimension d
WHERE h.id = d.hypertable_id
AND h.table_name = 'Param_Table';
table_name | column_name | num_slices
-------------+------------------+------------
Param_Table | __region | 2
Param_Table | time Col %#^#@$# |
(2 rows)
-- Test multi-dimensional hypertable. The add_dimension() command
-- should be propagated to backends.
CREATE TABLE dimented_table (time timestamptz, column1 int, column2 timestamptz, column3 int);
@ -1950,7 +1985,7 @@ SELECT * FROM _timescaledb_catalog.dimension;
2 | 1 | device | integer | f | 3 | _timescaledb_internal | get_partition_hash | | |
3 | 2 | time | timestamp with time zone | t | | | | 604800000000 | |
5 | 4 | time Col %#^#@$# | timestamp with time zone | t | | | | 604800000000 | |
6 | 4 | __region | text | f | 4 | _timescaledb_internal | get_partition_hash | | |
6 | 4 | __region | text | f | 2 | _timescaledb_internal | get_partition_hash | | |
7 | 5 | time | timestamp with time zone | t | | | | 604800000000 | |
8 | 5 | column1 | integer | f | 4 | _timescaledb_internal | get_partition_hash | | |
9 | 5 | column2 | timestamp with time zone | t | | | | 604800000000 | |
@ -1970,7 +2005,7 @@ SELECT * FROM _timescaledb_catalog.dimension;
2 | 1 | device | integer | f | 3 | _timescaledb_internal | get_partition_hash | | |
3 | 2 | time | timestamp with time zone | t | | | | 604800000000 | |
5 | 4 | time Col %#^#@$# | timestamp with time zone | t | | | | 604800000000 | |
6 | 4 | __region | text | f | 4 | _timescaledb_internal | get_partition_hash | | |
6 | 4 | __region | text | f | 2 | _timescaledb_internal | get_partition_hash | | |
7 | 5 | time | timestamp with time zone | t | | | | 604800000000 | |
8 | 5 | column1 | integer | f | 4 | _timescaledb_internal | get_partition_hash | | |
9 | 5 | column2 | timestamp with time zone | t | | | | 604800000000 | |

View File

@ -1909,6 +1909,41 @@ ts_insert_blocker| 7|_timescaledb_internal.insert_blocker
(1 row)
-- Verify that repartitioning works as expected on detach_data_node
SELECT * FROM detach_data_node('data_node_1', '"Table\\Schema"."Param_Table"', repartition => true);
NOTICE: the number of partitions in dimension "__region" was decreased to 2
detach_data_node
------------------
1
(1 row)
SELECT h.table_name, d.column_name, d.num_slices
FROM _timescaledb_catalog.hypertable h, _timescaledb_catalog.dimension d
WHERE h.id = d.hypertable_id
AND h.table_name = 'Param_Table';
table_name | column_name | num_slices
-------------+------------------+------------
Param_Table | __region | 2
Param_Table | time Col %#^#@$# |
(2 rows)
SELECT * FROM detach_data_node('data_node_2', '"Table\\Schema"."Param_Table"', force => true, repartition => false);
WARNING: new data for hypertable "Param_Table" will be under-replicated due to detaching data node "data_node_2"
detach_data_node
------------------
1
(1 row)
SELECT h.table_name, d.column_name, d.num_slices
FROM _timescaledb_catalog.hypertable h, _timescaledb_catalog.dimension d
WHERE h.id = d.hypertable_id
AND h.table_name = 'Param_Table';
table_name | column_name | num_slices
-------------+------------------+------------
Param_Table | __region | 2
Param_Table | time Col %#^#@$# |
(2 rows)
-- Test multi-dimensional hypertable. The add_dimension() command
-- should be propagated to backends.
CREATE TABLE dimented_table (time timestamptz, column1 int, column2 timestamptz, column3 int);
@ -1950,7 +1985,7 @@ SELECT * FROM _timescaledb_catalog.dimension;
2 | 1 | device | integer | f | 3 | _timescaledb_internal | get_partition_hash | | |
3 | 2 | time | timestamp with time zone | t | | | | 604800000000 | |
5 | 4 | time Col %#^#@$# | timestamp with time zone | t | | | | 604800000000 | |
6 | 4 | __region | text | f | 4 | _timescaledb_internal | get_partition_hash | | |
6 | 4 | __region | text | f | 2 | _timescaledb_internal | get_partition_hash | | |
7 | 5 | time | timestamp with time zone | t | | | | 604800000000 | |
8 | 5 | column1 | integer | f | 4 | _timescaledb_internal | get_partition_hash | | |
9 | 5 | column2 | timestamp with time zone | t | | | | 604800000000 | |
@ -1970,7 +2005,7 @@ SELECT * FROM _timescaledb_catalog.dimension;
2 | 1 | device | integer | f | 3 | _timescaledb_internal | get_partition_hash | | |
3 | 2 | time | timestamp with time zone | t | | | | 604800000000 | |
5 | 4 | time Col %#^#@$# | timestamp with time zone | t | | | | 604800000000 | |
6 | 4 | __region | text | f | 4 | _timescaledb_internal | get_partition_hash | | |
6 | 4 | __region | text | f | 2 | _timescaledb_internal | get_partition_hash | | |
7 | 5 | time | timestamp with time zone | t | | | | 604800000000 | |
8 | 5 | column1 | integer | f | 4 | _timescaledb_internal | get_partition_hash | | |
9 | 5 | column2 | timestamp with time zone | t | | | | 604800000000 | |

View File

@ -571,6 +571,18 @@ SELECT t.tgname, t.tgtype, t.tgfoid::regproc
FROM pg_trigger t, pg_class c WHERE c.relname = 'Param_Table' AND t.tgrelid = c.oid;
$$);
-- Verify that repartitioning works as expected on detach_data_node
SELECT * FROM detach_data_node('data_node_1', '"Table\\Schema"."Param_Table"', repartition => true);
SELECT h.table_name, d.column_name, d.num_slices
FROM _timescaledb_catalog.hypertable h, _timescaledb_catalog.dimension d
WHERE h.id = d.hypertable_id
AND h.table_name = 'Param_Table';
SELECT * FROM detach_data_node('data_node_2', '"Table\\Schema"."Param_Table"', force => true, repartition => false);
SELECT h.table_name, d.column_name, d.num_slices
FROM _timescaledb_catalog.hypertable h, _timescaledb_catalog.dimension d
WHERE h.id = d.hypertable_id
AND h.table_name = 'Param_Table';
-- Test multi-dimensional hypertable. The add_dimension() command
-- should be propagated to backends.
CREATE TABLE dimented_table (time timestamptz, column1 int, column2 timestamptz, column3 int);