/*
This file is part of GNUnet.
- (C) 2011-2015 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2011-2015 Christian Grothoff (and other contributing authors)
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
*/
/**
* @file ats/gnunet-service-ats_preferences.c
- * @brief ats service, interaction with 'performance' API
+ * @brief manage preferences expressed by clients
* @author Matthias Wachs
* @author Christian Grothoff
*/
#define LOG(kind,...) GNUNET_log_from (kind, "ats-preferencesx",__VA_ARGS__)
+/**
+ *
+ */
#define PREF_AGING_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
+
+/**
+ *
+ */
#define PREF_AGING_FACTOR 0.95
+
+/**
+ *
+ */
#define PREF_EPSILON 0.01
double f_rel[GNUNET_ATS_PreferenceCount];
/**
- * Peer id
+ * Peer identity for which we have these preferences.
*/
struct GNUNET_PeerIdentity id;
};
-/**
- * FIXME
- */
-struct GAS_Addresses_Preference_Clients
-{
- /**
- * Next in DLL
- */
- struct GAS_Addresses_Preference_Clients *next;
-
- /**
- * Previous in DLL
- */
- struct GAS_Addresses_Preference_Clients *prev;
-
- /**
- * Peer ID
- */
- void *client;
-};
-
-
-/**
- * Preference requests DLL head
- */
-static struct GAS_Addresses_Preference_Clients *preference_clients_head;
-
-/**
- * Preference requests DLL head
- */
-static struct GAS_Addresses_Preference_Clients *preference_clients_tail;
-
-/**
- * Preferences clients
- */
-static int pref_clients;
-
/**
* Default values
*/
static struct PeerRelative defvalues;
-
/**
- * Preference client
+ * Preference client, information we keep track of per client.
*/
struct PreferenceClient
{
/**
- * Next in DLL
+ * Previous in DLL
*/
struct PreferenceClient *prev;
struct PreferenceClient *next;
/**
- * Client handle
+ * Head of peer list
*/
- void *client;
+ struct PreferencePeer *p_head;
/**
- * Array of sum of absolute preferences for this client
+ * Tail of peer list
*/
- double f_abs_sum[GNUNET_ATS_PreferenceCount];
+ struct PreferencePeer *p_tail;
/**
- * Array of sum of relative preferences for this client
+ * Client handle
*/
- double f_rel_sum[GNUNET_ATS_PreferenceCount];
+ struct GNUNET_SERVER_Client *client;
/**
- * Head of peer list
+ * Array of sum of absolute preferences for this client
*/
- struct PreferencePeer *p_head;
+ double f_abs_sum[GNUNET_ATS_PreferenceCount];
/**
- * Tail of peer list
+ * Array of sum of relative preferences for this client
*/
- struct PreferencePeer *p_tail;
+ double f_rel_sum[GNUNET_ATS_PreferenceCount];
};
/**
- * Preference peer
+ * Preference information per peer and client.
*/
struct PreferencePeer
{
/**
- * Next in DLL
+ * Next in DLL of preference entries for the same client.
*/
struct PreferencePeer *next;
/**
- * Previous in DLL
+ * Previous in DLL of preference entries for the same client.
*/
struct PreferencePeer *prev;
/**
- * Client
+ * Client that expressed this preferences.
*/
struct PreferenceClient *client;
/**
- * Peer id
+ * Peer identity for which the preference was expressed.
*/
struct GNUNET_PeerIdentity id;
*/
static struct PreferenceClient *pc_tail;
-
-
-static struct GNUNET_SCHEDULER_Task * aging_task;
-
-
-
-
-static struct GAS_Addresses_Preference_Clients *
-find_preference_client (struct GNUNET_SERVER_Client *client)
-{
- struct GAS_Addresses_Preference_Clients *cur;
-
- for (cur = preference_clients_head; NULL != cur; cur = cur->next)
- if (cur->client == client)
- return cur;
- return NULL;
-}
+/**
+ * Handle for task we run periodically to age preferences over time.
+ */
+static struct GNUNET_SCHEDULER_Task *aging_task;
/**
peer_count ++;
f_rel_total += p_cur->f_rel[kind];
}
-
}
}
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "%u clients have a total relative preference for peer `%s' `%s' of %.3f and for %s in total %.3f\n",
- peer_count, GNUNET_i2s (id),
- GNUNET_ATS_print_preference_type (kind),
- f_rel_total,
- GNUNET_ATS_print_preference_type (kind),
- f_rel_sum);
+ "%u clients have a total relative preference for peer `%s' `%s' of %.3f and for %s in total %.3f\n",
+ peer_count,
+ GNUNET_i2s (id),
+ GNUNET_ATS_print_preference_type (kind),
+ f_rel_total,
+ GNUNET_ATS_print_preference_type (kind),
+ f_rel_sum);
/* Find entry for the peer containing relative values in the hashmap */
if (NULL != rp)
rp->f_rel[kind] = DEFAULT_REL_PREFERENCE;
}
if (backup != rp->f_rel[kind])
- GAS_normalized_preference_changed (&rp->id, kind, rp->f_rel[kind]);
+ GAS_plugin_notify_preference_changed (&rp->id, kind,
+ rp->f_rel[kind]);
}
}
+/**
+ * FIXME
+ */
static int
update_iterator (void *cls,
const struct GNUNET_PeerIdentity *key,
}
-
/**
* Recalculate preference for a specific ATS property
*
}
-
+/**
+ * FIXME.
+ *
+ */
static void
run_preference_update (struct PreferenceClient *c_cur,
struct PreferencePeer *p_cur,
}
-
-
/**
* Reduce absolute preferences since they got old
*
* @param tc context
*/
static void
-preference_aging (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+preference_aging (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
{
struct PreferencePeer *p;
struct PreferenceClient *cur_client;
- int i;
- int values_to_update;
+ unsigned int i;
+ unsigned int values_to_update;
double backup;
aging_task = NULL;
if (values_to_update > 0)
{
- GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
- "Rescheduling aging task due to %u elements to age\n",
- values_to_update);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Rescheduling aging task due to %u elements to age\n",
+ values_to_update);
aging_task = GNUNET_SCHEDULER_add_delayed (PREF_AGING_INTERVAL,
- &preference_aging, NULL );
+ &preference_aging,
+ NULL);
}
else
- GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
- "No values to age left, not rescheduling aging task\n");
-
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "No values to age left, not rescheduling aging task\n");
+ }
}
p->f_abs[kind] = score;
/* p->f_abs[kind] = (p->f_abs[kind] + score) / 2; */
p->next_aging[kind] = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
- PREF_AGING_INTERVAL);
+ PREF_AGING_INTERVAL);
break;
case GNUNET_ATS_PREFERENCE_END:
break;
}
-
-
-
/**
- * A performance client disconnected
+ * Normalize an updated preference value
*
- * @param client the client
+ * @param client the client with this preference
+ * @param peer the peer to change the preference for
+ * @param kind the kind to change the preference
+ * @param score_abs the normalized score
*/
-void
-GAS_preference_client_disconnect (struct GNUNET_SERVER_Client *client)
+static void
+normalize_preference (struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_PeerIdentity *peer,
+ enum GNUNET_ATS_PreferenceKind kind,
+ float score_abs)
{
- struct GAS_Addresses_Preference_Clients *pc;
+ struct PreferenceClient *c_cur;
+ struct PreferencePeer *p_cur;
+ struct PeerRelative *r_cur;
+ double old_value;
+ int i;
- if (NULL != (pc = find_preference_client (client)))
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Client changes preference for peer `%s' for `%s' to %.2f\n",
+ GNUNET_i2s (peer),
+ GNUNET_ATS_print_preference_type (kind),
+ score_abs);
+
+ if (kind >= GNUNET_ATS_PreferenceCount)
{
- GNUNET_CONTAINER_DLL_remove (preference_clients_head,
- preference_clients_tail,
- pc);
- GNUNET_free (pc);
- GNUNET_assert (pref_clients > 0);
- pref_clients --;
- GNUNET_STATISTICS_set (GSA_stats,
- "# active performance clients",
- pref_clients,
- GNUNET_NO);
+ GNUNET_break(0);
+ return;
}
-}
+ /* Find preference client */
+ for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
+ if (client == c_cur->client)
+ break;
+ /* Not found: create new preference client */
+ if (NULL == c_cur)
+ {
+ c_cur = GNUNET_new (struct PreferenceClient);
+ c_cur->client = client;
+ for (i = 0; i < GNUNET_ATS_PreferenceCount; i++)
+ {
+ c_cur->f_abs_sum[i] = DEFAULT_ABS_PREFERENCE;
+ c_cur->f_rel_sum[i] = DEFAULT_REL_PREFERENCE;
+ }
+ GNUNET_CONTAINER_DLL_insert (pc_head,
+ pc_tail,
+ c_cur);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Adding new client %p\n",
+ c_cur);
+ }
-/**
- * Change the preference for a peer
- *
- * @param client the client sending this request
- * @param peer the peer id
- * @param kind the preference kind to change
- * @param score_abs the new preference score
- */
-static void
-preference_change (struct GNUNET_SERVER_Client *client,
- const struct GNUNET_PeerIdentity *peer,
- enum GNUNET_ATS_PreferenceKind kind,
- float score_abs)
-{
- struct GAS_Addresses_Preference_Clients *pc;
-
- GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
- "Received `%s' for peer `%s' for client %p\n", "CHANGE PREFERENCE",
- GNUNET_i2s (peer), client);
+ /* Find entry for peer */
+ for (p_cur = c_cur->p_head; NULL != p_cur; p_cur = p_cur->next)
+ if (0 == memcmp (&p_cur->id,
+ peer,
+ sizeof (p_cur->id)))
+ break;
- if (GNUNET_NO ==
- GNUNET_CONTAINER_multipeermap_contains (GSA_addresses,
- peer))
+ /* Not found: create new peer entry */
+ if (NULL == p_cur)
{
- GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
- "Received `%s' for unknown peer `%s' from client %p\n",
- "CHANGE PREFERENCE", GNUNET_i2s (peer), client);
- return;
+ p_cur = GNUNET_new (struct PreferencePeer);
+ p_cur->client = c_cur;
+ p_cur->id = *peer;
+ for (i = 0; i < GNUNET_ATS_PreferenceCount; i++)
+ {
+ /* Default value per peer absolute preference for a preference: 0 */
+ p_cur->f_abs[i] = DEFAULT_ABS_PREFERENCE;
+ /* Default value per peer relative preference for a quality: 1.0 */
+ p_cur->f_rel[i] = DEFAULT_REL_PREFERENCE;
+ p_cur->next_aging[i] = GNUNET_TIME_UNIT_FOREVER_ABS;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Adding new peer %p for client %p\n",
+ p_cur,
+ c_cur);
+ GNUNET_CONTAINER_DLL_insert (c_cur->p_head,
+ c_cur->p_tail,
+ p_cur);
}
- if (NULL == find_preference_client (client))
+ /* Create struct for peer */
+ if (NULL ==
+ GNUNET_CONTAINER_multipeermap_get (preference_peers,
+ peer))
{
- pc = GNUNET_new (struct GAS_Addresses_Preference_Clients);
- pc->client = client;
- GNUNET_CONTAINER_DLL_insert (preference_clients_head,
- preference_clients_tail,
- pc);
- pref_clients ++;
- GNUNET_STATISTICS_set (GSA_stats,
- "# active performance clients",
- pref_clients,
- GNUNET_NO);
+ r_cur = GNUNET_new (struct PeerRelative);
+ r_cur->id = *peer;
+ for (i = 0; i < GNUNET_ATS_PreferenceCount; i++)
+ r_cur->f_rel[i] = DEFAULT_REL_PREFERENCE;
+ GNUNET_assert(GNUNET_OK ==
+ GNUNET_CONTAINER_multipeermap_put (preference_peers,
+ &r_cur->id,
+ r_cur,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
}
- GAS_plugin_update_preferences (client, peer, kind, score_abs);
+
+ /* Update absolute value */
+ old_value = p_cur->f_abs[kind];
+ update_abs_preference (c_cur, p_cur, kind, score_abs);
+ if (p_cur->f_abs[kind] == old_value)
+ return;
+
+ GAS_plugin_solver_lock ();
+ run_preference_update (c_cur,
+ p_cur,
+ kind,
+ score_abs);
+ GAS_plugin_solver_unlock ();
+
+ if (NULL == aging_task)
+ aging_task = GNUNET_SCHEDULER_add_delayed (PREF_AGING_INTERVAL,
+ &preference_aging,
+ NULL);
}
uint32_t i;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received `%s' message\n",
- "PREFERENCE_CHANGE");
+ "Received PREFERENCE_CHANGE message\n");
msize = ntohs (message->size);
if (msize < sizeof (struct ChangePreferenceMessage))
{
1, GNUNET_NO);
pi = (const struct PreferenceInformation *) &msg[1];
for (i = 0; i < nump; i++)
- preference_change (client,
- &msg->peer,
- (enum GNUNET_ATS_PreferenceKind)
- ntohl (pi[i].preference_kind),
- pi[i].preference_value);
+ normalize_preference (client,
+ &msg->peer,
+ (enum GNUNET_ATS_PreferenceKind)
+ ntohl (pi[i].preference_kind),
+ pi[i].preference_value);
GNUNET_SERVER_receive_done (client, GNUNET_OK);
}
void
GAS_preference_done ()
{
- struct GAS_Addresses_Preference_Clients *pcur;
struct PreferenceClient *pc;
struct PreferenceClient *next_pc;
while (NULL != (pc = next_pc))
{
next_pc = pc->next;
- GNUNET_CONTAINER_DLL_remove(pc_head, pc_tail, pc);
+ GNUNET_CONTAINER_DLL_remove (pc_head,
+ pc_tail,
+ pc);
free_client (pc);
}
GNUNET_CONTAINER_multipeermap_iterate (preference_peers,
NULL);
GNUNET_CONTAINER_multipeermap_destroy (preference_peers);
- while (NULL != (pcur = preference_clients_head))
- {
- GNUNET_CONTAINER_DLL_remove (preference_clients_head,
- preference_clients_tail,
- pcur);
- GNUNET_assert (pref_clients > 0);
- pref_clients --;
- GNUNET_STATISTICS_set (GSA_stats,
- "# active performance clients",
- pref_clients,
- GNUNET_NO);
- GNUNET_free (pcur);
- }
-}
-
-
-/**
- * Normalize an updated preference value
- *
- * @param client the client with this preference
- * @param peer the peer to change the preference for
- * @param kind the kind to change the preference
- * @param score_abs the normalized score
- */
-void
-GAS_normalization_normalize_preference (struct GNUNET_SERVER_Client *client,
- const struct GNUNET_PeerIdentity *peer,
- enum GNUNET_ATS_PreferenceKind kind,
- float score_abs)
-{
- struct PreferenceClient *c_cur;
- struct PreferencePeer *p_cur;
- struct PeerRelative *r_cur;
- double old_value;
- int i;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Client changes preference for peer `%s' for `%s' to %.2f\n",
- GNUNET_i2s (peer),
- GNUNET_ATS_print_preference_type (kind),
- score_abs);
-
- if (kind >= GNUNET_ATS_PreferenceCount)
- {
- GNUNET_break(0);
- return;
- }
-
- /* Find preference client */
- for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
- {
- if (client == c_cur->client)
- break;
- }
- /* Not found: create new preference client */
- if (NULL == c_cur)
- {
- c_cur = GNUNET_new (struct PreferenceClient);
- c_cur->client = client;
- for (i = 0; i < GNUNET_ATS_PreferenceCount; i++)
- {
- c_cur->f_abs_sum[i] = DEFAULT_ABS_PREFERENCE;
- c_cur->f_rel_sum[i] = DEFAULT_REL_PREFERENCE;
- }
-
- GNUNET_CONTAINER_DLL_insert(pc_head, pc_tail, c_cur);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding new client %p \n", c_cur);
- }
-
- /* Find entry for peer */
- for (p_cur = c_cur->p_head; NULL != p_cur; p_cur = p_cur->next)
- if (0 == memcmp (&p_cur->id, peer, sizeof(p_cur->id)))
- break;
-
- /* Not found: create new peer entry */
- if (NULL == p_cur)
- {
- p_cur = GNUNET_new (struct PreferencePeer);
- p_cur->client = c_cur;
- p_cur->id = (*peer);
- for (i = 0; i < GNUNET_ATS_PreferenceCount; i++)
- {
- /* Default value per peer absolute preference for a preference: 0 */
- p_cur->f_abs[i] = DEFAULT_ABS_PREFERENCE;
- /* Default value per peer relative preference for a quality: 1.0 */
- p_cur->f_rel[i] = DEFAULT_REL_PREFERENCE;
- p_cur->next_aging[i] = GNUNET_TIME_UNIT_FOREVER_ABS;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding new peer %p for client %p \n",
- p_cur, c_cur);
- GNUNET_CONTAINER_DLL_insert(c_cur->p_head, c_cur->p_tail, p_cur);
- }
-
- /* Create struct for peer */
- if (NULL == GNUNET_CONTAINER_multipeermap_get (preference_peers, peer))
- {
- r_cur = GNUNET_new (struct PeerRelative);
- r_cur->id = (*peer);
- for (i = 0; i < GNUNET_ATS_PreferenceCount; i++)
- r_cur->f_rel[i] = DEFAULT_REL_PREFERENCE;
- GNUNET_assert(
- GNUNET_OK == GNUNET_CONTAINER_multipeermap_put (preference_peers,
- &r_cur->id, r_cur, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
- }
-
- /* Update absolute value */
- old_value = p_cur->f_abs[kind];
- update_abs_preference (c_cur, p_cur, kind, score_abs);
- if (p_cur->f_abs[kind] == old_value)
- return;
-
- run_preference_update (c_cur, p_cur, kind, score_abs);
-
- /* Start aging task */
- if (NULL == aging_task)
- aging_task = GNUNET_SCHEDULER_add_delayed (PREF_AGING_INTERVAL,
- &preference_aging,
- NULL);
-
}
* default preferences if peer does not exist
*/
const double *
-GAS_normalization_get_preferences_by_peer (void *cls,
- const struct GNUNET_PeerIdentity *id)
+GAS_preference_get_by_peer (void *cls,
+ const struct GNUNET_PeerIdentity *id)
{
- GNUNET_assert(NULL != preference_peers);
- GNUNET_assert(NULL != id);
-
struct PeerRelative *rp;
- if (NULL == (rp = GNUNET_CONTAINER_multipeermap_get (preference_peers, id)))
+
+ if (NULL ==
+ (rp = GNUNET_CONTAINER_multipeermap_get (preference_peers,
+ id)))
{
return defvalues.f_rel;
}
* @param client the client
*/
void
-GAS_normalization_preference_client_disconnect (struct GNUNET_SERVER_Client *client)
+GAS_preference_client_disconnect (struct GNUNET_SERVER_Client *client)
{
struct PreferenceClient *c_cur;
- /* Find preference client */
for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
- {
if (client == c_cur->client)
break;
- }
if (NULL == c_cur)
return;
-
- GNUNET_CONTAINER_DLL_remove(pc_head, pc_tail, c_cur);
+ GNUNET_CONTAINER_DLL_remove (pc_head,
+ pc_tail,
+ c_cur);
free_client (c_cur);
}
+
+
+/* end of gnunet-service-ats_preferences.c */