aboutsummaryrefslogtreecommitdiff
path: root/src/testbed/testbed_api_statistics.c
diff options
context:
space:
mode:
authorSree Harsha Totakura <totakura@in.tum.de>2013-03-13 10:51:45 +0000
committerSree Harsha Totakura <totakura@in.tum.de>2013-03-13 10:51:45 +0000
commit0043aada3f5172d461f89eecc9138b6a1754ca14 (patch)
tree6970bdc8d0acf430db3b6dee674149a2aeb9273a /src/testbed/testbed_api_statistics.c
parente27e2a35da519f85d7597890557f83a4d432e414 (diff)
downloadgnunet-0043aada3f5172d461f89eecc9138b6a1754ca14.tar.gz
gnunet-0043aada3f5172d461f89eecc9138b6a1754ca14.zip
Implement GNUNET_TESTBED_get_statistics() - resolves #2662
Test case for testing GNUNET_TESTBED_get_statistics() Fix waiting for SHUTDOWN_PEERS reply when controller crashes
Diffstat (limited to 'src/testbed/testbed_api_statistics.c')
-rw-r--r--src/testbed/testbed_api_statistics.c341
1 files changed, 336 insertions, 5 deletions
diff --git a/src/testbed/testbed_api_statistics.c b/src/testbed/testbed_api_statistics.c
index f013c0302..d6af1bce2 100644
--- a/src/testbed/testbed_api_statistics.c
+++ b/src/testbed/testbed_api_statistics.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet 2 This file is part of GNUnet
3 (C) 2008--2012 Christian Grothoff (and other contributing authors) 3 (C) 2008--2013 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -25,8 +25,324 @@
25 * @author Sree Harsha Totakura 25 * @author Sree Harsha Totakura
26 */ 26 */
27#include "platform.h" 27#include "platform.h"
28#include "gnunet_common.h"
28#include "gnunet_testbed_service.h" 29#include "gnunet_testbed_service.h"
29 30
31#include "testbed_api_operations.h"
32
33
34/**
35 * Generic logging shorthand
36 */
37#define LOG(kind,...) \
38 GNUNET_log_from (kind, "testbed-api-statistics", __VA_ARGS__)
39
40/**
41 * Debug logging shorthand
42 */
43#define LOG_DEBUG(...) \
44 LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
45
46
47/**
48 * Context information for use in GNUNET_TESTBED_get_statistics()
49 */
50struct GetStatsContext
51{
52 /**
53 * The main operation we generate while creating this context
54 */
55 struct GNUNET_TESTBED_Operation *main_op;
56
57 /**
58 * The service connect operations we create to open connection to the
59 * statistics service of each given peer
60 */
61 struct GNUNET_TESTBED_Operation **ops;
62
63 /**
64 * The array of peers whose statistics services are to be accessed
65 */
66 struct GNUNET_TESTBED_Peer **peers;
67
68 /**
69 * The iterator to call with statistics information
70 */
71 GNUNET_TESTBED_StatisticsIterator proc;
72
73 /**
74 * The callback to call when we are done iterating through all peers'
75 * statistics services
76 */
77 GNUNET_TESTBED_OperationCompletionCallback cont;
78
79 /**
80 * The closure for the above callbacks
81 */
82 void *cb_cls;
83
84 /**
85 * The task for calling the continuation callback
86 */
87 GNUNET_SCHEDULER_TaskIdentifier call_completion_task_id;
88
89 /**
90 * The number of peers present in the peers array. This number also
91 * represents the number of service connect operations in the ops array
92 */
93 unsigned int num_peers;
94
95 /**
96 * How many peers' statistics have we iterated through
97 */
98 unsigned int num_completed;
99
100};
101
102
103/**
104 * Context information with respect to a particular peer
105 */
106struct PeerGetStatsContext
107{
108 /**
109 * The GetStatsContext which is associated with this context
110 */
111 struct GetStatsContext *sc;
112
113 /**
114 * The handle from GNUNET_STATISTICS_get()
115 */
116 struct GNUNET_STATISTICS_GetHandle *get_handle;
117
118 /**
119 * The index of this peer in the peers array of GetStatsContext
120 */
121 unsigned int peer_index;
122};
123
124
125/**
126 * A no-wait operation queue
127 */
128static struct OperationQueue *no_wait_queue;
129
130
131/**
132 * Call statistics operation completion. We call it in a separate task because
133 * the iteration_completion_cb() cannot destroy statistics handle which will be
134 * the case if the user calles GNUNET_TESTBED_operation_done() on the
135 * get_statistics operation.
136 *
137 * @param cls the GetStatsContext
138 * @param tc the scheduler task context
139 */
140static void
141call_completion_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
142{
143 struct GetStatsContext *sc = cls;
144
145 GNUNET_assert (sc->call_completion_task_id != GNUNET_SCHEDULER_NO_TASK);
146 sc->call_completion_task_id = GNUNET_SCHEDULER_NO_TASK;
147 LOG_DEBUG ("Calling get_statistics() continuation callback\n");
148 sc->cont (sc->cb_cls, sc->main_op, NULL);
149}
150
151
152/**
153 * Continuation called by the "get_all" and "get" functions.
154 *
155 * @param cls the PeerGetStatsContext
156 * @param success GNUNET_OK if statistics were
157 * successfully obtained, GNUNET_SYSERR if not.
158 */
159static void
160iteration_completion_cb (void *cls, int success)
161{
162 struct PeerGetStatsContext *peer_sc = cls;
163 struct GetStatsContext *sc;
164
165 if (NULL == peer_sc->get_handle)
166 {
167 /* We are being called after we cancelled the GetHandle */
168 GNUNET_assert (GNUNET_SYSERR == success);
169 return;
170 }
171 GNUNET_break (GNUNET_OK == success);
172 sc = peer_sc->sc;
173 peer_sc->get_handle = NULL;
174 sc->num_completed++;
175 if (sc->num_completed == sc->num_peers)
176 {
177 LOG_DEBUG ("Scheduling to call iteration completion callback\n");
178 sc->call_completion_task_id =
179 GNUNET_SCHEDULER_add_now (&call_completion_task, sc);
180 }
181}
182
183
184/**
185 * Callback function to process statistic values.
186 *
187 * @param cls the PeerGetStatsContext
188 * @param subsystem name of subsystem that created the statistic
189 * @param name the name of the datum
190 * @param value the current value
191 * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
192 * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
193 */
194static int
195iterator_cb (void *cls, const char *subsystem,
196 const char *name, uint64_t value,
197 int is_persistent)
198{
199 struct PeerGetStatsContext *peer_sc = cls;
200 struct GetStatsContext *sc;
201 struct GNUNET_TESTBED_Peer *peer;
202 int ret;
203
204 sc = peer_sc->sc;
205 peer = sc->peers[peer_sc->peer_index];
206 LOG_DEBUG ("Peer %u: [%s,%s] -> %lu\n", peer_sc->peer_index,
207 subsystem, name, (unsigned long) value);
208 ret = sc->proc (sc->cb_cls, peer,
209 subsystem, name, value, is_persistent);
210 if (GNUNET_SYSERR == ret)
211 LOG_DEBUG ("Aborting iteration for peer %u\n", peer_sc->peer_index);
212 return ret;
213}
214
215
216/**
217 * Called after opening a connection to the statistics service of a peer
218 *
219 * @param cls the PeerGetStatsContext
220 * @param op the operation that has been finished
221 * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
222 * @param emsg error message in case the operation has failed; will be NULL if
223 * operation has executed successfully.
224 */
225static void
226service_connect_comp (void *cls,
227 struct GNUNET_TESTBED_Operation *op,
228 void *ca_result,
229 const char *emsg)
230{
231 struct PeerGetStatsContext *peer_sc = cls;
232 struct GNUNET_STATISTICS_Handle *h = ca_result;
233
234 LOG_DEBUG ("Retrieving statistics of peer %u\n", peer_sc->peer_index);
235 peer_sc->get_handle =
236 GNUNET_STATISTICS_get (h, NULL, NULL,
237 GNUNET_TIME_UNIT_FOREVER_REL,
238 &iteration_completion_cb,
239 iterator_cb, peer_sc);
240}
241
242
243/**
244 * Adapter function called to establish a connection to the statistics service
245 * of a peer.
246 *
247 * @param cls the PeerGetStatsContext
248 * @param cfg configuration of the peer to connect to; will be available until
249 * GNUNET_TESTBED_operation_done() is called on the operation returned
250 * from GNUNET_TESTBED_service_connect()
251 * @return service handle to return in 'op_result', NULL on error
252 */
253static void *
254statistics_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
255{
256 struct PeerGetStatsContext *peer_sc = cls;
257
258 LOG_DEBUG ("Connecting to statistics service of peer %u\n",
259 peer_sc->peer_index);
260 return GNUNET_STATISTICS_create ("<testbed-api>", cfg);
261}
262
263
264/**
265 * Adapter function called to destroy statistics connection
266 *
267 * @param cls the PeerGetStatsContext
268 * @param op_result service handle returned from the connect adapter
269 */
270static void
271statistics_da (void *cls, void *op_result)
272{
273 struct PeerGetStatsContext *peer_sc = cls;
274
275 if (NULL != peer_sc->get_handle)
276 {
277 GNUNET_STATISTICS_get_cancel (peer_sc->get_handle);
278 peer_sc->get_handle = NULL;
279 }
280 GNUNET_STATISTICS_destroy ((struct GNUNET_STATISTICS_Handle *) op_result,
281 GNUNET_NO);
282 GNUNET_free (peer_sc);
283}
284
285
286/**
287 * Function called when get_statistics operation is ready
288 *
289 * @param cls the GetStatsContext
290 */
291static void
292opstart_get_stats (void *cls)
293{
294 struct GetStatsContext *sc = cls;
295 struct PeerGetStatsContext *peer_sc;
296 unsigned int peer;
297
298 LOG_DEBUG ("Starting get_statistics operation\n");
299 sc->ops = GNUNET_malloc (sc->num_peers *
300 sizeof (struct GNUNET_TESTBED_Operation *));
301 for (peer = 0; peer < sc->num_peers; peer++)
302 {
303 peer_sc = GNUNET_malloc (sizeof (struct PeerGetStatsContext));
304 peer_sc->sc = sc;
305 peer_sc->peer_index = peer;
306 sc->ops[peer] =
307 GNUNET_TESTBED_service_connect (sc, sc->peers[peer], "statistics",
308 &service_connect_comp,
309 peer_sc,
310 &statistics_ca,
311 &statistics_da,
312 peer_sc);
313 }
314}
315
316
317/**
318 * Function called when get_statistics operation is cancelled or marked as done
319 *
320 * @param cls the GetStatsContext
321 */
322static void
323oprelease_get_stats (void *cls)
324{
325 struct GetStatsContext *sc = cls;
326 unsigned int peer;
327
328 LOG_DEBUG ("Cleaning up get_statistics operation\n");
329 if (GNUNET_SCHEDULER_NO_TASK != sc->call_completion_task_id)
330 GNUNET_SCHEDULER_cancel (sc->call_completion_task_id);
331 if (NULL != sc->ops)
332 {
333 for (peer = 0; peer < sc->num_peers; peer++)
334 {
335 if (NULL != sc->ops[peer])
336 GNUNET_TESTBED_operation_done (sc->ops[peer]);
337 }
338 GNUNET_free (sc->ops);
339 }
340 GNUNET_free (sc);
341 if (GNUNET_YES ==
342 GNUNET_TESTBED_operation_queue_destroy_empty_ (no_wait_queue))
343 no_wait_queue = NULL;
344}
345
30 346
31/** 347/**
32 * Convenience method that iterates over all (running) peers 348 * Convenience method that iterates over all (running) peers
@@ -46,10 +362,25 @@ GNUNET_TESTBED_get_statistics (unsigned int num_peers,
46 GNUNET_TESTBED_OperationCompletionCallback cont, 362 GNUNET_TESTBED_OperationCompletionCallback cont,
47 void *cls) 363 void *cls)
48{ 364{
49 // FIXME: not implemented, but clients will kind-of work if we do this: 365 struct GetStatsContext *sc;
50 GNUNET_break (0); 366
51 cont (cls, NULL, "not implemented"); 367 GNUNET_assert (NULL != proc);
52 return NULL; 368 GNUNET_assert (NULL != cont);
369 if (NULL == no_wait_queue)
370 no_wait_queue =
371 GNUNET_TESTBED_operation_queue_create_ (UINT_MAX);
372 sc = GNUNET_malloc (sizeof (struct GetStatsContext));
373 sc->peers = peers;
374 sc->proc = proc;
375 sc->cont = cont;
376 sc->cb_cls = cls;
377 sc->num_peers = num_peers;
378 sc->main_op =
379 GNUNET_TESTBED_operation_create_ (sc, &opstart_get_stats,
380 &oprelease_get_stats);
381 GNUNET_TESTBED_operation_queue_insert_ (no_wait_queue, sc->main_op);
382 GNUNET_TESTBED_operation_begin_wait_ (sc->main_op);
383 return sc->main_op;
53} 384}
54 385
55 386