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 
59 struct PeerRelative {
65 
71  unsigned int num_clients;
72 };
73 
74 
79 static struct PeerRelative defvalues;
80 
81 
90 
95 
101 
108 };
109 
110 
121 
126 
131 
137 
142  double f_abs_sum[GNUNET_ATS_PREFERENCE_END];
143 };
144 
145 
152 
156 static struct PreferenceClient *pc_head;
157 
161 static struct PreferenceClient *pc_tail;
162 
167 
168 
172 struct SumContext {
176  double f_rel_total;
177 
182 };
183 
184 
195 static int
197  const struct GNUNET_PeerIdentity *peer,
198  void *value)
199 {
200  struct SumContext *sum_ctx = cls;
201  struct PreferencePeer *p_cur = value;
202 
203  sum_ctx->f_rel_total += p_cur->f_rel[sum_ctx->kind];
204  return GNUNET_OK;
205 }
206 
207 
216 static void
218  enum GNUNET_ATS_PreferenceKind kind)
219 {
220  struct PreferenceClient *c_cur;
221  struct SumContext sum_ctx;
222  struct PeerRelative *rp;
223 
224  sum_ctx.f_rel_total = 0.0;
225  sum_ctx.kind = kind;
226  for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
228  id,
230  &sum_ctx);
232  "Total relative preference for peer `%s' for `%s' is %.3f\n",
233  GNUNET_i2s(id),
235  sum_ctx.f_rel_total);
236  rp = GNUNET_CONTAINER_multipeermap_get(preference_peers,
237  id);
238  GNUNET_assert(NULL != rp);
239  if (rp->f_rel[kind] != sum_ctx.f_rel_total)
240  {
241  rp->f_rel[kind] = sum_ctx.f_rel_total;
243  kind,
244  rp->f_rel[kind]);
245  }
246 }
247 
248 
257 static int
258 free_peer(void *cls,
259  const struct GNUNET_PeerIdentity *key,
260  void *value)
261 {
262  struct PeerRelative *rp = value;
263 
265  GNUNET_CONTAINER_multipeermap_remove(preference_peers,
266  key,
267  value));
268  GNUNET_free(rp);
269  return GNUNET_OK;
270 }
271 
272 
281 static int
282 free_preference(void *cls,
283  const struct GNUNET_PeerIdentity *key,
284  void *value)
285 {
286  struct PreferenceClient *pc = cls;
287  struct PreferencePeer *p = value;
288  struct PeerRelative *pr;
289 
292  key,
293  p));
294  GNUNET_free(p);
295  pr = GNUNET_CONTAINER_multipeermap_get(preference_peers,
296  key);
297  GNUNET_assert(NULL != pr);
298  GNUNET_assert(pr->num_clients > 0);
299  pr->num_clients--;
300  if (0 == pr->num_clients)
301  {
302  free_peer(NULL,
303  key,
304  pr);
305  }
306  return GNUNET_OK;
307 }
308 
309 
313 struct AgeContext {
318  unsigned int values_to_update;
319 
324 };
325 
326 
335 static int
336 age_values(void *cls,
337  const struct GNUNET_PeerIdentity *peer,
338  void *value)
339 {
340  struct AgeContext *ac = cls;
341  struct PreferencePeer *p = value;
342  unsigned int i;
343  int dead;
344 
345  dead = GNUNET_YES;
346  for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
347  {
349  "Aging preference for peer `%s'\n",
350  GNUNET_i2s(peer));
351  if (p->f_abs[i] > DEFAULT_ABS_PREFERENCE)
352  p->f_abs[i] *= PREF_AGING_FACTOR;
354  {
358  i);
359  }
360  else
361  {
362  ac->values_to_update++;
363  dead = GNUNET_NO;
364  }
365  }
366  if (GNUNET_YES == dead)
367  {
368  /* all preferences are zero, remove this entry */
370  peer,
371  p);
372  }
373  return GNUNET_OK;
374 }
375 
376 
382 static void
384 {
385  struct AgeContext ac;
386 
387  aging_task = NULL;
389  ac.values_to_update = 0;
390  for (ac.cur_client = pc_head; NULL != ac.cur_client; ac.cur_client = ac.cur_client->next)
392  &age_values,
393  &ac);
395  if (ac.values_to_update > 0)
396  {
398  "Rescheduling aging task due to %u elements remaining to age\n",
399  ac.values_to_update);
400  if (NULL == aging_task)
403  NULL);
404  }
405  else
406  {
408  "No values to age left, not rescheduling aging task\n");
409  }
410 }
411 
412 
421 
426 };
427 
428 
438 static int
439 update_abs_sum(void *cls,
440  const struct GNUNET_PeerIdentity *peer,
441  void *value)
442 {
443  struct UpdateContext *uc = cls;
444  struct PreferencePeer *p_cur = value;
445 
446  uc->pc->f_abs_sum[uc->kind] += p_cur->f_abs[uc->kind];
447  return GNUNET_OK;
448 }
449 
450 
460 static int
461 update_rel_sum(void *cls,
462  const struct GNUNET_PeerIdentity *peer,
463  void *value)
464 {
465  struct UpdateContext *uc = cls;
466  struct PreferencePeer *p_cur = value;
467 
468  p_cur->f_rel[uc->kind] = p_cur->f_abs[uc->kind] / uc->pc->f_abs_sum[uc->kind];
470  "Client has relative preference for %s for peer `%s' of %.3f\n",
472  GNUNET_i2s(peer),
473  p_cur->f_rel[uc->kind]);
474  return GNUNET_OK;
475 }
476 
477 
485 static void
487  enum GNUNET_ATS_PreferenceKind kind)
488 {
489  struct UpdateContext uc;
490 
491  /* For this client: sum of absolute preference values for this preference */
492  uc.kind = kind;
493  uc.pc = c;
494  c->f_abs_sum[kind] = 0.0;
495 
496  /* For all peers: calculate sum of absolute preferences */
499  &uc);
501  "Client has sum of total preferences for %s of %.3f\n",
503  c->f_abs_sum[kind]);
504 
505  /* For all peers: calculate relative preference */
508  &uc);
509 }
510 
511 
522 static int
523 update_iterator(void *cls,
524  const struct GNUNET_PeerIdentity *key,
525  void *value)
526 {
527  enum GNUNET_ATS_PreferenceKind *kind = cls;
528 
530  *kind);
531  return GNUNET_OK;
532 }
533 
534 
544 static void
546  const struct GNUNET_PeerIdentity *peer,
548  float score_abs)
549 {
550  struct PreferenceClient *c_cur;
551  struct PreferencePeer *p_cur;
552  struct PeerRelative *r_cur;
553  unsigned int i;
554 
555  if (kind >= GNUNET_ATS_PREFERENCE_END)
556  {
557  GNUNET_break(0);
558  return;
559  }
561  "Client changes preference for peer `%s' for `%s' to %.2f\n",
562  GNUNET_i2s(peer),
564  score_abs);
565 
566  /* Find preference client */
567  for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
568  if (client == c_cur->client)
569  break;
570  /* Not found: create new preference client */
571  if (NULL == c_cur)
572  {
573  c_cur = GNUNET_new(struct PreferenceClient);
574  c_cur->client = client;
576  GNUNET_NO);
577  for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
578  c_cur->f_abs_sum[i] = DEFAULT_ABS_PREFERENCE;
580  pc_tail,
581  c_cur);
582  }
583 
584  /* check global peer entry exists */
585  if (NULL ==
586  (r_cur = GNUNET_CONTAINER_multipeermap_get(preference_peers,
587  peer)))
588  {
589  /* Create struct for peer */
590  r_cur = GNUNET_new(struct PeerRelative);
591  for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
592  r_cur->f_rel[i] = DEFAULT_REL_PREFERENCE;
594  GNUNET_CONTAINER_multipeermap_put(preference_peers,
595  peer,
596  r_cur,
598  }
599 
600  /* Find entry for peer */
602  peer);
603  if (NULL == p_cur)
604  {
605  /* Not found: create new peer entry */
606  p_cur = GNUNET_new(struct PreferencePeer);
607  for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
608  {
609  /* Default value per peer absolute preference for a preference*/
610  p_cur->f_abs[i] = DEFAULT_ABS_PREFERENCE;
611  /* Default value per peer relative preference for a quality */
612  p_cur->f_rel[i] = DEFAULT_REL_PREFERENCE;
613  }
616  peer,
617  p_cur,
619  r_cur->num_clients++;
620  }
621 
622  p_cur->f_abs[kind] += score_abs;
624  GNUNET_CONTAINER_multipeermap_iterate(preference_peers,
626  &kind);
627 
628  if (NULL == aging_task)
631  NULL);
632 }
633 
634 
641 void
643  const struct ChangePreferenceMessage *msg)
644 {
645  const struct PreferenceInformation *pi;
646  uint32_t nump;
647 
648  nump = ntohl(msg->num_preferences);
650  "Received PREFERENCE_CHANGE message for peer `%s'\n",
651  GNUNET_i2s(&msg->peer));
653  "# preference change requests processed",
654  1,
655  GNUNET_NO);
656  pi = (const struct PreferenceInformation *)&msg[1];
658  for (uint32_t i = 0; i < nump; i++)
659  update_preference(client,
660  &msg->peer,
661  (enum GNUNET_ATS_PreferenceKind)ntohl(pi[i].preference_kind),
662  pi[i].preference_value);
664 }
665 
666 
670 void
672 {
673  unsigned int i;
674 
675  preference_peers = GNUNET_CONTAINER_multipeermap_create(16,
676  GNUNET_NO);
677  for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
679 }
680 
681 
685 void
687 {
688  struct PreferenceClient *pc;
689  struct PreferenceClient *next_pc;
690 
691  if (NULL != aging_task)
692  {
693  GNUNET_SCHEDULER_cancel(aging_task);
694  aging_task = NULL;
695  }
696  next_pc = pc_head;
697  while (NULL != (pc = next_pc))
698  {
699  next_pc = pc->next;
701  pc_tail,
702  pc);
705  pc);
707  GNUNET_free(pc);
708  }
709  GNUNET_CONTAINER_multipeermap_iterate(preference_peers,
710  &free_peer,
711  NULL);
712  GNUNET_CONTAINER_multipeermap_destroy(preference_peers);
713 }
714 
715 
725 const double *
727  const struct GNUNET_PeerIdentity *id)
728 {
729  struct PeerRelative *rp;
730 
731  if (NULL ==
732  (rp = GNUNET_CONTAINER_multipeermap_get(preference_peers,
733  id)))
734  {
735  return defvalues.f_rel;
736  }
737  return rp->f_rel;
738 }
739 
740 
746 void
748 {
749  struct PreferenceClient *c_cur;
750 
751  for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
752  if (client == c_cur->client)
753  break;
754  if (NULL == c_cur)
755  return;
757  pc_tail,
758  c_cur);
761  c_cur);
763  GNUNET_free(c_cur);
764 }
765 
766 
767 /* 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:440
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:412
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:78
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
#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:246
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:1237
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:435
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:131
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:408
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:425
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:77
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:418
#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:956