You can subscribe to this list here.
2010 |
Jan
|
Feb
|
Mar
|
Apr
(4) |
May
(28) |
Jun
(12) |
Jul
(11) |
Aug
(12) |
Sep
(5) |
Oct
(19) |
Nov
(14) |
Dec
(12) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2011 |
Jan
(18) |
Feb
(30) |
Mar
(115) |
Apr
(89) |
May
(50) |
Jun
(44) |
Jul
(22) |
Aug
(13) |
Sep
(11) |
Oct
(30) |
Nov
(28) |
Dec
(39) |
2012 |
Jan
(38) |
Feb
(18) |
Mar
(43) |
Apr
(91) |
May
(108) |
Jun
(46) |
Jul
(37) |
Aug
(44) |
Sep
(33) |
Oct
(29) |
Nov
(36) |
Dec
(15) |
2013 |
Jan
(35) |
Feb
(611) |
Mar
(5) |
Apr
(55) |
May
(30) |
Jun
(28) |
Jul
(458) |
Aug
(34) |
Sep
(9) |
Oct
(39) |
Nov
(22) |
Dec
(32) |
2014 |
Jan
(16) |
Feb
(16) |
Mar
(42) |
Apr
(179) |
May
(7) |
Jun
(6) |
Jul
(9) |
Aug
|
Sep
(4) |
Oct
|
Nov
(3) |
Dec
|
2015 |
Jan
|
Feb
|
Mar
|
Apr
(2) |
May
(4) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
|
|
|
|
|
1
(2) |
2
(3) |
3
|
4
(2) |
5
(3) |
6
(2) |
7
(8) |
8
(12) |
9
|
10
|
11
(17) |
12
(16) |
13
(4) |
14
(3) |
15
(5) |
16
|
17
|
18
(1) |
19
(3) |
20
(2) |
21
(1) |
22
(1) |
23
|
24
|
25
(3) |
26
(1) |
27
|
28
|
29
|
30
|
From: Michael P. <mic...@us...> - 2011-04-07 04:30:38
|
Project "Postgres-XC". The branch, master has been updated via 8b018fd20850ec0753fdfbef024b9a957efaeb0a (commit) from 913fba843d425a786196bcffc965e5ceea75e55d (commit) - Log ----------------------------------------------------------------- commit 8b018fd20850ec0753fdfbef024b9a957efaeb0a Author: Michael P <mic...@us...> Date: Thu Apr 7 13:10:09 2011 +0900 Support for session and local parameters This commit adds support for commands like: SET ROLE ... ; SET param TO value; SET SESSION param TO value; SET LOCAL param TO value; When a SET command is launched, it is saved in pooler and then launched to nodes by pooler if connections to backend nodes exist. Commands are saved with the following format as a string: "SET param1 TO value1;...;SET paramN TO valueN" Local and session commands are saved as separate strings. When a new connection is created to a backend node, pooler replays all the saved SET commands. When a transaction is finished, local parameters are deleted from pooler. It is not necessary in this case to reset on backend nodes as transaction commit has made the work. If a SET command has been launched for a non-local parameter, connections to nodes are kept alive with the session and not sent back to pool when a transaction finishes. When session is finished (user logging off), pooler sends asynchronously a "RESET ALL" command to each connection and put connections back to pool. Reset is not launched if no SET queries for session parameters have been launched. A SET command for local parameters is not sent to pooler if it is not inside a transaction block to save ressources in the cluster. This commit contains also a couple of corrections for regression tests according to implementation of session parameters. diff --git a/src/backend/pgxc/pool/execRemote.c b/src/backend/pgxc/pool/execRemote.c index cf38041..848a3cc 100644 --- a/src/backend/pgxc/pool/execRemote.c +++ b/src/backend/pgxc/pool/execRemote.c @@ -4398,6 +4398,9 @@ PGXCNodeCleanAndRelease(int code, Datum arg) /* Release data node connections */ release_handles(); + /* Disconnect from Pooler */ + PoolManagerDisconnect(); + /* Close connection with GTM */ CloseGTM(); diff --git a/src/backend/pgxc/pool/pgxcnode.c b/src/backend/pgxc/pool/pgxcnode.c index dcd721d..d7230b0 100644 --- a/src/backend/pgxc/pool/pgxcnode.c +++ b/src/backend/pgxc/pool/pgxcnode.c @@ -196,6 +196,28 @@ PGXCNodeClose(NODE_CONNECTION *conn) PQfinish((PGconn *) conn); } +/* + * Send SET query to given connection. + * Query is sent asynchronously and results are consumed + */ +int +PGXCNodeSendSetQuery(NODE_CONNECTION *conn, const char *sql_command) +{ + PGresult *result; + + if (!PQsendQuery((PGconn *) conn, sql_command)) + return -1; + + /* Consume results from SET commands */ + while ((result = PQgetResult((PGconn *) conn)) != NULL) + { + /* TODO: Check that results are of type 'S' */ + PQclear(result); + } + + return 0; +} + /* * Checks if connection active diff --git a/src/backend/pgxc/pool/poolmgr.c b/src/backend/pgxc/pool/poolmgr.c index 478ba42..ecd18f9 100644 --- a/src/backend/pgxc/pool/poolmgr.c +++ b/src/backend/pgxc/pool/poolmgr.c @@ -93,6 +93,7 @@ static void agent_init(PoolAgent *agent, const char *database, const char *user_ static void agent_destroy(PoolAgent *agent); static void agent_create(void); static void agent_handle_input(PoolAgent *agent, StringInfo s); +static int agent_set_command(PoolAgent *agent, const char *set_command, bool is_local); 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); @@ -102,6 +103,7 @@ static DatabasePool *remove_database_pool(const char *database, const char *user static int *agent_acquire_connections(PoolAgent *agent, List *datanodelist, List *coordlist); static PGXCNodePoolSlot *acquire_connection(DatabasePool *dbPool, int node, char client_conn_type); static void agent_release_connections(PoolAgent *agent, List *dn_discard, List *co_discard); +static void agent_reset_params(PoolAgent *agent, List *dn_list, List *co_list); static void release_connection(DatabasePool *dbPool, PGXCNodePoolSlot *slot, int index, bool clean, char client_conn_type); static void destroy_slot(PGXCNodePoolSlot *slot); @@ -476,6 +478,8 @@ agent_create(void) agent->pool = NULL; agent->dn_connections = NULL; agent->coord_connections = NULL; + agent->session_params = NULL; + agent->local_params = NULL; agent->pid = 0; /* Append new agent to the list */ @@ -528,6 +532,36 @@ PoolManagerConnect(PoolHandle *handle, const char *database, const char *user_na pool_flush(&handle->port); } +int +PoolManagerSetCommand(bool is_local, const char *set_command) +{ + int n32; + char msgtype = 's'; + + Assert(set_command); + Assert(Handle); + + /* Message type */ + pool_putbytes(&Handle->port, &msgtype, 1); + + /* Message length */ + n32 = htonl(strlen(set_command) + 10); + pool_putbytes(&Handle->port, (char *) &n32, 4); + + /* LOCAL or SESSION parameter ? */ + pool_putbytes(&Handle->port, (char *) &is_local, 1); + + /* Length of SET command string */ + n32 = htonl(strlen(set_command) + 1); + pool_putbytes(&Handle->port, (char *) &n32, 4); + + /* Send command string followed by \0 terminator */ + pool_putbytes(&Handle->port, set_command, strlen(set_command) + 1); + pool_flush(&Handle->port); + + /* Get result */ + pool_recvres(&Handle->port); +} /* * Init PoolAgent @@ -567,9 +601,9 @@ agent_destroy(PoolAgent *agent) /* Discard connections if any remaining */ if (agent->pool) { - List *dn_conn = NIL; - List *co_conn = NIL; - int i; + List *dn_conn = NIL; + List *co_conn = NIL; + int i; /* gather abandoned datanode connections */ if (agent->dn_connections) @@ -583,6 +617,12 @@ agent_destroy(PoolAgent *agent) if (agent->coord_connections[i]) co_conn = lappend_int(co_conn, i+1); + /* + * agent is being destroyed, so reset session parameters + * before putting back connections to pool + */ + agent_reset_params(agent, dn_conn, co_conn); + /* release them all */ agent_release_connections(agent, dn_conn, co_conn); } @@ -603,6 +643,16 @@ agent_destroy(PoolAgent *agent) pfree(agent->coord_connections); agent->coord_connections = NULL; } + if (agent->local_params) + { + pfree(agent->local_params); + agent->local_params = NULL; + } + if (agent->session_params) + { + pfree(agent->session_params); + agent->session_params = NULL; + } pfree(agent); /* shrink the list and move last agent into the freed slot */ if (i < --agentCount) @@ -618,16 +668,14 @@ agent_destroy(PoolAgent *agent) * Release handle to pool manager */ void -PoolManagerDisconnect(PoolHandle *handle) +PoolManagerDisconnect(void) { - Assert(handle); + Assert(Handle); - pool_putmessage(&handle->port, 'd', NULL, 0); + pool_putmessage(&Handle->port, 'd', NULL, 0); pool_flush(&Handle->port); - close(Socket(handle->port)); - - pfree(handle); + close(Socket(Handle->port)); } @@ -784,6 +832,8 @@ agent_handle_input(PoolAgent * agent, StringInfo s) { const char *database; const char *user_name; + const char *set_command; + bool is_local; int datanodecount; int coordcount; List *datanodelist = NIL; @@ -905,6 +955,20 @@ agent_handle_input(PoolAgent * agent, StringInfo s) list_free(datanodelist); list_free(coordlist); break; + case 's': /* SET COMMAND */ + pool_getmessage(&agent->port, s, 0); + /* Determine if command is local or session */ + is_local = (bool) pq_getmsgbyte(s); + /* Get the SET command */ + len = pq_getmsgint(s, 4); + set_command = pq_getmsgbytes(s, len); + pq_getmsgend(s); + + res = agent_set_command(agent, set_command, is_local); + + /* Send success result */ + pool_sendres(&agent->port, res); + break; default: /* EOF or protocol violation */ agent_destroy(agent); return; @@ -915,6 +979,77 @@ agent_handle_input(PoolAgent * agent, StringInfo s) } } +/* + * Save a SET command and distribute it to the agent connections + * already in use. + */ +static int +agent_set_command(PoolAgent *agent, const char *set_command, bool is_local) +{ + char *params_string; + int i; + int res = 0; + + Assert(agent); + Assert(set_command); + + if (is_local) + params_string = agent->local_params; + else + params_string = agent->session_params; + + /* First command recorded */ + if (!params_string) + { + params_string = pstrdup(set_command); + if (!params_string) + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); + } + else + { + /* + * Second command or more recorded. + * Commands are saved with format 'SET param1 TO value1;...;SET paramN TO valueN' + */ + params_string = (char *) repalloc(params_string, + strlen(params_string) + strlen(set_command) + 2); + if (!params_string) + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); + + sprintf(params_string, "%s;%s", params_string, set_command); + } + + /* Launch the new command to all the connections already hold by the agent */ + if (agent->dn_connections) + { + for (i = 0; i < NumDataNodes; i++) + { + if (agent->dn_connections[i]) + res = PGXCNodeSendSetQuery(agent->dn_connections[i]->conn, set_command); + } + } + + if (agent->coord_connections) + { + for (i = 0; i < NumCoords; i++) + { + if (agent->coord_connections[i]) + res |= PGXCNodeSendSetQuery(agent->coord_connections[i]->conn, set_command); + } + } + + /* Save the latest string */ + if (is_local) + agent->local_params = params_string; + else + agent->session_params = params_string; + + return res; +} /* * acquire connection @@ -1005,6 +1140,12 @@ agent_acquire_connections(PoolAgent *agent, List *datanodelist, List *coordlist) /* Store in the descriptor */ agent->dn_connections[node - 1] = slot; + + /* Update newly-acquired slot with session parameters */ + if (agent->session_params) + PGXCNodeSendSetQuery(slot->conn, agent->session_params); + if (agent->local_params) + PGXCNodeSendSetQuery(slot->conn, agent->local_params); } result[i++] = PQsocket((PGconn *) agent->dn_connections[node - 1]->conn); @@ -1029,6 +1170,12 @@ agent_acquire_connections(PoolAgent *agent, List *datanodelist, List *coordlist) /* Store in the descriptor */ agent->coord_connections[node - 1] = slot; + + /* Update newly-acquired slot with session parameters */ + if (agent->session_params) + PGXCNodeSendSetQuery(slot->conn, agent->session_params); + if (agent->local_params) + PGXCNodeSendSetQuery(slot->conn, agent->local_params); } result[i++] = PQsocket((PGconn *) agent->coord_connections[node - 1]->conn); @@ -1095,6 +1242,20 @@ agent_release_connections(PoolAgent *agent, List *dn_discard, List *co_discard) if (!agent->dn_connections && !agent->coord_connections) return; + /* + * If there are some session parameters, do not put back connections to pool + * disconnection will be made when session is cut for this user. + * Local parameters are reset when transaction block is finished, + * so don't do anything for them, but just reset their list. + */ + if (agent->local_params) + { + pfree(agent->local_params); + agent->local_params = NULL; + } + if (agent->session_params) + return; + /* Discard first for Datanodes */ if (dn_discard) { @@ -1156,6 +1317,65 @@ agent_release_connections(PoolAgent *agent, List *dn_discard, List *co_discard) } } +/* + * Reset session parameters for given connections in the agent. + * This is done before putting back to pool connections that have been + * modified by session parameters. + */ +static void +agent_reset_params(PoolAgent *agent, List *dn_list, List *co_list) +{ + PGXCNodePoolSlot *slot; + + if (!agent->dn_connections && !agent->coord_connections) + return; + + /* Parameters are reset, so free commands */ + if (agent->session_params) + { + pfree(agent->session_params); + agent->session_params = NULL; + } + if (agent->local_params) + { + pfree(agent->local_params); + agent->local_params = NULL; + } + + /* Reset Datanode connection params */ + if (dn_list) + { + ListCell *lc; + + foreach(lc, dn_list) + { + int node = lfirst_int(lc); + Assert(node > 0 && node <= NumDataNodes); + slot = agent->dn_connections[node - 1]; + + /* Reset connection params */ + if (slot) + PGXCNodeSendSetQuery(slot->conn, "RESET ALL;"); + } + } + + /* Reset Coordinator connection params */ + if (co_list) + { + ListCell *lc; + + foreach(lc, co_list) + { + int node = lfirst_int(lc); + Assert(node > 0 && node <= NumCoords); + slot = agent->coord_connections[node - 1]; + + /* Reset connection params */ + if (slot) + PGXCNodeSendSetQuery(slot->conn, "RESET ALL;"); + } + } +} /* * Create new empty pool for a database. diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 1ffeead..8408b40 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -62,6 +62,7 @@ #include "pgxc/pgxc.h" #include "pgxc/planner.h" #include "pgxc/poolutils.h" +#include "pgxc/poolmgr.h" static void ExecUtilityStmtOnNodes(const char *queryString, ExecNodes *nodes, bool force_autocommit, RemoteQueryExecType exec_type); @@ -1414,11 +1415,18 @@ standard_ProcessUtility(Node *parsetree, case T_VariableSetStmt: ExecSetVariableStmt((VariableSetStmt *) parsetree); #ifdef PGXC -/* PGXCTODO - this currently causes an assertion failure. - We should change when we add SET handling properly - if (IS_PGXC_COORDINATOR) - ExecUtilityStmtOnNodes(queryString, NULL, false); -*/ + /* Let the pooler manage the statement */ + if (IS_PGXC_COORDINATOR && !IsConnFromCoord()) + { + VariableSetStmt *stmt = (VariableSetStmt *) parsetree; + /* + * If command is local and we are not in a transaction block do NOT + * send this query to backend nodes + */ + if (!stmt->is_local || !IsTransactionBlock()) + if (PoolManagerSetCommand(stmt->is_local, queryString) < 0) + elog(ERROR, "Postgres-XC: ERROR SET query"); + } #endif break; @@ -1576,6 +1584,14 @@ standard_ProcessUtility(Node *parsetree, case T_ConstraintsSetStmt: AfterTriggerSetState((ConstraintsSetStmt *) parsetree); + + /* + * PGXCTODO: SET CONSTRAINT management + * This can just be done inside a transaction block, + * so just launch it on all the Datanodes. + * For the time being only IMMEDIATE constraints are supported + * so this is not really useful... + */ break; case T_CheckPointStmt: diff --git a/src/include/pgxc/pgxcnode.h b/src/include/pgxc/pgxcnode.h index 007e1dc..83dce0c 100644 --- a/src/include/pgxc/pgxcnode.h +++ b/src/include/pgxc/pgxcnode.h @@ -96,6 +96,7 @@ extern void InitMultinodeExecutor(void); extern char *PGXCNodeConnStr(char *host, char *port, char *dbname, char *user, char *remote_type); extern NODE_CONNECTION *PGXCNodeConnect(char *connstr); +extern int PGXCNodeSendSetQuery(NODE_CONNECTION *conn, const char *sql_command); extern void PGXCNodeClose(NODE_CONNECTION * conn); extern int PGXCNodeConnected(NODE_CONNECTION * conn); extern int PGXCNodeConnClean(NODE_CONNECTION * conn); diff --git a/src/include/pgxc/poolmgr.h b/src/include/pgxc/poolmgr.h index 7e53b48..febf1d4 100644 --- a/src/include/pgxc/poolmgr.h +++ b/src/include/pgxc/poolmgr.h @@ -56,8 +56,10 @@ typedef struct databasepool struct databasepool *next; } DatabasePool; -/* Agent of client session (Pool Manager side) +/* + * Agent of client session (Pool Manager side) * Acts as a session manager, grouping connections together + * and managing session parameters */ typedef struct { @@ -68,6 +70,8 @@ typedef struct DatabasePool *pool; PGXCNodePoolSlot **dn_connections; /* one for each Datanode */ PGXCNodePoolSlot **coord_connections; /* one for each Coordinator */ + char *session_params; + char *local_params; } PoolAgent; /* Handle to the pool manager (Session's side) */ @@ -116,7 +120,7 @@ extern void PoolManagerCloseHandle(PoolHandle *handle); /* * Gracefully close connection to the PoolManager */ -extern void PoolManagerDisconnect(PoolHandle *handle); +extern void PoolManagerDisconnect(void); /* * Called from Session process after fork(). Associate handle with session @@ -125,6 +129,14 @@ extern void PoolManagerDisconnect(PoolHandle *handle); */ extern void PoolManagerConnect(PoolHandle *handle, const char *database, const char *user_name); +/* + * 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 + * are requested. + */ +extern int PoolManagerSetCommand(bool is_local, const char *set_command); + /* Get pooled connections */ extern int *PoolManagerGetConnections(List *datanodelist, List *coordlist); diff --git a/src/test/regress/expected/guc_1.out b/src/test/regress/expected/guc_1.out index d71a66c..83b5b65 100644 --- a/src/test/regress/expected/guc_1.out +++ b/src/test/regress/expected/guc_1.out @@ -513,6 +513,7 @@ SELECT current_user = 'temp_reset_user'; (1 row) DROP ROLE temp_reset_user; +ERROR: permission denied to drop role -- -- Tests for function-local GUC settings -- @@ -520,32 +521,35 @@ set work_mem = '3MB'; create function report_guc(text) returns text as $$ select current_setting($1) $$ language sql set work_mem = '1MB'; +ERROR: stable and volatile not yet supported, function volatility has to be immutable select report_guc('work_mem'), current_setting('work_mem'); - report_guc | current_setting -------------+----------------- - 1MB | 3MB -(1 row) - +ERROR: function report_guc(unknown) does not exist +LINE 1: select report_guc('work_mem'), current_setting('work_mem'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. -- this should draw only a warning alter function report_guc(text) set search_path = no_such_schema; -NOTICE: schema "no_such_schema" does not exist +ERROR: function report_guc(text) does not exist -- with error occurring here select report_guc('work_mem'), current_setting('work_mem'); -ERROR: schema "no_such_schema" does not exist +ERROR: function report_guc(unknown) does not exist +LINE 1: select report_guc('work_mem'), current_setting('work_mem'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. alter function report_guc(text) reset search_path set work_mem = '2MB'; +ERROR: function report_guc(text) does not exist select report_guc('work_mem'), current_setting('work_mem'); - report_guc | current_setting -------------+----------------- - 2MB | 3MB -(1 row) - +ERROR: function report_guc(unknown) does not exist +LINE 1: select report_guc('work_mem'), current_setting('work_mem'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. alter function report_guc(text) reset all; +ERROR: function report_guc(text) does not exist select report_guc('work_mem'), current_setting('work_mem'); - report_guc | current_setting -------------+----------------- - 3MB | 3MB -(1 row) - +ERROR: function report_guc(unknown) does not exist +LINE 1: select report_guc('work_mem'), current_setting('work_mem'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. -- SET LOCAL is restricted by a function SET option create or replace function myfunc(int) returns text as $$ begin @@ -554,19 +558,19 @@ begin end $$ language plpgsql set work_mem = '1MB'; +ERROR: stable and volatile not yet supported, function volatility has to be immutable select myfunc(0), current_setting('work_mem'); - myfunc | current_setting ---------+----------------- - 2MB | 3MB -(1 row) - +ERROR: function myfunc(integer) does not exist +LINE 1: select myfunc(0), current_setting('work_mem'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. alter function myfunc(int) reset all; +ERROR: function myfunc(integer) does not exist select myfunc(0), current_setting('work_mem'); - myfunc | current_setting ---------+----------------- - 2MB | 2MB -(1 row) - +ERROR: function myfunc(integer) does not exist +LINE 1: select myfunc(0), current_setting('work_mem'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. set work_mem = '3MB'; -- but SET isn't create or replace function myfunc(int) returns text as $$ @@ -576,12 +580,12 @@ begin end $$ language plpgsql set work_mem = '1MB'; +ERROR: stable and volatile not yet supported, function volatility has to be immutable select myfunc(0), current_setting('work_mem'); - myfunc | current_setting ---------+----------------- - 2MB | 2MB -(1 row) - +ERROR: function myfunc(integer) does not exist +LINE 1: select myfunc(0), current_setting('work_mem'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. set work_mem = '3MB'; -- it should roll back on error, though create or replace function myfunc(int) returns text as $$ @@ -592,10 +596,12 @@ begin end $$ language plpgsql set work_mem = '1MB'; +ERROR: stable and volatile not yet supported, function volatility has to be immutable select myfunc(0); -ERROR: division by zero -CONTEXT: SQL statement "SELECT 1/$1" -PL/pgSQL function "myfunc" line 3 at PERFORM +ERROR: function myfunc(integer) does not exist +LINE 1: select myfunc(0); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. select current_setting('work_mem'); current_setting ----------------- @@ -603,8 +609,7 @@ select current_setting('work_mem'); (1 row) select myfunc(1), current_setting('work_mem'); - myfunc | current_setting ---------+----------------- - 2MB | 2MB -(1 row) - +ERROR: function myfunc(integer) does not exist +LINE 1: select myfunc(1), current_setting('work_mem'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. diff --git a/src/test/regress/expected/plancache_1.out b/src/test/regress/expected/plancache_1.out index 389d0da..683a42e 100644 --- a/src/test/regress/expected/plancache_1.out +++ b/src/test/regress/expected/plancache_1.out @@ -150,7 +150,11 @@ ERROR: Postgres-XC does not support EXECUTE yet DETAIL: The feature is not currently supported set search_path = s2; select f1 from abc; -ERROR: relation "abc" does not exist + f1 +----- + 456 +(1 row) + execute p1; ERROR: Postgres-XC does not support EXECUTE yet DETAIL: The feature is not currently supported diff --git a/src/test/regress/expected/privileges_1.out b/src/test/regress/expected/privileges_1.out index d71fd34..51153a2 100644 --- a/src/test/regress/expected/privileges_1.out +++ b/src/test/regress/expected/privileges_1.out @@ -157,6 +157,7 @@ UPDATE atest2 SET col2 = NULL; -- ok UPDATE atest2 SET col2 = NOT col2; -- fails; requires SELECT on atest2 ERROR: permission denied for relation atest2 UPDATE atest2 SET col2 = true FROM atest1 WHERE atest1.a = 5; -- ok +ERROR: permission denied for relation atest2 SELECT * FROM atest1 FOR UPDATE; -- fail ERROR: permission denied for relation atest1 SELECT * FROM atest2 FOR UPDATE; -- fail @@ -217,26 +218,17 @@ SELECT * FROM atestv1; -- ok SELECT * FROM atestv2; -- fail ERROR: permission denied for relation atestv2 SELECT * FROM atestv3; -- ok - one | two | three ------+-----+------- -(0 rows) - +ERROR: permission denied for relation atest3 CREATE VIEW atestv4 AS SELECT * FROM atestv3; -- nested view SELECT * FROM atestv4; -- ok - one | two | three ------+-----+------- -(0 rows) - +ERROR: permission denied for relation atest3 GRANT SELECT ON atestv4 TO regressuser2; SET SESSION AUTHORIZATION regressuser2; -- Two complex cases: SELECT * FROM atestv3; -- fail ERROR: permission denied for relation atestv3 SELECT * FROM atestv4; -- ok (even though regressuser2 cannot access underlying atestv3) - one | two | three ------+-----+------- -(0 rows) - +ERROR: permission denied for relation atest3 SELECT * FROM atest2; -- ok col1 | col2 ------+------ @@ -294,17 +286,9 @@ ERROR: permission denied for relation atest5 SELECT * FROM atest1, atest5; -- fail ERROR: permission denied for relation atest5 SELECT atest1.* FROM atest1, atest5; -- ok - a | b ----+----- - 2 | two -(1 row) - +ERROR: permission denied for relation atest5 SELECT atest1.*,atest5.one FROM atest1, atest5; -- ok - a | b | one ----+-----+----- - 2 | two | 1 -(1 row) - +ERROR: permission denied for relation atest5 SELECT atest1.*,atest5.one FROM atest1 JOIN atest5 ON (atest1.a = atest5.two); -- fail ERROR: permission denied for relation atest5 SELECT atest1.*,atest5.one FROM atest1 JOIN atest5 ON (atest1.a = atest5.one); -- ok @@ -817,7 +801,6 @@ SELECT has_table_privilege('regressuser3', 'atest4', 'SELECT'); -- true REVOKE SELECT ON atest4 FROM regressuser2; -- fail ERROR: dependent privileges exist -HINT: Use CASCADE to revoke them too. REVOKE GRANT OPTION FOR SELECT ON atest4 FROM regressuser2 CASCADE; -- ok SELECT has_table_privilege('regressuser2', 'atest4', 'SELECT'); -- true has_table_privilege @@ -1235,8 +1218,6 @@ REVOKE USAGE ON LANGUAGE sql FROM regressuser1; DROP OWNED BY regressuser1; DROP USER regressuser1; DROP USER regressuser2; -ERROR: role "regressuser2" cannot be dropped because some objects depend on it -DETAIL: privileges for language sql DROP USER regressuser3; DROP USER regressuser4; DROP USER regressuser5; ----------------------------------------------------------------------- Summary of changes: src/backend/pgxc/pool/execRemote.c | 3 + src/backend/pgxc/pool/pgxcnode.c | 22 +++ src/backend/pgxc/pool/poolmgr.c | 238 ++++++++++++++++++++++++++- src/backend/tcop/utility.c | 26 +++- src/include/pgxc/pgxcnode.h | 1 + src/include/pgxc/poolmgr.h | 16 ++- src/test/regress/expected/guc_1.out | 85 ++++++----- src/test/regress/expected/plancache_1.out | 6 +- src/test/regress/expected/privileges_1.out | 31 +--- 9 files changed, 346 insertions(+), 82 deletions(-) hooks/post-receive -- Postgres-XC |
From: Michael P. <mic...@us...> - 2011-04-07 03:36:54
|
Project "Postgres-XC". The branch, master has been updated via 913fba843d425a786196bcffc965e5ceea75e55d (commit) from 112ad257947a5cc60b7c598880d335a5b9a351c1 (commit) - Log ----------------------------------------------------------------- commit 913fba843d425a786196bcffc965e5ceea75e55d Author: Michael P <mic...@us...> Date: Thu Apr 7 12:31:07 2011 +0900 Block FULL JOIN expressions This was leading to issues in join tests in XC planner like bug 3277038. It was not noticed before because this test has problems with relation "t1", which is created in test create_view but not removed correctly. diff --git a/src/backend/pgxc/plan/planner.c b/src/backend/pgxc/plan/planner.c index 45c453a..019b6b8 100644 --- a/src/backend/pgxc/plan/planner.c +++ b/src/backend/pgxc/plan/planner.c @@ -1355,6 +1355,12 @@ examine_conditions_fromlist(Node *treenode, XCWalkerContext *context) { JoinExpr *joinexpr = (JoinExpr *) treenode; + /* Block FULL JOIN expressions until it is supported */ + if (joinexpr->jointype == JOIN_FULL) + ereport(ERROR, + (errcode(ERRCODE_STATEMENT_TOO_COMPLEX), + (errmsg("FULL JOIN clause not yet supported")))); + /* recursively examine FROM join tree */ if (examine_conditions_fromlist(joinexpr->larg, context)) return true; ----------------------------------------------------------------------- Summary of changes: src/backend/pgxc/plan/planner.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) hooks/post-receive -- Postgres-XC |
From: Koichi S. <koi...@us...> - 2011-04-06 04:55:48
|
Project "Postgres-XC". The branch, documentation has been created at 180361060615c52e211244be7d5939c4a5edc0c4 (commit) - Log ----------------------------------------------------------------- commit 180361060615c52e211244be7d5939c4a5edc0c4 Author: Koichi Suzuki <koi...@gm...> Date: Wed Apr 6 13:49:40 2011 +0900 This is the first commit of "documentation" branch. This branch is to construct reference manual, man page and html document for Postgres-XC. Deatailed information of document preparaton will be given in a file in "doc" directory. At this time, I added "makesgml" tool. To make it easy to merge with PostgreSQL documentation and to translate to other language, makesgml can be used. This tool accepts two kind of tags, <!## label> ... <!## end> in the input file (namely, *.sgmlin) and selects only an area specified by -I option of "makesgml" command. This pair of label can be nested and you can select any part of the source file to be used in the target SGML file. diff --git a/doc/tools/makesgml/makesgml.c b/doc/tools/makesgml/makesgml.c new file mode 100644 index 0000000..013942c --- /dev/null +++ b/doc/tools/makesgml/makesgml.c @@ -0,0 +1,331 @@ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> + + +typedef struct tokenlist +{ + struct tokenlist *next; + char *token; +} tokenlist; + + +#define STARTTOKEN "<!##" + +tokenlist *ignoreToks = NULL; +tokenlist *lastIgnoreToken = NULL; +tokenlist *includeToks = NULL; +tokenlist *lastIncludeToken = NULL; + +FILE *inf; +FILE *outf; +int inf_lno; +char *progname; +int default_include = 0; + +void make_sgml(int writeflag); +void usage(int exitcode); +void format_err(int lno); +int my_getline(char *buf); + +main(int argc, char *argv[]) +{ + int flags,opt; + char *ifnam = NULL; + char *ofnam = NULL; + + char *token; + + inf = stdin; + outf = stdout; + + progname = argv[0]; + while((opt = getopt(argc, argv, "i:o:E:I:d:")) != -1) + { + switch(opt) + { + case 'i': + if (ifnam) { + free(ifnam); + ifnam = NULL; + } + if ((strcmp(optarg, "-") == 0) || (strcmp(optarg, "stdin") == 0)) + { + inf = stdin; + } + else + { + ifnam = strndup(optarg, strlen(optarg)); + } + break; + case 'o': + if (ofnam) + { + free(ofnam); + ofnam = NULL; + } + if ((strcmp(optarg, "-") == 0) || (strcmp(optarg, "stdout") == 0)) + { + outf = stdout; + } + else + { + ofnam = strndup(optarg, strlen(optarg)); + } + break; + case 'E': + token = strndup(optarg,strlen(optarg)); + if (ignoreToks == NULL) + { + ignoreToks = (tokenlist *)malloc(sizeof(tokenlist)); + if (ignoreToks == NULL) goto memerr; + ignoreToks->token = token; + ignoreToks->next = NULL; + lastIgnoreToken = ignoreToks; + } + else + { + lastIgnoreToken->next = (tokenlist *)malloc(sizeof(tokenlist)); + if (lastIgnoreToken->next == NULL) goto memerr; + lastIgnoreToken = lastIgnoreToken->next; + lastIgnoreToken->next = NULL; + lastIgnoreToken->token = token; + } + break; + case 'I': + token = strndup(optarg, strlen(optarg)); + if (includeToks == NULL) + { + includeToks = (tokenlist *)malloc(sizeof(tokenlist)); + if (includeToks == NULL) goto memerr; + includeToks->token = token; + includeToks->next = NULL; + lastIncludeToken = includeToks; + } + else + { + lastIncludeToken->next = (tokenlist *)malloc(sizeof(tokenlist)); + if (lastIncludeToken->next == NULL) goto memerr; + lastIncludeToken = lastIncludeToken->next; + lastIncludeToken->next = NULL; + lastIncludeToken->token = token; + } + break; + case 'd': /* Default handling: include/exclude */ + if (strcmp(optarg, "i") == 0) + { + default_include = 1; + } + else if (strcmp(optarg, "e") == 0) + { + default_include = 0; + } + else + { + usage(1); + } + break; + default: + usage(1); + exit(1); + } + } + if (ifnam) + { + inf = fopen(ifnam, "r"); + if (inf == NULL) + { + fprintf(stderr, "Cannot open input file %s, %s\n", ifnam, strerror(errno)); + exit(1); + } + } + inf_lno = 0; + if (ofnam) + { + outf = fopen(ofnam, "w"); + if (outf == NULL) + { + fprintf(stderr, "Cannot open output file %s, %s\n", ofnam, strerror(errno)); + exit(1); + } + } + make_sgml(1); + exit(0); + + memerr: + fprintf(stderr, "Memory not available.\n"); + exit(1); +} + +int my_getline(char *buf) +{ + int c; + + c = getc(inf); + if (c == EOF) + { + *buf = 0; + return(EOF); + } + else + { + ungetc(c, inf); + } + for(;;) { + c = getc(inf); + switch(c) + { + case '\n': + *buf++ = c; + *buf = 0; + inf_lno++; + return(1); + case EOF: + *buf = 0; + inf_lno++; + return(1); + default: + *buf++ = c; + continue; + } + } + exit(1); +} + + +int find_match(char *token, tokenlist *toks) +{ + tokenlist *currToks; + + for (currToks = toks; currToks; currToks = currToks->next) + { + if (strcmp(token, currToks->token) == 0) + return(1); + } + return(0); +} + +int find_match_exclude(char *token) +{ + return(find_match(token, ignoreToks)); +} + +int find_match_include(char *token) +{ + return(find_match(token, includeToks)); +} + +void format_err(int lno) +{ + fprintf(stderr, "Input file format error. Line %d.\n", lno); + exit(1); +} + + +void make_sgml(int writeflag) +{ + int rv; + char inputline[4096]; + + for(;;) { + char *curr; + char *token; + + rv = my_getline(inputline); + if (rv == EOF) + return; + curr = inputline; + for (;;curr++) { + if (*curr == ' ' || *curr == '\t') + continue; + else + break; + } + if (memcmp(curr, STARTTOKEN, strlen(STARTTOKEN)) == 0) + { + curr += strlen(STARTTOKEN); + if (*curr != ' ' && *curr != '\t') { + format_err(inf_lno); + } + for (curr++;;curr++) { + if (*curr == '\n' || *curr == 0) { + format_err(inf_lno); + } + if (*curr == ' ' || *curr == '\t') { + continue; + } + else { + break; + } + } + token = curr; + for (;;curr++) { + if (*curr == '\n' || *curr == 0) { + format_err(inf_lno); + } + if (*curr == ' ' || *curr == '\t') { + *curr = 0; + curr++; + break; + } + else if (*curr == '>') { + *curr = 0; + curr++; + *curr = '>'; + break; + } + else { + continue; + } + } + for (;;curr++) { + if (*curr == '\n' || *curr == 0) { + format_err(inf_lno); + } + if (*curr == ' ' || *curr == '\t') { + continue; + } + else if (*curr == '>') { + break; + } + else { + format_err(inf_lno); + } + } + /* You can write anything after clsing '>' */ + fputc('\n', outf); + if (strcmp(token, "end") == 0) + return; + if (find_match_exclude(token)) { + make_sgml(0); + } + else if (find_match_include(token)) { + if (writeflag) + make_sgml(1); + else + make_sgml(0); + } + else { + make_sgml(0); + } + } + else + { + if (writeflag) + fputs(inputline, outf); + else + fputc('\n', outf); + } + } + exit(1); +} + +void usage(int exitcode) +{ + fprintf(stderr, + "%s -i infile -o outfile [-d i|e ] -D exclude_token -D ... -U include_token -U ...\n", + progname); + exit(exitcode); +} diff --git a/doc/tools/makesgml/test.multilang b/doc/tools/makesgml/test.multilang new file mode 100644 index 0000000..b6ce67c --- /dev/null +++ b/doc/tools/makesgml/test.multilang @@ -0,0 +1,22 @@ +Common to PostgreSQL and Postgres-XC, English or Japanese + +<!## PGXC > +PGXC +<!## en > +this +<!## end > +<!## jp > +ãã +<!## end > +<!## end > + +<!## PostgreSQL > +PostgreSQL +<!## en > +that +<!## end > +<!## jp > +ãã +<!## end > +<!## end > +ddd diff --git a/doc/tools/makesgml/test.out b/doc/tools/makesgml/test.out new file mode 100644 index 0000000..994ce81 --- /dev/null +++ b/doc/tools/makesgml/test.out @@ -0,0 +1,13 @@ +abcdefg + + +this + +more + + + + + + +ddd diff --git a/doc/tools/makesgml/test.test b/doc/tools/makesgml/test.test new file mode 100644 index 0000000..90f8bc7 --- /dev/null +++ b/doc/tools/makesgml/test.test @@ -0,0 +1,13 @@ +abcdefg + +<!## this> +this +<!## more> +more +<!## end> +<!## end> +<!## that> +that +<!## end> + +ddd ----------------------------------------------------------------------- hooks/post-receive -- Postgres-XC |
From: Michael P. <mic...@us...> - 2011-04-06 00:57:25
|
Project "Postgres-XC". The branch, master has been updated via 112ad257947a5cc60b7c598880d335a5b9a351c1 (commit) from e1946160fe64042e76b5252c66b6f6fb5da6b85d (commit) - Log ----------------------------------------------------------------- commit 112ad257947a5cc60b7c598880d335a5b9a351c1 Author: Michael P <mic...@us...> Date: Wed Apr 6 09:34:39 2011 +0900 Fix a memory leak in GTM: free connection data A memory free for string pgxc_node_id was not done, making it a possible memory leak. Patch written by Terasaka Mitsunobu diff --git a/src/gtm/client/fe-connect.c b/src/gtm/client/fe-connect.c index 9e2b564..52ce93c 100644 --- a/src/gtm/client/fe-connect.c +++ b/src/gtm/client/fe-connect.c @@ -869,6 +869,8 @@ freeGTM_Conn(GTM_Conn *conn) free(conn->pgport); if (conn->connect_timeout) free(conn->connect_timeout); + if (conn->pgxc_node_id) + free(conn->pgxc_node_id); if (conn->inBuffer) free(conn->inBuffer); if (conn->outBuffer) ----------------------------------------------------------------------- Summary of changes: src/gtm/client/fe-connect.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) hooks/post-receive -- Postgres-XC |
From: Koichi S. <koi...@us...> - 2011-04-05 10:02:09
|
Project "Postgres-XC". The branch, ha_support has been updated via 0794d85a15b5124f666190926ae036dec9f39855 (commit) from c811d7f4a755154cdf9f4b5e0353aad56fa16331 (commit) - Log ----------------------------------------------------------------- commit 0794d85a15b5124f666190926ae036dec9f39855 Author: Koichi Suzuki <koi...@gm...> Date: Tue Apr 5 19:00:05 2011 +0900 This commit is to tweak the message from xcm_telhowto. When all the coordinators fails, it tells to stop the failed coordinator and then shutdown whole cluster. If all the mirrors of a datanode fails, it does not tell to stop the last failed mirror and just tells to shutdown the whole cluster. This commit tweaks this bahavior and tells to stop the last failed mirror before shutdown. diff --git a/src/pgxc/xcm/xcm_telhowto.c b/src/pgxc/xcm/xcm_telhowto.c index c53d257..3a3afa8 100644 --- a/src/pgxc/xcm/xcm_telhowto.c +++ b/src/pgxc/xcm/xcm_telhowto.c @@ -605,7 +605,11 @@ static void handle_mirror_failure(int ac, char *av[]) if (surviving_mirror <= 0) { /* * No mirror available! + * Anyway we should try to stop the mirro gracefully before shutdown. + * Please note it may not make sense to try to change primary. + * There's no datanode mirror surviving to take over primary. */ + printf("stop mirror %d %d\n", datanode_id, mirror_id); printf("shutdown\n"); fflush(stdout); return; ----------------------------------------------------------------------- Summary of changes: src/pgxc/xcm/xcm_telhowto.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) hooks/post-receive -- Postgres-XC |
From: Koichi S. <koi...@us...> - 2011-04-05 09:40:42
|
Project "Postgres-XC". The branch, ha_support has been updated via c811d7f4a755154cdf9f4b5e0353aad56fa16331 (commit) from 79263d24f7768522f238b7be0b8c07fc162fb742 (commit) - Log ----------------------------------------------------------------- commit c811d7f4a755154cdf9f4b5e0353aad56fa16331 Author: Koichi Suzuki <koi...@gm...> Date: Tue Apr 5 18:38:43 2011 +0900 This commit is a tweak to gtm_txn.c to avoid warning messages at the time of make. This code is not complete yet and actually is not used from any other code. To avoid any problems in the future, I added some of the lines so that the variable is properly initialized and we will have assert message when incomplete codes are accidentally reached. diff --git a/src/gtm/main/gtm_txn.c b/src/gtm/main/gtm_txn.c index 9cfbeb6..0c6c238 100644 --- a/src/gtm/main/gtm_txn.c +++ b/src/gtm/main/gtm_txn.c @@ -101,7 +101,7 @@ GTM_InitTxnManager(void) static XidStatus GlobalTransactionIdGetStatus(GlobalTransactionId transactionId) { - XidStatus xidstatus; + XidStatus xidstatus = TRANSACTION_STATUS_IN_PROGRESS; /* * Also, check to see if the transaction ID is a permanent one. @@ -117,7 +117,10 @@ GlobalTransactionIdGetStatus(GlobalTransactionId transactionId) /* * TODO To be implemeneted + * + * This code is not completed yet and the latter code must not be reached. */ + Assert(0); return xidstatus; } ----------------------------------------------------------------------- Summary of changes: src/gtm/main/gtm_txn.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) hooks/post-receive -- Postgres-XC |
From: Koichi S. <koi...@us...> - 2011-04-05 05:14:15
|
Project "Postgres-XC". The branch, ha_support has been updated via 79263d24f7768522f238b7be0b8c07fc162fb742 (commit) from 1fc12bd8cc427393ad4c0597a85c35060e1b1a2b (commit) - Log ----------------------------------------------------------------- commit 79263d24f7768522f238b7be0b8c07fc162fb742 Author: Koichi Suzuki <koi...@gm...> Date: Tue Apr 5 14:12:24 2011 +0900 This commit is to fix wrong commit done last. It was to fix xcm_telhowto behavior where it should have told to shutdown the cluster when no coordinator is running. Code correction was wrong and was corrected. Thanks Sudo-san for findding this. diff --git a/src/include/pgxc/xcm/node_membership_struct.h b/src/include/pgxc/xcm/node_membership_struct.h index 754e472..affad93 100644 --- a/src/include/pgxc/xcm/node_membership_struct.h +++ b/src/include/pgxc/xcm/node_membership_struct.h @@ -460,13 +460,13 @@ typedef struct xcm_fault_comps { */ #define XCM_OK 0 /* Successful */ #define XCM_OTHER_UPDATE 1 /* Shared memory updated for some reason */ +#define XCM_ERR_COMP_FAILED 2 /* Specified component is not running */ #define XCM_ERR_NOT_INITIALIZED -1 /* Shared memory not built yet */ #define XCM_ERR_OUT_OF_RANGE -2 /* Specified component does not exist */ -#define XCM_ERR_COMP_FAILED -3 /* Specified component is not running */ -#define XCM_ERR_MISC -4 /* Other system call error */ -#define XCM_ERR_PARM -5 /* Invalid parameters specified */ -#define XCM_ERR_STATUS -6 /* Cluster status cannot accept the operation */ -#define XCM_NOT_FOUND -7 /* Indicates that the specified object not found */ +#define XCM_ERR_MISC -3 /* Other system call error */ +#define XCM_ERR_PARM -4 /* Invalid parameters specified */ +#define XCM_ERR_STATUS -5 /* Cluster status cannot accept the operation */ +#define XCM_NOT_FOUND -6 /* Indicates that the specified object not found */ /* * Misc. magic numbers/values. diff --git a/src/pgxc/xcm/xcm_telhowto.c b/src/pgxc/xcm/xcm_telhowto.c index 41e736f..c53d257 100644 --- a/src/pgxc/xcm/xcm_telhowto.c +++ b/src/pgxc/xcm/xcm_telhowto.c @@ -514,7 +514,7 @@ static void handle_coordinator_failure(int ac, char *av[]) rv, __LINE__); end_and_exit(1); } - for (ii = 1, live_coord_count = 0; ii <= rv; ii++) + for (ii = 1, live_coord_count = 0; ii <= coord_count; ii++) { rv = get_xcm_coordinator_status(ii, &coord_status); if (rv < 0) @@ -530,7 +530,7 @@ static void handle_coordinator_failure(int ac, char *av[]) } if (live_coord_count <= 0) { - printf("shutdonw\n"); + printf("shutdown\n"); end_and_exit(0); } fflush(stdout); ----------------------------------------------------------------------- Summary of changes: src/include/pgxc/xcm/node_membership_struct.h | 10 +++++----- src/pgxc/xcm/xcm_telhowto.c | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) hooks/post-receive -- Postgres-XC |
From: Koichi S. <koi...@us...> - 2011-04-04 06:18:22
|
Project "Postgres-XC". The branch, ha_support has been updated via 1fc12bd8cc427393ad4c0597a85c35060e1b1a2b (commit) from 066fb159d1008f869bd396bb4be4d966bb0a74cf (commit) - Log ----------------------------------------------------------------- commit 1fc12bd8cc427393ad4c0597a85c35060e1b1a2b Author: Koichi Suzuki <koi...@gm...> Date: Mon Apr 4 15:17:08 2011 +0900 This commit is to fix the bug #3266463 in the track. Now xcm_telhowto tells to shutdown the whole cluster if no coordinators are running. diff --git a/src/pgxc/xcm/xcm_telhowto.c b/src/pgxc/xcm/xcm_telhowto.c index 8488cfb..41e736f 100644 --- a/src/pgxc/xcm/xcm_telhowto.c +++ b/src/pgxc/xcm/xcm_telhowto.c @@ -476,6 +476,9 @@ static void handle_coordinator_failure(int ac, char *av[]) int coord_id; /* Failed one */ int coord_count; int rv; + int ii; + unsigned coord_status; + int live_coord_count; rv = str_toi(&coord_id, av[3]); if (rv) @@ -501,6 +504,35 @@ static void handle_coordinator_failure(int ac, char *av[]) * Clean outstanding 2PCs */ printf("cleanup coordinator %d\n", coord_id); + /* + * Check if we can continue XCM cluster operation + */ + rv = get_xcm_coordinator_count(&coord_count); + if (rv < 0) + { + printf("ERR: Coundn't get coordinator count (%d, %d)\n", + rv, __LINE__); + end_and_exit(1); + } + for (ii = 1, live_coord_count = 0; ii <= rv; ii++) + { + rv = get_xcm_coordinator_status(ii, &coord_status); + if (rv < 0) + { + printf("ERR: Couldn't get coordinator %d status (%d, %d)\n", + ii, rv, __LINE__); + end_and_exit(1); + } + if (XCM_IS_RUNNING(coord_status)) + { + live_coord_count++; + } + } + if (live_coord_count <= 0) + { + printf("shutdonw\n"); + end_and_exit(0); + } fflush(stdout); return; } ----------------------------------------------------------------------- Summary of changes: src/pgxc/xcm/xcm_telhowto.c | 32 ++++++++++++++++++++++++++++++++ 1 files changed, 32 insertions(+), 0 deletions(-) hooks/post-receive -- Postgres-XC |
From: Koichi S. <koi...@us...> - 2011-04-04 02:49:59
|
Project "Postgres-XC". The branch, ha_support has been updated via 066fb159d1008f869bd396bb4be4d966bb0a74cf (commit) from 263fffdb2d9865eac2d6780b2ac7edb6d4c0b857 (commit) - Log ----------------------------------------------------------------- commit 066fb159d1008f869bd396bb4be4d966bb0a74cf Author: Koichi Suzuki <koi...@gm...> Date: Mon Apr 4 11:45:24 2011 +0900 This commit resolves conflict to build pgxc_clean and gtm-standby. Gtm-standby introduced more module from Postgres-XC core and it introduced some conflicts to build pgxc_clean. They're resolved by this commit, which changed conflicted indentifiers. diff --git a/src/gtm/common/gtm_serialize.c b/src/gtm/common/gtm_serialize.c new file mode 100644 index 0000000..cdd9cdd --- /dev/null +++ b/src/gtm/common/gtm_serialize.c @@ -0,0 +1,864 @@ + + +#include "gtm/gtm_c.h" +#include "gtm/elog.h" +#include "gtm/palloc.h" +#include "gtm/gtm.h" +#include "gtm/gtm_txn.h" +#include "gtm/gtm_seq.h" +#include "gtm/assert.h" +#include "gtm/register.h" +#include "gtm/stringinfo.h" +#include "gtm/libpq.h" +#include "gtm/pqformat.h" +#include "gtm/gtm_msg.h" + +#include "gtm/gtm_serialize.h" + +//#include "gtm/gtm_list.h" +//#include "gtm/memutils.h" + +/* ----------------------------------------------------- + * Get a serialized size of GTM_SnapshotData structure + * ----------------------------------------------------- + */ +size_t +gtm_get_snapshotdata_size(GTM_SnapshotData *data) +{ + size_t len = 0; + + len += sizeof(GlobalTransactionId); + len += sizeof(GlobalTransactionId); + len += sizeof(GlobalTransactionId); + len += sizeof(uint32); + len += sizeof(GlobalTransactionId); + + return len; +} + +/* ----------------------------------------------------- + * Serialize a GTM_SnapshotData structure + * ----------------------------------------------------- + */ +size_t +gtm_serialize_snapshotdata(GTM_SnapshotData *data, char *buf, size_t buflen) +{ + int len = 0; + + memset(buf, 0, buflen); + + /* size check */ + if ( gtm_get_snapshotdata_size(data) > buflen ) + return 0; + + /* GTM_SnapshotData.sn_xmin */ + memcpy(buf+len, &(data->sn_xmin), sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_SnapshotData.sn_xmax */ + memcpy(buf+len, &(data->sn_xmax), sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_SnapshotData.sn_recent_global_xmin */ + memcpy(buf+len, &(data->sn_recent_global_xmin), sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_SnapshotData.sn_xcnt */ + memcpy(buf+len, &(data->sn_xcnt), sizeof(uint32)); + len += sizeof(uint32); + + /* GTM_SnapshotData.sn_xip */ + memcpy(buf+len, &(data->sn_xip), sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + return len; +} + +/* ----------------------------------------------------- + * Deserialize a GTM_SnapshotData structure + * ----------------------------------------------------- + */ +size_t +gtm_deserialize_snapshotdata(GTM_SnapshotData *data, const char *buf, size_t buflen) +{ + size_t len = 0; + + /* GTM_SnapshotData.sn_xmin */ + memcpy(&(data->sn_xmin), buf+len, sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_SnapshotData.sn_xmax */ + memcpy(&(data->sn_xmax), buf+len, sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_SnapshotData.sn_recent_global_xmin */ + memcpy(&(data->sn_recent_global_xmin), buf+len, sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_SnapshotData.sn_xcnt */ + memcpy(&(data->sn_xcnt), buf+len, sizeof(uint32)); + len += sizeof(uint32); + + /* GTM_SnapshotData.sn_xip */ + memcpy(&(data->sn_xip), buf+len, sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + return len; +} + + +/* ----------------------------------------------------- + * Get a serialized size ofGTM_TransactionInfo structure + * ----------------------------------------------------- + */ +size_t +gtm_get_transactioninfo_size(GTM_TransactionInfo *data) +{ + size_t len = 0; + + if ( data==NULL ) + return len; + + len += sizeof(GTM_TransactionHandle); /* gti_handle */ + len += sizeof(GTM_ThreadID); /* gti_thread_id */ + len += sizeof(bool); /* gti_in_use */ + len += sizeof(GlobalTransactionId); /* gti_gxid */ + len += sizeof(GTM_TransactionStates); /* gti_state */ + len += sizeof(PGXC_NodeId); /* gti_coordid */ + len += sizeof(GlobalTransactionId); /* gti_xmin */ + len += sizeof(GTM_IsolationLevel); /* gti_isolevel */ + len += sizeof(bool); /* gti_readonly */ + len += sizeof(GTMProxy_ConnID); /* gti_backend_id */ + len += sizeof(uint32); /* gti_datanodecount */ + len += sizeof(PGXC_NodeId) * data->gti_datanodecount; + /* gti_datanodes */ + len += sizeof(uint32); /* gti_coordcount */ + len += sizeof(PGXC_NodeId) * data->gti_coordcount; + /* gti_coordinators */ + + if ( data->gti_gid != NULL ) + len += strlen(data->gti_gid) + 1; /* gti_gid */ + else + len += 1; + + len += gtm_get_snapshotdata_size( &(data->gti_current_snapshot) ); + /* gti_current_snapshot */ + len += sizeof(bool); /* gti_snapshot_set */ + /* NOTE: nothing to be done for gti_lock */ + len += sizeof(bool); /* gti_vacuum */ + + return len; +} + + +/* ----------------------------------------------------- + * Serialize a GTM_TransactionInfo structure + * ----------------------------------------------------- + */ +size_t +gtm_serialize_transactioninfo(GTM_TransactionInfo *data, char *buf, size_t buflen) +{ + int len = 0; + char *buf2; + int i; + + /* size check */ + if ( gtm_get_transactioninfo_size(data) > buflen ) + return 0; + + memset(buf, 0, buflen); + + /* GTM_TransactionInfo.gti_handle */ + memcpy(buf+len, &(data->gti_handle), sizeof(GTM_TransactionHandle)); + len += sizeof(GTM_TransactionHandle); + + /* GTM_TransactionInfo.gti_thread_id */ + memcpy(buf+len, &(data->gti_thread_id), sizeof(GTM_ThreadID)); + len += sizeof(GTM_ThreadID); + + /* GTM_TransactionInfo.gti_in_use */ + memcpy(buf+len, &(data->gti_in_use), sizeof(bool)); + len += sizeof(bool); + + /* GTM_TransactionInfo.gti_gxid */ + memcpy(buf+len, &(data->gti_gxid), sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_TransactionInfo.gti_state */ + memcpy(buf+len, &(data->gti_state), sizeof(GTM_TransactionStates)); + len += sizeof(GTM_TransactionStates); + + /* GTM_TransactionInfo.gti_coordid */ + memcpy(buf+len, &(data->gti_coordid), sizeof(PGXC_NodeId)); + len += sizeof(PGXC_NodeId); + + /* GTM_TransactionInfo.gti_xmin */ + memcpy(buf+len, &(data->gti_xmin), sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_TransactionInfo.gti_isolevel */ + memcpy(buf+len, &(data->gti_isolevel), sizeof(GTM_IsolationLevel)); + len += sizeof(GTM_IsolationLevel); + + /* GTM_TransactionInfo.gti_readonly */ + memcpy(buf+len, &(data->gti_readonly), sizeof(bool)); + len += sizeof(bool); + + /* GTM_TransactionInfo.gti_backend_id */ + memcpy(buf+len, &(data->gti_backend_id), sizeof(GTMProxy_ConnID)); + len += sizeof(GTMProxy_ConnID); + + /* GTM_TransactionInfo.gti_datanodecount */ + memcpy(buf+len, &(data->gti_datanodecount), sizeof(uint32)); + len += sizeof(uint32); + + /* GTM_TransactionInfo.gti_datanodes */ + for (i=0 ; i<data->gti_datanodecount ; i++) + { + memcpy(buf+len, &(data->gti_datanodes[i]), sizeof(PGXC_NodeId)); + len += sizeof(PGXC_NodeId); + } + + /* GTM_TransactionInfo.gti_coordcount */ + memcpy(buf+len, &(data->gti_coordcount), sizeof(uint32)); + len += sizeof(uint32); + + /* GTM_TransactionInfo.gti_coordinators */ + for (i=0 ; i<data->gti_coordcount ; i++) + { + memcpy(buf+len, &(data->gti_coordinators[i]), sizeof(PGXC_NodeId)); + len += sizeof(PGXC_NodeId); + } + + /* GTM_TransactionInfo.gti_gid */ + if ( data->gti_gid!=NULL ) + { + memcpy(buf+len, data->gti_gid, strlen(data->gti_gid)); + len += strlen(data->gti_gid) + 1; /* null-terminated */ + } + else + { + *(buf+len) = '\0'; + len += 1; + } + + /* GTM_TransactionInfo.gti_current_snapshot */ + buf2 = malloc( gtm_get_snapshotdata_size( &(data->gti_current_snapshot) ) ); + i = gtm_serialize_snapshotdata( &(data->gti_current_snapshot), + buf2, + gtm_get_snapshotdata_size( &(data->gti_current_snapshot) )); + memcpy(buf+len, buf2, i); + free(buf2); + len += i; + + /* GTM_TransactionInfo.gti_snapshot_set */ + memcpy(buf+len, &(data->gti_snapshot_set), sizeof(bool)); + len += sizeof(bool); + + /* GTM_TransactionInfo.gti_lock would not be serialized. */ + + /* GTM_TransactionInfo.gti_vacuum */ + memcpy(buf+len, &(data->gti_vacuum), sizeof(bool)); + len += sizeof(bool); + + return len; +} + +/* ----------------------------------------------------- + * Deserialize a GTM_TransactionInfo structure + * ----------------------------------------------------- + */ +size_t +gtm_deserialize_transactioninfo(GTM_TransactionInfo *data, const char *buf, size_t maxlen) +{ + int len = 0; + int i; + + memset(data, 0, sizeof(GTM_TransactionInfo)); + + /* GTM_TransactionInfo.gti_handle */ + memcpy(&(data->gti_handle), buf+len, sizeof(GTM_TransactionHandle)); + len += sizeof(GTM_TransactionHandle); + + /* GTM_TransactionInfo.gti_thread_id */ + memcpy(&(data->gti_thread_id), buf+len, sizeof(GTM_ThreadID)); + len += sizeof(GTM_ThreadID); + + /* GTM_TransactionInfo.gti_in_use */ + memcpy(&(data->gti_in_use), buf+len, sizeof(bool)); + len += sizeof(bool); + + /* GTM_TransactionInfo.gti_gxid */ + memcpy(&(data->gti_gxid), buf+len, sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_TransactionInfo.gti_state */ + memcpy(&(data->gti_state), buf+len, sizeof(GTM_TransactionStates)); + len += sizeof(GTM_TransactionStates); + + /* GTM_TransactionInfo.gti_coordid */ + memcpy(&(data->gti_coordid), buf+len, sizeof(PGXC_NodeId)); + len += sizeof(PGXC_NodeId); + + /* GTM_TransactionInfo.gti_xmin */ + memcpy(&(data->gti_xmin), buf+len, sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_TransactionInfo.gti_isolevel */ + memcpy(&(data->gti_isolevel), buf+len, sizeof(GTM_IsolationLevel)); + len += sizeof(GTM_IsolationLevel); + + /* GTM_TransactionInfo.gti_readonly */ + memcpy(&(data->gti_readonly), buf+len, sizeof(bool)); + len += sizeof(bool); + + /* GTM_TransactionInfo.gti_backend_id */ + memcpy(&(data->gti_backend_id), buf+len, sizeof(GTMProxy_ConnID)); + len += sizeof(GTMProxy_ConnID); + + /* GTM_TransactionInfo.gti_datanodecount */ + memcpy(&(data->gti_datanodecount), buf+len, sizeof(uint32)); + len += sizeof(uint32); + + /* GTM_TransactionInfo.gti_datanodes */ + data->gti_datanodes = (PGXC_NodeId *)malloc( sizeof(PGXC_NodeId) * data->gti_datanodecount ); + + for (i=0 ; i<data->gti_datanodecount ; i++) + { + memcpy(&(data->gti_datanodes[i]), buf+len, sizeof(PGXC_NodeId)); + len += sizeof(PGXC_NodeId); + } + + /* GTM_TransactionInfo.gti_coordcount */ + memcpy(&(data->gti_coordcount), buf+len, sizeof(uint32)); + len += sizeof(uint32); + + /* GTM_TransactionInfo.gti_coordinators */ + data->gti_coordinators = (PGXC_NodeId *)malloc( sizeof(PGXC_NodeId) * data->gti_coordcount ); + + for (i=0 ; i<data->gti_coordcount ; i++) + { + PGXC_NodeId *cur = data->gti_coordinators; + + memcpy(cur, buf+len, sizeof(PGXC_NodeId)); + + len += sizeof(PGXC_NodeId); + cur++; + } + + /* GTM_TransactionInfo.gti_gid */ + if ( *(buf+len) != '\0' ) + { + data->gti_gid = (char *)malloc( strlen(buf+len)+1); + strncpy(data->gti_gid, buf+len, strlen(buf+len) ); + len += strlen(buf+len) + 1; /* null-terminated */ + } + else + { + data->gti_gid = NULL; + len += 1; + } + + /* GTM_TransactionInfo.gti_current_snapshot */ + i = gtm_deserialize_snapshotdata( &(data->gti_current_snapshot), + buf+len, + sizeof(GTM_SnapshotData) ); + len += i; + + /* GTM_TransactionInfo.gti_snapshot_set */ + memcpy(&(data->gti_snapshot_set), buf+len, sizeof(bool)); + len += sizeof(bool); + + /* GTM_TransactionInfo.gti_lock would not be serialized. */ + + /* GTM_TransactionInfo.gti_vacuum */ + memcpy(&(data->gti_vacuum), buf+len, sizeof(bool)); + len += sizeof(bool); + + return len; +} + + +size_t +gtm_get_transactions_size(GTM_Transactions *data) +{ + size_t len = 0; + int i; + + len += sizeof(uint32); /* gt_txn_count */ + len += sizeof(GTM_States); /* gt_gtm_state */ + + /* NOTE: nothing to be done for gt_XidGenLock */ + + len += sizeof(GlobalTransactionId); /* gt_nextXid */ + len += sizeof(GlobalTransactionId); /* gt_oldestXid */ + len += sizeof(GlobalTransactionId); /* gt_xidVacLimit */ + len += sizeof(GlobalTransactionId); /* gt_xidWarnLimit */ + len += sizeof(GlobalTransactionId); /* gt_xidStopLimit */ + len += sizeof(GlobalTransactionId); /* gt_xidWrapLimit */ + + len += sizeof(GlobalTransactionId); /* gt_latestCompletedXid */ + len += sizeof(GlobalTransactionId); /* gt_recent_global_xmin */ + + len += sizeof(int32); /* gt_lastslot */ + + len += sizeof(int32); /* txn_count */ + + for (i=0 ; i<GTM_MAX_GLOBAL_TRANSACTIONS ; i++) + { + len += sizeof(size_t); /* length */ + len += gtm_get_transactioninfo_size(&data->gt_transactions_array[i]); + } + + /* NOTE: nothing to be done for gt_open_transactions */ + /* NOTE: nothing to be done for gt_TransArrayLock */ + + return len; +} + +size_t +gtm_serialize_transactions(GTM_Transactions *data, char *buf, size_t buflen) +{ + int len = 0; + int i; + uint32 txn_count; + + /* size check */ + if ( gtm_get_transactions_size(data) > buflen ) + return 0; + + memset(buf, 0, buflen); + + /* GTM_Transactions.gt_txn_count */ + memcpy(buf+len, &(data->gt_txn_count), sizeof(uint32)); + len += sizeof(uint32); + + /* GTM_Transactions.gt_gtm_state */ + memcpy(buf+len, &(data->gt_gtm_state), sizeof(GTM_States)); + len += sizeof(GTM_States); + + /* NOTE: nothing to be done for gt_XidGenLock */ + + /* GTM_Transactions.gt_nextXid */ + memcpy(buf+len, &(data->gt_nextXid), sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_Transactions.gt_oldestXid */ + memcpy(buf+len, &(data->gt_oldestXid), sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_Transactions.gt_xidVacLimit */ + memcpy(buf+len, &(data->gt_xidVacLimit), sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_Transactions.gt_xidWarnLimit */ + memcpy(buf+len, &(data->gt_xidWarnLimit), sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_Transactions.gt_xidStopLimit */ + memcpy(buf+len, &(data->gt_xidStopLimit), sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_Transactions.gt_xidWrapLimit */ + memcpy(buf+len, &(data->gt_xidWrapLimit), sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_Transactions.gt_latestCompletedXid */ + memcpy(buf+len, &(data->gt_latestCompletedXid), sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_Transactions.gt_recent_global_xmin */ + memcpy(buf+len, &(data->gt_recent_global_xmin), sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_Transactions.gt_lastslot */ + memcpy(buf+len, &(data->gt_lastslot), sizeof(int32)); + len += sizeof(int32); + + /* Count up for valid transactions. */ + txn_count = 0; + + for (i=0 ; i<GTM_MAX_GLOBAL_TRANSACTIONS ; i++) + { + if ( data->gt_transactions_array[i].gti_gxid != InvalidGlobalTransactionId ) + txn_count++; + } + + memcpy(buf+len, &txn_count, sizeof(int32)); + len += sizeof(int32); + + /* + * GTM_Transactions.gt_transactions_array + */ + for (i=0 ; i<txn_count ; i++) + { + char *buf2; + size_t buflen2, len2; + + /* + * Not to include invalid global transactions. + */ + if ( data->gt_transactions_array[i].gti_gxid == InvalidGlobalTransactionId ) + continue; + + buflen2 = gtm_get_transactioninfo_size( &data->gt_transactions_array[i] ); + + /* store a length of following data. */ + memcpy(buf+len, &buflen2, sizeof(size_t)); + len += sizeof(size_t); + + buf2 = (char *)malloc( buflen2 ); + + len2 = gtm_serialize_transactioninfo( &data->gt_transactions_array[i], + buf2, + buflen2); + + /* store a serialized GTM_TransactionInfo structure. */ + memcpy(buf+len, buf2, len2); + len += len2; + + free(buf2); + } + + // dump_transactions_elog(data, txn_count); + + /* NOTE: nothing to be done for gt_TransArrayLock */ + + return len; +} + + +/* + * Return a number of deserialized transactions. + */ +size_t +gtm_deserialize_transactions(GTM_Transactions *data, const char *buf, size_t maxlen) +{ + int len = 0; + int i; + uint32 txn_count; + + /* GTM_Transactions.gt_txn_count */ + memcpy(&(data->gt_txn_count), buf+len, sizeof(uint32)); + len += sizeof(uint32); + + /* GTM_Transactions.gt_gtm_state */ + memcpy(&(data->gt_gtm_state), buf+len, sizeof(GTM_States)); + len += sizeof(GTM_States); + + /* NOTE: nothing to be done for gt_XidGenLock */ + + /* GTM_Transactions.gt_nextXid */ + memcpy(&(data->gt_nextXid), buf+len, sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_Transactions.gt_oldestXid */ + memcpy(&(data->gt_oldestXid), buf+len, sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_Transactions.gt_xidVacLimit */ + memcpy(&(data->gt_xidVacLimit), buf+len, sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_Transactions.gt_xidWarnLimit */ + memcpy(&(data->gt_xidWarnLimit), buf+len, sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_Transactions.gt_xidStopLimit */ + memcpy(&(data->gt_xidStopLimit), buf+len, sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_Transactions.gt_xidWrapLimit */ + memcpy(&(data->gt_xidWrapLimit), buf+len, sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_Transactions.gt_latestCompletedXid */ + memcpy(&(data->gt_latestCompletedXid), buf+len, sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_Transactions.gt_recent_global_xmin */ + memcpy(&(data->gt_recent_global_xmin), buf+len, sizeof(GlobalTransactionId)); + len += sizeof(GlobalTransactionId); + + /* GTM_Transactions.gt_lastslot */ + memcpy(&(data->gt_lastslot), buf+len, sizeof(int32)); + len += sizeof(int32); + + /* A number of valid transactions */ + memcpy(&txn_count, buf+len, sizeof(int32)); + len += sizeof(int32); + + /* GTM_Transactions.gt_transactions_array */ + for (i=0 ; i<txn_count ; i++) + { + size_t buflen2, len2; + + /* read a length of following data. */ + memcpy(&buflen2, buf+len, sizeof(size_t)); + len += sizeof(size_t); + + /* reada serialized GTM_TransactionInfo structure. */ + len2 = gtm_deserialize_transactioninfo( &(data->gt_transactions_array[i]), + buf+len, + buflen2); + + len += len2; + } + + /* NOTE: nothing to be done for gt_TransArrayLock */ + + return txn_count; +} + +size_t +gtm_get_pgxcnodeinfo_size(GTM_PGXCNodeInfo *data) +{ + size_t len = 0; + + len += sizeof(GTM_PGXCNodeType); /* type */ + len += sizeof(GTM_PGXCNodeId); /* nodenum */ + len += sizeof(GTM_PGXCNodeId); /* proxynum */ + len += sizeof(GTM_PGXCNodePort); /* port */ + + if ( data->ipaddress == NULL ) /* ipaddress */ + len += 1; + else + len += strlen(data->ipaddress) + 1; + + if ( data->datafolder == NULL ) /* datafolder */ + len += 1; + else + len += strlen(data->datafolder) + 1; + + len += sizeof(GTM_PGXCNodeStatus); /* status */ + + return len; +} + +size_t +gtm_serialize_pgxcnodeinfo(GTM_PGXCNodeInfo *data, char *buf, size_t buflen) +{ + size_t len = 0; + + /* size check */ + if ( gtm_get_pgxcnodeinfo_size(data) > buflen ) + return 0; + + memset(buf, 0, buflen); + + /* GTM_PGXCNodeInfo.type */ + memcpy(buf+len, &(data->type), sizeof(GTM_PGXCNodeType)); + len += sizeof(GTM_PGXCNodeType); + + /* GTM_PGXCNodeInfo.nodenum */ + memcpy(buf+len, &(data->nodenum), sizeof(GTM_PGXCNodeId)); + len += sizeof(GTM_PGXCNodeId); + + /* GTM_PGXCNodeInfo.proxynum */ + memcpy(buf+len, &(data->proxynum), sizeof(GTM_PGXCNodeId)); + len += sizeof(GTM_PGXCNodeId); + + /* GTM_PGXCNodeInfo.port */ + memcpy(buf+len, &(data->port), sizeof(GTM_PGXCNodePort)); + len += sizeof(GTM_PGXCNodePort); + + /* GTM_PGXCNodeInfo.ipaddress */ + if ( data->ipaddress == NULL ) + { + len += 1; + } + else + { + strncpy(buf+len, data->ipaddress, strlen(data->ipaddress)); + len += strlen(data->ipaddress) + 1; + } + + /* GTM_PGXCNodeInfo.datafolder */ + if ( data->datafolder == NULL ) + { + len += 1; + } + else + { + strncpy(buf+len, data->datafolder, strlen(data->datafolder)); + len += strlen(data->datafolder) + 1; + } + + /* GTM_PGXCNodeInfo.status */ + memcpy(buf+len, &(data->status), sizeof(GTM_PGXCNodeStatus)); + len += sizeof(GTM_PGXCNodeStatus); + + /* NOTE: nothing to be done for node_lock */ + + return len; +} + +size_t +gtm_deserialize_pgxcnodeinfo(GTM_PGXCNodeInfo *data, const char *buf, size_t buflen) +{ + size_t len = 0; + + /* GTM_PGXCNodeInfo.type */ + memcpy(&(data->type), buf+len, sizeof(GTM_PGXCNodeType)); + len += sizeof(GTM_PGXCNodeType); + + /* GTM_PGXCNodeInfo.nodenum */ + memcpy(&(data->nodenum), buf+len, sizeof(GTM_PGXCNodeId)); + len += sizeof(GTM_PGXCNodeId); + + /* GTM_PGXCNodeInfo.proxynum */ + memcpy(&(data->proxynum), buf+len, sizeof(GTM_PGXCNodeId)); + len += sizeof(GTM_PGXCNodeId); + + /* GTM_PGXCNodeInfo.port */ + memcpy(&(data->port), buf+len, sizeof(GTM_PGXCNodePort)); + len += sizeof(GTM_PGXCNodePort); + + /* GTM_PGXCNodeInfo.ipaddress */ + if ( *(buf+len) == '\0' ) + { + len += 1; + data->ipaddress = NULL; + } + else + { + data->ipaddress = (char *)malloc( strlen(buf+len) ) + 1; + strncpy(data->ipaddress, buf+len, strlen(buf+len)); + len += strlen(buf+len) + 1; + } + + /* GTM_PGXCNodeInfo.datafolder */ + if ( *(buf+len) == '\0' ) + { + len += 1; + data->datafolder = NULL; + } + else + { + data->datafolder = (char *)malloc( strlen(buf+len) ) + 1; + strncpy(data->datafolder, buf+len, strlen(buf+len)); + len += strlen(buf+len) + 1; + } + + /* GTM_PGXCNodeInfo.status */ + memcpy(&(data->status), buf+len, sizeof(GTM_PGXCNodeStatus)); + len += sizeof(GTM_PGXCNodeStatus); + + /* NOTE: nothing to be done for node_lock */ + + return len; +} + +size_t +gtm_get_sequence_size(GTM_SeqInfo *seq) +{ + size_t len = 0; + + len += sizeof(uint32); /* gs_key.gsk_keylen */ + len += seq->gs_key->gsk_keylen; /* gs_key.gsk_key */ + len += sizeof(GTM_SequenceKeyType); /* gs_key.gsk_type */ + len += sizeof(GTM_Sequence); /* gs_value */ + len += sizeof(GTM_Sequence); /* gs_init_value */ + len += sizeof(GTM_Sequence); /* gs_last_value */ + len += sizeof(GTM_Sequence); /* gs_increment_by */ + len += sizeof(GTM_Sequence); /* gs_min_value */ + len += sizeof(GTM_Sequence); /* gs_max_value */ + len += sizeof(bool); /* gs_cycle */ + len += sizeof(bool); /* gs_called */ + + return len; +} + +size_t +gtm_serialize_sequence(GTM_SeqInfo *s, char *buf, size_t buflen) +{ + size_t len = 0; + + /* size check */ + if ( gtm_get_sequence_size(s) > buflen ) + return 0; + + memset(buf, 0, buflen); + + memcpy(buf+len, &s->gs_key->gsk_keylen, sizeof(uint32)); + len += sizeof(uint32); /* gs_key.gsk_keylen */ + + memcpy(buf+len, s->gs_key->gsk_key, s->gs_key->gsk_keylen); + len += s->gs_key->gsk_keylen; /* gs_key.gsk_key */ + + memcpy(buf+len, &s->gs_key->gsk_type, sizeof(GTM_SequenceKeyType)); + len += sizeof(GTM_SequenceKeyType); /* gs_key.gsk_type */ + + memcpy(buf+len, &s->gs_value, sizeof(GTM_Sequence)); + len += sizeof(GTM_Sequence); /* gs_value */ + + memcpy(buf+len, &s->gs_init_value, sizeof(GTM_Sequence)); + len += sizeof(GTM_Sequence); /* gs_init_value */ + + memcpy(buf+len, &s->gs_last_value, sizeof(GTM_Sequence)); + len += sizeof(GTM_Sequence); /* gs_last_value */ + + memcpy(buf+len, &s->gs_increment_by, sizeof(GTM_Sequence)); + len += sizeof(GTM_Sequence); /* gs_increment_by */ + + memcpy(buf+len, &s->gs_min_value, sizeof(GTM_Sequence)); + len += sizeof(GTM_Sequence); /* gs_min_value */ + + memcpy(buf+len, &s->gs_max_value, sizeof(GTM_Sequence)); + len += sizeof(GTM_Sequence); /* gs_max_value */ + + memcpy(buf+len, &s->gs_cycle, sizeof(bool)); + len += sizeof(bool); /* gs_cycle */ + + memcpy(buf+len, &s->gs_called, sizeof(bool)); + len += sizeof(bool); /* gs_called */ + + return len; +} + +GTM_SeqInfo * +gtm_deserialize_sequence(const char *buf, size_t buflen) +{ + size_t len = 0; + GTM_SeqInfo *seq; + + seq = (GTM_SeqInfo *)malloc( sizeof(GTM_SeqInfo) ); + seq->gs_key = (GTM_SequenceKeyData *)malloc( sizeof(GTM_SequenceKeyData) ); + + memcpy(&seq->gs_key->gsk_keylen, buf+len, sizeof(uint32)); + len += sizeof(uint32); /* gs_key.gsk_keylen */ + + seq->gs_key->gsk_key = (char *)malloc(seq->gs_key->gsk_keylen+1); + memset(seq->gs_key->gsk_key, 0, seq->gs_key->gsk_keylen+1); + memcpy(seq->gs_key->gsk_key, buf+len, seq->gs_key->gsk_keylen); + len += seq->gs_key->gsk_keylen; /* gs_key.gsk_key */ + + memcpy(&seq->gs_key->gsk_type, buf+len, sizeof(GTM_SequenceKeyType)); + len += sizeof(GTM_SequenceKeyType); /* gs_key.gsk_type */ + + memcpy(&seq->gs_value, buf+len, sizeof(GTM_Sequence)); + len += sizeof(GTM_Sequence); /* gs_value */ + + memcpy(&seq->gs_init_value, buf+len, sizeof(GTM_Sequence)); + len += sizeof(GTM_Sequence); /* gs_init_value */ + + memcpy(&seq->gs_last_value, buf+len, sizeof(GTM_Sequence)); + len += sizeof(GTM_Sequence); /* gs_last_value */ + + memcpy(&seq->gs_increment_by, buf+len, sizeof(GTM_Sequence)); + len += sizeof(GTM_Sequence); /* gs_increment_by */ + + memcpy(&seq->gs_min_value, buf+len, sizeof(GTM_Sequence)); + len += sizeof(GTM_Sequence); /* gs_min_value */ + + memcpy(&seq->gs_max_value, buf+len, sizeof(GTM_Sequence)); + len += sizeof(GTM_Sequence); /* gs_max_value */ + + memcpy(&seq->gs_cycle, buf+len, sizeof(bool)); + len += sizeof(bool); /* gs_cycle */ + + memcpy(&seq->gs_called, buf+len, sizeof(bool)); + len += sizeof(bool); /* gs_called */ + + return seq; +} diff --git a/src/gtm/common/gtm_serialize_debug.c b/src/gtm/common/gtm_serialize_debug.c new file mode 100644 index 0000000..d9d689e --- /dev/null +++ b/src/gtm/common/gtm_serialize_debug.c @@ -0,0 +1,76 @@ + +#include "gtm/gtm_c.h" +#include "gtm/elog.h" +#include "gtm/palloc.h" +#include "gtm/gtm.h" +#include "gtm/gtm_txn.h" +#include "gtm/gtm_seq.h" +#include "gtm/assert.h" +#include "gtm/register.h" +#include "gtm/stringinfo.h" +#include "gtm/libpq.h" +#include "gtm/pqformat.h" +#include "gtm/gtm_msg.h" + +#include "gtm/gtm_serialize.h" + +void +dump_transactioninfo_elog(GTM_TransactionInfo *txn) +{ + elog(LOG, " ========= GTM_TransactionInfo ========="); + elog(LOG, " gti_handle: %d", txn->gti_handle); + elog(LOG, " gti_thread_id: %ld", txn->gti_thread_id); + elog(LOG, " gti_in_use: %d", txn->gti_in_use); + elog(LOG, " gti_gxid: %d", txn->gti_gxid); + elog(LOG, " gti_state: %d", txn->gti_state); + elog(LOG, " gti_coordid: %d", txn->gti_coordid); + elog(LOG, " gti_xmin: %d", txn->gti_xmin); + elog(LOG, " gti_isolevel: %d", txn->gti_isolevel); + elog(LOG, " gti_readonly: %d", txn->gti_readonly); + elog(LOG, " gti_backend_id: %d", txn->gti_backend_id); + elog(LOG, " gti_datanodecount: %d", txn->gti_datanodecount); + // PGXC_NodeId *gti_datanodes; + elog(LOG, " gti_coordcount: %d", txn->gti_coordcount); + // PGXC_NodeId *gti_coordinators; + elog(LOG, " gti_gid: %s", txn->gti_gid); + + elog(LOG, " sn_xmin: %d", txn->gti_current_snapshot.sn_xmin); + elog(LOG, " sn_xmax: %d", txn->gti_current_snapshot.sn_xmax); + elog(LOG, " sn_recent_global_xmin: %d", txn->gti_current_snapshot.sn_recent_global_xmin); + elog(LOG, " sn_xcnt: %d", txn->gti_current_snapshot.sn_xcnt); + elog(LOG, " sn_xip: %d", *(txn->gti_current_snapshot.sn_xip)); + + elog(LOG, " gti_snapshot_set: %d", txn->gti_snapshot_set); + elog(LOG, " gti_vacuum: %d", txn->gti_vacuum); + elog(LOG, " ========================================"); +} + +void +dump_transactions_elog(GTM_Transactions *txn, int num_txn) +{ + int i; + + elog(LOG, "============ GTM_Transactions ============"); + elog(LOG, " gt_txn_count: %d", txn->gt_txn_count); + elog(LOG, " gt_XidGenLock: %p", &txn->gt_XidGenLock); + elog(LOG, " gt_nextXid: %d", txn->gt_nextXid); + elog(LOG, " gt_oldestXid: %d", txn->gt_oldestXid); + elog(LOG, " gt_xidVacLimit: %d", txn->gt_xidVacLimit); + elog(LOG, " gt_xidWarnLimit: %d", txn->gt_xidWarnLimit); + elog(LOG, " gt_xidStopLimit: %d", txn->gt_xidStopLimit); + elog(LOG, " gt_xidWrapLimit: %d", txn->gt_xidWrapLimit); + elog(LOG, " gt_latestCompletedXid: %d", txn->gt_latestCompletedXid); + elog(LOG, " gt_recent_global_xmin: %d", txn->gt_recent_global_xmin); + elog(LOG, " gt_lastslot: %d", txn->gt_lastslot); + + for (i=0 ; i<num_txn ; i++) + { + if ( txn->gt_transactions_array[i].gti_gxid != InvalidGlobalTransactionId ) + dump_transactioninfo_elog(&txn->gt_transactions_array[i]); + } + // gtm_List *gt_open_transactions; + elog(LOG, " gt_TransArrayLock: %p", &txn->gt_TransArrayLock); + elog(LOG, "=========================================="); +} + + diff --git a/src/gtm/common/gtm_utils.c b/src/gtm/common/gtm_utils.c new file mode 100644 index 0000000..a25ae6a --- /dev/null +++ b/src/gtm/common/gtm_utils.c @@ -0,0 +1,19 @@ +#include "gtm/gtm_utils.h" + +#include "gtm/elog.h" +#include "gtm/gtm.h" + +/* + * gtm_report_failure() is an utility function to report fatal failure + * which occureed inside GTM to XCM, especially communication errors. + * + * `failed_conn' is null-able when failed to establish a connection + * with other node. + */ +void +gtm_report_failure(GTM_Conn *failed_conn) +{ + /* FIXME: report_xcwatch_gtm_failure() */ + elog(LOG, "Calling report_xcwatch_gtm_failure()..."); + return; +} diff --git a/src/gtm/main/gtm_standby.c b/src/gtm/main/gtm_standby.c new file mode 100644 index 0000000..bca82f7 --- /dev/null +++ b/src/gtm/main/gtm_standby.c @@ -0,0 +1,489 @@ +#include "gtm/gtm_standby.h" + +#include "gtm/elog.h" +#include "gtm/gtm.h" +#include "gtm/gtm_c.h" +#include "gtm/gtm_client.h" +#include "gtm/gtm_seq.h" +#include "gtm/gtm_serialize.h" +#include "gtm/gtm_utils.h" +#include "gtm/register.h" + +/* + * Variables to interact with GTM active under GTM standby mode. + * + * FIXME: need to protect these values with mutex lock for thread safe. + */ +static bool GTM_StandbyMode = false; +static char *GTM_ActiveAddress; +static int GTM_ActivePort; +static GTM_Conn *GTM_ActiveConn = NULL; + +static char standbyNodeName[NI_MAXHOST]; +static GTM_PGXCNodeId standbyNodeNum; +static int standbyPortNumber; +static char *standbyDataDir; + +static GTM_Conn *gtm_standby_connect_to_standby_int(int *); + +bool +gtm_is_standby() +{ + return GTM_StandbyMode; +} + +void +gtm_set_standby(bool standby) +{ + GTM_StandbyMode = standby; +} + +void +gtm_set_active_conninfo(const char *addr, int port) +{ + GTM_ActiveAddress = strdup(addr); + GTM_ActivePort = port; +} + +int +gtm_standby_start_startup() +{ + char connect_string[1024]; + + elog(LOG, "Connecting the GTM active on %s:%d...", GTM_ActiveAddress, GTM_ActivePort); + + sprintf(connect_string, "host=%s port=%d pgxc_node_id=1 remote_type=%d", + GTM_ActiveAddress, GTM_ActivePort, PGXC_NODE_GTM); + + GTM_ActiveConn = PQconnectGTM(connect_string); + if (GTM_ActiveConn == NULL) + { + elog(DEBUG3, "Error in connection"); + return 0; + } + elog(LOG, "Connection established to the GTM active."); + + return 1; +} + +int +gtm_standby_finish_startup() +{ + elog(LOG, "Closing a startup connection..."); + + GTMPQfinish(GTM_ActiveConn); + + elog(LOG, "A startup connection closed."); + + return 1; +} + +int +gtm_standby_restore_next_gxid() +{ + GlobalTransactionId next_gxid = InvalidGlobalTransactionId; + + next_gxid = get_next_gxid(GTM_ActiveConn); + GTM_RestoreTxnInfo(-1, next_gxid); + + elog(LOG, "Restoring the next GXID done."); + + return 1; +} + +int +gtm_standby_restore_sequence() +{ + GTM_SeqInfo *seq_list[1024]; + int num_seq; + int i; + + /* + * Restore sequence data. + */ + num_seq = get_sequence_list(GTM_ActiveConn, seq_list, 1024); + + for (i=0 ; i<num_seq ; i++) + { + GTM_SeqRestore(seq_list[i]->gs_key, + seq_list[i]->gs_increment_by, + seq_list[i]->gs_min_value, + seq_list[i]->gs_max_value, + seq_list[i]->gs_init_value, + seq_list[i]->gs_value, + seq_list[i]->gs_state, + seq_list[i]->gs_cycle, + seq_list[i]->gs_called); + } + + elog(LOG, "Restoring sequences done."); + + return 1; +} + +int +gtm_standby_restore_gxid() +{ + int num_txn; + GTM_Transactions txn; + int i; + + /* + * Restore gxid data. + */ + num_txn = get_txn_gxid_list(GTM_ActiveConn, &txn); + + GTM_RWLockAcquire(>MTransactions.gt_XidGenLock, GTM_LOCKMODE_WRITE); + + GTMTransactions.gt_txn_count = txn.gt_txn_count; + GTMTransactions.gt_gtm_state = txn.gt_gtm_state; + GTMTransactions.gt_nextXid = txn.gt_nextXid; + GTMTransactions.gt_oldestXid = txn.gt_oldestXid; + GTMTransactions.gt_xidVacLimit = txn.gt_xidVacLimit; + GTMTransactions.gt_xidWarnLimit = txn.gt_xidWarnLimit; + GTMTransactions.gt_xidStopLimit = txn.gt_xidStopLimit; + GTMTransactions.gt_xidWrapLimit = txn.gt_xidWrapLimit; + GTMTransactions.gt_latestCompletedXid = txn.gt_latestCompletedXid; + GTMTransactions.gt_recent_global_xmin = txn.gt_recent_global_xmin; + GTMTransactions.gt_lastslot = txn.gt_lastslot; + + for (i=0 ; i<num_txn ; i++) + { + GTMTransactions.gt_transactions_array[i].gti_handle = txn.gt_transactions_array[i].gti_handle; + GTMTransactions.gt_transactions_array[i].gti_thread_id = txn.gt_transactions_array[i].gti_thread_id; + GTMTransactions.gt_transactions_array[i].gti_in_use = txn.gt_transactions_array[i].gti_in_use; + GTMTransactions.gt_transactions_array[i].gti_gxid = txn.gt_transactions_array[i].gti_gxid; + GTMTransactions.gt_transactions_array[i].gti_state = txn.gt_transactions_array[i].gti_state; + GTMTransactions.gt_transactions_array[i].gti_coordid = txn.gt_transactions_array[i].gti_coordid; + GTMTransactions.gt_transactions_array[i].gti_xmin = txn.gt_transactions_array[i].gti_xmin; + GTMTransactions.gt_transactions_array[i].gti_isolevel = txn.gt_transactions_array[i].gti_isolevel; + GTMTransactions.gt_transactions_array[i].gti_readonly = txn.gt_transactions_array[i].gti_readonly; + GTMTransactions.gt_transactions_array[i].gti_backend_id = txn.gt_transactions_array[i].gti_backend_id; + + /* data node */ + GTMTransactions.gt_transactions_array[i].gti_datanodecount + = txn.gt_transactions_array[i].gti_datanodecount; + GTMTransactions.gt_transactions_array[i].gti_datanodes + = palloc(sizeof (PGXC_NodeId) * GTMTransactions.gt_transactions_array[i].gti_datanodecount); + memcpy(GTMTransactions.gt_transactions_array[i].gti_datanodes, + txn.gt_transactions_array[i].gti_datanodes, + sizeof (PGXC_NodeId) * GTMTransactions.gt_transactions_array[i].gti_datanodecount); + + /* coordinator node */ + GTMTransactions.gt_transactions_array[i].gti_coordcount + = txn.gt_transactions_array[i].gti_coordcount; + GTMTransactions.gt_transactions_array[i].gti_coordinators + = palloc(sizeof (PGXC_NodeId) * GTMTransactions.gt_transactions_array[i].gti_coordcount); + memcpy(GTMTransactions.gt_transactions_array[i].gti_coordinators, + txn.gt_transactions_array[i].gti_coordinators, + sizeof (PGXC_NodeId) * GTMTransactions.gt_transactions_array[i].gti_coordcount); + + if (txn.gt_transactions_array[i].gti_gid==NULL ) + GTMTransactions.gt_transactions_array[i].gti_gid = NULL; + else + GTMTransactions.gt_transactions_array[i].gti_gid = strdup(txn.gt_transactions_array[i].gti_gid); + + /* copy GTM_SnapshotData */ + GTMTransactions.gt_transactions_array[i].gti_current_snapshot.sn_xmin + = txn.gt_transactions_array[i].gti_current_snapshot.sn_xmin; + GTMTransactions.gt_transactions_array[i].gti_current_snapshot.sn_xmax + = txn.gt_transactions_array[i].gti_current_snapshot.sn_xmax; + GTMTransactions.gt_transactions_array[i].gti_current_snapshot.sn_recent_global_xmin + = txn.gt_transactions_array[i].gti_current_snapshot.sn_recent_global_xmin; + GTMTransactions.gt_transactions_array[i].gti_current_snapshot.sn_xcnt + = txn.gt_transactions_array[i].gti_current_snapshot.sn_xcnt; + GTMTransactions.gt_transactions_array[i].gti_current_snapshot.sn_xip + = txn.gt_transactions_array[i].gti_current_snapshot.sn_xip; + /* end of copying GTM_SnapshotData */ + + GTMTransactions.gt_transactions_array[i].gti_snapshot_set + = txn.gt_transactions_array[i].gti_snapshot_set; + GTMTransactions.gt_transactions_array[i].gti_vacuum + = txn.gt_transactions_array[i].gti_vacuum; + + if ( GTMTransactions.gt_transactions_array[i].gti_state != GTM_TXN_ABORTED ) + { + GTMTransactions.gt_open_transactions = gtm_lappend(GTMTransactions.gt_open_transactions, + >MTransactions.gt_transactions_array[i]); + } + } + + dump_transactions_elog(>MTransactions, num_txn); + + GTM_RWLockRelease(>MTransactions.gt_XidGenLock); + + elog(LOG, "Restoring %d gxid(s) done.", num_txn); + + return 1; +} + +int +gtm_standby_restore_node() +{ + GTM_PGXCNodeInfo *data; + int rc, i; + int num_node; + + elog(LOG, "Copying node information from the GTM active..."); + + data = (GTM_PGXCNodeInfo *)malloc( sizeof(GTM_PGXCNodeInfo)*128 ); + memset(data, 0, sizeof(GTM_PGXCNodeInfo)*128); + + rc = get_node_list(GTM_ActiveConn, data, 128); + if ( rc<0 ) + { + elog(DEBUG3, "get_node_list() failed."); + rc = 0; + goto finished; + } + + num_node = rc; + + for (i=0 ; i<num_node ; i++) + { + elog(LOG, "get_node_list: nodetype=%d, nodenum=%d, datafolder=%s", + data[i].type, data[i].nodenum, data[i].datafolder); + + if ( Recovery_PGXCNodeRegister(data[i].type, data[i].nodenum, data[i].port, + data[i].proxynum, data[i].status, + data[i].ipaddress, data[i].datafolder, true, + -1 /* dummy socket */) != 0 ) + { + rc = 0; + goto finished; + } + } + + elog(LOG, "Copying node information from GTM active done."); + + finished: + free(data); + return rc; +} + +/* + * Regiter myself to the GTM (active) as a "disconnected" node. + * + * This status would be updated later after restoring completion. + * See gtm_standby_update_self(). + * + * Returns 1 on success, 0 on failure. + */ +int +gtm_standby_register_self(GTM_PGXCNodeId nodenum, int port, const char *datadir) +{ + int rc; + + elog(LOG, "Registering standby-GTM status..."); + + node_get_local_addr(GTM_ActiveConn, standbyNodeName, sizeof(standbyNodeName), &rc); + if ( rc!=0 ) + return 0; + + standbyNodeNum = nodenum; + standbyPortNumber = port; + standbyDataDir = (char *)datadir; + + rc = node_register2(GTM_ActiveConn, PGXC_NODE_GTM, standbyNodeName, standbyPortNumber, + standbyNodeNum, standbyDataDir, NODE_DISCONNECTED); + if ( rc<0 ) + { + elog(LOG, "Failed to register a standby-GTM status."); + return 0; + } + + elog(LOG, "Registering standby-GTM done."); + + return 1; +} + +/* + * Update my node status from "disconnected" to "connected" in GTM by myself. + * + * Returns 1 on success, 0 on failure. + */ +int +gtm_standby_activate_self() +{ + int rc; + + elog(LOG, "Updating the standby-GTM status to \"CONNECTED\"..."); + + rc = node_unregister(GTM_ActiveConn, PGXC_NODE_GTM, standbyNodeNum); + if ( rc<0 ) + { + elog(LOG, "Failed to unregister old standby-GTM status."); + return 0; + } + + rc = node_register2(GTM_ActiveConn, PGXC_NODE_GTM, standbyNodeName, standbyPortNumber, + standbyNodeNum, standbyDataDir, NODE_CONNECTED); + if ( rc<0 ) + { + elog(LOG, "Failed to register a new standby-GTM status."); + return 0; + } + + elog(LOG, "Updating the standby-GTM status done."); + + return 1; +} + + +/* + * Find "one" GTM standby node info. + * + * Returns a pointer to GTM_PGXCNodeInfo on success, + * or returns NULL on failure. + */ +static GTM_PGXCNodeInfo * +find_standby_node_info() +{ + GTM_PGXCNodeInfo *node[1024]; + size_t n; + int i; + + n = pgxcnode_find_by_type(PGXC_NODE_GTM, node, 1024); + + for (i=0 ; i<n ; i++) + { + elog(LOG, "pgxcnode_find_by_type: nodenum=%d, type=%d, ipaddress=%s, port=%d, status=%d", + node[i]->nodenum, + node[i]->type, + node[i]->ipaddress, + node[i]->port, + node[i]->status); + + if ( node[i]->nodenum!=standbyNodeNum && node[i]->status==NODE_CONNECTED ) + return node[i]; + } + + return NULL; +} + + +/* + * Make a connection to the GTM standby node when getting connected + * from the client. + * + * Returns a pointer to a GTM_Conn object on success, or NULL on failure. + */ +GTM_Conn * +gtm_standby_connect_to_standby() +{ + GTM_Conn *conn; + int report; + + conn = gtm_standby_connect_to_standby_int(&report); + if ( !conn && report ) + gtm_report_failure(NULL); + + return conn; +} + +static GTM_Conn * +gtm_standby_connect_to_standby_int(int *report_needed) +{ + GTM_Conn *standby = NULL; + GTM_PGXCNodeInfo *n; + char conn_string[1024]; + + *report_needed = 0; + + if ( GTM_StandbyMode ) + return NULL; + + n = find_standby_node_info(); + + if ( !n ) + { + elog(LOG, "Any GTM standby node not found in registered node(s)."); + return NULL; + } + + elog(LOG, "GTM standby is active. Going to connect."); + *report_needed = 1; + + snprintf(conn_string, sizeof(conn_string), + "host=%s port=%d pgxc_node_id=1 remote_type=4", + n->ipaddress, n->port); + + standby = PQconnectGTM(conn_string); + + if ( !standby ) + { + elog(LOG, "Failed to establish a connection with GTM standby. - %p", n); + return NULL; + } + + elog(LOG, "Connection established with GTM standby. - %p", n); + + return standby; +} + +void +gtm_standby_disconnect_from_standby(GTM_Conn *conn) +{ + if ( GTM_StandbyMode ) + return; + + GTMPQfinish(conn); +} + + +GTM_Conn * +gtm_standby_reconnect_to_standby(GTM_Conn *old_conn, int retry_max) +{ + GTM_Conn *newconn; + int report; + int i; + + if ( GTM_StandbyMode ) + return NULL; + + if ( old_conn!=NULL ) + gtm_standby_disconnect_from_standby(old_conn); + + for (i=0 ; i<retry_max ; i++) + { + elog(LOG, "gtm_standby_reconnect_to_standby(): going to re-connect. retry=%d", i); + + newconn = gtm_standby_connect_to_standby_int(&report); + if ( newconn!=NULL ) + break; + + elog(LOG, "gtm_standby_reconnect_to_standby(): re-connect failed. retry=%d", i); + } + + if ( newconn ) + gtm_report_failure(NULL); + + return newconn; +} + + +#define GTM_STANDBY_RETRY_MAX 3 + +bool +gtm_standby_check_communication_error(int *retry_count, GTM_Conn *oldconn) +{ + if ( GetMyThreadInfo->thr_conn->standby->result->gr_status == GTM_RESULT_COMM_ERROR ) + { + if ( *retry_count==0 ) + { + (*retry_count)++; + + GetMyThreadInfo->thr_conn->standby + = gtm_standby_reconnect_to_standby(GetMyThreadInfo->thr_conn->standby, + GTM_STANDBY_RETRY_MAX); + + if ( GetMyThreadInfo->thr_conn->standby ) + return true; + } + + elog(LOG, "communication error with standby."); + gtm_report_failure(oldconn); + } + return false; +} + diff --git a/src/gtm/main/main2.c b/src/gtm/main/main2.c new file mode 100644 index 0000000..b8d7287 --- /dev/null +++ b/src/gtm/main/main2.c @@ -0,0 +1,58 @@ + if ( GTM_StandbyMode ) + { + /* initialize standby */ + char connstr[1024]; + + /* FIXME: node id must be suppied. */ + int node_id = 1; + + snprintf(connstr, sizeof(connstr), "host=%s port=%d pgxc_node_id=%d remote_type=%d", + GTM_ActiveAddress, GTM_ActivePort, node_id, PGXC_NODE_GTM_PROXY_POSTMASTER); + + GTM_ActiveConn = PQconnectGTM(connstr); + + if ( GTMPQstatus(GTM_ActiveConn)!=CONNECTION_OK ) + { + /* failed to connect GTM-active. */ + elog(ERROR, "Failed to connect to GTM-active."); + exit(1); + } + + elog(LOG, "Connected to GTM active running on %s:%d.", GTM_ActiveAddress, GTM_ActivePort); + +#ifdef NOT_USED + elog(LOG, "Starting GTM standby on %s:%d /w control file %s.", ListenAddresses, GTMPortNumber, GTMControlFile); + + /* FIXME: how can I generate GTM_PGXCNodeId? */ + GTM_PGXCNodeId nodenum = 1; + + node_register(GTM_ActiveConn, PGXC_NODE_GTM, GTM_ActivePort, nodenum, GTMDataDir); + + begin_replication_initial_sync(GTM_ActiveConn); + end_replication_initial_sync(GTM_ActiveConn); + + node_unregister(GTM_ActiveConn, PGXC_NODE_GTM, nodenum); +#endif /* NOT_USED */ + + GTMPQfinish(GTM_ActiveConn); + + GTM_ActiveConn = NULL; + + exit(0); + } + else + { + /* + * Read the last GXID and start from there + */ + ctlfd = open(GTMControlFile, O_RDONLY); + + GTM_RestoreTxnInfo(ctlfd, next_gxid); + GTM_RestoreSeqInfo(ctlfd); + + close(ctlfd); + + /* Recover Data of Registered nodes. */ + Recovery_RestoreRegisterInfo(); + } + diff --git a/src/gtm/proxy/proxy_utils.c b/src/gtm/proxy/proxy_utils.c new file mode 100644 index 0000000..077afbe --- /dev/null +++ b/src/gtm/proxy/proxy_utils.c @@ -0,0 +1,36 @@ +#include "gtm/proxy_utils.h" + +#include "gtm/elog.h" +#include "gtm/gtm.h" +#include "gtm/gtm_c.h" +#include "gtm/gtm_client.h" +#include "gtm/gtm_seq.h" +#include "gtm/register.h" + +/* + * This function is a dummy function of gtm_proxy mobule to avoid + * object link problem. + * + * Most of command processing functions are existing only in GTM main + * module, but a few are both in GTM main and GTM proxy modules, which + * consist of same binary objects. And all the command processing + * functions require calling gtm_standby_check_communication_error() + * for GTM main. + * + * Two options should be considered here: (1) Moving all command + * processing functions into the common modules, or (2) Creating a + * dummy function in GTM proxy module. + * + * (1) may cause another hard thing because of object and variable + * referencing issue. + * + * This is the reason why this dummy function needed. So this is here. + * + * The object and module structure of GTM/GTM Proxy needs review, and + * fix to remove this kind of tricks. + */ +bool +gtm_standby_check_communication_error(int *retry_count, GTM_Conn *oldconn) +{ + return false; +} diff --git a/src/gtm/recovery/replication.c b/src/gtm/recovery/replication.c new file mode 100644 index 0000000..46d29a5 --- /dev/null +++ b/src/gtm/recovery/replication.c @@ -0,0 +1,123 @@ +/*------------------------------------------------------------------------- + * + * register.c + * PGXC Node Register on GTM and GTM Proxy, node registering functions + * + * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * Portions Copyright (c) 2010-2011 Nippon Telegraph and Telephone Corporation + * + * + * IDENTIFICATION + * $PostgreSQL$ + * + *------------------------------------------------------------------------- + */ +#include "gtm/replication.h" + +#include <fcntl.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "gtm/gtm_c.h" +#include "gtm/gtm.h" +#include "gtm/gtm_txn.h" +#include "gtm/gtm_standby.h" +#include "gtm/register.h" +#include "gtm/assert.h" +#include <stdio.h> +#include "gtm/libpq.h" +#include "gtm/pqformat.h" +#include "gtm/gtm_msg.h" +#include "gtm/gtm_ip.h" + +/* + * Process MSG_NODE_BEGIN_REPlCATION_INIT + */ +void +ProcessBeginReplicationInitialSyncRequest(Port *myport, StringInfo message) +{ + StringInfoData buf; + MemoryContext oldContext; + + pq_getmsgend(message); + + if ( gtm_is_standby() ) + ereport(ERROR, + (EPERM, + errmsg("Operation not permitted under the standby mode."))); + + oldContext = MemoryContextSwitchTo(TopMemoryContext); + + /* + * Acquire global locks to copy resource data to the standby. + */ + GTM_RWLockAcquire(>MTransactions.gt_XidGenLock, GTM_LOCKMODE_WRITE); + GTM_RWLockAcquire(>MTransactions.gt_TransArrayLock, GTM_LOCKMODE_WRITE); + elog(LOG, "Prepared for copying data with holding XidGenLock and TransArrayLock."); + + MemoryContextSwitchTo(oldContext); + + pq_beginmessage(&buf, 'S'); + pq_sendint(&buf, NODE_BEGIN_REPLICATION_INIT_RESULT, 4); + if (myport->remote_type == PGXC_NODE_GTM_PROXY) + { + GTM_ProxyMsgHeader proxyhdr; + proxyhdr.ph_conid = myport->conn_id; + pq_sendbytes(&buf, (char *)&proxyhdr, sizeof (GTM_ProxyMsgHeader)); + } + pq_endmessage(myport, &buf); + + if (myport->remote_type != PGXC_NODE_GTM_PROXY) + pq_flush(myport); + + elog(LOG, "ProcessBeginReplicationInitialSyncRequest() ok."); + + return; +} + +/* + * Process MSG_NODE_END_REPlCATION_INIT + */ +void +ProcessEndReplicationInitialSyncRequest(Port *myport, StringInfo message) +{ + StringInfoData buf; + MemoryContext oldContext; + + pq_getmsgend(message); + + if ( gtm_is_standby() ) + ereport(ERROR, + (EPERM, + errmsg("Operation not permitted under the standby mode."))); + + oldContext = MemoryContextSwitchTo(TopMemoryContext); + + /* + * Release global locks after copying resource data to the standby. + */ + GTM_RWLockRelease(>MTransactions.gt_TransArrayLock); + GTM_RWLockRelease(>MTransactions.gt_XidGenLock); + elog(LOG, "XidGenLock and TransArrayLock released."); + + MemoryContextSwitchTo(oldContext); + + pq_beginmessage(&buf, 'S'); + pq_sendint(&buf, NODE_END_REPLICATION_INIT_RESULT, 4); + if (myport->remote_type == PGXC_NODE_GTM_PROXY) + { + GTM_ProxyMsgHeader proxyhdr; + proxyhdr.ph_conid = myport->conn_id; + pq_sendbytes(&buf, (char *)&proxyhdr, sizeof (GTM_ProxyMsgHeader)); + } + pq_endmessage(myport, &buf); + + if (myport->remote_type != PGXC_NODE_GTM_PROXY) + pq_flush(myport); + + elog(LOG, "ProcessEndReplicationInitialSyncRequest() ok."); + + return; +} + diff --git a/src/gtm/test/Makefile b/src/gtm/test/Makefile new file mode 100644 index 0000000..e6155ea --- /dev/null +++ b/src/gtm/test/Makefile @@ -0,0 +1,53 @@ +# Copyright (c) 2010-2011 Nippon Telegraph and Telephone Corporation + +top_build_dir=../.. +include $(top_build_dir)/gtm/Makefile.global + +override CPPFLAGS := -I$(top_build_dir)/gtm/client $(CPPFLAGS) + +SRCS=test_serialize.c test_connect.c test_node.c test_node5.c test_txn.c test_txn4.c test_txn5.c test_repli.c test_repli2.c test_seq.c test_seq4.c test_seq5.c test_scenario.c test_startup.c test_standby.c test_common.c + +PROGS=test_serialize test_connect test_txn test_txn4 test_txn5 test_repli test_repli2 test_seq test_seq4 test_seq5 test_scenario test_startup test_node test_node5 test_standby + +OBJS=$(SRCS:.c=.o) +LIBS=$(top_build_dir)/gtm/client/libgtmclient.a \ + $(top_build_dir)/gtm/common/libgtm.a \ + $(top_build_dir)/gtm/libpq/libpqcomm.a + +LOADLIBES=-lpthread +CFLAGS=-g -O0 + +all: $(PROGS) + +test_serialize: test_serialize.o test_common.o $(LIBS) + +test_connect: test_connect.o test_common.o $(LIBS) +test_startup: test_startup.o test_common.o $(LIBS) + +test_node: test_node.o test_common.o $(LIBS) +test_node5: test_node5.o test_common.o $(LIBS) + +test_txn: test_txn.o test_common.o $(LIBS) + +test_txn4: test_txn4.o test_common.o $(LIBS) +test_txn5: test_txn5.o test_common.o $(LIBS) + +test_repli: test_repli.o test_common.o $(LIBS) + +test_standby: test_standby.o test_common.o $(LIBS) + +test_repli2: test_repli2.o test_common.o $(LIBS) + +test_seq: test_seq.o test_common.o $(LIBS) +test_seq4: test_seq4.o test_common.o $(LIBS) +test_seq5: test_seq5.o test_common.o $(LIBS) + +test_scenario: test_scenario.o test_common.o $(LIBS) + +clean: + rm -f $(OBJS) *~ + rm -f $(PROGS) + +distclean: clean + +maintainer-clean: distclean diff --git a/src/gtm/test/clean.sh b/src/gtm/test/clean.sh new file mode 100755 index 0000000..87c452b --- /dev/null +++ b/src/gtm/test/clean.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +# GTM start script for test + +pushd /tmp/pgxc/bin; ln -fs gtm gtm_standby; popd + +export PATH=/tmp/pgxc/bin:$PATH + +# ------------------------------- +# starting standby... +# ------------------------------- +echo "cleaning standby..." +export DATA=/tmp/pgxc/data/gtm_standby + +pushd $DATA +rm -rf gtm.control gtm.opts gtm.pid register.node +cat /dev/null > gtm.log +popd + +# ------------------------------- +# starting active... +# ------------------------------- +echo "cleaning active..." +export DATA=/tmp/pgxc/data/gtm + +pushd $DATA +rm -rf gtm.control gtm.opts gtm.pid register.node +cat /dev/null > gtm.log +popd diff --git a/src/gtm/test/promote.sh b/src/gtm/test/promote.sh new file mode 100755 index 0000000..ae60e9c --- /dev/null +++ b/src/gtm/test/promote.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +# GTM start script for test + +pushd /tmp/pgxc/bin; ln -fs gtm gtm_standby; popd + +export PATH=/tmp/pgxc/bin:$PATH + +# ------------------------------- +# promoting standby... +# ------------------------------- +echo "promoting standby..." +export DATA=/tmp/pgxc/data/gtm_standby + +gtm_ctl -D ${DATA} -S gtm_standby promote + +# ------------------------------- +# process check +# ------------------------------- +echo "checking process..." +ps -aef |grep gtm diff --git a/src/gtm/test/regress.sh b/src/gtm/test/regress.sh new file mode 100755 index 0000000..314d17c --- /dev/null +++ b/src/gtm/test/regress.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +cat /dev/null>regress.log + +./test_serialize | tee -a regress.log 2>&1 + +./stop.sh +./start_a.sh +./test_connect 2>&1 | tee -a regress.log +./test_node 2>&1 | tee -a regress.log +./test_txn 2>&1 | tee -a regress.log +./test_seq 2>&1 | tee -a regress.log + +echo "" +echo "=========== SUMMARY ============" +date +echo -n "Assert: " +grep -c ASSERT regress.log diff --git a/src/gtm/test/start.sh b/src/gtm/test/start.sh new file mode 100755 index 0000000..24951ff --- /dev/null +++ b/src/gtm/test/start.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +# GTM start script for test + +pushd /tmp/pgxc/bin; ln -fs gtm gtm_standby; popd + +./start_a.sh + +echo "sleeping 3 seconds..." +sleep 3; + +./start_s.sh diff --git a/src/gtm/test/start_a.sh b/src/gtm/test/start_a.sh new file mode 100755 index 0000000..4a6c1c1 --- /dev/null +++ b/src/gtm/test/start_a.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +# GTM start script for test + +pushd /tmp/pgxc/bin; ln -fs gtm gtm_standby; popd + +export PATH=/tmp/pgxc/bin:$PATH +export DATA=/tmp/pgxc/data/gtm + +# ------------------------------- +# starting active... +# ------------------------------- +echo "starting active..." + +gtm_ctl -D ${DATA} -S gtm stop +rm -rf ${DATA}/gtm.opts ${DATA}/gtm.pid ${DATA}/register.node + +gtm_ctl -D ${DATA} -S gtm -o "-n 101" start + +# ------------------------------- +# process check +# ------------------------------- +echo "checking process..." +ps -aef |grep gtm diff --git a/src/gtm/test/start_s.sh b/src/gtm/test/start_s.sh new file mode 100755 index 0000000..b016bce --- /dev/null +++ b/src/gtm/test/start_s.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +# GTM start script for test + +pushd /tmp/pgxc/bin; ln -fs gtm gtm_standby; popd + +export PATH=/tmp/pgxc/bin:$PATH + +# ------------------------------- +# starting standby... +# ------------------------------- +echo "starting standby..." + +export DATA=/tmp/pgxc/data/gtm_standby + +gtm_ctl -D ${DATA} -S gtm stop +rm -rf ${DATA}/gtm.opts ${DATA}/gtm.pid ${DATA}/register.node + +gtm_ctl -D ${DATA} -S gtm_standby -o "-n 102 -s -p 6667 -i 127.0.0.1 -q 6666" start + +# ------------------------------- +# process check +# ------------------------------- +echo "checking process..." +ps -aef |grep gtm diff --git a/src/gtm/test/stop.sh b/src/gtm/test/stop.sh new file mode 100755 index 0000000..4660ecc --- /dev/null +++ b/src/gtm/test/stop.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +# GTM start script for test + +pushd /tmp/pgxc/bin; ln -fs gtm gtm_standby; popd + +export PATH=/tmp/pgxc/bin:$PATH + +# ------------------------------- +# starting standby... +# ------------------------------- +echo "stopping standby..." +export DATA=/tmp/pgxc/data/gtm_standby + +gtm_ctl -D ${DATA} -S gtm stop + +# ------------------------------- +# starting active... +# ------------------------------- +echo "stopping active..." +export DATA=/tmp/pgxc/data/gtm + +gtm_ctl -D ${DATA} -S gtm stop + +killall -9 gtm gtm_standby + +# ------------------------------- +# process check +# ------------------------------- +echo "checking process..." +ps -aef |grep gtm diff --git a/src/gtm/test/test_common.c b/src/gtm/test/test_common.c new file mode 100644 index 0000000..df8b581 --- /dev/null +++ b/src/gtm/test/test_common.c @@ -0,0 +1,80 @@ +#include "test_common.h" + +pthread_key_t threadinfo_key; + +GTM_ThreadID TopMostThreadID; + +GTM_Conn *conn = NULL; +GTM_Conn *conn2 = NULL; +GTM_Timestamp *timestamp = NULL; +char connect_string[100]; + +void +print_nodeinfo(GTM_PGXCNodeInfo d) +{ + client_log(("type=%d, nodenum=%d, proxynum=%d, ipaddress=%s, port=%d, datafolder=%s, status=%d\n", + d.type, + d.nodenum, + d.proxynum, + d.ipaddress, + d.port, + d.datafolder, + d.status)); +} + + +/* + * Connect to active GTM. + */ +void +connect1() +{ + sprintf(connect_string, "host=localhost port=6666 pgxc_node_id=101 remote_type=%d", + PGXC_NODE_GTM); + + conn = PQconnectGTM(connect_string); + if (conn == NULL) + { + client_log(("Error in connection\n")); + exit(1); + } + client_log(("PGconnectGTM() ok.\n")); +} + +/* + * Connect to standby GTM. + */ +void +connect2() +{ + sprintf(connect_string, "host=localhost port=6667 pgxc_node_id=102 remote_type=%d", + PGXC_NODE_GTM); + + conn = PQconnectGTM(connect_string); + if (conn == NULL) + { + client_log(("Error in connection\n")); + exit(1); + } + client_log(("PGconnectGTM() ok.\n")); +} + + +/* + * Get a word count with using grep command in a log file. + */ +int +grep_count(const char *file, const char *key) +{ + FILE *fp; + int count; + char cmd[1024]; + + snprintf(cmd, sizeof(cmd), "grep -c '%s' %s", key, file); + + fp = popen(cmd, "r"); + fscanf(fp, "%d", &count); + pclose(fp); + + return count; +} diff --git a/src/gtm/test/test_connect.c b/src/gtm/test/test_connect.c new file mode 100644 index 0000000..cb25378 --- /dev/null +++ b/src/gtm/test/test_connect.c @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2010-2011 Nippon Telegraph and Telephone Corporation + */ + +#include <sys/types.h> +#include <unistd.h> + +#include "gtm/libpq-fe.h" +#include "gtm/gtm_c.h" +#include "gtm/gtm_client.h" + +#include "test_common.h" + +#define client_log(x) printf x + +void +setUp() +{ +} + +void +tearDown() +{ +} + +void +test01() +{ + GTM_Conn *conn; + char connect_string[100]; + + SETUP(); + + sprintf(connect_string, "host=localhost port=6666 pgxc_node_id=1 remote_type=%d", + PGXC_NODE_GTM_PROXY); + + conn = PQconnectGTM(connect_string); + if (conn == NULL) + { + client_log(("Error in connection\n")); + exit(1); + } + client_log(("PGconnectGTM() ok.\n")); + + GTMPQfinish(conn); + + TEARDOWN(); +} + +void +test02() +{ + GTM_Conn *conn; + char connect_string[100]; + + SETUP(); + + sprintf(connect_string, "host=localhost port=6666 pgxc_node_id=1 remote_type=%d", + PGXC_NODE_GTM_PROXY_POSTMASTER); + + conn = PQconnectGTM(connect_string); + if (conn == NULL) + { + client_log(("Error in connection\n")); + exit(1); + } + client_log(("PGconnectGTM() ok.\n")); + + GTMPQfinish(conn); + + TEARDOWN(); +} + +void +test03() +{ + GTM_Conn *conn; + char connect_string[100]; + + SETUP(); + + sprintf(connect_string, "host=localhost port=6666 pgxc_node_id=1 remote_type=%d", + PGXC_NODE_COORDINATOR); + + conn = PQconnectGTM(connect_string); + if (conn == NULL) + { + client_log(("Error in connection\n")); + exit(1); + } + client_log(("PGconnectGTM() ok.\n")); + + GTMPQfinish(conn); + + TEARDOWN(); +} + +void +test04() +{ + GTM_Conn *conn; + char connect_string[100]; + + SETUP(); + + sprintf(connect_string, "host=localhost port=6666 pgxc_node_id=1 remote_type=%d", + PGXC_NODE_DATANODE); + + conn = PQconnectGTM(connect_string); + if (conn == NULL) + { + client_log(("Error in connection\n")); + exit(1); + } + client_log(("PGconnectGTM() ok.\n")); + + GTMPQfinish(c... [truncated message content] |
From: Michael P. <mic...@us...> - 2011-04-02 17:28:23
|
Project "Postgres-XC". The branch, master has been updated via e1946160fe64042e76b5252c66b6f6fb5da6b85d (commit) from 098a076729929a8ecf2c6eecd5cc6de63628e882 (commit) - Log ----------------------------------------------------------------- commit e1946160fe64042e76b5252c66b6f6fb5da6b85d Author: Michael P <mic...@us...> Date: Sun Apr 3 02:27:21 2011 +0900 Support for COMMENT Depending on the object type, COMMENT is treated on Coordinators or on all nodes. diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index a184b89..1ffeead 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -804,6 +804,24 @@ standard_ProcessUtility(Node *parsetree, case T_CommentStmt: CommentObject((CommentStmt *) parsetree); + +#ifdef PGXC + /* + * We need to check details of the object being dropped and + * run command on correct nodes + */ + if (IS_PGXC_COORDINATOR && !IsConnFromCoord()) + { + CommentStmt *stmt = (CommentStmt *) parsetree; + + /* Sequence and views exists only on Coordinators */ + if (stmt->objtype == OBJECT_SEQUENCE || + stmt->objtype == OBJECT_VIEW) + ExecUtilityStmtOnNodes(queryString, NULL, false, EXEC_ON_COORDS); + else + ExecUtilityStmtOnNodes(queryString, NULL, false, EXEC_ON_ALL_NODES); + } +#endif break; case T_CopyStmt: ----------------------------------------------------------------------- Summary of changes: src/backend/tcop/utility.c | 18 ++++++++++++++++++ 1 files changed, 18 insertions(+), 0 deletions(-) hooks/post-receive -- Postgres-XC |
From: Michael P. <mic...@us...> - 2011-04-02 16:48:55
|
Project "Postgres-XC". The branch, master has been updated via 098a076729929a8ecf2c6eecd5cc6de63628e882 (commit) from 894ec20ad348f6230e1a796b7435d62f6867eab8 (commit) - Log ----------------------------------------------------------------- commit 098a076729929a8ecf2c6eecd5cc6de63628e882 Author: Michael P <mic...@us...> Date: Sun Apr 3 01:46:20 2011 +0900 Fix for bug 3237724: CREATE/DROP TABLE in test join The origin of this bug was a query in inherit. This query dropped a dozen of tables at once but some tables did not exist due to Postgres-XC's SQL restrictions. It was resulting in diff about tables already existing for test cases create_view and join. diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql index 4babd68..d735a73 100644 --- a/src/test/regress/sql/inherit.sql +++ b/src/test/regress/sql/inherit.sql @@ -333,7 +333,16 @@ SELECT c.relname, objsubid, description FROM pg_description, pg_index i, pg_clas CREATE TABLE inh_error1 () INHERITS (t1, t4); CREATE TABLE inh_error2 (LIKE t4 INCLUDING STORAGE) INHERITS (t1); -DROP TABLE t1, t2, t3, t4, t12_storage, t12_comments, t1_inh, t13_inh, t13_like, t_all; +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; +DROP TABLE t12_storage; +DROP TABLE t12_comments; +DROP TABLE t1_inh; +DROP TABLE t13_inh; +DROP TABLE t13_like; +DROP TABLE t_all; -- Test for renaming in simple multiple inheritance CREATE TABLE t1 (a int, b int); ----------------------------------------------------------------------- Summary of changes: src/test/regress/sql/inherit.sql | 11 ++++++++++- 1 files changed, 10 insertions(+), 1 deletions(-) hooks/post-receive -- Postgres-XC |
From: Michael P. <mic...@us...> - 2011-04-02 16:33:25
|
Project "Postgres-XC". The branch, master has been updated via 894ec20ad348f6230e1a796b7435d62f6867eab8 (commit) from f738280c29b0e50348a8b0940679595534220e24 (commit) - Log ----------------------------------------------------------------- commit 894ec20ad348f6230e1a796b7435d62f6867eab8 Author: Michael P <mic...@us...> Date: Sun Apr 3 01:32:35 2011 +0900 Fix for bug 3269392: GRANT for VIEW and SEQUENCE GRANT was launched on all the nodes, but for views and sequence objects it is only necessary to launch it on Coordinators. When multiple objects are granted at the same time, XC checks their types and returns an error in case Coordinator-only objects are mixed with normal relations. There is also a fix for regression test privileges. diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 49c018b..a184b89 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -1007,12 +1007,58 @@ standard_ProcessUtility(Node *parsetree, break; case T_GrantStmt: - ExecuteGrantStmt((GrantStmt *) parsetree); - #ifdef PGXC - if (IS_PGXC_COORDINATOR) - ExecUtilityStmtOnNodes(queryString, NULL, false, EXEC_ON_ALL_NODES); + if (IS_PGXC_COORDINATOR && !IsConnFromCoord()) + { + RemoteQueryExecType remoteExecType = EXEC_ON_ALL_NODES; + GrantStmt *stmt = (GrantStmt *) parsetree; + + /* Launch GRANT on Coordinator if object is a sequence */ + if (stmt->objtype == ACL_OBJECT_SEQUENCE) + remoteExecType = EXEC_ON_COORDS; + else if (stmt->objtype == ACL_OBJECT_RELATION && + stmt->targtype == ACL_TARGET_OBJECT) + { + /* + * In case object is a relation, differenciate the case + * of a sequence, a view and a table + */ + ListCell *cell; + /* Check the list of objects */ + bool first = true; + RemoteQueryExecType type_local = remoteExecType; + + foreach (cell, stmt->objects) + { + RangeVar *relvar = (RangeVar *) lfirst(cell); + Oid relid = RangeVarGetRelid(relvar, false); + + if (get_rel_relkind(relid) == RELKIND_SEQUENCE || + get_rel_relkind(relid) == RELKIND_VIEW) + remoteExecType = EXEC_ON_COORDS; + else + remoteExecType = EXEC_ON_ALL_NODES; + + /* Check if objects can be launched at the same place as 1st one */ + if (first) + { + type_local = remoteExecType; + first = false; + } + else + { + if (type_local != remoteExecType) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("PGXC does not support GRANT on multiple object types"), + errdetail("Grant VIEW/SEQUENCE and relations on separate queries"))); + } + } + } + ExecUtilityStmtOnNodes(queryString, NULL, false, remoteExecType); + } #endif + ExecuteGrantStmt((GrantStmt *) parsetree); break; case T_GrantRoleStmt: diff --git a/src/test/regress/expected/privileges_1.out b/src/test/regress/expected/privileges_1.out index 94b9267..d71fd34 100644 --- a/src/test/regress/expected/privileges_1.out +++ b/src/test/regress/expected/privileges_1.out @@ -457,7 +457,6 @@ REVOKE ALL PRIVILEGES ON LANGUAGE sql FROM PUBLIC; GRANT USAGE ON LANGUAGE sql TO regressuser1; -- ok GRANT USAGE ON LANGUAGE c TO PUBLIC; -- fail ERROR: language "c" is not trusted -HINT: Only superusers can use untrusted languages. SET SESSION AUTHORIZATION regressuser1; GRANT USAGE ON LANGUAGE sql TO regressuser2; -- fail WARNING: no privileges were granted for "sql" @@ -893,14 +892,19 @@ SELECT lo_create(1005); (1 row) GRANT ALL ON LARGE OBJECT 1001 TO PUBLIC; +ERROR: large object 1001 does not exist GRANT SELECT ON LARGE OBJECT 1003 TO regressuser2; +ERROR: large object 1003 does not exist GRANT SELECT,UPDATE ON LARGE OBJECT 1004 TO regressuser2; +ERROR: large object 1004 does not exist GRANT ALL ON LARGE OBJECT 1005 TO regressuser2; +ERROR: large object 1005 does not exist GRANT SELECT ON LARGE OBJECT 1005 TO regressuser2 WITH GRANT OPTION; +ERROR: large object 1005 does not exist GRANT SELECT, INSERT ON LARGE OBJECT 1001 TO PUBLIC; -- to be failed -ERROR: invalid privilege type INSERT for large object +ERROR: large object 1001 does not exist GRANT SELECT, UPDATE ON LARGE OBJECT 1001 TO nosuchuser; -- to be failed -ERROR: role "nosuchuser" does not exist +ERROR: large object 1001 does not exist GRANT SELECT, UPDATE ON LARGE OBJECT 999 TO PUBLIC; -- to be failed ERROR: large object 999 does not exist \c - @@ -918,46 +922,29 @@ SELECT lo_create(2002); (1 row) SELECT loread(lo_open(1001, x'40000'::int), 32); - loread --------- - \x -(1 row) - +ERROR: permission denied for large object 1001 SELECT loread(lo_open(1002, x'40000'::int), 32); -- to be denied ERROR: permission denied for large object 1002 SELECT loread(lo_open(1003, x'40000'::int), 32); - loread --------- - \x -(1 row) - +ERROR: permission denied for large object 1003 SELECT loread(lo_open(1004, x'40000'::int), 32); - loread --------- - \x -(1 row) - +ERROR: permission denied for large object 1004 SELECT lowrite(lo_open(1001, x'20000'::int), 'abcd'); - lowrite ---------- - 4 -(1 row) - +ERROR: permission denied for large object 1001 SELECT lowrite(lo_open(1002, x'20000'::int), 'abcd'); -- to be denied ERROR: permission denied for large object 1002 SELECT lowrite(lo_open(1003, x'20000'::int), 'abcd'); -- to be denied ERROR: permission denied for large object 1003 SELECT lowrite(lo_open(1004, x'20000'::int), 'abcd'); - lowrite ---------- - 4 -(1 row) - +ERROR: permission denied for large object 1004 GRANT SELECT ON LARGE OBJECT 1005 TO regressuser3; +ERROR: large object 1005 does not exist GRANT UPDATE ON LARGE OBJECT 1006 TO regressuser3; -- to be denied ERROR: large object 1006 does not exist REVOKE ALL ON LARGE OBJECT 2001, 2002 FROM PUBLIC; +ERROR: large object 2001 does not exist GRANT ALL ON LARGE OBJECT 2001 TO regressuser3; +ERROR: large object 2001 does not exist SELECT lo_unlink(1001); -- to be denied ERROR: must be owner of large object 1001 SELECT lo_unlink(2002); @@ -969,39 +956,27 @@ SELECT lo_unlink(2002); \c - -- confirm ACL setting SELECT oid, pg_get_userbyid(lomowner) ownername, lomacl FROM pg_largeobject_metadata; - oid | ownername | lomacl -------+--------------+------------------------------------------------------------------------------------------ + oid | ownername | lomacl +------+--------------+-------- + 1001 | regressuser1 | 1002 | regressuser1 | - 1001 | regressuser1 | {regressuser1=rw/regressuser1,=rw/regressuser1} - 1003 | regressuser1 | {regressuser1=rw/regressuser1,regressuser2=r/regressuser1} - 1004 | regressuser1 | {regressuser1=rw/regressuser1,regressuser2=rw/regressuser1} - 1005 | regressuser1 | {regressuser1=rw/regressuser1,regressuser2=r*w/regressuser1,regressuser3=r/regressuser2} - 2001 | regressuser2 | {regressuser2=rw/regressuser2,regressuser3=rw/regressuser2} + 1003 | regressuser1 | + 1004 | regressuser1 | + 1005 | regressuser1 | + 2001 | regressuser2 | (6 rows) SET SESSION AUTHORIZATION regressuser3; SELECT loread(lo_open(1001, x'40000'::int), 32); - loread ------------- - \x61626364 -(1 row) - +ERROR: permission denied for large object 1001 SELECT loread(lo_open(1003, x'40000'::int), 32); -- to be denied ERROR: permission denied for large object 1003 SELECT loread(lo_open(1005, x'40000'::int), 32); - loread --------- - \x -(1 row) - +ERROR: permission denied for large object 1005 SELECT lo_truncate(lo_open(1005, x'20000'::int), 10); -- to be denied ERROR: permission denied for large object 1005 SELECT lo_truncate(lo_open(2001, x'20000'::int), 10); - lo_truncate -------------- - 0 -(1 row) - +ERROR: permission denied for large object 2001 -- compatibility mode in largeobject permission \c - SET lo_compat_privileges = false; -- default setting @@ -1260,6 +1235,8 @@ REVOKE USAGE ON LANGUAGE sql FROM regressuser1; DROP OWNED BY regressuser1; DROP USER regressuser1; DROP USER regressuser2; +ERROR: role "regressuser2" cannot be dropped because some objects depend on it +DETAIL: privileges for language sql DROP USER regressuser3; DROP USER regressuser4; DROP USER regressuser5; ----------------------------------------------------------------------- Summary of changes: src/backend/tcop/utility.c | 54 ++++++++++++++++++-- src/test/regress/expected/privileges_1.out | 77 ++++++++++------------------ 2 files changed, 77 insertions(+), 54 deletions(-) hooks/post-receive -- Postgres-XC |
From: Abbas B. <ga...@us...> - 2011-04-01 18:17:46
|
Project "Postgres-XC". The branch, master has been updated via f738280c29b0e50348a8b0940679595534220e24 (commit) from 91466a5b79ebd8aea0b6313704654b0a1b7818ac (commit) - Log ----------------------------------------------------------------- commit f738280c29b0e50348a8b0940679595534220e24 Author: Abbas <abb...@en...> Date: Fri Apr 1 22:40:29 2011 +0500 This patch fixes bug ID 3136257. The test case was trying to prepare a transaction after a fetch from a cursor inside a transaction. The way cursors are handled in XC, a FETCH can leave one of the datanodes in DN_CONNECTION_STATE_QUERY. This fact was being ignored by pgxc_all_handles_send_query, which would error out if any of the data nodes is in any state other than DN_CONNECTION_STATE_IDLE, where as the correct handling in this case is to call BufferConnection and continue. Next there was an error in ExecEndRemoteQuery. PGXCNodePrepare called in response to PREPARE TRANSACTION would call release_handles to release all data node connections and coordinator connections back to pool. Later when ExecEndRemoteQuery would try to close cursors, it would find a -1 in sock of all data node connections and hence the system would report that it was unable to close cursors. This patch adds correct handling while closing cursors in ExecEndRemoteQuery. diff --git a/src/backend/pgxc/pool/execRemote.c b/src/backend/pgxc/pool/execRemote.c index 7c9ec5b..cf38041 100644 --- a/src/backend/pgxc/pool/execRemote.c +++ b/src/backend/pgxc/pool/execRemote.c @@ -3470,9 +3470,17 @@ do_query(RemoteQueryState *node) int i = 0; if (pgxc_node_receive(regular_conn_count, connections, NULL)) + { + pfree(connections); + if (primaryconnection) + pfree(primaryconnection); + if (node->cursor_connections) + pfree(node->cursor_connections); + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("Failed to read response from data nodes"))); + } /* * Handle input from the data nodes. * If we got a RESPONSE_DATAROW we can break handling to wrap @@ -3631,6 +3639,7 @@ ExecRemoteQuery(RemoteQueryState *node) node->update_cursor); pfree(node->update_cursor); node->update_cursor = NULL; + pfree_pgxc_all_handles(all_dn_handles); } handle_results: @@ -3878,17 +3887,45 @@ ExecEndRemoteQuery(RemoteQueryState *node) /* * If there are active cursors close them */ - if (node->cursor) - close_node_cursors(node->cursor_connections, node->cursor_count, node->cursor); - - if (node->update_cursor) + if (node->cursor || node->update_cursor) { - PGXCNodeAllHandles *all_dn_handles = get_exec_connections(node, NULL, EXEC_ON_DATANODES); - close_node_cursors(all_dn_handles->datanode_handles, - all_dn_handles->dn_conn_count, - node->update_cursor); - pfree(node->update_cursor); - node->update_cursor = NULL; + PGXCNodeAllHandles *all_handles = NULL; + PGXCNodeHandle **cur_handles; + bool bFree = false; + int nCount; + int i; + + cur_handles = node->cursor_connections; + nCount = node->cursor_count; + + for(i=0;i<node->cursor_count;i++) + { + if (node->cursor_connections == NULL || node->cursor_connections[i]->sock == -1) + { + bFree = true; + all_handles = get_exec_connections(node, NULL, EXEC_ON_DATANODES); + cur_handles = all_handles->datanode_handles; + nCount = all_handles->dn_conn_count; + break; + } + } + + if (node->cursor) + { + close_node_cursors(cur_handles, nCount, node->cursor); + pfree(node->cursor); + node->cursor = NULL; + } + + if (node->update_cursor) + { + close_node_cursors(cur_handles, nCount, node->update_cursor); + pfree(node->update_cursor); + node->update_cursor = NULL; + } + + if (bFree) + pfree_pgxc_all_handles(all_handles); } /* diff --git a/src/backend/pgxc/pool/pgxcnode.c b/src/backend/pgxc/pool/pgxcnode.c index 8c1de08..dcd721d 100644 --- a/src/backend/pgxc/pool/pgxcnode.c +++ b/src/backend/pgxc/pool/pgxcnode.c @@ -1832,13 +1832,12 @@ pgxc_all_handles_send_query(PGXCNodeAllHandles *pgxc_handles, const char *buffer if (pgxc_handles->primary_handle) dn_conn_count--; - /* Send to Datanodes */ - for (i = 0; i < dn_conn_count; i++) + /* Send to Datanodes */ + for (i = 0; i < dn_conn_count; i++) { if (pgxc_handles->datanode_handles[i]->state != DN_CONNECTION_STATE_IDLE) { - pgxc_handles->datanode_handles[i]->state = DN_CONNECTION_STATE_ERROR_FATAL; - continue; + BufferConnection(pgxc_handles->datanode_handles[i]); } if (pgxc_node_send_query(pgxc_handles->datanode_handles[i], buffer)) { @@ -1848,8 +1847,8 @@ pgxc_all_handles_send_query(PGXCNodeAllHandles *pgxc_handles, const char *buffer goto finish; } } - /* Send to Coordinators */ - for (i = 0; i < co_conn_count; i++) + /* Send to Coordinators */ + for (i = 0; i < co_conn_count; i++) { if (pgxc_node_send_query(pgxc_handles->coord_handles[i], buffer)) { ----------------------------------------------------------------------- Summary of changes: src/backend/pgxc/pool/execRemote.c | 57 +++++++++++++++++++++++++++++------ src/backend/pgxc/pool/pgxcnode.c | 11 +++---- 2 files changed, 52 insertions(+), 16 deletions(-) hooks/post-receive -- Postgres-XC |
From: Michael P. <mic...@us...> - 2011-04-01 07:32:06
|
Project "Postgres-XC". The branch, master has been updated via 91466a5b79ebd8aea0b6313704654b0a1b7818ac (commit) from 0429a889372c6db0b4b1253624601c42410cc108 (commit) - Log ----------------------------------------------------------------- commit 91466a5b79ebd8aea0b6313704654b0a1b7818ac Author: Michael P <mic...@us...> Date: Fri Apr 1 16:21:34 2011 +0900 Fix for bug 3234421: multiple user support for pooler This commit extends pooler functionalities for multiple users. Now user name used for connection string is built directly from the user name got on port of postmaster at a user connection on Coordinator. This also solves a serious security issue with passwords parameters in postgresql.conf and when building the connection string of pooler. It also avoids that passwords are written by pooler logging system. In consequence, the following GUC parameters are deleted: data_node_users, data_node_passwords, coordinator_users, coordinator_passwords. This commit is a first step for the support of session parameters. diff --git a/src/backend/pgxc/pool/pgxcnode.c b/src/backend/pgxc/pool/pgxcnode.c index e93ee7f..8c1de08 100644 --- a/src/backend/pgxc/pool/pgxcnode.c +++ b/src/backend/pgxc/pool/pgxcnode.c @@ -144,7 +144,7 @@ InitMultinodeExecutor(void) */ char * PGXCNodeConnStr(char *host, char *port, char *dbname, - char *user, char *password, char *remote_type) + char *user, char *remote_type) { char *out, connstr[256]; @@ -155,8 +155,8 @@ PGXCNodeConnStr(char *host, char *port, char *dbname, * remote type can be coordinator, datanode or application. */ num = snprintf(connstr, sizeof(connstr), - "host=%s port=%s dbname=%s user=%s password=%s options='-c remotetype=%s'", - host, port, dbname, user, password, remote_type); + "host=%s port=%s dbname=%s user=%s options='-c remotetype=%s'", + host, port, dbname, user, remote_type); /* Check for overflow */ if (num > 0 && num < sizeof(connstr)) diff --git a/src/backend/pgxc/pool/poolmgr.c b/src/backend/pgxc/pool/poolmgr.c index 28e9dce..478ba42 100644 --- a/src/backend/pgxc/pool/poolmgr.c +++ b/src/backend/pgxc/pool/poolmgr.c @@ -68,14 +68,10 @@ static MemoryContext PoolerMemoryContext = NULL; /* Connection info of Datanodes */ char *DataNodeHosts = NULL; char *DataNodePorts = NULL; -char *DataNodeUsers = NULL; -char *DataNodePwds = NULL; /* Connection info of Coordinators */ char *CoordinatorHosts = NULL; char *CoordinatorPorts = NULL; -char *CoordinatorUsers = NULL; -char *CoordinatorPwds = NULL; /* PGXC Nodes info list */ static PGXCNodeConnectionInfo *datanode_connInfos; @@ -93,15 +89,16 @@ static PoolHandle *Handle = NULL; static int is_pool_cleaning = false; static int server_fd = -1; -static void agent_init(PoolAgent *agent, const char *database); +static void agent_init(PoolAgent *agent, const char *database, const char *user_name); static void agent_destroy(PoolAgent *agent); static void agent_create(void); static void agent_handle_input(PoolAgent *agent, StringInfo s); -static DatabasePool *create_database_pool(const char *database); +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); -static DatabasePool *find_database_pool(const char *database); -static DatabasePool *remove_database_pool(const char *database); +static int destroy_database_pool(const char *database, const char *user_name); +static DatabasePool *find_database_pool(const char *database, const char *user_name); +static DatabasePool *find_database_pool_to_clean(const char *database, List *dn_list, List *co_list); +static DatabasePool *remove_database_pool(const char *database, const char *user_name); static int *agent_acquire_connections(PoolAgent *agent, List *datanodelist, List *coordlist); static PGXCNodePoolSlot *acquire_connection(DatabasePool *dbPool, int node, char client_conn_type); static void agent_release_connections(PoolAgent *agent, List *dn_discard, List *co_discard); @@ -352,164 +349,8 @@ PoolManagerInit() (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid list syntax for \"coordinator_ports\""))); } - - if (count == 0) - rawstring = pstrdup(DataNodeUsers); - if (count == 1) - rawstring = pstrdup(CoordinatorUsers); - - /* Parse string into list of identifiers */ - if (!SplitIdentifierString(rawstring, ',', &elemlist)) - { - if (count == 0) - /* syntax error in list */ - ereport(FATAL, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid list syntax for \"data_node_users\""))); - else - ereport(FATAL, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid list syntax for \"coordinator_users\""))); - } - - i = 0; - foreach(l, elemlist) - { - char *curuser = (char *) lfirst(l); - - connectionInfos[i].uname = pstrdup(curuser); - if (connectionInfos[i].uname == NULL) - { - ereport(ERROR, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); - } - /* Ignore extra entries, if any */ - if (++i == num_nodes) - break; - } - list_free(elemlist); - pfree(rawstring); - - /* Validate */ - if (i == 0) - { - if (count == 0) - /* syntax error in list */ - ereport(FATAL, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid list syntax for \"data_node_users\""))); - else - /* syntax error in list */ - ereport(FATAL, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid list syntax for \"coordinator_users\""))); - } - else if (i == 1) - { - /* Copy all values from first */ - for (; i < num_nodes; i++) - { - connectionInfos[i].uname = pstrdup(connectionInfos[0].uname); - if (connectionInfos[i].uname == NULL) - { - ereport(ERROR, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); - } - } - } - else if (i < num_nodes) - { - if (count == 0) - /* syntax error in list */ - ereport(FATAL, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid list syntax for \"data_node_users\""))); - else - ereport(FATAL, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid list syntax for \"coordinator_users\""))); - } - - if (count == 0) - rawstring = pstrdup(DataNodePwds); - if (count == 1) - rawstring = pstrdup(CoordinatorPwds); - - /* Parse string into list of identifiers */ - if (!SplitIdentifierString(rawstring, ',', &elemlist)) - { - if (count == 0) - /* syntax error in list */ - ereport(FATAL, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid list syntax for \"data_node_passwords\""))); - else - ereport(FATAL, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid list syntax for \"coordinator_passwords\""))); - } - - i = 0; - foreach(l, elemlist) - { - char *curpassword = (char *) lfirst(l); - - connectionInfos[i].password = pstrdup(curpassword); - if (connectionInfos[i].password == NULL) - { - ereport(ERROR, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); - } - /* Ignore extra entries, if any */ - if (++i == num_nodes) - break; - } - list_free(elemlist); - pfree(rawstring); - - /* Validate */ - if (i == 0) - { - if (count == 0) - /* syntax error in list */ - ereport(FATAL, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid list syntax for \"data_node_passwords\""))); - else - ereport(FATAL, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid list syntax for \"coordinator_passwords\""))); - } - else if (i == 1) - { - /* Copy all values from first */ - for (; i < num_nodes; i++) - { - connectionInfos[i].password = pstrdup(connectionInfos[0].password); - if (connectionInfos[i].password == NULL) - { - ereport(ERROR, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); - } - } - } - else if (i < num_nodes) - { - if (count == 0) - /* syntax error in list */ - ereport(FATAL, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid list syntax for \"data_node_passwords\""))); - else - ereport(FATAL, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid list syntax for \"coordinator_passwords\""))); - } } + /* End of Parsing for Datanode and Coordinator Data */ PoolerLoop(); @@ -647,13 +488,14 @@ agent_create(void) * Invoked from Session process */ void -PoolManagerConnect(PoolHandle *handle, const char *database) +PoolManagerConnect(PoolHandle *handle, const char *database, const char *user_name) { int n32; char msgtype = 'c'; Assert(handle); Assert(database); + Assert(user_name); /* Save the handle */ Handle = handle; @@ -662,7 +504,7 @@ PoolManagerConnect(PoolHandle *handle, const char *database) pool_putbytes(&handle->port, &msgtype, 1); /* Message length */ - n32 = htonl(strlen(database) + 13); + n32 = htonl(strlen(database) + strlen(user_name) + 18); pool_putbytes(&handle->port, (char *) &n32, 4); /* PID number */ @@ -676,28 +518,37 @@ PoolManagerConnect(PoolHandle *handle, const char *database) /* Send database name followed by \0 terminator */ pool_putbytes(&handle->port, database, strlen(database) + 1); pool_flush(&handle->port); + + /* Length of user name string */ + n32 = htonl(strlen(user_name) + 1); + pool_putbytes(&handle->port, (char *) &n32, 4); + + /* Send user name followed by \0 terminator */ + pool_putbytes(&handle->port, user_name, strlen(user_name) + 1); + pool_flush(&handle->port); } /* * Init PoolAgent -*/ + */ static void -agent_init(PoolAgent *agent, const char *database) +agent_init(PoolAgent *agent, const char *database, const char *user_name) { Assert(agent); Assert(database); + Assert(user_name); /* disconnect if we are still connected */ if (agent->pool) agent_release_connections(agent, NULL, NULL); /* find database */ - agent->pool = find_database_pool(database); + agent->pool = find_database_pool(database, user_name); /* create if not found */ if (agent->pool == NULL) - agent->pool = create_database_pool(database); + agent->pool = create_database_pool(database, user_name); } @@ -932,6 +783,7 @@ agent_handle_input(PoolAgent * agent, StringInfo s) for (;;) { const char *database; + const char *user_name; int datanodecount; int coordcount; List *datanodelist = NIL; @@ -969,11 +821,13 @@ agent_handle_input(PoolAgent * agent, StringInfo s) agent->pid = pq_getmsgint(s, 4); len = pq_getmsgint(s, 4); database = pq_getmsgbytes(s, len); + len = pq_getmsgint(s, 4); + user_name = pq_getmsgbytes(s, len); /* * Coordinator pool is not initialized. * With that it would be impossible to create a Database by default. */ - agent_init(agent, database); + agent_init(agent, database, user_name); pq_getmsgend(s); break; case 'd': /* DISCONNECT */ @@ -1312,13 +1166,13 @@ agent_release_connections(PoolAgent *agent, List *dn_discard, List *co_discard) * error and POOL_WEXIST if poll for this database already exist. */ static DatabasePool * -create_database_pool(const char *database) +create_database_pool(const char *database, const char *user_name) { DatabasePool *databasePool; int i; /* check if exist */ - databasePool = find_database_pool(database); + databasePool = find_database_pool(database, user_name); if (databasePool) { /* already exist */ @@ -1336,8 +1190,10 @@ create_database_pool(const char *database) return NULL; } - /* Copy the database name */ ; + /* Copy the database name */ databasePool->database = pstrdup(database); + /* Copy the user name */ + databasePool->user_name = pstrdup(user_name); if (!databasePool->database) { /* out of memory */ @@ -1361,6 +1217,7 @@ create_database_pool(const char *database) (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); pfree(databasePool->database); + pfree(databasePool->user_name); pfree(databasePool); return NULL; } @@ -1378,6 +1235,7 @@ create_database_pool(const char *database) (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); pfree(databasePool->database); + pfree(databasePool->user_name); pfree(databasePool); return NULL; } @@ -1396,13 +1254,13 @@ create_database_pool(const char *database) * Destroy the pool and free memory */ static int -destroy_database_pool(const char *database) +destroy_database_pool(const char *database, const char *user_name) { DatabasePool *databasePool; int i; /* Delete from the list */ - databasePool = remove_database_pool(database); + databasePool = remove_database_pool(database, user_name); if (databasePool) { if (databasePool->dataNodePools) @@ -1421,6 +1279,7 @@ destroy_database_pool(const char *database) } /* free allocated memory */ pfree(databasePool->database); + pfree(databasePool->user_name); pfree(databasePool); return 1; } @@ -1448,10 +1307,10 @@ insert_database_pool(DatabasePool *databasePool) /* - * Find pool for specified database in the list + * Find pool for specified database and username in the list */ static DatabasePool * -find_database_pool(const char *database) +find_database_pool(const char *database, const char *user_name) { DatabasePool *databasePool; @@ -1459,8 +1318,8 @@ find_database_pool(const char *database) databasePool = databasePools; while (databasePool) { - /* if match break the loop and return */ - if (strcmp(database, databasePool->database) == 0) + if (strcmp(database, databasePool->database) == 0 && + strcmp(user_name, databasePool->user_name) == 0) break; databasePool = databasePool->next; @@ -1468,12 +1327,55 @@ find_database_pool(const char *database) return databasePool; } +/* + * Find pool to be cleaned for specified database in the list + */ +static DatabasePool * +find_database_pool_to_clean(const char *database, List *dn_list, List *co_list) +{ + DatabasePool *databasePool; + + /* Scan the list */ + databasePool = databasePools; + while (databasePool) + { + /* Check for given database name */ + if (strcmp(database, databasePool->database) == 0) + { + ListCell *nodelist_item; + + /* Check if this database pool is clean for given coordinator list */ + foreach (nodelist_item, co_list) + { + int nodenum = lfirst_int(nodelist_item); + + if (databasePool->coordNodePools && + databasePool->coordNodePools[nodenum - 1] && + databasePool->coordNodePools[nodenum - 1]->freeSize != 0) + return databasePool; + } + + /* Check if this database pool is clean for given datanode list */ + foreach (nodelist_item, dn_list) + { + int nodenum = lfirst_int(nodelist_item); + + if (databasePool->dataNodePools && + databasePool->dataNodePools[nodenum - 1] && + databasePool->dataNodePools[nodenum - 1]->freeSize != 0) + return databasePool; + } + } + databasePool = databasePool->next; + } + return databasePool; +} /* * Remove pool for specified database from the list */ static DatabasePool * -remove_database_pool(const char *database) +remove_database_pool(const char *database, const char *user_name) { DatabasePool *databasePool, *prev; @@ -1485,7 +1387,8 @@ remove_database_pool(const char *database) { /* if match break the loop and return */ - if (strcmp(database, databasePool->database) == 0) + if (strcmp(database, databasePool->database) == 0 && + strcmp(user_name, databasePool->user_name) == 0) break; prev = databasePool; databasePool = databasePool->next; @@ -1680,7 +1583,6 @@ grow_pool(DatabasePool * dbPool, int index, char client_conn_type) if (IS_PGXC_COORDINATOR) { remote_type = pstrdup("coordinator"); - } else if (IS_PGXC_DATANODE) { @@ -1692,18 +1594,15 @@ grow_pool(DatabasePool * dbPool, int index, char client_conn_type) nodePool->connstr = PGXCNodeConnStr(datanode_connInfos[index].host, datanode_connInfos[index].port, dbPool->database, - datanode_connInfos[index].uname, - datanode_connInfos[index].password, + dbPool->user_name, remote_type); else if (client_conn_type == REMOTE_CONN_COORD) nodePool->connstr = PGXCNodeConnStr(coord_connInfos[index].host, coord_connInfos[index].port, dbPool->database, - coord_connInfos[index].uname, - coord_connInfos[index].password, + dbPool->user_name, remote_type); - if (!nodePool->connstr) { pfree(nodePool); @@ -1864,7 +1763,8 @@ PoolerLoop(void) agent_destroy(agent); } while (databasePools) - if (destroy_database_pool(databasePools->database) == 0) + if (destroy_database_pool(databasePools->database, + databasePools->user_name) == 0) break; close(server_fd); exit(0); @@ -1918,74 +1818,79 @@ clean_connection(List *dn_discard, List *co_discard, const char *database) co_list[count++] = lfirst_int(nodelist_item); /* Find correct Database pool to clean */ - databasePool = find_database_pool(database); + databasePool = find_database_pool_to_clean(database, dn_discard, co_discard); - /* Database pool has not been found, it is already clean */ - if (!databasePool) - return CLEAN_CONNECTION_COMPLETED; - - /* - * Clean each Pool Correctly - * First for Datanode Pool - */ - for (count = 0; count < dn_len; count++) + while (databasePool) { - int node_num = dn_list[count]; - nodePool = databasePool->dataNodePools[node_num - 1]; + databasePool = find_database_pool_to_clean(database, dn_discard, co_discard); + + /* Database pool has not been found, cleaning is over */ + if (!databasePool) + break; - if (nodePool) + /* + * Clean each Pool Correctly + * First for Datanode Pool + */ + for (count = 0; count < dn_len; count++) { - /* Check if connections are in use */ - if (nodePool->freeSize != nodePool->size) - { - elog(WARNING, "Pool of Database %s is using Datanode %d connections", - databasePool->database, node_num); - res = CLEAN_CONNECTION_NOT_COMPLETED; - } + int node_num = dn_list[count]; + nodePool = databasePool->dataNodePools[node_num - 1]; - /* Destroy connections currently in Node Pool */ - if (nodePool->slot) + if (nodePool) { - for (i = 0; i < nodePool->freeSize; i++) - destroy_slot(nodePool->slot[i]); + /* Check if connections are in use */ + if (nodePool->freeSize != nodePool->size) + { + elog(WARNING, "Pool of Database %s is using Datanode %d connections", + databasePool->database, node_num); + res = CLEAN_CONNECTION_NOT_COMPLETED; + } + + /* Destroy connections currently in Node Pool */ + if (nodePool->slot) + { + for (i = 0; i < nodePool->freeSize; i++) + destroy_slot(nodePool->slot[i]); - /* Move slots in use at the beginning of Node Pool array */ - for (i = nodePool->freeSize; i < nodePool->size; i++ ) - nodePool->slot[i - nodePool->freeSize] = nodePool->slot[i]; + /* Move slots in use at the beginning of Node Pool array */ + for (i = nodePool->freeSize; i < nodePool->size; i++ ) + nodePool->slot[i - nodePool->freeSize] = nodePool->slot[i]; + } + nodePool->size -= nodePool->freeSize; + nodePool->freeSize = 0; } - nodePool->size -= nodePool->freeSize; - nodePool->freeSize = 0; } - } - - /* Then for Coordinators */ - for (count = 0; count < co_len; count++) - { - int node_num = co_list[count]; - nodePool = databasePool->coordNodePools[node_num - 1]; - if (nodePool) + /* Then for Coordinators */ + for (count = 0; count < co_len; count++) { - /* Check if connections are in use */ - if (nodePool->freeSize != nodePool->size) - { - elog(WARNING, "Pool of Database %s is using Coordinator %d connections", - databasePool->database, node_num); - res = CLEAN_CONNECTION_NOT_COMPLETED; - } + int node_num = co_list[count]; + nodePool = databasePool->coordNodePools[node_num - 1]; - /* Destroy connections currently in Node Pool */ - if (nodePool->slot) + if (nodePool) { - for (i = 0; i < nodePool->freeSize; i++) - destroy_slot(nodePool->slot[i]); + /* Check if connections are in use */ + if (nodePool->freeSize != nodePool->size) + { + elog(WARNING, "Pool of Database %s is using Coordinator %d connections", + databasePool->database, node_num); + res = CLEAN_CONNECTION_NOT_COMPLETED; + } - /* Move slots in use at the beginning of Node Pool array */ - for (i = nodePool->freeSize; i < nodePool->size; i++ ) - nodePool->slot[i - nodePool->freeSize] = nodePool->slot[i]; + /* Destroy connections currently in Node Pool */ + if (nodePool->slot) + { + for (i = 0; i < nodePool->freeSize; i++) + destroy_slot(nodePool->slot[i]); + + /* Move slots in use at the beginning of Node Pool array */ + for (i = nodePool->freeSize; i < nodePool->size; i++ ) + nodePool->slot[i - nodePool->freeSize] = nodePool->slot[i]; + } + nodePool->size -= nodePool->freeSize; + nodePool->freeSize = 0; } - nodePool->size -= nodePool->freeSize; - nodePool->freeSize = 0; } } diff --git a/src/backend/pgxc/pool/poolutils.c b/src/backend/pgxc/pool/poolutils.c index 32cdfea..24a5c72 100644 --- a/src/backend/pgxc/pool/poolutils.c +++ b/src/backend/pgxc/pool/poolutils.c @@ -36,6 +36,8 @@ * Use of CLEAN CONNECTION is limited to a super user. * It is advised to clean connections before shutting down a Node or drop a Database. * + * Pool cleaning is done for all the users of a given database. + * * SQL query synopsis is as follows: * CLEAN CONNECTION TO * (COORDINATOR num | DATANODE num | ALL {FORCE}) diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 8bc77ea..552b0d8 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -3415,7 +3415,7 @@ BackendStartup(Port *port) if (IS_PGXC_COORDINATOR) { /* User is authenticated and dbname is known at this point */ - PoolManagerConnect(pool_handle, port->database_name); + PoolManagerConnect(pool_handle, port->database_name, port->user_name); InitGTM(); } #endif diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index cb0adb9..0b2c9dd 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -353,6 +353,9 @@ ProcArrayRemove(PGPROC *proc, TransactionId latestXid) } else { +#ifdef PGXC + if (IS_PGXC_DATANODE || !IsConnFromCoord()) +#endif /* Shouldn't be trying to remove a live transaction here */ Assert(!TransactionIdIsValid(proc->xid)); } diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index a184866..c8648ee 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -2819,26 +2819,6 @@ static struct config_string ConfigureNamesString[] = }, { - {"data_node_users", PGC_POSTMASTER, DATA_NODES, - gettext_noop("User names or addresses of data nodes."), - gettext_noop("Comma separated list or single value, " - "if user names are the same on all data nodes") - }, - &DataNodeUsers, - "postgres", NULL, NULL - }, - - { - {"data_node_passwords", PGC_POSTMASTER, DATA_NODES, - gettext_noop("Passwords of data nodes."), - gettext_noop("Comma separated list or single value, " - "if passwords are the same on all data nodes") - }, - &DataNodePwds, - "postgres", NULL, NULL - }, - - { {"gtm_host", PGC_POSTMASTER, GTM, gettext_noop("Host name or address of GTM"), NULL @@ -2867,26 +2847,6 @@ static struct config_string ConfigureNamesString[] = "5432", NULL, NULL }, - { - {"coordinator_users", PGC_POSTMASTER, COORDINATORS, - gettext_noop("User names or addresses of Coordinators."), - gettext_noop("Comma separated list or single value, " - "if user names are the same on all Coordinators") - }, - &CoordinatorUsers, - "postgres", NULL, NULL - }, - - { - {"coordinator_passwords", PGC_POSTMASTER, COORDINATORS, - gettext_noop("Passwords of Coordinators."), - gettext_noop("Comma separated list or single value, " - "if passwords are the same on all Coordinators") - }, - &CoordinatorPwds, - "postgres", NULL, NULL - }, - #endif #ifdef USE_SSL { diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 83c54d4..24bc2fa 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -542,10 +542,6 @@ # (change requires restart) #data_node_ports = '15432,25432' # Port numbers of data nodes # (change requires restart) -#data_node_users = 'postgres' # User names of data nodes - # (change requires restart) -#data_node_passwords = 'postgres' # Passwords of data nodes - # (change requires restart) #primary_data_node = 1 # Which data node to use first for # replicated writes @@ -564,10 +560,6 @@ # (change require restart) #coordinator_ports = '5432' # Port numbers of Coordinators # (change require restart) -#coordinator_users = 'postgres' # User names of Coordinators - # (change requires restart) -#coordinator_passwords = 'postgres' # Passwords of Coordinators - # (change requires restart) #------------------------------------------------------------------------------ # GTM CONNECTION diff --git a/src/include/pgxc/pgxcnode.h b/src/include/pgxc/pgxcnode.h index 321e49c..007e1dc 100644 --- a/src/include/pgxc/pgxcnode.h +++ b/src/include/pgxc/pgxcnode.h @@ -94,7 +94,7 @@ extern void InitMultinodeExecutor(void); /* Open/close connection routines (invoked from Pool Manager) */ extern char *PGXCNodeConnStr(char *host, char *port, char *dbname, char *user, - char *password, char *remote_type); + char *remote_type); extern NODE_CONNECTION *PGXCNodeConnect(char *connstr); extern void PGXCNodeClose(NODE_CONNECTION * conn); extern int PGXCNodeConnected(NODE_CONNECTION * conn); diff --git a/src/include/pgxc/poolmgr.h b/src/include/pgxc/poolmgr.h index 0ae3cc2..7e53b48 100644 --- a/src/include/pgxc/poolmgr.h +++ b/src/include/pgxc/poolmgr.h @@ -28,8 +28,6 @@ typedef struct { char *host; char *port; - char *uname; - char *password; } PGXCNodeConnectionInfo; /* Connection pool entry */ @@ -51,8 +49,8 @@ typedef struct /* All pools for specified database */ typedef struct databasepool { - Oid databaseId; char *database; + char *user_name; PGXCNodePool **dataNodePools; /* one for each Datanode */ PGXCNodePool **coordNodePools; /* one for each Coordinator */ struct databasepool *next; @@ -89,13 +87,9 @@ extern bool PersistentConnections; extern char *DataNodeHosts; extern char *DataNodePorts; -extern char *DataNodeUsers; -extern char *DataNodePwds; extern char *CoordinatorHosts; extern char *CoordinatorPorts; -extern char *CoordinatorUsers; -extern char *CoordinatorPwds; /* Initialize internal structures */ extern int PoolManagerInit(void); @@ -129,7 +123,7 @@ extern void PoolManagerDisconnect(PoolHandle *handle); * for subsequent calls. Associate session with specified database and * initialize respective connection pool */ -extern void PoolManagerConnect(PoolHandle *handle, const char *database); +extern void PoolManagerConnect(PoolHandle *handle, const char *database, const char *user_name); /* Get pooled connections */ extern int *PoolManagerGetConnections(List *datanodelist, List *coordlist); ----------------------------------------------------------------------- Summary of changes: src/backend/pgxc/pool/pgxcnode.c | 6 +- src/backend/pgxc/pool/poolmgr.c | 393 ++++++++++--------------- src/backend/pgxc/pool/poolutils.c | 2 + src/backend/postmaster/postmaster.c | 2 +- src/backend/storage/ipc/procarray.c | 3 + src/backend/utils/misc/guc.c | 40 --- src/backend/utils/misc/postgresql.conf.sample | 8 - src/include/pgxc/pgxcnode.h | 2 +- src/include/pgxc/poolmgr.h | 10 +- 9 files changed, 161 insertions(+), 305 deletions(-) hooks/post-receive -- Postgres-XC |