aboutsummaryrefslogtreecommitdiff
path: root/src/experimentation/gnunet-daemon-experimentation_scheduler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/experimentation/gnunet-daemon-experimentation_scheduler.c')
-rw-r--r--src/experimentation/gnunet-daemon-experimentation_scheduler.c448
1 files changed, 0 insertions, 448 deletions
diff --git a/src/experimentation/gnunet-daemon-experimentation_scheduler.c b/src/experimentation/gnunet-daemon-experimentation_scheduler.c
deleted file mode 100644
index c13434e9b..000000000
--- a/src/experimentation/gnunet-daemon-experimentation_scheduler.c
+++ /dev/null
@@ -1,448 +0,0 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
4
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
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file experimentation/gnunet-daemon-experimentation_scheduler.c
23 * @brief experimentation daemon: execute experiments
24 * @author Christian Grothoff
25 * @author Matthias Wachs
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_core_service.h"
30#include "gnunet_statistics_service.h"
31#include "gnunet-daemon-experimentation.h"
32
33/**
34 * An experiment is added during startup as not running NOT_RUNNING
35 *
36 * The scheduler then decides to schedule it and sends a request to the
37 * remote peer, if core cannot send since it is busy we wait for some time
38 * and change state to BUSY, if we can send we change to REQUESTED and wait
39 * for remote peers ACK.
40 *
41 * When we receive an ACK we change to STARTED and when scheduler decides that
42 * the experiment is finished we change to STOPPED.
43 */
44
45enum ExperimentState
46{
47 /* Experiment is added and waiting to be executed */
48 NOT_RUNNING,
49 /* Cannot send request to remote peer, core is busy*/
50 BUSY,
51 /* We requested experiment and wait for remote peer to ACK */
52 REQUESTED,
53 /* Experiment is running */
54 STARTED,
55 /* Experiment is done */
56 STOPPED
57};
58
59struct ScheduledExperiment {
60 struct ScheduledExperiment *next;
61 struct ScheduledExperiment *prev;
62
63 struct Experiment *e;
64 struct Node *n;
65 int state;
66 int outbound;
67 GNUNET_SCHEDULER_TaskIdentifier task;
68};
69
70struct ScheduledExperiment *waiting_in_head;
71struct ScheduledExperiment *waiting_in_tail;
72
73struct ScheduledExperiment *running_in_head;
74struct ScheduledExperiment *running_in_tail;
75
76struct ScheduledExperiment *waiting_out_head;
77struct ScheduledExperiment *waiting_out_tail;
78
79struct ScheduledExperiment *running_out_head;
80struct ScheduledExperiment *running_out_tail;
81
82
83static unsigned int experiments_scheduled;
84static unsigned int experiments_outbound_running;
85static unsigned int experiments_inbound_running;
86static unsigned int experiments_requested;
87
88
89static struct ScheduledExperiment *
90find_experiment (struct ScheduledExperiment *head, struct ScheduledExperiment *tail,
91 struct Node *n, struct Experiment *e, int outbound)
92{
93 struct ScheduledExperiment *cur;
94 for (cur = head; NULL != cur; cur = cur->next)
95 {
96 if ((cur->n == n) && (cur->e == e) && (cur->outbound == outbound)) /* Node and experiment are equal */
97 break;
98 }
99 return cur;
100}
101
102static void
103request_timeout (void *cls,const struct GNUNET_SCHEDULER_TaskContext* tc)
104{
105 struct ScheduledExperiment *se = cls;
106 se->task = GNUNET_SCHEDULER_NO_TASK;
107
108 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Peer `%s' did not respond to request for experiment `%s'\n"),
109 GNUNET_i2s (&se->n->id), se->e->name);
110
111 GNUNET_CONTAINER_DLL_remove (waiting_out_head, waiting_out_tail, se);
112 GNUNET_free (se);
113
114 /* Remove experiment */
115 GNUNET_assert (experiments_requested > 0);
116 experiments_requested --;
117 GNUNET_STATISTICS_set (GED_stats, "# experiments requested", experiments_requested, GNUNET_NO);
118}
119
120static void run_experiment_inbound (void *cls,const struct GNUNET_SCHEDULER_TaskContext* tc)
121{
122 struct ScheduledExperiment *se = cls;
123 struct GNUNET_TIME_Relative start;
124 struct GNUNET_TIME_Relative end;
125
126 se->task = GNUNET_SCHEDULER_NO_TASK;
127
128 switch (se->state) {
129 case NOT_RUNNING:
130 /* Send START_ACK message */
131 GED_nodes_send_start_ack (se->n, se->e);
132 se->state = REQUESTED;
133 /* Schedule to run */
134 start = GNUNET_TIME_absolute_get_remaining(se->e->start);
135 if (0 == start.rel_value_us)
136 se->task = GNUNET_SCHEDULER_add_now (&run_experiment_inbound, se);
137 else
138 se->task = GNUNET_SCHEDULER_add_delayed (start, &run_experiment_inbound, se);
139 break;
140 case REQUESTED:
141 experiments_inbound_running ++;
142 GNUNET_STATISTICS_set (GED_stats, "# experiments inbound running", experiments_inbound_running, GNUNET_NO);
143 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting inbound experiment `%s' with peer `%s'\n"),
144 se->e->name, GNUNET_i2s (&se->n->id));
145 se->state = STARTED;
146 se->task = GNUNET_SCHEDULER_add_now (&run_experiment_inbound, se);
147 break;
148 case STARTED:
149 /* Experiment is running */
150 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Running %s experiment `%s' peer for `%s'\n",
151 "inbound", GNUNET_i2s (&se->n->id), se->e->name);
152
153 /* do work here */
154
155 /* Reschedule */
156 end = GNUNET_TIME_absolute_get_remaining(GNUNET_TIME_absolute_add (se->e->stop, se->e->frequency));
157 if (0 == end.rel_value_us)
158 {
159 se->state = STOPPED;
160 return; /* End of experiment is reached */
161 }
162 /* Reschedule */
163 se->task = GNUNET_SCHEDULER_add_delayed (se->e->frequency, &run_experiment_inbound, se);
164 break;
165 case STOPPED:
166 /* Experiment expired */
167 break;
168 default:
169 break;
170 }
171
172}
173
174static void run_experiment_outbound (void *cls,const struct GNUNET_SCHEDULER_TaskContext* tc)
175{
176 struct ScheduledExperiment *se = cls;
177 struct GNUNET_TIME_Relative end;
178
179 se->task = GNUNET_SCHEDULER_NO_TASK;
180
181 switch (se->state) {
182 case NOT_RUNNING:
183 /* Send START message */
184 GED_nodes_send_start (se->n, se->e);
185 se->state = REQUESTED;
186 se->task = GNUNET_SCHEDULER_add_delayed (EXP_RESPONSE_TIMEOUT, &request_timeout, se);
187 experiments_requested ++;
188 GNUNET_STATISTICS_set (GED_stats, "# experiments requested", experiments_requested, GNUNET_NO);
189 break;
190 case REQUESTED:
191 /* Expecting START_ACK */
192 GNUNET_break (0);
193 break;
194 case STARTED:
195 /* Experiment is running */
196 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Running %s experiment `%s' peer for `%s'\n",
197 "outbound", GNUNET_i2s (&se->n->id), se->e->name);
198
199 /* do work here */
200
201 /* Reschedule */
202 end = GNUNET_TIME_absolute_get_remaining(GNUNET_TIME_absolute_add (se->e->stop, se->e->frequency));
203 if (0 == end.rel_value_us)
204 {
205 se->state = STOPPED;
206 return; /* End of experiment is reached */
207 }
208 /* Reschedule */
209 se->task = GNUNET_SCHEDULER_add_delayed (se->e->frequency, &run_experiment_outbound, se);
210 break;
211 case STOPPED:
212 /* Experiment expired */
213 break;
214 default:
215 break;
216 }
217}
218
219
220/**
221 * Handle a START message from a remote node
222 *
223 * @param n the node
224 * @param e the experiment
225 */
226void
227GED_scheduler_handle_start (struct Node *n, struct Experiment *e)
228{
229 if ((NULL != find_experiment (waiting_in_head, waiting_in_tail, n, e, GNUNET_NO)) ||
230 (NULL != find_experiment (running_in_head, running_in_tail, n, e, GNUNET_NO)))
231 {
232 GNUNET_break_op (0);
233 return;
234 }
235
236 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
237 "Received %s message from peer %s for experiment `%s'\n",
238 "START", GNUNET_i2s (&n->id), e->name);
239 GED_scheduler_add (n, e, GNUNET_NO);
240}
241
242
243/**
244 * Handle a START_ACK message from a remote node
245 *
246 * @param n the node
247 * @param e the experiment
248 */
249void
250GED_scheduler_handle_start_ack (struct Node *n, struct Experiment *e)
251{
252 struct ScheduledExperiment *se;
253
254 if (NULL == (se = find_experiment (waiting_out_head, waiting_out_tail, n, e, GNUNET_YES)))
255 {
256 GNUNET_break (0);
257 return;
258 }
259
260 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received %s message from peer %s for requested experiment `%s'\n",
261 "START_ACK", GNUNET_i2s (&n->id), e->name);
262
263 if (GNUNET_SCHEDULER_NO_TASK != se->task)
264 {
265 GNUNET_SCHEDULER_cancel (se->task); /* *Canceling timeout task */
266 se->task = GNUNET_SCHEDULER_NO_TASK;
267 }
268
269 /* Remove from waiting list, add to running list */
270 GNUNET_CONTAINER_DLL_remove (waiting_out_head, waiting_out_tail, se);
271 GNUNET_CONTAINER_DLL_insert (running_out_head, running_out_tail, se);
272
273 /* Change state and schedule to run */
274 experiments_outbound_running ++;
275 GNUNET_STATISTICS_set (GED_stats, "# experiments outbound running", experiments_outbound_running, GNUNET_NO);
276 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting outbound experiment `%s' with peer `%s'\n"),
277 e->name, GNUNET_i2s (&n->id));
278 se->state = STARTED;
279 se->task = GNUNET_SCHEDULER_add_now (&run_experiment_outbound, se);
280}
281
282
283/**
284 * Handle a STOP message from a remote node
285 *
286 * @param n the node
287 * @param e the experiment
288 */
289void
290GED_scheduler_handle_stop (struct Node *n, struct Experiment *e)
291{
292 struct ScheduledExperiment *se;
293
294 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Received %s message from peer %s for experiment `%s'\n"),
295 "STOP", GNUNET_i2s (&n->id), e->name);
296
297 if (NULL != (se = find_experiment (waiting_in_head, waiting_in_tail, n, e, GNUNET_NO)))
298 {
299 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received %s message from peer %s for waiting experiment `%s'\n",
300 "STOP", GNUNET_i2s (&n->id), e->name);
301 }
302
303 if (NULL != (se = find_experiment (running_in_head, running_in_tail, n, e, GNUNET_NO)))
304 {
305 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received %s message from peer %s for running experiment `%s'\n",
306 "STOP", GNUNET_i2s (&n->id), e->name);
307 }
308
309}
310
311/**
312 * Add a new experiment for a node
313 *
314 * @param n the node
315 * @param e the experiment
316 * @param outbound are we initiator (GNUNET_YES) or client (GNUNET_NO)?
317 */
318void
319GED_scheduler_add (struct Node *n, struct Experiment *e, int outbound)
320{
321 struct ScheduledExperiment *se;
322 struct GNUNET_TIME_Relative start;
323 struct GNUNET_TIME_Relative end;
324
325 GNUNET_assert ((GNUNET_YES == outbound) || (GNUNET_NO == outbound));
326
327 start = GNUNET_TIME_absolute_get_remaining(e->start);
328 end = GNUNET_TIME_absolute_get_remaining(e->stop);
329 if (0 == end.rel_value_us)
330 return; /* End of experiment is reached */
331
332 /* Add additional checks here if required */
333 se = GNUNET_new (struct ScheduledExperiment);
334 se->state = NOT_RUNNING;
335 se->outbound = outbound;
336 se->e = e;
337 se->n = n;
338
339 if (GNUNET_YES == outbound)
340 {
341 if (0 == start.rel_value_us)
342 se->task = GNUNET_SCHEDULER_add_now (&run_experiment_outbound, se);
343 else
344 se->task = GNUNET_SCHEDULER_add_delayed (start, &run_experiment_outbound, se);
345 GNUNET_CONTAINER_DLL_insert (waiting_out_head, waiting_out_tail, se);
346 }
347 else
348 {
349 if (0 == start.rel_value_us)
350 se->task = GNUNET_SCHEDULER_add_now (&run_experiment_inbound, se);
351 else
352 se->task = GNUNET_SCHEDULER_add_delayed (start, &run_experiment_inbound, se);
353 GNUNET_CONTAINER_DLL_insert (waiting_in_head, waiting_in_tail, se);
354 }
355
356 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added %s experiment `%s' for node to be scheduled\n",
357 (GNUNET_YES == outbound) ? "outbound" : "inbound", e->name, GNUNET_i2s(&se->n->id));
358 experiments_scheduled ++;
359 GNUNET_STATISTICS_set (GED_stats, "# experiments scheduled", experiments_scheduled, GNUNET_NO);
360
361}
362
363/**
364 * Start the scheduler component
365 */
366void
367GED_scheduler_start ()
368{
369 experiments_requested = 0;
370 experiments_scheduled = 0;
371}
372
373
374/**
375 * Stop the scheduler component
376 */
377void
378GED_scheduler_stop ()
379{
380 struct ScheduledExperiment *cur;
381 struct ScheduledExperiment *next;
382
383 next = waiting_in_head;
384 while (NULL != (cur = next))
385 {
386 next = cur->next;
387 GNUNET_CONTAINER_DLL_remove (waiting_in_head, waiting_in_tail, cur);
388 if (GNUNET_SCHEDULER_NO_TASK != cur->task)
389 {
390 GNUNET_SCHEDULER_cancel (cur->task);
391 cur->task = GNUNET_SCHEDULER_NO_TASK;
392 }
393 GNUNET_free (cur);
394 GNUNET_assert (experiments_scheduled > 0);
395 experiments_scheduled --;
396 GNUNET_STATISTICS_set (GED_stats, "# experiments scheduled", experiments_scheduled, GNUNET_NO);
397 }
398
399 next = running_in_head;
400 while (NULL != (cur = next))
401 {
402 next = cur->next;
403 GNUNET_CONTAINER_DLL_remove (running_in_head, running_in_tail, cur);
404 if (GNUNET_SCHEDULER_NO_TASK != cur->task)
405 {
406 GNUNET_SCHEDULER_cancel (cur->task);
407 cur->task = GNUNET_SCHEDULER_NO_TASK;
408 }
409 GNUNET_free (cur);
410 GNUNET_assert (experiments_outbound_running > 0);
411 experiments_inbound_running --;
412 GNUNET_STATISTICS_set (GED_stats, "# experiments inbound running", experiments_inbound_running, GNUNET_NO);
413 }
414
415 next = waiting_out_head;
416 while (NULL != (cur = next))
417 {
418 next = cur->next;
419 GNUNET_CONTAINER_DLL_remove (waiting_out_head, waiting_out_tail, cur);
420 if (GNUNET_SCHEDULER_NO_TASK != cur->task)
421 {
422 GNUNET_SCHEDULER_cancel (cur->task);
423 cur->task = GNUNET_SCHEDULER_NO_TASK;
424 }
425 GNUNET_free (cur);
426 GNUNET_assert (experiments_scheduled > 0);
427 experiments_scheduled --;
428 GNUNET_STATISTICS_set (GED_stats, "# experiments scheduled", experiments_scheduled, GNUNET_NO);
429 }
430
431 next = running_out_head;
432 while (NULL != (cur = next))
433 {
434 next = cur->next;
435 GNUNET_CONTAINER_DLL_remove (running_out_head, running_out_tail, cur);
436 if (GNUNET_SCHEDULER_NO_TASK != cur->task)
437 {
438 GNUNET_SCHEDULER_cancel (cur->task);
439 cur->task = GNUNET_SCHEDULER_NO_TASK;
440 }
441 GNUNET_free (cur);
442 GNUNET_assert (experiments_outbound_running > 0);
443 experiments_outbound_running --;
444 GNUNET_STATISTICS_set (GED_stats, "# experiments outbound running", experiments_outbound_running, GNUNET_NO);
445 }
446}
447
448/* end of gnunet-daemon-experimentation_scheduler.c */