fix for 0002392
[oweals/gnunet.git] / src / ats / gnunet-service-ats_addresses_mlp.c
index 7b5134517c9f8fe6a3670d8bde80da017eb9496f..8bfa010caaa86914b06e406416ac824e053065cd 100644 (file)
@@ -505,7 +505,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 +567,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 +593,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;
 
       /* coefficient for c 2) */
-
       ia[mlp->ci] = peer->r_c2;
       ja[mlp->ci] = mlpi->c_n;
       ar[mlp->ci] = 1;
@@ -625,8 +627,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 +640,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];
@@ -657,7 +657,7 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON
 
           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++;
         }
   }
@@ -747,7 +747,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 +757,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 */
@@ -807,13 +805,6 @@ mlp_create_problem (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHas
 }
 
 
-struct SolveContext
-{
-  struct GNUNET_TIME_Relative lp_duration;
-  struct GNUNET_TIME_Relative mlp_duration;
-};
-
-
 /**
  * Solves the LP problem
  *
@@ -822,7 +813,7 @@ struct SolveContext
  * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
  */
 static int
-mlp_solve_lp_problem (struct GAS_MLP_Handle *mlp, struct SolveContext *s_ctx)
+mlp_solve_lp_problem (struct GAS_MLP_Handle *mlp, struct GAS_MLP_SolutionContext *s_ctx)
 {
   int res;
   struct GNUNET_TIME_Relative duration;
@@ -883,9 +874,6 @@ lp_solv:
   GNUNET_STATISTICS_set (mlp->stats,"# LP execution time average (ms)",
                          mlp->lp_total_duration / mlp->lp_solved,  GNUNET_NO);
 
-  GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
-      "ats-mlp",
-      "%llu %llu \n", duration.rel_value, mlp->lp_total_duration / mlp->lp_solved);
   /* Analyze problem status  */
   res = glp_get_status (mlp->prob);
   switch (res) {
@@ -919,7 +907,7 @@ lp_solv:
  * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
  */
 int
-mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp, struct SolveContext *s_ctx)
+mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp, struct GAS_MLP_SolutionContext *s_ctx)
 {
   int res;
   struct GNUNET_TIME_Relative duration;
@@ -962,7 +950,7 @@ mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp, struct SolveContext *s_ctx)
   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);
-GNUNET_break(0);
+
   /* Analyze problem status  */
   res = glp_mip_status(mlp->prob);
   switch (res) {
@@ -984,38 +972,58 @@ GNUNET_break(0);
   return GNUNET_OK;
 }
 
-int GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp);
+int GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp, 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 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 (struct GAS_MLP_Handle *mlp, struct GAS_MLP_SolutionContext *ctx)
 {
   int res;
-  struct SolveContext s_ctx;
+  /* 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;
+
   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;
@@ -1026,12 +1034,15 @@ GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp)
   GNUNET_free (name);
 # endif
 
-  res = mlp_solve_lp_problem (mlp, &s_ctx);
+  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);
   glp_print_sol (mlp->prob,  name);
@@ -1040,10 +1051,12 @@ GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp)
 
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Solve MLP problem\n");
-  res = mlp_solve_mlp_problem (mlp, &s_ctx);
+  res = mlp_solve_mlp_problem (mlp, ctx);
+  ctx->mlp_result = res;
   if (res != GNUNET_OK)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP Problem solving failed\n");
+    mlp->semaphore = GNUNET_NO;
     return GNUNET_SYSERR;
   }
 #if WRITE_MLP
@@ -1053,7 +1066,7 @@ GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp)
 # endif
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem solved %s (LP duration %llu / MLP duration %llu)\n",
-      (GNUNET_OK == res) ? "successfully" : "failed", s_ctx.lp_duration, s_ctx.mlp_duration);
+      (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;
@@ -1089,6 +1102,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;
 }
 
@@ -1112,7 +1126,7 @@ GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
   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;
@@ -1121,12 +1135,30 @@ GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
   char * quota_in_str;
 
   /* Init GLPK environment */
-  int res = 0;
-  if (0 != (res = glp_init_env()))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK %u\n", res);
-    GNUNET_free(mlp);
-    return NULL;
+  int res = glp_init_env();
+  switch (res) {
+    case 0:
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n",
+          "initialization successful");
+      break;
+    case 1:
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n",
+          "environment is already initialized");
+      break;
+    case 2:
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n",
+          "initialization failed (insufficient memory)");
+      GNUNET_free(mlp);
+      return NULL;
+      break;
+    case 3:
+      GNUNET_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 */
@@ -1285,8 +1317,8 @@ GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
     /* Check if defined quota could make problem unsolvable */
     if (((n_min * b_min) > quota_out) && (GNUNET_ATS_NET_UNSPECIFIED != quotas[c]))
     {
-      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);
+      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);
 
       GAS_mlp_done(mlp);
       mlp = NULL;
@@ -1337,7 +1369,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;
@@ -1345,7 +1377,7 @@ 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;
   return mlp;
 }
 
@@ -1412,7 +1444,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
@@ -1437,7 +1469,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
@@ -1525,6 +1557,7 @@ GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_Mult
 {
   int new;
   struct MLP_information *mlpi;
+  struct GAS_MLP_SolutionContext ctx;
 
   GNUNET_STATISTICS_update (mlp->stats, "# MLP address updates", 1, GNUNET_NO);
 
@@ -1609,7 +1642,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);
 }
 
 /**
@@ -1626,6 +1659,7 @@ void
 GAS_mlp_address_delete (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
 {
   GNUNET_STATISTICS_update (mlp->stats,"# LP address deletions", 1, GNUNET_NO);
+  struct GAS_MLP_SolutionContext ctx;
 
   /* Free resources */
   if (address->mlp_information != NULL)
@@ -1667,7 +1701,7 @@ 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);
   }
 }