mirror of https://github.com/citusdata/citus.git
183 lines
4.5 KiB
C
183 lines
4.5 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* variableset.c
|
|
* Support for propagation of SET (commands to set variables)
|
|
*
|
|
* Copyright (c) 2019, Citus Data, Inc.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
#include "c.h"
|
|
|
|
#include "common/string.h"
|
|
#include "distributed/commands.h"
|
|
#include "distributed/commands/utility_hook.h"
|
|
#include "distributed/metadata_cache.h"
|
|
#include "distributed/resource_lock.h"
|
|
#include "distributed/transaction_management.h"
|
|
#include "distributed/version_compat.h"
|
|
#include "storage/lmgr.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/lsyscache.h"
|
|
#include "lib/ilist.h"
|
|
#include "utils/varlena.h"
|
|
#include "distributed/remote_commands.h"
|
|
|
|
|
|
static bool IsSettingSafeToPropagate(char *name);
|
|
|
|
|
|
/*
|
|
* ShouldPropagateSetCommand determines whether a SET or RESET command should be
|
|
* propagated to the workers.
|
|
*
|
|
* We currently propagate:
|
|
* - SET LOCAL (for allowed settings)
|
|
* - RESET (for allowed settings)
|
|
* - RESET ALL
|
|
*/
|
|
bool
|
|
ShouldPropagateSetCommand(VariableSetStmt *setStmt)
|
|
{
|
|
if (PropagateSetCommands != PROPSETCMD_LOCAL)
|
|
{
|
|
/* SET propagation is disabled */
|
|
return false;
|
|
}
|
|
|
|
switch (setStmt->kind)
|
|
{
|
|
case VAR_SET_VALUE:
|
|
case VAR_SET_CURRENT:
|
|
case VAR_SET_DEFAULT:
|
|
{
|
|
/* SET LOCAL on a safe setting */
|
|
return setStmt->is_local && IsSettingSafeToPropagate(setStmt->name);
|
|
}
|
|
|
|
case VAR_RESET:
|
|
{
|
|
/* may need to reset prior SET LOCAL */
|
|
return IsSettingSafeToPropagate(setStmt->name);
|
|
}
|
|
|
|
case VAR_RESET_ALL:
|
|
{
|
|
/* always propagate RESET ALL since it might affect prior SET LOCALs */
|
|
return true;
|
|
}
|
|
|
|
case VAR_SET_MULTI:
|
|
default:
|
|
{
|
|
/* SET (LOCAL) TRANSACTION should be handled locally */
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* IsSettingSafeToPropagate returns whether a SET LOCAL is safe to propagate.
|
|
*
|
|
* We exclude settings that are highly specific to the client or session and also
|
|
* ban propagating the citus.propagate_set_commands setting (not for correctness,
|
|
* more to avoid confusion).
|
|
*/
|
|
static bool
|
|
IsSettingSafeToPropagate(char *name)
|
|
{
|
|
/* if this list grows considerably we should switch to bsearch */
|
|
const char *skipSettings[] = {
|
|
"citus.propagate_set_commands",
|
|
"client_encoding",
|
|
"exit_on_error",
|
|
"max_stack_depth"
|
|
};
|
|
|
|
for (Index settingIndex = 0; settingIndex < lengthof(skipSettings); settingIndex++)
|
|
{
|
|
if (pg_strcasecmp(skipSettings[settingIndex], name) == 0)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/*
|
|
* ProcessVariableSetStmt actually does the work of propagating a provided SET stmt
|
|
* to currently-participating worker nodes and adding the SET command test to a string
|
|
* keeping track of all propagated SET commands since (sub-)xact start.
|
|
*/
|
|
void
|
|
ProcessVariableSetStmt(VariableSetStmt *setStmt, const char *setStmtString)
|
|
{
|
|
dlist_iter iter;
|
|
const bool raiseInterrupts = true;
|
|
List *connectionList = NIL;
|
|
|
|
/* at present we only support SET LOCAL */
|
|
AssertArg(ShouldPropagateSetCommand(setStmt));
|
|
|
|
/* haven't seen any SET stmts so far in this (sub-)xact: initialize StringInfo */
|
|
if (activeSetStmts == NULL)
|
|
{
|
|
MemoryContext old_context = MemoryContextSwitchTo(CurTransactionContext);
|
|
activeSetStmts = makeStringInfo();
|
|
MemoryContextSwitchTo(old_context);
|
|
}
|
|
|
|
/* send text of SET stmt to participating nodes... */
|
|
dlist_foreach(iter, &InProgressTransactions)
|
|
{
|
|
MultiConnection *connection = dlist_container(MultiConnection, transactionNode,
|
|
iter.cur);
|
|
|
|
RemoteTransaction *transaction = &connection->remoteTransaction;
|
|
if (transaction->transactionFailed)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!SendRemoteCommand(connection, setStmtString))
|
|
{
|
|
const bool raiseErrors = true;
|
|
HandleRemoteTransactionConnectionError(connection, raiseErrors);
|
|
}
|
|
|
|
connectionList = lappend(connectionList, connection);
|
|
}
|
|
|
|
WaitForAllConnections(connectionList, raiseInterrupts);
|
|
|
|
/* ... and wait for the results */
|
|
dlist_foreach(iter, &InProgressTransactions)
|
|
{
|
|
MultiConnection *connection = dlist_container(MultiConnection, transactionNode,
|
|
iter.cur);
|
|
const bool raiseErrors = true;
|
|
|
|
RemoteTransaction *transaction = &connection->remoteTransaction;
|
|
if (transaction->transactionFailed)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ClearResults(connection, raiseErrors);
|
|
}
|
|
|
|
/* SET propagation successful: add to active SET stmt string */
|
|
appendStringInfoString(activeSetStmts, setStmtString);
|
|
|
|
/* ensure semicolon on end to allow appending future SET stmts */
|
|
if (!pg_str_endswith(setStmtString, ";"))
|
|
{
|
|
appendStringInfoChar(activeSetStmts, ';');
|
|
}
|
|
}
|