GNUnet  0.19.5
gnunet-service-ats_preferences.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2011-2015 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your 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  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
26 #include "platform.h"
27 #include "gnunet-service-ats.h"
33 #include "ats.h"
34 
35 #define LOG(kind, ...) GNUNET_log_from (kind, "ats-preferences", __VA_ARGS__)
36 
40 #define PREF_AGING_INTERVAL GNUNET_TIME_relative_multiply ( \
41  GNUNET_TIME_UNIT_SECONDS, 10)
42 
47 #define PREF_AGING_FACTOR 0.95
48 
54 #define PREF_EPSILON 0.01
55 
56 
61 {
67 
73  unsigned int num_clients;
74 };
75 
76 
81 static struct PeerRelative defvalues;
82 
83 
88 {
93 
98 
104 
111 };
112 
113 
120 {
125 
130 
135 
141 
147 };
148 
149 
156 
160 static struct PreferenceClient *pc_head;
161 
165 static struct PreferenceClient *pc_tail;
166 
171 
172 
177 {
181  double f_rel_total;
182 
187 };
188 
189 
200 static int
202  const struct GNUNET_PeerIdentity *peer,
203  void *value)
204 {
205  struct SumContext *sum_ctx = cls;
206  struct PreferencePeer *p_cur = value;
207 
208  sum_ctx->f_rel_total += p_cur->f_rel[sum_ctx->kind];
209  return GNUNET_OK;
210 }
211 
212 
221 static void
223  enum GNUNET_ATS_PreferenceKind kind)
224 {
225  struct PreferenceClient *c_cur;
226  struct SumContext sum_ctx;
227  struct PeerRelative *rp;
228 
229  sum_ctx.f_rel_total = 0.0;
230  sum_ctx.kind = kind;
231  for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
233  id,
235  &sum_ctx);
237  "Total relative preference for peer `%s' for `%s' is %.3f\n",
238  GNUNET_i2s (id),
240  sum_ctx.f_rel_total);
242  id);
243  GNUNET_assert (NULL != rp);
244  if (rp->f_rel[kind] != sum_ctx.f_rel_total)
245  {
246  rp->f_rel[kind] = sum_ctx.f_rel_total;
248  kind,
249  rp->f_rel[kind]);
250  }
251 }
252 
253 
262 static int
263 free_peer (void *cls,
264  const struct GNUNET_PeerIdentity *key,
265  void *value)
266 {
267  struct PeerRelative *rp = value;
268 
271  key,
272  value));
273  GNUNET_free (rp);
274  return GNUNET_OK;
275 }
276 
277 
286 static int
287 free_preference (void *cls,
288  const struct GNUNET_PeerIdentity *key,
289  void *value)
290 {
291  struct PreferenceClient *pc = cls;
292  struct PreferencePeer *p = value;
293  struct PeerRelative *pr;
294 
297  key,
298  p));
299  GNUNET_free (p);
301  key);
302  GNUNET_assert (NULL != pr);
303  GNUNET_assert (pr->num_clients > 0);
304  pr->num_clients--;
305  if (0 == pr->num_clients)
306  {
307  free_peer (NULL,
308  key,
309  pr);
310  }
311  return GNUNET_OK;
312 }
313 
314 
319 {
324  unsigned int values_to_update;
325 
330 };
331 
332 
341 static int
342 age_values (void *cls,
343  const struct GNUNET_PeerIdentity *peer,
344  void *value)
345 {
346  struct AgeContext *ac = cls;
347  struct PreferencePeer *p = value;
348  unsigned int i;
349  int dead;
350 
351  dead = GNUNET_YES;
352  for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
353  {
355  "Aging preference for peer `%s'\n",
356  GNUNET_i2s (peer));
357  if (p->f_abs[i] > DEFAULT_ABS_PREFERENCE)
358  p->f_abs[i] *= PREF_AGING_FACTOR;
359  if (p->f_abs[i] <= DEFAULT_ABS_PREFERENCE + PREF_EPSILON)
360  {
361  p->f_abs[i] = DEFAULT_ABS_PREFERENCE;
362  p->f_rel[i] = DEFAULT_REL_PREFERENCE;
364  i);
365  }
366  else
367  {
368  ac->values_to_update++;
369  dead = GNUNET_NO;
370  }
371  }
372  if (GNUNET_YES == dead)
373  {
374  /* all preferences are zero, remove this entry */
375  free_preference (ac->cur_client,
376  peer,
377  p);
378  }
379  return GNUNET_OK;
380 }
381 
382 
388 static void
389 preference_aging (void *cls)
390 {
391  struct AgeContext ac;
392 
393  aging_task = NULL;
395  ac.values_to_update = 0;
396  for (ac.cur_client = pc_head; NULL != ac.cur_client; ac.cur_client =
397  ac.cur_client->next)
398  GNUNET_CONTAINER_multipeermap_iterate (ac.cur_client->peer2pref,
399  &age_values,
400  &ac);
402  if (ac.values_to_update > 0)
403  {
405  "Rescheduling aging task due to %u elements remaining to age\n",
406  ac.values_to_update);
407  if (NULL == aging_task)
410  NULL);
411  }
412  else
413  {
415  "No values to age left, not rescheduling aging task\n");
416  }
417 }
418 
419 
424 {
429 
434 };
435 
436 
446 static int
447 update_abs_sum (void *cls,
448  const struct GNUNET_PeerIdentity *peer,
449  void *value)
450 {
451  struct UpdateContext *uc = cls;
452  struct PreferencePeer *p_cur = value;
453 
454  uc->pc->f_abs_sum[uc->kind] += p_cur->f_abs[uc->kind];
455  return GNUNET_OK;
456 }
457 
458 
468 static int
469 update_rel_sum (void *cls,
470  const struct GNUNET_PeerIdentity *peer,
471  void *value)
472 {
473  struct UpdateContext *uc = cls;
474  struct PreferencePeer *p_cur = value;
475 
476  p_cur->f_rel[uc->kind] = p_cur->f_abs[uc->kind] / uc->pc->f_abs_sum[uc->kind];
478  "Client has relative preference for %s for peer `%s' of %.3f\n",
480  GNUNET_i2s (peer),
481  p_cur->f_rel[uc->kind]);
482  return GNUNET_OK;
483 }
484 
485 
493 static void
495  enum GNUNET_ATS_PreferenceKind kind)
496 {
497  struct UpdateContext uc;
498 
499  /* For this client: sum of absolute preference values for this preference */
500  uc.kind = kind;
501  uc.pc = c;
502  c->f_abs_sum[kind] = 0.0;
503 
504  /* For all peers: calculate sum of absolute preferences */
507  &uc);
509  "Client has sum of total preferences for %s of %.3f\n",
511  c->f_abs_sum[kind]);
512 
513  /* For all peers: calculate relative preference */
516  &uc);
517 }
518 
519 
530 static int
531 update_iterator (void *cls,
532  const struct GNUNET_PeerIdentity *key,
533  void *value)
534 {
535  enum GNUNET_ATS_PreferenceKind *kind = cls;
536 
538  *kind);
539  return GNUNET_OK;
540 }
541 
542 
552 static void
554  const struct GNUNET_PeerIdentity *peer,
556  float score_abs)
557 {
558  struct PreferenceClient *c_cur;
559  struct PreferencePeer *p_cur;
560  struct PeerRelative *r_cur;
561  unsigned int i;
562 
563  if (kind >= GNUNET_ATS_PREFERENCE_END)
564  {
565  GNUNET_break (0);
566  return;
567  }
569  "Client changes preference for peer `%s' for `%s' to %.2f\n",
570  GNUNET_i2s (peer),
572  score_abs);
573 
574  /* Find preference client */
575  for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
576  if (client == c_cur->client)
577  break;
578  /* Not found: create new preference client */
579  if (NULL == c_cur)
580  {
581  c_cur = GNUNET_new (struct PreferenceClient);
582  c_cur->client = client;
584  GNUNET_NO);
585  for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
586  c_cur->f_abs_sum[i] = DEFAULT_ABS_PREFERENCE;
588  pc_tail,
589  c_cur);
590  }
591 
592  /* check global peer entry exists */
593  if (NULL ==
595  peer)))
596  {
597  /* Create struct for peer */
598  r_cur = GNUNET_new (struct PeerRelative);
599  for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
600  r_cur->f_rel[i] = DEFAULT_REL_PREFERENCE;
603  peer,
604  r_cur,
606  }
607 
608  /* Find entry for peer */
610  peer);
611  if (NULL == p_cur)
612  {
613  /* Not found: create new peer entry */
614  p_cur = GNUNET_new (struct PreferencePeer);
615  for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
616  {
617  /* Default value per peer absolute preference for a preference*/
618  p_cur->f_abs[i] = DEFAULT_ABS_PREFERENCE;
619  /* Default value per peer relative preference for a quality */
620  p_cur->f_rel[i] = DEFAULT_REL_PREFERENCE;
621  }
624  peer,
625  p_cur,
627  r_cur->num_clients++;
628  }
629 
630  p_cur->f_abs[kind] += score_abs;
631  recalculate_relative_preferences (c_cur, kind);
634  &kind);
635 
636  if (NULL == aging_task)
639  NULL);
640 }
641 
642 
649 void
651  const struct ChangePreferenceMessage *msg)
652 {
653  const struct PreferenceInformation *pi;
654  uint32_t nump;
655 
656  nump = ntohl (msg->num_preferences);
658  "Received PREFERENCE_CHANGE message for peer `%s'\n",
659  GNUNET_i2s (&msg->peer));
661  "# preference change requests processed",
662  1,
663  GNUNET_NO);
664  pi = (const struct PreferenceInformation *) &msg[1];
666  for (uint32_t i = 0; i < nump; i++)
667  update_preference (client,
668  &msg->peer,
669  (enum GNUNET_ATS_PreferenceKind) ntohl (
670  pi[i].preference_kind),
671  pi[i].preference_value);
673 }
674 
675 
679 void
681 {
682  unsigned int i;
683 
685  GNUNET_NO);
686  for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
688 }
689 
690 
694 void
696 {
697  struct PreferenceClient *pc;
698  struct PreferenceClient *next_pc;
699 
700  if (NULL != aging_task)
701  {
703  aging_task = NULL;
704  }
705  next_pc = pc_head;
706  while (NULL != (pc = next_pc))
707  {
708  next_pc = pc->next;
710  pc_tail,
711  pc);
714  pc);
716  GNUNET_free (pc);
717  }
719  &free_peer,
720  NULL);
722 }
723 
724 
734 const double *
736  const struct GNUNET_PeerIdentity *id)
737 {
738  struct PeerRelative *rp;
739 
740  if (NULL ==
742  id)))
743  {
744  return defvalues.f_rel;
745  }
746  return rp->f_rel;
747 }
748 
749 
750 void
752 {
753  struct PreferenceClient *c_cur;
754 
755  for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
756  if (client == c_cur->client)
757  break;
758  if (NULL == c_cur)
759  return;
761  pc_tail,
762  c_cur);
765  c_cur);
767  GNUNET_free (c_cur);
768 }
769 
770 
771 /* end of gnunet-service-ats_preferences.c */
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
automatic transport selection messages
struct GNUNET_STATISTICS_Handle * GSA_stats
Handle for statistics.
static struct GNUNET_PEERINFO_Handle * pi
Handle to peerinfo service.
struct GNUNET_HashCode key
The key used in the DHT.
static char * value
Value of the record to add/remove.
static struct GNUNET_MQ_Envelope * ac
Handle to current GNUNET_PEERINFO_add_peer() operation.
static struct GNUNET_FS_PublishContext * pc
Handle to FS-publishing operation.
static char * rp
Relying party.
ats service address management
ats service, interaction with 'performance' API
void GAS_plugin_solver_unlock()
Resume instant solving, we are done with the bulk state updates.
void GAS_plugin_solver_lock()
Stop instant solving, there are many state updates happening in bulk right now.
void GAS_plugin_notify_preference_changed(const struct GNUNET_PeerIdentity *peer, enum GNUNET_ATS_PreferenceKind kind, double pref_rel)
The preference changed for a peer, update solver.
ats service plugin management
static int update_rel_sum(void *cls, const struct GNUNET_PeerIdentity *peer, void *value)
Compute updated relative score for each peer based on the current absolute score given by this client...
#define PREF_AGING_FACTOR
By which factor do we age preferences expressed during each PREF_AGING_INTERVAL?
#define PREF_EPSILON
What is the lowest threshold up to which preference values are aged, and below which we consider them...
static void update_relative_values_for_peer(const struct GNUNET_PeerIdentity *id, enum GNUNET_ATS_PreferenceKind kind)
Update the total relative preference for a peer by summing up the relative preferences all clients ha...
void GAS_preference_client_disconnect(struct GNUNET_SERVICE_Client *client)
A performance client disconnected.
static int free_peer(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
Free a peer's struct PeerRelative.
static int age_values(void *cls, const struct GNUNET_PeerIdentity *peer, void *value)
Age preference values of the given peer.
#define PREF_AGING_INTERVAL
How frequently do we age preference values?
void GAS_preference_init()
Initialize preferences subsystem.
static int sum_relative_preferences(void *cls, const struct GNUNET_PeerIdentity *peer, void *value)
Add the relative preference for the kind given to the closure.
static void preference_aging(void *cls)
Reduce absolute preferences since they got old.
static struct PeerRelative defvalues
Default values, returned as our preferences if we do not have any preferences expressed for a peer.
static struct GNUNET_SCHEDULER_Task * aging_task
Handle for task we run periodically to age preferences over time.
static struct GNUNET_CONTAINER_MultiPeerMap * preference_peers
Hashmap to store peer information for preference normalization.
void GAS_preference_done()
Shutdown preferences subsystem.
static void update_preference(struct GNUNET_SERVICE_Client *client, const struct GNUNET_PeerIdentity *peer, enum GNUNET_ATS_PreferenceKind kind, float score_abs)
Update the absolute preference and calculate the new relative preference value.
void GAS_handle_preference_change(struct GNUNET_SERVICE_Client *client, const struct ChangePreferenceMessage *msg)
Handle 'preference change' messages from clients.
static int update_iterator(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
The relative preferences of one of the clients have changed, update the global preferences for the gi...
#define LOG(kind,...)
static int free_preference(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
Free struct PreferencePeer entry in map.
static int update_abs_sum(void *cls, const struct GNUNET_PeerIdentity *peer, void *value)
Compute updated absolute score for the client based on the current absolute scores for each peer.
const double * GAS_preference_get_by_peer(void *cls, const struct GNUNET_PeerIdentity *id)
Get the normalized preference values for a specific peer or the default values if.
static void recalculate_relative_preferences(struct PreferenceClient *c, enum GNUNET_ATS_PreferenceKind kind)
Recalculate preference for a specific ATS property.
static struct PreferenceClient * pc_head
Clients in DLL: head.
static struct PreferenceClient * pc_tail
Clients in DLL: tail.
manage preferences expressed by clients
#define DEFAULT_ABS_PREFERENCE
Default preference value we assume if we know nothing.
#define DEFAULT_REL_PREFERENCE
Default relative preference value we assume if we know nothing.
ats service, inbound bandwidth reservation management
static struct GNUNET_FS_UnindexContext * uc
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-uri.c:38
const char * GNUNET_ATS_print_preference_type(enum GNUNET_ATS_PreferenceKind type)
Convert an enum GNUNET_ATS_PreferenceType to a string.
GNUNET_ATS_PreferenceKind
Enum defining all known preference categories.
@ GNUNET_ATS_PREFERENCE_END
End of preference list.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
void GNUNET_CONTAINER_multipeermap_destroy(struct GNUNET_CONTAINER_MultiPeerMap *map)
Destroy a hash map.
int GNUNET_CONTAINER_multipeermap_iterate(struct GNUNET_CONTAINER_MultiPeerMap *map, GNUNET_CONTAINER_PeerMapIterator it, void *it_cls)
Iterate over all entries in the map.
struct GNUNET_CONTAINER_MultiPeerMap * GNUNET_CONTAINER_multipeermap_create(unsigned int len, int do_not_copy_keys)
Create a multi peer map (hash map for public keys of peers).
void * GNUNET_CONTAINER_multipeermap_get(const struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key)
Given a key find a value in the map matching the key.
int GNUNET_CONTAINER_multipeermap_get_multiple(struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key, GNUNET_CONTAINER_PeerMapIterator it, void *it_cls)
Iterate over all entries in the map that match a particular key.
int GNUNET_CONTAINER_multipeermap_put(struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt)
Store a key-value pair in the map.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multipeermap_remove(struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key, const void *value)
Remove the given key-value pair from the map.
@ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY
There must only be one value per key; storing a value should fail if a value under the same key alrea...
#define GNUNET_log(kind,...)
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
const char * GNUNET_i2s(const struct GNUNET_PeerIdentity *pid)
Convert a peer identity to a string (for printing debug messages).
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
@ GNUNET_ERROR_TYPE_DEBUG
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:975
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1272
void GNUNET_STATISTICS_update(struct GNUNET_STATISTICS_Handle *handle, const char *name, int64_t delta, int make_persistent)
Set statistic value for the peer.
Closure for age_values().
unsigned int values_to_update
Counter of values remaining to update, incremented for each value changed (to a new non-zero value).
struct PreferenceClient * cur_client
Client we are currently aging values for.
Client to ATS: I have a performance preference for a peer.
Definition: ats.h:438
Internal representation of the hash map.
struct GNUNET_MQ_Envelope * next
Messages are stored in a linked list.
Definition: mq.c:39
The identity of the host (wraps the signing key of the peer).
Entry in list of pending tasks.
Definition: scheduler.c:136
Handle to a client that is connected to a service.
Definition: service.c:252
Relative preferences for a peer.
unsigned int num_clients
Number of clients that are expressing a preference for this peer.
double f_rel[GNUNET_ATS_PREFERENCE_END]
Array of relative preference values, to be indexed by an enum GNUNET_ATS_PreferenceKind.
Preference client, as in a client that expressed preferences for peers.
struct GNUNET_SERVICE_Client * client
Client handle.
struct PreferenceClient * prev
Previous in client peer list.
struct PreferenceClient * next
Next in client list.
double f_abs_sum[GNUNET_ATS_PREFERENCE_END]
Array of sums of absolute preferences for all peers as expressed by this client.
struct GNUNET_CONTAINER_MultiPeerMap * peer2pref
Mapping peer identities to struct PreferencePeer entry for the respective peer.
Variable-size entry in a struct ChangePreferenceMessage or struct FeedbackPreferenceMessage.
Definition: ats.h:420
uint32_t preference_kind
An enum GNUNET_ATS_PreferenceKind in NBO.
Definition: ats.h:424
float preference_value
Degree of preference (or appreciation) for this preference_kind being expressed.
Definition: ats.h:430
Preference information per peer and client.
struct PreferencePeer * prev
Previous in DLL of preference entries for the same client.
double f_abs[GNUNET_ATS_PREFERENCE_END]
Absolute preference values for all preference types as expressed by this client for this peer.
struct PreferencePeer * next
Next in DLL of preference entries for the same client.
double f_rel[GNUNET_ATS_PREFERENCE_END]
Relative preference values for all preference types, normalized in [0..1] based on how the respective...
Closure for sum_relative_preferences().
double f_rel_total
Where to accumulate the result.
enum GNUNET_ATS_PreferenceKind kind
Which kind of preference value are we adding up?
Closure for update_rel_sum() and update_abs_sum().
struct PreferenceClient * pc
Preference client with the sum of all absolute scores.
enum GNUNET_ATS_PreferenceKind kind
Which kind are we updating?
struct GNUNET_TESTBED_Peer * peer
The peer associated with this model.