Fix crash in citus_copy_shard_placement

pull/6146/head
Marco Slot 2022-08-09 00:38:58 +02:00 committed by Marco Slot
parent 76a31f3234
commit 3b57ff2867
3 changed files with 111 additions and 2 deletions

View File

@ -74,6 +74,8 @@ static void VerifyTablesHaveReplicaIdentity(List *colocatedTableList);
static bool RelationCanPublishAllModifications(Oid relationId);
static bool CanUseLogicalReplication(Oid relationId, char shardReplicationMode);
static void ErrorIfTableCannotBeReplicated(Oid relationId);
static void ErrorIfTargetNodeIsNotSafeToCopyTo(const char *targetNodeName,
int targetNodePort);
static void RepairShardPlacement(int64 shardId, const char *sourceNodeName,
int32 sourceNodePort, const char *targetNodeName,
int32 targetNodePort);
@ -183,6 +185,7 @@ citus_copy_shard_placement(PG_FUNCTION_ARGS)
ShardInterval *shardInterval = LoadShardInterval(shardId);
ErrorIfTableCannotBeReplicated(shardInterval->relationId);
ErrorIfTargetNodeIsNotSafeToCopyTo(targetNodeName, targetNodePort);
AcquirePlacementColocationLock(shardInterval->relationId, ExclusiveLock,
doRepair ? "repair" : "copy");
@ -789,6 +792,41 @@ ErrorIfTableCannotBeReplicated(Oid relationId)
}
/*
* ErrorIfTargetNodeIsNotSafeToCopyTo throws an error if the target node is not
* eligible for copying shards.
*/
static void
ErrorIfTargetNodeIsNotSafeToCopyTo(const char *targetNodeName, int targetNodePort)
{
WorkerNode *workerNode = FindWorkerNode(targetNodeName, targetNodePort);
if (workerNode == NULL)
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("Copying shards to a non-existing node is not supported"),
errhint(
"Add the target node via SELECT citus_add_node('%s', %d);",
targetNodeName, targetNodePort)));
}
if (!workerNode->isActive)
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("Copying shards to a non-active node is not supported"),
errhint(
"Activate the target node via SELECT citus_activate_node('%s', %d);",
targetNodeName, targetNodePort)));
}
if (!NodeIsPrimary(workerNode))
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("Copying shards to a secondary (e.g., replica) node is "
"not supported")));
}
}
/*
* LookupShardTransferMode maps the oids of citus.shard_transfer_mode enum
* values to a char.

View File

@ -781,7 +781,51 @@ SELECT create_reference_table('ref_table');
(1 row)
INSERT INTO ref_table SELECT * FROM generate_series(1, 10);
SELECT 1 FROM master_add_node('localhost', :worker_2_port);
-- verify direct call to citus_copy_shard_placement errors if target node is not yet added
SELECT citus_copy_shard_placement(
(SELECT shardid FROM pg_dist_shard WHERE logicalrelid='ref_table'::regclass::oid),
'localhost', :worker_1_port,
'localhost', :worker_2_port,
do_repair := false,
transfer_mode := 'block_writes');
ERROR: Copying shards to a non-existing node is not supported
HINT: Add the target node via SELECT citus_add_node('localhost', 57638);
-- verify direct call to citus_copy_shard_placement errors if target node is secondary
SELECT citus_add_secondary_node('localhost', :worker_2_port, 'localhost', :worker_1_port);
citus_add_secondary_node
---------------------------------------------------------------------
1370012
(1 row)
SELECT citus_copy_shard_placement(
(SELECT shardid FROM pg_dist_shard WHERE logicalrelid='ref_table'::regclass::oid),
'localhost', :worker_1_port,
'localhost', :worker_2_port,
do_repair := false,
transfer_mode := 'block_writes');
ERROR: Copying shards to a secondary (e.g., replica) node is not supported
SELECT citus_remove_node('localhost', :worker_2_port);
citus_remove_node
---------------------------------------------------------------------
(1 row)
-- verify direct call to citus_copy_shard_placement errors if target node is inactive
SELECT 1 FROM master_add_inactive_node('localhost', :worker_2_port);
?column?
---------------------------------------------------------------------
1
(1 row)
SELECT citus_copy_shard_placement(
(SELECT shardid FROM pg_dist_shard WHERE logicalrelid='ref_table'::regclass::oid),
'localhost', :worker_1_port,
'localhost', :worker_2_port,
do_repair := false,
transfer_mode := 'block_writes');
ERROR: Copying shards to a non-active node is not supported
HINT: Activate the target node via SELECT citus_activate_node('localhost', 57638);
SELECT 1 FROM master_activate_node('localhost', :worker_2_port);
?column?
---------------------------------------------------------------------
1

View File

@ -509,7 +509,34 @@ CREATE TABLE ref_table(a int);
SELECT create_reference_table('ref_table');
INSERT INTO ref_table SELECT * FROM generate_series(1, 10);
SELECT 1 FROM master_add_node('localhost', :worker_2_port);
-- verify direct call to citus_copy_shard_placement errors if target node is not yet added
SELECT citus_copy_shard_placement(
(SELECT shardid FROM pg_dist_shard WHERE logicalrelid='ref_table'::regclass::oid),
'localhost', :worker_1_port,
'localhost', :worker_2_port,
do_repair := false,
transfer_mode := 'block_writes');
-- verify direct call to citus_copy_shard_placement errors if target node is secondary
SELECT citus_add_secondary_node('localhost', :worker_2_port, 'localhost', :worker_1_port);
SELECT citus_copy_shard_placement(
(SELECT shardid FROM pg_dist_shard WHERE logicalrelid='ref_table'::regclass::oid),
'localhost', :worker_1_port,
'localhost', :worker_2_port,
do_repair := false,
transfer_mode := 'block_writes');
SELECT citus_remove_node('localhost', :worker_2_port);
-- verify direct call to citus_copy_shard_placement errors if target node is inactive
SELECT 1 FROM master_add_inactive_node('localhost', :worker_2_port);
SELECT citus_copy_shard_placement(
(SELECT shardid FROM pg_dist_shard WHERE logicalrelid='ref_table'::regclass::oid),
'localhost', :worker_1_port,
'localhost', :worker_2_port,
do_repair := false,
transfer_mode := 'block_writes');
SELECT 1 FROM master_activate_node('localhost', :worker_2_port);
-- verify we cannot replicate reference tables in a transaction modifying pg_dist_node
BEGIN;