changes for experimentation
[oweals/gnunet.git] / src / experimentation / gnunet-daemon-experimentation_scheduler.c
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_getopt_lib.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_core_service.h"
31 #include "gnunet_statistics_service.h"
32 #include "gnunet-daemon-experimentation.h"
33
34 enum ExperimentState
35 {
36         NOT_RUNNING,
37         BUSY,
38         REQUESTED,
39         STARTED,
40         STOPPED
41 };
42
43 struct ScheduledExperiment {
44         struct ScheduledExperiment *next;
45         struct ScheduledExperiment *prev;
46
47         struct Experiment *e;
48         struct Node *n;
49         int state;
50         GNUNET_SCHEDULER_TaskIdentifier task;
51 };
52
53 struct ScheduledExperiment *list_head;
54 struct ScheduledExperiment *list_tail;
55
56 static unsigned int experiments_scheduled;
57 static unsigned int experiments_requested;
58
59 static void
60 request_timeout (void *cls,const struct GNUNET_SCHEDULER_TaskContext* tc)
61 {
62         struct ScheduledExperiment *se = cls;
63         se->task = GNUNET_SCHEDULER_NO_TASK;
64
65         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peer `%s' did not respond to request for experiment `%s'\n",
66                         GNUNET_i2s (&se->n->id), se->e->name);
67
68         GNUNET_CONTAINER_DLL_remove (list_head, list_tail, se);
69         GNUNET_free (se);
70
71         /* Remove experiment */
72
73         GNUNET_assert (experiments_requested > 0);
74         experiments_requested --;
75         GNUNET_STATISTICS_set (GSE_stats, "# experiments requested", experiments_requested, GNUNET_NO);
76 }
77
78 static void start_experiment (void *cls,const struct GNUNET_SCHEDULER_TaskContext* tc)
79 {
80         struct ScheduledExperiment *se = cls;
81         struct GNUNET_TIME_Relative end;
82         struct GNUNET_TIME_Relative backoff;
83
84         se->task = GNUNET_SCHEDULER_NO_TASK;
85
86         if (GNUNET_NO == GNUNET_EXPERIMENTATION_nodes_rts (se->n))
87         {
88                 se->state = BUSY;
89                 backoff = GNUNET_TIME_UNIT_SECONDS;
90                 backoff.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
91                 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Delaying start request to peer `%s' for `%s' for %llu ms\n",
92                                 GNUNET_i2s (&se->n->id), se->e->name, (unsigned long long) backoff.rel_value);
93                 se->task = GNUNET_SCHEDULER_add_delayed (backoff, &start_experiment, se);
94                 return;
95         }
96         else if (BUSY == se->state)
97                 se->state = NOT_RUNNING;
98
99         if (NOT_RUNNING == se->state)
100         {
101                         /* Send start message */
102                         GNUNET_EXPERIMENTATION_nodes_request_start (se->n, se->e);
103                         se->state = REQUESTED;
104                         se->task = GNUNET_SCHEDULER_add_delayed (EXP_RESPONSE_TIMEOUT, &request_timeout, se);
105
106                         GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Sending start request to peer `%s' for `%s'\n",
107                                         GNUNET_i2s (&se->n->id), se->e->name);
108                         experiments_requested ++;
109                         GNUNET_STATISTICS_set (GSE_stats, "# experiments requested", experiments_requested, GNUNET_NO);
110                         return;
111         }
112         else if (REQUESTED == se->state)
113         {
114                         /* Already requested */
115                         return;
116         }
117         else if (STARTED == se->state)
118         {
119                         /* Experiment is running */
120                         GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Running experiment `%s' peer for `%s'\n",
121                                         GNUNET_i2s (&se->n->id), se->e->name);
122
123                         /* do work here */
124
125                         /* Reschedule */
126                         end = GNUNET_TIME_absolute_get_remaining(GNUNET_TIME_absolute_add (se->e->stop, se->e->frequency));
127                         if (0 == end.rel_value)
128                         {
129                                 se->state = STOPPED;
130                                 return; /* End of experiment is reached */
131                         }
132                         /* Reschedule */
133                 se->task = GNUNET_SCHEDULER_add_delayed (se->e->frequency, &start_experiment, se);
134         }
135
136         else if (STOPPED == se->state)
137         {
138                         /* Experiment expired */
139         }
140 }
141
142 /**
143  * Start the scheduler component
144  */
145 void
146 GNUNET_EXPERIMENTATION_scheduler_handle_start (struct Node *n, struct Experiment *e)
147 {
148
149 }
150
151
152 /**
153  * Start the scheduler component
154  */
155 void
156 GNUNET_EXPERIMENTATION_scheduler_handle_stop (struct Node *n, struct Experiment *e)
157 {
158
159 }
160
161 /**
162  * Start the scheduler component
163  */
164 void
165 GNUNET_EXPERIMENTATION_scheduler_add (struct Node *n, struct Experiment *e)
166 {
167         struct ScheduledExperiment *se;
168         struct GNUNET_TIME_Relative start;
169         struct GNUNET_TIME_Relative end;
170
171         start = GNUNET_TIME_absolute_get_remaining(e->start);
172         end = GNUNET_TIME_absolute_get_remaining(e->stop);
173         if (0 == end.rel_value)
174                         return; /* End of experiment is reached */
175
176         /* Add additional checks here if required */
177
178         se = GNUNET_malloc (sizeof (struct ScheduledExperiment));
179         se->state = NOT_RUNNING;
180         se->e = e;
181         se->n = n;
182         if (0 == start.rel_value)
183                         se->task = GNUNET_SCHEDULER_add_now (&start_experiment, se);
184         else
185                         se->task = GNUNET_SCHEDULER_add_delayed (start, &start_experiment, se);
186
187         GNUNET_CONTAINER_DLL_insert (list_head, list_tail, se);
188         GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Added experiment `%s' for node to be scheduled\n",
189                         e->name, GNUNET_i2s(&se->n->id));
190         experiments_scheduled ++;
191         GNUNET_STATISTICS_set (GSE_stats, "# experiments scheduled", experiments_scheduled, GNUNET_NO);
192 }
193
194 /**
195  * Start the scheduler component
196  */
197 void
198 GNUNET_EXPERIMENTATION_scheduler_start ()
199 {
200         experiments_requested = 0;
201         experiments_scheduled = 0;
202 }
203
204
205 /**
206  * Stop the scheduler component
207  */
208 void
209 GNUNET_EXPERIMENTATION_scheduler_stop ()
210 {
211         struct ScheduledExperiment *cur;
212         struct ScheduledExperiment *next;
213
214         next = list_head;
215         while (NULL != (cur = next))
216         {
217                         next = cur->next;
218                         GNUNET_CONTAINER_DLL_remove (list_head, list_tail, cur);
219                         if (GNUNET_SCHEDULER_NO_TASK != cur->task)
220                         {
221                                         GNUNET_SCHEDULER_cancel (cur->task);
222                                         cur->task = GNUNET_SCHEDULER_NO_TASK;
223                         }
224                         GNUNET_free (cur);
225                         GNUNET_assert (experiments_scheduled > 0);
226                         experiments_scheduled --;
227                         GNUNET_STATISTICS_set (GSE_stats, "# experiments scheduled", experiments_scheduled, GNUNET_NO);
228         }
229 }
230
231 /* end of gnunet-daemon-experimentation_scheduler.c */