Permalink
Browse files

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
  • Loading branch information...
2 parents ce06e6c + 3ef1fa1 commit 20af4ffc2c87b851d1605e5d3a35ab98c51bdfc2 Greg Smith committed Feb 15, 2011
Showing with 542 additions and 234 deletions.
  1. +1 −0 CREDITS
  2. +13 −2 Makefile
  3. +1 −0 README.rst
  4. +10 −6 check_dir.c
  5. +2 −0 config.c
  6. +1 −0 config.h
  7. +77 −33 dbutils.c
  8. +6 −4 dbutils.h
  9. +260 −143 repmgr.c
  10. +2 −4 repmgr.h
  11. +20 −16 repmgr.sql
  12. +39 −26 repmgrd.c
  13. +72 −0 strutil.c
  14. +25 −0 strutil.h
  15. +13 −0 uninstall_repmgr.sql
View
@@ -9,3 +9,4 @@ Bas van Oostveen <v.oostveen@gmail.com>
Hannu Krosing <hannu@2ndQuadrant.com>
Cédric Villemain <cedric@2ndquadrant.com>
Charles Duffy <charles@dyfis.net>
+Daniel Farina <daniel@heroku.com>
View
@@ -2,8 +2,10 @@
# Makefile
# Copyright (c) 2ndQuadrant, 2010-2011
-repmgrd_OBJS = dbutils.o config.o repmgrd.o log.o
-repmgr_OBJS = dbutils.o check_dir.o config.o repmgr.o log.o
+repmgrd_OBJS = dbutils.o config.o repmgrd.o log.o strutil.o
+repmgr_OBJS = dbutils.o check_dir.o config.o repmgr.o log.o strutil.o
+
+DATA = repmgr.sql uninstall_repmgr.sql
PG_CPPFLAGS = -I$(libpq_srcdir)
PG_LIBS = $(libpq_pgport)
@@ -26,10 +28,19 @@ include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
endif
+# XXX: Try to use PROGRAM construct (see pgxs.mk) someday. Right now
+# is overriding pgxs install.
install:
$(INSTALL_PROGRAM) repmgrd$(X) '$(DESTDIR)$(bindir)'
$(INSTALL_PROGRAM) repmgr$(X) '$(DESTDIR)$(bindir)'
+ifneq (,$(DATA)$(DATA_built))
+ @for file in $(addprefix $(srcdir)/, $(DATA)) $(DATA_built); do \
+ echo "$(INSTALL_DATA) $$file '$(DESTDIR)$(datadir)/$(datamoduledir)'"; \
+ $(INSTALL_DATA) $$file '$(DESTDIR)$(datadir)/$(datamoduledir)'; \
+ done
+endif
+
clean:
rm -f *.o
rm -f repmgrd
View
@@ -555,6 +555,7 @@ following
* ERR_DB_CON 6: Error when trying to connect to a database.
* ERR_DB_QUERY 7: Error executing a database query.
* ERR_PROMOTED 8: Exiting program because the node has been promoted to master.
+* ERR_BAD_PASSWORD 9: Password used to connect to a database was rejected.
Detailed walkthrough
====================
View
@@ -1,6 +1,6 @@
/*
* check_dir.c - Directories management functions
- * Copyright (C) 2ndQuadrant, 2011
+ * Copyright (C) 2ndQuadrant, 2010-2011
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,9 +24,12 @@
#include <stdio.h>
#include <string.h>
+/* NB: postgres_fe must be included BEFORE check_dir */
#include "postgres_fe.h"
#include "check_dir.h"
+#include "strutil.h"
+
static int mkdir_p(char *path, mode_t omode);
@@ -64,7 +67,7 @@ check_dir(char *dir)
}
else
{
- result = 2; /* not empty */
+ result = 2; /* not empty */
break;
}
}
@@ -111,7 +114,7 @@ set_directory_permissions(char *dir)
/* function from initdb.c */
-/* source stolen from FreeBSD /src/bin/mkdir/mkdir.c and adapted */
+/* source adapted from FreeBSD /src/bin/mkdir/mkdir.c */
/*
* this tries to build all the elements of a path to a directory a la mkdir -p
@@ -219,10 +222,11 @@ mkdir_p(char *path, mode_t omode)
bool
is_pg_dir(char *dir)
{
- char path[8192];
- struct stat sb;
+ const size_t buf_sz = 8192;
+ char path[buf_sz];
+ struct stat sb;
- sprintf(path, "%s/PG_VERSION", dir);
+ xsnprintf(path, buf_sz, "%s/PG_VERSION", dir);
return (stat(path, &sb) == 0) ? true : false;
}
View
@@ -18,6 +18,8 @@
*/
#include "config.h"
+#include "repmgr.h"
+#include "strutil.h"
void
parse_config(const char* config_file, t_configuration_options* options)
View
@@ -21,6 +21,7 @@
#define _REPMGR_CONFIG_H_
#include "repmgr.h"
+#include "strutil.h"
typedef struct
{
View
110 dbutils.c
@@ -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,14 +44,14 @@ establishDBConnection(const char *conninfo, const bool exit_on_error)
}
-
bool
is_standby(PGconn *conn)
{
PGresult *res;
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,43 +79,51 @@ 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));
PQclear(res);
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,12 +273,12 @@ 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.
*/
PQclear(res1);
return NULL;
}
-
View
@@ -21,10 +21,12 @@
#define _REPMGR_DBUTILS_H_
PGconn *establishDBConnection(const char *conninfo, const bool exit_on_error);
-bool is_standby(PGconn *conn);
+bool is_standby(PGconn *conn);
char *pg_version(PGconn *conn, char* major_version);
-bool guc_setted(PGconn *conn, const char *parameter, const char *op, const char *value);
-const char *get_cluster_size(PGconn *conn);
-PGconn * getMasterConnection(PGconn *standby_conn, int id, char *cluster, int *master_id);
+bool guc_setted(PGconn *conn, const char *parameter, const char *op,
+ const char *value);
+const char *get_cluster_size(PGconn *conn);
+PGconn *getMasterConnection(PGconn *standby_conn, int id, char *cluster,
+ int *master_id, char *master_conninfo_out);
#endif
Oops, something went wrong.

0 comments on commit 20af4ff

Please sign in to comment.