diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-10-17 09:40:36 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-10-17 09:40:36 +0000 |
commit | ba8c01f2e3d41fb21dd8efa3dcfe2cc555d5f530 (patch) | |
tree | f340ced5207da20651c1b7daa729f69f64523bc2 /src/ats | |
parent | 710709c0d4eaa001fa185b5b72972666cb64f926 (diff) | |
download | gnunet-ba8c01f2e3d41fb21dd8efa3dcfe2cc555d5f530.tar.gz gnunet-ba8c01f2e3d41fb21dd8efa3dcfe2cc555d5f530.zip |
towards nicer scheduling code
Diffstat (limited to 'src/ats')
-rw-r--r-- | src/ats/gnunet-service-ats_addresses.c | 298 |
1 files changed, 230 insertions, 68 deletions
diff --git a/src/ats/gnunet-service-ats_addresses.c b/src/ats/gnunet-service-ats_addresses.c index 68d4b03de..f8cd2ab16 100644 --- a/src/ats/gnunet-service-ats_addresses.c +++ b/src/ats/gnunet-service-ats_addresses.c | |||
@@ -25,6 +25,7 @@ | |||
25 | * @author Christian Grothoff | 25 | * @author Christian Grothoff |
26 | */ | 26 | */ |
27 | #include "platform.h" | 27 | #include "platform.h" |
28 | #include "gnunet_ats_service.h" | ||
28 | #include "gnunet-service-ats_addresses.h" | 29 | #include "gnunet-service-ats_addresses.h" |
29 | #include "gnunet-service-ats_performance.h" | 30 | #include "gnunet-service-ats_performance.h" |
30 | #include "gnunet-service-ats_scheduling.h" | 31 | #include "gnunet-service-ats_scheduling.h" |
@@ -46,12 +47,12 @@ struct ATS_Address | |||
46 | 47 | ||
47 | struct GNUNET_ATS_Information * ats; | 48 | struct GNUNET_ATS_Information * ats; |
48 | 49 | ||
50 | struct GNUNET_TIME_Relative atsp_latency; | ||
51 | |||
49 | struct GNUNET_BANDWIDTH_Value32NBO atsp_utilization_in; | 52 | struct GNUNET_BANDWIDTH_Value32NBO atsp_utilization_in; |
50 | 53 | ||
51 | struct GNUNET_BANDWIDTH_Value32NBO atsp_utilization_out; | 54 | struct GNUNET_BANDWIDTH_Value32NBO atsp_utilization_out; |
52 | 55 | ||
53 | struct GNUNET_TIME_Relative atsp_latency; | ||
54 | |||
55 | uint32_t atsp_distance; | 56 | uint32_t atsp_distance; |
56 | 57 | ||
57 | uint32_t atsp_cost_wan; | 58 | uint32_t atsp_cost_wan; |
@@ -64,9 +65,10 @@ struct ATS_Address | |||
64 | 65 | ||
65 | struct GNUNET_BANDWIDTH_Value32NBO assigned_bw_out; | 66 | struct GNUNET_BANDWIDTH_Value32NBO assigned_bw_out; |
66 | 67 | ||
67 | struct GNUNET_BANDWIDTH_Value32NBO bw_in; | 68 | /** |
68 | 69 | * Is this the active address for this peer? | |
69 | struct GNUNET_BANDWIDTH_Value32NBO bw_out; | 70 | */ |
71 | int active; | ||
70 | 72 | ||
71 | }; | 73 | }; |
72 | 74 | ||
@@ -80,75 +82,138 @@ static unsigned long long total_quota_out; | |||
80 | static unsigned int active_addr_count; | 82 | static unsigned int active_addr_count; |
81 | 83 | ||
82 | 84 | ||
83 | struct CompareAddressContext | 85 | /** |
86 | * Update a bandwidth assignment for a peer. This trivial method currently | ||
87 | * simply assigns the same share to all active connections. | ||
88 | * | ||
89 | * @param cls unused | ||
90 | * @param key unused | ||
91 | * @param value the 'struct ATS_Address' | ||
92 | * @return GNUNET_OK (continue to iterate) | ||
93 | */ | ||
94 | static int | ||
95 | update_bw_it (void *cls, | ||
96 | const GNUNET_HashCode * key, | ||
97 | void *value) | ||
84 | { | 98 | { |
85 | struct ATS_Address * search; | 99 | struct ATS_Address *aa = value; |
86 | struct ATS_Address * result; | 100 | |
87 | }; | 101 | if (GNUNET_YES != aa->active) |
102 | return GNUNET_OK; | ||
103 | aa->assigned_bw_in.value__ = htonl (total_quota_in / active_addr_count); | ||
104 | aa->assigned_bw_out.value__ = htonl (total_quota_out / active_addr_count); | ||
105 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
106 | "New bandwidth for peer %s is %u/%u\n", | ||
107 | GNUNET_i2s (&aa->peer), | ||
108 | ntohl (aa->assigned_bw_in.value__), | ||
109 | ntohl (aa->assigned_bw_out.value__)); | ||
110 | GAS_scheduling_transmit_address_suggestion (&aa->peer, | ||
111 | aa->plugin, | ||
112 | aa->addr, aa->addr_len, | ||
113 | aa->session_id, | ||
114 | aa->ats, aa->ats_count, | ||
115 | aa->assigned_bw_out, aa->assigned_bw_in); | ||
116 | GAS_reservations_set_bandwidth (&aa->peer, | ||
117 | aa->assigned_bw_in); | ||
118 | GAS_performance_notify_clients (&aa->peer, | ||
119 | aa->plugin, | ||
120 | aa->addr, aa->addr_len, | ||
121 | aa->ats, aa->ats_count, | ||
122 | aa->assigned_bw_out, aa->assigned_bw_in); | ||
123 | return GNUNET_OK; | ||
124 | } | ||
88 | 125 | ||
89 | 126 | ||
127 | /** | ||
128 | * Some (significant) input changed, recalculate bandwidth assignment | ||
129 | * for all peers. | ||
130 | */ | ||
90 | static void | 131 | static void |
132 | recalculate_assigned_bw () | ||
133 | { | ||
134 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
135 | "Recalculating bandwidth for all active connections\n"); | ||
136 | GNUNET_CONTAINER_multihashmap_iterate (addresses, | ||
137 | &update_bw_it, | ||
138 | NULL); | ||
139 | } | ||
140 | |||
141 | |||
142 | /** | ||
143 | * Destroy the given address. | ||
144 | * | ||
145 | * @param addr address to destroy | ||
146 | * @return GNUNET_YES if bandwidth allocations should be recalcualted | ||
147 | */ | ||
148 | static int | ||
91 | destroy_address (struct ATS_Address *addr) | 149 | destroy_address (struct ATS_Address *addr) |
92 | { | 150 | { |
151 | int ret; | ||
152 | |||
153 | ret = GNUNET_NO; | ||
93 | GNUNET_assert (GNUNET_YES == | 154 | GNUNET_assert (GNUNET_YES == |
94 | GNUNET_CONTAINER_multihashmap_remove(addresses, | 155 | GNUNET_CONTAINER_multihashmap_remove(addresses, |
95 | &addr->peer.hashPubKey, | 156 | &addr->peer.hashPubKey, |
96 | addr)); | 157 | addr)); |
97 | if (ntohl (addr->bw_in.value__) > 0) | 158 | if (GNUNET_YES == addr->active) |
98 | { | 159 | { |
99 | active_addr_count--; | 160 | active_addr_count--; |
100 | // FIXME: update address assignment for other peers... | 161 | ret = GNUNET_YES; |
101 | } | 162 | } |
102 | GNUNET_free_non_null (addr->ats); | 163 | GNUNET_free_non_null (addr->ats); |
103 | GNUNET_free (addr->plugin); | 164 | GNUNET_free (addr->plugin); |
104 | GNUNET_free (addr); | 165 | GNUNET_free (addr); |
166 | return ret; | ||
105 | } | 167 | } |
106 | 168 | ||
107 | 169 | ||
170 | struct CompareAddressContext | ||
171 | { | ||
172 | const struct ATS_Address * search; | ||
173 | struct ATS_Address * result; | ||
174 | }; | ||
175 | |||
176 | |||
108 | static int | 177 | static int |
109 | compare_address_it (void *cls, | 178 | compare_address_it (void *cls, |
110 | const GNUNET_HashCode * key, | 179 | const GNUNET_HashCode * key, |
111 | void *value) | 180 | void *value) |
112 | { | 181 | { |
113 | struct CompareAddressContext * cac = cls; | 182 | struct CompareAddressContext * cac = cls; |
114 | struct ATS_Address * aa = (struct ATS_Address *) value; | 183 | struct ATS_Address * aa = value; |
115 | |||
116 | /* compare sessions */ | ||
117 | if (aa->session_id != cac->search->session_id) | ||
118 | return GNUNET_YES; | ||
119 | |||
120 | if (aa->addr_len != cac->search->addr_len) | ||
121 | { | ||
122 | return GNUNET_YES; | ||
123 | } | ||
124 | 184 | ||
125 | if (0 == strcmp(aa->plugin, cac->search->plugin)) | 185 | if ( ( (aa->addr_len != cac->search->addr_len) || |
126 | { | 186 | (0 != strcmp(aa->plugin, cac->search->plugin)) || |
187 | (0 != memcmp (aa->addr, cac->search->addr, aa->addr_len)) ) && | ||
188 | ( (aa->session_id != cac->search->session_id) || | ||
189 | (cac->search->session_id == 0) )) | ||
127 | return GNUNET_YES; | 190 | return GNUNET_YES; |
128 | } | 191 | cac->result = aa; |
129 | 192 | return GNUNET_NO; | |
130 | if (0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) | ||
131 | { | ||
132 | cac->result = aa; | ||
133 | return GNUNET_NO; | ||
134 | } | ||
135 | return GNUNET_YES; | ||
136 | } | 193 | } |
137 | 194 | ||
138 | 195 | ||
196 | /** | ||
197 | * Find an existing equivalent address record. | ||
198 | * Compares by peer identity and network address OR by session ID | ||
199 | * (one of the two must match). | ||
200 | * | ||
201 | * @param peer peer to lookup addresses for | ||
202 | * @param addr existing address record | ||
203 | * @return existing address record, NULL for none | ||
204 | */ | ||
139 | struct ATS_Address * | 205 | struct ATS_Address * |
140 | find_address (const struct GNUNET_PeerIdentity *peer, | 206 | find_address (const struct GNUNET_PeerIdentity *peer, |
141 | struct ATS_Address * addr) | 207 | const struct ATS_Address * addr) |
142 | { | 208 | { |
143 | struct CompareAddressContext cac; | 209 | struct CompareAddressContext cac; |
210 | |||
144 | cac.result = NULL; | 211 | cac.result = NULL; |
145 | cac.search = addr; | 212 | cac.search = addr; |
146 | |||
147 | GNUNET_CONTAINER_multihashmap_get_multiple(addresses, | 213 | GNUNET_CONTAINER_multihashmap_get_multiple(addresses, |
148 | &peer->hashPubKey, | 214 | &peer->hashPubKey, |
149 | compare_address_it, | 215 | compare_address_it, |
150 | &cac); | 216 | &cac); |
151 | |||
152 | return cac.result; | 217 | return cac.result; |
153 | } | 218 | } |
154 | 219 | ||
@@ -163,6 +228,7 @@ GAS_addresses_update (const struct GNUNET_PeerIdentity *peer, | |||
163 | { | 228 | { |
164 | struct ATS_Address * aa; | 229 | struct ATS_Address * aa; |
165 | struct ATS_Address * old; | 230 | struct ATS_Address * old; |
231 | uint32_t i; | ||
166 | 232 | ||
167 | aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len); | 233 | aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len); |
168 | aa->ats = GNUNET_malloc(atsi_count * sizeof (struct GNUNET_ATS_Information)); | 234 | aa->ats = GNUNET_malloc(atsi_count * sizeof (struct GNUNET_ATS_Information)); |
@@ -185,18 +251,50 @@ GAS_addresses_update (const struct GNUNET_PeerIdentity *peer, | |||
185 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 251 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
186 | "Added new address for peer `%s' %X\n", | 252 | "Added new address for peer `%s' %X\n", |
187 | GNUNET_i2s (peer), aa); | 253 | GNUNET_i2s (peer), aa); |
188 | return; | 254 | old = aa; |
189 | } | 255 | } |
190 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 256 | else |
191 | "Updated existing address for peer `%s' %X \n", | 257 | { |
192 | GNUNET_i2s (peer), old); | 258 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
193 | GNUNET_free_non_null (old->ats); | 259 | "Updated existing address for peer `%s' %X \n", |
194 | old->ats = NULL; | 260 | GNUNET_i2s (peer), old); |
195 | old->ats_count = 0; | 261 | GNUNET_free_non_null (old->ats); |
196 | old->ats = aa->ats; | 262 | old->session_id = session_id; |
197 | old->ats_count = aa->ats_count; | 263 | old->ats = NULL; |
198 | GNUNET_free (aa->plugin); | 264 | old->ats_count = 0; |
199 | GNUNET_free (aa); | 265 | old->ats = aa->ats; |
266 | old->ats_count = aa->ats_count; | ||
267 | GNUNET_free (aa->plugin); | ||
268 | GNUNET_free (aa); | ||
269 | } | ||
270 | for (i=0;i<atsi_count;i++) | ||
271 | switch (atsi[i].type) | ||
272 | { | ||
273 | case GNUNET_ATS_UTILIZATION_UP: | ||
274 | old->atsp_utilization_out.value__ = atsi[i].value; | ||
275 | break; | ||
276 | case GNUNET_ATS_UTILIZATION_DOWN: | ||
277 | old->atsp_utilization_in.value__ = atsi[i].value; | ||
278 | break; | ||
279 | case GNUNET_ATS_QUALITY_NET_DELAY: | ||
280 | old->atsp_latency.rel_value = ntohl (atsi[i].value); | ||
281 | break; | ||
282 | case GNUNET_ATS_QUALITY_NET_DISTANCE: | ||
283 | old->atsp_distance = ntohl (atsi[i].value); | ||
284 | break; | ||
285 | case GNUNET_ATS_COST_WAN: | ||
286 | old->atsp_cost_wan = ntohl (atsi[i].value); | ||
287 | break; | ||
288 | case GNUNET_ATS_COST_LAN: | ||
289 | old->atsp_cost_lan = ntohl (atsi[i].value); | ||
290 | break; | ||
291 | case GNUNET_ATS_COST_WLAN: | ||
292 | old->atsp_cost_wlan = ntohl (atsi[i].value); | ||
293 | break; | ||
294 | default: | ||
295 | GNUNET_break (0); | ||
296 | break; | ||
297 | } | ||
200 | } | 298 | } |
201 | 299 | ||
202 | 300 | ||
@@ -206,7 +304,6 @@ GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer, | |||
206 | const void *plugin_addr, size_t plugin_addr_len, | 304 | const void *plugin_addr, size_t plugin_addr_len, |
207 | uint32_t session_id) | 305 | uint32_t session_id) |
208 | { | 306 | { |
209 | |||
210 | struct ATS_Address aa; | 307 | struct ATS_Address aa; |
211 | struct ATS_Address *res; | 308 | struct ATS_Address *res; |
212 | 309 | ||
@@ -215,7 +312,6 @@ GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer, | |||
215 | aa.addr = plugin_addr; | 312 | aa.addr = plugin_addr; |
216 | aa.plugin = (char*) plugin_name; | 313 | aa.plugin = (char*) plugin_name; |
217 | aa.session_id = session_id; | 314 | aa.session_id = session_id; |
218 | |||
219 | res = find_address (peer, &aa); | 315 | res = find_address (peer, &aa); |
220 | if (res == NULL) | 316 | if (res == NULL) |
221 | { | 317 | { |
@@ -225,10 +321,75 @@ GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer, | |||
225 | GNUNET_i2s (peer)); | 321 | GNUNET_i2s (peer)); |
226 | return; | 322 | return; |
227 | } | 323 | } |
324 | if ( (aa.session_id == session_id) && | ||
325 | (session_id != 0) && | ||
326 | (res->addr_len > 0) ) | ||
327 | { | ||
328 | /* just session died */ | ||
329 | res->session_id = 0; | ||
330 | if (GNUNET_YES == addr->active) | ||
331 | { | ||
332 | active_addr_count--; | ||
333 | ret = GNUNET_YES; | ||
334 | recalculate_assigned_bw (); | ||
335 | } | ||
336 | return; | ||
337 | } | ||
338 | /* destroy address entirely (either was only session or was | ||
339 | not even with a session) */ | ||
228 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 340 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
229 | "Deleting address for peer `%s': `%s'\n", | 341 | "Deleting address for peer `%s': `%s'\n", |
230 | GNUNET_i2s (peer), plugin_name); | 342 | GNUNET_i2s (peer), plugin_name); |
231 | destroy_address (res); | 343 | if (GNUNET_YES == destroy_address (res)) |
344 | recalculate_assigned_bw (); | ||
345 | } | ||
346 | |||
347 | |||
348 | /** | ||
349 | * Find a "good" address to use for a peer. If we already have an existing | ||
350 | * address, we stick to it. Otherwise, we pick by lowest distance and then | ||
351 | * by lowest latency. | ||
352 | * | ||
353 | * @param cls the 'struct ATS_Address**' where we store the result | ||
354 | * @param key unused | ||
355 | * @param value another 'struct ATS_Address*' to consider using | ||
356 | * @return GNUNET_OK (continue to iterate) | ||
357 | */ | ||
358 | static int | ||
359 | find_address_it (void *cls, | ||
360 | const GNUNET_HashCode * key, | ||
361 | void *value) | ||
362 | { | ||
363 | struct ATS_Address **ap = cls; | ||
364 | struct ATS_Address * aa = (struct ATS_Address *) value; | ||
365 | struct ATS_Address * ab = *ap; | ||
366 | |||
367 | if (NULL == ab) | ||
368 | { | ||
369 | *ap = aa; | ||
370 | return GNUNET_OK; | ||
371 | } | ||
372 | if ( (ntohl (ab->assigned_bw_in.value__) == 0) && | ||
373 | (ntohl (aa->assigned_bw_in.value__) > 0) ) | ||
374 | { | ||
375 | /* stick to existing connection */ | ||
376 | *ap = aa; | ||
377 | return GNUNET_OK; | ||
378 | } | ||
379 | if (ab->atsp_distance > aa->atsp_distance) | ||
380 | { | ||
381 | /* user shorter distance */ | ||
382 | *ap = aa; | ||
383 | return GNUNET_OK; | ||
384 | } | ||
385 | if (ab->atsp_latency.rel_value > aa->atsp_latency.rel_value) | ||
386 | { | ||
387 | /* user lower latency */ | ||
388 | *ap = aa; | ||
389 | return GNUNET_OK; | ||
390 | } | ||
391 | /* don't care */ | ||
392 | return GNUNET_OK; | ||
232 | } | 393 | } |
233 | 394 | ||
234 | 395 | ||
@@ -237,7 +398,11 @@ GAS_addresses_request_address (const struct GNUNET_PeerIdentity *peer) | |||
237 | { | 398 | { |
238 | struct ATS_Address * aa; | 399 | struct ATS_Address * aa; |
239 | 400 | ||
240 | aa = GNUNET_CONTAINER_multihashmap_get (addresses, &peer->hashPubKey); | 401 | aa = NULL; |
402 | GNUNET_CONTAINER_multihashmap_get_multiple (addresses, | ||
403 | &peer->hashPubKey, | ||
404 | &find_address_it, | ||
405 | &aa); | ||
241 | if (aa == NULL) | 406 | if (aa == NULL) |
242 | { | 407 | { |
243 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 408 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
@@ -245,25 +410,21 @@ GAS_addresses_request_address (const struct GNUNET_PeerIdentity *peer) | |||
245 | GNUNET_i2s (peer)); | 410 | GNUNET_i2s (peer)); |
246 | return; | 411 | return; |
247 | } | 412 | } |
248 | /* FIXME: ensure that we don't do this multiple times per peer! */ | 413 | if (aa->active == GNUNET_NO) |
249 | if (ntohl (aa->bw_in.value__) == 0) | ||
250 | { | 414 | { |
415 | aa->active = GNUNET_YES; | ||
251 | active_addr_count++; | 416 | active_addr_count++; |
252 | aa->bw_in.value__ = htonl (total_quota_in / active_addr_count); | 417 | recalculate_assigned_bw (); |
253 | aa->bw_out.value__ = htonl (total_quota_out / active_addr_count); | 418 | } |
254 | /* FIXME: update bw assignments for other addresses... */ | 419 | else |
420 | { | ||
421 | /* just to be sure... */ | ||
422 | GAS_scheduling_transmit_address_suggestion (peer, aa->plugin, | ||
423 | aa->addr, aa->addr_len, | ||
424 | aa->session_id, | ||
425 | aa->ats, aa->ats_count, | ||
426 | aa->assigned_bw_out, aa->assigned_bw_in); | ||
255 | } | 427 | } |
256 | GAS_reservations_set_bandwidth (peer, | ||
257 | aa->bw_in); | ||
258 | GAS_scheduling_transmit_address_suggestion (peer, aa->plugin, | ||
259 | aa->addr, aa->addr_len, | ||
260 | aa->session_id, | ||
261 | aa->ats, aa->ats_count, | ||
262 | aa->bw_out, aa->bw_in); | ||
263 | GAS_performance_notify_clients (peer, aa->plugin, | ||
264 | aa->addr, aa->addr_len, | ||
265 | aa->ats, aa->ats_count, | ||
266 | aa->bw_out, aa->bw_in); | ||
267 | } | 428 | } |
268 | 429 | ||
269 | 430 | ||
@@ -326,6 +487,7 @@ GAS_addresses_destroy_all () | |||
326 | if (addresses != NULL) | 487 | if (addresses != NULL) |
327 | GNUNET_CONTAINER_multihashmap_iterate(addresses, | 488 | GNUNET_CONTAINER_multihashmap_iterate(addresses, |
328 | &free_address_it, NULL); | 489 | &free_address_it, NULL); |
490 | GNUNET_assert (active_addr_count == 0); | ||
329 | } | 491 | } |
330 | 492 | ||
331 | 493 | ||