mirror of https://github.com/citusdata/citus.git
Adding comments and code for cleanup
parent
9e88c14096
commit
8c871bcd10
|
@ -379,8 +379,9 @@ GetConnParams(ConnectionHashKey *key, char ***keywords, char ***values,
|
||||||
|
|
||||||
if (key->replication)
|
if (key->replication)
|
||||||
{
|
{
|
||||||
connKeywords[authParamsIdx] = "replication";
|
connKeywords[authParamsIdx] = MemoryContextStrdup(context, "replication");
|
||||||
connValues[authParamsIdx] = "database";
|
connValues[authParamsIdx] = MemoryContextStrdup(context, "database");
|
||||||
|
|
||||||
authParamsIdx++;
|
authParamsIdx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,11 +71,6 @@ static void CreateDummyShardsForShardGroup(List *sourceColocatedShardIntervalLis
|
||||||
List *shardGroupSplitIntervalListList,
|
List *shardGroupSplitIntervalListList,
|
||||||
WorkerNode *sourceWorkerNode,
|
WorkerNode *sourceWorkerNode,
|
||||||
List *workersForPlacementList);
|
List *workersForPlacementList);
|
||||||
static void SplitShardReplicationSetup(ShardInterval *shardIntervalToSplit,
|
|
||||||
List *sourceColocatedShardIntervalList,
|
|
||||||
List *shardGroupSplitIntervalListList,
|
|
||||||
WorkerNode *sourceWorkerNode,
|
|
||||||
List *workersForPlacementList);
|
|
||||||
static HTAB * CreateWorkerForPlacementSet(List *workersForPlacementList);
|
static HTAB * CreateWorkerForPlacementSet(List *workersForPlacementList);
|
||||||
static void CreateAuxiliaryStructuresForShardGroup(List *shardGroupSplitIntervalListList,
|
static void CreateAuxiliaryStructuresForShardGroup(List *shardGroupSplitIntervalListList,
|
||||||
List *workersForPlacementList);
|
List *workersForPlacementList);
|
||||||
|
@ -100,10 +95,6 @@ static void DoSplitCopy(WorkerNode *sourceShardNode,
|
||||||
List *shardGroupSplitIntervalListList,
|
List *shardGroupSplitIntervalListList,
|
||||||
List *workersForPlacementList,
|
List *workersForPlacementList,
|
||||||
char *snapShotName);
|
char *snapShotName);
|
||||||
static void DoSplitCopy(WorkerNode *sourceShardNode,
|
|
||||||
List *sourceColocatedShardIntervalList,
|
|
||||||
List *shardGroupSplitIntervalListList,
|
|
||||||
List *workersForPlacementList);
|
|
||||||
static StringInfo CreateSplitCopyCommand(ShardInterval *sourceShardSplitInterval,
|
static StringInfo CreateSplitCopyCommand(ShardInterval *sourceShardSplitInterval,
|
||||||
List *splitChildrenShardIntervalList,
|
List *splitChildrenShardIntervalList,
|
||||||
List *workersForPlacementList);
|
List *workersForPlacementList);
|
||||||
|
@ -124,7 +115,9 @@ static void AddDummyShardEntryInMap(uint32 targetNodeId, ShardInterval *shardInt
|
||||||
static void DropDummyShards(void);
|
static void DropDummyShards(void);
|
||||||
void TryDropShard(MultiConnection *connection, ShardInterval *shardInterval);
|
void TryDropShard(MultiConnection *connection, ShardInterval *shardInterval);
|
||||||
char * CreateTemplateReplicationSlotAndReturnSnapshot(ShardInterval *shardInterval,
|
char * CreateTemplateReplicationSlotAndReturnSnapshot(ShardInterval *shardInterval,
|
||||||
WorkerNode *sourceWorkerNode);
|
WorkerNode *sourceWorkerNode,
|
||||||
|
MultiConnection **
|
||||||
|
templateSlotConnection);
|
||||||
|
|
||||||
static List * ExecuteSplitShardReplicationSetupUDF(WorkerNode *sourceWorkerNode,
|
static List * ExecuteSplitShardReplicationSetupUDF(WorkerNode *sourceWorkerNode,
|
||||||
List *sourceColocatedShardIntervalList,
|
List *sourceColocatedShardIntervalList,
|
||||||
|
@ -181,28 +174,6 @@ ErrorIfCannotSplitShard(SplitOperation splitOperation, ShardInterval *sourceShar
|
||||||
errdetail("Splitting shards backed by foreign tables "
|
errdetail("Splitting shards backed by foreign tables "
|
||||||
"is not supported.")));
|
"is not supported.")));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* At the moment, we do not support copying a shard if that shard's
|
|
||||||
* relation is in a colocation group with a partitioned table or partition.
|
|
||||||
*/
|
|
||||||
if (PartitionedTable(colocatedTableId))
|
|
||||||
{
|
|
||||||
char *sourceRelationName = get_rel_name(relationId);
|
|
||||||
char *colocatedRelationName = get_rel_name(colocatedTableId);
|
|
||||||
|
|
||||||
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
||||||
errmsg("cannot %s of '%s', because it "
|
|
||||||
"is a partitioned table",
|
|
||||||
SplitOperationName[splitOperation],
|
|
||||||
colocatedRelationName),
|
|
||||||
errdetail("In colocation group of '%s', a partitioned "
|
|
||||||
"relation exists: '%s'. Citus does not support "
|
|
||||||
"%s of partitioned tables.",
|
|
||||||
sourceRelationName,
|
|
||||||
colocatedRelationName,
|
|
||||||
SplitOperationName[splitOperation])));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check shards with inactive placements */
|
/* check shards with inactive placements */
|
||||||
|
@ -787,48 +758,48 @@ DoSplitCopy(WorkerNode *sourceShardNode, List *sourceColocatedShardIntervalList,
|
||||||
*/
|
*/
|
||||||
if (!PartitionedTable(sourceShardIntervalToCopy->relationId))
|
if (!PartitionedTable(sourceShardIntervalToCopy->relationId))
|
||||||
{
|
{
|
||||||
StringInfo splitCopyUdfCommand = CreateSplitCopyCommand(sourceShardIntervalToCopy,
|
StringInfo splitCopyUdfCommand = CreateSplitCopyCommand(
|
||||||
splitShardIntervalList,
|
sourceShardIntervalToCopy,
|
||||||
destinationWorkerNodesList);
|
splitShardIntervalList,
|
||||||
|
destinationWorkerNodesList);
|
||||||
|
|
||||||
List *ddlCommandList = NIL;
|
List *ddlCommandList = NIL;
|
||||||
StringInfo beginTransaction = makeStringInfo();
|
StringInfo beginTransaction = makeStringInfo();
|
||||||
appendStringInfo(beginTransaction,
|
appendStringInfo(beginTransaction,
|
||||||
"BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;");
|
"BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;");
|
||||||
ddlCommandList = lappend(ddlCommandList, beginTransaction->data);
|
ddlCommandList = lappend(ddlCommandList, beginTransaction->data);
|
||||||
|
|
||||||
/* Set snapshot */
|
/* Set snapshot */
|
||||||
if (snapShotName != NULL)
|
if (snapShotName != NULL)
|
||||||
{
|
{
|
||||||
StringInfo snapShotString = makeStringInfo();
|
StringInfo snapShotString = makeStringInfo();
|
||||||
appendStringInfo(snapShotString, "SET TRANSACTION SNAPSHOT %s;",
|
appendStringInfo(snapShotString, "SET TRANSACTION SNAPSHOT %s;",
|
||||||
quote_literal_cstr(
|
quote_literal_cstr(
|
||||||
snapShotName));
|
snapShotName));
|
||||||
ddlCommandList = lappend(ddlCommandList, snapShotString->data);
|
ddlCommandList = lappend(ddlCommandList, snapShotString->data);
|
||||||
printf("Sameer final string snapshotted:%s\n", snapShotString->data);
|
printf("Sameer final string snapshotted:%s\n", snapShotString->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
ddlCommandList = lappend(ddlCommandList, splitCopyUdfCommand->data);
|
ddlCommandList = lappend(ddlCommandList, splitCopyUdfCommand->data);
|
||||||
|
|
||||||
StringInfo commitCommand = makeStringInfo();
|
StringInfo commitCommand = makeStringInfo();
|
||||||
appendStringInfo(commitCommand, "COMMIT;");
|
appendStringInfo(commitCommand, "COMMIT;");
|
||||||
ddlCommandList = lappend(ddlCommandList, commitCommand->data);
|
ddlCommandList = lappend(ddlCommandList, commitCommand->data);
|
||||||
|
|
||||||
Task *splitCopyTask = CitusMakeNode(Task);
|
Task *splitCopyTask = CitusMakeNode(Task);
|
||||||
splitCopyTask->jobId = sourceShardIntervalToCopy->shardId;
|
splitCopyTask->jobId = sourceShardIntervalToCopy->shardId;
|
||||||
splitCopyTask->taskId = taskId;
|
splitCopyTask->taskId = taskId;
|
||||||
splitCopyTask->taskType = READ_TASK;
|
splitCopyTask->taskType = READ_TASK;
|
||||||
splitCopyTask->replicationModel = REPLICATION_MODEL_INVALID;
|
splitCopyTask->replicationModel = REPLICATION_MODEL_INVALID;
|
||||||
SetTaskQueryStringList(splitCopyTask, ddlCommandList);
|
SetTaskQueryStringList(splitCopyTask, ddlCommandList);
|
||||||
|
|
||||||
ShardPlacement *taskPlacement = CitusMakeNode(ShardPlacement);
|
ShardPlacement *taskPlacement = CitusMakeNode(ShardPlacement);
|
||||||
SetPlacementNodeMetadata(taskPlacement, sourceShardNode);
|
SetPlacementNodeMetadata(taskPlacement, sourceShardNode);
|
||||||
|
|
||||||
splitCopyTask->taskPlacementList = list_make1(taskPlacement);
|
splitCopyTask->taskPlacementList = list_make1(taskPlacement);
|
||||||
|
|
||||||
splitCopyTaskList = lappend(splitCopyTaskList, splitCopyTask);
|
|
||||||
taskId++;
|
|
||||||
|
|
||||||
|
splitCopyTaskList = lappend(splitCopyTaskList, splitCopyTask);
|
||||||
|
taskId++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1307,16 +1278,10 @@ NonBlockingShardSplit(SplitOperation splitOperation,
|
||||||
CreateEmptyMapForShardsCreatedByWorkflow();
|
CreateEmptyMapForShardsCreatedByWorkflow();
|
||||||
PG_TRY();
|
PG_TRY();
|
||||||
{
|
{
|
||||||
/*
|
/* Physically create split children. */
|
||||||
* Physically create split children, perform split copy and create auxillary structures.
|
CreateSplitShardsForShardGroup(mapOfShardToPlacementCreatedByWorkflow,
|
||||||
* This includes: indexes, replicaIdentity. triggers and statistics.
|
shardGroupSplitIntervalListList,
|
||||||
* Foreign key constraints are created after Metadata changes (see CreateForeignKeyConstraints).
|
workersForPlacementList);
|
||||||
*/
|
|
||||||
CreateSplitShardsForShardGroupTwo(
|
|
||||||
sourceShardToCopyNode,
|
|
||||||
sourceColocatedShardIntervalList,
|
|
||||||
shardGroupSplitIntervalListList,
|
|
||||||
workersForPlacementList);
|
|
||||||
|
|
||||||
|
|
||||||
CreateDummyShardsForShardGroup(
|
CreateDummyShardsForShardGroup(
|
||||||
|
@ -1327,9 +1292,10 @@ NonBlockingShardSplit(SplitOperation splitOperation,
|
||||||
|
|
||||||
CreateShardSplitPublications(sourceConnection, shardSplitHashMapForPublication);
|
CreateShardSplitPublications(sourceConnection, shardSplitHashMapForPublication);
|
||||||
|
|
||||||
/*Create Template Replication Slot */
|
/* Create Template Replication Slot */
|
||||||
char *snapShotName = NULL;
|
MultiConnection *templateSlotConnection = NULL;
|
||||||
snapShotName = CreateTemplateReplicationSlotAndReturnSnapshot(shardIntervalToSplit, sourceShardToCopyNode);
|
char *snapShotName = CreateTemplateReplicationSlotAndReturnSnapshot(
|
||||||
|
shardIntervalToSplit, sourceShardToCopyNode, &templateSlotConnection);
|
||||||
|
|
||||||
/* DoSplitCopy */
|
/* DoSplitCopy */
|
||||||
DoSplitCopy(sourceShardToCopyNode, sourceColocatedShardIntervalList,
|
DoSplitCopy(sourceShardToCopyNode, sourceColocatedShardIntervalList,
|
||||||
|
@ -1354,7 +1320,10 @@ NonBlockingShardSplit(SplitOperation splitOperation,
|
||||||
superUser, databaseName);
|
superUser, databaseName);
|
||||||
|
|
||||||
/* Create copies of template replication slot */
|
/* Create copies of template replication slot */
|
||||||
CreateReplicationSlots(sourceConnection, shardSplitSubscribersMetadataList);
|
char *templateSlotName = ShardSplitTemplateReplicationSlotName(
|
||||||
|
shardIntervalToSplit->shardId);
|
||||||
|
CreateReplicationSlots(sourceConnection, templateSlotName,
|
||||||
|
shardSplitSubscribersMetadataList);
|
||||||
|
|
||||||
CreateShardSplitSubscriptions(targetNodeConnectionList,
|
CreateShardSplitSubscriptions(targetNodeConnectionList,
|
||||||
shardSplitSubscribersMetadataList,
|
shardSplitSubscribersMetadataList,
|
||||||
|
@ -1382,6 +1351,12 @@ NonBlockingShardSplit(SplitOperation splitOperation,
|
||||||
WaitForShardSplitRelationSubscriptionsToBeCaughtUp(sourcePosition,
|
WaitForShardSplitRelationSubscriptionsToBeCaughtUp(sourcePosition,
|
||||||
shardSplitSubscribersMetadataList);
|
shardSplitSubscribersMetadataList);
|
||||||
|
|
||||||
|
/* Drop Subscribers */
|
||||||
|
DropShardSplitSubsriptions(shardSplitSubscribersMetadataList);
|
||||||
|
|
||||||
|
/* Drop Publications */
|
||||||
|
DropShardSplitPublications(sourceConnection, shardSplitHashMapForPublication);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Drop old shards and delete related metadata. Have to do that before
|
* Drop old shards and delete related metadata. Have to do that before
|
||||||
* creating the new shard metadata, because there's cross-checks
|
* creating the new shard metadata, because there's cross-checks
|
||||||
|
@ -1400,7 +1375,17 @@ NonBlockingShardSplit(SplitOperation splitOperation,
|
||||||
*/
|
*/
|
||||||
CreateForeignKeyConstraints(shardGroupSplitIntervalListList,
|
CreateForeignKeyConstraints(shardGroupSplitIntervalListList,
|
||||||
workersForPlacementList);
|
workersForPlacementList);
|
||||||
|
|
||||||
DropDummyShards();
|
DropDummyShards();
|
||||||
|
|
||||||
|
/* Close source connection */
|
||||||
|
CloseConnection(sourceConnection);
|
||||||
|
|
||||||
|
/* Close all subscriber connections */
|
||||||
|
CloseShardSplitSubscriberConnections(shardSplitSubscribersMetadataList);
|
||||||
|
|
||||||
|
/* Close connection of template replication slot */
|
||||||
|
CloseConnection(templateSlotConnection);
|
||||||
}
|
}
|
||||||
PG_CATCH();
|
PG_CATCH();
|
||||||
{
|
{
|
||||||
|
@ -1561,84 +1546,6 @@ CreateWorkerForPlacementSet(List *workersForPlacementList)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
SplitShardReplicationSetup(ShardInterval *shardIntervalToSplit,
|
|
||||||
List *sourceColocatedShardIntervalList,
|
|
||||||
List *shardGroupSplitIntervalListList,
|
|
||||||
WorkerNode *sourceWorkerNode,
|
|
||||||
List *destinationWorkerNodesList)
|
|
||||||
{
|
|
||||||
char *superUser = CitusExtensionOwnerName();
|
|
||||||
char *databaseName = get_database_name(MyDatabaseId);
|
|
||||||
int connectionFlags = FORCE_NEW_CONNECTION;
|
|
||||||
|
|
||||||
HTAB *shardSplitHashMapForPublication = CreateShardSplitInfoMapForPublication(
|
|
||||||
sourceColocatedShardIntervalList,
|
|
||||||
shardGroupSplitIntervalListList,
|
|
||||||
destinationWorkerNodesList);
|
|
||||||
|
|
||||||
DropAllShardSplitLeftOvers(sourceWorkerNode, shardSplitHashMapForPublication);
|
|
||||||
|
|
||||||
MultiConnection *sourceConnection = GetNodeUserDatabaseConnection(connectionFlags,
|
|
||||||
sourceWorkerNode->
|
|
||||||
workerName,
|
|
||||||
sourceWorkerNode->
|
|
||||||
workerPort,
|
|
||||||
superUser,
|
|
||||||
databaseName);
|
|
||||||
ClaimConnectionExclusively(sourceConnection);
|
|
||||||
|
|
||||||
CreateShardSplitPublications(sourceConnection, shardSplitHashMapForPublication);
|
|
||||||
|
|
||||||
/*Create Template Replication Slot */
|
|
||||||
|
|
||||||
/* DoSplitCopy */
|
|
||||||
|
|
||||||
/*worker_split_replication_setup_udf*/
|
|
||||||
List *replicationSlotInfoList = ExecuteSplitShardReplicationSetupUDF(
|
|
||||||
sourceWorkerNode,
|
|
||||||
sourceColocatedShardIntervalList,
|
|
||||||
shardGroupSplitIntervalListList,
|
|
||||||
destinationWorkerNodesList);
|
|
||||||
|
|
||||||
/* Subscriber flow starts from here */
|
|
||||||
List *shardSplitSubscribersMetadataList = PopulateShardSplitSubscriptionsMetadataList(
|
|
||||||
shardSplitHashMapForPublication, replicationSlotInfoList);
|
|
||||||
|
|
||||||
List *targetNodeConnectionList = CreateTargetNodeConnectionsForShardSplit(
|
|
||||||
shardSplitSubscribersMetadataList,
|
|
||||||
connectionFlags,
|
|
||||||
superUser, databaseName);
|
|
||||||
|
|
||||||
CreateShardSplitSubscriptions(targetNodeConnectionList,
|
|
||||||
shardSplitSubscribersMetadataList,
|
|
||||||
sourceWorkerNode,
|
|
||||||
superUser,
|
|
||||||
databaseName);
|
|
||||||
|
|
||||||
WaitForShardSplitRelationSubscriptionsBecomeReady(shardSplitSubscribersMetadataList);
|
|
||||||
|
|
||||||
XLogRecPtr sourcePosition = GetRemoteLogPosition(sourceConnection);
|
|
||||||
WaitForShardSplitRelationSubscriptionsToBeCaughtUp(sourcePosition,
|
|
||||||
shardSplitSubscribersMetadataList);
|
|
||||||
|
|
||||||
CreateAuxiliaryStructuresForShardGroup(shardGroupSplitIntervalListList,
|
|
||||||
destinationWorkerNodesList);
|
|
||||||
|
|
||||||
sourcePosition = GetRemoteLogPosition(sourceConnection);
|
|
||||||
WaitForShardSplitRelationSubscriptionsToBeCaughtUp(sourcePosition,
|
|
||||||
shardSplitSubscribersMetadataList);
|
|
||||||
|
|
||||||
BlockWritesToShardList(sourceColocatedShardIntervalList);
|
|
||||||
|
|
||||||
sourcePosition = GetRemoteLogPosition(sourceConnection);
|
|
||||||
WaitForShardSplitRelationSubscriptionsToBeCaughtUp(sourcePosition,
|
|
||||||
shardSplitSubscribersMetadataList);
|
|
||||||
|
|
||||||
/*DropAllShardSplitLeftOvers(sourceWorkerNode, shardSplitHashMapForPublication); */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
AddDummyShardEntryInMap(uint32 targetNodeId, ShardInterval *shardInterval)
|
AddDummyShardEntryInMap(uint32 targetNodeId, ShardInterval *shardInterval)
|
||||||
{
|
{
|
||||||
|
@ -1681,6 +1588,7 @@ DropDummyShards()
|
||||||
|
|
||||||
int connectionFlags = FOR_DDL;
|
int connectionFlags = FOR_DDL;
|
||||||
connectionFlags |= OUTSIDE_TRANSACTION;
|
connectionFlags |= OUTSIDE_TRANSACTION;
|
||||||
|
connectionFlags |= FORCE_NEW_CONNECTION;
|
||||||
MultiConnection *connection = GetNodeUserDatabaseConnection(
|
MultiConnection *connection = GetNodeUserDatabaseConnection(
|
||||||
connectionFlags,
|
connectionFlags,
|
||||||
shardToBeDroppedNode->workerName,
|
shardToBeDroppedNode->workerName,
|
||||||
|
@ -1694,6 +1602,8 @@ DropDummyShards()
|
||||||
{
|
{
|
||||||
TryDropShard(connection, shardInterval);
|
TryDropShard(connection, shardInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CloseConnection(connection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1721,7 +1631,8 @@ TryDropShard(MultiConnection *connection, ShardInterval *shardInterval)
|
||||||
|
|
||||||
char *
|
char *
|
||||||
CreateTemplateReplicationSlotAndReturnSnapshot(ShardInterval *shardInterval,
|
CreateTemplateReplicationSlotAndReturnSnapshot(ShardInterval *shardInterval,
|
||||||
WorkerNode *sourceWorkerNode)
|
WorkerNode *sourceWorkerNode,
|
||||||
|
MultiConnection **templateSlotConnection)
|
||||||
{
|
{
|
||||||
/*Create Template replication slot */
|
/*Create Template replication slot */
|
||||||
int connectionFlags = FORCE_NEW_CONNECTION;
|
int connectionFlags = FORCE_NEW_CONNECTION;
|
||||||
|
@ -1736,9 +1647,12 @@ CreateTemplateReplicationSlotAndReturnSnapshot(ShardInterval *shardInterval,
|
||||||
get_database_name(
|
get_database_name(
|
||||||
MyDatabaseId));
|
MyDatabaseId));
|
||||||
|
|
||||||
|
ClaimConnectionExclusively(sourceConnection);
|
||||||
|
|
||||||
char *snapShotName = DropExistingIfAnyAndCreateTemplateReplicationSlot(shardInterval,
|
char *snapShotName = DropExistingIfAnyAndCreateTemplateReplicationSlot(shardInterval,
|
||||||
sourceConnection);
|
sourceConnection);
|
||||||
|
|
||||||
|
*templateSlotConnection = sourceConnection;
|
||||||
return snapShotName;
|
return snapShotName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1785,6 +1699,7 @@ ExecuteSplitShardReplicationSetupUDF(WorkerNode *sourceWorkerNode,
|
||||||
|
|
||||||
PQclear(result);
|
PQclear(result);
|
||||||
ForgetResults(sourceConnection);
|
ForgetResults(sourceConnection);
|
||||||
|
CloseConnection(sourceConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get replication slot information */
|
/* Get replication slot information */
|
||||||
|
@ -1792,8 +1707,8 @@ ExecuteSplitShardReplicationSetupUDF(WorkerNode *sourceWorkerNode,
|
||||||
|
|
||||||
PQclear(result);
|
PQclear(result);
|
||||||
ForgetResults(sourceConnection);
|
ForgetResults(sourceConnection);
|
||||||
UnclaimConnection(sourceConnection);
|
|
||||||
|
|
||||||
|
CloseConnection(sourceConnection);
|
||||||
return replicationSlotInfoList;
|
return replicationSlotInfoList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,7 +140,6 @@ static XLogRecPtr GetSubscriptionPosition(MultiConnection *connection,
|
||||||
Bitmapset *tableOwnerIds,
|
Bitmapset *tableOwnerIds,
|
||||||
char *operationPrefix);
|
char *operationPrefix);
|
||||||
static char * ShardMovePublicationName(Oid ownerId);
|
static char * ShardMovePublicationName(Oid ownerId);
|
||||||
static char * ShardSubscriptionName(Oid ownerId, char *operationPrefix);
|
|
||||||
static void AcquireLogicalReplicationLock(void);
|
static void AcquireLogicalReplicationLock(void);
|
||||||
static void DropAllShardMoveLeftovers(void);
|
static void DropAllShardMoveLeftovers(void);
|
||||||
static void DropAllShardMoveSubscriptions(MultiConnection *connection);
|
static void DropAllShardMoveSubscriptions(MultiConnection *connection);
|
||||||
|
@ -149,8 +148,6 @@ static void DropAllShardMovePublications(MultiConnection *connection);
|
||||||
static void DropAllShardMoveUsers(MultiConnection *connection);
|
static void DropAllShardMoveUsers(MultiConnection *connection);
|
||||||
static char * ShardSubscriptionNamesValueList(Bitmapset *tableOwnerIds,
|
static char * ShardSubscriptionNamesValueList(Bitmapset *tableOwnerIds,
|
||||||
char *operationPrefix);
|
char *operationPrefix);
|
||||||
static void DropShardMoveReplicationSlot(MultiConnection *connection,
|
|
||||||
char *publicationName);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* LogicallyReplicateShards replicates a list of shards from one node to another
|
* LogicallyReplicateShards replicates a list of shards from one node to another
|
||||||
|
@ -1096,7 +1093,7 @@ DropShardMovePublications(MultiConnection *connection, Bitmapset *tableOwnerIds)
|
||||||
* DropShardMoveReplicationSlot drops the replication slot with the given name
|
* DropShardMoveReplicationSlot drops the replication slot with the given name
|
||||||
* if it exists.
|
* if it exists.
|
||||||
*/
|
*/
|
||||||
static void
|
void
|
||||||
DropShardMoveReplicationSlot(MultiConnection *connection, char *replicationSlotName)
|
DropShardMoveReplicationSlot(MultiConnection *connection, char *replicationSlotName)
|
||||||
{
|
{
|
||||||
ExecuteCriticalRemoteCommand(
|
ExecuteCriticalRemoteCommand(
|
||||||
|
@ -1144,7 +1141,7 @@ ShardMovePublicationName(Oid ownerId)
|
||||||
* This PID is then extracted from the application_name to find out which PID on the
|
* This PID is then extracted from the application_name to find out which PID on the
|
||||||
* coordinator is blocked by the blocked replication process.
|
* coordinator is blocked by the blocked replication process.
|
||||||
*/
|
*/
|
||||||
static char *
|
char *
|
||||||
ShardSubscriptionName(Oid ownerId, char *operationPrefix)
|
ShardSubscriptionName(Oid ownerId, char *operationPrefix)
|
||||||
{
|
{
|
||||||
if (RunningUnderIsolationTest)
|
if (RunningUnderIsolationTest)
|
||||||
|
@ -1162,7 +1159,7 @@ ShardSubscriptionName(Oid ownerId, char *operationPrefix)
|
||||||
* ShardSubscriptionRole returns the name of the role used by the
|
* ShardSubscriptionRole returns the name of the role used by the
|
||||||
* subscription that subscribes to the tables of the given owner.
|
* subscription that subscribes to the tables of the given owner.
|
||||||
*/
|
*/
|
||||||
static char *
|
char *
|
||||||
ShardSubscriptionRole(Oid ownerId, char *operationPrefix)
|
ShardSubscriptionRole(Oid ownerId, char *operationPrefix)
|
||||||
{
|
{
|
||||||
return psprintf("%s%i", operationPrefix, ownerId);
|
return psprintf("%s%i", operationPrefix, ownerId);
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "commands/dbcommands.h"
|
#include "commands/dbcommands.h"
|
||||||
|
|
||||||
|
|
||||||
static HTAB *ShardInfoHashMapForPublications = NULL;
|
static HTAB *ShardInfoHashMapForPublications = NULL;
|
||||||
|
|
||||||
/* function declarations */
|
/* function declarations */
|
||||||
|
@ -32,46 +33,15 @@ ShardSplitSubscriberMetadata * CreateShardSplitSubscriberMetadata(Oid tableOwner
|
||||||
nodeId,
|
nodeId,
|
||||||
List *
|
List *
|
||||||
replicationSlotInfoList);
|
replicationSlotInfoList);
|
||||||
|
|
||||||
static void CreateShardSplitPublicationForNode(MultiConnection *connection,
|
static void CreateShardSplitPublicationForNode(MultiConnection *connection,
|
||||||
List *shardList,
|
List *shardList,
|
||||||
uint32_t publicationForTargetNodeId, Oid
|
uint32_t publicationForTargetNodeId, Oid
|
||||||
tableOwner);
|
tableOwner);
|
||||||
|
|
||||||
static char * ShardSplitPublicationName(uint32_t nodeId, Oid ownerId);
|
static char * ShardSplitPublicationName(uint32_t nodeId, Oid ownerId);
|
||||||
|
|
||||||
|
|
||||||
static void DropAllShardSplitSubscriptions(MultiConnection *cleanupConnection);
|
static void DropAllShardSplitSubscriptions(MultiConnection *cleanupConnection);
|
||||||
static void DropAllShardSplitPublications(MultiConnection *cleanupConnection);
|
static void DropAllShardSplitPublications(MultiConnection *cleanupConnection);
|
||||||
static void DropAllShardSplitUsers(MultiConnection *cleanupConnection);
|
static void DropAllShardSplitUsers(MultiConnection *cleanupConnection);
|
||||||
static void DropAllReplicationSlots(List *replicationSlotInfo);
|
static void DropAllShardSplitReplicationSlots(MultiConnection *cleanupConnection);
|
||||||
|
|
||||||
|
|
||||||
List *
|
|
||||||
ParseReplicationSlotInfoFromResult(PGresult *result)
|
|
||||||
{
|
|
||||||
int64 rowCount = PQntuples(result);
|
|
||||||
int64 colCount = PQnfields(result);
|
|
||||||
|
|
||||||
List *replicationSlotInfoList = NIL;
|
|
||||||
for (int64 rowIndex = 0; rowIndex < rowCount; rowIndex++)
|
|
||||||
{
|
|
||||||
ReplicationSlotInfo *replicationSlotInfo = (ReplicationSlotInfo *) palloc0(
|
|
||||||
sizeof(ReplicationSlotInfo));
|
|
||||||
|
|
||||||
char *targeNodeIdString = PQgetvalue(result, rowIndex, 0);
|
|
||||||
replicationSlotInfo->targetNodeId = strtoul(targeNodeIdString, NULL, 10);
|
|
||||||
|
|
||||||
/* we're using the pstrdup to copy the data into the current memory context */
|
|
||||||
replicationSlotInfo->tableOwnerName = pstrdup(PQgetvalue(result, rowIndex, 1));
|
|
||||||
|
|
||||||
replicationSlotInfo->slotName = pstrdup(PQgetvalue(result, rowIndex, 2));
|
|
||||||
|
|
||||||
replicationSlotInfoList = lappend(replicationSlotInfoList, replicationSlotInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
return replicationSlotInfoList;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
HTAB *
|
HTAB *
|
||||||
|
@ -150,74 +120,6 @@ AddPublishableShardEntryInMap(uint32 targetNodeId, ShardInterval *shardInterval,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
LogicallyReplicateSplitShards(WorkerNode *sourceWorkerNode,
|
|
||||||
List *shardSplitPubSubMetadataList,
|
|
||||||
List *sourceColocatedShardIntervalList,
|
|
||||||
List *shardGroupSplitIntervalListList,
|
|
||||||
List *destinationWorkerNodesList)
|
|
||||||
{
|
|
||||||
char *superUser = CitusExtensionOwnerName();
|
|
||||||
char *databaseName = get_database_name(MyDatabaseId);
|
|
||||||
int connectionFlags = FORCE_NEW_CONNECTION;
|
|
||||||
|
|
||||||
/* Get source node connection */
|
|
||||||
MultiConnection *sourceConnection =
|
|
||||||
GetNodeUserDatabaseConnection(connectionFlags, sourceWorkerNode->workerName,
|
|
||||||
sourceWorkerNode->workerPort,
|
|
||||||
superUser, databaseName);
|
|
||||||
|
|
||||||
ClaimConnectionExclusively(sourceConnection);
|
|
||||||
|
|
||||||
List *targetNodeConnectionList = CreateTargetNodeConnectionsForShardSplit(
|
|
||||||
shardSplitPubSubMetadataList,
|
|
||||||
connectionFlags,
|
|
||||||
superUser, databaseName);
|
|
||||||
|
|
||||||
/* create publications */
|
|
||||||
/*CreateShardSplitPublications(sourceConnection, shardSplitPubSubMetadataList); */
|
|
||||||
|
|
||||||
CreateShardSplitSubscriptions(targetNodeConnectionList,
|
|
||||||
shardSplitPubSubMetadataList,
|
|
||||||
sourceWorkerNode,
|
|
||||||
superUser,
|
|
||||||
databaseName);
|
|
||||||
|
|
||||||
WaitForShardSplitRelationSubscriptionsBecomeReady(shardSplitPubSubMetadataList);
|
|
||||||
|
|
||||||
XLogRecPtr sourcePosition = GetRemoteLogPosition(sourceConnection);
|
|
||||||
WaitForShardSplitRelationSubscriptionsToBeCaughtUp(sourcePosition,
|
|
||||||
shardSplitPubSubMetadataList);
|
|
||||||
|
|
||||||
CreateAuxiliaryStructuresForShardGroup(shardGroupSplitIntervalListList,
|
|
||||||
destinationWorkerNodesList);
|
|
||||||
|
|
||||||
sourcePosition = GetRemoteLogPosition(sourceConnection);
|
|
||||||
WaitForShardSplitRelationSubscriptionsToBeCaughtUp(sourcePosition,
|
|
||||||
shardSplitPubSubMetadataList);
|
|
||||||
|
|
||||||
BlockWritesToShardList(sourceColocatedShardIntervalList);
|
|
||||||
|
|
||||||
sourcePosition = GetRemoteLogPosition(sourceConnection);
|
|
||||||
WaitForShardSplitRelationSubscriptionsToBeCaughtUp(sourcePosition,
|
|
||||||
shardSplitPubSubMetadataList);
|
|
||||||
|
|
||||||
/*TOOD : Create foreign key constraints and handle partitioned tables*/
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
PrintShardSplitPubSubMetadata(ShardSplitSubscriberMetadata *shardSplitMetadata)
|
|
||||||
{
|
|
||||||
printf("\nsameer: ShardSplitPubSbuMetadata");
|
|
||||||
ReplicationSlotInfo *replicationInfo = shardSplitMetadata->slotInfo;
|
|
||||||
printf("Manual Username from OID at source: %s \n", GetUserNameFromId(
|
|
||||||
shardSplitMetadata->tableOwnerId, false));
|
|
||||||
printf("slotname:%s targetNode:%u tableOwner:%s \n", replicationInfo->slotName,
|
|
||||||
replicationInfo->targetNodeId, replicationInfo->tableOwnerName);
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CreateShardSplitSubscriptions(List *targetNodeConnectionList,
|
CreateShardSplitSubscriptions(List *targetNodeConnectionList,
|
||||||
List *shardSplitPubSubMetadataList,
|
List *shardSplitPubSubMetadataList,
|
||||||
|
@ -348,18 +250,14 @@ char *
|
||||||
DropExistingIfAnyAndCreateTemplateReplicationSlot(ShardInterval *shardIntervalToSplit,
|
DropExistingIfAnyAndCreateTemplateReplicationSlot(ShardInterval *shardIntervalToSplit,
|
||||||
MultiConnection *sourceConnection)
|
MultiConnection *sourceConnection)
|
||||||
{
|
{
|
||||||
StringInfo splitTemplateReplicationSlotName = makeStringInfo();
|
|
||||||
appendStringInfo(splitTemplateReplicationSlotName,
|
|
||||||
"citus_split_replicationslot_for_shard_%lu",
|
|
||||||
shardIntervalToSplit->shardId);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* To ensure SPLIT is idempotent drop any existing slot from
|
* To ensure SPLIT is idempotent drop any existing slot from
|
||||||
* previous failed operation.
|
* previous failed operation.
|
||||||
*/
|
*/
|
||||||
StringInfo dropReplicationSlotCommand = makeStringInfo();
|
StringInfo dropReplicationSlotCommand = makeStringInfo();
|
||||||
appendStringInfo(dropReplicationSlotCommand, "SELECT pg_drop_replication_slot('%s')",
|
appendStringInfo(dropReplicationSlotCommand, "SELECT pg_drop_replication_slot('%s')",
|
||||||
splitTemplateReplicationSlotName->data);
|
ShardSplitTemplateReplicationSlotName(
|
||||||
|
shardIntervalToSplit->shardId));
|
||||||
|
|
||||||
/* The Drop command can fail so ignore the response / result and proceed anyways */
|
/* The Drop command can fail so ignore the response / result and proceed anyways */
|
||||||
PGresult *result = NULL;
|
PGresult *result = NULL;
|
||||||
|
@ -383,7 +281,8 @@ DropExistingIfAnyAndCreateTemplateReplicationSlot(ShardInterval *shardIntervalTo
|
||||||
/*TODO(saawasek): Try creating TEMPORAL once basic flow is ready and we have a testcase*/
|
/*TODO(saawasek): Try creating TEMPORAL once basic flow is ready and we have a testcase*/
|
||||||
appendStringInfo(createReplicationSlotCommand,
|
appendStringInfo(createReplicationSlotCommand,
|
||||||
"CREATE_REPLICATION_SLOT %s LOGICAL citus EXPORT_SNAPSHOT;",
|
"CREATE_REPLICATION_SLOT %s LOGICAL citus EXPORT_SNAPSHOT;",
|
||||||
splitTemplateReplicationSlotName->data);
|
ShardSplitTemplateReplicationSlotName(
|
||||||
|
shardIntervalToSplit->shardId));
|
||||||
|
|
||||||
response = ExecuteOptionalRemoteCommand(sourceConnection,
|
response = ExecuteOptionalRemoteCommand(sourceConnection,
|
||||||
createReplicationSlotCommand->data, &result);
|
createReplicationSlotCommand->data, &result);
|
||||||
|
@ -396,103 +295,10 @@ DropExistingIfAnyAndCreateTemplateReplicationSlot(ShardInterval *shardIntervalTo
|
||||||
/*'snapshot_name' is second column where index starts from zero.
|
/*'snapshot_name' is second column where index starts from zero.
|
||||||
* We're using the pstrdup to copy the data into the current memory context */
|
* We're using the pstrdup to copy the data into the current memory context */
|
||||||
char *snapShotName = pstrdup(PQgetvalue(result, 0, 2 /* columIndex */));
|
char *snapShotName = pstrdup(PQgetvalue(result, 0, 2 /* columIndex */));
|
||||||
|
|
||||||
return snapShotName;
|
return snapShotName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
DropAllShardSplitLeftOvers(WorkerNode *sourceNode, HTAB *shardSplitHashMapForPubSub)
|
|
||||||
{
|
|
||||||
char *superUser = CitusExtensionOwnerName();
|
|
||||||
char *databaseName = get_database_name(MyDatabaseId);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We open new connections to all nodes. The reason for this is that
|
|
||||||
* operations on subscriptions and publications cannot be run in a
|
|
||||||
* transaction. By forcing a new connection we make sure no transaction is
|
|
||||||
* active on the connection.
|
|
||||||
*/
|
|
||||||
int connectionFlags = FORCE_NEW_CONNECTION;
|
|
||||||
|
|
||||||
HASH_SEQ_STATUS statusForSubscription;
|
|
||||||
hash_seq_init(&statusForSubscription, shardSplitHashMapForPubSub);
|
|
||||||
|
|
||||||
NodeShardMappingEntry *entry = NULL;
|
|
||||||
while ((entry = (NodeShardMappingEntry *) hash_seq_search(&statusForSubscription)) !=
|
|
||||||
NULL)
|
|
||||||
{
|
|
||||||
uint32_t nodeId = entry->key.nodeId;
|
|
||||||
WorkerNode *workerNode = FindNodeWithNodeId(nodeId, false /*missingOk*/);
|
|
||||||
MultiConnection *cleanupConnection = GetNodeUserDatabaseConnection(
|
|
||||||
connectionFlags, workerNode->workerName, workerNode->workerPort,
|
|
||||||
superUser, databaseName);
|
|
||||||
|
|
||||||
DropAllShardSplitSubscriptions(cleanupConnection);
|
|
||||||
DropAllShardSplitUsers(cleanupConnection);
|
|
||||||
|
|
||||||
CloseConnection(cleanupConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*Drop all shard split publications at the source*/
|
|
||||||
MultiConnection *sourceNodeConnection = GetNodeUserDatabaseConnection(
|
|
||||||
connectionFlags, sourceNode->workerName, sourceNode->workerPort,
|
|
||||||
superUser, databaseName);
|
|
||||||
|
|
||||||
DropAllShardSplitPublications(sourceNodeConnection);
|
|
||||||
|
|
||||||
CloseConnection(sourceNodeConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
DropAllShardSplitSubscriptions(MultiConnection *cleanupConnection)
|
|
||||||
{
|
|
||||||
char *query = psprintf(
|
|
||||||
"SELECT subname FROM pg_subscription "
|
|
||||||
"WHERE subname LIKE %s || '%%'",
|
|
||||||
quote_literal_cstr(SHARD_SPLIT_SUBSCRIPTION_PREFIX));
|
|
||||||
List *subscriptionNameList = GetQueryResultStringList(cleanupConnection, query);
|
|
||||||
char *subscriptionName = NULL;
|
|
||||||
foreach_ptr(subscriptionName, subscriptionNameList)
|
|
||||||
{
|
|
||||||
DropShardSubscription(cleanupConnection, subscriptionName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
DropAllShardSplitPublications(MultiConnection *connection)
|
|
||||||
{
|
|
||||||
char *query = psprintf(
|
|
||||||
"SELECT pubname FROM pg_publication "
|
|
||||||
"WHERE pubname LIKE %s || '%%'",
|
|
||||||
quote_literal_cstr(SHARD_SPLIT_PUBLICATION_PREFIX));
|
|
||||||
List *publicationNameList = GetQueryResultStringList(connection, query);
|
|
||||||
char *publicationName;
|
|
||||||
foreach_ptr(publicationName, publicationNameList)
|
|
||||||
{
|
|
||||||
DropShardPublication(connection, publicationName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
DropAllShardSplitUsers(MultiConnection *connection)
|
|
||||||
{
|
|
||||||
char *query = psprintf(
|
|
||||||
"SELECT rolname FROM pg_roles "
|
|
||||||
"WHERE rolname LIKE %s || '%%'",
|
|
||||||
quote_literal_cstr(SHARD_SPLIT_SUBSCRIPTION_ROLE_PREFIX));
|
|
||||||
List *usernameList = GetQueryResultStringList(connection, query);
|
|
||||||
char *username;
|
|
||||||
foreach_ptr(username, usernameList)
|
|
||||||
{
|
|
||||||
DropShardUser(connection, username);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CreateShardSplitPublications(MultiConnection *sourceConnection,
|
CreateShardSplitPublications(MultiConnection *sourceConnection,
|
||||||
HTAB *shardInfoHashMapForPublication)
|
HTAB *shardInfoHashMapForPublication)
|
||||||
|
@ -560,17 +366,13 @@ CreateShardSplitSubscriberMetadata(Oid tableOwnerId, uint32 nodeId,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintShardSplitPubSubMetadata(shardSplitSubscriberMetadata);
|
|
||||||
|
|
||||||
return shardSplitSubscriberMetadata;
|
return shardSplitSubscriberMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*TODO(saawasek): Remove existing slots before creating newer ones */
|
/*TODO(saawasek): Remove existing slots before creating newer ones */
|
||||||
|
|
||||||
/* extern void CreateReplicationSlots(MultiConnection *sourceNodeConnection, List * shardSplitSubscriberMetadataList); */
|
|
||||||
void
|
void
|
||||||
CreateReplicationSlots(MultiConnection *sourceNodeConnection,
|
CreateReplicationSlots(MultiConnection *sourceNodeConnection, char *templateSlotName,
|
||||||
List *shardSplitSubscriberMetadataList)
|
List *shardSplitSubscriberMetadataList)
|
||||||
{
|
{
|
||||||
ShardSplitSubscriberMetadata *subscriberMetadata = NULL;
|
ShardSplitSubscriberMetadata *subscriberMetadata = NULL;
|
||||||
|
@ -580,10 +382,9 @@ CreateReplicationSlots(MultiConnection *sourceNodeConnection,
|
||||||
|
|
||||||
StringInfo createReplicationSlotCommand = makeStringInfo();
|
StringInfo createReplicationSlotCommand = makeStringInfo();
|
||||||
|
|
||||||
/* TODO(niupre): Replace pgoutput with an appropriate name (to e introduced in by saawasek's PR) */
|
|
||||||
appendStringInfo(createReplicationSlotCommand,
|
appendStringInfo(createReplicationSlotCommand,
|
||||||
"SELECT * FROM pg_create_logical_replication_slot('%s','citus', false)",
|
"SELECT * FROM pg_copy_logical_replication_slot ('%s','%s')",
|
||||||
slotName);
|
templateSlotName, slotName);
|
||||||
|
|
||||||
PGresult *result = NULL;
|
PGresult *result = NULL;
|
||||||
int response = ExecuteOptionalRemoteCommand(sourceNodeConnection,
|
int response = ExecuteOptionalRemoteCommand(sourceNodeConnection,
|
||||||
|
@ -598,3 +399,243 @@ CreateReplicationSlots(MultiConnection *sourceNodeConnection,
|
||||||
ForgetResults(sourceNodeConnection);
|
ForgetResults(sourceNodeConnection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ShardSplitTemplateReplicationSlotName returns name of template replication slot.
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
ShardSplitTemplateReplicationSlotName(uint64 shardId)
|
||||||
|
{
|
||||||
|
return psprintf("%s%lu", SHARD_SPLIT_TEMPLATE_REPLICATION_SLOT_PREFIX, shardId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ParseReplicationSlotInfoFromResult parses custom datatype 'replication_slot_info'.
|
||||||
|
* 'replication_slot_info' is a tuple with below format:
|
||||||
|
* <targetNodeId, tableOwnerName, replicationSlotName>
|
||||||
|
*/
|
||||||
|
List *
|
||||||
|
ParseReplicationSlotInfoFromResult(PGresult *result)
|
||||||
|
{
|
||||||
|
int64 rowCount = PQntuples(result);
|
||||||
|
int64 colCount = PQnfields(result);
|
||||||
|
|
||||||
|
List *replicationSlotInfoList = NIL;
|
||||||
|
for (int64 rowIndex = 0; rowIndex < rowCount; rowIndex++)
|
||||||
|
{
|
||||||
|
ReplicationSlotInfo *replicationSlotInfo = (ReplicationSlotInfo *) palloc0(
|
||||||
|
sizeof(ReplicationSlotInfo));
|
||||||
|
|
||||||
|
char *targeNodeIdString = PQgetvalue(result, rowIndex, 0 /* nodeId column*/);
|
||||||
|
|
||||||
|
replicationSlotInfo->targetNodeId = strtoul(targeNodeIdString, NULL, 10);
|
||||||
|
|
||||||
|
/* We're using the pstrdup to copy the data into the current memory context */
|
||||||
|
replicationSlotInfo->tableOwnerName = pstrdup(PQgetvalue(result, rowIndex,
|
||||||
|
1 /* table owner name column */));
|
||||||
|
|
||||||
|
/* Replication slot name */
|
||||||
|
replicationSlotInfo->slotName = pstrdup(PQgetvalue(result, rowIndex,
|
||||||
|
2 /* slot name column */));
|
||||||
|
|
||||||
|
replicationSlotInfoList = lappend(replicationSlotInfoList, replicationSlotInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return replicationSlotInfoList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DropAllShardSplitLeftOvers drops shard split subscriptions, publications, roles
|
||||||
|
* and replication slots on all nodes. These might have been left there after
|
||||||
|
* the coordinator crashed during a shard split. It's important to delete them
|
||||||
|
* for two reasons:
|
||||||
|
* 1. Starting new shard split might fail when they exist, because it cannot
|
||||||
|
* create them.
|
||||||
|
* 2. Leftover replication slots that are not consumed from anymore make it
|
||||||
|
* impossible for WAL to be dropped. This can cause out-of-disk issues.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
DropAllShardSplitLeftOvers(WorkerNode *sourceNode, HTAB *shardSplitHashMapForPubSub)
|
||||||
|
{
|
||||||
|
char *superUser = CitusExtensionOwnerName();
|
||||||
|
char *databaseName = get_database_name(MyDatabaseId);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We open new connections to all nodes. The reason for this is that
|
||||||
|
* operations on subscriptions and publications cannot be run in a
|
||||||
|
* transaction. By forcing a new connection we make sure no transaction is
|
||||||
|
* active on the connection.
|
||||||
|
*/
|
||||||
|
int connectionFlags = FORCE_NEW_CONNECTION;
|
||||||
|
|
||||||
|
HASH_SEQ_STATUS statusForSubscription;
|
||||||
|
hash_seq_init(&statusForSubscription, shardSplitHashMapForPubSub);
|
||||||
|
|
||||||
|
NodeShardMappingEntry *entry = NULL;
|
||||||
|
while ((entry = (NodeShardMappingEntry *) hash_seq_search(&statusForSubscription)) !=
|
||||||
|
NULL)
|
||||||
|
{
|
||||||
|
uint32_t nodeId = entry->key.nodeId;
|
||||||
|
WorkerNode *workerNode = FindNodeWithNodeId(nodeId, false /*missingOk*/);
|
||||||
|
|
||||||
|
MultiConnection *cleanupConnection = GetNodeUserDatabaseConnection(
|
||||||
|
connectionFlags, workerNode->workerName, workerNode->workerPort,
|
||||||
|
superUser, databaseName);
|
||||||
|
|
||||||
|
/* We need to claim the connection exclusively while dropping the subscription */
|
||||||
|
ClaimConnectionExclusively(cleanupConnection);
|
||||||
|
|
||||||
|
DropAllShardSplitSubscriptions(cleanupConnection);
|
||||||
|
DropAllShardSplitUsers(cleanupConnection);
|
||||||
|
|
||||||
|
/* Close connection after cleanup */
|
||||||
|
CloseConnection(cleanupConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Drop all shard split publications at the source*/
|
||||||
|
MultiConnection *sourceNodeConnection = GetNodeUserDatabaseConnection(
|
||||||
|
connectionFlags, sourceNode->workerName, sourceNode->workerPort,
|
||||||
|
superUser, databaseName);
|
||||||
|
|
||||||
|
ClaimConnectionExclusively(sourceNodeConnection);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If replication slot could not be dropped while dropping the
|
||||||
|
* subscriber, drop it here.
|
||||||
|
*/
|
||||||
|
DropAllShardSplitReplicationSlots(sourceNodeConnection);
|
||||||
|
DropAllShardSplitPublications(sourceNodeConnection);
|
||||||
|
|
||||||
|
CloseConnection(sourceNodeConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DropAllShardSplitSubscriptions(MultiConnection *cleanupConnection)
|
||||||
|
{
|
||||||
|
char *query = psprintf(
|
||||||
|
"SELECT subname FROM pg_subscription "
|
||||||
|
"WHERE subname LIKE %s || '%%'",
|
||||||
|
quote_literal_cstr(SHARD_SPLIT_SUBSCRIPTION_PREFIX));
|
||||||
|
List *subscriptionNameList = GetQueryResultStringList(cleanupConnection, query);
|
||||||
|
char *subscriptionName = NULL;
|
||||||
|
foreach_ptr(subscriptionName, subscriptionNameList)
|
||||||
|
{
|
||||||
|
DropShardSubscription(cleanupConnection, subscriptionName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
DropAllShardSplitPublications(MultiConnection *connection)
|
||||||
|
{
|
||||||
|
char *query = psprintf(
|
||||||
|
"SELECT pubname FROM pg_publication "
|
||||||
|
"WHERE pubname LIKE %s || '%%'",
|
||||||
|
quote_literal_cstr(SHARD_SPLIT_PUBLICATION_PREFIX));
|
||||||
|
List *publicationNameList = GetQueryResultStringList(connection, query);
|
||||||
|
char *publicationName;
|
||||||
|
foreach_ptr(publicationName, publicationNameList)
|
||||||
|
{
|
||||||
|
DropShardPublication(connection, publicationName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
DropAllShardSplitUsers(MultiConnection *connection)
|
||||||
|
{
|
||||||
|
char *query = psprintf(
|
||||||
|
"SELECT rolname FROM pg_roles "
|
||||||
|
"WHERE rolname LIKE %s || '%%'",
|
||||||
|
quote_literal_cstr(SHARD_SPLIT_SUBSCRIPTION_ROLE_PREFIX));
|
||||||
|
List *usernameList = GetQueryResultStringList(connection, query);
|
||||||
|
char *username;
|
||||||
|
foreach_ptr(username, usernameList)
|
||||||
|
{
|
||||||
|
DropShardUser(connection, username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
DropAllShardSplitReplicationSlots(MultiConnection *cleanupConnection)
|
||||||
|
{
|
||||||
|
char *query = psprintf(
|
||||||
|
"SELECT slot_name FROM pg_replication_slots "
|
||||||
|
"WHERE slot_name LIKE %s || '%%'",
|
||||||
|
quote_literal_cstr(SHARD_SPLIT_REPLICATION_SLOT_PREFIX));
|
||||||
|
List *slotNameList = GetQueryResultStringList(cleanupConnection, query);
|
||||||
|
char *slotName;
|
||||||
|
foreach_ptr(slotName, slotNameList)
|
||||||
|
{
|
||||||
|
DropShardMoveReplicationSlot(cleanupConnection, slotName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DropShardSplitPublications drops the publication used for shard splits over the given
|
||||||
|
* connection, if it exists.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
DropShardSplitPublications(MultiConnection *sourceConnection,
|
||||||
|
HTAB *shardInfoHashMapForPublication)
|
||||||
|
{
|
||||||
|
HASH_SEQ_STATUS status;
|
||||||
|
hash_seq_init(&status, shardInfoHashMapForPublication);
|
||||||
|
|
||||||
|
NodeShardMappingEntry *entry = NULL;
|
||||||
|
while ((entry = (NodeShardMappingEntry *) hash_seq_search(&status)) != NULL)
|
||||||
|
{
|
||||||
|
uint32 nodeId = entry->key.nodeId;
|
||||||
|
uint32 tableOwnerId = entry->key.tableOwnerId;
|
||||||
|
DropShardPublication(sourceConnection, ShardSplitPublicationName(nodeId,
|
||||||
|
tableOwnerId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DropShardSplitSubsriptions drops subscriptions from the subscriber node that
|
||||||
|
* are used to split shards for the given table owners. Note that, it drops the
|
||||||
|
* replication slots on the publisher node if it can drop the slots as well
|
||||||
|
* with the DROP SUBSCRIPTION command. Otherwise, only the subscriptions will
|
||||||
|
* be deleted with DROP SUBSCRIPTION via the connection. In the latter case,
|
||||||
|
* replication slots will be dropped separately by calling DropShardSplitReplicationSlots.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
DropShardSplitSubsriptions(List *shardSplitSubscribersMetadataList)
|
||||||
|
{
|
||||||
|
ShardSplitSubscriberMetadata *subscriberMetadata = NULL;
|
||||||
|
foreach_ptr(subscriberMetadata, shardSplitSubscribersMetadataList)
|
||||||
|
{
|
||||||
|
uint32 tableOwnerId = subscriberMetadata->tableOwnerId;
|
||||||
|
MultiConnection *targetNodeConnection = subscriberMetadata->targetNodeConnection;
|
||||||
|
|
||||||
|
DropShardSubscription(targetNodeConnection, ShardSubscriptionName(tableOwnerId,
|
||||||
|
SHARD_SPLIT_SUBSCRIPTION_PREFIX));
|
||||||
|
|
||||||
|
DropShardUser(targetNodeConnection, ShardSubscriptionRole(tableOwnerId,
|
||||||
|
SHARD_SPLIT_SUBSCRIPTION_ROLE_PREFIX));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CloseShardSplitSubscriberConnections closes connection of subscriber nodes.
|
||||||
|
* 'ShardSplitSubscriberMetadata' holds connection for a subscriber node. The method
|
||||||
|
* traverses the list and closes each connection.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
CloseShardSplitSubscriberConnections(List *shardSplitSubscriberMetadataList)
|
||||||
|
{
|
||||||
|
ShardSplitSubscriberMetadata *subscriberMetadata = NULL;
|
||||||
|
foreach_ptr(subscriberMetadata, shardSplitSubscriberMetadataList)
|
||||||
|
{
|
||||||
|
CloseConnection(subscriberMetadata->targetNodeConnection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "distributed/shardinterval_utils.h"
|
#include "distributed/shardinterval_utils.h"
|
||||||
#include "distributed/shardsplit_shared_memory.h"
|
#include "distributed/shardsplit_shared_memory.h"
|
||||||
#include "distributed/citus_safe_lib.h"
|
#include "distributed/citus_safe_lib.h"
|
||||||
|
#include "distributed/multi_logical_replication.h"
|
||||||
#include "storage/ipc.h"
|
#include "storage/ipc.h"
|
||||||
#include "utils/memutils.h"
|
#include "utils/memutils.h"
|
||||||
#include "common/hashfn.h"
|
#include "common/hashfn.h"
|
||||||
|
@ -199,7 +200,8 @@ encode_replication_slot(uint32_t nodeId,
|
||||||
uint32_t tableOwnerId)
|
uint32_t tableOwnerId)
|
||||||
{
|
{
|
||||||
StringInfo slotName = makeStringInfo();
|
StringInfo slotName = makeStringInfo();
|
||||||
appendStringInfo(slotName, "citus_split_%u_%u", nodeId, tableOwnerId);
|
appendStringInfo(slotName, "%s%u_%u", SHARD_SPLIT_REPLICATION_SLOT_PREFIX, nodeId,
|
||||||
|
tableOwnerId);
|
||||||
|
|
||||||
if (slotName->len > NAMEDATALEN)
|
if (slotName->len > NAMEDATALEN)
|
||||||
{
|
{
|
||||||
|
|
|
@ -34,7 +34,12 @@ extern void DropShardSubscription(MultiConnection *connection,
|
||||||
extern void DropShardPublication(MultiConnection *connection, char *publicationName);
|
extern void DropShardPublication(MultiConnection *connection, char *publicationName);
|
||||||
|
|
||||||
extern void DropShardUser(MultiConnection *connection, char *username);
|
extern void DropShardUser(MultiConnection *connection, char *username);
|
||||||
|
extern void DropShardMoveReplicationSlot(MultiConnection *connection,
|
||||||
|
char *publicationName);
|
||||||
|
|
||||||
|
|
||||||
|
extern char * ShardSubscriptionRole(Oid ownerId, char *operationPrefix);
|
||||||
|
extern char * ShardSubscriptionName(Oid ownerId, char *operationPrefix);
|
||||||
extern void CreateShardSubscription(MultiConnection *connection, char *sourceNodeName,
|
extern void CreateShardSubscription(MultiConnection *connection, char *sourceNodeName,
|
||||||
int sourceNodePort, char *userName,
|
int sourceNodePort, char *userName,
|
||||||
char *databaseName,
|
char *databaseName,
|
||||||
|
@ -50,9 +55,11 @@ extern void WaitForShardSubscriptionToCatchUp(MultiConnection *targetConnection,
|
||||||
char *operationPrefix);
|
char *operationPrefix);
|
||||||
|
|
||||||
#define SHARD_MOVE_PUBLICATION_PREFIX "citus_shard_move_publication_"
|
#define SHARD_MOVE_PUBLICATION_PREFIX "citus_shard_move_publication_"
|
||||||
#define SHARD_MOVE_SUBSCRIPTION_PREFIX "citus_shard_move_subscription_"
|
|
||||||
#define SHARD_MOVE_SUBSCRIPTION_ROLE_PREFIX "citus_shard_move_subscription_role_"
|
#define SHARD_MOVE_SUBSCRIPTION_ROLE_PREFIX "citus_shard_move_subscription_role_"
|
||||||
|
#define SHARD_MOVE_SUBSCRIPTION_PREFIX "citus_shard_move_subscription_"
|
||||||
#define SHARD_SPLIT_PUBLICATION_PREFIX "citus_shard_split_publication_"
|
#define SHARD_SPLIT_PUBLICATION_PREFIX "citus_shard_split_publication_"
|
||||||
#define SHARD_SPLIT_SUBSCRIPTION_PREFIX "citus_shard_split_subscription_"
|
#define SHARD_SPLIT_SUBSCRIPTION_PREFIX "citus_shard_split_subscription_"
|
||||||
#define SHARD_SPLIT_SUBSCRIPTION_ROLE_PREFIX "citus_shard_split_subscription_role_"
|
#define SHARD_SPLIT_SUBSCRIPTION_ROLE_PREFIX "citus_shard_split_subscription_role_"
|
||||||
|
#define SHARD_SPLIT_TEMPLATE_REPLICATION_SLOT_PREFIX "citus_shard_split_template_slot_"
|
||||||
|
#define SHARD_SPLIT_REPLICATION_SLOT_PREFIX "citus_shard_split_"
|
||||||
#endif /* MULTI_LOGICAL_REPLICATION_H_ */
|
#endif /* MULTI_LOGICAL_REPLICATION_H_ */
|
||||||
|
|
|
@ -59,8 +59,6 @@ extern void SplitShard(SplitMode splitMode,
|
||||||
/* TODO(niupre): Make all these APIs private when all consumers (Example : ISOLATE_TENANT_TO_NEW_SHARD) directly call 'SplitShard' API. */
|
/* TODO(niupre): Make all these APIs private when all consumers (Example : ISOLATE_TENANT_TO_NEW_SHARD) directly call 'SplitShard' API. */
|
||||||
extern void ErrorIfCannotSplitShard(SplitOperation splitOperation,
|
extern void ErrorIfCannotSplitShard(SplitOperation splitOperation,
|
||||||
ShardInterval *sourceShard);
|
ShardInterval *sourceShard);
|
||||||
extern void CreateAuxiliaryStructuresForShardGroup(List *shardGroupSplitIntervalListList,
|
|
||||||
List *workersForPlacementList);
|
|
||||||
extern void DropShardList(List *shardIntervalList);
|
extern void DropShardList(List *shardIntervalList);
|
||||||
|
|
||||||
#endif /* SHARDSPLIT_H_ */
|
#endif /* SHARDSPLIT_H_ */
|
||||||
|
|
|
@ -12,6 +12,12 @@
|
||||||
|
|
||||||
#include "distributed/multi_logical_replication.h"
|
#include "distributed/multi_logical_replication.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Invocation of 'worker_split_shard_replication_setup' UDF returns set of records
|
||||||
|
* of custom datatype 'replication_slot_info'. This information is parsed and stored in
|
||||||
|
* the below data structure. The information is used to create a subscriber on target node
|
||||||
|
* with corresponding slot name.
|
||||||
|
*/
|
||||||
typedef struct ReplicationSlotInfo
|
typedef struct ReplicationSlotInfo
|
||||||
{
|
{
|
||||||
uint32 targetNodeId;
|
uint32 targetNodeId;
|
||||||
|
@ -19,13 +25,18 @@ typedef struct ReplicationSlotInfo
|
||||||
char *slotName;
|
char *slotName;
|
||||||
} ReplicationSlotInfo;
|
} ReplicationSlotInfo;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stores information necesary for creating a subscriber on target node.
|
||||||
|
* Based on how a shard is split and mapped to target nodes, for each unique combination of
|
||||||
|
* <tableOwner, targetNodeId> there is a 'ShardSplitSubscriberMetadata'.
|
||||||
|
*/
|
||||||
typedef struct ShardSplitSubscriberMetadata
|
typedef struct ShardSplitSubscriberMetadata
|
||||||
{
|
{
|
||||||
Oid tableOwnerId;
|
Oid tableOwnerId;
|
||||||
ReplicationSlotInfo *slotInfo;
|
ReplicationSlotInfo *slotInfo;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Exclusively claimed connection for subscription.The target node of subscription
|
* Exclusively claimed connection for a subscription.The target node of subscription
|
||||||
* is pointed by ReplicationSlotInfo.
|
* is pointed by ReplicationSlotInfo.
|
||||||
*/
|
*/
|
||||||
MultiConnection *targetNodeConnection;
|
MultiConnection *targetNodeConnection;
|
||||||
|
@ -47,52 +58,52 @@ typedef struct NodeShardMappingEntry
|
||||||
|
|
||||||
extern uint32 NodeShardMappingHash(const void *key, Size keysize);
|
extern uint32 NodeShardMappingHash(const void *key, Size keysize);
|
||||||
extern int NodeShardMappingHashCompare(const void *left, const void *right, Size keysize);
|
extern int NodeShardMappingHashCompare(const void *left, const void *right, Size keysize);
|
||||||
HTAB * SetupHashMapForShardInfo(void);
|
extern HTAB * SetupHashMapForShardInfo(void);
|
||||||
|
|
||||||
|
/* Functions for subscriber metadata management */
|
||||||
extern List * ParseReplicationSlotInfoFromResult(PGresult *result);
|
extern List * ParseReplicationSlotInfoFromResult(PGresult *result);
|
||||||
|
extern List * PopulateShardSplitSubscriptionsMetadataList(HTAB *shardSplitInfoHashMap,
|
||||||
|
List *replicationSlotInfoList);
|
||||||
extern HTAB * CreateShardSplitInfoMapForPublication(
|
extern HTAB * CreateShardSplitInfoMapForPublication(
|
||||||
List *sourceColocatedShardIntervalList,
|
List *sourceColocatedShardIntervalList,
|
||||||
List *shardGroupSplitIntervalListList,
|
List *shardGroupSplitIntervalListList,
|
||||||
List *destinationWorkerNodesList);
|
List *destinationWorkerNodesList);
|
||||||
|
|
||||||
extern void LogicallyReplicateSplitShards(WorkerNode *sourceWorkerNode,
|
/* Functions for creating publications and subscriptions*/
|
||||||
List *shardSplitPubSubMetadataList,
|
|
||||||
List *sourceColocatedShardIntervalList,
|
|
||||||
List *shardGroupSplitIntervalListList,
|
|
||||||
List *destinationWorkerNodesList);
|
|
||||||
extern void CreateShardSplitPublications(MultiConnection *sourceConnection,
|
extern void CreateShardSplitPublications(MultiConnection *sourceConnection,
|
||||||
HTAB *shardInfoHashMapForPublication);
|
HTAB *shardInfoHashMapForPublication);
|
||||||
|
extern void CreateShardSplitSubscriptions(List *targetNodeConnectionList,
|
||||||
|
List *shardSplitPubSubMetadataList,
|
||||||
|
WorkerNode *sourceWorkerNode, char *superUser,
|
||||||
|
char *databaseName);
|
||||||
|
extern void CreateReplicationSlots(MultiConnection *sourceNodeConnection,
|
||||||
|
char *templateSlotName,
|
||||||
|
List *shardSplitSubscriberMetadataList);
|
||||||
|
extern List * CreateTargetNodeConnectionsForShardSplit(
|
||||||
|
List *shardSplitSubscribersMetadataList,
|
||||||
|
int
|
||||||
|
connectionFlags, char *user,
|
||||||
|
char *databaseName);
|
||||||
|
|
||||||
|
/* Functions to drop publisher-subscriber resources */
|
||||||
extern void DropAllShardSplitLeftOvers(WorkerNode *sourceNode,
|
extern void DropAllShardSplitLeftOvers(WorkerNode *sourceNode,
|
||||||
HTAB *shardSplitMapOfPublications);
|
HTAB *shardSplitMapOfPublications);
|
||||||
|
extern void DropShardSplitPublications(MultiConnection *sourceConnection,
|
||||||
extern List * PopulateShardSplitSubscriptionsMetadataList(HTAB *shardSplitInfoHashMap,
|
HTAB *shardInfoHashMapForPublication);
|
||||||
List *replicationSlotInfoList);
|
extern void DropShardSplitSubsriptions(List *shardSplitSubscribersMetadataList);
|
||||||
|
|
||||||
extern char * DropExistingIfAnyAndCreateTemplateReplicationSlot(
|
extern char * DropExistingIfAnyAndCreateTemplateReplicationSlot(
|
||||||
ShardInterval *shardIntervalToSplit,
|
ShardInterval *shardIntervalToSplit,
|
||||||
MultiConnection *
|
MultiConnection *
|
||||||
sourceConnection);
|
sourceConnection);
|
||||||
|
|
||||||
extern void CreateShardSplitSubscriptions(List *targetNodeConnectionList,
|
/* Wrapper functions which wait for a subscriber to be ready and catchup */
|
||||||
List *shardSplitPubSubMetadataList,
|
|
||||||
WorkerNode *sourceWorkerNode, char *superUser,
|
|
||||||
char *databaseName);
|
|
||||||
extern void WaitForShardSplitRelationSubscriptionsBecomeReady(
|
extern void WaitForShardSplitRelationSubscriptionsBecomeReady(
|
||||||
List *shardSplitPubSubMetadataList);
|
List *shardSplitPubSubMetadataList);
|
||||||
extern void WaitForShardSplitRelationSubscriptionsToBeCaughtUp(XLogRecPtr sourcePosition,
|
extern void WaitForShardSplitRelationSubscriptionsToBeCaughtUp(XLogRecPtr sourcePosition,
|
||||||
List *
|
List *
|
||||||
shardSplitPubSubMetadataList);
|
shardSplitPubSubMetadataList);
|
||||||
|
|
||||||
List * CreateTargetNodeConnectionsForShardSplit(List *shardSplitSubscribersMetadataList,
|
extern char * ShardSplitTemplateReplicationSlotName(uint64 shardId);
|
||||||
int
|
|
||||||
connectionFlags, char *user,
|
|
||||||
char *databaseName);
|
|
||||||
extern void CreateReplicationSlots(MultiConnection *sourceNodeConnection,
|
|
||||||
List *shardSplitSubscriberMetadataList);
|
|
||||||
|
|
||||||
/*used for debuggin. Remove later*/
|
extern void CloseShardSplitSubscriberConnections(List *shardSplitSubscriberMetadataList);
|
||||||
extern void PrintShardSplitPubSubMetadata(
|
|
||||||
ShardSplitSubscriberMetadata *shardSplitMetadata);
|
|
||||||
#endif /* SHARDSPLIT_LOGICAL_REPLICATION_H */
|
#endif /* SHARDSPLIT_LOGICAL_REPLICATION_H */
|
||||||
|
|
|
@ -0,0 +1,465 @@
|
||||||
|
/*
|
||||||
|
Citus Shard Split Test.The test is model similar to 'shard_move_constraints'.
|
||||||
|
Here is a high level overview of test plan:
|
||||||
|
1. Create a table 'sensors' (ShardCount = 2) to be split. Add indexes and statistics on this table.
|
||||||
|
2. Create two other tables: 'reference_table' and 'colocated_dist_table', co-located with sensors.
|
||||||
|
3. Create Foreign key constraints between the two co-located distributed tables.
|
||||||
|
4. Load data into the three tables.
|
||||||
|
5. Move one of the shards for 'sensors' to test ShardMove -> Split.
|
||||||
|
6. Trigger Split on both shards of 'sensors'. This will also split co-located tables.
|
||||||
|
7. Move one of the split shard to test Split -> ShardMove.
|
||||||
|
8. Split an already split shard second time on a different schema.
|
||||||
|
*/
|
||||||
|
CREATE SCHEMA "citus_split_test_schema";
|
||||||
|
CREATE ROLE test_split_role WITH LOGIN;
|
||||||
|
GRANT USAGE, CREATE ON SCHEMA "citus_split_test_schema" TO test_split_role;
|
||||||
|
SET ROLE test_split_role;
|
||||||
|
SET search_path TO "citus_split_test_schema";
|
||||||
|
SET citus.next_shard_id TO 8981000;
|
||||||
|
SET citus.next_placement_id TO 8610000;
|
||||||
|
SET citus.shard_count TO 2;
|
||||||
|
SET citus.shard_replication_factor TO 1;
|
||||||
|
-- BEGIN: Create table to split, along with other co-located tables. Add indexes, statistics etc.
|
||||||
|
CREATE TABLE sensors(
|
||||||
|
measureid integer,
|
||||||
|
eventdatetime date,
|
||||||
|
measure_data jsonb,
|
||||||
|
meaure_quantity decimal(15, 2),
|
||||||
|
measure_status char(1),
|
||||||
|
measure_comment varchar(44),
|
||||||
|
PRIMARY KEY (measureid, eventdatetime, measure_data));
|
||||||
|
CREATE INDEX index_on_sensors ON sensors(lower(measureid::text));
|
||||||
|
ALTER INDEX index_on_sensors ALTER COLUMN 1 SET STATISTICS 1000;
|
||||||
|
CREATE INDEX hash_index_on_sensors ON sensors USING HASH((measure_data->'IsFailed'));
|
||||||
|
CREATE INDEX index_with_include_on_sensors ON sensors ((measure_data->'IsFailed')) INCLUDE (measure_data, eventdatetime, measure_status);
|
||||||
|
CREATE STATISTICS stats_on_sensors (dependencies) ON measureid, eventdatetime FROM sensors;
|
||||||
|
SELECT create_distributed_table('sensors', 'measureid', colocate_with:='none');
|
||||||
|
create_distributed_table
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- END: Create table to split, along with other co-located tables. Add indexes, statistics etc.
|
||||||
|
-- BEGIN: Create co-located distributed and reference tables.
|
||||||
|
CREATE TABLE reference_table (measureid integer PRIMARY KEY);
|
||||||
|
SELECT create_reference_table('reference_table');
|
||||||
|
create_reference_table
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
CREATE TABLE colocated_dist_table (measureid integer PRIMARY KEY);
|
||||||
|
CLUSTER colocated_dist_table USING colocated_dist_table_pkey;
|
||||||
|
SELECT create_distributed_table('colocated_dist_table', 'measureid', colocate_with:='sensors');
|
||||||
|
create_distributed_table
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
CREATE TABLE table_with_index_rep_identity(key int NOT NULL);
|
||||||
|
CREATE UNIQUE INDEX uqx ON table_with_index_rep_identity(key);
|
||||||
|
ALTER TABLE table_with_index_rep_identity REPLICA IDENTITY USING INDEX uqx;
|
||||||
|
CLUSTER table_with_index_rep_identity USING uqx;
|
||||||
|
SELECT create_distributed_table('table_with_index_rep_identity', 'key', colocate_with:='sensors');
|
||||||
|
create_distributed_table
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- END: Create co-located distributed and reference tables.
|
||||||
|
-- BEGIN : Create Foreign key constraints.
|
||||||
|
ALTER TABLE sensors ADD CONSTRAINT fkey_table_to_dist FOREIGN KEY (measureid) REFERENCES colocated_dist_table(measureid);
|
||||||
|
-- END : Create Foreign key constraints.
|
||||||
|
-- BEGIN : Load data into tables.
|
||||||
|
INSERT INTO reference_table SELECT i FROM generate_series(0,1000)i;
|
||||||
|
INSERT INTO colocated_dist_table SELECT i FROM generate_series(0,1000)i;
|
||||||
|
INSERT INTO sensors SELECT i, '2020-01-05', '{}', 11011.10, 'A', 'I <3 Citus' FROM generate_series(0,1000)i;
|
||||||
|
SELECT COUNT(*) FROM sensors;
|
||||||
|
count
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
1001
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT COUNT(*) FROM reference_table;
|
||||||
|
count
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
1001
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT COUNT(*) FROM colocated_dist_table;
|
||||||
|
count
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
1001
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- END: Load data into tables.
|
||||||
|
-- BEGIN : Display current state.
|
||||||
|
SELECT shard.shardid, logicalrelid, shardminvalue, shardmaxvalue, nodename, nodeport
|
||||||
|
FROM pg_dist_shard AS shard
|
||||||
|
INNER JOIN pg_dist_placement placement ON shard.shardid = placement.shardid
|
||||||
|
INNER JOIN pg_dist_node node ON placement.groupid = node.groupid
|
||||||
|
INNER JOIN pg_catalog.pg_class cls ON shard.logicalrelid = cls.oid
|
||||||
|
WHERE node.noderole = 'primary' AND (logicalrelid = 'sensors'::regclass OR logicalrelid = 'colocated_dist_table'::regclass OR logicalrelid = 'table_with_index_rep_identity'::regclass)
|
||||||
|
ORDER BY logicalrelid, shardminvalue::BIGINT;
|
||||||
|
shardid | logicalrelid | shardminvalue | shardmaxvalue | nodename | nodeport
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
8981000 | sensors | -2147483648 | -1 | localhost | 57637
|
||||||
|
8981001 | sensors | 0 | 2147483647 | localhost | 57638
|
||||||
|
8981003 | colocated_dist_table | -2147483648 | -1 | localhost | 57637
|
||||||
|
8981004 | colocated_dist_table | 0 | 2147483647 | localhost | 57638
|
||||||
|
8981005 | table_with_index_rep_identity | -2147483648 | -1 | localhost | 57637
|
||||||
|
8981006 | table_with_index_rep_identity | 0 | 2147483647 | localhost | 57638
|
||||||
|
(6 rows)
|
||||||
|
|
||||||
|
\c - - - :worker_1_port
|
||||||
|
SET search_path TO "citus_split_test_schema", public, pg_catalog;
|
||||||
|
SET citus.show_shards_for_app_name_prefixes = '*';
|
||||||
|
SELECT tbl.relname, fk."Constraint", fk."Definition"
|
||||||
|
FROM pg_catalog.pg_class tbl
|
||||||
|
JOIN public.table_fkeys fk on tbl.oid = fk.relid
|
||||||
|
WHERE tbl.relname like 'sensors_%'
|
||||||
|
ORDER BY 1, 2;
|
||||||
|
relname | Constraint | Definition
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
sensors_8981000 | fkey_table_to_dist_8981000 | FOREIGN KEY (measureid) REFERENCES colocated_dist_table_8981003(measureid)
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT tablename, indexdef FROM pg_indexes WHERE tablename like 'sensors_%' ORDER BY 1,2;
|
||||||
|
tablename | indexdef
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
sensors_8981000 | CREATE INDEX hash_index_on_sensors_8981000 ON citus_split_test_schema.sensors_8981000 USING hash (((measure_data -> 'IsFailed'::text)))
|
||||||
|
sensors_8981000 | CREATE INDEX index_on_sensors_8981000 ON citus_split_test_schema.sensors_8981000 USING btree (lower((measureid)::text))
|
||||||
|
sensors_8981000 | CREATE INDEX index_with_include_on_sensors_8981000 ON citus_split_test_schema.sensors_8981000 USING btree (((measure_data -> 'IsFailed'::text))) INCLUDE (measure_data, eventdatetime, measure_status)
|
||||||
|
sensors_8981000 | CREATE UNIQUE INDEX sensors_pkey_8981000 ON citus_split_test_schema.sensors_8981000 USING btree (measureid, eventdatetime, measure_data)
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
|
SELECT tablename, indexdef FROM pg_indexes WHERE tablename like 'table_with_index_rep_identity_%' ORDER BY 1,2;
|
||||||
|
tablename | indexdef
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
table_with_index_rep_identity_8981005 | CREATE UNIQUE INDEX uqx_8981005 ON citus_split_test_schema.table_with_index_rep_identity_8981005 USING btree (key)
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT stxname FROM pg_statistic_ext
|
||||||
|
WHERE stxnamespace IN (
|
||||||
|
SELECT oid
|
||||||
|
FROM pg_namespace
|
||||||
|
WHERE nspname IN ('citus_split_test_schema')
|
||||||
|
)
|
||||||
|
ORDER BY stxname ASC;
|
||||||
|
stxname
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
stats_on_sensors
|
||||||
|
stats_on_sensors_8981000
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
\c - - - :worker_2_port
|
||||||
|
SET search_path TO "citus_split_test_schema", public, pg_catalog;
|
||||||
|
SET citus.show_shards_for_app_name_prefixes = '*';
|
||||||
|
SELECT tbl.relname, fk."Constraint", fk."Definition"
|
||||||
|
FROM pg_catalog.pg_class tbl
|
||||||
|
JOIN public.table_fkeys fk on tbl.oid = fk.relid
|
||||||
|
WHERE tbl.relname like 'sensors_%'
|
||||||
|
ORDER BY 1, 2;
|
||||||
|
relname | Constraint | Definition
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
sensors_8981001 | fkey_table_to_dist_8981001 | FOREIGN KEY (measureid) REFERENCES colocated_dist_table_8981004(measureid)
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT tablename, indexdef FROM pg_indexes WHERE tablename like 'sensors_%' ORDER BY 1,2;
|
||||||
|
tablename | indexdef
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
sensors_8981001 | CREATE INDEX hash_index_on_sensors_8981001 ON citus_split_test_schema.sensors_8981001 USING hash (((measure_data -> 'IsFailed'::text)))
|
||||||
|
sensors_8981001 | CREATE INDEX index_on_sensors_8981001 ON citus_split_test_schema.sensors_8981001 USING btree (lower((measureid)::text))
|
||||||
|
sensors_8981001 | CREATE INDEX index_with_include_on_sensors_8981001 ON citus_split_test_schema.sensors_8981001 USING btree (((measure_data -> 'IsFailed'::text))) INCLUDE (measure_data, eventdatetime, measure_status)
|
||||||
|
sensors_8981001 | CREATE UNIQUE INDEX sensors_pkey_8981001 ON citus_split_test_schema.sensors_8981001 USING btree (measureid, eventdatetime, measure_data)
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
|
SELECT tablename, indexdef FROM pg_indexes WHERE tablename like 'table_with_index_rep_identity_%' ORDER BY 1,2;
|
||||||
|
tablename | indexdef
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
table_with_index_rep_identity_8981006 | CREATE UNIQUE INDEX uqx_8981006 ON citus_split_test_schema.table_with_index_rep_identity_8981006 USING btree (key)
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT stxname FROM pg_statistic_ext
|
||||||
|
WHERE stxnamespace IN (
|
||||||
|
SELECT oid
|
||||||
|
FROM pg_namespace
|
||||||
|
WHERE nspname IN ('citus_split_test_schema')
|
||||||
|
)
|
||||||
|
ORDER BY stxname ASC;
|
||||||
|
stxname
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
stats_on_sensors
|
||||||
|
stats_on_sensors_8981001
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
-- END : Display current state
|
||||||
|
-- BEGIN : Move one shard before we split it.
|
||||||
|
\c - postgres - :master_port
|
||||||
|
SET ROLE test_split_role;
|
||||||
|
SET search_path TO "citus_split_test_schema";
|
||||||
|
SET citus.next_shard_id TO 8981007;
|
||||||
|
SET citus.defer_drop_after_shard_move TO OFF;
|
||||||
|
SELECT citus_move_shard_placement(8981000, 'localhost', :worker_1_port, 'localhost', :worker_2_port, shard_transfer_mode:='force_logical');
|
||||||
|
citus_move_shard_placement
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- END : Move one shard before we split it.
|
||||||
|
-- BEGIN : Set node id variables
|
||||||
|
SELECT nodeid AS worker_1_node FROM pg_dist_node WHERE nodeport=:worker_1_port \gset
|
||||||
|
SELECT nodeid AS worker_2_node FROM pg_dist_node WHERE nodeport=:worker_2_port \gset
|
||||||
|
-- END : Set node id variables
|
||||||
|
-- BEGIN : Split two shards : One with move and One without move.
|
||||||
|
-- Perform 2 way split
|
||||||
|
SELECT pg_catalog.citus_split_shard_by_split_points(
|
||||||
|
8981000,
|
||||||
|
ARRAY['-1073741824'],
|
||||||
|
ARRAY[:worker_1_node, :worker_2_node],
|
||||||
|
'force_logical');
|
||||||
|
WARNING: replication slot "citus_shard_split_template_slot_8981000" does not exist
|
||||||
|
CONTEXT: while executing command on localhost:xxxxx
|
||||||
|
citus_split_shard_by_split_points
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- Perform 3 way split
|
||||||
|
SELECT pg_catalog.citus_split_shard_by_split_points(
|
||||||
|
8981001,
|
||||||
|
ARRAY['536870911', '1610612735'],
|
||||||
|
ARRAY[:worker_1_node, :worker_1_node, :worker_2_node],
|
||||||
|
'force_logical');
|
||||||
|
WARNING: replication slot "citus_shard_split_template_slot_8981001" does not exist
|
||||||
|
CONTEXT: while executing command on localhost:xxxxx
|
||||||
|
citus_split_shard_by_split_points
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- END : Split two shards : One with move and One without move.
|
||||||
|
-- BEGIN : Move a shard post split.
|
||||||
|
SELECT citus_move_shard_placement(8981007, 'localhost', :worker_1_port, 'localhost', :worker_2_port, shard_transfer_mode:='block_writes');
|
||||||
|
citus_move_shard_placement
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- END : Move a shard post split.
|
||||||
|
-- BEGIN : Display current state.
|
||||||
|
SELECT shard.shardid, logicalrelid, shardminvalue, shardmaxvalue, nodename, nodeport
|
||||||
|
FROM pg_dist_shard AS shard
|
||||||
|
INNER JOIN pg_dist_placement placement ON shard.shardid = placement.shardid
|
||||||
|
INNER JOIN pg_dist_node node ON placement.groupid = node.groupid
|
||||||
|
INNER JOIN pg_catalog.pg_class cls ON shard.logicalrelid = cls.oid
|
||||||
|
WHERE node.noderole = 'primary' AND (logicalrelid = 'sensors'::regclass OR logicalrelid = 'colocated_dist_table'::regclass OR logicalrelid = 'table_with_index_rep_identity'::regclass)
|
||||||
|
ORDER BY logicalrelid, shardminvalue::BIGINT;
|
||||||
|
shardid | logicalrelid | shardminvalue | shardmaxvalue | nodename | nodeport
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
8981007 | sensors | -2147483648 | -1073741824 | localhost | 57638
|
||||||
|
8981008 | sensors | -1073741823 | -1 | localhost | 57638
|
||||||
|
8981013 | sensors | 0 | 536870911 | localhost | 57637
|
||||||
|
8981014 | sensors | 536870912 | 1610612735 | localhost | 57637
|
||||||
|
8981015 | sensors | 1610612736 | 2147483647 | localhost | 57638
|
||||||
|
8981009 | colocated_dist_table | -2147483648 | -1073741824 | localhost | 57638
|
||||||
|
8981010 | colocated_dist_table | -1073741823 | -1 | localhost | 57638
|
||||||
|
8981016 | colocated_dist_table | 0 | 536870911 | localhost | 57637
|
||||||
|
8981017 | colocated_dist_table | 536870912 | 1610612735 | localhost | 57637
|
||||||
|
8981018 | colocated_dist_table | 1610612736 | 2147483647 | localhost | 57638
|
||||||
|
8981011 | table_with_index_rep_identity | -2147483648 | -1073741824 | localhost | 57638
|
||||||
|
8981012 | table_with_index_rep_identity | -1073741823 | -1 | localhost | 57638
|
||||||
|
8981019 | table_with_index_rep_identity | 0 | 536870911 | localhost | 57637
|
||||||
|
8981020 | table_with_index_rep_identity | 536870912 | 1610612735 | localhost | 57637
|
||||||
|
8981021 | table_with_index_rep_identity | 1610612736 | 2147483647 | localhost | 57638
|
||||||
|
(15 rows)
|
||||||
|
|
||||||
|
\c - - - :worker_1_port
|
||||||
|
SET search_path TO "citus_split_test_schema", public, pg_catalog;
|
||||||
|
SET citus.show_shards_for_app_name_prefixes = '*';
|
||||||
|
SELECT tbl.relname, fk."Constraint", fk."Definition"
|
||||||
|
FROM pg_catalog.pg_class tbl
|
||||||
|
JOIN public.table_fkeys fk on tbl.oid = fk.relid
|
||||||
|
WHERE tbl.relname like 'sensors_%'
|
||||||
|
ORDER BY 1, 2;
|
||||||
|
relname | Constraint | Definition
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
sensors_8981013 | fkey_table_to_dist_8981013 | FOREIGN KEY (measureid) REFERENCES colocated_dist_table_8981016(measureid)
|
||||||
|
sensors_8981014 | fkey_table_to_dist_8981014 | FOREIGN KEY (measureid) REFERENCES colocated_dist_table_8981017(measureid)
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
SELECT tablename, indexdef FROM pg_indexes WHERE tablename like 'sensors_%' ORDER BY 1,2;
|
||||||
|
tablename | indexdef
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
sensors_8981013 | CREATE INDEX hash_index_on_sensors_8981013 ON citus_split_test_schema.sensors_8981013 USING hash (((measure_data -> 'IsFailed'::text)))
|
||||||
|
sensors_8981013 | CREATE INDEX index_on_sensors_8981013 ON citus_split_test_schema.sensors_8981013 USING btree (lower((measureid)::text))
|
||||||
|
sensors_8981013 | CREATE INDEX index_with_include_on_sensors_8981013 ON citus_split_test_schema.sensors_8981013 USING btree (((measure_data -> 'IsFailed'::text))) INCLUDE (measure_data, eventdatetime, measure_status)
|
||||||
|
sensors_8981013 | CREATE UNIQUE INDEX sensors_pkey_8981013 ON citus_split_test_schema.sensors_8981013 USING btree (measureid, eventdatetime, measure_data)
|
||||||
|
sensors_8981014 | CREATE INDEX hash_index_on_sensors_8981014 ON citus_split_test_schema.sensors_8981014 USING hash (((measure_data -> 'IsFailed'::text)))
|
||||||
|
sensors_8981014 | CREATE INDEX index_on_sensors_8981014 ON citus_split_test_schema.sensors_8981014 USING btree (lower((measureid)::text))
|
||||||
|
sensors_8981014 | CREATE INDEX index_with_include_on_sensors_8981014 ON citus_split_test_schema.sensors_8981014 USING btree (((measure_data -> 'IsFailed'::text))) INCLUDE (measure_data, eventdatetime, measure_status)
|
||||||
|
sensors_8981014 | CREATE UNIQUE INDEX sensors_pkey_8981014 ON citus_split_test_schema.sensors_8981014 USING btree (measureid, eventdatetime, measure_data)
|
||||||
|
(8 rows)
|
||||||
|
|
||||||
|
SELECT tablename, indexdef FROM pg_indexes WHERE tablename like 'table_with_index_rep_identity_%' ORDER BY 1,2;
|
||||||
|
tablename | indexdef
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
table_with_index_rep_identity_8981019 | CREATE UNIQUE INDEX uqx_8981019 ON citus_split_test_schema.table_with_index_rep_identity_8981019 USING btree (key)
|
||||||
|
table_with_index_rep_identity_8981020 | CREATE UNIQUE INDEX uqx_8981020 ON citus_split_test_schema.table_with_index_rep_identity_8981020 USING btree (key)
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
SELECT stxname FROM pg_statistic_ext
|
||||||
|
WHERE stxnamespace IN (
|
||||||
|
SELECT oid
|
||||||
|
FROM pg_namespace
|
||||||
|
WHERE nspname IN ('citus_split_test_schema')
|
||||||
|
)
|
||||||
|
ORDER BY stxname ASC;
|
||||||
|
stxname
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
stats_on_sensors
|
||||||
|
stats_on_sensors_8981013
|
||||||
|
stats_on_sensors_8981014
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
\c - - - :worker_2_port
|
||||||
|
SET search_path TO "citus_split_test_schema", public, pg_catalog;
|
||||||
|
SET citus.show_shards_for_app_name_prefixes = '*';
|
||||||
|
SELECT tbl.relname, fk."Constraint", fk."Definition"
|
||||||
|
FROM pg_catalog.pg_class tbl
|
||||||
|
JOIN public.table_fkeys fk on tbl.oid = fk.relid
|
||||||
|
WHERE tbl.relname like 'sensors_%'
|
||||||
|
ORDER BY 1, 2;
|
||||||
|
relname | Constraint | Definition
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
sensors_8981007 | fkey_table_to_dist_8981007 | FOREIGN KEY (measureid) REFERENCES colocated_dist_table_8981009(measureid)
|
||||||
|
sensors_8981008 | fkey_table_to_dist_8981008 | FOREIGN KEY (measureid) REFERENCES colocated_dist_table_8981010(measureid)
|
||||||
|
sensors_8981015 | fkey_table_to_dist_8981015 | FOREIGN KEY (measureid) REFERENCES colocated_dist_table_8981018(measureid)
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
SELECT tablename, indexdef FROM pg_indexes WHERE tablename like 'sensors_%' ORDER BY 1,2;
|
||||||
|
tablename | indexdef
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
sensors_8981007 | CREATE INDEX hash_index_on_sensors_8981007 ON citus_split_test_schema.sensors_8981007 USING hash (((measure_data -> 'IsFailed'::text)))
|
||||||
|
sensors_8981007 | CREATE INDEX index_on_sensors_8981007 ON citus_split_test_schema.sensors_8981007 USING btree (lower((measureid)::text))
|
||||||
|
sensors_8981007 | CREATE INDEX index_with_include_on_sensors_8981007 ON citus_split_test_schema.sensors_8981007 USING btree (((measure_data -> 'IsFailed'::text))) INCLUDE (measure_data, eventdatetime, measure_status)
|
||||||
|
sensors_8981007 | CREATE UNIQUE INDEX sensors_pkey_8981007 ON citus_split_test_schema.sensors_8981007 USING btree (measureid, eventdatetime, measure_data)
|
||||||
|
sensors_8981008 | CREATE INDEX hash_index_on_sensors_8981008 ON citus_split_test_schema.sensors_8981008 USING hash (((measure_data -> 'IsFailed'::text)))
|
||||||
|
sensors_8981008 | CREATE INDEX index_on_sensors_8981008 ON citus_split_test_schema.sensors_8981008 USING btree (lower((measureid)::text))
|
||||||
|
sensors_8981008 | CREATE INDEX index_with_include_on_sensors_8981008 ON citus_split_test_schema.sensors_8981008 USING btree (((measure_data -> 'IsFailed'::text))) INCLUDE (measure_data, eventdatetime, measure_status)
|
||||||
|
sensors_8981008 | CREATE UNIQUE INDEX sensors_pkey_8981008 ON citus_split_test_schema.sensors_8981008 USING btree (measureid, eventdatetime, measure_data)
|
||||||
|
sensors_8981015 | CREATE INDEX hash_index_on_sensors_8981015 ON citus_split_test_schema.sensors_8981015 USING hash (((measure_data -> 'IsFailed'::text)))
|
||||||
|
sensors_8981015 | CREATE INDEX index_on_sensors_8981015 ON citus_split_test_schema.sensors_8981015 USING btree (lower((measureid)::text))
|
||||||
|
sensors_8981015 | CREATE INDEX index_with_include_on_sensors_8981015 ON citus_split_test_schema.sensors_8981015 USING btree (((measure_data -> 'IsFailed'::text))) INCLUDE (measure_data, eventdatetime, measure_status)
|
||||||
|
sensors_8981015 | CREATE UNIQUE INDEX sensors_pkey_8981015 ON citus_split_test_schema.sensors_8981015 USING btree (measureid, eventdatetime, measure_data)
|
||||||
|
(12 rows)
|
||||||
|
|
||||||
|
SELECT tablename, indexdef FROM pg_indexes WHERE tablename like 'table_with_index_rep_identity_%' ORDER BY 1,2;
|
||||||
|
tablename | indexdef
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
table_with_index_rep_identity_8981011 | CREATE UNIQUE INDEX uqx_8981011 ON citus_split_test_schema.table_with_index_rep_identity_8981011 USING btree (key)
|
||||||
|
table_with_index_rep_identity_8981012 | CREATE UNIQUE INDEX uqx_8981012 ON citus_split_test_schema.table_with_index_rep_identity_8981012 USING btree (key)
|
||||||
|
table_with_index_rep_identity_8981021 | CREATE UNIQUE INDEX uqx_8981021 ON citus_split_test_schema.table_with_index_rep_identity_8981021 USING btree (key)
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
SELECT stxname FROM pg_statistic_ext
|
||||||
|
WHERE stxnamespace IN (
|
||||||
|
SELECT oid
|
||||||
|
FROM pg_namespace
|
||||||
|
WHERE nspname IN ('citus_split_test_schema')
|
||||||
|
)
|
||||||
|
ORDER BY stxname ASC;
|
||||||
|
stxname
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
stats_on_sensors
|
||||||
|
stats_on_sensors_8981007
|
||||||
|
stats_on_sensors_8981008
|
||||||
|
stats_on_sensors_8981015
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
|
-- END : Display current state
|
||||||
|
-- BEGIN: Should be able to change/drop constraints
|
||||||
|
\c - postgres - :master_port
|
||||||
|
SET ROLE test_split_role;
|
||||||
|
SET search_path TO "citus_split_test_schema";
|
||||||
|
ALTER INDEX index_on_sensors RENAME TO index_on_sensors_renamed;
|
||||||
|
ALTER INDEX index_on_sensors_renamed ALTER COLUMN 1 SET STATISTICS 200;
|
||||||
|
DROP STATISTICS stats_on_sensors;
|
||||||
|
DROP INDEX index_on_sensors_renamed;
|
||||||
|
ALTER TABLE sensors DROP CONSTRAINT fkey_table_to_dist;
|
||||||
|
-- END: Should be able to change/drop constraints
|
||||||
|
-- BEGIN: Split second time on another schema
|
||||||
|
SET search_path TO public;
|
||||||
|
SET citus.next_shard_id TO 8981031;
|
||||||
|
SELECT pg_catalog.citus_split_shard_by_split_points(
|
||||||
|
8981007,
|
||||||
|
ARRAY['-2100000000'],
|
||||||
|
ARRAY[:worker_1_node, :worker_2_node],
|
||||||
|
'force_logical');
|
||||||
|
WARNING: replication slot "citus_shard_split_template_slot_8981007" does not exist
|
||||||
|
CONTEXT: while executing command on localhost:xxxxx
|
||||||
|
citus_split_shard_by_split_points
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SET search_path TO "citus_split_test_schema";
|
||||||
|
SELECT shard.shardid, logicalrelid, shardminvalue, shardmaxvalue, nodename, nodeport
|
||||||
|
FROM pg_dist_shard AS shard
|
||||||
|
INNER JOIN pg_dist_placement placement ON shard.shardid = placement.shardid
|
||||||
|
INNER JOIN pg_dist_node node ON placement.groupid = node.groupid
|
||||||
|
INNER JOIN pg_catalog.pg_class cls ON shard.logicalrelid = cls.oid
|
||||||
|
WHERE node.noderole = 'primary' AND (logicalrelid = 'sensors'::regclass OR logicalrelid = 'colocated_dist_table'::regclass OR logicalrelid = 'table_with_index_rep_identity'::regclass)
|
||||||
|
ORDER BY logicalrelid, shardminvalue::BIGINT;
|
||||||
|
shardid | logicalrelid | shardminvalue | shardmaxvalue | nodename | nodeport
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
8981031 | sensors | -2147483648 | -2100000000 | localhost | 57637
|
||||||
|
8981032 | sensors | -2099999999 | -1073741824 | localhost | 57638
|
||||||
|
8981008 | sensors | -1073741823 | -1 | localhost | 57638
|
||||||
|
8981013 | sensors | 0 | 536870911 | localhost | 57637
|
||||||
|
8981014 | sensors | 536870912 | 1610612735 | localhost | 57637
|
||||||
|
8981015 | sensors | 1610612736 | 2147483647 | localhost | 57638
|
||||||
|
8981033 | colocated_dist_table | -2147483648 | -2100000000 | localhost | 57637
|
||||||
|
8981034 | colocated_dist_table | -2099999999 | -1073741824 | localhost | 57638
|
||||||
|
8981010 | colocated_dist_table | -1073741823 | -1 | localhost | 57638
|
||||||
|
8981016 | colocated_dist_table | 0 | 536870911 | localhost | 57637
|
||||||
|
8981017 | colocated_dist_table | 536870912 | 1610612735 | localhost | 57637
|
||||||
|
8981018 | colocated_dist_table | 1610612736 | 2147483647 | localhost | 57638
|
||||||
|
8981035 | table_with_index_rep_identity | -2147483648 | -2100000000 | localhost | 57637
|
||||||
|
8981036 | table_with_index_rep_identity | -2099999999 | -1073741824 | localhost | 57638
|
||||||
|
8981012 | table_with_index_rep_identity | -1073741823 | -1 | localhost | 57638
|
||||||
|
8981019 | table_with_index_rep_identity | 0 | 536870911 | localhost | 57637
|
||||||
|
8981020 | table_with_index_rep_identity | 536870912 | 1610612735 | localhost | 57637
|
||||||
|
8981021 | table_with_index_rep_identity | 1610612736 | 2147483647 | localhost | 57638
|
||||||
|
(18 rows)
|
||||||
|
|
||||||
|
-- END: Split second time on another schema
|
||||||
|
-- BEGIN: Validate Data Count
|
||||||
|
SELECT COUNT(*) FROM sensors;
|
||||||
|
count
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
1001
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT COUNT(*) FROM reference_table;
|
||||||
|
count
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
1001
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT COUNT(*) FROM colocated_dist_table;
|
||||||
|
count
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
1001
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- END: Validate Data Count
|
||||||
|
--BEGIN : Cleanup
|
||||||
|
\c - postgres - :master_port
|
||||||
|
DROP SCHEMA "citus_split_test_schema" CASCADE;
|
||||||
|
NOTICE: drop cascades to 4 other objects
|
||||||
|
DETAIL: drop cascades to table citus_split_test_schema.sensors
|
||||||
|
drop cascades to table citus_split_test_schema.reference_table
|
||||||
|
drop cascades to table citus_split_test_schema.colocated_dist_table
|
||||||
|
drop cascades to table citus_split_test_schema.table_with_index_rep_identity
|
||||||
|
--END : Cleanup
|
|
@ -22,13 +22,13 @@ SELECT nodeid AS worker_2_node FROM pg_dist_node WHERE nodeport=:worker_2_port \
|
||||||
SELECT * FROM citus_shards;
|
SELECT * FROM citus_shards;
|
||||||
table_name | shardid | shard_name | citus_table_type | colocation_id | nodename | nodeport | shard_size
|
table_name | shardid | shard_name | citus_table_type | colocation_id | nodename | nodeport | shard_size
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
table_to_split | 1 | citus_split_shard_by_split_points_negative.table_to_split_1 | distributed | 1390006 | localhost | 8888 | 0
|
table_to_split | 1 | citus_split_shard_by_split_points_negative.table_to_split_1 | distributed | 1390009 | localhost | 8888 | 0
|
||||||
table_to_split | 1 | citus_split_shard_by_split_points_negative.table_to_split_1 | distributed | 1390006 | localhost | 8887 | 0
|
table_to_split | 1 | citus_split_shard_by_split_points_negative.table_to_split_1 | distributed | 1390009 | localhost | 8887 | 0
|
||||||
table_to_split | 1 | citus_split_shard_by_split_points_negative.table_to_split_1 | distributed | 1390006 | localhost | 9995 | 0
|
table_to_split | 1 | citus_split_shard_by_split_points_negative.table_to_split_1 | distributed | 1390009 | localhost | 9995 | 0
|
||||||
table_to_split | 1 | citus_split_shard_by_split_points_negative.table_to_split_1 | distributed | 1390006 | localhost | 9992 | 0
|
table_to_split | 1 | citus_split_shard_by_split_points_negative.table_to_split_1 | distributed | 1390009 | localhost | 9992 | 0
|
||||||
table_to_split | 1 | citus_split_shard_by_split_points_negative.table_to_split_1 | distributed | 1390006 | localhost | 57637 | 0
|
table_to_split | 1 | citus_split_shard_by_split_points_negative.table_to_split_1 | distributed | 1390009 | localhost | 57637 | 0
|
||||||
table_to_split | 1 | citus_split_shard_by_split_points_negative.table_to_split_1 | distributed | 1390006 | localhost | 9998 | 0
|
table_to_split | 1 | citus_split_shard_by_split_points_negative.table_to_split_1 | distributed | 1390009 | localhost | 9998 | 0
|
||||||
table_to_split | 1 | citus_split_shard_by_split_points_negative.table_to_split_1 | distributed | 1390006 | localhost | 9997 | 0
|
table_to_split | 1 | citus_split_shard_by_split_points_negative.table_to_split_1 | distributed | 1390009 | localhost | 9997 | 0
|
||||||
(7 rows)
|
(7 rows)
|
||||||
|
|
||||||
SELECT * FROM pg_dist_shard;
|
SELECT * FROM pg_dist_shard;
|
||||||
|
@ -62,7 +62,7 @@ SELECT citus_split_shard_by_split_points(
|
||||||
ARRAY['0'],
|
ARRAY['0'],
|
||||||
ARRAY[:worker_1_node, :worker_2_node],
|
ARRAY[:worker_1_node, :worker_2_node],
|
||||||
'force_logical');
|
'force_logical');
|
||||||
WARNING: replication slot "citus_split_replicationslot_for_shard_1" does not exist
|
WARNING: replication slot "citus_shard_split_template_slot_1" does not exist
|
||||||
CONTEXT: while executing command on localhost:xxxxx
|
CONTEXT: while executing command on localhost:xxxxx
|
||||||
WARNING: connection claimed exclusively at transaction commit
|
WARNING: connection claimed exclusively at transaction commit
|
||||||
WARNING: connection claimed exclusively at transaction commit
|
WARNING: connection claimed exclusively at transaction commit
|
||||||
|
@ -88,7 +88,7 @@ SELECT * FROM show_catalog;
|
||||||
SELECT * FROM pg_subscription;
|
SELECT * FROM pg_subscription;
|
||||||
oid | subdbid | subname | subowner | subenabled | subbinary | substream | subconninfo | subslotname | subsynccommit | subpublications
|
oid | subdbid | subname | subowner | subenabled | subbinary | substream | subconninfo | subslotname | subsynccommit | subpublications
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
17311 | 16384 | citus_shard_split_subscription_10 | 17310 | t | f | f | host='localhost' port=xxxxx user='postgres' dbname='regression' connect_timeout=20 sslmode=prefer | citus_split_18_10 | off | {citus_shard_split_publication_18_10}
|
20669 | 16384 | citus_shard_split_subscription_10 | 20668 | t | f | f | host='localhost' port=xxxxx user='postgres' dbname='regression' connect_timeout=20 sslmode=prefer | citus_split_18_10 | off | {citus_shard_split_publication_18_10}
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT slot_name FROM pg_replication_slots;
|
SELECT slot_name FROM pg_replication_slots;
|
||||||
|
@ -115,20 +115,20 @@ SELECT * FROM show_catalog;
|
||||||
SELECT * FROM pg_publication;
|
SELECT * FROM pg_publication;
|
||||||
oid | pubname | pubowner | puballtables | pubinsert | pubupdate | pubdelete | pubtruncate | pubviaroot
|
oid | pubname | pubowner | puballtables | pubinsert | pubupdate | pubdelete | pubtruncate | pubviaroot
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
17371 | citus_shard_split_publication_16_10 | 10 | f | t | t | t | t | f
|
20728 | citus_shard_split_publication_16_10 | 10 | f | t | t | t | t | f
|
||||||
17374 | citus_shard_split_publication_18_10 | 10 | f | t | t | t | t | f
|
20731 | citus_shard_split_publication_18_10 | 10 | f | t | t | t | t | f
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
SELECT * FROM pg_subscription;
|
SELECT * FROM pg_subscription;
|
||||||
oid | subdbid | subname | subowner | subenabled | subbinary | substream | subconninfo | subslotname | subsynccommit | subpublications
|
oid | subdbid | subname | subowner | subenabled | subbinary | substream | subconninfo | subslotname | subsynccommit | subpublications
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
17378 | 16384 | citus_shard_split_subscription_10 | 17377 | t | f | f | host='localhost' port=xxxxx user='postgres' dbname='regression' connect_timeout=20 sslmode=prefer | citus_split_16_10 | off | {citus_shard_split_publication_16_10}
|
20735 | 16384 | citus_shard_split_subscription_10 | 20734 | t | f | f | host='localhost' port=xxxxx user='postgres' dbname='regression' connect_timeout=20 sslmode=prefer | citus_split_16_10 | off | {citus_shard_split_publication_16_10}
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT slot_name FROM pg_replication_slots;
|
SELECT slot_name FROM pg_replication_slots;
|
||||||
slot_name
|
slot_name
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
citus_split_replicationslot_for_shard_1
|
citus_shard_split_template_slot_1
|
||||||
citus_split_16_10
|
citus_split_16_10
|
||||||
citus_split_18_10
|
citus_split_18_10
|
||||||
(3 rows)
|
(3 rows)
|
||||||
|
|
|
@ -78,8 +78,8 @@ WARNING: Previous split shard worflow was not successfully and could not comple
|
||||||
|
|
||||||
SELECT relowner AS table_owner_one FROM pg_class WHERE relname='table_first' \gset
|
SELECT relowner AS table_owner_one FROM pg_class WHERE relname='table_first' \gset
|
||||||
SELECT relowner AS table_owner_two FROM pg_class WHERE relname='table_second' \gset
|
SELECT relowner AS table_owner_two FROM pg_class WHERE relname='table_second' \gset
|
||||||
SELECT slot_name AS slot_for_first_owner FROM pg_create_logical_replication_slot(FORMAT('citus_split_%s_%s', :worker_2_node, :table_owner_one), 'citus') \gset
|
SELECT slot_name AS slot_for_first_owner FROM pg_create_logical_replication_slot(FORMAT('citus_shard_split_%s_%s', :worker_2_node, :table_owner_one), 'citus') \gset
|
||||||
SELECT slot_name AS slot_for_second_owner FROM pg_create_logical_replication_slot(FORMAT('citus_split_%s_%s', :worker_2_node, :table_owner_two), 'citus') \gset
|
SELECT slot_name AS slot_for_second_owner FROM pg_create_logical_replication_slot(FORMAT('citus_shard_split_%s_%s', :worker_2_node, :table_owner_two), 'citus') \gset
|
||||||
-- Create subscription at worker2 with copy_data to 'false'
|
-- Create subscription at worker2 with copy_data to 'false'
|
||||||
\c - postgres - :worker_2_port
|
\c - postgres - :worker_2_port
|
||||||
SET search_path TO split_shard_replication_setup_schema;
|
SET search_path TO split_shard_replication_setup_schema;
|
||||||
|
|
|
@ -71,7 +71,7 @@ SELECT count(*) FROM worker_split_shard_replication_setup(ARRAY[
|
||||||
1
|
1
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT slot_name FROM pg_create_logical_replication_slot(FORMAT('citus_split_%s_10', :worker_2_node), 'citus') \gset
|
SELECT slot_name FROM pg_create_logical_replication_slot(FORMAT('citus_shard_split_%s_10', :worker_2_node), 'citus') \gset
|
||||||
-- Create subscription at worker2 with copy_data to 'false' and derived replication slot name
|
-- Create subscription at worker2 with copy_data to 'false' and derived replication slot name
|
||||||
\c - - - :worker_2_port
|
\c - - - :worker_2_port
|
||||||
SET search_path TO split_shard_replication_setup_schema;
|
SET search_path TO split_shard_replication_setup_schema;
|
||||||
|
|
|
@ -19,7 +19,7 @@ SELECT count(*) FROM worker_split_shard_replication_setup(ARRAY[
|
||||||
1
|
1
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT slot_name AS local_slot FROM pg_create_logical_replication_slot(FORMAT('citus_split_%s_10', :worker_1_node), 'citus') \gset
|
SELECT slot_name AS local_slot FROM pg_create_logical_replication_slot(FORMAT('citus_shard_split_%s_10', :worker_1_node), 'citus') \gset
|
||||||
-- Create subscription at worker1 with copy_data to 'false' a
|
-- Create subscription at worker1 with copy_data to 'false' a
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE SUBSCRIPTION local_subscription
|
CREATE SUBSCRIPTION local_subscription
|
||||||
|
|
|
@ -18,8 +18,8 @@ WARNING: Previous split shard worflow was not successfully and could not comple
|
||||||
2
|
2
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT slot_name AS slot_for_worker1 FROM pg_create_logical_replication_slot(FORMAT('citus_split_%s_10', :worker_1_node), 'citus') \gset
|
SELECT slot_name AS slot_for_worker1 FROM pg_create_logical_replication_slot(FORMAT('citus_shard_split_%s_10', :worker_1_node), 'citus') \gset
|
||||||
SELECT slot_name AS slot_for_worker2 FROM pg_create_logical_replication_slot(FORMAT('citus_split_%s_10', :worker_2_node), 'citus') \gset
|
SELECT slot_name AS slot_for_worker2 FROM pg_create_logical_replication_slot(FORMAT('citus_shard_split_%s_10', :worker_2_node), 'citus') \gset
|
||||||
-- Create subscription at worker1 with copy_data to 'false' and 'slot_for_worker1'
|
-- Create subscription at worker1 with copy_data to 'false' and 'slot_for_worker1'
|
||||||
CREATE SUBSCRIPTION sub_worker1
|
CREATE SUBSCRIPTION sub_worker1
|
||||||
CONNECTION 'host=localhost port=xxxxx user=postgres dbname=regression'
|
CONNECTION 'host=localhost port=xxxxx user=postgres dbname=regression'
|
||||||
|
|
|
@ -8,16 +8,17 @@ test: tablespace
|
||||||
test: foreign_key_to_reference_table
|
test: foreign_key_to_reference_table
|
||||||
# Split tests go here.
|
# Split tests go here.
|
||||||
#test: citus_sameer
|
#test: citus_sameer
|
||||||
test: split_shard_replication_setup
|
#test: split_shard_replication_setup
|
||||||
test: split_shard_replication_setup_remote_local
|
#test: split_shard_replication_setup_remote_local
|
||||||
test: split_shard_replication_setup_local
|
#test: split_shard_replication_setup_local
|
||||||
test: split_shard_replication_colocated_setup
|
#test: split_shard_replication_colocated_setup
|
||||||
test: worker_split_copy_test
|
#test: worker_split_copy_test
|
||||||
test: worker_split_binary_copy_test
|
#test: worker_split_binary_copy_test
|
||||||
test: worker_split_text_copy_test
|
#test: worker_split_text_copy_test
|
||||||
test: citus_split_shard_by_split_points_negative
|
#test: citus_split_shard_by_split_points_negative
|
||||||
test: citus_split_shard_by_split_points
|
#test: citus_split_shard_by_split_points
|
||||||
test: citus_split_shard_by_split_points_failure
|
#test: citus_split_shard_by_split_points_failure
|
||||||
# Name citus_split_shard_by_split_points_columnar_partitioned was too long and being truncated.
|
# Name citus_split_shard_by_split_points_columnar_partitioned was too long and being truncated.
|
||||||
# use citus_split_shard_columnar_partitioned instead.
|
# use citus_split_shard_columnar_partitioned instead.
|
||||||
test: citus_split_shard_columnar_partitioned
|
#test: citus_split_shard_columnar_partitioned
|
||||||
|
test: citus_non_blocking_split_shards
|
||||||
|
|
|
@ -0,0 +1,240 @@
|
||||||
|
/*
|
||||||
|
Citus Shard Split Test.The test is model similar to 'shard_move_constraints'.
|
||||||
|
Here is a high level overview of test plan:
|
||||||
|
1. Create a table 'sensors' (ShardCount = 2) to be split. Add indexes and statistics on this table.
|
||||||
|
2. Create two other tables: 'reference_table' and 'colocated_dist_table', co-located with sensors.
|
||||||
|
3. Create Foreign key constraints between the two co-located distributed tables.
|
||||||
|
4. Load data into the three tables.
|
||||||
|
5. Move one of the shards for 'sensors' to test ShardMove -> Split.
|
||||||
|
6. Trigger Split on both shards of 'sensors'. This will also split co-located tables.
|
||||||
|
7. Move one of the split shard to test Split -> ShardMove.
|
||||||
|
8. Split an already split shard second time on a different schema.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CREATE SCHEMA "citus_split_test_schema";
|
||||||
|
|
||||||
|
CREATE ROLE test_split_role WITH LOGIN;
|
||||||
|
GRANT USAGE, CREATE ON SCHEMA "citus_split_test_schema" TO test_split_role;
|
||||||
|
SET ROLE test_split_role;
|
||||||
|
|
||||||
|
SET search_path TO "citus_split_test_schema";
|
||||||
|
SET citus.next_shard_id TO 8981000;
|
||||||
|
SET citus.next_placement_id TO 8610000;
|
||||||
|
SET citus.shard_count TO 2;
|
||||||
|
SET citus.shard_replication_factor TO 1;
|
||||||
|
|
||||||
|
-- BEGIN: Create table to split, along with other co-located tables. Add indexes, statistics etc.
|
||||||
|
CREATE TABLE sensors(
|
||||||
|
measureid integer,
|
||||||
|
eventdatetime date,
|
||||||
|
measure_data jsonb,
|
||||||
|
meaure_quantity decimal(15, 2),
|
||||||
|
measure_status char(1),
|
||||||
|
measure_comment varchar(44),
|
||||||
|
PRIMARY KEY (measureid, eventdatetime, measure_data));
|
||||||
|
|
||||||
|
CREATE INDEX index_on_sensors ON sensors(lower(measureid::text));
|
||||||
|
ALTER INDEX index_on_sensors ALTER COLUMN 1 SET STATISTICS 1000;
|
||||||
|
CREATE INDEX hash_index_on_sensors ON sensors USING HASH((measure_data->'IsFailed'));
|
||||||
|
CREATE INDEX index_with_include_on_sensors ON sensors ((measure_data->'IsFailed')) INCLUDE (measure_data, eventdatetime, measure_status);
|
||||||
|
CREATE STATISTICS stats_on_sensors (dependencies) ON measureid, eventdatetime FROM sensors;
|
||||||
|
|
||||||
|
SELECT create_distributed_table('sensors', 'measureid', colocate_with:='none');
|
||||||
|
-- END: Create table to split, along with other co-located tables. Add indexes, statistics etc.
|
||||||
|
|
||||||
|
-- BEGIN: Create co-located distributed and reference tables.
|
||||||
|
CREATE TABLE reference_table (measureid integer PRIMARY KEY);
|
||||||
|
SELECT create_reference_table('reference_table');
|
||||||
|
|
||||||
|
CREATE TABLE colocated_dist_table (measureid integer PRIMARY KEY);
|
||||||
|
CLUSTER colocated_dist_table USING colocated_dist_table_pkey;
|
||||||
|
SELECT create_distributed_table('colocated_dist_table', 'measureid', colocate_with:='sensors');
|
||||||
|
|
||||||
|
CREATE TABLE table_with_index_rep_identity(key int NOT NULL);
|
||||||
|
CREATE UNIQUE INDEX uqx ON table_with_index_rep_identity(key);
|
||||||
|
ALTER TABLE table_with_index_rep_identity REPLICA IDENTITY USING INDEX uqx;
|
||||||
|
CLUSTER table_with_index_rep_identity USING uqx;
|
||||||
|
SELECT create_distributed_table('table_with_index_rep_identity', 'key', colocate_with:='sensors');
|
||||||
|
-- END: Create co-located distributed and reference tables.
|
||||||
|
|
||||||
|
-- BEGIN : Create Foreign key constraints.
|
||||||
|
ALTER TABLE sensors ADD CONSTRAINT fkey_table_to_dist FOREIGN KEY (measureid) REFERENCES colocated_dist_table(measureid);
|
||||||
|
-- END : Create Foreign key constraints.
|
||||||
|
|
||||||
|
-- BEGIN : Load data into tables.
|
||||||
|
INSERT INTO reference_table SELECT i FROM generate_series(0,1000)i;
|
||||||
|
INSERT INTO colocated_dist_table SELECT i FROM generate_series(0,1000)i;
|
||||||
|
INSERT INTO sensors SELECT i, '2020-01-05', '{}', 11011.10, 'A', 'I <3 Citus' FROM generate_series(0,1000)i;
|
||||||
|
|
||||||
|
SELECT COUNT(*) FROM sensors;
|
||||||
|
SELECT COUNT(*) FROM reference_table;
|
||||||
|
SELECT COUNT(*) FROM colocated_dist_table;
|
||||||
|
-- END: Load data into tables.
|
||||||
|
|
||||||
|
-- BEGIN : Display current state.
|
||||||
|
SELECT shard.shardid, logicalrelid, shardminvalue, shardmaxvalue, nodename, nodeport
|
||||||
|
FROM pg_dist_shard AS shard
|
||||||
|
INNER JOIN pg_dist_placement placement ON shard.shardid = placement.shardid
|
||||||
|
INNER JOIN pg_dist_node node ON placement.groupid = node.groupid
|
||||||
|
INNER JOIN pg_catalog.pg_class cls ON shard.logicalrelid = cls.oid
|
||||||
|
WHERE node.noderole = 'primary' AND (logicalrelid = 'sensors'::regclass OR logicalrelid = 'colocated_dist_table'::regclass OR logicalrelid = 'table_with_index_rep_identity'::regclass)
|
||||||
|
ORDER BY logicalrelid, shardminvalue::BIGINT;
|
||||||
|
|
||||||
|
\c - - - :worker_1_port
|
||||||
|
SET search_path TO "citus_split_test_schema", public, pg_catalog;
|
||||||
|
SET citus.show_shards_for_app_name_prefixes = '*';
|
||||||
|
SELECT tbl.relname, fk."Constraint", fk."Definition"
|
||||||
|
FROM pg_catalog.pg_class tbl
|
||||||
|
JOIN public.table_fkeys fk on tbl.oid = fk.relid
|
||||||
|
WHERE tbl.relname like 'sensors_%'
|
||||||
|
ORDER BY 1, 2;
|
||||||
|
SELECT tablename, indexdef FROM pg_indexes WHERE tablename like 'sensors_%' ORDER BY 1,2;
|
||||||
|
SELECT tablename, indexdef FROM pg_indexes WHERE tablename like 'table_with_index_rep_identity_%' ORDER BY 1,2;
|
||||||
|
SELECT stxname FROM pg_statistic_ext
|
||||||
|
WHERE stxnamespace IN (
|
||||||
|
SELECT oid
|
||||||
|
FROM pg_namespace
|
||||||
|
WHERE nspname IN ('citus_split_test_schema')
|
||||||
|
)
|
||||||
|
ORDER BY stxname ASC;
|
||||||
|
|
||||||
|
\c - - - :worker_2_port
|
||||||
|
SET search_path TO "citus_split_test_schema", public, pg_catalog;
|
||||||
|
SET citus.show_shards_for_app_name_prefixes = '*';
|
||||||
|
SELECT tbl.relname, fk."Constraint", fk."Definition"
|
||||||
|
FROM pg_catalog.pg_class tbl
|
||||||
|
JOIN public.table_fkeys fk on tbl.oid = fk.relid
|
||||||
|
WHERE tbl.relname like 'sensors_%'
|
||||||
|
ORDER BY 1, 2;
|
||||||
|
SELECT tablename, indexdef FROM pg_indexes WHERE tablename like 'sensors_%' ORDER BY 1,2;
|
||||||
|
SELECT tablename, indexdef FROM pg_indexes WHERE tablename like 'table_with_index_rep_identity_%' ORDER BY 1,2;
|
||||||
|
SELECT stxname FROM pg_statistic_ext
|
||||||
|
WHERE stxnamespace IN (
|
||||||
|
SELECT oid
|
||||||
|
FROM pg_namespace
|
||||||
|
WHERE nspname IN ('citus_split_test_schema')
|
||||||
|
)
|
||||||
|
ORDER BY stxname ASC;
|
||||||
|
-- END : Display current state
|
||||||
|
|
||||||
|
-- BEGIN : Move one shard before we split it.
|
||||||
|
\c - postgres - :master_port
|
||||||
|
SET ROLE test_split_role;
|
||||||
|
SET search_path TO "citus_split_test_schema";
|
||||||
|
SET citus.next_shard_id TO 8981007;
|
||||||
|
SET citus.defer_drop_after_shard_move TO OFF;
|
||||||
|
|
||||||
|
SELECT citus_move_shard_placement(8981000, 'localhost', :worker_1_port, 'localhost', :worker_2_port, shard_transfer_mode:='force_logical');
|
||||||
|
-- END : Move one shard before we split it.
|
||||||
|
|
||||||
|
-- BEGIN : Set node id variables
|
||||||
|
SELECT nodeid AS worker_1_node FROM pg_dist_node WHERE nodeport=:worker_1_port \gset
|
||||||
|
SELECT nodeid AS worker_2_node FROM pg_dist_node WHERE nodeport=:worker_2_port \gset
|
||||||
|
-- END : Set node id variables
|
||||||
|
|
||||||
|
-- BEGIN : Split two shards : One with move and One without move.
|
||||||
|
-- Perform 2 way split
|
||||||
|
SELECT pg_catalog.citus_split_shard_by_split_points(
|
||||||
|
8981000,
|
||||||
|
ARRAY['-1073741824'],
|
||||||
|
ARRAY[:worker_1_node, :worker_2_node],
|
||||||
|
'force_logical');
|
||||||
|
|
||||||
|
-- Perform 3 way split
|
||||||
|
SELECT pg_catalog.citus_split_shard_by_split_points(
|
||||||
|
8981001,
|
||||||
|
ARRAY['536870911', '1610612735'],
|
||||||
|
ARRAY[:worker_1_node, :worker_1_node, :worker_2_node],
|
||||||
|
'force_logical');
|
||||||
|
-- END : Split two shards : One with move and One without move.
|
||||||
|
|
||||||
|
-- BEGIN : Move a shard post split.
|
||||||
|
SELECT citus_move_shard_placement(8981007, 'localhost', :worker_1_port, 'localhost', :worker_2_port, shard_transfer_mode:='block_writes');
|
||||||
|
-- END : Move a shard post split.
|
||||||
|
|
||||||
|
-- BEGIN : Display current state.
|
||||||
|
SELECT shard.shardid, logicalrelid, shardminvalue, shardmaxvalue, nodename, nodeport
|
||||||
|
FROM pg_dist_shard AS shard
|
||||||
|
INNER JOIN pg_dist_placement placement ON shard.shardid = placement.shardid
|
||||||
|
INNER JOIN pg_dist_node node ON placement.groupid = node.groupid
|
||||||
|
INNER JOIN pg_catalog.pg_class cls ON shard.logicalrelid = cls.oid
|
||||||
|
WHERE node.noderole = 'primary' AND (logicalrelid = 'sensors'::regclass OR logicalrelid = 'colocated_dist_table'::regclass OR logicalrelid = 'table_with_index_rep_identity'::regclass)
|
||||||
|
ORDER BY logicalrelid, shardminvalue::BIGINT;
|
||||||
|
|
||||||
|
\c - - - :worker_1_port
|
||||||
|
SET search_path TO "citus_split_test_schema", public, pg_catalog;
|
||||||
|
SET citus.show_shards_for_app_name_prefixes = '*';
|
||||||
|
SELECT tbl.relname, fk."Constraint", fk."Definition"
|
||||||
|
FROM pg_catalog.pg_class tbl
|
||||||
|
JOIN public.table_fkeys fk on tbl.oid = fk.relid
|
||||||
|
WHERE tbl.relname like 'sensors_%'
|
||||||
|
ORDER BY 1, 2;
|
||||||
|
SELECT tablename, indexdef FROM pg_indexes WHERE tablename like 'sensors_%' ORDER BY 1,2;
|
||||||
|
SELECT tablename, indexdef FROM pg_indexes WHERE tablename like 'table_with_index_rep_identity_%' ORDER BY 1,2;
|
||||||
|
SELECT stxname FROM pg_statistic_ext
|
||||||
|
WHERE stxnamespace IN (
|
||||||
|
SELECT oid
|
||||||
|
FROM pg_namespace
|
||||||
|
WHERE nspname IN ('citus_split_test_schema')
|
||||||
|
)
|
||||||
|
ORDER BY stxname ASC;
|
||||||
|
|
||||||
|
\c - - - :worker_2_port
|
||||||
|
SET search_path TO "citus_split_test_schema", public, pg_catalog;
|
||||||
|
SET citus.show_shards_for_app_name_prefixes = '*';
|
||||||
|
SELECT tbl.relname, fk."Constraint", fk."Definition"
|
||||||
|
FROM pg_catalog.pg_class tbl
|
||||||
|
JOIN public.table_fkeys fk on tbl.oid = fk.relid
|
||||||
|
WHERE tbl.relname like 'sensors_%'
|
||||||
|
ORDER BY 1, 2;
|
||||||
|
SELECT tablename, indexdef FROM pg_indexes WHERE tablename like 'sensors_%' ORDER BY 1,2;
|
||||||
|
SELECT tablename, indexdef FROM pg_indexes WHERE tablename like 'table_with_index_rep_identity_%' ORDER BY 1,2;
|
||||||
|
SELECT stxname FROM pg_statistic_ext
|
||||||
|
WHERE stxnamespace IN (
|
||||||
|
SELECT oid
|
||||||
|
FROM pg_namespace
|
||||||
|
WHERE nspname IN ('citus_split_test_schema')
|
||||||
|
)
|
||||||
|
ORDER BY stxname ASC;
|
||||||
|
-- END : Display current state
|
||||||
|
|
||||||
|
-- BEGIN: Should be able to change/drop constraints
|
||||||
|
\c - postgres - :master_port
|
||||||
|
SET ROLE test_split_role;
|
||||||
|
SET search_path TO "citus_split_test_schema";
|
||||||
|
ALTER INDEX index_on_sensors RENAME TO index_on_sensors_renamed;
|
||||||
|
ALTER INDEX index_on_sensors_renamed ALTER COLUMN 1 SET STATISTICS 200;
|
||||||
|
DROP STATISTICS stats_on_sensors;
|
||||||
|
DROP INDEX index_on_sensors_renamed;
|
||||||
|
ALTER TABLE sensors DROP CONSTRAINT fkey_table_to_dist;
|
||||||
|
-- END: Should be able to change/drop constraints
|
||||||
|
|
||||||
|
-- BEGIN: Split second time on another schema
|
||||||
|
SET search_path TO public;
|
||||||
|
SET citus.next_shard_id TO 8981031;
|
||||||
|
SELECT pg_catalog.citus_split_shard_by_split_points(
|
||||||
|
8981007,
|
||||||
|
ARRAY['-2100000000'],
|
||||||
|
ARRAY[:worker_1_node, :worker_2_node],
|
||||||
|
'force_logical');
|
||||||
|
|
||||||
|
SET search_path TO "citus_split_test_schema";
|
||||||
|
SELECT shard.shardid, logicalrelid, shardminvalue, shardmaxvalue, nodename, nodeport
|
||||||
|
FROM pg_dist_shard AS shard
|
||||||
|
INNER JOIN pg_dist_placement placement ON shard.shardid = placement.shardid
|
||||||
|
INNER JOIN pg_dist_node node ON placement.groupid = node.groupid
|
||||||
|
INNER JOIN pg_catalog.pg_class cls ON shard.logicalrelid = cls.oid
|
||||||
|
WHERE node.noderole = 'primary' AND (logicalrelid = 'sensors'::regclass OR logicalrelid = 'colocated_dist_table'::regclass OR logicalrelid = 'table_with_index_rep_identity'::regclass)
|
||||||
|
ORDER BY logicalrelid, shardminvalue::BIGINT;
|
||||||
|
-- END: Split second time on another schema
|
||||||
|
|
||||||
|
-- BEGIN: Validate Data Count
|
||||||
|
SELECT COUNT(*) FROM sensors;
|
||||||
|
SELECT COUNT(*) FROM reference_table;
|
||||||
|
SELECT COUNT(*) FROM colocated_dist_table;
|
||||||
|
-- END: Validate Data Count
|
||||||
|
|
||||||
|
--BEGIN : Cleanup
|
||||||
|
\c - postgres - :master_port
|
||||||
|
DROP SCHEMA "citus_split_test_schema" CASCADE;
|
||||||
|
--END : Cleanup
|
|
@ -67,5 +67,5 @@ SET search_path TO citus_split_shard_by_split_points_negative;
|
||||||
SELECT * FROM show_catalog;
|
SELECT * FROM show_catalog;
|
||||||
SELECT * FROM pg_publication;
|
SELECT * FROM pg_publication;
|
||||||
SELECT * FROM pg_subscription;
|
SELECT * FROM pg_subscription;
|
||||||
SELECT slot_name FROM pg_replication_slots;
|
SELECT * FROM pg_replication_slots;
|
||||||
SELECT * FROM table_to_split_100;
|
SELECT * FROM table_to_split_100;
|
||||||
|
|
|
@ -76,9 +76,9 @@ SELECT count(*) FROM worker_split_shard_replication_setup(ARRAY[
|
||||||
SELECT relowner AS table_owner_one FROM pg_class WHERE relname='table_first' \gset
|
SELECT relowner AS table_owner_one FROM pg_class WHERE relname='table_first' \gset
|
||||||
SELECT relowner AS table_owner_two FROM pg_class WHERE relname='table_second' \gset
|
SELECT relowner AS table_owner_two FROM pg_class WHERE relname='table_second' \gset
|
||||||
|
|
||||||
SELECT slot_name AS slot_for_first_owner FROM pg_create_logical_replication_slot(FORMAT('citus_split_%s_%s', :worker_2_node, :table_owner_one), 'citus') \gset
|
SELECT slot_name AS slot_for_first_owner FROM pg_create_logical_replication_slot(FORMAT('citus_shard_split_%s_%s', :worker_2_node, :table_owner_one), 'citus') \gset
|
||||||
|
|
||||||
SELECT slot_name AS slot_for_second_owner FROM pg_create_logical_replication_slot(FORMAT('citus_split_%s_%s', :worker_2_node, :table_owner_two), 'citus') \gset
|
SELECT slot_name AS slot_for_second_owner FROM pg_create_logical_replication_slot(FORMAT('citus_shard_split_%s_%s', :worker_2_node, :table_owner_two), 'citus') \gset
|
||||||
|
|
||||||
-- Create subscription at worker2 with copy_data to 'false'
|
-- Create subscription at worker2 with copy_data to 'false'
|
||||||
\c - postgres - :worker_2_port
|
\c - postgres - :worker_2_port
|
||||||
|
|
|
@ -71,7 +71,7 @@ SELECT count(*) FROM worker_split_shard_replication_setup(ARRAY[
|
||||||
ROW(1, 3, '0', '2147483647', :worker_2_node)::citus.split_shard_info
|
ROW(1, 3, '0', '2147483647', :worker_2_node)::citus.split_shard_info
|
||||||
]);
|
]);
|
||||||
|
|
||||||
SELECT slot_name FROM pg_create_logical_replication_slot(FORMAT('citus_split_%s_10', :worker_2_node), 'citus') \gset
|
SELECT slot_name FROM pg_create_logical_replication_slot(FORMAT('citus_shard_split_%s_10', :worker_2_node), 'citus') \gset
|
||||||
|
|
||||||
-- Create subscription at worker2 with copy_data to 'false' and derived replication slot name
|
-- Create subscription at worker2 with copy_data to 'false' and derived replication slot name
|
||||||
\c - - - :worker_2_port
|
\c - - - :worker_2_port
|
||||||
|
|
|
@ -18,7 +18,7 @@ SELECT count(*) FROM worker_split_shard_replication_setup(ARRAY[
|
||||||
ROW(1, 3, '0', '2147483647', :worker_1_node)::citus.split_shard_info
|
ROW(1, 3, '0', '2147483647', :worker_1_node)::citus.split_shard_info
|
||||||
]);
|
]);
|
||||||
|
|
||||||
SELECT slot_name AS local_slot FROM pg_create_logical_replication_slot(FORMAT('citus_split_%s_10', :worker_1_node), 'citus') \gset
|
SELECT slot_name AS local_slot FROM pg_create_logical_replication_slot(FORMAT('citus_shard_split_%s_10', :worker_1_node), 'citus') \gset
|
||||||
|
|
||||||
-- Create subscription at worker1 with copy_data to 'false' a
|
-- Create subscription at worker1 with copy_data to 'false' a
|
||||||
BEGIN;
|
BEGIN;
|
||||||
|
|
|
@ -16,8 +16,8 @@ SELECT count(*) FROM worker_split_shard_replication_setup(ARRAY[
|
||||||
ROW(1, 3, '0', '2147483647', :worker_2_node)::citus.split_shard_info
|
ROW(1, 3, '0', '2147483647', :worker_2_node)::citus.split_shard_info
|
||||||
]);
|
]);
|
||||||
|
|
||||||
SELECT slot_name AS slot_for_worker1 FROM pg_create_logical_replication_slot(FORMAT('citus_split_%s_10', :worker_1_node), 'citus') \gset
|
SELECT slot_name AS slot_for_worker1 FROM pg_create_logical_replication_slot(FORMAT('citus_shard_split_%s_10', :worker_1_node), 'citus') \gset
|
||||||
SELECT slot_name AS slot_for_worker2 FROM pg_create_logical_replication_slot(FORMAT('citus_split_%s_10', :worker_2_node), 'citus') \gset
|
SELECT slot_name AS slot_for_worker2 FROM pg_create_logical_replication_slot(FORMAT('citus_shard_split_%s_10', :worker_2_node), 'citus') \gset
|
||||||
|
|
||||||
-- Create subscription at worker1 with copy_data to 'false' and 'slot_for_worker1'
|
-- Create subscription at worker1 with copy_data to 'false' and 'slot_for_worker1'
|
||||||
CREATE SUBSCRIPTION sub_worker1
|
CREATE SUBSCRIPTION sub_worker1
|
||||||
|
|
Loading…
Reference in New Issue