aboutsummaryrefslogtreecommitdiff
path: root/src/ats/gnunet-service-ats_preferences.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-02-05 12:52:20 +0000
committerChristian Grothoff <christian@grothoff.org>2015-02-05 12:52:20 +0000
commitc55971f17dc99f9833af48e078c8f681be771cb7 (patch)
tree544fd671b67903506419c98d463d086a696e25a1 /src/ats/gnunet-service-ats_preferences.c
parent15dd8e6cc1199d611d804853e134882bf13b234a (diff)
downloadgnunet-c55971f17dc99f9833af48e078c8f681be771cb7.tar.gz
gnunet-c55971f17dc99f9833af48e078c8f681be771cb7.zip
big ATS refactoring, no serious semantic changes should stem from this
Diffstat (limited to 'src/ats/gnunet-service-ats_preferences.c')
-rw-r--r--src/ats/gnunet-service-ats_preferences.c1004
1 files changed, 1004 insertions, 0 deletions
diff --git a/src/ats/gnunet-service-ats_preferences.c b/src/ats/gnunet-service-ats_preferences.c
new file mode 100644
index 000000000..cf0082f9d
--- /dev/null
+++ b/src/ats/gnunet-service-ats_preferences.c
@@ -0,0 +1,1004 @@
1/*
2 This file is part of GNUnet.
3 (C) 2011-2015 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 ats/gnunet-service-ats_performance.c
23 * @brief ats service, interaction with 'performance' API
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet-service-ats.h"
29#include "gnunet-service-ats_addresses.h"
30#include "gnunet-service-ats_performance.h"
31#include "gnunet-service-ats_plugins.h"
32#include "gnunet-service-ats_preferences.h"
33#include "gnunet-service-ats_reservations.h"
34#include "ats.h"
35
36#define LOG(kind,...) GNUNET_log_from (kind, "ats-preferencesx",__VA_ARGS__)
37
38#define PREF_AGING_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
39#define PREF_AGING_FACTOR 0.95
40#define PREF_EPSILON 0.01
41
42
43/**
44 * Relative preferences for a peer
45 */
46struct PeerRelative
47{
48 /**
49 * Relative preference values
50 */
51 double f_rel[GNUNET_ATS_PreferenceCount];
52
53 /**
54 * Peer id
55 */
56 struct GNUNET_PeerIdentity id;
57};
58
59
60/**
61 * FIXME
62 */
63struct GAS_Addresses_Preference_Clients
64{
65 /**
66 * Next in DLL
67 */
68 struct GAS_Addresses_Preference_Clients *next;
69
70 /**
71 * Previous in DLL
72 */
73 struct GAS_Addresses_Preference_Clients *prev;
74
75 /**
76 * Peer ID
77 */
78 void *client;
79};
80
81
82/**
83 * Preference requests DLL head
84 */
85static struct GAS_Addresses_Preference_Clients *preference_clients_head;
86
87/**
88 * Preference requests DLL head
89 */
90static struct GAS_Addresses_Preference_Clients *preference_clients_tail;
91
92/**
93 * Preferences clients
94 */
95static int pref_clients;
96
97/**
98 * Default values
99 */
100static struct PeerRelative defvalues;
101
102
103
104/**
105 * Preference client
106 */
107struct PreferenceClient
108{
109 /**
110 * Next in DLL
111 */
112 struct PreferenceClient *prev;
113
114 /**
115 * Next in DLL
116 */
117
118 struct PreferenceClient *next;
119
120 /**
121 * Client handle
122 */
123 void *client;
124
125 /**
126 * Array of sum of absolute preferences for this client
127 */
128 double f_abs_sum[GNUNET_ATS_PreferenceCount];
129
130 /**
131 * Array of sum of relative preferences for this client
132 */
133 double f_rel_sum[GNUNET_ATS_PreferenceCount];
134
135 /**
136 * List of peer preferences for this client
137 */
138
139 /**
140 * Head of peer list
141 */
142 struct PreferencePeer *p_head;
143
144 /**
145 * Tail of peer list
146 */
147 struct PreferencePeer *p_tail;
148};
149
150/**
151 * Preference peer
152 */
153struct PreferencePeer
154{
155 /**
156 * Next in DLL
157 */
158 struct PreferencePeer *next;
159
160 /**
161 * Previous in DLL
162 */
163 struct PreferencePeer *prev;
164
165 /**
166 * Client
167 */
168 struct PreferenceClient *client;
169
170 /**
171 * Peer id
172 */
173 struct GNUNET_PeerIdentity id;
174
175 /**
176 * Absolute preference values for all preference types
177 */
178 double f_abs[GNUNET_ATS_PreferenceCount];
179
180 /**
181 * Relative preference values for all preference types
182 */
183 double f_rel[GNUNET_ATS_PreferenceCount];
184
185 /**
186 * Absolute point of time of next aging process
187 */
188 struct GNUNET_TIME_Absolute next_aging[GNUNET_ATS_PreferenceCount];
189};
190
191
192/**
193 * Hashmap to store peer information for preference normalization
194 */
195static struct GNUNET_CONTAINER_MultiPeerMap *preference_peers;
196
197
198/**
199 * Clients in DLL: head
200 */
201static struct PreferenceClient *pc_head;
202
203/**
204 * Clients in DLL: tail
205 */
206static struct PreferenceClient *pc_tail;
207
208
209
210static struct GNUNET_SCHEDULER_Task * aging_task;
211
212
213
214
215static struct GAS_Addresses_Preference_Clients *
216find_preference_client (void *client)
217{
218 struct GAS_Addresses_Preference_Clients *cur;
219
220 for (cur = preference_clients_head; NULL != cur; cur = cur->next)
221 if (cur->client == client)
222 return cur;
223 return NULL;
224}
225
226
227/**
228 * Update a peer
229 *
230 * @param id peer id
231 * @param kind the kind
232 * @param rp the relative peer struct
233 * @return the new relative preference
234 */
235static void
236update_relative_values_for_peer (const struct GNUNET_PeerIdentity *id,
237 enum GNUNET_ATS_PreferenceKind kind,
238 struct PeerRelative *rp)
239{
240 struct PreferenceClient *c_cur;
241 struct PreferencePeer *p_cur;
242 double f_rel_total;
243 double f_rel_sum;
244 double backup;
245 unsigned int peer_count;
246
247 f_rel_sum = 0.0;
248 f_rel_total = 0.0;
249 peer_count = 0;
250
251 /* For all clients */
252 for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
253 {
254 /* For peer entries with this id */
255 for (p_cur = c_cur->p_head; NULL != p_cur; p_cur = p_cur->next)
256 {
257 f_rel_sum += p_cur->f_rel[kind];
258 if (0 == memcmp (id, &p_cur->id, sizeof(struct GNUNET_PeerIdentity)))
259 {
260 peer_count ++;
261 f_rel_total += p_cur->f_rel[kind];
262 }
263
264 }
265 }
266
267 LOG (GNUNET_ERROR_TYPE_DEBUG,
268 "%u clients have a total relative preference for peer `%s' `%s' of %.3f and for %s in total %.3f\n",
269 peer_count, GNUNET_i2s (id),
270 GNUNET_ATS_print_preference_type (kind),
271 f_rel_total,
272 GNUNET_ATS_print_preference_type (kind),
273 f_rel_sum);
274
275 /* Find entry for the peer containing relative values in the hashmap */
276 if (NULL != rp)
277 {
278 backup = rp->f_rel[kind];
279 if (f_rel_sum > 0)
280 rp->f_rel[kind] = f_rel_total / f_rel_sum;
281 else
282 {
283 /* No client had any preferences for this type and any peer */
284 rp->f_rel[kind] = DEFAULT_REL_PREFERENCE;
285 }
286 if (backup != rp->f_rel[kind])
287 GAS_normalized_preference_changed (&rp->id, kind, rp->f_rel[kind]);
288 }
289}
290
291
292static int
293update_iterator (void *cls,
294 const struct GNUNET_PeerIdentity *key,
295 void *value)
296{
297 enum GNUNET_ATS_PreferenceKind *kind = cls;
298 struct PeerRelative *pr = value;
299
300 update_relative_values_for_peer (key,
301 *kind,
302 pr);
303 return GNUNET_OK;
304}
305
306
307
308/**
309 * Recalculate preference for a specific ATS property
310 *
311 * @param c the preference client
312 * @param kind the preference kind
313 * @return the result
314 */
315static void
316recalculate_relative_preferences (struct PreferenceClient *c,
317 enum GNUNET_ATS_PreferenceKind kind)
318{
319 struct PreferencePeer *p_cur;
320
321 /* For this client: sum of absolute preference values for this preference */
322 c->f_abs_sum[kind] = 0.0;
323 /* For this client: sum of relative preference values for this preference
324 *
325 * Note: this value should also be 1.0, but:
326 * if no preferences exist due to aging, this value can be 0.0
327 * and the client can be removed */
328 c->f_rel_sum[kind] = 0.0;
329
330 for (p_cur = c->p_head; NULL != p_cur; p_cur = p_cur->next)
331 c->f_abs_sum[kind] += p_cur->f_abs[kind];
332 LOG (GNUNET_ERROR_TYPE_DEBUG,
333 "Client %p has sum of total preferences for %s of %.3f\n",
334 c->client, GNUNET_ATS_print_preference_type (kind), c->f_abs_sum[kind]);
335
336 /* For all peers: calculate relative preference */
337 for (p_cur = c->p_head; NULL != p_cur; p_cur = p_cur->next)
338 {
339 /* Calculate relative preference for specific kind */
340
341 /* Every application has a preference for each peer between
342 * [0 .. 1] in relative values
343 * and [0 .. inf] in absolute values */
344 p_cur->f_rel[kind] = p_cur->f_abs[kind] / c->f_abs_sum[kind];
345 c->f_rel_sum[kind] += p_cur->f_rel[kind];
346
347 LOG (GNUNET_ERROR_TYPE_DEBUG,
348 "Client %p has relative preference for %s for peer `%s' of %.3f\n",
349 c->client,
350 GNUNET_ATS_print_preference_type (kind),
351 GNUNET_i2s (&p_cur->id),
352 p_cur->f_rel[kind]);
353 }
354
355}
356
357
358
359static void
360run_preference_update (struct PreferenceClient *c_cur,
361 struct PreferencePeer *p_cur,
362 enum GNUNET_ATS_PreferenceKind kind,
363 float score_abs)
364{
365 double old_value;
366
367 /* Update relative value */
368 old_value = p_cur->f_rel[kind];
369 recalculate_relative_preferences (c_cur, kind);
370 if (p_cur->f_rel[kind] == old_value)
371 return;
372
373 /* Relative preference value changed, recalculate for all peers */
374 GNUNET_CONTAINER_multipeermap_iterate (preference_peers,
375 &update_iterator,
376 &kind);
377}
378
379
380
381
382/**
383 * Reduce absolute preferences since they got old
384 *
385 * @param cls the PreferencePeer
386 * @param tc context
387 */
388static void
389preference_aging (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
390{
391 struct PreferencePeer *p;
392 struct PreferenceClient *cur_client;
393 int i;
394 int values_to_update;
395 double backup;
396
397 aging_task = NULL;
398 values_to_update = 0;
399 cur_client = NULL;
400
401 for (cur_client = pc_head; NULL != cur_client; cur_client = cur_client->next)
402 {
403 for (p = cur_client->p_head; NULL != p; p = p->next)
404 {
405 /* Aging absolute values: */
406 for (i = 0; i < GNUNET_ATS_PreferenceCount; i++)
407 {
408 if (0
409 == GNUNET_TIME_absolute_get_remaining (p->next_aging[i]).rel_value_us)
410 {
411 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
412 "Aging preference for peer `%s'\n", GNUNET_i2s (&p->id));
413 backup = p->f_abs[i];
414 if (p->f_abs[i] > DEFAULT_ABS_PREFERENCE)
415 p->f_abs[i] *= PREF_AGING_FACTOR;
416
417 if (p->f_abs[i] <= DEFAULT_ABS_PREFERENCE + PREF_EPSILON)
418 p->f_abs[i] = DEFAULT_ABS_PREFERENCE;
419
420 if ( (p->f_abs[i] != DEFAULT_ABS_PREFERENCE) &&
421 (backup != p->f_abs[i]) )
422 {
423 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
424 "Aged preference for peer `%s' from %.3f to %.3f\n",
425 GNUNET_i2s (&p->id), backup, p->f_abs[i]);
426
427 run_preference_update(cur_client, p, i, p->f_abs[i]);
428
429 p->next_aging[i] = GNUNET_TIME_absolute_add (
430 GNUNET_TIME_absolute_get (), PREF_AGING_INTERVAL);
431 values_to_update++;
432 }
433 }
434 }
435 }
436 }
437
438 if (values_to_update > 0)
439 {
440 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
441 "Rescheduling aging task due to %u elements to age\n",
442 values_to_update);
443 aging_task = GNUNET_SCHEDULER_add_delayed (PREF_AGING_INTERVAL,
444 &preference_aging, NULL );
445 }
446 else
447 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
448 "No values to age left, not rescheduling aging task\n");
449
450}
451
452
453/**
454 * Update the absolute preference value for a peer
455 * @param c the client
456 * @param p the peer
457 * @param kind the preference kind
458 * @param score_abs the absolute value
459 * @return the new relative preference value
460 */
461static void
462update_abs_preference (struct PreferenceClient *c,
463 struct PreferencePeer *p,
464 enum GNUNET_ATS_PreferenceKind kind,
465 float score_abs)
466{
467 double score = score_abs;
468
469 /* Update preference value according to type */
470 switch (kind)
471 {
472 case GNUNET_ATS_PREFERENCE_BANDWIDTH:
473 case GNUNET_ATS_PREFERENCE_LATENCY:
474 p->f_abs[kind] = score;
475 /* p->f_abs[kind] = (p->f_abs[kind] + score) / 2; */
476 p->next_aging[kind] = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
477 PREF_AGING_INTERVAL);
478 break;
479 case GNUNET_ATS_PREFERENCE_END:
480 break;
481 default:
482 break;
483 }
484}
485
486
487
488
489
490/**
491 * A performance client disconnected
492 *
493 * @param client the client
494 */
495void
496GAS_addresses_preference_client_disconnect (void *client)
497{
498 struct GAS_Addresses_Preference_Clients *pc;
499
500 if (NULL != (pc = find_preference_client (client)))
501 {
502 GNUNET_CONTAINER_DLL_remove (preference_clients_head,
503 preference_clients_tail,
504 pc);
505 GNUNET_free (pc);
506 GNUNET_assert (pref_clients > 0);
507 pref_clients --;
508 GNUNET_STATISTICS_set (GSA_stats,
509 "# active performance clients",
510 pref_clients,
511 GNUNET_NO);
512 }
513}
514
515
516
517/**
518 * Change the preference for a peer
519 *
520 * @param client the client sending this request
521 * @param peer the peer id
522 * @param kind the preference kind to change
523 * @param score_abs the new preference score
524 */
525void
526GAS_addresses_preference_change (void *client,
527 const struct GNUNET_PeerIdentity *peer,
528 enum GNUNET_ATS_PreferenceKind kind,
529 float score_abs)
530{
531 struct GAS_Addresses_Preference_Clients *pc;
532
533 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
534 "Received `%s' for peer `%s' for client %p\n", "CHANGE PREFERENCE",
535 GNUNET_i2s (peer), client);
536
537 if (GNUNET_NO ==
538 GNUNET_CONTAINER_multipeermap_contains (GSA_addresses,
539 peer))
540 {
541 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
542 "Received `%s' for unknown peer `%s' from client %p\n",
543 "CHANGE PREFERENCE", GNUNET_i2s (peer), client);
544 return;
545 }
546
547 if (NULL == find_preference_client (client))
548 {
549 pc = GNUNET_new (struct GAS_Addresses_Preference_Clients);
550 pc->client = client;
551 GNUNET_CONTAINER_DLL_insert (preference_clients_head,
552 preference_clients_tail,
553 pc);
554 pref_clients ++;
555 GNUNET_STATISTICS_set (GSA_stats,
556 "# active performance clients",
557 pref_clients,
558 GNUNET_NO);
559 }
560 GAS_plugin_update_preferences (client, peer, kind, score_abs);
561}
562
563
564/**
565 * Handle 'preference change' messages from clients.
566 *
567 * @param cls unused, NULL
568 * @param client client that sent the request
569 * @param message the request message
570 */
571void
572GAS_handle_preference_change (void *cls,
573 struct GNUNET_SERVER_Client *client,
574 const struct GNUNET_MessageHeader *message)
575{
576 const struct ChangePreferenceMessage *msg;
577 const struct PreferenceInformation *pi;
578 uint16_t msize;
579 uint32_t nump;
580 uint32_t i;
581
582 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
583 "Received `%s' message\n",
584 "PREFERENCE_CHANGE");
585 msize = ntohs (message->size);
586 if (msize < sizeof (struct ChangePreferenceMessage))
587 {
588 GNUNET_break (0);
589 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
590 return;
591 }
592 msg = (const struct ChangePreferenceMessage *) message;
593 nump = ntohl (msg->num_preferences);
594 if (msize !=
595 sizeof (struct ChangePreferenceMessage) +
596 nump * sizeof (struct PreferenceInformation))
597 {
598 GNUNET_break (0);
599 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
600 return;
601 }
602 GNUNET_STATISTICS_update (GSA_stats,
603 "# preference change requests processed",
604 1, GNUNET_NO);
605 pi = (const struct PreferenceInformation *) &msg[1];
606 for (i = 0; i < nump; i++)
607 GAS_addresses_preference_change (client,
608 &msg->peer,
609 (enum GNUNET_ATS_PreferenceKind)
610 ntohl (pi[i].preference_kind),
611 pi[i].preference_value);
612 GNUNET_SERVER_receive_done (client, GNUNET_OK);
613}
614
615
616
617
618/**
619 * Change the preference for a peer
620 *
621 * @param application the client sending this request
622 * @param peer the peer id
623 * @param scope the time interval for this feedback: [now - scope .. now]
624 * @param kind the preference kind to change
625 * @param score_abs the new preference score
626 */
627void
628GAS_addresses_preference_feedback (void *application,
629 const struct GNUNET_PeerIdentity *peer,
630 const struct GNUNET_TIME_Relative scope,
631 enum GNUNET_ATS_PreferenceKind kind,
632 float score_abs)
633{
634 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
635 "Received `%s' for peer `%s' for client %p\n",
636 "PREFERENCE FEEDBACK",
637 GNUNET_i2s (peer),
638 application);
639
640 if (GNUNET_NO ==
641 GNUNET_CONTAINER_multipeermap_contains (GSA_addresses,
642 peer))
643 {
644 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
645 "Received `%s' for unknown peer `%s' from client %p\n",
646 "PREFERENCE FEEDBACK",
647 GNUNET_i2s (peer),
648 application);
649 return;
650 }
651
652 GAS_plugin_preference_feedback (application,
653 peer,
654 scope,
655 kind,
656 score_abs);
657}
658
659
660/**
661 * Handle 'preference feedback' messages from clients.
662 *
663 * @param cls unused, NULL
664 * @param client client that sent the request
665 * @param message the request message
666 */
667void
668GAS_handle_preference_feedback (void *cls,
669 struct GNUNET_SERVER_Client *client,
670 const struct GNUNET_MessageHeader *message)
671{
672 const struct FeedbackPreferenceMessage *msg;
673 const struct PreferenceInformation *pi;
674 uint16_t msize;
675 uint32_t nump;
676 uint32_t i;
677
678 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
679 "Received `%s' message\n",
680 "PREFERENCE_FEEDBACK");
681 msize = ntohs (message->size);
682 if (msize < sizeof (struct FeedbackPreferenceMessage))
683 {
684 GNUNET_break (0);
685 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
686 return;
687 }
688 msg = (const struct FeedbackPreferenceMessage *) message;
689 nump = ntohl (msg->num_feedback);
690 if (msize !=
691 sizeof (struct FeedbackPreferenceMessage) +
692 nump * sizeof (struct PreferenceInformation))
693 {
694 GNUNET_break (0);
695 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
696 return;
697 }
698 GNUNET_STATISTICS_update (GSA_stats,
699 "# preference feedbacks requests processed",
700 1, GNUNET_NO);
701 pi = (const struct PreferenceInformation *) &msg[1];
702 for (i = 0; i < nump; i++)
703 GAS_addresses_preference_feedback (client,
704 &msg->peer,
705 GNUNET_TIME_relative_ntoh(msg->scope),
706 (enum GNUNET_ATS_PreferenceKind)
707 ntohl (pi[i].preference_kind),
708 pi[i].preference_value);
709 GNUNET_SERVER_receive_done (client, GNUNET_OK);
710}
711
712
713/**
714 * Shutdown preferences subsystem.
715 */
716void
717GAS_preference_init ()
718{
719 int i;
720
721 preference_peers = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
722 for (i = 0; i < GNUNET_ATS_PreferenceCount; i++)
723 defvalues.f_rel[i] = DEFAULT_REL_PREFERENCE;
724
725}
726
727
728/**
729 * Free a peer
730 *
731 * @param cls unused
732 * @param key the key
733 * @param value RelativePeer
734 * @return #GNUNET_OK to continue
735 */
736static int
737free_peer (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
738{
739 struct PeerRelative *rp = value;
740 if (GNUNET_YES
741 == GNUNET_CONTAINER_multipeermap_remove (preference_peers, key, value))
742 GNUNET_free(rp);
743 else
744 GNUNET_break(0);
745 return GNUNET_OK;
746}
747
748
749static void
750free_client (struct PreferenceClient *pc)
751{
752 struct PreferencePeer *next_p;
753 struct PreferencePeer *p;
754 next_p = pc->p_head;
755 while (NULL != (p = next_p))
756 {
757 next_p = p->next;
758 GNUNET_CONTAINER_DLL_remove(pc->p_head, pc->p_tail, p);
759 GNUNET_free(p);
760 }
761 GNUNET_free(pc);
762}
763
764
765
766
767
768/**
769 * Shutdown preferences subsystem.
770 */
771void
772GAS_preference_done ()
773{
774 struct GAS_Addresses_Preference_Clients *pcur;
775 struct PreferenceClient *pc;
776 struct PreferenceClient *next_pc;
777
778 if (NULL != aging_task)
779 {
780 GNUNET_SCHEDULER_cancel (aging_task);
781 aging_task = NULL;
782 }
783
784 next_pc = pc_head;
785 while (NULL != (pc = next_pc))
786 {
787 next_pc = pc->next;
788 GNUNET_CONTAINER_DLL_remove(pc_head, pc_tail, pc);
789 free_client (pc);
790 }
791
792 GNUNET_CONTAINER_multipeermap_iterate (preference_peers,
793 &free_peer, NULL);
794 GNUNET_CONTAINER_multipeermap_destroy (preference_peers);
795
796 while (NULL != (pcur = preference_clients_head))
797 {
798 GNUNET_CONTAINER_DLL_remove (preference_clients_head,
799 preference_clients_tail,
800 pcur);
801 GNUNET_assert (pref_clients > 0);
802 pref_clients --;
803 GNUNET_STATISTICS_set (GSA_stats,
804 "# active performance clients",
805 pref_clients,
806 GNUNET_NO);
807 GNUNET_free (pcur);
808 }
809}
810
811
812
813
814/**
815 * Normalize an updated preference value
816 *
817 * @param client the client with this preference
818 * @param peer the peer to change the preference for
819 * @param kind the kind to change the preference
820 * @param score_abs the normalized score
821 */
822void
823GAS_normalization_normalize_preference (void *client,
824 const struct GNUNET_PeerIdentity *peer,
825 enum GNUNET_ATS_PreferenceKind kind,
826 float score_abs)
827{
828 struct PreferenceClient *c_cur;
829 struct PreferencePeer *p_cur;
830 struct PeerRelative *r_cur;
831 double old_value;
832 int i;
833
834 LOG (GNUNET_ERROR_TYPE_DEBUG,
835 "Client changes preference for peer `%s' for `%s' to %.2f\n",
836 GNUNET_i2s (peer),
837 GNUNET_ATS_print_preference_type (kind),
838 score_abs);
839
840 if (kind >= GNUNET_ATS_PreferenceCount)
841 {
842 GNUNET_break(0);
843 return;
844 }
845
846 /* Find preference client */
847 for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
848 {
849 if (client == c_cur->client)
850 break;
851 }
852 /* Not found: create new preference client */
853 if (NULL == c_cur)
854 {
855 c_cur = GNUNET_new (struct PreferenceClient);
856 c_cur->client = client;
857 for (i = 0; i < GNUNET_ATS_PreferenceCount; i++)
858 {
859 c_cur->f_abs_sum[i] = DEFAULT_ABS_PREFERENCE;
860 c_cur->f_rel_sum[i] = DEFAULT_REL_PREFERENCE;
861 }
862
863 GNUNET_CONTAINER_DLL_insert(pc_head, pc_tail, c_cur);
864 LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding new client %p \n", c_cur);
865 }
866
867 /* Find entry for peer */
868 for (p_cur = c_cur->p_head; NULL != p_cur; p_cur = p_cur->next)
869 if (0 == memcmp (&p_cur->id, peer, sizeof(p_cur->id)))
870 break;
871
872 /* Not found: create new peer entry */
873 if (NULL == p_cur)
874 {
875 p_cur = GNUNET_new (struct PreferencePeer);
876 p_cur->client = c_cur;
877 p_cur->id = (*peer);
878 for (i = 0; i < GNUNET_ATS_PreferenceCount; i++)
879 {
880 /* Default value per peer absolute preference for a preference: 0 */
881 p_cur->f_abs[i] = DEFAULT_ABS_PREFERENCE;
882 /* Default value per peer relative preference for a quality: 1.0 */
883 p_cur->f_rel[i] = DEFAULT_REL_PREFERENCE;
884 p_cur->next_aging[i] = GNUNET_TIME_UNIT_FOREVER_ABS;
885 }
886 LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding new peer %p for client %p \n",
887 p_cur, c_cur);
888 GNUNET_CONTAINER_DLL_insert(c_cur->p_head, c_cur->p_tail, p_cur);
889 }
890
891 /* Create struct for peer */
892 if (NULL == GNUNET_CONTAINER_multipeermap_get (preference_peers, peer))
893 {
894 r_cur = GNUNET_new (struct PeerRelative);
895 r_cur->id = (*peer);
896 for (i = 0; i < GNUNET_ATS_PreferenceCount; i++)
897 r_cur->f_rel[i] = DEFAULT_REL_PREFERENCE;
898 GNUNET_assert(
899 GNUNET_OK == GNUNET_CONTAINER_multipeermap_put (preference_peers,
900 &r_cur->id, r_cur, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
901 }
902
903 /* Update absolute value */
904 old_value = p_cur->f_abs[kind];
905 update_abs_preference (c_cur, p_cur, kind, score_abs);
906 if (p_cur->f_abs[kind] == old_value)
907 return;
908
909 run_preference_update (c_cur, p_cur, kind, score_abs);
910
911 /* Start aging task */
912 if (NULL == aging_task)
913 aging_task = GNUNET_SCHEDULER_add_delayed (PREF_AGING_INTERVAL,
914 &preference_aging, NULL );
915
916}
917
918
919/**
920 * Get the normalized preference values for a specific peer or
921 * the default values if
922 *
923 * @param cls ignored
924 * @param id the peer
925 * @return pointer to the values, can be indexed with GNUNET_ATS_PreferenceKind,
926 * default preferences if peer does not exist
927 */
928const double *
929GAS_normalization_get_preferences_by_peer (void *cls,
930 const struct GNUNET_PeerIdentity *id)
931{
932 GNUNET_assert(NULL != preference_peers);
933 GNUNET_assert(NULL != id);
934
935 struct PeerRelative *rp;
936 if (NULL == (rp = GNUNET_CONTAINER_multipeermap_get (preference_peers, id)))
937 {
938 return defvalues.f_rel;
939 }
940 return rp->f_rel;
941}
942
943
944/**
945 * Get the normalized preference values for a specific client and peer
946 *
947 * @param client client
948 * @param peer the peer
949 * @param pref the preference type
950 * @return the value
951 */
952double
953GAS_normalization_get_preferences_by_client (const void *client,
954 const struct GNUNET_PeerIdentity *peer,
955 enum GNUNET_ATS_PreferenceKind pref)
956{
957 struct PreferenceClient *c_cur;
958 struct PreferencePeer *p_cur;
959
960 /* Find preference client */
961 for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
962 {
963 if (client == c_cur->client)
964 break;
965 }
966 if (NULL == c_cur)
967 return -1.0;
968
969 for (p_cur = c_cur->p_head; NULL != p_cur; p_cur = p_cur->next)
970 {
971 if (0 == memcmp (peer, &p_cur->id, sizeof (struct GNUNET_PeerIdentity)))
972 break;
973 }
974 if (NULL == p_cur)
975 return DEFAULT_REL_PREFERENCE; /* Not found, return default */
976
977 return p_cur->f_rel[pref];
978}
979
980
981
982/**
983 * A performance client disconnected
984 *
985 * @param client the client
986 */
987void
988GAS_normalization_preference_client_disconnect (void *client)
989{
990 struct PreferenceClient *c_cur;
991 /* Find preference client */
992
993 for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
994 {
995 if (client == c_cur->client)
996 break;
997 }
998 if (NULL == c_cur)
999 return;
1000
1001 GNUNET_CONTAINER_DLL_remove(pc_head, pc_tail, c_cur);
1002 free_client (c_cur);
1003}
1004