summaryrefslogtreecommitdiffstats
path: root/include/clplumbing/replytrack.h
blob: f98fe480ae24561375c4c186963340cbd0bb61c0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
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