GNUnet  0.10.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 (GNUNET_TIME_UNIT_SECONDS, 10)
41 
46 #define PREF_AGING_FACTOR 0.95
47 
53 #define PREF_EPSILON 0.01
54 
55 
60 {
66 
72  unsigned int num_clients;
73 };
74 
75 
80 static struct PeerRelative defvalues;
81 
82 
87 {
92 
97 
103 
110 
111 };
112 
113 
120 {
121 
126 
131 
136 
142 
147  double f_abs_sum[GNUNET_ATS_PREFERENCE_END];
148 
149 };
150 
151 
158 
162 static struct PreferenceClient *pc_head;
163 
167 static struct PreferenceClient *pc_tail;
168 
173 
174 
179 {
183  double f_rel_total;
184 
189 };
190 
191 
202 static int
204  const struct GNUNET_PeerIdentity *peer,
205  void *value)
206 {
207  struct SumContext *sum_ctx = cls;
208  struct PreferencePeer *p_cur = value;
209 
210  sum_ctx->f_rel_total += p_cur->f_rel[sum_ctx->kind];
211  return GNUNET_OK;
212 }
213 
214 
223 static void
225  enum GNUNET_ATS_PreferenceKind kind)
226 {
227  struct PreferenceClient *c_cur;
228  struct SumContext sum_ctx;
229  struct PeerRelative *rp;
230 
231  sum_ctx.f_rel_total = 0.0;
232  sum_ctx.kind = kind;
233  for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
235  id,
237  &sum_ctx);
239  "Total relative preference for peer `%s' for `%s' is %.3f\n",
240  GNUNET_i2s (id),
242  sum_ctx.f_rel_total);
243  rp = GNUNET_CONTAINER_multipeermap_get (preference_peers,
244  id);
245  GNUNET_assert (NULL != rp);
246  if (rp->f_rel[kind] != sum_ctx.f_rel_total)
247  {
248  rp->f_rel[kind] = sum_ctx.f_rel_total;
250  kind,
251  rp->f_rel[kind]);
252  }
253 }
254 
255 
264 static int
265 free_peer (void *cls,
266  const struct GNUNET_PeerIdentity *key,
267  void *value)
268 {
269  struct PeerRelative *rp = value;
270 
272  GNUNET_CONTAINER_multipeermap_remove (preference_peers,
273  key,
274  value));
275  GNUNET_free (rp);
276  return GNUNET_OK;
277 }
278 
279 
288 static int
289 free_preference (void *cls,
290  const struct GNUNET_PeerIdentity *key,
291  void *value)
292 {
293  struct PreferenceClient *pc = cls;
294  struct PreferencePeer *p = value;
295  struct PeerRelative *pr;
296 
299  key,
300  p));
301  GNUNET_free (p);
302  pr = GNUNET_CONTAINER_multipeermap_get (preference_peers,
303  key);
304  GNUNET_assert (NULL != pr);
305  GNUNET_assert (pr->num_clients > 0);
306  pr->num_clients--;
307  if (0 == pr->num_clients)
308  {
309  free_peer (NULL,
310  key,
311  pr);
312  }
313  return GNUNET_OK;
314 }
315 
316 
321 {
326  unsigned int values_to_update;
327 
332 
333 };
334 
335 
344 static int
345 age_values (void *cls,
346  const struct GNUNET_PeerIdentity *peer,
347  void *value)
348 {
349  struct AgeContext *ac = cls;
350  struct PreferencePeer *p = value;
351  unsigned int i;
352  int dead;
353 
354  dead = GNUNET_YES;
355  for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
356  {
358  "Aging preference for peer `%s'\n",
359  GNUNET_i2s (peer));
360  if (p->f_abs[i] > DEFAULT_ABS_PREFERENCE)
361  p->f_abs[i] *= PREF_AGING_FACTOR;
363  {
367  i);
368  }
369  else
370  {
371  ac->values_to_update++;
372  dead = GNUNET_NO;
373  }
374  }
375  if (GNUNET_YES == dead)
376  {
377  /* all preferences are zero, remove this entry */
379  peer,
380  p);
381  }
382  return GNUNET_OK;
383 }
384 
385 
391 static void
392 preference_aging (void *cls)
393 {
394  struct AgeContext ac;
395 
396  aging_task = NULL;
398  ac.values_to_update = 0;
399  for (ac.cur_client = pc_head; NULL != ac.cur_client; ac.cur_client = ac.cur_client->next)
401  &age_values,
402  &ac);
404  if (ac.values_to_update > 0)
405  {
407  "Rescheduling aging task due to %u elements remaining to age\n",
408  ac.values_to_update);
409  if (NULL == aging_task)
412  NULL);
413  }
414  else
415  {
417  "No values to age left, not rescheduling aging task\n");
418  }
419 }
420 
421 
426 {
431 
436 
437 };
438 
439 
449 static int
450 update_abs_sum (void *cls,
451  const struct GNUNET_PeerIdentity *peer,
452  void *value)
453 {
454  struct UpdateContext *uc = cls;
455  struct PreferencePeer *p_cur = value;
456 
457  uc->pc->f_abs_sum[uc->kind] += p_cur->f_abs[uc->kind];
458  return GNUNET_OK;
459 }
460 
461 
471 static int
472 update_rel_sum (void *cls,
473  const struct GNUNET_PeerIdentity *peer,
474  void *value)
475 {
476  struct UpdateContext *uc = cls;
477  struct PreferencePeer *p_cur = value;
478 
479  p_cur->f_rel[uc->kind] = p_cur->f_abs[uc->kind] / uc->pc->f_abs_sum[uc->kind];
481  "Client has relative preference for %s for peer `%s' of %.3f\n",
483  GNUNET_i2s (peer),
484  p_cur->f_rel[uc->kind]);
485  return GNUNET_OK;
486 }
487 
488 
496 static void
498  enum GNUNET_ATS_PreferenceKind kind)
499 {
500  struct UpdateContext uc;
501 
502  /* For this client: sum of absolute preference values for this preference */
503  uc.kind = kind;
504  uc.pc = c;
505  c->f_abs_sum[kind] = 0.0;
506 
507  /* For all peers: calculate sum of absolute preferences */
510  &uc);
512  "Client has sum of total preferences for %s of %.3f\n",
514  c->f_abs_sum[kind]);
515 
516  /* For all peers: calculate relative preference */
519  &uc);
520 }
521 
522 
533 static int
534 update_iterator (void *cls,
535  const struct GNUNET_PeerIdentity *key,
536  void *value)
537 {
538  enum GNUNET_ATS_PreferenceKind *kind = cls;
539 
541  *kind);
542  return GNUNET_OK;
543 }
544 
545 
555 static void
557  const struct GNUNET_PeerIdentity *peer,
559  float score_abs)
560 {
561  struct PreferenceClient *c_cur;
562  struct PreferencePeer *p_cur;
563  struct PeerRelative *r_cur;
564  unsigned int i;
565 
566  if (kind >= GNUNET_ATS_PREFERENCE_END)
567  {
568  GNUNET_break(0);
569  return;
570  }
572  "Client changes preference for peer `%s' for `%s' to %.2f\n",
573  GNUNET_i2s (peer),
575  score_abs);
576 
577  /* Find preference client */
578  for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
579  if (client == c_cur->client)
580  break;
581  /* Not found: create new preference client */
582  if (NULL == c_cur)
583  {
584  c_cur = GNUNET_new (struct PreferenceClient);
585  c_cur->client = client;
587  GNUNET_NO);
588  for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
589  c_cur->f_abs_sum[i] = DEFAULT_ABS_PREFERENCE;
591  pc_tail,
592  c_cur);
593  }
594 
595  /* check global peer entry exists */
596  if (NULL ==
597  (r_cur = GNUNET_CONTAINER_multipeermap_get (preference_peers,
598  peer)))
599  {
600  /* Create struct for peer */
601  r_cur = GNUNET_new (struct PeerRelative);
602  for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
603  r_cur->f_rel[i] = DEFAULT_REL_PREFERENCE;
605  GNUNET_CONTAINER_multipeermap_put (preference_peers,
606  peer,
607  r_cur,
609  }
610 
611  /* Find entry for peer */
613  peer);
614  if (NULL == p_cur)
615  {
616  /* Not found: create new peer entry */
617  p_cur = GNUNET_new (struct PreferencePeer);
618  for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
619  {
620  /* Default value per peer absolute preference for a preference*/
621  p_cur->f_abs[i] = DEFAULT_ABS_PREFERENCE;
622  /* Default value per peer relative preference for a quality */
623  p_cur->f_rel[i] = DEFAULT_REL_PREFERENCE;
624  }
627  peer,
628  p_cur,
630  r_cur->num_clients++;
631  }
632 
633  p_cur->f_abs[kind] += score_abs;
634  recalculate_relative_preferences (c_cur, kind);
635  GNUNET_CONTAINER_multipeermap_iterate (preference_peers,
637  &kind);
638 
639  if (NULL == aging_task)
642  NULL);
643 }
644 
645 
652 void
654  const struct ChangePreferenceMessage *msg)
655 {
656  const struct PreferenceInformation *pi;
657  uint32_t nump;
658 
659  nump = ntohl (msg->num_preferences);
661  "Received PREFERENCE_CHANGE message for peer `%s'\n",
662  GNUNET_i2s (&msg->peer));
664  "# preference change requests processed",
665  1,
666  GNUNET_NO);
667  pi = (const struct PreferenceInformation *) &msg[1];
669  for (uint32_t i = 0; i < nump; i++)
670  update_preference (client,
671  &msg->peer,
672  (enum GNUNET_ATS_PreferenceKind) ntohl (pi[i].preference_kind),
673  pi[i].preference_value);
675 }
676 
677 
681 void
683 {
684  unsigned int i;
685 
686  preference_peers = GNUNET_CONTAINER_multipeermap_create (16,
687  GNUNET_NO);
688  for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
690 }
691 
692 
696 void
698 {
699  struct PreferenceClient *pc;
700  struct PreferenceClient *next_pc;
701 
702  if (NULL != aging_task)
703  {
704  GNUNET_SCHEDULER_cancel (aging_task);
705  aging_task = NULL;
706  }
707  next_pc = pc_head;
708  while (NULL != (pc = next_pc))
709  {
710  next_pc = pc->next;
712  pc_tail,
713  pc);
716  pc);
718  GNUNET_free (pc);
719  }
720  GNUNET_CONTAINER_multipeermap_iterate (preference_peers,
721  &free_peer,
722  NULL);
723  GNUNET_CONTAINER_multipeermap_destroy (preference_peers);
724 
725 }
726 
727 
737 const double *
739  const struct GNUNET_PeerIdentity *id)
740 {
741  struct PeerRelative *rp;
742 
743  if (NULL ==
744  (rp = GNUNET_CONTAINER_multipeermap_get (preference_peers,
745  id)))
746  {
747  return defvalues.f_rel;
748  }
749  return rp->f_rel;
750 }
751 
752 
758 void
760 {
761  struct PreferenceClient *c_cur;
762 
763  for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
764  if (client == c_cur->client)
765  break;
766  if (NULL == c_cur)
767  return;
769  pc_tail,
770  c_cur);
773  c_cur);
775  GNUNET_free (c_cur);
776 }
777 
778 
779 /* 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:463
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:433
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_NO
Definition: gnunet_common.h:81
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
#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:249
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:1246
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:458
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:427
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:447
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...
#define GNUNET_YES
Definition: gnunet_common.h:80
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:439
#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:965