Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions src/backend/distributed/metadata/node_metadata.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ static BackgroundWorkerHandle * LockPlacementsWithBackgroundWorkersInPrimaryNode
static int32 CitusAddCloneNode(WorkerNode *primaryWorkerNode,
char *cloneHostname, int32 clonePort);
static void RemoveCloneNode(WorkerNode *cloneNode);
static void ActivateNode(WorkerNode *acivateNode);

/* Function definitions go here */

Expand Down Expand Up @@ -787,6 +788,11 @@ citus_activate_node(PG_FUNCTION_ARGS)
if (NodeIsSecondary(workerNode))
{
EnsureTransactionalMetadataSyncMode();

ActivateNode(workerNode);
TransactionModifiedNodeMetadata = true;

PG_RETURN_INT32(workerNode->nodeId);
}

/*
Expand Down Expand Up @@ -3720,3 +3726,65 @@ SyncNodeMetadata(MetadataSyncContext *context)
*/
SendOrCollectCommandListToActivatedNodes(context, recreateNodeSnapshotCommandList);
}


/*
* ActivateNode It sets the node's isactive value to active with transactional
* mode.
*/
static void
ActivateNode(WorkerNode *acivateNode)
{
const bool indexOK = true;

Relation pgDistNode = table_open(DistNodeRelationId(), RowExclusiveLock);
TupleDesc tupleDescriptor = RelationGetDescr(pgDistNode);

ScanKeyData scanKey[1];


Datum *values = palloc0(tupleDescriptor->natts * sizeof(Datum));
bool *isnull = palloc0(tupleDescriptor->natts * sizeof(bool));
bool *replace = palloc0(tupleDescriptor->natts * sizeof(bool));

ScanKeyInit(&scanKey[0], Anum_pg_dist_node_nodeid,
BTEqualStrategyNumber, F_INT4EQ, Int32GetDatum(acivateNode->nodeId));

SysScanDesc scanDescriptor = systable_beginscan(pgDistNode, DistNodeNodeIdIndexId(),
indexOK,
NULL, 1, scanKey);

HeapTuple heapTuple = systable_getnext(scanDescriptor);
if (!HeapTupleIsValid(heapTuple))
{
ereport(ERROR, (errmsg("could not find valid entry for node \"%s:%d\"",
acivateNode->workerName, acivateNode->workerPort)));
}

values[Anum_pg_dist_node_isactive - 1] = BoolGetDatum(true);
isnull[Anum_pg_dist_node_isactive - 1] = false;
replace[Anum_pg_dist_node_isactive - 1] = true;


heapTuple = heap_modify_tuple(heapTuple, tupleDescriptor, values, isnull, replace);

CatalogTupleUpdate(pgDistNode, &heapTuple->t_self, heapTuple);

CitusInvalidateRelcacheByRelid(DistNodeRelationId());

CommandCounterIncrement();

if (EnableMetadataSync)
{
/* Send the update command to all primary nodes with metadata */
char *nodeUpdateCommand = NodeStateUpdateCommand(acivateNode->nodeId, true);
SendCommandToWorkersWithMetadata(nodeUpdateCommand);
}

systable_endscan(scanDescriptor);
table_close(pgDistNode, NoLock);

pfree(values);
pfree(isnull);
pfree(replace);
}
84 changes: 84 additions & 0 deletions src/test/regress/expected/check_activate_secondary_node.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
\c - - - :master_port
-- prepare testing
SELECT citus_set_coordinator_host('localhost', :master_port);
citus_set_coordinator_host
---------------------------------------------------------------------

(1 row)

SET citus.metadata_sync_mode TO 'transactional';
-- add inactive secondary node
SELECT 1 FROM citus_add_secondary_node('localhost', :follower_worker_2_port, 'localhost', :worker_2_port);
?column?
---------------------------------------------------------------------
1
(1 row)

SELECT 1 FROM citus_disable_node('localhost', :follower_worker_2_port);
?column?
---------------------------------------------------------------------
1
(1 row)

-- check inactive node
SELECT count(*) FROM pg_dist_node WHERE nodeport=:follower_worker_2_port AND nodename='localhost' AND NOT isactive;
count
---------------------------------------------------------------------
1
(1 row)

SELECT start_metadata_sync_to_all_nodes();
start_metadata_sync_to_all_nodes
---------------------------------------------------------------------
t
(1 row)

