aboutsummaryrefslogtreecommitdiff
path: root/src/ats/gnunet-service-ats_preferences.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-02-08 15:12:14 +0000
committerChristian Grothoff <christian@grothoff.org>2015-02-08 15:12:14 +0000
commit73189c33eb0e4c065c2dbd31ced703f48efdee6a (patch)
treed3761ce5f7a4726d8a258ea486e5074b89d7f5bd /src/ats/gnunet-service-ats_preferences.c
parent1d971bac50ceddcd6ea2ff20525013becc1d6170 (diff)
downloadgnunet-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.c679
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 */
59struct PeerRelative 59struct 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 */
76static struct PeerRelative defvalues; 74static 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 */
82struct PreferenceClient 80struct 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 */
124struct PreferencePeer 113struct 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 */
194static void 172struct SumContext
195update_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 */
196static int
197sum_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 */
259static void 218static void
260recalculate_relative_preferences (struct PreferenceClient *c, 219update_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 */
306static int 254struct AgeContext
307update_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 */
325static void 278static int
326run_preference_update (struct PreferenceClient *c_cur, 279age_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 */
352static void 329static void
353preference_aging (void *cls, 330preference_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 361struct 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 */
385static int
386update_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 */
407static int
408update_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 */
428static void 432static void
429update_abs_preference (struct PreferenceClient *c, 433recalculate_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 */
469static int
470update_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 */
462static void 491static void
463normalize_preference (struct GNUNET_SERVER_Client *client, 492update_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
666static void 675/**
667free_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 */
683static int
684free_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