GNUnet  0.11.x
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 
146  double f_abs_sum[GNUNET_ATS_PREFERENCE_END];
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);
241  rp = GNUNET_CONTAINER_multipeermap_get (preference_peers,
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 
270  GNUNET_CONTAINER_multipeermap_remove (preference_peers,
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);
300  pr = GNUNET_CONTAINER_multipeermap_get (preference_peers,
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;
360  {
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 */
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)
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 ==
594  (r_cur = GNUNET_CONTAINER_multipeermap_get (preference_peers,
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;
602  GNUNET_CONTAINER_multipeermap_put (preference_peers,
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);
632  GNUNET_CONTAINER_multipeermap_iterate (preference_peers,
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 
684  preference_peers = GNUNET_CONTAINER_multipeermap_create (16,
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  {
702  GNUNET_SCHEDULER_cancel (aging_task);
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  }
718  GNUNET_CONTAINER_multipeermap_iterate (preference_peers,
719  &free_peer,
720  NULL);
721  GNUNET_CONTAINER_multipeermap_destroy (preference_peers);
722 }
723 
724 
734 const double *
736  const struct GNUNET_PeerIdentity *id)
737 {
738  struct PeerRelative *rp;
739 
740  if (NULL ==
741  (rp = GNUNET_CONTAINER_multipeermap_get (preference_peers,
742  id)))
743  {
744  return defvalues.f_rel;
745  }
746  return rp->f_rel;
747 }
748 
749 
755 void
757 {
758  struct PreferenceClient *c_cur;
759 
760  for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
761  if (client == c_cur->client)
762  break;
763  if (NULL == c_cur)
764  return;
766  pc_tail,
767  c_cur);
770  c_cur);
772  GNUNET_free (c_cur);
773 }
774 
775 
776 /* end of gnunet-service-ats_preferences.c */
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
struct GNUNET_PeerIdentity peer
Which peer is the preference being expressed for?
Definition: ats.h:453
enum GNUNET_ATS_PreferenceKind kind
Which kind of preference value are we adding up?
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...
struct GNUNET_SERVICE_Client * client
Client handle.
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
struct PreferencePeer * next
Next in DLL of preference entries for the same client.
Closure for update_rel_sum() and update_abs_sum().
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
struct PreferenceClient * next
Next in client list.
double f_rel_total
Where to accumulate the result.
void GAS_preference_init()
Initialize preferences subsystem.
void GAS_plugin_solver_lock()
Stop instant solving, there are many state updates happening in bulk right now.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
struct PreferenceClient * cur_client
Client we are currently aging values for.
static struct GNUNET_FS_UnindexContext * uc
uint32_t preference_kind
An enum GNUNET_ATS_PreferenceKind in NBO.
Definition: ats.h:424
Closure for sum_relative_preferences().
int 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.
ats service plugin management
#define GNUNET_new(type)
Allocate a struct or union of the given type.
void GNUNET_STATISTICS_update(struct GNUNET_STATISTICS_Handle *handle, const char *name, int64_t delta, int make_persistent)
Set statistic value for the peer.
static struct GNUNET_PEERINFO_Handle * pi
Handle to peerinfo service.
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 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.
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.
struct GNUNET_STATISTICS_Handle * GSA_stats
Handle for statistics.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
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.
End of preference list.
double f_rel[GNUNET_ATS_PREFERENCE_END]
Relative preference values for all preference types, normalized in [0..1] based on how the respective...
void GNUNET_CONTAINER_multipeermap_destroy(struct GNUNET_CONTAINER_MultiPeerMap *map)
Destroy a hash map.
ats service, interaction with &#39;performance&#39; API
void GAS_preference_client_disconnect(struct GNUNET_SERVICE_Client *client)
A performance client disconnected.
Handle to a client that is connected to a service.
Definition: service.c:250
void GAS_plugin_solver_unlock()
Resume instant solving, we are done with the bulk state updates.
Closure for age_values().
static void recalculate_relative_preferences(struct PreferenceClient *c, enum GNUNET_ATS_PreferenceKind kind)
Recalculate preference for a specific ATS property.
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:1269
static int free_peer(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
Free a peer&#39;s struct PeerRelative.
ats service, inbound bandwidth reservation management
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-qr.c:59
static char * value
Value of the record to add/remove.
enum GNUNET_ATS_PreferenceKind kind
Which kind are we updating?
#define PREF_AGING_FACTOR
By which factor do we age preferences expressed during each PREF_AGING_INTERVAL?
double f_rel[GNUNET_ATS_PREFERENCE_END]
Array of relative preference values, to be indexed by an enum GNUNET_ATS_PreferenceKind.
static int age_values(void *cls, const struct GNUNET_PeerIdentity *peer, void *value)
Age preference values of the given peer.
struct PreferenceClient * prev
Previous in client peer list.
Preference client, as in a client that expressed preferences for peers.
Internal representation of the hash map.
const char * GNUNET_ATS_print_preference_type(enum GNUNET_ATS_PreferenceKind type)
Convert a enum GNUNET_ATS_PreferenceType to a string.
struct PreferencePeer * prev
Previous in DLL of preference entries for the same client.
void GAS_preference_done()
Shutdown preferences subsystem.
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...
There must only be one value per key; storing a value should fail if a value under the same key alrea...
struct GNUNET_TESTBED_Peer * peer
The peer associated with this model.
struct GNUNET_HashCode key
The key used in the DHT.
unsigned int values_to_update
Counter of values remaining to update, incremented for each value changed (to a new non-zero value)...
static struct GNUNET_CONTAINER_MultiPeerMap * preference_peers
Hashmap to store peer information for preference normalization.
Preference information per peer and client.
uint32_t num_preferences
How many struct PreferenceInformation entries follow this struct?
Definition: ats.h:448
static struct GNUNET_MQ_Envelope * ac
Handle to current GNUNET_PEERINFO_add_peer() operation.
#define DEFAULT_REL_PREFERENCE
Default relative preference value we assume if we know nothing.
manage preferences expressed by clients
Relative preferences for a peer.
ats service address management
#define PREF_EPSILON
What is the lowest threshold up to which prefernce values are aged, and below which we consider them ...
double f_abs_sum[GNUNET_ATS_PREFERENCE_END]
Array of sums of absolute preferences for all peers as expressed by this client.
void GAS_handle_preference_change(struct GNUNET_SERVICE_Client *client, const struct ChangePreferenceMessage *msg)
Handle &#39;preference change&#39; messages from clients.
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.
int GNUNET_CONTAINER_multipeermap_iterate(struct GNUNET_CONTAINER_MultiPeerMap *map, GNUNET_CONTAINER_PeerMapIterator it, void *it_cls)
Iterate over all entries in the map.
static struct GNUNET_FS_PublishContext * pc
Handle to FS-publishing operation.
The identity of the host (wraps the signing key of the peer).
static struct GNUNET_SCHEDULER_Task * aging_task
Handle for task we run periodically to age preferences over time.
#define PREF_AGING_INTERVAL
How frequently do we age preference values?
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.
static void preference_aging(void *cls)
Reduce absolute preferences since they got old.
#define GNUNET_log(kind,...)
Entry in list of pending tasks.
Definition: scheduler.c:134
unsigned int num_clients
Number of clients that are expressing a preference for this peer.
static struct PreferenceClient * pc_tail
Clients in DLL: tail.
static int free_preference(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
Free struct PreferencePeer entry in map.
Variable-size entry in a struct ChangePreferenceMessage or struct FeedbackPreferenceMessage.
Definition: ats.h:419
static void update_relative_values_for_peer(const struct GNUNET_PeerIdentity *id, enum GNUNET_ATS_PreferenceKind kind)
Update the total releative preference for a peer by summing up the relative preferences all clients h...
static char * rp
Relying party.
Client to ATS: I have a performance preference for a peer.
Definition: ats.h:437
static struct PreferenceClient * pc_head
Clients in DLL: head.
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...
static struct PeerRelative defvalues
Default values, returned as our preferences if we do not have any preferences expressed for a peer...
#define DEFAULT_ABS_PREFERENCE
Default preference value we assume if we know nothing.
struct PreferenceClient * pc
Preference client with the sum of all absolute scores.
GNUNET_ATS_PreferenceKind
Enum defining all known preference categories.
float preference_value
Degree of preference (or appreciation) for this preference_kind being expressed.
Definition: ats.h:430
#define LOG(kind,...)
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.
const char * GNUNET_i2s(const struct GNUNET_PeerIdentity *pid)
Convert a peer identity to a string (for printing debug messages).
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.
automatic transport selection messages
double f_abs[GNUNET_ATS_PREFERENCE_END]
Absolute preference values for all preference types as expressed by this client for this peer...
#define GNUNET_free(ptr)
Wrapper around free.
struct GNUNET_CONTAINER_MultiPeerMap * peer2pref
Mapping peer identities to struct PreferencePeer entry for the respective peer.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:972