-- error because the node does not exist
SELECT 1 FROM citus_activate_node('localhost', 7777);
ERROR: node at "localhost:xxxxx" does not exist
\c - - - :worker_2_port
-- check inactive node on worker
SELECT count(*) FROM pg_dist_node WHERE nodeport=:follower_worker_2_port AND nodename='localhost' AND NOT isactive;
count
---------------------------------------------------------------------
1
(1 row)

\c - - - :master_port
-- main test: activate secondary node
SELECT 1 FROM citus_activate_node('localhost', :follower_worker_2_port);
?column?
---------------------------------------------------------------------
1
(1 row)

-- check is active node
SELECT count(*) FROM pg_dist_node WHERE nodeport=:follower_worker_2_port AND nodename='localhost' AND isactive;
count
---------------------------------------------------------------------
1
(1 row)

\c - - - :worker_2_port
-- check is active node
SELECT count(*) FROM pg_dist_node WHERE nodeport=:follower_worker_2_port AND nodename='localhost' AND isactive;
count
---------------------------------------------------------------------
1
(1 row)

\c - - - :worker_1_port
-- check active node
SELECT count(*) FROM pg_dist_node WHERE nodeport=:follower_worker_2_port AND nodename='localhost' AND isactive;
count
---------------------------------------------------------------------
1
(1 row)

\c - - - :master_port
SET citus.metadata_sync_mode TO 'nontransactional';
-- error this operation cannot be completed in nontransactional metadata sync mode
-- if the GUC citus.metadata_sync_mode set to 'nontransactional'
SELECT 1 FROM citus_activate_node('localhost', :follower_worker_2_port);
ERROR: this operation cannot be completed in nontransactional metadata sync mode
HINT: SET citus.metadata_sync_mode to 'transactional'
1 change: 1 addition & 0 deletions src/test/regress/multi_follower_schedule
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ test: multi_add_node_from_backup_sync_replica
# test that no tests leaked intermediate results. This should always be last
test: ensure_no_intermediate_data_leak
test: check_mx
test: check_activate_secondary_node
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new test is added after ensure_no_intermediate_data_leak, which has the comment "This should always be last."
Please move it before that line (e.g., before ensure_no_intermediate_data_leak, after multi_add_node_from_backup_sync_replica).

45 changes: 45 additions & 0 deletions src/test/regress/sql/check_activate_secondary_node.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
\c - - - :master_port
-- prepare testing
SELECT citus_set_coordinator_host('localhost', :master_port);

SET citus.metadata_sync_mode TO 'transactional';

-- add inactive secondary node
SELECT 1 FROM citus_add_secondary_node('localhost', :follower_worker_2_port, 'localhost', :worker_2_port);
SELECT 1 FROM citus_disable_node('localhost', :follower_worker_2_port);

-- check inactive node
SELECT count(*) FROM pg_dist_node WHERE nodeport=:follower_worker_2_port AND nodename='localhost' AND NOT isactive;
SELECT start_metadata_sync_to_all_nodes();

-- error because the node does not exist
SELECT 1 FROM citus_activate_node('localhost', 7777);


\c - - - :worker_2_port
-- check inactive node on worker
SELECT count(*) FROM pg_dist_node WHERE nodeport=:follower_worker_2_port AND nodename='localhost' AND NOT isactive;

\c - - - :master_port

-- main test: activate secondary node
SELECT 1 FROM citus_activate_node('localhost', :follower_worker_2_port);


-- check is active node
SELECT count(*) FROM pg_dist_node WHERE nodeport=:follower_worker_2_port AND nodename='localhost' AND isactive;

\c - - - :worker_2_port
-- check is active node
SELECT count(*) FROM pg_dist_node WHERE nodeport=:follower_worker_2_port AND nodename='localhost' AND isactive;

\c - - - :worker_1_port
-- check active node
SELECT count(*) FROM pg_dist_node WHERE nodeport=:follower_worker_2_port AND nodename='localhost' AND isactive;

\c - - - :master_port
SET citus.metadata_sync_mode TO 'nontransactional';

-- error this operation cannot be completed in nontransactional metadata sync mode
-- if the GUC citus.metadata_sync_mode set to 'nontransactional'
SELECT 1 FROM citus_activate_node('localhost', :follower_worker_2_port);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test adds a secondary node and activates it but doesn't clean up. Consider adding cleanup at the end to avoid polluting state for any future tests that might be added after this one in the schedule:
May be:
-- cleanup
SELECT citus_remove_node('localhost', :follower_worker_2_port);