diff options
author | Michael P | 2011-12-01 04:21:25 +0000 |
---|---|---|
committer | Michael P | 2011-12-01 04:21:25 +0000 |
commit | 6fbceecbfedd310d539d4fefe5e75f05b69c6805 (patch) | |
tree | 326a7063dadfdcbf151a62dc9ba538cfe1528e15 | |
parent | a43534d7519176e6dcdaf4517b329c2fed935c8b (diff) |
Support for dynamic pooler/session connection information cache reload
A new system function called pgxc_pool_reload has been added.
If called, this function reloads connection information to remote nodes
in a consistent way with the following process:
1) A lock is taken on pooler forbidding new connection requests
2) Database pools (user and database-dependant pools) are reloaded
depending on the node information located on catalog pgxc_node.
The following rules are followed depending on node connection
information modification:
- node whose node and port value is changed has its connections
dropped and this node pool is deleted from each database pool
- node deleted is deleted from each database pool
- node unchanged is kept as is. However, its index value is changed
depending on the new cluster configuration.
- node created is added to each database pool
3) Lock is released
4) Session that invocated pgxc_pool_reload signals all the other
server sessions to reconnect to pooler to allow each agent to update
with newest connection information and reload session information
related to remote node handles. This has as effect to abort current
transactions and to remove all the temporary and prepared objects
on session. Then a WARNING message is sent back to client to inform
about the cluster configuration modification.
5) Session that invocated pgxc_pool_reload reconnects to pooler by
itself and reloads its session information related to remote
node handles. No WARNING message is sent back to client to inform
about the session reload.
This operation is limited to local Coordinator and returns a boolean
depending on the success of the operation. If pooler data is consistent
with catalog information when pgxc_pool_reload is invocated, nothing is
done but a success message is returned.
This has the following siplifications for cluster settings:
- cluster_nodes.sql is deleted.
- a new mandatory option --nodename is used to specify the node name
of the node initialized. This allows to set up pgxc_node catalog
with the node itself. pgxc_node_name in postgresql.conf is also
set automatically.
- CREATE/ALTER/DROP node are launched on local Coordinator only, meaning
that when a cluster is set up, it is necessary to create node information
on each Coordinator and then upload this information to pooler and sessions
by invocaing pgxc_pool_reload.
This optimization avoids to have to restart a Coordinator when changing
cluster configuration and solves security problems related to cluster_nodes.sql
that could be edited with all types of SQL even if its first target was only NODE
DDL.
23 files changed, 767 insertions, 107 deletions
diff --git a/doc-xc/src/sgml/func.sgmlin b/doc-xc/src/sgml/func.sgmlin index 07dab181eb..bc0392e2d6 100644 --- a/doc-xc/src/sgml/func.sgmlin +++ b/doc-xc/src/sgml/func.sgmlin @@ -15350,6 +15350,13 @@ SELECT (pg_stat_file('filename')).modification; <link linkend="catalog-pgxc-node"><structname>pgxc_node</structname></link>. </entry> </row> + <row> + <entry> + <literal><function>pgxc_pool_reload()</function></literal> + </entry> + <entry><type>boolean</type></entry> + <entry>Reload connection data cached in pooler and reload sessions in server</entry> + </row> </tbody> </tgroup> </table> @@ -15364,6 +15371,16 @@ SELECT (pg_stat_file('filename')).modification; node port (<literal><link linkend="catalog-pgxc-node"><structname>pgxc_node</structname></link>.node_port</literal>) and node host (<literal><link linkend="catalog-pgxc-node"><structname>pgxc_node</structname></link>.node_host</literal>). </para> + <indexterm> + <primary>pgxc_pool_reload</primary> + </indexterm> + <para> + <function>pgxc_pool_reload</> reloads connection data cached in pooler from + <link linkend="catalog-pgxc-node"><structname>pgxc_node</structname></link> catalog + and reloads all the information info cached in pooler. All the active transactions + are aborted and all existing pooler connections are dropped. This results in having + all the temporary and prepared objects dropped on remote and local node for session. + </para> &xconly; <para> diff --git a/doc-xc/src/sgml/ref/alter_node.sgmlin b/doc-xc/src/sgml/ref/alter_node.sgmlin index 14a082ec1c..59b58a5d7d 100644 --- a/doc-xc/src/sgml/ref/alter_node.sgmlin +++ b/doc-xc/src/sgml/ref/alter_node.sgmlin @@ -44,6 +44,9 @@ ALTER NODE <replaceable class="parameter">nodename</replaceable> SET Node connection that has been modified does not guarranty that connection information cached in pooler is updated accordingly. </para> + <para> + <command>ALTER NODE</command> only runs on the local node where it is launched. + </para> </refsect1> diff --git a/doc-xc/src/sgml/ref/create_node.sgmlin b/doc-xc/src/sgml/ref/create_node.sgmlin index 7ca1d7e8ee..8076a3eddd 100644 --- a/doc-xc/src/sgml/ref/create_node.sgmlin +++ b/doc-xc/src/sgml/ref/create_node.sgmlin @@ -53,6 +53,9 @@ CREATE NODE <replaceable class="parameter">nodename</replaceable> WITH Node connection information is created on pooler only if it has not been the case yet on Coordinator connected at the moment of connection. </para> + <para> + <command>CREATE NODE</command> only runs on the local node where it is launched. + </para> </refsect1> diff --git a/doc-xc/src/sgml/ref/drop_node.sgmlin b/doc-xc/src/sgml/ref/drop_node.sgmlin index f91ec08f5b..f2dc66bf6e 100644 --- a/doc-xc/src/sgml/ref/drop_node.sgmlin +++ b/doc-xc/src/sgml/ref/drop_node.sgmlin @@ -40,6 +40,9 @@ DROP NODE <replaceable class="parameter">nodename</replaceable> Node connection that has been deleted does not guarranty that connection information cached in pooler is updated accordingly. </para> + <para> + <command>DROP NODE</command> only runs on the local node where it is launched. + </para> </refsect1> diff --git a/doc-xc/src/sgml/ref/initdb.sgmlin b/doc-xc/src/sgml/ref/initdb.sgmlin index 96efe12803..92288b9586 100644 --- a/doc-xc/src/sgml/ref/initdb.sgmlin +++ b/doc-xc/src/sgml/ref/initdb.sgmlin @@ -28,6 +28,7 @@ PostgreSQL documentation <cmdsynopsis> <command>initdb</command> <arg rep="repeat"><replaceable>option</replaceable></arg> + <arg>--nodename <replaceable>nodename</replaceable></arg> <group choice="plain"> <arg>--pgdata</arg> <arg>-D </arg> @@ -161,6 +162,20 @@ PostgreSQL documentation </listitem> </varlistentry> +<!## XC> + <varlistentry> + <term><option>--nodename=<replaceable class="parameter">nodename</replaceable></option></term> + <listitem> + <para> + Set the name of Postgres-XC node initialized. This option is mandatory when setting a node. + It permits to define the node itself in cluster node catalog + <link linkend="catalog-pgxc-node"><structname>pgxc_node</structname></link>. The node name + specified is also added in <filename>postgresql.conf</> as value of <varname>pgxc_node_name</>. + </para> + </listitem> + </varlistentry> +<!## end> + <varlistentry> <term><option>-E <replaceable class="parameter">encoding</replaceable></option></term> <term><option>--encoding=<replaceable class="parameter">encoding</replaceable></option></term> diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index 82a4a826ba..c30dccc3c4 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -68,14 +68,13 @@ install-data: $(BKIFILES) installdirs $(INSTALL_DATA) $(srcdir)/system_views.sql '$(DESTDIR)$(datadir)/system_views.sql' $(INSTALL_DATA) $(srcdir)/information_schema.sql '$(DESTDIR)$(datadir)/information_schema.sql' $(INSTALL_DATA) $(srcdir)/sql_features.txt '$(DESTDIR)$(datadir)/sql_features.txt' - $(INSTALL_DATA) $(srcdir)/cluster_nodes.sql '$(DESTDIR)$(datadir)/cluster_nodes.sql' installdirs: $(MKDIR_P) '$(DESTDIR)$(datadir)' .PHONY: uninstall-data uninstall-data: - rm -f $(addprefix '$(DESTDIR)$(datadir)'/, $(BKIFILES) system_views.sql information_schema.sql sql_features.txt cluster_nodes.sql) + rm -f $(addprefix '$(DESTDIR)$(datadir)'/, $(BKIFILES) system_views.sql information_schema.sql sql_features.txt) # postgres.bki, postgres.description, postgres.shdescription, and schemapg.h # are in the distribution tarball, so they are not cleaned here. diff --git a/src/backend/catalog/cluster_nodes.sql b/src/backend/catalog/cluster_nodes.sql deleted file mode 100644 index 1cb1bf2de9..0000000000 --- a/src/backend/catalog/cluster_nodes.sql +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Postgres-XC Cluster information - * - * Copyright (c) 1996-2011, PostgreSQL Global Development Group - * Portions Copyright (c) 2010-2011 Nippon Telegraph and Telephone Corporation - * - * src/backend/catalog/cluster_nodes.sql - */ - --- PGXC default catalog node entries -CREATE NODE COORD_1 WITH (HOSTIP = 'localhost', COORDINATOR MASTER, NODEPORT = 5432); -CREATE NODE DATA_NODE_1 WITH (HOSTIP = 'localhost', NODE MASTER, NODEPORT = 15432); -CREATE NODE DATA_NODE_2 WITH (HOSTIP = 'localhost', NODE MASTER, NODEPORT = 25432); diff --git a/src/backend/pgxc/nodemgr/nodemgr.c b/src/backend/pgxc/nodemgr/nodemgr.c index 74f83ac959..64ed0fabcd 100644 --- a/src/backend/pgxc/nodemgr/nodemgr.c +++ b/src/backend/pgxc/nodemgr/nodemgr.c @@ -25,6 +25,7 @@ #include "utils/tqual.h" #include "pgxc/locator.h" #include "pgxc/nodemgr.h" +#include "pgxc/pgxc.h" /* Global number of nodes */ int NumDataNodes = 2; @@ -144,6 +145,10 @@ PgxcNodeListAndCount(Oid **coOids, Oid **dnOids, Oid **coslaveOids, Oid **dnslav *num_co_slaves = 0; *num_dn_slaves = 0; + /* Don't forget to reinitialize primary and preferred nodes also */ + primary_data_node = InvalidOid; + num_preferred_data_nodes = 0; + /* * Node information initialization is made in one scan: * 1) Scan pgxc_node catalog to find the number of nodes for @@ -674,6 +679,12 @@ PgxcNodeRemove(DropNodeStmt *stmt) errmsg("PGXC Node %s: object not defined", node_name))); + if (strcmp(node_name, PGXCNodeName) == 0) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("PGXC Node %s: cannot drop local node", + node_name))); + /* PGXCTODO: * Is there any group which has this node as member * XC Tables will also have this as a member in their array diff --git a/src/backend/pgxc/pool/pgxcnode.c b/src/backend/pgxc/pool/pgxcnode.c index 2e82b686d1..b1c1f84997 100644 --- a/src/backend/pgxc/pool/pgxcnode.c +++ b/src/backend/pgxc/pool/pgxcnode.c @@ -72,6 +72,7 @@ static PGXCNodeHandle *co_slave_handles = NULL; static void pgxc_node_init(PGXCNodeHandle *handle, int sock); static void pgxc_node_free(PGXCNodeHandle *handle); +static void pgxc_node_all_free(void); static int get_int(PGXCNodeHandle * conn, size_t len, int *out); static int get_char(PGXCNodeHandle * conn, char *out); @@ -114,11 +115,15 @@ init_pgxc_handle(PGXCNodeHandle *pgxc_handle) * Allocate and initialize memory to store Datanode and Coordinator handles. */ void -InitMultinodeExecutor(void) +InitMultinodeExecutor(bool is_force) { int count; Oid *coOids, *dnOids, *coslaveOids, *dnslaveOids; + /* Free all the existing information first */ + if (is_force) + pgxc_node_all_free(); + /* This function could get called multiple times because of sigjmp */ if (dn_handles != NULL && co_handles != NULL && @@ -310,6 +315,55 @@ pgxc_node_free(PGXCNodeHandle *handle) handle->sock = NO_SOCKET; } +/* + * Free all the node handles cached + */ +static void +pgxc_node_all_free(void) +{ + int i, j; + + for (i = 0; i < 4; i++) + { + int num_nodes; + PGXCNodeHandle *array_handles; + + switch (i) + { + case 0: + num_nodes = NumCoords; + array_handles = co_handles; + break; + case 1: + num_nodes = NumDataNodes; + array_handles = dn_handles; + break; + case 2: + num_nodes = NumCoordSlaves; + array_handles = co_slave_handles; + break; + case 3: + num_nodes = NumDataNodeSlaves; + array_handles = dn_slave_handles; + break; + default: + Assert(0); + } + /* Coordinator masters */ + for (j = 0; j < num_nodes; j++) + { + PGXCNodeHandle *handle = &array_handles[j]; + pgxc_node_free(handle); + } + if (array_handles) + pfree(array_handles); + } + + co_handles = NULL; + dn_handles = NULL; + co_slave_handles = NULL; + dn_slave_handles = NULL; +} /* * Create and initialise internal structure to communicate to diff --git a/src/backend/pgxc/pool/poolmgr.c b/src/backend/pgxc/pool/poolmgr.c index 43fa441025..b7e3a861f3 100644 --- a/src/backend/pgxc/pool/poolmgr.c +++ b/src/backend/pgxc/pool/poolmgr.c @@ -39,6 +39,7 @@ #include "libpq/pqsignal.h" #include "miscadmin.h" #include "catalog/pgxc_node.h" +#include "commands/dbcommands.h" #include "nodes/nodes.h" #include "pgxc/poolmgr.h" #include "utils/builtins.h" @@ -95,9 +96,10 @@ static PoolAgent **poolAgents; static PoolHandle *poolHandle = NULL; -static int is_pool_cleaning = false; +static int is_pool_locked = false; static int server_fd = -1; +static void node_info_free(void); static void node_info_load(void); static int node_info_check(void); static void agent_init(PoolAgent *agent, const char *database, const char *user_name); @@ -114,6 +116,7 @@ static int agent_temp_command(PoolAgent *agent); static DatabasePool *create_database_pool(const char *database, const char *user_name); static void insert_database_pool(DatabasePool *pool); static int destroy_database_pool(const char *database, const char *user_name); +static void reload_database_pools(void); static DatabasePool *find_database_pool(const char *database, const char *user_name); static DatabasePool *find_database_pool_to_clean(const char *database, const char *user_name, @@ -234,6 +237,42 @@ PoolManagerInit() } /* + * Free connection info cached + */ +static void +node_info_free(void) +{ + int count; + + for (count = 0; count < NumCoords; count++) + pfree(coord_connInfos[count].host); + for (count = 0; count < NumCoordSlaves; count++) + pfree(coord_slave_connInfos[count].host); + for (count = 0; count < NumDataNodes; count++) + pfree(datanode_connInfos[count].host); + for (count = 0; count < NumDataNodeSlaves; count++) + pfree(datanode_slave_connInfos[count].host); + + if (datanode_connInfos) + pfree(datanode_connInfos); + if (coord_connInfos) + pfree(coord_connInfos); + if (coord_slave_connInfos) + pfree(coord_slave_connInfos); + if (datanode_slave_connInfos) + pfree(datanode_slave_connInfos); + + NumCoords = 0; + NumDataNodes = 0; + NumDataNodeSlaves = 0; + NumCoordSlaves = 0; + datanode_slave_connInfos = NULL; + coord_slave_connInfos = NULL; + coord_connInfos = NULL; + datanode_connInfos = NULL; +} + +/* * Load node info cached by scanning PGXC node catalog */ static void @@ -251,8 +290,8 @@ node_info_load(void) /* Then initialize the node informations */ if (NumDataNodes != 0) - datanode_connInfos = (PGXCNodeConnectionInfo *) - palloc(NumDataNodes * sizeof(PGXCNodeConnectionInfo)); + datanode_connInfos = (PGXCNodeConnectionInfo *) + palloc(NumDataNodes * sizeof(PGXCNodeConnectionInfo)); if (NumCoords != 0) coord_connInfos = (PGXCNodeConnectionInfo *) palloc(NumCoords * sizeof(PGXCNodeConnectionInfo)); @@ -260,7 +299,7 @@ node_info_load(void) coord_slave_connInfos = (PGXCNodeConnectionInfo *) palloc(NumCoordSlaves * sizeof(PGXCNodeConnectionInfo)); if (NumDataNodeSlaves != 0) - coord_slave_connInfos = (PGXCNodeConnectionInfo *) + datanode_slave_connInfos = (PGXCNodeConnectionInfo *) palloc(NumDataNodeSlaves * sizeof(PGXCNodeConnectionInfo)); /* Fill in connection info structures */ @@ -505,6 +544,8 @@ agent_create(void) agent->port.RecvPointer = 0; agent->port.SendPointer = 0; agent->pool = NULL; + agent->num_dn_connections = NumDataNodes; + agent->num_coord_connections = NumCoords; agent->dn_connections = NULL; agent->coord_connections = NULL; agent->session_params = NULL; @@ -562,6 +603,24 @@ PoolManagerConnect(PoolHandle *handle, const char *database, const char *user_na pool_flush(&handle->port); } +/* + * Reconnect to pool manager + * It simply does a disconnection and a reconnection. + */ +void +PoolManagerReconnect(void) +{ + PoolHandle *handle; + + Assert(poolHandle); + + PoolManagerDisconnect(); + handle = GetPoolManagerHandle(); + PoolManagerConnect(handle, + get_database_name(MyDatabaseId), + GetUserNameFromId(GetUserId())); +} + int PoolManagerSetCommand(PoolCommandType command_type, const char *set_command) { @@ -609,6 +668,31 @@ PoolManagerSetCommand(PoolCommandType command_type, const char *set_command) return res; } +/* + * Lock/unlock pool manager + * During locking, the only operations not permitted are abort, connection and + * connection obtention. + */ +void +PoolManagerLock(bool is_lock) +{ + char msgtype = 'o'; + int n32; + int msglen = 8; + Assert(poolHandle); + + /* Message type */ + pool_putbytes(&poolHandle->port, &msgtype, 1); + + /* Message length */ + n32 = htonl(msglen); + pool_putbytes(&poolHandle->port, (char *) &n32, 4); + + /* Lock information */ + n32 = htonl((int) is_lock); + pool_putbytes(&poolHandle->port, (char *) &n32, 4); + pool_flush(&poolHandle->port); +} /* * Init PoolAgent @@ -711,6 +795,7 @@ PoolManagerDisconnect(void) pool_flush(&poolHandle->port); close(Socket(poolHandle->port)); + poolHandle = NULL; } @@ -913,6 +998,18 @@ PoolManagerCheckConnectionInfo(void) /* + * Reload connection data in pooler and drop all the existing connections of pooler + */ +void +PoolManagerReloadConnectionInfo(void) +{ + Assert(poolHandle); + pool_putmessage(&poolHandle->port, 'p', NULL, 0); + pool_flush(&poolHandle->port); +} + + +/* * Handle messages to agent */ static void @@ -945,8 +1042,8 @@ agent_handle_input(PoolAgent * agent, StringInfo s) * while remaining transactions are aborted during FORCE and then * Pools are being shrinked. */ - if (is_pool_cleaning && (qtype == 'a' || qtype == 'c' || qtype == 'g')) - elog(WARNING,"Pool operation cannot run during Pool cleaning"); + if (is_pool_locked && (qtype == 'a' || qtype == 'c' || qtype == 'g')) + elog(WARNING,"Pool operation cannot run during pool lock"); switch (qtype) { @@ -1072,6 +1169,44 @@ agent_handle_input(PoolAgent * agent, StringInfo s) list_free(datanodelist); list_free(coordlist); break; + case 'o': /* Lock/unlock pooler */ + pool_getmessage(&agent->port, s, 8); + is_pool_locked = pq_getmsgint(s, 4); + pq_getmsgend(s); + break; + case 'p': /* Reload connection info */ + /* + * Connection information reloaded concerns all the database pools. + * A database pool is reloaded as follows for each remote node: + * - node pool is deleted if the node has been deleted from catalog. + * Subsequently all its connections are dropped. + * - node pool is deleted if its port or host information is changed. + * Subsequently all its connections are dropped. + * - node pool is kept unchanged with existing connection information + * is not changed. However its index position in node pool is changed + * according to the alphabetical order of the node name in new + * cluster configuration. + * Backend sessions are responsible to reconnect to the pooler to update + * their agent with newest connection information. + * The session invocating connection information reload is reconnected + * and uploaded automatically after database pool reload. + * Other server sessions are signaled to reconnect to pooler and update + * their connection information separately. + * During reload process done internally on pooler, pooler is locked + * to forbid new connection requests. + */ + pool_getmessage(&agent->port, s, 4); + pq_getmsgend(s); + + /* Free all the node info before reloading */ + node_info_free(); + + /* Reload node information */ + node_info_load(); + + /* First update all the pools */ + reload_database_pools(); + break; case 'q': /* Check connection info consistency */ pool_getmessage(&agent->port, s, 4); pq_getmsgend(s); @@ -1201,7 +1336,7 @@ agent_set_command(PoolAgent *agent, const char *set_command, PoolCommandType com /* Launch the new command to all the connections already hold by the agent */ if (agent->dn_connections) { - for (i = 0; i < NumDataNodes; i++) + for (i = 0; i < agent->num_dn_connections; i++) { if (agent->dn_connections[i]) res = PGXCNodeSendSetQuery(agent->dn_connections[i]->conn, set_command); @@ -1210,7 +1345,7 @@ agent_set_command(PoolAgent *agent, const char *set_command, PoolCommandType com if (agent->coord_connections) { - for (i = 0; i < NumCoords; i++) + for (i = 0; i < agent->num_coord_connections; i++) { if (agent->coord_connections[i]) res |= PGXCNodeSendSetQuery(agent->coord_connections[i]->conn, set_command); @@ -1238,6 +1373,11 @@ agent_acquire_connections(PoolAgent *agent, List *datanodelist, List *coordlist) Assert(agent); + /* Check if pooler can accept those requests */ + if (list_length(datanodelist) > NumDataNodes || + list_length(coordlist) > NumCoords) + return NULL; + /* * Allocate memory * File descriptors of Datanodes and Coordinators are saved in the same array, @@ -1261,7 +1401,7 @@ agent_acquire_connections(PoolAgent *agent, List *datanodelist, List *coordlist) if (!agent->dn_connections) { agent->dn_connections = (PGXCNodePoolSlot **) - palloc(NumDataNodes * sizeof(PGXCNodePoolSlot *)); + palloc(agent->num_dn_connections * sizeof(PGXCNodePoolSlot *)); if (!agent->dn_connections) { pfree(result); @@ -1271,14 +1411,15 @@ agent_acquire_connections(PoolAgent *agent, List *datanodelist, List *coordlist) return NULL; } - for (i = 0; i < NumDataNodes; i++) + for (i = 0; i < agent->num_dn_connections; i++) agent->dn_connections[i] = NULL; } /* Then for the Coordinators */ if (!agent->coord_connections) { - agent->coord_connections = (PGXCNodePoolSlot **)palloc(NumCoords * sizeof(PGXCNodePoolSlot *)); + agent->coord_connections = (PGXCNodePoolSlot **) + palloc(agent->num_coord_connections * sizeof(PGXCNodePoolSlot *)); if (!agent->coord_connections) { pfree(result); @@ -1288,7 +1429,7 @@ agent_acquire_connections(PoolAgent *agent, List *datanodelist, List *coordlist) return NULL; } - for (i = 0; i < NumCoords; i++) + for (i = 0; i < agent->num_coord_connections; i++) agent->coord_connections[i] = NULL; } @@ -1502,7 +1643,7 @@ agent_release_connections(PoolAgent *agent, bool force_destroy) * Remaining connections are assumed to be clean. * First clean up for Datanodes */ - for (i = 0; i < NumDataNodes; i++) + for (i = 0; i < agent->num_dn_connections; i++) { PGXCNodePoolSlot *slot = agent->dn_connections[i]; @@ -1515,7 +1656,7 @@ agent_release_connections(PoolAgent *agent, bool force_destroy) agent->dn_connections[i] = NULL; } /* Then clean up for Coordinator connections */ - for (i = 0; i < NumCoords; i++) + for (i = 0; i < agent->num_coord_connections; i++) { PGXCNodePoolSlot *slot = agent->coord_connections[i]; @@ -1551,7 +1692,7 @@ agent_reset_session(PoolAgent *agent) /* Check agent slot for each Datanode */ if (agent->dn_connections) { - for (i = 0; i < NumDataNodes; i++) + for (i = 0; i < agent->num_dn_connections; i++) { PGXCNodePoolSlot *slot = agent->dn_connections[i]; @@ -1564,7 +1705,7 @@ agent_reset_session(PoolAgent *agent) if (agent->coord_connections) { /* Check agent slot for each Coordinator */ - for (i = 0; i < NumCoords; i++) + for (i = 0; i < agent->num_coord_connections; i++) { PGXCNodePoolSlot *slot = agent->coord_connections[i]; @@ -1640,38 +1781,55 @@ create_database_pool(const char *database, const char *user_name) databasePool->next = NULL; /* Init Datanode pools */ - databasePool->dataNodePools = (PGXCNodePool **) palloc(NumDataNodes * sizeof(PGXCNodePool **)); - if (!databasePool->dataNodePools) + if (NumDataNodes != 0) { - /* out of memory */ - ereport(ERROR, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); - pfree(databasePool->database); - pfree(databasePool->user_name); - pfree(databasePool); - return NULL; + databasePool->dataNodePools = + (PGXCNodePool **) palloc(NumDataNodes * sizeof(PGXCNodePool **)); + if (!databasePool->dataNodePools) + { + /* out of memory */ + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); + pfree(databasePool->database); + pfree(databasePool->user_name); + pfree(databasePool); + return NULL; + } + + for (i = 0; i < NumDataNodes; i++) + databasePool->dataNodePools[i] = NULL; } + else + databasePool->dataNodePools = NULL; - for (i = 0; i < NumDataNodes; i++) - databasePool->dataNodePools[i] = NULL; /* Init Coordinator pools */ - databasePool->coordNodePools = (PGXCNodePool **) palloc(NumCoords * sizeof(PGXCNodePool **)); - if (!databasePool->coordNodePools) + if (NumCoords != 0) { - /* out of memory */ - ereport(ERROR, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); - pfree(databasePool->database); - pfree(databasePool->user_name); - pfree(databasePool); - return NULL; + databasePool->coordNodePools = (PGXCNodePool **) palloc(NumCoords * sizeof(PGXCNodePool **)); + if (!databasePool->coordNodePools) + { + /* out of memory */ + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); + pfree(databasePool->database); + pfree(databasePool->user_name); + pfree(databasePool); + return NULL; + } + + + for (i = 0; i < NumCoords; i++) + databasePool->coordNodePools[i] = NULL; } + else + databasePool->coordNodePools = NULL; - for (i = 0; i < NumCoords; i++) - databasePool->coordNodePools[i] = NULL; + /* Save number of node pool */ + databasePool->num_dn_pools = NumDataNodes; + databasePool->num_co_pools = NumCoords; /* Insert into the list */ insert_database_pool(databasePool); @@ -1735,6 +1893,145 @@ insert_database_pool(DatabasePool *databasePool) databasePools = databasePool; } +/* + * Rebuild information of database pools + */ +static void +reload_database_pools(void) +{ + DatabasePool *databasePool; + + /* Scan the list and reload each pool */ + databasePool = databasePools; + while (databasePool) + { + /* Update each database pool slot with new connection information */ + int i; + bool co_slot_used[databasePool->num_co_pools]; + bool dn_slot_used[databasePool->num_dn_pools]; + int new_co_num = NumCoords; + int new_dn_num = NumDataNodes; + PGXCNodePool **new_co_pools = NULL; + PGXCNodePool **new_dn_pools = NULL; + + new_co_pools = (PGXCNodePool **) palloc(new_co_num * sizeof(PGXCNodePool **)); + new_dn_pools = (PGXCNodePool **) palloc(new_dn_num * sizeof(PGXCNodePool **)); + + /* Check on the database pools that have been reused */ + for (i = 0; i < databasePool->num_co_pools; i++) + co_slot_used[i] = false; + for (i = 0; i < databasePool->num_dn_pools; i++) + dn_slot_used[i] = false; + + for (i = 0; i < new_co_num; i++) + { + int j; + Oid nodeoid_check = coord_connInfos[i].nodeoid; + bool is_found = false; + int index_id = 0; + char *connstr_chk = PGXCNodeConnStr(coord_connInfos[i].host, + coord_connInfos[i].port, + databasePool->database, + databasePool->user_name, + "coordinator"); + + /* Scan for pool existence */ + for (j = 0; j < databasePool->num_co_pools; j++) + { + PGXCNodePool *pool = databasePool->coordNodePools[j]; + if (!pool) + continue; + + /* + * Node Oid and connection string has to be the same + * to ensure consistency. + */ + if (pool->nodeoid == nodeoid_check && + strcmp(pool->connstr, connstr_chk) == 0) + { + co_slot_used[j] = true; + is_found = true; + index_id = j; + break; + } + } + + if (co_slot_used[index_id] && + databasePool->coordNodePools && + is_found) + { + new_co_pools[i] = databasePool->coordNodePools[index_id]; + } + else + new_co_pools[i] = NULL; + pfree(connstr_chk); + } + for (i = 0; i < new_dn_num; i++) + { + int j; + Oid nodeoid_check = datanode_connInfos[i].nodeoid; + int index_id = 0; + bool is_found = false; + char *connstr_chk = PGXCNodeConnStr(datanode_connInfos[i].host, + datanode_connInfos[i].port, + databasePool->database, + databasePool->user_name, + "coordinator"); + + /* Scan for pool existence */ + for (j = 0; j < databasePool->num_dn_pools; j++) + { + PGXCNodePool *pool = databasePool->dataNodePools[j]; + + if (!pool) + continue; + + if (pool->nodeoid == nodeoid_check && + strcmp(pool->connstr, connstr_chk) == 0) + { + dn_slot_used[j] = true; + is_found = true; + index_id = j; + break; + } + } + + if (dn_slot_used[index_id] && + databasePool->dataNodePools && + is_found) + { + new_dn_pools[i] = databasePool->dataNodePools[index_id]; + } + else + new_dn_pools[i] = NULL; + pfree(connstr_chk); + } + + /* Clean up node pools that are not necessary anymore */ + for (i = 0; i < databasePool->num_co_pools; i++) + { + if (!co_slot_used[i]) + destroy_node_pool(databasePool->coordNodePools[i]); + } + for (i = 0; i < databasePool->num_dn_pools; i++) + { + if (!dn_slot_used[i]) + destroy_node_pool(databasePool->dataNodePools[i]); + } + if (databasePool->coordNodePools) + pfree(databasePool->coordNodePools); + if (databasePool->dataNodePools) + pfree(databasePool->dataNodePools); + + /* Update new database pool */ + databasePool->num_co_pools = new_co_num; + databasePool->num_dn_pools = new_dn_num; + databasePool->coordNodePools = new_co_pools; + databasePool->dataNodePools = new_dn_pools; + databasePool = databasePool->next; + } +} + /* * Find pool for specified database and username in the list @@ -1865,6 +2162,18 @@ acquire_connection(DatabasePool *dbPool, int node, char client_conn_type) Assert(dbPool); + /* Manage the case where pool is not ready */ + if (node >= NumCoords && client_conn_type == REMOTE_CONN_COORD) + { + elog(WARNING, "can not connect to coordinator %d", node); + return NULL; + } + if (node >= NumDataNodes && client_conn_type == REMOTE_CONN_DATANODE) + { + elog(WARNING, "can not connect to datanode %d", node); + return NULL; + } + if (client_conn_type == REMOTE_CONN_DATANODE) Assert(0 <= node && node < NumDataNodes); else if (client_conn_type == REMOTE_CONN_COORD) @@ -1929,7 +2238,7 @@ acquire_connection(DatabasePool *dbPool, int node, char client_conn_type) if (slot == NULL) { if (client_conn_type == REMOTE_CONN_DATANODE) - elog(WARNING, "can not connect to data node %d", node); + elog(WARNING, "can not connect to datanode %d", node); else if (client_conn_type == REMOTE_CONN_COORD) elog(WARNING, "can not connect to coordinator %d", node); } @@ -2025,13 +2334,9 @@ grow_pool(DatabasePool * dbPool, int index, char client_conn_type) * but Dn->Dn Connections could be used for other purposes. */ if (IS_PGXC_COORDINATOR) - { remote_type = pstrdup("coordinator"); - } else if (IS_PGXC_DATANODE) - { remote_type = pstrdup("datanode"); - } if (client_conn_type == REMOTE_CONN_DATANODE) /* initialize it */ @@ -2070,9 +2375,15 @@ grow_pool(DatabasePool * dbPool, int index, char client_conn_type) /* and insert into the array */ if (client_conn_type == REMOTE_CONN_DATANODE) + { + nodePool->nodeoid = datanode_connInfos[index].nodeoid; dbPool->dataNodePools[index] = nodePool; + } else if (client_conn_type == REMOTE_CONN_COORD) + { + nodePool->nodeoid = coord_connInfos[index].nodeoid; dbPool->coordNodePools[index] = nodePool; + } } while (nodePool->size < MinPoolSize || (nodePool->freeSize == 0 && nodePool->size < MaxPoolSize)) @@ -2122,6 +2433,9 @@ grow_pool(DatabasePool * dbPool, int index, char client_conn_type) static void destroy_slot(PGXCNodePoolSlot *slot) { + if (!slot) + return; + PQfreeCancel((PGcancel *)slot->xc_cancelConn); PGXCNodeClose(slot->conn); pfree(slot); @@ -2136,6 +2450,9 @@ destroy_node_pool(PGXCNodePool *node_pool) { int i; + if (!node_pool) + return; + /* * At this point all agents using connections from this pool should be already closed * If this not the connections to the data nodes assigned to them remain open, this will @@ -2345,7 +2662,7 @@ clean_connection(List *dn_discard, List *co_discard, const char *database, const } /* Release lock on Pooler, to allow transactions to connect again. */ - is_pool_cleaning = false; + is_pool_locked = false; return res; } @@ -2361,10 +2678,10 @@ abort_pids(int *len, int pid, const char *database, const char *user_name) int i = 0; int count; - Assert(!is_pool_cleaning); + Assert(!is_pool_locked); Assert(agentCount > 0); - is_pool_cleaning = true; + is_pool_locked = true; pids = (int *) palloc((agentCount - 1) * sizeof(int)); diff --git a/src/backend/pgxc/pool/poolutils.c b/src/backend/pgxc/pool/poolutils.c index 92954993db..2b61003393 100644 --- a/src/backend/pgxc/pool/poolutils.c +++ b/src/backend/pgxc/pool/poolutils.c @@ -25,10 +25,15 @@ #include "pgxc/poolutils.h" #include "pgxc/pgxcnode.h" #include "access/gtm.h" +#include "access/xact.h" #include "commands/dbcommands.h" +#include "commands/prepare.h" +#include "storage/procarray.h" #include "utils/acl.h" #include "utils/builtins.h" #include "utils/lsyscache.h" +#include "utils/memutils.h" +#include "utils/resowner.h" /* * pgxc_pool_check @@ -44,11 +49,107 @@ pgxc_pool_check(PG_FUNCTION_ARGS) (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to manage pooler")))); + /* A datanode has no pooler active, so do not bother about that */ + if (IS_PGXC_DATANODE) + PG_RETURN_BOOL(true); + /* Simply check with pooler */ PG_RETURN_BOOL(PoolManagerCheckConnectionInfo()); } /* + * pgxc_pool_reload + * + * Reload data cached in pooler and reload node connection + * information in all the server sessions. This aborts all + * the existing transactions on this node and reinitializes pooler. + * First a lock is taken on Pooler to keep consistency of node information + * being updated. If connection information cached is already consistent + * in pooler, reload is not executed. + * Reload itself is made in 2 phases: + * 1) Update database pools with new connection information based on catalog + * pgxc_node. Remote node pools are changed as follows: + * - cluster nodes dropped in new cluster configuration are deleted and all + * their remote connections are dropped. + * - cluster nodes whose port or host value is modified are dropped the same + * way, as connection information has changed. + * - cluster nodes whose port or host has not changed are kept as is, but + * reorganized respecting the new cluster configuration. + * - new cluster nodes are added. + * 2) Reload information in all the sessions of the local node. + * All the sessions in server are signaled to reconnect to pooler to get + * newest connection information and update connection information related + * to remote nodes. This results in losing prepared and temporary objects + * in all the sessions of server. All the existing transactions are aborted + * and a WARNING message is sent back to client. + * Session that invocated the reload does the same process, but no WARNING + * message is sent back to client. + */ +Datum +pgxc_pool_reload(PG_FUNCTION_ARGS) +{ + MemoryContext old_context; + + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + (errmsg("must be superuser to manage pooler")))); + + if (IsTransactionBlock()) + ereport(ERROR, + (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION), + errmsg("pgxc_pool_reload cannot run inside a transaction block"))); + + /* A datanode has no pooler active, so do not bother about that */ + if (IS_PGXC_DATANODE) + PG_RETURN_BOOL(true); + + /* Take a lock on pooler to forbid any action during reload */ + PoolManagerLock(true); + + /* No need to reload, node information is consistent */ + if (PoolManagerCheckConnectionInfo()) + { + /* Release the lock on pooler */ + PoolManagerLock(false); + PG_RETURN_BOOL(true); + } + + /* Reload connection information in pooler */ + PoolManagerReloadConnectionInfo(); + + /* Be sure it is done consistently */ + if (!PoolManagerCheckConnectionInfo()) + { + /* Release the lock on pooler */ + PoolManagerLock(false); + PG_RETURN_BOOL(false); + } + + /* Now release the lock on pooler */ + PoolManagerLock(false); + + /* Signal other sessions to reconnect to pooler */ + ReloadConnInfoOnBackends(); + + /* Session is being reloaded, drop prepared and temporary objects */ + DropAllPreparedStatements(); + + /* Now session information is reset in correct memory context */ + old_context = MemoryContextSwitchTo(TopMemoryContext); + + /* Reconnect to pool manager */ + PoolManagerReconnect(); + + /* And reinitialize session */ + InitMultinodeExecutor(true); + + MemoryContextSwitchTo(old_context); + + PG_RETURN_BOOL(true); +} + +/* * CleanConnection() * * Utility to clean up Postgres-XC Pooler connections. @@ -264,3 +365,53 @@ DropDBCleanConnection(char *dbname) if (dn_list) list_free(dn_list); } + +/* + * HandlePoolerReload + * + * This is called when PROCSIG_PGXCPOOL_RELOAD is activated. + * Abort the current transaction if any, then reconnect to pooler. + * and reinitialize session connection information. + */ +void +HandlePoolerReload(void) +{ + MemoryContext old_context; + + /* A Datanode has no pooler active, so do not bother about that */ + if (IS_PGXC_DATANODE) + return; + + /* Abort existing xact if any */ + AbortCurrentTransactionOnce(); + + /* Session is being reloaded, drop prepared and temporary objects */ + DropAllPreparedStatements(); + + /* Now session information is reset in correct memory context */ + old_context = MemoryContextSwitchTo(TopMemoryContext); + + /* Need to be able to look into catalogs */ + CurrentResourceOwner = ResourceOwnerCreate(NULL, "ForPoolerReload"); + + /* Reconnect to pool manager */ + PoolManagerReconnect(); + + /* And reinitialize session */ + InitMultinodeExecutor(true); + + /* Send a message back to client regarding session being reloaded */ + ereport(WARNING, + (errcode(ERRCODE_OPERATOR_INTERVENTION), + errmsg("session has been reloaded due to a cluster configuration modification"), + errdetail("Temporary and prepared objects hold by session have been" + " dropped and current transaction has been aborted."))); + + /* Release everything */ + ResourceOwnerRelease(CurrentResourceOwner, RESOURCE_RELEASE_BEFORE_LOCKS, true, true); + ResourceOwnerRelease(CurrentResourceOwner, RESOURCE_RELEASE_LOCKS, true, true); + ResourceOwnerRelease(CurrentResourceOwner, RESOURCE_RELEASE_AFTER_LOCKS, true, true); + CurrentResourceOwner = NULL; + + MemoryContextSwitchTo(old_context); +} diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index 5be4d2597d..e4f7f28e27 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -2270,6 +2270,47 @@ CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared) return true; /* timed out, still conflicts */ } +#ifdef PGXC +/* + * ReloadConnInfoOnBackends -- reload connection information for all the backends + */ +void +ReloadConnInfoOnBackends(void) +{ + ProcArrayStruct *arrayP = procArray; + int index; + pid_t pid = 0; + + /* tell all backends to reload except this one who already reloaded */ + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + + for (index = 0; index < arrayP->numProcs; index++) + { + volatile PGPROC *proc = arrayP->procs[index]; + VirtualTransactionId vxid; + GET_VXID_FROM_PGPROC(vxid, *proc); + + if (proc == MyProc) + continue; /* do not do that on myself */ + if (proc->isPooler) + continue; /* Pooler cannot do that */ + if (proc->pid == 0) + continue; /* useless on prepared xacts */ + if (!OidIsValid(proc->databaseId)) + continue; /* ignore backends not connected to a database */ + if (proc->vacuumFlags & PROC_IN_VACUUM) + continue; /* ignore vacuum processes */ + + pid = proc->pid; + /* + * Send the reload signal if backend still exists + */ + (void) SendProcSignal(pid, PROCSIG_PGXCPOOL_RELOAD, vxid.backendId); + } + + LWLockRelease(ProcArrayLock); +} +#endif #define XidCacheRemove(i) \ do { \ diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c index 28bcaa7e1e..80f69025d8 100644 --- a/src/backend/storage/ipc/procsignal.c +++ b/src/backend/storage/ipc/procsignal.c @@ -27,7 +27,9 @@ #include "storage/sinval.h" #include "storage/standby.h" #include "tcop/tcopprot.h" - +#ifdef PGXC +#include "pgxc/poolutils.h" +#endif /* * The SIGUSR1 signal is multiplexed to support signalling multiple event @@ -261,6 +263,11 @@ procsignal_sigusr1_handler(SIGNAL_ARGS) if (CheckProcSignal(PROCSIG_NOTIFY_INTERRUPT)) HandleNotifyInterrupt(); +#ifdef PGXC + if (CheckProcSignal(PROCSIG_PGXCPOOL_RELOAD)) + HandlePoolerReload(); +#endif + if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_DATABASE)) RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_DATABASE); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index ba95f61083..4088bcbf87 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3882,7 +3882,7 @@ PostgresMain(int argc, char *argv[], const char *username) { CurrentResourceOwner = ResourceOwnerCreate(NULL, "ForPGXCNodes"); - InitMultinodeExecutor(); + InitMultinodeExecutor(false); pool_handle = GetPoolManagerHandle(); if (pool_handle == NULL) @@ -3978,7 +3978,7 @@ PostgresMain(int argc, char *argv[], const char *username) /* * Temporarily do not abort if we are already in an abort state. * This change tries to handle the case where the error data stack fills up. - */ + */ AbortCurrentTransactionOnce(); #else AbortCurrentTransaction(); diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index bff2788c86..19436b59ac 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -1950,25 +1950,21 @@ standard_ProcessUtility(Node *parsetree, RequestBarrier(((BarrierStmt *) parsetree)->id, completionTag); break; + /* + * Node DDL is an operation local to Coordinator. + * In case of a new node being created in the cluster, + * it is necessary to create this node on all the Coordinators independently. + */ case T_AlterNodeStmt: PgxcNodeAlter((AlterNodeStmt *) parsetree); - - if (IS_PGXC_COORDINATOR) - ExecUtilityStmtOnNodes(queryString, NULL, true, EXEC_ON_ALL_NODES, false); break; case T_CreateNodeStmt: PgxcNodeCreate((CreateNodeStmt *) parsetree); - - if (IS_PGXC_COORDINATOR) - ExecUtilityStmtOnNodes(queryString, NULL, true, EXEC_ON_ALL_NODES, false); break; case T_DropNodeStmt: PgxcNodeRemove((DropNodeStmt *) parsetree); - - if (IS_PGXC_COORDINATOR) - ExecUtilityStmtOnNodes(queryString, NULL, true, EXEC_ON_ALL_NODES, false); break; case T_CreateGroupStmt: @@ -2147,6 +2143,14 @@ ExecUtilityStmtOnNodes(const char *queryString, ExecNodes *nodes, if (exec_type == EXEC_ON_NONE) return; + /* If no Datanodes defined, the query cannot be launched */ + if (NumDataNodes == 0) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("No PGXC Datanode master defined in cluster"), + errhint("You need to define at least 1 Datanode master with " + "CREATE NODE."))); + if (!IsConnFromCoord()) { RemoteQuery *step = makeNode(RemoteQuery); diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index 5cd2cc3ee4..2b8f691b37 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -89,7 +89,10 @@ static bool debug = false; static bool noclean = false; static bool show_setting = false; static char *xlog_dir = ""; - +#ifdef PGXC +/* Name of the PGXC node initialized */ +static char *nodename = NULL; +#endif /* internal vars */ static const char *progname; @@ -105,9 +108,6 @@ static char *dictionary_file; static char *info_schema_file; static char *features_file; static char *system_views_file; -#ifdef PGXC -static char *cluster_nodes_file; -#endif static bool made_new_pgdata = false; static bool found_existing_pgdata = false; static bool made_new_xlogdir = false; @@ -173,7 +173,7 @@ static void get_set_pwd(void); static void setup_depend(void); static void setup_sysviews(void); #ifdef PGXC -static void setup_clusternodes(void); +static void setup_nodeself(void); #endif static void setup_description(void); static void setup_collation(void); @@ -1019,6 +1019,13 @@ setup_config(void) conflines = replace_token(conflines, "#default_text_search_config = 'pg_catalog.simple'", repltok); +#ifdef PGXC + /* Add Postgres-XC node name to configuration file */ + snprintf(repltok, sizeof(repltok), + "pgxc_node_name = '%s'", + escape_quotes(nodename)); + conflines = replace_token(conflines, "#pgxc_node_name = ''", repltok); +#endif snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data); @@ -1471,40 +1478,29 @@ setup_sysviews(void) #ifdef PGXC /* - * set up Postgres-XC cluster node catalog data + * set up Postgres-XC cluster node catalog data with node self + * which is the node currently initialized. */ static void -setup_clusternodes(void) +setup_nodeself(void) { PG_CMD_DECL; - char **line; - char **nodes_setup; fputs(_("creating cluster information ... "), stdout); fflush(stdout); - nodes_setup = readfile(cluster_nodes_file); - - /* - * We use -j here to avoid backslashing stuff in system_views.sql - */ snprintf(cmd, sizeof(cmd), - "\"%s\" %s -j template1 >%s", + "\"%s\" %s template1 >%s", backend_exec, backend_options, DEVNULL); PG_CMD_OPEN; - for (line = nodes_setup; *line != NULL; line++) - { - PG_CMD_PUTS(*line); - free(*line); - } + PG_CMD_PRINTF1("CREATE NODE %s WITH (COORDINATOR MASTER);\n", + nodename); PG_CMD_CLOSE; - free(nodes_setup); - check_ok(); } #endif @@ -2561,10 +2557,13 @@ usage(const char *progname) { printf(_("%s initializes a PostgreSQL database cluster.\n\n"), progname); printf(_("Usage:\n")); - printf(_(" %s [OPTION]... [DATADIR]\n"), progname); + printf(_(" %s [OPTION]... [DATADIR] [NODENAME]\n"), progname); printf(_("\nOptions:\n")); printf(_(" -A, --auth=METHOD default authentication method for local connections\n")); printf(_(" [-D, --pgdata=]DATADIR location for this database cluster\n")); +#ifdef PGXC + printf(_(" --nodename=NODENAME name of Postgres-XC node initialized\n")); +#endif printf(_(" -E, --encoding=ENCODING set default encoding for new databases\n")); printf(_(" --locale=LOCALE set default locale for new databases\n")); printf(_(" --lc-collate=, --lc-ctype=, --lc-messages=LOCALE\n" @@ -2620,6 +2619,9 @@ main(int argc, char *argv[]) {"show", no_argument, NULL, 's'}, {"noclean", no_argument, NULL, 'n'}, {"xlogdir", required_argument, NULL, 'X'}, +#ifdef PGXC + {"nodename", required_argument, NULL, 10}, +#endif {NULL, 0, NULL, 0} }; @@ -2739,6 +2741,11 @@ main(int argc, char *argv[]) case 'X': xlog_dir = xstrdup(optarg); break; +#ifdef PGXC + case 10: + nodename = xstrdup(optarg); + break; +#endif default: /* getopt_long already emitted a complaint */ fprintf(stderr, _("Try \"%s --help\" for more information.\n"), @@ -2770,6 +2777,16 @@ main(int argc, char *argv[]) exit(1); } +#ifdef PGXC + if (!nodename) + { + fprintf(stderr, _("%s: Postgres-XC node name is mandatory\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); + exit(1); + } +#endif + if (authmethod == NULL || !strlen(authmethod)) { authwarning = _("\nWARNING: enabling \"trust\" authentication for local connections\n" @@ -2965,9 +2982,6 @@ main(int argc, char *argv[]) set_input(&info_schema_file, "information_schema.sql"); set_input(&features_file, "sql_features.txt"); set_input(&system_views_file, "system_views.sql"); -#ifdef PGXC - set_input(&cluster_nodes_file, "cluster_nodes.sql"); -#endif set_info_version(); @@ -3001,9 +3015,6 @@ main(int argc, char *argv[]) check_input(info_schema_file); check_input(features_file); check_input(system_views_file); -#ifdef PGXC - check_input(cluster_nodes_file); -#endif setlocales(); @@ -3328,7 +3339,8 @@ main(int argc, char *argv[]) setup_sysviews(); #ifdef PGXC - setup_clusternodes(); + /* Initialize catalog information about the node self */ + setup_nodeself(); #endif setup_description(); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index cfe923eda9..2d75af3d94 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -4344,6 +4344,8 @@ DESCR("fetch the Nth row value"); #ifdef PGXC DATA(insert OID = 3200 ( pgxc_pool_check PGNSP PGUID 12 1 0 0 f f f t f v 0 0 16 "" _null_ _null_ _null_ _null_ pgxc_pool_check _null_ _null_ _null_ )); DESCR("check connection information consistency in pooler"); +DATA(insert OID = 3201 ( pgxc_pool_reload PGNSP PGUID 12 1 0 0 f f f t f v 0 0 16 "" _null_ _null_ _null_ _null_ pgxc_pool_reload _null_ _null_ _null_ )); +DESCR("reload connection information in pooler and reload server sessions"); #endif /* diff --git a/src/include/pgxc/pgxcnode.h b/src/include/pgxc/pgxcnode.h index 2f6b3d8f94..d701e55b82 100644 --- a/src/include/pgxc/pgxcnode.h +++ b/src/include/pgxc/pgxcnode.h @@ -92,7 +92,7 @@ typedef struct PGXCNodeHandle **coord_handles; /* an array of Coordinator handles */ } PGXCNodeAllHandles; -extern void InitMultinodeExecutor(void); +extern void InitMultinodeExecutor(bool is_force); /* Open/close connection routines (invoked from Pool Manager) */ extern char *PGXCNodeConnStr(char *host, int port, char *dbname, char *user, diff --git a/src/include/pgxc/poolmgr.h b/src/include/pgxc/poolmgr.h index a120c38695..0d6f1e46a9 100644 --- a/src/include/pgxc/poolmgr.h +++ b/src/include/pgxc/poolmgr.h @@ -58,6 +58,7 @@ typedef struct typedef struct { char *connstr; + Oid nodeoid; /* Node Oid related to this pool */ int freeSize; /* available connections */ int size; /* total pool size */ PGXCNodePoolSlot **slot; @@ -68,6 +69,8 @@ typedef struct databasepool { char *database; char *user_name; + int num_dn_pools; + int num_co_pools; PGXCNodePool **dataNodePools; /* one for each Datanode */ PGXCNodePool **coordNodePools; /* one for each Coordinator */ struct databasepool *next; @@ -85,6 +88,8 @@ typedef struct /* communication channel */ PoolPort port; DatabasePool *pool; + int num_dn_connections; + int num_coord_connections; PGXCNodePoolSlot **dn_connections; /* one for each Datanode */ PGXCNodePoolSlot **coord_connections; /* one for each Coordinator */ char *session_params; @@ -144,6 +149,12 @@ extern void PoolManagerDisconnect(void); extern void PoolManagerConnect(PoolHandle *handle, const char *database, const char *user_name); /* + * Reconnect to pool manager + * This simply does a disconnection followed by a reconnection. + */ +extern void PoolManagerReconnect(void); + +/* * Save a SET command in Pooler. * This command is run on existent agent connections * and stored in pooler agent to be replayed when new connections @@ -160,6 +171,9 @@ extern void PoolManagerCleanConnection(List *datanodelist, List *coordlist, char /* Check consistency of connection information cached in pooler with catalogs */ extern bool PoolManagerCheckConnectionInfo(void); +/* Reload connection data in pooler and drop all the existing connections of pooler */ +extern void PoolManagerReloadConnectionInfo(void); + /* Send Abort signal to transactions being run */ extern int PoolManagerAbortTransactions(char *dbname, char *username, int **proc_pids); @@ -169,6 +183,9 @@ extern void PoolManagerReleaseConnections(void); /* Cancel a running query on data nodes as well as on other coordinators */ extern void PoolManagerCancelQuery(int dn_count, int* dn_list, int co_count, int* co_list); +/* Lock/unlock pool manager */ +extern void PoolManagerLock(bool is_lock); + /* Check if pool has a handle */ extern bool IsPoolHandle(void); #endif diff --git a/src/include/pgxc/poolutils.h b/src/include/pgxc/poolutils.h index a8c216d4e3..6988e298f8 100644 --- a/src/include/pgxc/poolutils.h +++ b/src/include/pgxc/poolutils.h @@ -32,4 +32,7 @@ void CleanConnection(CleanConnStmt *stmt); void DropDBCleanConnection(char *dbname); + +/* Handle pooler connection reload when signaled by SIGUSR1 */ +void HandlePoolerReload(void); #endif diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h index dad89de578..64be237f25 100644 --- a/src/include/storage/procarray.h +++ b/src/include/storage/procarray.h @@ -36,6 +36,7 @@ extern void CreateSharedAnalyzeProcArray(void); extern void AnalyzeProcArrayRemove(PGPROC *proc, TransactionId latestXid); extern void SetGlobalSnapshotData(int xmin, int xmax, int xcnt, int *xip); extern void UnsetGlobalSnapshotData(void); +extern void ReloadConnInfoOnBackends(void); #endif /* PGXC */ extern void ProcArrayApplyRecoveryInfo(RunningTransactions running); extern void ProcArrayApplyXidAssignment(TransactionId topxid, diff --git a/src/include/storage/procsignal.h b/src/include/storage/procsignal.h index 2a27e0b7ed..8c8be47eef 100644 --- a/src/include/storage/procsignal.h +++ b/src/include/storage/procsignal.h @@ -27,10 +27,22 @@ * Also, because of race conditions, it's important that all the signals be * defined so that no harm is done if a process mistakenly receives one. */ +#ifdef PGXC +/* + * In the case of Postgres-XC, it may be possible that this backend is + * signaled during a pool manager reload process. In this case it means that + * remote node connection has been changed inside pooler, so backend has to + * abort its current transaction, reconnect to pooler and update its session + * information regarding remote node handles. + */ +#endif typedef enum { PROCSIG_CATCHUP_INTERRUPT, /* sinval catchup interrupt */ PROCSIG_NOTIFY_INTERRUPT, /* listen/notify interrupt */ +#ifdef PGXC + PROCSIG_PGXCPOOL_RELOAD, /* abort current transaction and reconnect to pooler */ +#endif /* Recovery conflict reasons */ PROCSIG_RECOVERY_CONFLICT_DATABASE, diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 47fb36b9f2..1e07ef18cb 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -1123,6 +1123,7 @@ extern Datum pg_cursor(PG_FUNCTION_ARGS); #ifdef PGXC /* backend/pgxc/pool/poolutils.c */ extern Datum pgxc_pool_check(PG_FUNCTION_ARGS); +extern Datum pgxc_pool_reload(PG_FUNCTION_ARGS); #endif #endif /* BUILTINS_H */ |