citus/src/backend/distributed/test/metadata_sync.c

130 lines
3.7 KiB
C

/*-------------------------------------------------------------------------
*
* test/src/metadata_sync.c
*
* This file contains functions to exercise the metadata snapshoy
* generation functionality within Citus.
*
* Copyright (c) 2014-2016, Citus Data, Inc.
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "c.h"
#include "fmgr.h"
#include "catalog/pg_type.h"
#include "distributed/connection_management.h"
#include "distributed/listutils.h"
#include "distributed/metadata_sync.h"
#include "distributed/remote_commands.h"
#include "postmaster/postmaster.h"
#include "miscadmin.h"
#include "storage/latch.h"
#include "utils/array.h"
#include "utils/builtins.h"
/* declarations for dynamic loading */
PG_FUNCTION_INFO_V1(master_metadata_snapshot);
PG_FUNCTION_INFO_V1(wait_until_metadata_sync);
/*
* master_metadata_snapshot prints all the queries that are required
* to generate a metadata snapshot.
*/
Datum
master_metadata_snapshot(PG_FUNCTION_ARGS)
{
List *dropSnapshotCommands = MetadataDropCommands();
List *createSnapshotCommands = MetadataCreateCommands();
List *snapshotCommandList = NIL;
ListCell *snapshotCommandCell = NULL;
int snapshotCommandIndex = 0;
Oid ddlCommandTypeId = TEXTOID;
snapshotCommandList = list_concat(snapshotCommandList, dropSnapshotCommands);
snapshotCommandList = list_concat(snapshotCommandList, createSnapshotCommands);
int snapshotCommandCount = list_length(snapshotCommandList);
Datum *snapshotCommandDatumArray = palloc0(snapshotCommandCount * sizeof(Datum));
foreach(snapshotCommandCell, snapshotCommandList)
{
char *metadataSnapshotCommand = (char *) lfirst(snapshotCommandCell);
Datum metadataSnapshotCommandDatum = CStringGetTextDatum(metadataSnapshotCommand);
snapshotCommandDatumArray[snapshotCommandIndex] = metadataSnapshotCommandDatum;
snapshotCommandIndex++;
}
ArrayType *snapshotCommandArrayType = DatumArrayToArrayType(snapshotCommandDatumArray,
snapshotCommandCount,
ddlCommandTypeId);
PG_RETURN_ARRAYTYPE_P(snapshotCommandArrayType);
}
/*
* wait_until_metadata_sync waits until the maintenance daemon does a metadata
* sync, or times out.
*/
Datum
wait_until_metadata_sync(PG_FUNCTION_ARGS)
{
uint32 timeout = PG_GETARG_UINT32(0);
List *workerList = ActivePrimaryWorkerNodeList(NoLock);
ListCell *workerCell = NULL;
bool waitNotifications = false;
foreach(workerCell, workerList)
{
WorkerNode *workerNode = (WorkerNode *) lfirst(workerCell);
/* if already has metadata, no need to do it again */
if (workerNode->hasMetadata && !workerNode->metadataSynced)
{
waitNotifications = true;
break;
}
}
/*
* If all the metadata nodes have already been synced, we should not wait.
* That's primarily because the maintenance deamon might have already sent
* the notification and we'd wait unnecessarily here. Worse, the test outputs
* might be inconsistent across executions due to the warning.
*/
if (!waitNotifications)
{
PG_RETURN_VOID();
}
MultiConnection *connection = GetNodeConnection(FORCE_NEW_CONNECTION,
"localhost", PostPortNumber);
ExecuteCriticalRemoteCommand(connection, "LISTEN " METADATA_SYNC_CHANNEL);
int waitFlags = WL_SOCKET_READABLE | WL_TIMEOUT | WL_POSTMASTER_DEATH;
int waitResult = WaitLatchOrSocket(NULL, waitFlags, PQsocket(connection->pgConn),
timeout, 0);
if (waitResult & WL_POSTMASTER_DEATH)
{
ereport(ERROR, (errmsg("postmaster was shut down, exiting")));
}
else if (waitResult & WL_SOCKET_MASK)
{
ClearResults(connection, true);
}
else if (waitResult & WL_TIMEOUT)
{
elog(WARNING, "waiting for metadata sync timed out");
}
CloseConnection(connection);
PG_RETURN_VOID();
}