#include "gnunet_statistics_service.h"
#include "glpk.h"
+#define LOG(kind,...) GNUNET_log_from (kind, "ats-mlp",__VA_ARGS__)
+
#define WRITE_MLP GNUNET_NO
#define DEBUG_ATS GNUNET_NO
#define VERBOSE_GLPK GNUNET_NO
switch (retcode) {
case 0:
return "ok";
- break;
case GLP_EBADB:
return "invalid basis";
- break;
case GLP_ESING:
return "singular matrix";
- break;
case GLP_ECOND:
return "ill-conditioned matrix";
- break;
case GLP_EBOUND:
return "invalid bounds";
- break;
case GLP_EFAIL:
return "solver failed";
- break;
case GLP_EOBJLL:
return "objective lower limit reached";
- break;
case GLP_EOBJUL:
return "objective upper limit reached";
- break;
case GLP_EITLIM:
return "iteration limit exceeded";
- break;
case GLP_ETMLIM:
return "time limit exceeded";
- break;
case GLP_ENOPFS:
return "no primal feasible solution";
- break;
case GLP_EROOT:
return "root LP optimum not provided";
- break;
case GLP_ESTOP:
return "search terminated by application";
- break;
case GLP_EMIPGAP:
return "relative mip gap tolerance reached";
- break;
case GLP_ENOFEAS:
return "no dual feasible solution";
- break;
case GLP_ENOCVG:
return "no convergence";
- break;
case GLP_EINSTAB:
return "numerical instability";
- break;
case GLP_EDATA:
return "invalid data";
- break;
case GLP_ERANGE:
return "result out of range";
- break;
default:
GNUNET_break (0);
return "unknown error";
- break;
}
- GNUNET_break (0);
- return "unknown error";
}
switch (retcode) {
case GLP_UNDEF:
return "solution is undefined";
- break;
case GLP_FEAS:
return "solution is feasible";
- break;
case GLP_INFEAS:
return "solution is infeasible";
- break;
case GLP_NOFEAS:
return "no feasible solution exists";
- break;
case GLP_OPT:
return "solution is optimal";
- break;
case GLP_UNBND:
return "solution is unbounded";
- break;
default:
GNUNET_break (0);
return "unknown error";
- break;
}
- GNUNET_break (0);
- return "unknown error";
}
/**
switch (ats_index) {
case GNUNET_ATS_ARRAY_TERMINATOR:
return "GNUNET_ATS_ARRAY_TERMINATOR";
- break;
case GNUNET_ATS_UTILIZATION_UP:
return "GNUNET_ATS_UTILIZATION_UP";
- break;
case GNUNET_ATS_UTILIZATION_DOWN:
return "GNUNET_ATS_UTILIZATION_DOWN";
- break;
case GNUNET_ATS_COST_LAN:
return "GNUNET_ATS_COST_LAN";
- break;
case GNUNET_ATS_COST_WAN:
return "GNUNET_ATS_COST_LAN";
- break;
case GNUNET_ATS_COST_WLAN:
return "GNUNET_ATS_COST_WLAN";
- break;
case GNUNET_ATS_NETWORK_TYPE:
return "GNUNET_ATS_NETWORK_TYPE";
- break;
case GNUNET_ATS_QUALITY_NET_DELAY:
return "GNUNET_ATS_QUALITY_NET_DELAY";
- break;
case GNUNET_ATS_QUALITY_NET_DISTANCE:
return "GNUNET_ATS_QUALITY_NET_DISTANCE";
- break;
default:
+ GNUNET_break (0);
return "unknown";
- break;
}
- GNUNET_break (0);
- return "unknown error";
}
/**
* @return GNUNET_OK to continue
*/
static int
-create_constraint_it (void *cls, const GNUNET_HashCode * key, void *value)
+create_constraint_it (void *cls, const struct GNUNET_HashCode * key, void *value)
{
struct GAS_MLP_Handle *mlp = cls;
struct ATS_Address *address = value;
unsigned int row_index;
char *name;
- GNUNET_assert (address->mlp_information != NULL);
- mlpi = (struct MLP_information *) address->mlp_information;
+ GNUNET_assert (address->solver_information != NULL);
+ mlpi = (struct MLP_information *) address->solver_information;
/* c 1) bandwidth capping
* b_t + (-M) * n_t <= 0
return GNUNET_OK;
}
+#if 0
/**
* Find the required ATS information for an address
*
*
* @return the index on success, otherwise GNUNET_SYSERR
*/
-
static int
mlp_lookup_ats (struct ATS_Address *addr, int ats_index)
{
else
return GNUNET_SYSERR;
}
+#endif
/**
* Adds the problem constraints for all addresses
* c 10) obey network specific quota
*/
+ /* Row for c4) minimum connection */
int min = mlp->n_min;
+ /* Number of minimum connections is min(|Peers|, n_min) */
if (mlp->n_min > mlp->c_p)
min = mlp->c_p;
mlp->ci++;
struct ATS_Peer * peer = mlp->peer_head;
+ /* For all peers */
while (peer != NULL)
{
struct ATS_Address *addr = peer->head;
/* Set -r */
ia[mlp->ci] = peer->r_c9;
ja[mlp->ci] = mlp->c_r;
- ar[mlp->ci] = -1;
+ ar[mlp->ci] = -peer->f;
mlp->ci++;
#endif
-
+ /* For all addresses of this peer */
while (addr != NULL)
{
- mlpi = (struct MLP_information *) addr->mlp_information;
+ mlpi = (struct MLP_information *) addr->solver_information;
/* coefficient for c 2) */
-
ia[mlp->ci] = peer->r_c2;
ja[mlp->ci] = mlpi->c_n;
ar[mlp->ci] = 1;
}
/* c 7) For all quality metrics */
-
-
for (c = 0; c < mlp->m_q; c++)
{
struct ATS_Peer *tp;
glp_set_row_name (mlp->prob, mlp->r_q[c], name);
GNUNET_free (name);
/* Set row bound == 0 */
- glp_set_row_bnds (mlp->prob, mlp->r_q[c], GLP_LO, 0.0, 0.0);
+ glp_set_row_bnds (mlp->prob, mlp->r_q[c], GLP_FX, 0.0, 0.0);
ia[mlp->ci] = mlp->r_q[c];
ja[mlp->ci] = mlp->c_q[c];
for (tp = mlp->peer_head; tp != NULL; tp = tp->next)
for (ta = tp->head; ta != NULL; ta = ta->next)
{
- mlpi = ta->mlp_information;
+ mlpi = ta->solver_information;
value = mlpi->q_averaged[c];
mlpi->r_q[c] = mlp->r_q[c];
ia[mlp->ci] = mlp->r_q[c];
ja[mlp->ci] = mlpi->c_b;
- ar[mlp->ci] = tp->f * value;
+ ar[mlp->ci] = tp->f_q[c] * value;
mlp->ci++;
}
}
* @return GNUNET_OK to continue
*/
static int
-create_columns_it (void *cls, const GNUNET_HashCode * key, void *value)
+create_columns_it (void *cls, const struct GNUNET_HashCode * key, void *value)
{
struct GAS_MLP_Handle *mlp = cls;
struct ATS_Address *address = value;
unsigned int col;
char *name;
- GNUNET_assert (address->mlp_information != NULL);
- mlpi = address->mlp_information;
+ GNUNET_assert (address->solver_information != NULL);
+ mlpi = address->solver_information;
/* Add bandwidth column */
col = glp_add_cols (mlp->prob, 2);
/* Adding invariant columns */
/* Diversity d column */
-
col = glp_add_cols (mlp->prob, 1);
mlp->c_d = col;
/* Column name */
glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0);
/* Utilization u column */
-
col = glp_add_cols (mlp->prob, 1);
mlp->c_u = col;
/* Column name */
return res;
}
+
/**
* Solves the LP problem
*
* @param mlp the MLP Handle
+ * @param s_ctx context to return results
* @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
*/
static int
-mlp_solve_lp_problem (struct GAS_MLP_Handle *mlp)
+mlp_solve_lp_problem (struct GAS_MLP_Handle *mlp, struct GAS_MLP_SolutionContext *s_ctx)
{
int res;
struct GNUNET_TIME_Relative duration;
end = GNUNET_TIME_absolute_get ();
duration = GNUNET_TIME_absolute_get_difference (start, end);
mlp->lp_solved++;
- mlp->lp_total_duration =+ duration.rel_value;
+ mlp->lp_total_duration += duration.rel_value;
+ s_ctx->lp_duration = duration;
GNUNET_STATISTICS_update (mlp->stats,"# LP problem solved", 1, GNUNET_NO);
- GNUNET_STATISTICS_set (mlp->stats,"# LP execution time", duration.rel_value, GNUNET_NO);
- GNUNET_STATISTICS_set (mlp->stats,"# LP execution time average",
+ GNUNET_STATISTICS_set (mlp->stats,"# LP execution time (ms)", duration.rel_value, GNUNET_NO);
+ GNUNET_STATISTICS_set (mlp->stats,"# LP execution time average (ms)",
mlp->lp_total_duration / mlp->lp_solved, GNUNET_NO);
-
/* Analyze problem status */
res = glp_get_status (mlp->prob);
switch (res) {
* Solves the MLP problem
*
* @param mlp the MLP Handle
+ * @param s_ctx context to return results
* @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
*/
int
-mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp)
+mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp, struct GAS_MLP_SolutionContext *s_ctx)
{
int res;
struct GNUNET_TIME_Relative duration;
end = GNUNET_TIME_absolute_get ();
duration = GNUNET_TIME_absolute_get_difference (start, end);
mlp->mlp_solved++;
- mlp->mlp_total_duration =+ duration.rel_value;
+ mlp->mlp_total_duration += duration.rel_value;
+ s_ctx->mlp_duration = duration;
GNUNET_STATISTICS_update (mlp->stats,"# MLP problem solved", 1, GNUNET_NO);
- GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time", duration.rel_value, GNUNET_NO);
- GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time average",
+ GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time (ms)", duration.rel_value, GNUNET_NO);
+ GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time average (ms)",
mlp->mlp_total_duration / mlp->mlp_solved, GNUNET_NO);
/* Analyze problem status */
return GNUNET_OK;
}
-int GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp);
+int GAS_mlp_solve_problem (void *solver, struct GAS_MLP_SolutionContext *ctx);
+
static void
mlp_scheduler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
struct GAS_MLP_Handle *mlp = cls;
+ struct GAS_MLP_SolutionContext ctx;
mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
return;
-
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scheduled problem solving\n");
if (mlp->addr_in_problem != 0)
- GAS_mlp_solve_problem(mlp);
+ GAS_mlp_solve_problem(mlp, &ctx);
}
/**
* Solves the MLP problem
*
- * @param mlp the MLP Handle
+ * @param solver the MLP Handle
+ * @param ctx solution context
* @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
*/
int
-GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp)
+GAS_mlp_solve_problem (void *solver, struct GAS_MLP_SolutionContext *ctx)
{
+ struct GAS_MLP_Handle *mlp = solver;
int res;
- mlp->last_execution = GNUNET_TIME_absolute_get ();
+ /* Check if solving is already running */
+ if (GNUNET_YES == mlp->semaphore)
+ {
+ if (mlp->mlp_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel(mlp->mlp_task);
+ mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ mlp->mlp_task = GNUNET_SCHEDULER_add_delayed (mlp->exec_interval, &mlp_scheduler, mlp);
+ return GNUNET_SYSERR;
+ }
+ mlp->semaphore = GNUNET_YES;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem solving\n");
+ mlp->last_execution = GNUNET_TIME_absolute_get ();
+ ctx->lp_result = GNUNET_SYSERR;
+ ctx->mlp_result = GNUNET_SYSERR;
+ ctx->lp_duration = GNUNET_TIME_UNIT_FOREVER_REL;
+ ctx->mlp_duration = GNUNET_TIME_UNIT_FOREVER_REL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Solve LP problem\n");
#if WRITE_MLP
char * name;
static int i;
GNUNET_free (name);
# endif
- res = mlp_solve_lp_problem (mlp);
+ res = mlp_solve_lp_problem (mlp, ctx);
+ ctx->lp_result = res;
+ if (res != GNUNET_OK)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "LP Problem solving failed\n");
+ mlp->semaphore = GNUNET_NO;
+ return GNUNET_SYSERR;
+ }
#if WRITE_MLP
GNUNET_asprintf(&name, "problem_%i_lp_solution", i);
GNUNET_free (name);
# endif
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Solve MLP problem\n");
+ res = mlp_solve_mlp_problem (mlp, ctx);
+ ctx->mlp_result = res;
if (res != GNUNET_OK)
{
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "LP Problem solving failed\n");
-
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP Problem solving failed\n");
+ mlp->semaphore = GNUNET_NO;
return GNUNET_SYSERR;
}
-
- res = mlp_solve_mlp_problem (mlp);
-
#if WRITE_MLP
GNUNET_asprintf(&name, "problem_%i_mlp_solution", i);
glp_print_mip (mlp->prob, name);
GNUNET_free (name);
# endif
- if (res != GNUNET_OK)
- {
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MLP Problem solving failed\n");
- return GNUNET_SYSERR;
- }
-
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem solved\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem solved %s (LP duration %llu / MLP duration %llu)\n",
+ (GNUNET_OK == res) ? "successfully" : "failed", ctx->lp_duration.rel_value, ctx->mlp_duration.rel_value);
/* Process result */
struct ATS_Peer *p = NULL;
struct ATS_Address *a = NULL;
double b = 0.0;
double n = 0.0;
- mlpi = a->mlp_information;
+ mlpi = a->solver_information;
b = glp_mip_col_val(mlp->prob, mlpi->c_b);
mlpi->b = b;
mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
}
mlp->mlp_task = GNUNET_SCHEDULER_add_delayed (mlp->exec_interval, &mlp_scheduler, mlp);
+ mlp->semaphore = GNUNET_NO;
return res;
}
*
* @param cfg the GNUNET_CONFIGURATION_Handle handle
* @param stats the GNUNET_STATISTICS handle
- * @param max_duration maximum numbers of iterations for the LP/MLP Solver
- * @param max_iterations maximum time limit for the LP/MLP Solver
- * @return struct GAS_MLP_Handle * on success, NULL on fail
+ * @param network array of GNUNET_ATS_NetworkType with length dest_length
+ * @param out_dest array of outbound quotas
+ * @param in_dest array of outbound quota
+ * @param dest_length array length for quota arrays
+ * @param bw_changed_cb callback for changed bandwidth amounts
+ * @param bw_changed_cb_cls cls for callback
+ * @return struct GAS_MLP_Handle on success, NULL on fail
*/
-struct GAS_MLP_Handle *
+void *
GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
const struct GNUNET_STATISTICS_Handle *stats,
- struct GNUNET_TIME_Relative max_duration,
- unsigned int max_iterations)
+ int *network,
+ unsigned long long *out_dest,
+ unsigned long long *in_dest,
+ int dest_length,
+ GAS_bandwidth_changed_cb bw_changed_cb,
+ void *bw_changed_cb_cls)
{
struct GAS_MLP_Handle * mlp = GNUNET_malloc (sizeof (struct GAS_MLP_Handle));
double D;
double R;
double U;
- long long unsigned int tmp;
+ unsigned long long tmp;
unsigned int b_min;
unsigned int n_min;
struct GNUNET_TIME_Relative i_exec;
int c;
+ int c2;
+ int found;
+
+ struct GNUNET_TIME_Relative max_duration;
+ long long unsigned int max_iterations;
/* Init GLPK environment */
- GNUNET_assert (glp_init_env() == 0);
+ int res = glp_init_env();
+ switch (res) {
+ case 0:
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n",
+ "initialization successful");
+ break;
+ case 1:
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n",
+ "environment is already initialized");
+ break;
+ case 2:
+ LOG (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n",
+ "initialization failed (insufficient memory)");
+ GNUNET_free(mlp);
+ return NULL;
+ break;
+ case 3:
+ LOG (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n",
+ "initialization failed (unsupported programming model)");
+ GNUNET_free(mlp);
+ return NULL;
+ break;
+ default:
+ break;
+ }
/* Create initial MLP problem */
mlp->prob = glp_create_prob();
- GNUNET_assert (mlp->prob != NULL);
+ if (NULL == mlp->prob)
+ {
+ GNUNET_assert (mlp->prob != NULL);
+ }
+
+ mlp->BIG_M = (double) BIG_M_VALUE;
+
+ /* Get timeout for iterations */
+ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time(cfg, "ats", "MLP_MAX_DURATION", &max_duration))
+ {
+ max_duration = MLP_MAX_EXEC_DURATION;
+ }
- mlp->BIG_M = (double) (UINT32_MAX) /10;
+ /* Get maximum number of iterations */
+ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_size(cfg, "ats", "MLP_MAX_ITERATIONS", &max_iterations))
+ {
+ max_iterations = MLP_MAX_ITERATIONS;
+ }
/* Get diversity coefficient from configuration */
if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
- "COEFFICIENT_D",
+ "MLP_COEFFICIENT_D",
&tmp))
D = (double) tmp / 100;
else
- D = 1.0;
+ D = DEFAULT_D;
/* Get proportionality coefficient from configuration */
if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
- "COEFFICIENT_R",
+ "MLP_COEFFICIENT_R",
&tmp))
R = (double) tmp / 100;
else
- R = 1.0;
+ R = DEFAULT_R;
/* Get utilization coefficient from configuration */
if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
- "COEFFICIENT_U",
+ "MLP_COEFFICIENT_U",
&tmp))
U = (double) tmp / 100;
else
- U = 1.0;
+ U = DEFAULT_U;
/* Get quality metric coefficients from configuration */
- int i_delay = -1;
- int i_distance = -1;
+ int i_delay = NaN;
+ int i_distance = NaN;
int q[GNUNET_ATS_QualityPropertiesCount] = GNUNET_ATS_QualityProperties;
for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
{
/* initialize quality coefficients with default value 1.0 */
- mlp->co_Q[c] = 1.0;
+ mlp->co_Q[c] = DEFAULT_QUALITY;
mlp->q[c] = q[c];
if (q[c] == GNUNET_ATS_QUALITY_NET_DELAY)
i_distance = c;
}
- if ((i_delay != -1) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
- "COEFFICIENT_QUALITY_DELAY",
+ if ((i_delay != NaN) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
+ "MLP_COEFFICIENT_QUALITY_DELAY",
&tmp)))
mlp->co_Q[i_delay] = (double) tmp / 100;
else
- mlp->co_Q[i_delay] = 1.0;
+ mlp->co_Q[i_delay] = DEFAULT_QUALITY;
- if ((i_distance != -1) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
- "COEFFICIENT_QUALITY_DISTANCE",
+ if ((i_distance != NaN) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
+ "MLP_COEFFICIENT_QUALITY_DISTANCE",
&tmp)))
mlp->co_Q[i_distance] = (double) tmp / 100;
else
- mlp->co_Q[i_distance] = 1.0;
+ mlp->co_Q[i_distance] = DEFAULT_QUALITY;
/* Get minimum bandwidth per used address from configuration */
if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
- "MIN_BANDWIDTH",
+ "MLP_MIN_BANDWIDTH",
&tmp))
b_min = tmp;
else
/* Get minimum number of connections from configuration */
if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
- "MIN_CONNECTIONS",
+ "MLP_MIN_CONNECTIONS",
&tmp))
n_min = tmp;
else
- n_min = 4;
+ n_min = DEFAULT_MIN_CONNECTIONS;
/* Init network quotas */
int quotas[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
{
- mlp->quota_index[c] = quotas[c];
- static char * entry_in = NULL;
- static char * entry_out = NULL;
- unsigned long long quota_in = 0;
- unsigned long long quota_out = 0;
-
- switch (quotas[c]) {
- case GNUNET_ATS_NET_UNSPECIFIED:
- entry_out = "UNSPECIFIED_QUOTA_OUT";
- entry_in = "UNSPECIFIED_QUOTA_IN";
- break;
- case GNUNET_ATS_NET_LOOPBACK:
- entry_out = "LOOPBACK_QUOTA_OUT";
- entry_in = "LOOPBACK_QUOTA_IN";
- break;
- case GNUNET_ATS_NET_LAN:
- entry_out = "LAN_QUOTA_OUT";
- entry_in = "LAN_QUOTA_IN";
- break;
- case GNUNET_ATS_NET_WAN:
- entry_out = "WAN_QUOTA_OUT";
- entry_in = "WAN_QUOTA_IN";
- break;
- case GNUNET_ATS_NET_WLAN:
- entry_out = "WLAN_QUOTA_OUT";
- entry_in = "WLAN_QUOTA_IN";
- break;
- default:
- break;
- }
-
- if ((entry_in == NULL) || (entry_out == NULL))
- continue;
+ found = GNUNET_NO;
+ for (c2 = 0; c2 < dest_length; c2++)
+ {
+ if (quotas[c] == network[c2])
+ {
+ mlp->quota_index[c] = network[c2];
+ mlp->quota_out[c] = out_dest[c2];
+ mlp->quota_in[c] = in_dest[c2];
+ found = GNUNET_YES;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Quota for network `%s' (in/out) %llu/%llu\n",
+ GNUNET_ATS_print_network_type(mlp->quota_index[c]),
+ mlp->quota_out[c],
+ mlp->quota_in[c]);
+ break;
+ }
+ }
+
+ /* Check if defined quota could make problem unsolvable */
+ if ((n_min * b_min) > mlp->quota_out[c])
+ {
+ LOG (GNUNET_ERROR_TYPE_INFO, _("Adjusting inconsistent outbound quota configuration for network `%s', is %llu must be at least %llu\n"),
+ GNUNET_ATS_print_network_type(mlp->quota_index[c]),
+ mlp->quota_out[c],
+ (n_min * b_min));
+ mlp->quota_out[c] = (n_min * b_min);
+ }
+ if ((n_min * b_min) > mlp->quota_in[c])
+ {
+ LOG (GNUNET_ERROR_TYPE_INFO, _("Adjusting inconsistent inbound quota configuration for network `%s', is %llu must be at least %llu\n"),
+ GNUNET_ATS_print_network_type(mlp->quota_index[c]),
+ mlp->quota_in[c],
+ (n_min * b_min));
+ mlp->quota_in[c] = (n_min * b_min);
+ }
- if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", entry_out, "a_out))
- {
- quota_out = mlp->BIG_M;
- }
- if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", entry_in, "a_in))
- {
- quota_in = mlp->BIG_M;
- }
- /* Check if defined quota could make problem unsolvable */
- if ((n_min * b_min) > quota_out)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Inconsistent quota configuration value `%s': " \
- "outbound quota (%u Bps) too small for combination of minimum connections and minimum bandwidth per peer (%u * %u Bps = %u)\n", entry_out, quota_out, n_min, b_min, n_min * b_min);
- unsigned int default_min = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
- if ((quota_out / n_min) > default_min)
+ /* Check if bandwidth is too big to make problem solvable */
+ if (mlp->BIG_M < mlp->quota_out[c])
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Reducing minimum bandwidth per peer to %u Bps\n",
- (quota_out / n_min));
- b_min = (quota_out / n_min);
+ LOG (GNUNET_ERROR_TYPE_INFO, _("Adjusting outbound quota configuration for network `%s'from %llu to %.0f\n"),
+ GNUNET_ATS_print_network_type(mlp->quota_index[c]),
+ mlp->quota_out[c],
+ mlp->BIG_M);
+ mlp->quota_out[c] = mlp->BIG_M;
}
- else
+ if (mlp->BIG_M < mlp->quota_in[c])
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Reducing minimum bandwidth per peer to %u Bps and minimum connections to %u \n",
- default_min, (quota_out / default_min));
- b_min = default_min;
- n_min = (quota_out / default_min);
+ LOG (GNUNET_ERROR_TYPE_INFO, _("Adjusting inbound quota configuration for network `%s' from %llu to %.0f\n"),
+ GNUNET_ATS_print_network_type(mlp->quota_index[c]),
+ mlp->quota_in[c],
+ mlp->BIG_M);
+ mlp->quota_in[c] = mlp->BIG_M;
}
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found `%s' quota %llu and `%s' quota %llu\n",
- entry_out, quota_out, entry_in, quota_in);
- mlp->quota_out[c] = quota_out;
- mlp->quota_in[c] = quota_in;
+ if (GNUNET_NO == found)
+ {
+ mlp->quota_in[c] = ntohl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
+ mlp->quota_out[c] = ntohl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
+ LOG (GNUNET_ERROR_TYPE_INFO, _("Using default quota configuration for network `%s' (in/out) %llu/%llu\n"),
+ GNUNET_ATS_print_network_type(mlp->quota_index[c]),
+ mlp->quota_in[c],
+ mlp->quota_out[c]);
+ }
}
/* Get minimum number of connections from configuration */
else
mlp->exec_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30);
+
+ /* Assign options to handle */
mlp->stats = (struct GNUNET_STATISTICS_Handle *) stats;
mlp->max_iterations = max_iterations;
mlp->max_exec_duration = max_duration;
#endif
mlp->control_param_mlp.tm_lim = max_duration.rel_value;
- mlp->last_execution = GNUNET_TIME_absolute_get_forever();
+ mlp->last_execution = GNUNET_TIME_UNIT_FOREVER_ABS;
mlp->co_D = D;
mlp->co_R = R;
mlp->b_min = b_min;
mlp->n_min = n_min;
mlp->m_q = GNUNET_ATS_QualityPropertiesCount;
+ mlp->semaphore = GNUNET_NO;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "solver ready\n");
return mlp;
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating quality metrics for peer `%s'\n",
GNUNET_i2s (&address->peer));
- struct MLP_information *mlpi = address->mlp_information;
- struct GNUNET_ATS_Information *ats = address->ats;
+ GNUNET_assert (NULL != address);
+ GNUNET_assert (NULL != address->solver_information);
+// GNUNET_assert (NULL != address->ats);
+
+ struct MLP_information *mlpi = address->solver_information;
+ //struct GNUNET_ATS_Information *ats = address->ats;
GNUNET_assert (mlpi != NULL);
int c;
-
for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
{
- int index = mlp_lookup_ats(address, mlp->q[c]);
+
+ /* FIXME int index = mlp_lookup_ats(address, mlp->q[c]); */
+ int index = GNUNET_SYSERR;
if (index == GNUNET_SYSERR)
continue;
-
+ /* FIXME
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating address for peer `%s' value `%s': %f\n",
GNUNET_i2s (&address->peer),
mlp_ats_to_string(mlp->q[c]),
(double) ats[index].value);
- int i = mlpi->q_avg_i[c];
+ int i = mlpi->q_avg_i[c];*/
double * qp = mlpi->q[c];
+ /* FIXME
qp[i] = (double) ats[index].value;
+ */
int t;
for (t = 0; t < MLP_AVERAGING_QUEUE_LENGTH; t++)
c3 ++;
}
}
- if (c3 > 0)
+ if ((c3 > 0) && (avg > 0))
/* avg = 1 / ((q[0] + ... + q[l]) /c3) => c3 / avg*/
mlpi->q_averaged[c] = (double) c3 / avg;
else
c3 ++;
}
}
- if (c3 > 0)
+ if ((c3 > 0) && (avg > 0))
/* avg = 1 / ((q[0] + ... + q[l]) /c3) => c3 / avg*/
mlpi->q_averaged[c] = (double) c3 / avg;
else
}
}
+
+/**
+ * Add a single address to the solve
+ *
+ * @param solver the solver Handle
+ * @param addresses the address hashmap containing all addresses
+ * @param address the address to add
+ */
+void
+GAS_mlp_address_add (void *solver, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding address for peer `%s'\n", GNUNET_i2s(&address->peer));
+}
+
/**
* Updates a single address in the MLP problem
*
* Otherwise the addresses' values can be updated and the existing base can
* be reused
*
- * @param mlp the MLP Handle
- * @param addresses the address hashmap
- * the address has to be already removed from the hashmap
- * @param address the address to update
+ * @param solver the solver Handle
+ * @param addresses the address hashmap containing all addresses
+ * @param address the update address
+ * @param session the new session (if changed otherwise current)
+ * @param in_use the new address in use state (if changed otherwise current)
+ * @param atsi the latest ATS information
+ * @param atsi_count the atsi count
*/
void
-GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
+GAS_mlp_address_update (void *solver,
+ struct GNUNET_CONTAINER_MultiHashMap *addresses,
+ struct ATS_Address *address,
+ uint32_t session,
+ int in_use,
+ const struct GNUNET_ATS_Information *atsi,
+ uint32_t atsi_count)
{
+ struct GAS_MLP_Handle *mlp = solver;
int new;
struct MLP_information *mlpi;
+ struct GAS_MLP_SolutionContext ctx;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Updating address for peer `%s'\n", GNUNET_i2s(&address->peer));
- GNUNET_STATISTICS_update (mlp->stats,"# LP address updates", 1, GNUNET_NO);
+ GNUNET_STATISTICS_update (mlp->stats, "# MLP address updates", 1, GNUNET_NO);
/* We add a new address */
- if (address->mlp_information == NULL)
+ if (address->solver_information == NULL)
new = GNUNET_YES;
else
new = GNUNET_NO;
mlpi->q_averaged[c] = 0.0;
}
- address->mlp_information = mlpi;
+ address->solver_information = mlpi;
mlp->addr_in_problem ++;
+ GNUNET_STATISTICS_update (mlp->stats, "# addresses in MLP", 1, GNUNET_NO);
/* Check for and add peer */
struct ATS_Peer *peer = mlp_find_peer (mlp, &address->peer);
GNUNET_CONTAINER_DLL_insert (peer->head, peer->tail, address);
GNUNET_CONTAINER_DLL_insert (mlp->peer_head, mlp->peer_tail, peer);
mlp->c_p ++;
+ GNUNET_STATISTICS_update (mlp->stats, "# peers in MLP", 1, GNUNET_NO);
}
else
{
GNUNET_CONTAINER_DLL_insert (peer->head, peer->tail, address);
}
-
update_quality (mlp, address);
}
else
mlp->presolver_required = GNUNET_YES;
}
if (mlp->auto_solve == GNUNET_YES)
- GAS_mlp_solve_problem (mlp);
+ GAS_mlp_solve_problem (mlp, &ctx);
}
/**
*
* The MLP problem has to be recreated and the problem has to be resolved
*
- * @param mlp the MLP Handle
+ * @param solver the MLP Handle
* @param addresses the address hashmap
* the address has to be already removed from the hashmap
* @param address the address to delete
+ * @param session_only delete only session not whole address
*/
void
-GAS_mlp_address_delete (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
+GAS_mlp_address_delete (void *solver,
+ struct GNUNET_CONTAINER_MultiHashMap * addresses,
+ struct ATS_Address *address,
+ int session_only)
{
+ struct GAS_MLP_Handle *mlp = solver;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Deleting address for peer `%s'\n", GNUNET_i2s(&address->peer));
GNUNET_STATISTICS_update (mlp->stats,"# LP address deletions", 1, GNUNET_NO);
+ struct GAS_MLP_SolutionContext ctx;
/* Free resources */
- if (address->mlp_information != NULL)
+ if (address->solver_information != NULL)
{
- GNUNET_free (address->mlp_information);
- address->mlp_information = NULL;
+ GNUNET_free (address->solver_information);
+ address->solver_information = NULL;
mlp->addr_in_problem --;
+ GNUNET_STATISTICS_update (mlp->stats, "# addresses in MLP", -1, GNUNET_NO);
}
/* Remove from peer list */
GNUNET_CONTAINER_DLL_remove (mlp->peer_head, mlp->peer_tail, head);
GNUNET_free (head);
mlp->c_p --;
+ GNUNET_STATISTICS_update (mlp->stats, "# peers in MLP", -1, GNUNET_NO);
}
/* Update problem */
/* Recalculate */
mlp->presolver_required = GNUNET_YES;
if (mlp->auto_solve == GNUNET_YES)
- GAS_mlp_solve_problem (mlp);
+ GAS_mlp_solve_problem (mlp, &ctx);
}
}
static int
-mlp_get_preferred_address_it (void *cls, const GNUNET_HashCode * key, void *value)
+mlp_get_preferred_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
{
- struct ATS_PreferedAddress *aa = (struct ATS_PreferedAddress *) cls;
+ struct ATS_Address *aa = (struct ATS_Address *) cls;
struct ATS_Address *addr = value;
- struct MLP_information *mlpi = addr->mlp_information;
+ struct MLP_information *mlpi = addr->solver_information;
if (mlpi == NULL)
return GNUNET_YES;
if (mlpi->n == GNUNET_YES)
{
- aa->address = addr;
+ aa = addr;
if (mlpi->b > (double) UINT32_MAX)
- aa->bandwidth_out = UINT32_MAX;
+ aa->assigned_bw_out.value__ = htonl (UINT32_MAX);
else
- aa->bandwidth_out = (uint32_t) mlpi->b;
- aa->bandwidth_in = 0;
+ aa->assigned_bw_out.value__ = htonl((uint32_t) mlpi->b);
+ aa->assigned_bw_in.value__ = htonl(0);
return GNUNET_NO;
}
return GNUNET_YES;
/**
* Get the preferred address for a specific peer
*
- * @param mlp the MLP Handle
+ * @param solver the MLP Handle
* @param addresses address hashmap
* @param peer the peer
* @return suggested address
*/
-struct ATS_PreferedAddress *
-GAS_mlp_get_preferred_address (struct GAS_MLP_Handle *mlp,
+const struct ATS_Address *
+GAS_mlp_get_preferred_address (void *solver,
struct GNUNET_CONTAINER_MultiHashMap * addresses,
const struct GNUNET_PeerIdentity *peer)
{
- struct ATS_PreferedAddress * aa = GNUNET_malloc (sizeof (struct ATS_PreferedAddress));
- aa->address = NULL;
- aa->bandwidth_in = 0;
- aa->bandwidth_out = 0;
+ struct ATS_Address * aa = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting preferred address for `%s'\n", GNUNET_i2s (peer));
GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey, mlp_get_preferred_address_it, aa);
return aa;
/**
* Changes the preferences for a peer in the MLP problem
*
- * @param mlp the MLP Handle
+ * @param solver the MLP Handle
+ * @param client client
* @param peer the peer
* @param kind the kind to change the preference
* @param score the score
*/
void
-GAS_mlp_address_change_preference (struct GAS_MLP_Handle *mlp,
+GAS_mlp_address_change_preference (void *solver,
+ void *client,
const struct GNUNET_PeerIdentity *peer,
enum GNUNET_ATS_PreferenceKind kind,
float score)
{
+ struct GAS_MLP_Handle *mlp = solver;
GNUNET_STATISTICS_update (mlp->stats,"# LP address preference changes", 1, GNUNET_NO);
- struct ATS_Peer *p = mlp_find_peer (mlp, peer);
- p = p;
+ //struct ATS_Peer *p = mlp_find_peer (mlp, peer);
+ //FIXME to finish implementation
/* Here we have to do the matching */
+
}
/**
* Shutdown the MLP problem solving component
- * @param mlp the MLP handle
+ *
+ * @param solver the solver handle
*/
void
-GAS_mlp_done (struct GAS_MLP_Handle *mlp)
+GAS_mlp_done (void *solver)
{
+ struct GAS_MLP_Handle *mlp = solver;
struct ATS_Peer * peer;
- struct ATS_Peer * tmp;
+ struct ATS_Address *addr;
GNUNET_assert (mlp != NULL);
peer = mlp->peer_head;
while (peer != NULL)
{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up peer `%s'\n", GNUNET_i2s (&peer->id));
GNUNET_CONTAINER_DLL_remove(mlp->peer_head, mlp->peer_tail, peer);
- tmp = peer->next;
+ for (addr = peer->head; NULL != addr; addr = peer->head)
+ {
+ GNUNET_CONTAINER_DLL_remove(peer->head, peer->tail, addr);
+ GNUNET_free (addr->solver_information);
+ addr->solver_information = NULL;
+ }
GNUNET_free (peer);
- peer = tmp;
+ peer = mlp->peer_head;
}
mlp_delete_problem (mlp);