pgpool2.git / summary / log / commit / refs
commit bcc2e9fd84fc4990ae701821340739d54ac0b150
Author: Yugo Nagata <nagata@sraoss.co.jp>
Date: Tue Apr 16 07:01:28 2013 +0000
Add interlocking mechanism of exclusive failover command execution
When using multiple pgpools with watchdog enabled, failover commands
(failover_command, failback_command, and follow_master_comman) get
executed only at one pgpool.
Previously, these command got executed at all pgpools.
watchdog/wd_interlock.c | 217 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 217 insertions(+)
diff --git a/watchdog/wd_interlock.c b/watchdog/wd_interlock.c
new file mode 100644
index 000000000..7c817a631
--- /dev/null
+++ b/watchdog/wd_interlock.c
@@ -0,0 +1,217 @@
+/*
+ * $Header$
+ *
+ * Handles watchdog connection, and protocol communication with pgpool-II
+ *
+ * pgpool: a language independent connection pool server for PostgreSQL
+ * written by Tatsuo Ishii
+ *
+ * Copyright (c) 2003-2013 PgPool Global Development Group
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of the
+ * author not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. The author makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include "pool.h"
+#include "pool_config.h"
+#include "watchdog.h"
+#include "wd_ext.h"
+
+static volatile bool * WD_Locks;
+
+int wd_init_interlock(void);
+void wd_start_interlock(void);
+void wd_end_interlock(void);
+void wd_leave_interlock(void);
+void wd_wait_for_lock(WD_LOCK_ID lock_id);
+bool wd_am_I_lock_holder(void);
+bool wd_is_locked(WD_LOCK_ID lock_id);
+void wd_set_lock(WD_LOCK_ID lock_id, bool value);
+int wd_unlock(WD_LOCK_ID lock_id);
+
+static void wd_update_lock_holder(void);
+static int wd_assume_lock_holder(void);
+static void wd_resign_lock_holder(void);
+static void wd_lock_all(void);
+
+/* initialize interlock */
+int
+wd_init_interlock(void)
+{
+ /* allocate WD_lock_holder */
+ if (WD_Locks == NULL)
+ {
+ WD_Locks = pool_shared_memory_create(sizeof(WD_Locks));
+ if (WD_Locks == NULL)
+ {
+ pool_error("wd_init_interlock: failed to allocate WD_Locks");
+ return WD_NG;
+ }
+ memset(WD_Locks, 0, sizeof(WD_Locks));
+ }
+
+ return WD_OK;
+}
+
+/* notify to start interlocking */
+void wd_start_interlock(void)
+{
+ pool_log("wd_end_interlock: start interlocking");
+
+ wd_set_interlocking(WD_MYSELF, true);
+ wd_send_packet_no(WD_START_INTERLOCK);
+
+ /* try to assume lock holder */
+ wd_assume_lock_holder();
+
+ /* lock all the resource */
+ wd_lock_all();
+}
+
+/* notify to end intelocking */
+void wd_end_interlock(void)
+{
+ pool_log("wd_end_interlock: end interlocking");
+
+ wd_set_interlocking(WD_MYSELF, false);
+ wd_send_packet_no(WD_END_INTERLOCK);
+
+ /* wait for all pgpools ending interlock */
+ while (wd_is_locked(WD_FAILOVER_END_LOCK))
+ {
+ struct timeval t = {1, 0};
+ select(0, NULL, NULL, NULL, &t);
+
+ if (wd_am_I_lock_holder() && !wd_get_interlocking())
+ {
+ wd_unlock(WD_FAILOVER_END_LOCK);
+ }
+ }
+
+ wd_clear_interlocking_info();
+}
+
+/* leave from interlocking by the wayside */
+void wd_leave_interlock(void)
+{
+ pool_log("wd_leave_interlock: leaving from interlocking");
+
+ if (wd_am_I_lock_holder())
+ wd_resign_lock_holder();
+
+ wd_end_interlock();
+}
+
+/* if lock holder return true otherwise false */
+bool wd_am_I_lock_holder(void)
+{
+ wd_update_lock_holder();
+ return WD_MYSELF->is_lock_holder;
+}
+
+/* waiting for the lock or to be lock holder */
+void wd_wait_for_lock(WD_LOCK_ID lock_id)
+{
+ while (wd_is_locked(lock_id))
+ {
+ struct timeval t = {1, 0};
+ select(0, NULL, NULL, NULL, &t);
+
+ if (wd_am_I_lock_holder())
+ break;
+ }
+}
+
+/*
+ * assume lock holder
+ * return WD_OK if success.
+ */
+static int
+wd_assume_lock_holder(void)
+{
+ int rtn = WD_NG;
+
+ wd_set_lock_holder(WD_MYSELF, false);
+
+ /* (master and lock holder) or (succeeded to become lock holder) */
+ if ((WD_MYSELF->status == WD_MASTER && wd_get_lock_holder() == NULL) ||
+ (wd_send_packet_no(WD_STAND_FOR_LOCK_HOLDER) == WD_OK))
+ {
+ wd_set_lock_holder(WD_MYSELF, true);
+ wd_send_packet_no(WD_DECLARE_LOCK_HOLDER);
+ rtn = WD_OK;
+ }
+
+ return rtn;
+}
+
+/*
+ * update information of who's loock holder
+ * Note that the lock holder pgpool can go down accidentally.
+ */
+static void
+wd_update_lock_holder(void)
+{
+ /* assume lock holder if not exist */
+ if (wd_get_lock_holder() == NULL)
+ wd_assume_lock_holder();
+}
+
+/* resign lock holder */
+static void
+wd_resign_lock_holder(void)
+{
+ wd_set_lock_holder(WD_MYSELF, false);
+ wd_send_packet_no(WD_RESIGN_LOCK_HOLDER);
+}
+
+/* returns true if lock_id is locked */
+bool
+wd_is_locked(WD_LOCK_ID lock_id)
+{
+ return WD_Locks[lock_id];
+}
+
+/* lock of unlock a resource */
+void
+wd_set_lock(WD_LOCK_ID lock_id, bool value)
+{
+ WD_Locks[lock_id] = value;
+}
+
+/* lock all the resource */
+static void
+wd_lock_all(void)
+{
+ int i;
+
+ for (i = 0; i < WD_MAX_LOCK_NUM; i++)
+ wd_set_lock(i, true);
+}
+
+/* unlock a resource */
+int
+wd_unlock(WD_LOCK_ID lock_id)
+{
+ int rtn;
+
+ wd_set_lock(lock_id, false);
+ rtn = wd_send_lock_packet(WD_UNLOCK_REQUEST, lock_id);
+ pool_debug("wd_unlock: send unlock request: %d", lock_id);
+
+ return rtn;
+}
[parent: 89eabdd8e78c]