summaryrefslogtreecommitdiffstats
path: root/include/clplumbing/replytrack.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/clplumbing/replytrack.h')
-rw-r--r--include/clplumbing/replytrack.h208
1 files changed, 208 insertions, 0 deletions
diff --git a/include/clplumbing/replytrack.h b/include/clplumbing/replytrack.h
new file mode 100644
index 0000000..f98fe48
--- /dev/null
+++ b/include/clplumbing/replytrack.h
@@ -0,0 +1,208 @@
+/*
+ * Process tracking object.
+ *
+ * Copyright (c) 2007 Alan Robertson
+ * Author: Alan Robertson <alanr@unix.sh>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _REPLYTRACK_H
+# define _REPLYTRACK_H
+#include <sys/types.h>
+#include <sys/times.h>
+#include <clplumbing/longclock.h>
+#include <clplumbing/cl_uuid.h>
+
+/*
+ * We track replies - so we can tell when all expected replies were received.
+ *
+ * There is a problem in clusters where a message is sent to each node, and a
+ * reply is expected from each node of knowing when all the replies have been
+ * received.
+ *
+ * If all nodes are up, it's easy to see when all replies are received.
+ * But, if some nodes are down, we really don't want to wait for a timeout
+ * before we decide that we've gotten all the replies we're going to get,
+ * since nodes can be down for potentially very long periods of time, and
+ * waiting for a long timeout can delay things a great deal again and
+ * again - causing significant delays and user frustration.
+ *
+ * That's where these functions come in!
+ * Instead, inform these functions what nodes are up and what ones are down,
+ * and when you receive a reply, and it will tell you when you've gotten
+ * them all - managing all that tedious bookwork for you.
+ */
+
+typedef enum _replytrack_completion_type replytrack_completion_type_t;
+typedef enum _nodetrack_change nodetrack_change_t;
+typedef struct _replytrack replytrack_t;
+typedef struct _nodetrack nodetrack_t;
+typedef struct _nodetrack_intersection nodetrack_intersection_t;
+
+/*
+ * The levels of logging possible for our process
+ */
+enum _replytrack_completion_type {
+ REPLYT_ALLRCVD = 2, /* All replies received */
+ REPLYT_TIMEOUT, /* Timeout occurred with replies missing */
+};
+
+
+typedef void (*replytrack_callback_t)
+( replytrack_t * rl
+, gpointer user_data
+, replytrack_completion_type_t reason);
+
+typedef void (*replytrack_iterator_t)
+( replytrack_t* rl
+, gpointer user_data
+, const char* node
+, cl_uuid_t uuid);
+
+typedef void (*nodetrack_iterator_t)
+( nodetrack_t* rl
+, gpointer user_data
+, const char* node
+, cl_uuid_t uuid);
+
+
+/*
+ * Note:
+ * If you use the timeout feature of this code, it relies on you using glib mainloop
+ * for your scheduling. timeout_ms should be zero for no timeout.
+ */
+replytrack_t* replytrack_new(nodetrack_t* membership
+, replytrack_callback_t callback
+, unsigned long timeout_ms
+, gpointer user_data);
+
+void replytrack_del(replytrack_t *rl);
+gboolean replytrack_gotreply(replytrack_t *rl
+, const char * node
+, cl_uuid_t uuid);
+ /* Returns TRUE if this was the final expected reply */
+/*
+ * Iterate over the set of outstanding replies:
+ * return count of how many items in the iteration
+ */
+int replytrack_outstanding_iterate(replytrack_t* rl
+, replytrack_iterator_t i, gpointer user_data);
+int replytrack_outstanding_count(replytrack_t* rl);
+
+/*
+ * The functions above operate using a view of membership which is established
+ * through the functions below.
+ *
+ * This can either be through the heartbeat low-level membership API, or any
+ * other view of membership you wish. Mentioning a node as either up or down
+ * will automatically add that node to our view of potential membership.
+ *
+ * These functions only support one view of membership per process.
+ *
+ * The general idea of how to use these functions:
+ * Initially:
+ * 1) iterate through init membership and call nodetrack_node(up|down) for
+ * each node to start things off.
+ *
+ * On an ongoing basis:
+ * 2) call nodetrack_node_up whenever a node comes up
+ * We expect a reply from nodes that are up.
+ * 3) call nodetrack_node_down whenever a node goes down
+ * We don't expect a reply from nodes that are down.
+ *
+ * For each set of replies you want tracked:
+ * 4) Create a replytrack_t for a set of expected replies
+ * 5) call replytrack_gotreply() each time you get an expected reply
+ * 6) replist_gotreply() returns TRUE when the final message was received.
+ * (it does this by comparing against the membership as defined below)
+ * 7) you will get a callback when timeout occurs or final message is received
+ * n. b.:
+ * No callback function => manage timeouts yourself
+ * 8) call replytrack_del() when you're done with the reply list
+ * n. b.:
+ * If you have replies outstanding, and you have a timeout and
+ * a callback function set, you will get a warning for destroying
+ * a replytrack_t object 'prematurely'.
+ * You will also log a warning if you call replytrack_gotreply() after
+ * all replies were received or a timeout occurred.
+ *
+ */
+
+/*
+ * The levels of logging possible for our process
+ */
+enum _nodetrack_change {
+ NODET_UP = 2, /* This node came up */
+ NODET_DOWN, /* This node went down */
+};
+
+typedef void (*nodetrack_callback_t)
+( nodetrack_t * mbr
+, const char * node
+, cl_uuid_t u
+, nodetrack_change_t reason
+, gpointer user_data);
+
+nodetrack_t* nodetrack_new(nodetrack_callback_t callback
+, gpointer user_data);
+void nodetrack_del(nodetrack_t*);
+gboolean nodetrack_nodeup(nodetrack_t* mbr, const char * node
+, cl_uuid_t u);
+gboolean nodetrack_nodedown(nodetrack_t* mbr, const char * node
+, cl_uuid_t u);
+gboolean nodetrack_ismember(nodetrack_t* mbr, const char * node
+, cl_uuid_t u);
+int nodetrack_iterate(nodetrack_t* mbr
+, nodetrack_iterator_t i, gpointer user_data);
+
+/* An intesection nodetrack table
+ * A node is put into the "intersection" nodetrack_t table when it is in all
+ * the underlying constituent nodetrack_t tables, and removed when it is
+ * removed from any of them.
+ * Note that you can set a callback to be informed when these "intersection"
+ * membership changes occur.
+ */
+nodetrack_intersection_t*
+ nodetrack_intersection_new(nodetrack_t** tables, int ntables
+, nodetrack_callback_t callback, gpointer user_data);
+void nodetrack_intersection_del(nodetrack_intersection_t*);
+nodetrack_t* nodetrack_intersection_table(nodetrack_intersection_t*);
+
+#if 0
+/*
+ * I don't know if this should be in this library, or just in
+ * the CCM. Probably only the CCM _should_ be using it (when I write it)
+ */
+/*
+ * Use of the nodetrack_hb_* functions implies you're using the heartbeat
+ * peer-connectivity information as your source of information. This is
+ * really only suitable if you're using heartbeat's low-level group membership
+ * for your source of who to expect replies from.
+ * If you're using nodetrack_hb_init, this replaces step (1) above.
+ */
+void nodetrack_hb_init(void)
+/*
+ * If you're using nodetrack_hb_statusmsg, just pass it all status messages
+ * and all peer-connectivity status messages or even all heartbeat messages
+ * (non-status messages will be ignored).
+ * This replaces steps (2) and (3) above _if_ you're using heartbeat low
+ * level membership for your source of who to expect replies from.
+ */
+void nodetrack_hb_statusmsg(struct ha_msg* statusmsg);
+#endif /*0*/
+
+#endif