Merge commit '3ef1fa126d9c9b9ba3b29deab7f67218cdf7ce10'

Conflicts:
	.gitignore
	Makefile
	README.rst
	check_dir.c
	config.c
	config.h
	dbutils.h
	repmgr.c
	repmgr.conf
	repmgr.h
	repmgrd.c
This commit is contained in:
Greg Smith
2011-02-15 00:06:01 -05:00
15 changed files with 541 additions and 233 deletions

110
dbutils.c
View File

@@ -19,8 +19,7 @@
#include "repmgr.h"
#define MAXQUERY 8192
#define MAXCONNINFO 1024
#include "strutil.h"
PGconn *
establishDBConnection(const char *conninfo, const bool exit_on_error)
@@ -33,6 +32,7 @@ establishDBConnection(const char *conninfo, const bool exit_on_error)
{
fprintf(stderr, "Connection to database failed: %s",
PQerrorMessage(conn));
if (exit_on_error)
{
PQfinish(conn);
@@ -44,7 +44,6 @@ establishDBConnection(const char *conninfo, const bool exit_on_error)
}
bool
is_standby(PGconn *conn)
{
@@ -52,6 +51,7 @@ is_standby(PGconn *conn)
bool result;
res = PQexec(conn, "SELECT pg_is_in_recovery()");
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
fprintf(stderr, "Can't query server mode: %s", PQerrorMessage(conn));
@@ -79,11 +79,15 @@ pg_version(PGconn *conn, char* major_version)
{
PGresult *res;
int major_version1;
char *major_version2;
int major_version1;
char *major_version2;
res = PQexec(conn,
"WITH pg_version(ver) AS "
"(SELECT split_part(version(), ' ', 2)) "
"SELECT split_part(ver, '.', 1), split_part(ver, '.', 2) "
"FROM pg_version");
res = PQexec(conn, "WITH pg_version(ver) AS (SELECT split_part(version(), ' ', 2)) "
"SELECT split_part(ver, '.', 1), split_part(ver, '.', 2) FROM pg_version");
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
fprintf(stderr, "PQexec failed: %s", PQerrorMessage(conn));
@@ -91,31 +95,35 @@ pg_version(PGconn *conn, char* major_version)
PQfinish(conn);
exit(ERR_DB_QUERY);
}
major_version1 = atoi(PQgetvalue(res, 0, 0));
major_version2 = PQgetvalue(res, 0, 1);
PQclear(res);
if (major_version1 >= 9)
{
/* form a major version string */
snprintf(major_version, MAXVERSIONSTR, "%d.%s", major_version1, major_version2);
xsnprintf(major_version, MAXVERSIONSTR, "%d.%s", major_version1,
major_version2);
}
else
strcpy(major_version, "");
PQclear(res);
return major_version;
}
bool
guc_setted(PGconn *conn, const char *parameter, const char *op, const char *value)
guc_setted(PGconn *conn, const char *parameter, const char *op,
const char *value)
{
PGresult *res;
char sqlquery[MAXQUERY];
char sqlquery[QUERY_STR_LEN];
sprintf(sqlquery, "SELECT true FROM pg_settings "
" WHERE name = '%s' AND setting %s '%s'",
parameter, op, value);
sqlquery_snprintf(sqlquery, "SELECT true FROM pg_settings "
" WHERE name = '%s' AND setting %s '%s'",
parameter, op, value);
res = PQexec(conn, sqlquery);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
@@ -140,11 +148,13 @@ const char *
get_cluster_size(PGconn *conn)
{
PGresult *res;
const char *size;
char sqlquery[MAXQUERY];
const char *size;
char sqlquery[QUERY_STR_LEN];
sprintf(sqlquery, "SELECT pg_size_pretty(SUM(pg_database_size(oid))::bigint) "
" FROM pg_database ");
sqlquery_snprintf(
sqlquery,
"SELECT pg_size_pretty(SUM(pg_database_size(oid))::bigint) "
" FROM pg_database ");
res = PQexec(conn, sqlquery);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
@@ -162,26 +172,57 @@ get_cluster_size(PGconn *conn)
/*
* get a connection to master by reading repl_nodes, creating a connection
* to each node (one at a time) and finding if it is a master or a standby
*
* NB: If master_conninfo_out may be NULL. If it is non-null, it is assumed to
* point to allocated memory of MAXCONNINFO in length, and the master server
* connection string is placed there.
*/
PGconn *
getMasterConnection(PGconn *standby_conn, int id, char *cluster, int *master_id)
getMasterConnection(PGconn *standby_conn, int id, char *cluster,
int *master_id, char *master_conninfo_out)
{
PGconn *master_conn = NULL;
PGresult *res1;
PGresult *res2;
char sqlquery[MAXQUERY];
char master_conninfo[MAXCONNINFO];
PGconn *master_conn = NULL;
PGresult *res1;
PGresult *res2;
char sqlquery[QUERY_STR_LEN];
char master_conninfo_stack[MAXCONNINFO];
char *master_conninfo = &*master_conninfo_stack;
char schema_str[MAXLEN];
char schema_quoted[MAXLEN];
int i;
/*
* If the caller wanted to get a copy of the connection info string, sub
* out the local stack pointer for the pointer passed by the caller.
*/
if (master_conninfo_out != NULL)
master_conninfo = master_conninfo_out;
/*
* XXX: This is copied in at least two other procedures
*
* Assemble the unquoted schema name
*/
maxlen_snprintf(schema_str, "repmgr_%s", cluster);
{
char *identifier = PQescapeIdentifier(standby_conn, schema_str,
strlen(schema_str));
maxlen_snprintf(schema_quoted, "%s", identifier);
PQfreemem(identifier);
}
/* find all nodes belonging to this cluster */
sprintf(sqlquery, "SELECT * FROM repmgr_%s.repl_nodes "
" WHERE cluster = '%s' and id <> %d",
cluster, cluster, id);
sqlquery_snprintf(sqlquery, "SELECT * FROM %s.repl_nodes "
" WHERE cluster = '%s' and id <> %d",
schema_quoted, cluster, id);
res1 = PQexec(standby_conn, sqlquery);
if (PQresultStatus(res1) != PGRES_TUPLES_OK)
{
fprintf(stderr, "Can't get nodes info: %s\n", PQerrorMessage(standby_conn));
fprintf(stderr, "Can't get nodes info: %s\n",
PQerrorMessage(standby_conn));
PQclear(res1);
PQfinish(standby_conn);
exit(ERR_DB_QUERY);
@@ -193,18 +234,21 @@ getMasterConnection(PGconn *standby_conn, int id, char *cluster, int *master_id)
*master_id = atoi(PQgetvalue(res1, i, 0));
strncpy(master_conninfo, PQgetvalue(res1, i, 2), MAXCONNINFO);
master_conn = establishDBConnection(master_conninfo, false);
if (PQstatus(master_conn) != CONNECTION_OK)
continue;
/*
* I can't use the is_standby() function here because on error that
* function closes the connection i pass and exit, but i still need to close
* standby_conn
* function closes the connection i pass and exit, but i still need to
* close standby_conn
*/
res2 = PQexec(master_conn, "SELECT pg_is_in_recovery()");
if (PQresultStatus(res2) != PGRES_TUPLES_OK)
{
fprintf(stderr, "Can't get recovery state from this node: %s\n", PQerrorMessage(master_conn));
fprintf(stderr, "Can't get recovery state from this node: %s\n",
PQerrorMessage(master_conn));
PQclear(res2);
PQfinish(master_conn);
continue;
@@ -229,7 +273,8 @@ getMasterConnection(PGconn *standby_conn, int id, char *cluster, int *master_id)
/* If we finish this loop without finding a master then
* we doesn't have the info or the master has failed (or we
* reached max_connections or superuser_reserved_connections,
* anything else i'm missing?),
* anything else I'm missing?).
*
* Probably we will need to check the error to know if we need
* to start failover procedure or just fix some situation on the
* standby.
@@ -237,4 +282,3 @@ getMasterConnection(PGconn *standby_conn, int id, char *cluster, int *master_id)
PQclear(res1);
return NULL;
}