Merge pull request #1158 from citusdata/convert_multi_shard

Use placement connection API for multi-shard transactions
pull/1124/head
Marco Slot 2017-01-23 18:55:16 +01:00 committed by GitHub
commit c227b35ca1
5 changed files with 89 additions and 71 deletions

View File

@ -925,12 +925,19 @@ ExecuteModifyTasks(List *taskList, bool expectResults, ParamListInfo paramListIn
{ {
int64 totalAffectedTupleCount = 0; int64 totalAffectedTupleCount = 0;
ListCell *taskCell = NULL; ListCell *taskCell = NULL;
char *userName = CurrentUserName(); Task *firstTask = NULL;
int connectionFlags = 0;
List *shardIntervalList = NIL; List *shardIntervalList = NIL;
List *affectedTupleCountList = NIL; List *affectedTupleCountList = NIL;
HTAB *shardConnectionHash = NULL;
bool tasksPending = true; bool tasksPending = true;
int placementIndex = 0; int placementIndex = 0;
if (taskList == NIL)
{
return 0;
}
if (XactModificationLevel == XACT_MODIFICATION_DATA) if (XactModificationLevel == XACT_MODIFICATION_DATA)
{ {
ereport(ERROR, (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION), ereport(ERROR, (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
@ -944,8 +951,28 @@ ExecuteModifyTasks(List *taskList, bool expectResults, ParamListInfo paramListIn
/* ensure that there are no concurrent modifications on the same shards */ /* ensure that there are no concurrent modifications on the same shards */
AcquireExecutorMultiShardLocks(taskList); AcquireExecutorMultiShardLocks(taskList);
BeginOrContinueCoordinatedTransaction();
firstTask = (Task *) linitial(taskList);
if (MultiShardCommitProtocol == COMMIT_PROTOCOL_2PC ||
firstTask->replicationModel == REPLICATION_MODEL_2PC)
{
CoordinatedTransactionUse2PC();
}
if (firstTask->taskType == DDL_TASK)
{
connectionFlags = FOR_DDL;
}
else
{
connectionFlags = FOR_DML;
}
/* open connection to all relevant placements, if not already open */ /* open connection to all relevant placements, if not already open */
OpenTransactionsToAllShardPlacements(shardIntervalList, userName); shardConnectionHash = OpenTransactionsToAllShardPlacements(shardIntervalList,
connectionFlags);
XactModificationLevel = XACT_MODIFICATION_MULTI_SHARD; XactModificationLevel = XACT_MODIFICATION_MULTI_SHARD;
@ -968,7 +995,8 @@ ExecuteModifyTasks(List *taskList, bool expectResults, ParamListInfo paramListIn
MultiConnection *connection = NULL; MultiConnection *connection = NULL;
bool queryOK = false; bool queryOK = false;
shardConnections = GetShardConnections(shardId, &shardConnectionsFound); shardConnections = GetShardHashConnections(shardConnectionHash, shardId,
&shardConnectionsFound);
connectionList = shardConnections->connectionList; connectionList = shardConnections->connectionList;
if (placementIndex >= list_length(connectionList)) if (placementIndex >= list_length(connectionList))
@ -1003,7 +1031,8 @@ ExecuteModifyTasks(List *taskList, bool expectResults, ParamListInfo paramListIn
/* abort in case of cancellation */ /* abort in case of cancellation */
CHECK_FOR_INTERRUPTS(); CHECK_FOR_INTERRUPTS();
shardConnections = GetShardConnections(shardId, &shardConnectionsFound); shardConnections = GetShardHashConnections(shardConnectionHash, shardId,
&shardConnectionsFound);
connectionList = shardConnections->connectionList; connectionList = shardConnections->connectionList;
if (placementIndex >= list_length(connectionList)) if (placementIndex >= list_length(connectionList))
@ -1074,6 +1103,8 @@ ExecuteModifyTasks(List *taskList, bool expectResults, ParamListInfo paramListIn
placementIndex++; placementIndex++;
} }
UnclaimAllShardConnections(shardConnectionHash);
CHECK_FOR_INTERRUPTS(); CHECK_FOR_INTERRUPTS();
return totalAffectedTupleCount; return totalAffectedTupleCount;

View File

@ -1124,7 +1124,7 @@ VacuumTaskList(Oid relationId, VacuumStmt *vacuumStmt)
task = CitusMakeNode(Task); task = CitusMakeNode(Task);
task->jobId = jobId; task->jobId = jobId;
task->taskId = taskId++; task->taskId = taskId++;
task->taskType = SQL_TASK; task->taskType = DDL_TASK;
task->queryString = pstrdup(vacuumString->data); task->queryString = pstrdup(vacuumString->data);
task->dependedTaskList = NULL; task->dependedTaskList = NULL;
task->replicationModel = REPLICATION_MODEL_INVALID; task->replicationModel = REPLICATION_MODEL_INVALID;
@ -2094,7 +2094,7 @@ DDLTaskList(Oid relationId, const char *commandString)
task = CitusMakeNode(Task); task = CitusMakeNode(Task);
task->jobId = jobId; task->jobId = jobId;
task->taskId = taskId++; task->taskId = taskId++;
task->taskType = SQL_TASK; task->taskType = DDL_TASK;
task->queryString = applyCommand->data; task->queryString = applyCommand->data;
task->replicationModel = REPLICATION_MODEL_INVALID; task->replicationModel = REPLICATION_MODEL_INVALID;
task->dependedTaskList = NULL; task->dependedTaskList = NULL;
@ -2158,7 +2158,7 @@ ForeignKeyTaskList(Oid leftRelationId, Oid rightRelationId,
task = CitusMakeNode(Task); task = CitusMakeNode(Task);
task->jobId = jobId; task->jobId = jobId;
task->taskId = taskId++; task->taskId = taskId++;
task->taskType = SQL_TASK; task->taskType = DDL_TASK;
task->queryString = applyCommand->data; task->queryString = applyCommand->data;
task->dependedTaskList = NULL; task->dependedTaskList = NULL;
task->replicationModel = REPLICATION_MODEL_INVALID; task->replicationModel = REPLICATION_MODEL_INVALID;

View File

@ -18,6 +18,7 @@
#include "distributed/master_metadata_utility.h" #include "distributed/master_metadata_utility.h"
#include "distributed/metadata_cache.h" #include "distributed/metadata_cache.h"
#include "distributed/multi_shard_transaction.h" #include "distributed/multi_shard_transaction.h"
#include "distributed/placement_connection.h"
#include "distributed/shardinterval_utils.h" #include "distributed/shardinterval_utils.h"
#include "distributed/worker_manager.h" #include "distributed/worker_manager.h"
#include "nodes/pg_list.h" #include "nodes/pg_list.h"
@ -25,34 +26,23 @@
#include "utils/memutils.h" #include "utils/memutils.h"
#define INITIAL_CONNECTION_CACHE_SIZE 1001 #define INITIAL_SHARD_CONNECTION_HASH_SIZE 128
/* per-transaction state */
static HTAB *shardConnectionHash = NULL;
/* /*
* OpenTransactionsToAllShardPlacements opens connections to all placements * OpenTransactionsToAllShardPlacements opens connections to all placements
* using the provided shard identifier list. Connections accumulate in a global * using the provided shard identifier list and returns it as a shard ID ->
* shardConnectionHash variable for use (and re-use) within this transaction. * ShardConnections hash. connectionFlags can be used to specify whether
* the command is FOR_DML or FOR_DDL.
*/ */
void HTAB *
OpenTransactionsToAllShardPlacements(List *shardIntervalList, char *userName) OpenTransactionsToAllShardPlacements(List *shardIntervalList, int connectionFlags)
{ {
HTAB *shardConnectionHash = NULL;
ListCell *shardIntervalCell = NULL; ListCell *shardIntervalCell = NULL;
List *newConnectionList = NIL; List *newConnectionList = NIL;
if (shardConnectionHash == NULL) shardConnectionHash = CreateShardConnectionHash(CurrentMemoryContext);
{
shardConnectionHash = CreateShardConnectionHash(TopTransactionContext);
}
BeginOrContinueCoordinatedTransaction();
if (MultiShardCommitProtocol == COMMIT_PROTOCOL_2PC)
{
CoordinatedTransactionUse2PC();
}
/* open connections to shards which don't have connections yet */ /* open connections to shards which don't have connections yet */
foreach(shardIntervalCell, shardIntervalList) foreach(shardIntervalCell, shardIntervalList)
@ -64,7 +54,8 @@ OpenTransactionsToAllShardPlacements(List *shardIntervalList, char *userName)
List *shardPlacementList = NIL; List *shardPlacementList = NIL;
ListCell *placementCell = NULL; ListCell *placementCell = NULL;
shardConnections = GetShardConnections(shardId, &shardConnectionsFound); shardConnections = GetShardHashConnections(shardConnectionHash, shardId,
&shardConnectionsFound);
if (shardConnectionsFound) if (shardConnectionsFound)
{ {
continue; continue;
@ -82,7 +73,6 @@ OpenTransactionsToAllShardPlacements(List *shardIntervalList, char *userName)
{ {
ShardPlacement *shardPlacement = (ShardPlacement *) lfirst(placementCell); ShardPlacement *shardPlacement = (ShardPlacement *) lfirst(placementCell);
MultiConnection *connection = NULL; MultiConnection *connection = NULL;
MemoryContext oldContext = NULL;
WorkerNode *workerNode = FindWorkerNode(shardPlacement->nodeName, WorkerNode *workerNode = FindWorkerNode(shardPlacement->nodeName,
shardPlacement->nodePort); shardPlacement->nodePort);
@ -93,20 +83,15 @@ OpenTransactionsToAllShardPlacements(List *shardIntervalList, char *userName)
shardPlacement->nodePort))); shardPlacement->nodePort)));
} }
connection = StartNodeUserDatabaseConnection(FORCE_NEW_CONNECTION, connection = StartPlacementConnection(connectionFlags,
shardPlacement->nodeName, shardPlacement,
shardPlacement->nodePort, NULL);
userName,
NULL);
/* we need to preserve the connection list for the next statement */ ClaimConnectionExclusively(connection);
oldContext = MemoryContextSwitchTo(TopTransactionContext);
shardConnections->connectionList = lappend(shardConnections->connectionList, shardConnections->connectionList = lappend(shardConnections->connectionList,
connection); connection);
MemoryContextSwitchTo(oldContext);
newConnectionList = lappend(newConnectionList, connection); newConnectionList = lappend(newConnectionList, connection);
/* /*
@ -125,6 +110,8 @@ OpenTransactionsToAllShardPlacements(List *shardIntervalList, char *userName)
{ {
RemoteTransactionsBeginIfNecessary(newConnectionList); RemoteTransactionsBeginIfNecessary(newConnectionList);
} }
return shardConnectionHash;
} }
@ -147,36 +134,13 @@ CreateShardConnectionHash(MemoryContext memoryContext)
hashFlags = (HASH_ELEM | HASH_CONTEXT | HASH_BLOBS); hashFlags = (HASH_ELEM | HASH_CONTEXT | HASH_BLOBS);
shardConnectionsHash = hash_create("Shard Connections Hash", shardConnectionsHash = hash_create("Shard Connections Hash",
INITIAL_CONNECTION_CACHE_SIZE, &info, INITIAL_SHARD_CONNECTION_HASH_SIZE, &info,
hashFlags); hashFlags);
return shardConnectionsHash; return shardConnectionsHash;
} }
/*
* GetShardConnections finds existing connections for a shard in the global
* connection hash. If not found, then a ShardConnections structure with empty
* connectionList is returned and the shardConnectionsFound output parameter
* will be set to false.
*/
ShardConnections *
GetShardConnections(int64 shardId, bool *shardConnectionsFound)
{
ShardConnections *shardConnections = NULL;
ShardInterval *shardInterval = LoadShardInterval(shardId);
List *colocatedShardIds = ColocatedShardIntervalList(shardInterval);
ShardInterval *baseShardInterval = LowestShardIntervalById(colocatedShardIds);
int64 baseShardId = baseShardInterval->shardId;
shardConnections = GetShardHashConnections(shardConnectionHash, baseShardId,
shardConnectionsFound);
return shardConnections;
}
/* /*
* GetShardHashConnections finds existing connections for a shard in the * GetShardHashConnections finds existing connections for a shard in the
* provided hash. If not found, then a ShardConnections structure with empty * provided hash. If not found, then a ShardConnections structure with empty
@ -235,16 +199,37 @@ ShardConnectionList(HTAB *connectionHash)
void void
ResetShardPlacementTransactionState(void) ResetShardPlacementTransactionState(void)
{ {
/*
* Now that transaction management does most of our work, nothing remains
* but to reset the connection hash, which wouldn't be valid next time
* round.
*/
shardConnectionHash = NULL;
if (MultiShardCommitProtocol == COMMIT_PROTOCOL_BARE) if (MultiShardCommitProtocol == COMMIT_PROTOCOL_BARE)
{ {
MultiShardCommitProtocol = SavedMultiShardCommitProtocol; MultiShardCommitProtocol = SavedMultiShardCommitProtocol;
SavedMultiShardCommitProtocol = COMMIT_PROTOCOL_BARE; SavedMultiShardCommitProtocol = COMMIT_PROTOCOL_BARE;
} }
} }
/*
* UnclaimAllShardConnections unclaims all connections in the given
* shard connections hash after previously claiming them exclusively
* in OpenTransactionsToAllShardPlacements.
*/
void
UnclaimAllShardConnections(HTAB *shardConnectionHash)
{
HASH_SEQ_STATUS status;
ShardConnections *shardConnections = NULL;
hash_seq_init(&status, shardConnectionHash);
while ((shardConnections = hash_seq_search(&status)) != 0)
{
List *connectionList = shardConnections->connectionList;
ListCell *connectionCell = NULL;
foreach(connectionCell, connectionList)
{
MultiConnection *connection = (MultiConnection *) lfirst(connectionCell);
UnclaimConnection(connection);
}
}
}

View File

@ -82,7 +82,8 @@ typedef enum
MAP_OUTPUT_FETCH_TASK = 5, MAP_OUTPUT_FETCH_TASK = 5,
MERGE_FETCH_TASK = 6, MERGE_FETCH_TASK = 6,
MODIFY_TASK = 7, MODIFY_TASK = 7,
ROUTER_TASK = 8 ROUTER_TASK = 8,
DDL_TASK = 9
} TaskType; } TaskType;

View File

@ -27,13 +27,14 @@ typedef struct ShardConnections
} ShardConnections; } ShardConnections;
extern void OpenTransactionsToAllShardPlacements(List *shardIdList, char *relationOwner); extern HTAB * OpenTransactionsToAllShardPlacements(List *shardIdList,
int connectionFlags);
extern HTAB * CreateShardConnectionHash(MemoryContext memoryContext); extern HTAB * CreateShardConnectionHash(MemoryContext memoryContext);
extern ShardConnections * GetShardConnections(int64 shardId, bool *shardConnectionsFound);
extern ShardConnections * GetShardHashConnections(HTAB *connectionHash, int64 shardId, extern ShardConnections * GetShardHashConnections(HTAB *connectionHash, int64 shardId,
bool *connectionsFound); bool *connectionsFound);
extern List * ShardConnectionList(HTAB *connectionHash); extern List * ShardConnectionList(HTAB *connectionHash);
extern void ResetShardPlacementTransactionState(void); extern void ResetShardPlacementTransactionState(void);
extern void UnclaimAllShardConnections(HTAB *shardConnectionHash);
#endif /* MULTI_SHARD_TRANSACTION_H */ #endif /* MULTI_SHARD_TRANSACTION_H */