diff options
author | Christian Grothoff <christian@grothoff.org> | 2015-02-08 15:12:14 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2015-02-08 15:12:14 +0000 |
commit | 73189c33eb0e4c065c2dbd31ced703f48efdee6a (patch) | |
tree | d3761ce5f7a4726d8a258ea486e5074b89d7f5bd /src/ats/gnunet-service-ats_preferences.c | |
parent | 1d971bac50ceddcd6ea2ff20525013becc1d6170 (diff) | |
download | gnunet-73189c33eb0e4c065c2dbd31ced703f48efdee6a.tar.gz gnunet-73189c33eb0e4c065c2dbd31ced703f48efdee6a.zip |
cleaning up gnunet-service-ats_preferences.c
Diffstat (limited to 'src/ats/gnunet-service-ats_preferences.c')
-rw-r--r-- | src/ats/gnunet-service-ats_preferences.c | 679 |
1 files changed, 351 insertions, 328 deletions
diff --git a/src/ats/gnunet-service-ats_preferences.c b/src/ats/gnunet-service-ats_preferences.c index e22a583ee..46c2073f4 100644 --- a/src/ats/gnunet-service-ats_preferences.c +++ b/src/ats/gnunet-service-ats_preferences.c | |||
@@ -54,109 +54,92 @@ | |||
54 | 54 | ||
55 | 55 | ||
56 | /** | 56 | /** |
57 | * Relative preferences for a peer | 57 | * Relative preferences for a peer. |
58 | */ | 58 | */ |
59 | struct PeerRelative | 59 | struct PeerRelative |
60 | { | 60 | { |
61 | /** | 61 | /** |
62 | * Relative preference values | 62 | * Array of relative preference values, to be indexed by |
63 | * an `enum GNUNET_ATS_PreferenceKind`. | ||
63 | */ | 64 | */ |
64 | double f_rel[GNUNET_ATS_PreferenceCount]; | 65 | double f_rel[GNUNET_ATS_PreferenceCount]; |
65 | 66 | ||
66 | /** | ||
67 | * Peer identity for which we have these preferences. | ||
68 | */ | ||
69 | struct GNUNET_PeerIdentity id; | ||
70 | }; | 67 | }; |
71 | 68 | ||
72 | 69 | ||
73 | /** | 70 | /** |
74 | * Default values | 71 | * Default values, returned as our preferences if we do not |
72 | * have any preferences expressed for a peer. | ||
75 | */ | 73 | */ |
76 | static struct PeerRelative defvalues; | 74 | static struct PeerRelative defvalues; |
77 | 75 | ||
78 | 76 | ||
79 | /** | 77 | /** |
80 | * Preference client, information we keep track of per client. | 78 | * Preference information per peer and client. |
81 | */ | 79 | */ |
82 | struct PreferenceClient | 80 | struct PreferencePeer |
83 | { | 81 | { |
84 | /** | 82 | /** |
85 | * Previous in DLL | 83 | * Next in DLL of preference entries for the same client. |
86 | */ | ||
87 | struct PreferenceClient *prev; | ||
88 | |||
89 | /** | ||
90 | * Next in DLL | ||
91 | */ | ||
92 | struct PreferenceClient *next; | ||
93 | |||
94 | /** | ||
95 | * Head of peer list | ||
96 | */ | 84 | */ |
97 | struct PreferencePeer *p_head; | 85 | struct PreferencePeer *next; |
98 | 86 | ||
99 | /** | 87 | /** |
100 | * Tail of peer list | 88 | * Previous in DLL of preference entries for the same client. |
101 | */ | 89 | */ |
102 | struct PreferencePeer *p_tail; | 90 | struct PreferencePeer *prev; |
103 | 91 | ||
104 | /** | 92 | /** |
105 | * Client handle | 93 | * Absolute preference values for all preference types |
94 | * as expressed by this client for this peer. | ||
106 | */ | 95 | */ |
107 | struct GNUNET_SERVER_Client *client; | 96 | double f_abs[GNUNET_ATS_PreferenceCount]; |
108 | 97 | ||
109 | /** | 98 | /** |
110 | * Array of sum of absolute preferences for this client | 99 | * Relative preference values for all preference types, |
100 | * normalized in [0..1] based on how the respective | ||
101 | * client scored other peers. | ||
111 | */ | 102 | */ |
112 | double f_abs_sum[GNUNET_ATS_PreferenceCount]; | 103 | double f_rel[GNUNET_ATS_PreferenceCount]; |
113 | 104 | ||
114 | /** | ||
115 | * Array of sum of relative preferences for this client | ||
116 | */ | ||
117 | double f_rel_sum[GNUNET_ATS_PreferenceCount]; | ||
118 | }; | 105 | }; |
119 | 106 | ||
120 | 107 | ||
121 | /** | 108 | /** |
122 | * Preference information per peer and client. | 109 | * Preference client, as in a client that expressed preferences |
110 | * for peers. This is the information we keep track of for each | ||
111 | * such client. | ||
123 | */ | 112 | */ |
124 | struct PreferencePeer | 113 | struct PreferenceClient |
125 | { | 114 | { |
126 | /** | ||
127 | * Next in DLL of preference entries for the same client. | ||
128 | */ | ||
129 | struct PreferencePeer *next; | ||
130 | 115 | ||
131 | /** | 116 | /** |
132 | * Previous in DLL of preference entries for the same client. | 117 | * Next in client list |
133 | */ | 118 | */ |
134 | struct PreferencePeer *prev; | 119 | struct PreferenceClient *next; |
135 | 120 | ||
136 | /** | 121 | /** |
137 | * Client that expressed this preferences. | 122 | * Previous in client peer list |
138 | */ | 123 | */ |
139 | struct PreferenceClient *client; | 124 | struct PreferenceClient *prev; |
140 | 125 | ||
141 | /** | 126 | /** |
142 | * Peer identity for which the preference was expressed. | 127 | * Client handle |
143 | */ | 128 | */ |
144 | struct GNUNET_PeerIdentity id; | 129 | struct GNUNET_SERVER_Client *client; |
145 | 130 | ||
146 | /** | 131 | /** |
147 | * Absolute preference values for all preference types | 132 | * Mapping peer identities to `struct PreferencePeer` entry |
133 | * for the respective peer. | ||
148 | */ | 134 | */ |
149 | double f_abs[GNUNET_ATS_PreferenceCount]; | 135 | struct GNUNET_CONTAINER_MultiPeerMap *peer2pref; |
150 | 136 | ||
151 | /** | 137 | /** |
152 | * Relative preference values for all preference types | 138 | * Array of sums of absolute preferences for all |
139 | * peers as expressed by this client. | ||
153 | */ | 140 | */ |
154 | double f_rel[GNUNET_ATS_PreferenceCount]; | 141 | double f_abs_sum[GNUNET_ATS_PreferenceCount]; |
155 | 142 | ||
156 | /** | ||
157 | * Absolute point of time of next aging process | ||
158 | */ | ||
159 | struct GNUNET_TIME_Absolute next_aging[GNUNET_ATS_PreferenceCount]; | ||
160 | }; | 143 | }; |
161 | 144 | ||
162 | 145 | ||
@@ -184,227 +167,182 @@ static struct GNUNET_SCHEDULER_Task *aging_task; | |||
184 | 167 | ||
185 | 168 | ||
186 | /** | 169 | /** |
187 | * Update a peer | 170 | * Closure for #sum_relative_preferences(). |
188 | * | ||
189 | * @param id peer id | ||
190 | * @param kind the kind | ||
191 | * @param rp the relative peer struct | ||
192 | * @return the new relative preference | ||
193 | */ | 171 | */ |
194 | static void | 172 | struct SumContext |
195 | update_relative_values_for_peer (const struct GNUNET_PeerIdentity *id, | ||
196 | enum GNUNET_ATS_PreferenceKind kind, | ||
197 | struct PeerRelative *rp) | ||
198 | { | 173 | { |
199 | struct PreferenceClient *c_cur; | 174 | /** |
200 | struct PreferencePeer *p_cur; | 175 | * Where to accumulate the result. |
176 | */ | ||
201 | double f_rel_total; | 177 | double f_rel_total; |
202 | double f_rel_sum; | ||
203 | double backup; | ||
204 | unsigned int peer_count; | ||
205 | 178 | ||
206 | f_rel_sum = 0.0; | 179 | /** |
207 | f_rel_total = 0.0; | 180 | * Which kind of preference value are we adding up? |
208 | peer_count = 0; | 181 | */ |
182 | enum GNUNET_ATS_PreferenceKind kind; | ||
183 | }; | ||
209 | 184 | ||
210 | /* For all clients */ | ||
211 | for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next) | ||
212 | { | ||
213 | /* For peer entries with this id */ | ||
214 | for (p_cur = c_cur->p_head; NULL != p_cur; p_cur = p_cur->next) | ||
215 | { | ||
216 | f_rel_sum += p_cur->f_rel[kind]; | ||
217 | if (0 == memcmp (id, &p_cur->id, sizeof(struct GNUNET_PeerIdentity))) | ||
218 | { | ||
219 | peer_count ++; | ||
220 | f_rel_total += p_cur->f_rel[kind]; | ||
221 | } | ||
222 | } | ||
223 | } | ||
224 | 185 | ||
225 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 186 | /** |
226 | "%u clients have a total relative preference for peer `%s' `%s' of %.3f and for %s in total %.3f\n", | 187 | * Add the relative preference for the kind given to the |
227 | peer_count, | 188 | * closure. |
228 | GNUNET_i2s (id), | 189 | * |
229 | GNUNET_ATS_print_preference_type (kind), | 190 | * @param cls the `struct SumContext` with the kind and place |
230 | f_rel_total, | 191 | * to store the result |
231 | GNUNET_ATS_print_preference_type (kind), | 192 | * @param peer ignored |
232 | f_rel_sum); | 193 | * @param value the `struct PreferencePeer` for getting the rel pref. |
194 | * @return #GNUNET_OK | ||
195 | */ | ||
196 | static int | ||
197 | sum_relative_preferences (void *cls, | ||
198 | const struct GNUNET_PeerIdentity *peer, | ||
199 | void *value) | ||
200 | { | ||
201 | struct SumContext *sum_ctx = cls; | ||
202 | struct PreferencePeer *p_cur = value; | ||
233 | 203 | ||
234 | /* Find entry for the peer containing relative values in the hashmap */ | 204 | sum_ctx->f_rel_total += p_cur->f_rel[sum_ctx->kind]; |
235 | if (NULL != rp) | 205 | return GNUNET_OK; |
236 | { | ||
237 | backup = rp->f_rel[kind]; | ||
238 | if (f_rel_sum > 0) | ||
239 | rp->f_rel[kind] = f_rel_total / f_rel_sum; | ||
240 | else | ||
241 | { | ||
242 | /* No client had any preferences for this type and any peer */ | ||
243 | rp->f_rel[kind] = DEFAULT_REL_PREFERENCE; | ||
244 | } | ||
245 | if (backup != rp->f_rel[kind]) | ||
246 | GAS_plugin_notify_preference_changed (&rp->id, kind, | ||
247 | rp->f_rel[kind]); | ||
248 | } | ||
249 | } | 206 | } |
250 | 207 | ||
251 | 208 | ||
252 | /** | 209 | /** |
253 | * Recalculate preference for a specific ATS property | 210 | * Update the total releative preference for a peer by summing |
211 | * up the relative preferences all clients have for this peer. | ||
254 | * | 212 | * |
255 | * @param c the preference client | 213 | * @param id peer id of the peer for which we should do the update |
256 | * @param kind the preference kind | 214 | * @param kind the kind of preference value to update |
257 | * @return the result | 215 | * @param rp the relative peer struct where we store the global result |
216 | * @return the new relative preference | ||
258 | */ | 217 | */ |
259 | static void | 218 | static void |
260 | recalculate_relative_preferences (struct PreferenceClient *c, | 219 | update_relative_values_for_peer (const struct GNUNET_PeerIdentity *id, |
261 | enum GNUNET_ATS_PreferenceKind kind) | 220 | enum GNUNET_ATS_PreferenceKind kind) |
262 | { | 221 | { |
263 | struct PreferencePeer *p_cur; | 222 | struct PreferenceClient *c_cur; |
223 | struct SumContext sum_ctx; | ||
224 | struct PeerRelative *rp; | ||
264 | 225 | ||
265 | /* For this client: sum of absolute preference values for this preference */ | 226 | sum_ctx.f_rel_total = 0.0; |
266 | c->f_abs_sum[kind] = 0.0; | 227 | sum_ctx.kind = kind; |
267 | /* For this client: sum of relative preference values for this preference | 228 | for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next) |
268 | * | 229 | GNUNET_CONTAINER_multipeermap_get_multiple (c_cur->peer2pref, |
269 | * Note: this value should also be 1.0, but: | 230 | id, |
270 | * if no preferences exist due to aging, this value can be 0.0 | 231 | &sum_relative_preferences, |
271 | * and the client can be removed */ | 232 | &sum_ctx); |
272 | c->f_rel_sum[kind] = 0.0; | ||
273 | |||
274 | for (p_cur = c->p_head; NULL != p_cur; p_cur = p_cur->next) | ||
275 | c->f_abs_sum[kind] += p_cur->f_abs[kind]; | ||
276 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 233 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
277 | "Client %p has sum of total preferences for %s of %.3f\n", | 234 | "Total relative preference for peer `%s' for `%s' is %.3f\n", |
278 | c->client, | 235 | GNUNET_i2s (id), |
279 | GNUNET_ATS_print_preference_type (kind), | 236 | GNUNET_ATS_print_preference_type (kind), |
280 | c->f_abs_sum[kind]); | 237 | sum_ctx.f_rel_total); |
281 | 238 | rp = GNUNET_CONTAINER_multipeermap_get (preference_peers, | |
282 | /* For all peers: calculate relative preference */ | 239 | id); |
283 | for (p_cur = c->p_head; NULL != p_cur; p_cur = p_cur->next) | 240 | GNUNET_assert (NULL != rp); |
241 | if (rp->f_rel[kind] != sum_ctx.f_rel_total) | ||
284 | { | 242 | { |
285 | /* Calculate relative preference for specific kind */ | 243 | rp->f_rel[kind] = sum_ctx.f_rel_total; |
286 | 244 | GAS_plugin_notify_preference_changed (id, | |
287 | /* Every application has a preference for each peer between | 245 | kind, |
288 | * [0 .. 1] in relative values | 246 | rp->f_rel[kind]); |
289 | * and [0 .. inf] in absolute values */ | ||
290 | p_cur->f_rel[kind] = p_cur->f_abs[kind] / c->f_abs_sum[kind]; | ||
291 | c->f_rel_sum[kind] += p_cur->f_rel[kind]; | ||
292 | |||
293 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
294 | "Client %p has relative preference for %s for peer `%s' of %.3f\n", | ||
295 | c->client, | ||
296 | GNUNET_ATS_print_preference_type (kind), | ||
297 | GNUNET_i2s (&p_cur->id), | ||
298 | p_cur->f_rel[kind]); | ||
299 | } | 247 | } |
300 | } | 248 | } |
301 | 249 | ||
302 | 250 | ||
303 | /** | 251 | /** |
304 | * FIXME | 252 | * Closure for #age_values(). |
305 | */ | 253 | */ |
306 | static int | 254 | struct AgeContext |
307 | update_iterator (void *cls, | ||
308 | const struct GNUNET_PeerIdentity *key, | ||
309 | void *value) | ||
310 | { | 255 | { |
311 | enum GNUNET_ATS_PreferenceKind *kind = cls; | 256 | /** |
312 | struct PeerRelative *pr = value; | 257 | * Counter of values remaining to update, incremented for each value |
258 | * changed (to a new non-zero value). | ||
259 | */ | ||
260 | unsigned int values_to_update; | ||
313 | 261 | ||
314 | update_relative_values_for_peer (key, | 262 | /** |
315 | *kind, | 263 | * Client we are currently aging values for. |
316 | pr); | 264 | */ |
317 | return GNUNET_OK; | 265 | struct PreferenceClient *cur_client; |
318 | } | 266 | |
267 | }; | ||
319 | 268 | ||
320 | 269 | ||
321 | /** | 270 | /** |
322 | * FIXME. | 271 | * Age preference values of the given peer. |
323 | * | 272 | * |
273 | * @param cls a ` | ||
274 | * @param peer peer being aged | ||
275 | * @param value the `struct PreferencePeer` for the peer | ||
276 | * @return #GNUNET_OK (continue to iterate) | ||
324 | */ | 277 | */ |
325 | static void | 278 | static int |
326 | run_preference_update (struct PreferenceClient *c_cur, | 279 | age_values (void *cls, |
327 | struct PreferencePeer *p_cur, | 280 | const struct GNUNET_PeerIdentity *peer, |
328 | enum GNUNET_ATS_PreferenceKind kind, | 281 | void *value) |
329 | float score_abs) | ||
330 | { | 282 | { |
331 | double old_value; | 283 | struct AgeContext *ac = cls; |
332 | 284 | struct PreferencePeer *p = value; | |
333 | /* Update relative value */ | 285 | unsigned int i; |
334 | old_value = p_cur->f_rel[kind]; | 286 | int dead; |
335 | recalculate_relative_preferences (c_cur, kind); | ||
336 | if (p_cur->f_rel[kind] == old_value) | ||
337 | return; | ||
338 | 287 | ||
339 | /* Relative preference value changed, recalculate for all peers */ | 288 | dead = GNUNET_YES; |
340 | GNUNET_CONTAINER_multipeermap_iterate (preference_peers, | 289 | for (i = 0; i < GNUNET_ATS_PreferenceCount; i++) |
341 | &update_iterator, | 290 | { |
342 | &kind); | 291 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
292 | "Aging preference for peer `%s'\n", | ||
293 | GNUNET_i2s (peer)); | ||
294 | if (p->f_abs[i] > DEFAULT_ABS_PREFERENCE) | ||
295 | p->f_abs[i] *= PREF_AGING_FACTOR; | ||
296 | if (p->f_abs[i] <= DEFAULT_ABS_PREFERENCE + PREF_EPSILON) | ||
297 | { | ||
298 | p->f_abs[i] = DEFAULT_ABS_PREFERENCE; | ||
299 | p->f_rel[i] = DEFAULT_REL_PREFERENCE; | ||
300 | update_relative_values_for_peer (peer, | ||
301 | i); | ||
302 | } | ||
303 | else | ||
304 | { | ||
305 | ac->values_to_update++; | ||
306 | dead = GNUNET_NO; | ||
307 | } | ||
308 | } | ||
309 | if (GNUNET_YES == dead) | ||
310 | { | ||
311 | /* all preferences are zero, remove this entry */ | ||
312 | GNUNET_CONTAINER_multipeermap_remove (ac->cur_client->peer2pref, | ||
313 | peer, | ||
314 | p); | ||
315 | GNUNET_free (p); | ||
316 | /* FIXME: Consider destroying the `struct PeerRelative` | ||
317 | as well here... */ | ||
318 | } | ||
319 | return GNUNET_OK; | ||
343 | } | 320 | } |
344 | 321 | ||
345 | 322 | ||
346 | /** | 323 | /** |
347 | * Reduce absolute preferences since they got old | 324 | * Reduce absolute preferences since they got old. |
348 | * | 325 | * |
349 | * @param cls the PreferencePeer | 326 | * @param cls unused |
350 | * @param tc context | 327 | * @param tc context |
351 | */ | 328 | */ |
352 | static void | 329 | static void |
353 | preference_aging (void *cls, | 330 | preference_aging (void *cls, |
354 | const struct GNUNET_SCHEDULER_TaskContext *tc) | 331 | const struct GNUNET_SCHEDULER_TaskContext *tc) |
355 | { | 332 | { |
356 | struct PreferencePeer *p; | 333 | struct AgeContext ac; |
357 | struct PreferenceClient *cur_client; | ||
358 | unsigned int i; | ||
359 | unsigned int values_to_update; | ||
360 | double backup; | ||
361 | 334 | ||
362 | aging_task = NULL; | 335 | aging_task = NULL; |
363 | values_to_update = 0; | 336 | ac.values_to_update = 0; |
364 | cur_client = NULL; | 337 | for (ac.cur_client = pc_head; NULL != ac.cur_client; ac.cur_client = ac.cur_client->next) |
365 | 338 | GNUNET_CONTAINER_multipeermap_iterate (ac.cur_client->peer2pref, | |
366 | for (cur_client = pc_head; NULL != cur_client; cur_client = cur_client->next) | 339 | &age_values, |
367 | { | 340 | &ac); |
368 | for (p = cur_client->p_head; NULL != p; p = p->next) | 341 | if (ac.values_to_update > 0) |
369 | { | ||
370 | /* Aging absolute values: */ | ||
371 | for (i = 0; i < GNUNET_ATS_PreferenceCount; i++) | ||
372 | { | ||
373 | if (0 | ||
374 | == GNUNET_TIME_absolute_get_remaining (p->next_aging[i]).rel_value_us) | ||
375 | { | ||
376 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, | ||
377 | "Aging preference for peer `%s'\n", GNUNET_i2s (&p->id)); | ||
378 | backup = p->f_abs[i]; | ||
379 | if (p->f_abs[i] > DEFAULT_ABS_PREFERENCE) | ||
380 | p->f_abs[i] *= PREF_AGING_FACTOR; | ||
381 | |||
382 | if (p->f_abs[i] <= DEFAULT_ABS_PREFERENCE + PREF_EPSILON) | ||
383 | p->f_abs[i] = DEFAULT_ABS_PREFERENCE; | ||
384 | |||
385 | if ( (p->f_abs[i] != DEFAULT_ABS_PREFERENCE) && | ||
386 | (backup != p->f_abs[i]) ) | ||
387 | { | ||
388 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, | ||
389 | "Aged preference for peer `%s' from %.3f to %.3f\n", | ||
390 | GNUNET_i2s (&p->id), backup, p->f_abs[i]); | ||
391 | |||
392 | run_preference_update(cur_client, p, i, p->f_abs[i]); | ||
393 | |||
394 | p->next_aging[i] = GNUNET_TIME_absolute_add ( | ||
395 | GNUNET_TIME_absolute_get (), PREF_AGING_INTERVAL); | ||
396 | values_to_update++; | ||
397 | } | ||
398 | } | ||
399 | } | ||
400 | } | ||
401 | } | ||
402 | |||
403 | if (values_to_update > 0) | ||
404 | { | 342 | { |
405 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 343 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
406 | "Rescheduling aging task due to %u elements to age\n", | 344 | "Rescheduling aging task due to %u elements remaining to age\n", |
407 | values_to_update); | 345 | ac.values_to_update); |
408 | aging_task = GNUNET_SCHEDULER_add_delayed (PREF_AGING_INTERVAL, | 346 | aging_task = GNUNET_SCHEDULER_add_delayed (PREF_AGING_INTERVAL, |
409 | &preference_aging, | 347 | &preference_aging, |
410 | NULL); | 348 | NULL); |
@@ -418,41 +356,132 @@ preference_aging (void *cls, | |||
418 | 356 | ||
419 | 357 | ||
420 | /** | 358 | /** |
421 | * Update the absolute preference value for a peer | 359 | * Closure for #update_rel_sum() and #update_abs_sum(). |
422 | * @param c the client | 360 | */ |
423 | * @param p the peer | 361 | struct UpdateContext |
362 | { | ||
363 | /** | ||
364 | * Preference client with the sum of all absolute scores. | ||
365 | */ | ||
366 | struct PreferenceClient *pc; | ||
367 | |||
368 | /** | ||
369 | * Which kind are we updating? | ||
370 | */ | ||
371 | enum GNUNET_ATS_PreferenceKind kind; | ||
372 | |||
373 | }; | ||
374 | |||
375 | |||
376 | /** | ||
377 | * Compute updated absolute score for the client based on the | ||
378 | * current absolute scores for each peer. | ||
379 | * | ||
380 | * @param cls a `struct UpdateContext` | ||
381 | * @param peer peer being updated | ||
382 | * @param value the `struct PreferencePeer` for the peer | ||
383 | * @return #GNUNET_OK (continue to iterate) | ||
384 | */ | ||
385 | static int | ||
386 | update_abs_sum (void *cls, | ||
387 | const struct GNUNET_PeerIdentity *peer, | ||
388 | void *value) | ||
389 | { | ||
390 | struct UpdateContext *uc = cls; | ||
391 | struct PreferencePeer *p_cur = value; | ||
392 | |||
393 | uc->pc->f_abs_sum[uc->kind] += p_cur->f_abs[uc->kind]; | ||
394 | return GNUNET_OK; | ||
395 | } | ||
396 | |||
397 | |||
398 | /** | ||
399 | * Compute updated relative score for each peer based on the | ||
400 | * current absolute score given by this client. | ||
401 | * | ||
402 | * @param cls a `struct UpdateContext` | ||
403 | * @param peer peer being updated | ||
404 | * @param value the `struct PreferencePeer` for the peer (updated) | ||
405 | * @return #GNUNET_OK (continue to iterate) | ||
406 | */ | ||
407 | static int | ||
408 | update_rel_sum (void *cls, | ||
409 | const struct GNUNET_PeerIdentity *peer, | ||
410 | void *value) | ||
411 | { | ||
412 | struct UpdateContext *uc = cls; | ||
413 | struct PreferencePeer *p_cur = value; | ||
414 | |||
415 | p_cur->f_rel[uc->kind] = p_cur->f_abs[uc->kind] / uc->pc->f_abs_sum[uc->kind]; | ||
416 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
417 | "Client has relative preference for %s for peer `%s' of %.3f\n", | ||
418 | GNUNET_ATS_print_preference_type (uc->kind), | ||
419 | GNUNET_i2s (peer), | ||
420 | p_cur->f_rel[uc->kind]); | ||
421 | return GNUNET_OK; | ||
422 | } | ||
423 | |||
424 | |||
425 | /** | ||
426 | * Recalculate preference for a specific ATS property | ||
427 | * | ||
428 | * @param c the preference client | ||
424 | * @param kind the preference kind | 429 | * @param kind the preference kind |
425 | * @param score_abs the absolute value | 430 | * @return the result |
426 | * @return the new relative preference value | ||
427 | */ | 431 | */ |
428 | static void | 432 | static void |
429 | update_abs_preference (struct PreferenceClient *c, | 433 | recalculate_relative_preferences (struct PreferenceClient *c, |
430 | struct PreferencePeer *p, | 434 | enum GNUNET_ATS_PreferenceKind kind) |
431 | enum GNUNET_ATS_PreferenceKind kind, | ||
432 | float score_abs) | ||
433 | { | 435 | { |
434 | double score = score_abs; | 436 | struct UpdateContext uc; |
435 | 437 | ||
436 | /* Update preference value according to type */ | 438 | /* For this client: sum of absolute preference values for this preference */ |
437 | switch (kind) | 439 | uc.kind = kind; |
438 | { | 440 | uc.pc = c; |
439 | case GNUNET_ATS_PREFERENCE_BANDWIDTH: | 441 | c->f_abs_sum[kind] = 0.0; |
440 | case GNUNET_ATS_PREFERENCE_LATENCY: | 442 | |
441 | p->f_abs[kind] = score; | 443 | /* For all peers: calculate sum of absolute preferences */ |
442 | /* p->f_abs[kind] = (p->f_abs[kind] + score) / 2; */ | 444 | GNUNET_CONTAINER_multipeermap_iterate (c->peer2pref, |
443 | p->next_aging[kind] = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), | 445 | &update_abs_sum, |
444 | PREF_AGING_INTERVAL); | 446 | &uc); |
445 | break; | 447 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
446 | case GNUNET_ATS_PREFERENCE_END: | 448 | "Client has sum of total preferences for %s of %.3f\n", |
447 | break; | 449 | GNUNET_ATS_print_preference_type (kind), |
448 | default: | 450 | c->f_abs_sum[kind]); |
449 | break; | 451 | |
450 | } | 452 | /* For all peers: calculate relative preference */ |
453 | GNUNET_CONTAINER_multipeermap_iterate (c->peer2pref, | ||
454 | &update_rel_sum, | ||
455 | &uc); | ||
451 | } | 456 | } |
452 | 457 | ||
453 | 458 | ||
454 | /** | 459 | /** |
455 | * Normalize an updated preference value | 460 | * The relative preferences of one of the clients have |
461 | * changed, update the global preferences for the given | ||
462 | * peer and notify the plugin. | ||
463 | * | ||
464 | * @param value the kind of preference to calculate the | ||
465 | * new global relative preference values for | ||
466 | * @param key the peer to update relative preference values for | ||
467 | * @param value a `struct PeerRelative`, unused | ||
468 | */ | ||
469 | static int | ||
470 | update_iterator (void *cls, | ||
471 | const struct GNUNET_PeerIdentity *key, | ||
472 | void *value) | ||
473 | { | ||
474 | enum GNUNET_ATS_PreferenceKind *kind = cls; | ||
475 | |||
476 | update_relative_values_for_peer (key, | ||
477 | *kind); | ||
478 | return GNUNET_OK; | ||
479 | } | ||
480 | |||
481 | |||
482 | /** | ||
483 | * Update the absolute preference and calculate the | ||
484 | * new relative preference value. | ||
456 | * | 485 | * |
457 | * @param client the client with this preference | 486 | * @param client the client with this preference |
458 | * @param peer the peer to change the preference for | 487 | * @param peer the peer to change the preference for |
@@ -460,28 +489,26 @@ update_abs_preference (struct PreferenceClient *c, | |||
460 | * @param score_abs the normalized score | 489 | * @param score_abs the normalized score |
461 | */ | 490 | */ |
462 | static void | 491 | static void |
463 | normalize_preference (struct GNUNET_SERVER_Client *client, | 492 | update_preference (struct GNUNET_SERVER_Client *client, |
464 | const struct GNUNET_PeerIdentity *peer, | 493 | const struct GNUNET_PeerIdentity *peer, |
465 | enum GNUNET_ATS_PreferenceKind kind, | 494 | enum GNUNET_ATS_PreferenceKind kind, |
466 | float score_abs) | 495 | float score_abs) |
467 | { | 496 | { |
468 | struct PreferenceClient *c_cur; | 497 | struct PreferenceClient *c_cur; |
469 | struct PreferencePeer *p_cur; | 498 | struct PreferencePeer *p_cur; |
470 | struct PeerRelative *r_cur; | 499 | struct PeerRelative *r_cur; |
471 | double old_value; | 500 | unsigned int i; |
472 | int i; | ||
473 | |||
474 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
475 | "Client changes preference for peer `%s' for `%s' to %.2f\n", | ||
476 | GNUNET_i2s (peer), | ||
477 | GNUNET_ATS_print_preference_type (kind), | ||
478 | score_abs); | ||
479 | 501 | ||
480 | if (kind >= GNUNET_ATS_PreferenceCount) | 502 | if (kind >= GNUNET_ATS_PreferenceCount) |
481 | { | 503 | { |
482 | GNUNET_break(0); | 504 | GNUNET_break(0); |
483 | return; | 505 | return; |
484 | } | 506 | } |
507 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
508 | "Client changes preference for peer `%s' for `%s' to %.2f\n", | ||
509 | GNUNET_i2s (peer), | ||
510 | GNUNET_ATS_print_preference_type (kind), | ||
511 | score_abs); | ||
485 | 512 | ||
486 | /* Find preference client */ | 513 | /* Find preference client */ |
487 | for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next) | 514 | for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next) |
@@ -491,78 +518,55 @@ normalize_preference (struct GNUNET_SERVER_Client *client, | |||
491 | if (NULL == c_cur) | 518 | if (NULL == c_cur) |
492 | { | 519 | { |
493 | c_cur = GNUNET_new (struct PreferenceClient); | 520 | c_cur = GNUNET_new (struct PreferenceClient); |
494 | c_cur->client = client; | 521 | c_cur->peer2pref = GNUNET_CONTAINER_multipeermap_create (16, |
522 | GNUNET_NO); | ||
495 | for (i = 0; i < GNUNET_ATS_PreferenceCount; i++) | 523 | for (i = 0; i < GNUNET_ATS_PreferenceCount; i++) |
496 | { | ||
497 | c_cur->f_abs_sum[i] = DEFAULT_ABS_PREFERENCE; | 524 | c_cur->f_abs_sum[i] = DEFAULT_ABS_PREFERENCE; |
498 | c_cur->f_rel_sum[i] = DEFAULT_REL_PREFERENCE; | ||
499 | } | ||
500 | GNUNET_CONTAINER_DLL_insert (pc_head, | 525 | GNUNET_CONTAINER_DLL_insert (pc_head, |
501 | pc_tail, | 526 | pc_tail, |
502 | c_cur); | 527 | c_cur); |
503 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
504 | "Adding new client %p\n", | ||
505 | c_cur); | ||
506 | } | 528 | } |
507 | |||
508 | /* Find entry for peer */ | 529 | /* Find entry for peer */ |
509 | for (p_cur = c_cur->p_head; NULL != p_cur; p_cur = p_cur->next) | 530 | p_cur = GNUNET_CONTAINER_multipeermap_get (c_cur->peer2pref, |
510 | if (0 == memcmp (&p_cur->id, | 531 | peer); |
511 | peer, | ||
512 | sizeof (p_cur->id))) | ||
513 | break; | ||
514 | |||
515 | /* Not found: create new peer entry */ | ||
516 | if (NULL == p_cur) | 532 | if (NULL == p_cur) |
517 | { | 533 | { |
534 | /* Not found: create new peer entry */ | ||
518 | p_cur = GNUNET_new (struct PreferencePeer); | 535 | p_cur = GNUNET_new (struct PreferencePeer); |
519 | p_cur->client = c_cur; | ||
520 | p_cur->id = *peer; | ||
521 | for (i = 0; i < GNUNET_ATS_PreferenceCount; i++) | 536 | for (i = 0; i < GNUNET_ATS_PreferenceCount; i++) |
522 | { | 537 | { |
523 | /* Default value per peer absolute preference for a preference: 0 */ | 538 | /* Default value per peer absolute preference for a preference*/ |
524 | p_cur->f_abs[i] = DEFAULT_ABS_PREFERENCE; | 539 | p_cur->f_abs[i] = DEFAULT_ABS_PREFERENCE; |
525 | /* Default value per peer relative preference for a quality: 1.0 */ | 540 | /* Default value per peer relative preference for a quality */ |
526 | p_cur->f_rel[i] = DEFAULT_REL_PREFERENCE; | 541 | p_cur->f_rel[i] = DEFAULT_REL_PREFERENCE; |
527 | p_cur->next_aging[i] = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
528 | } | 542 | } |
529 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 543 | GNUNET_assert (GNUNET_YES == |
530 | "Adding new peer %p for client %p\n", | 544 | GNUNET_CONTAINER_multipeermap_put (c_cur->peer2pref, |
531 | p_cur, | 545 | peer, |
532 | c_cur); | 546 | p_cur, |
533 | GNUNET_CONTAINER_DLL_insert (c_cur->p_head, | 547 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); |
534 | c_cur->p_tail, | ||
535 | p_cur); | ||
536 | } | 548 | } |
537 | 549 | ||
538 | /* Create struct for peer */ | ||
539 | if (NULL == | 550 | if (NULL == |
540 | GNUNET_CONTAINER_multipeermap_get (preference_peers, | 551 | GNUNET_CONTAINER_multipeermap_get (preference_peers, |
541 | peer)) | 552 | peer)) |
542 | { | 553 | { |
554 | /* Create struct for peer */ | ||
543 | r_cur = GNUNET_new (struct PeerRelative); | 555 | r_cur = GNUNET_new (struct PeerRelative); |
544 | r_cur->id = *peer; | ||
545 | for (i = 0; i < GNUNET_ATS_PreferenceCount; i++) | 556 | for (i = 0; i < GNUNET_ATS_PreferenceCount; i++) |
546 | r_cur->f_rel[i] = DEFAULT_REL_PREFERENCE; | 557 | r_cur->f_rel[i] = DEFAULT_REL_PREFERENCE; |
547 | GNUNET_assert (GNUNET_OK == | 558 | GNUNET_assert (GNUNET_OK == |
548 | GNUNET_CONTAINER_multipeermap_put (preference_peers, | 559 | GNUNET_CONTAINER_multipeermap_put (preference_peers, |
549 | &r_cur->id, | 560 | peer, |
550 | r_cur, | 561 | r_cur, |
551 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | 562 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); |
552 | } | 563 | } |
553 | 564 | ||
554 | /* Update absolute value */ | 565 | p_cur->f_abs[kind] += score_abs; |
555 | old_value = p_cur->f_abs[kind]; | 566 | recalculate_relative_preferences (c_cur, kind); |
556 | update_abs_preference (c_cur, p_cur, kind, score_abs); | 567 | GNUNET_CONTAINER_multipeermap_iterate (preference_peers, |
557 | if (p_cur->f_abs[kind] == old_value) | 568 | &update_iterator, |
558 | return; | 569 | &kind); |
559 | |||
560 | GAS_plugin_solver_lock (); | ||
561 | run_preference_update (c_cur, | ||
562 | p_cur, | ||
563 | kind, | ||
564 | score_abs); | ||
565 | GAS_plugin_solver_unlock (); | ||
566 | 570 | ||
567 | if (NULL == aging_task) | 571 | if (NULL == aging_task) |
568 | aging_task = GNUNET_SCHEDULER_add_delayed (PREF_AGING_INTERVAL, | 572 | aging_task = GNUNET_SCHEDULER_add_delayed (PREF_AGING_INTERVAL, |
@@ -593,7 +597,8 @@ GAS_handle_preference_change (void *cls, | |||
593 | if (msize < sizeof (struct ChangePreferenceMessage)) | 597 | if (msize < sizeof (struct ChangePreferenceMessage)) |
594 | { | 598 | { |
595 | GNUNET_break (0); | 599 | GNUNET_break (0); |
596 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | 600 | GNUNET_SERVER_receive_done (client, |
601 | GNUNET_SYSERR); | ||
597 | return; | 602 | return; |
598 | } | 603 | } |
599 | msg = (const struct ChangePreferenceMessage *) message; | 604 | msg = (const struct ChangePreferenceMessage *) message; |
@@ -604,7 +609,8 @@ GAS_handle_preference_change (void *cls, | |||
604 | (UINT16_MAX / sizeof (struct PreferenceInformation) < nump) ) | 609 | (UINT16_MAX / sizeof (struct PreferenceInformation) < nump) ) |
605 | { | 610 | { |
606 | GNUNET_break (0); | 611 | GNUNET_break (0); |
607 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | 612 | GNUNET_SERVER_receive_done (client, |
613 | GNUNET_SYSERR); | ||
608 | return; | 614 | return; |
609 | } | 615 | } |
610 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 616 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
@@ -612,15 +618,18 @@ GAS_handle_preference_change (void *cls, | |||
612 | GNUNET_i2s (&msg->peer)); | 618 | GNUNET_i2s (&msg->peer)); |
613 | GNUNET_STATISTICS_update (GSA_stats, | 619 | GNUNET_STATISTICS_update (GSA_stats, |
614 | "# preference change requests processed", | 620 | "# preference change requests processed", |
615 | 1, GNUNET_NO); | 621 | 1, |
622 | GNUNET_NO); | ||
616 | pi = (const struct PreferenceInformation *) &msg[1]; | 623 | pi = (const struct PreferenceInformation *) &msg[1]; |
624 | GAS_plugin_solver_lock (); | ||
617 | for (i = 0; i < nump; i++) | 625 | for (i = 0; i < nump; i++) |
618 | normalize_preference (client, | 626 | update_preference (client, |
619 | &msg->peer, | 627 | &msg->peer, |
620 | (enum GNUNET_ATS_PreferenceKind) | 628 | (enum GNUNET_ATS_PreferenceKind) ntohl (pi[i].preference_kind), |
621 | ntohl (pi[i].preference_kind), | 629 | pi[i].preference_value); |
622 | pi[i].preference_value); | 630 | GAS_plugin_solver_unlock (); |
623 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | 631 | GNUNET_SERVER_receive_done (client, |
632 | GNUNET_OK); | ||
624 | } | 633 | } |
625 | 634 | ||
626 | 635 | ||
@@ -663,22 +672,28 @@ free_peer (void *cls, | |||
663 | } | 672 | } |
664 | 673 | ||
665 | 674 | ||
666 | static void | 675 | /** |
667 | free_client (struct PreferenceClient *pc) | 676 | * Free `struct PreferencePeer` entry in map. |
677 | * | ||
678 | * @param cls the `struct PreferenceClient` with the map | ||
679 | * @param key the peer the entry is for | ||
680 | * @param value the `struct PreferencePeer` entry to free | ||
681 | * @return #GNUNET_OK (continue to iterate) | ||
682 | */ | ||
683 | static int | ||
684 | free_preference (void *cls, | ||
685 | const struct GNUNET_PeerIdentity *key, | ||
686 | void *value) | ||
668 | { | 687 | { |
669 | struct PreferencePeer *next_p; | 688 | struct PreferenceClient *pc = cls; |
670 | struct PreferencePeer *p; | 689 | struct PreferencePeer *p = value; |
671 | 690 | ||
672 | next_p = pc->p_head; | 691 | GNUNET_assert (GNUNET_OK == |
673 | while (NULL != (p = next_p)) | 692 | GNUNET_CONTAINER_multipeermap_remove (pc->peer2pref, |
674 | { | 693 | key, |
675 | next_p = p->next; | 694 | p)); |
676 | GNUNET_CONTAINER_DLL_remove (pc->p_head, | 695 | GNUNET_free (p); |
677 | pc->p_tail, | 696 | return GNUNET_OK; |
678 | p); | ||
679 | GNUNET_free (p); | ||
680 | } | ||
681 | GNUNET_free (pc); | ||
682 | } | 697 | } |
683 | 698 | ||
684 | 699 | ||
@@ -703,7 +718,11 @@ GAS_preference_done () | |||
703 | GNUNET_CONTAINER_DLL_remove (pc_head, | 718 | GNUNET_CONTAINER_DLL_remove (pc_head, |
704 | pc_tail, | 719 | pc_tail, |
705 | pc); | 720 | pc); |
706 | free_client (pc); | 721 | GNUNET_CONTAINER_multipeermap_iterate (pc->peer2pref, |
722 | &free_preference, | ||
723 | pc); | ||
724 | GNUNET_CONTAINER_multipeermap_destroy (pc->peer2pref); | ||
725 | GNUNET_free (pc); | ||
707 | } | 726 | } |
708 | GNUNET_CONTAINER_multipeermap_iterate (preference_peers, | 727 | GNUNET_CONTAINER_multipeermap_iterate (preference_peers, |
709 | &free_peer, | 728 | &free_peer, |
@@ -756,7 +775,11 @@ GAS_preference_client_disconnect (struct GNUNET_SERVER_Client *client) | |||
756 | GNUNET_CONTAINER_DLL_remove (pc_head, | 775 | GNUNET_CONTAINER_DLL_remove (pc_head, |
757 | pc_tail, | 776 | pc_tail, |
758 | c_cur); | 777 | c_cur); |
759 | free_client (c_cur); | 778 | GNUNET_CONTAINER_multipeermap_iterate (c_cur->peer2pref, |
779 | &free_preference, | ||
780 | c_cur); | ||
781 | GNUNET_CONTAINER_multipeermap_destroy (c_cur->peer2pref); | ||
782 | GNUNET_free (c_cur); | ||
760 | } | 783 | } |
761 | 784 | ||
762 | 785 | ||