X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fats%2Fgnunet-service-ats_addresses_mlp.c;h=50983cec1eed0cc6480d344705ba5d3fee76ff95;hb=7e7b70bcdbc067949bfd5249944b27ad57b3777c;hp=61aa73397b3b140b7617a564db2b098873eef31b;hpb=65b12e6421b3b3f3733855b338aa09e36d09e44f;p=oweals%2Fgnunet.git diff --git a/src/ats/gnunet-service-ats_addresses_mlp.c b/src/ats/gnunet-service-ats_addresses_mlp.c index 61aa73397..50983cec1 100644 --- a/src/ats/gnunet-service-ats_addresses_mlp.c +++ b/src/ats/gnunet-service-ats_addresses_mlp.c @@ -31,6 +31,8 @@ #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 @@ -48,68 +50,46 @@ mlp_solve_to_string (int retcode) 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"; } @@ -124,29 +104,20 @@ mlp_status_to_string (int retcode) 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"; } /** @@ -162,37 +133,26 @@ mlp_ats_to_string (int ats_index) 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"; } /** @@ -278,7 +238,7 @@ mlp_delete_problem (struct GAS_MLP_Handle *mlp) * @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; @@ -286,8 +246,8 @@ create_constraint_it (void *cls, const GNUNET_HashCode * key, void *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 @@ -379,6 +339,7 @@ create_constraint_it (void *cls, const GNUNET_HashCode * key, void *value) return GNUNET_OK; } +#if 0 /** * Find the required ATS information for an address * @@ -387,7 +348,6 @@ create_constraint_it (void *cls, const GNUNET_HashCode * key, void *value) * * @return the index on success, otherwise GNUNET_SYSERR */ - static int mlp_lookup_ats (struct ATS_Address *addr, int ats_index) { @@ -407,6 +367,7 @@ mlp_lookup_ats (struct ATS_Address *addr, int ats_index) else return GNUNET_SYSERR; } +#endif /** * Adds the problem constraints for all addresses @@ -505,7 +466,9 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON * 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; @@ -565,6 +528,7 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON mlp->ci++; struct ATS_Peer * peer = mlp->peer_head; + /* For all peers */ while (peer != NULL) { struct ATS_Address *addr = peer->head; @@ -590,16 +554,15 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON /* 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; @@ -625,8 +588,6 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON } /* c 7) For all quality metrics */ - - for (c = 0; c < mlp->m_q; c++) { struct ATS_Peer *tp; @@ -640,7 +601,7 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON 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]; @@ -650,14 +611,14 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON 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++; } } @@ -674,7 +635,7 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON * @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; @@ -682,8 +643,8 @@ create_columns_it (void *cls, const GNUNET_HashCode * key, void *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); @@ -747,7 +708,6 @@ mlp_create_problem (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHas /* Adding invariant columns */ /* Diversity d column */ - col = glp_add_cols (mlp->prob, 1); mlp->c_d = col; /* Column name */ @@ -758,7 +718,6 @@ mlp_create_problem (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHas 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 */ @@ -806,14 +765,16 @@ mlp_create_problem (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHas 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; @@ -866,14 +827,14 @@ lp_solv: 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) { @@ -903,10 +864,11 @@ lp_solv: * 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; @@ -942,11 +904,12 @@ mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp) 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 */ @@ -970,41 +933,60 @@ mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp) 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; @@ -1014,7 +996,14 @@ GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp) 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); @@ -1022,31 +1011,24 @@ GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp) 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; @@ -1060,7 +1042,7 @@ GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp) 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; @@ -1082,6 +1064,7 @@ GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp) 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; } @@ -1090,68 +1073,120 @@ GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp) * * @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) @@ -1160,24 +1195,24 @@ GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg, 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 @@ -1187,83 +1222,78 @@ GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg, /* 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 */ @@ -1274,6 +1304,8 @@ GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg, 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; @@ -1302,7 +1334,7 @@ GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg, #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; @@ -1310,6 +1342,9 @@ GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg, 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; } @@ -1320,27 +1355,34 @@ update_quality (struct GAS_MLP_Handle *mlp, struct ATS_Address * address) 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++) @@ -1374,7 +1416,7 @@ update_quality (struct GAS_MLP_Handle *mlp, struct ATS_Address * address) 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 @@ -1399,7 +1441,7 @@ update_quality (struct GAS_MLP_Handle *mlp, struct ATS_Address * address) 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 @@ -1468,6 +1510,20 @@ update_quality (struct GAS_MLP_Handle *mlp, struct ATS_Address * address) } } + +/** + * 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 * @@ -1477,21 +1533,34 @@ update_quality (struct GAS_MLP_Handle *mlp, struct ATS_Address * address) * 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; @@ -1512,8 +1581,9 @@ GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_Mult 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); @@ -1540,6 +1610,7 @@ GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_Mult 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 { @@ -1549,7 +1620,6 @@ GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_Mult GNUNET_CONTAINER_DLL_insert (peer->head, peer->tail, address); } - update_quality (mlp, address); } else @@ -1570,7 +1640,7 @@ GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_Mult mlp->presolver_required = GNUNET_YES; } if (mlp->auto_solve == GNUNET_YES) - GAS_mlp_solve_problem (mlp); + GAS_mlp_solve_problem (mlp, &ctx); } /** @@ -1578,23 +1648,32 @@ GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_Mult * * 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 */ @@ -1613,6 +1692,7 @@ GAS_mlp_address_delete (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_Mult 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 */ @@ -1626,27 +1706,27 @@ GAS_mlp_address_delete (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_Mult /* 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; @@ -1656,20 +1736,17 @@ mlp_get_preferred_address_it (void *cls, const GNUNET_HashCode * key, void *valu /** * 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; @@ -1679,33 +1756,39 @@ GAS_mlp_get_preferred_address (struct GAS_MLP_Handle *mlp, /** * 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); @@ -1719,10 +1802,16 @@ GAS_mlp_done (struct GAS_MLP_Handle *mlp) 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);