- fix (case where peers <= 2)
authorSree Harsha Totakura <totakura@in.tum.de>
Fri, 8 Mar 2013 15:34:45 +0000 (15:34 +0000)
committerSree Harsha Totakura <totakura@in.tum.de>
Fri, 8 Mar 2013 15:34:45 +0000 (15:34 +0000)
src/testbed/gnunet-service-testbed.c
src/testbed/test_testbed_api_testbed_run.c
src/testbed/testbed_api_testbed.c
src/testbed/testbed_api_topology.c

index 2435ba50e13504bbdbf0164bc1637a2384d35fc5..a7af7b99cbf802232b9ccb63c43c3292d364b5df 100644 (file)
@@ -1972,6 +1972,194 @@ handle_slave_get_config (void *cls, struct GNUNET_SERVER_Client *client,
 }
 
 
+/**
+ * Context data for GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS handler
+ */
+struct HandlerContext_ShutdownPeers
+{
+  /**
+   * The number of slave we expect to hear from since we forwarded the
+   * GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS message to them
+   */
+  unsigned int nslaves;
+
+  /**
+   * Did we observe a timeout with respect to this operation at any of the
+   * slaves
+   */
+  int timeout;
+};
+
+
+/**
+ * Task run upon timeout of forwarded SHUTDOWN_PEERS operation
+ *
+ * @param cls the ForwardedOperationContext
+ * @param tc the scheduler task context
+ */
+static void
+shutdown_peers_timeout_cb (void *cls,
+                           const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct ForwardedOperationContext *fo_ctxt = cls;
+  struct HandlerContext_ShutdownPeers *hc;
+
+  hc = fo_ctxt->cls;
+  hc->timeout = GNUNET_YES;
+  GNUNET_assert (0 < hc->nslaves);
+  hc->nslaves--;
+  if (0 == hc->nslaves)
+    GST_send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id,
+                                 "Timeout at a slave controller");
+  GNUNET_TESTBED_forward_operation_msg_cancel_ (fo_ctxt->opc);  
+  GNUNET_SERVER_client_drop (fo_ctxt->client);
+  GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fo_ctxt);
+  GNUNET_free (fo_ctxt);
+}
+
+
+/**
+ * The reply msg handler forwarded SHUTDOWN_PEERS operation.  Checks if a
+ * success reply is received from all clients and then sends the success message
+ * to the client
+ *
+ * @param cls ForwardedOperationContext
+ * @param msg the message to relay
+ */
+static void
+shutdown_peers_reply_cb (void *cls,
+                         const struct GNUNET_MessageHeader *msg)
+{
+  struct ForwardedOperationContext *fo_ctxt = cls;
+  struct HandlerContext_ShutdownPeers *hc;
+  
+  hc = fo_ctxt->cls;
+  GNUNET_assert (0 < hc->nslaves);
+  hc->nslaves--;
+  if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS != 
+      ntohs (msg->type))
+    hc->timeout = GNUNET_YES;
+  if (0 == hc->nslaves)
+  {
+    if (GNUNET_YES == hc->timeout)
+      GST_send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id,
+                                   "Timeout at a slave controller");
+    else
+      send_operation_success_msg (fo_ctxt->client, fo_ctxt->operation_id);
+  }
+  GNUNET_SERVER_client_drop (fo_ctxt->client);
+  GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fo_ctxt);
+  GNUNET_free (fo_ctxt);
+}
+
+
+/**
+ * Stops and destroys all peers
+ */
+static void
+destroy_peers ()
+{
+  struct Peer *peer;
+  unsigned int id;
+
+  if (NULL == GST_peer_list)
+    return;
+  for (id = 0; id < GST_peer_list_size; id++)
+  {
+    peer = GST_peer_list[id];
+    if (NULL == peer)
+      continue;
+    /* If destroy flag is set it means that this peer should have been
+     * destroyed by a context which we destroy before */
+    GNUNET_break (GNUNET_NO == peer->destroy_flag);
+    /* counter should be zero as we free all contexts before */
+    GNUNET_break (0 == peer->reference_cnt);
+    if ((GNUNET_NO == peer->is_remote) &&
+        (GNUNET_YES == peer->details.local.is_running))
+      GNUNET_TESTING_peer_kill (peer->details.local.peer);
+  }
+  for (id = 0; id < GST_peer_list_size; id++)
+  {
+    peer = GST_peer_list[id];
+    if (NULL == peer)
+      continue;    
+    if (GNUNET_NO == peer->is_remote)
+    {
+      if (GNUNET_YES == peer->details.local.is_running)
+        GNUNET_TESTING_peer_wait (peer->details.local.peer);
+      GNUNET_TESTING_peer_destroy (peer->details.local.peer);
+      GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
+    }
+    GNUNET_free (peer);
+  }
+  GNUNET_free_non_null (GST_peer_list);
+  GST_peer_list = NULL;
+}
+
+
+/**
+ * Handler for GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
+ *
+ * @param cls NULL
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_shutdown_peers (void *cls, struct GNUNET_SERVER_Client *client,
+                       const struct GNUNET_MessageHeader *message)
+{
+  const struct GNUNET_TESTBED_ShutdownPeersMessage *msg;
+  struct HandlerContext_ShutdownPeers *hc;
+  struct Slave *slave;
+  struct ForwardedOperationContext *fo_ctxt;
+  uint64_t op_id;
+  unsigned int cnt;
+
+  msg = (const struct GNUNET_TESTBED_ShutdownPeersMessage *) message;
+  LOG_DEBUG ("Received SHUTDOWN_PEERS\n");
+  /* Forward to all slaves which we have started */
+  op_id = GNUNET_ntohll (msg->operation_id);
+  hc = GNUNET_malloc (sizeof (struct HandlerContext_ShutdownPeers));
+  /* FIXME: have a better implementation where we track which slaves are
+     started by this controller */
+  for (cnt = 0; cnt < GST_slave_list_size; cnt++)
+  {
+    slave = GST_slave_list[cnt];
+    if (NULL == slave)
+      continue;
+    if (NULL == slave->controller_proc) /* We didn't start the slave */
+      continue;
+    LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n");
+    hc->nslaves++;
+    fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
+    GNUNET_SERVER_client_keep (client);
+    fo_ctxt->client = client;
+    fo_ctxt->operation_id = op_id;
+    fo_ctxt->cls = hc;
+    fo_ctxt->type = OP_SHUTDOWN_PEERS;
+    fo_ctxt->opc =
+        GNUNET_TESTBED_forward_operation_msg_ (slave->controller,
+                                               fo_ctxt->operation_id,
+                                               &msg->header,
+                                               shutdown_peers_reply_cb,
+                                               fo_ctxt);
+    fo_ctxt->timeout_task =
+        GNUNET_SCHEDULER_add_delayed (GST_timeout, &shutdown_peers_timeout_cb,
+                                      fo_ctxt);
+    GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
+  }
+  LOG_DEBUG ("Shutting down peers\n");
+  /* Stop and destroy all peers */
+  destroy_peers ();
+  if (0 == hc->nslaves)
+  {
+    send_operation_success_msg (client, op_id);
+    GNUNET_free (hc);
+  }
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);  
+}
+
+
 /**
  * Iterator over hash map entries.
  *
@@ -2062,6 +2250,16 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     case OP_PEER_CREATE:
       GNUNET_free (fopc->cls);
       break;
+    case OP_SHUTDOWN_PEERS:
+      {
+        struct HandlerContext_ShutdownPeers *hc = fopc->cls;
+        
+        GNUNET_assert (0 < hc->nslaves);
+        hc->nslaves--;
+        if (0 == hc->nslaves)
+          GNUNET_free (hc);
+      }
+      break;
     case OP_PEER_START:
     case OP_PEER_STOP:
     case OP_PEER_DESTROY:
@@ -2096,31 +2294,7 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   GST_free_occq ();
   GST_free_roccq ();
   /* Clear peer list */
-  for (id = 0; id < GST_peer_list_size; id++)
-    if (NULL != GST_peer_list[id])
-    {
-      /* If destroy flag is set it means that this peer should have been
-       * destroyed by a context which we destroy before */
-      GNUNET_break (GNUNET_NO == GST_peer_list[id]->destroy_flag);
-      /* counter should be zero as we free all contexts before */
-      GNUNET_break (0 == GST_peer_list[id]->reference_cnt);
-      if ((GNUNET_NO == GST_peer_list[id]->is_remote) &&
-          (GNUNET_YES == GST_peer_list[id]->details.local.is_running))
-        GNUNET_TESTING_peer_kill (GST_peer_list[id]->details.local.peer);
-    }
-  for (id = 0; id < GST_peer_list_size; id++)
-    if (NULL != GST_peer_list[id])
-    {
-      if (GNUNET_NO == GST_peer_list[id]->is_remote)
-      {
-        if (GNUNET_YES == GST_peer_list[id]->details.local.is_running)
-          GNUNET_TESTING_peer_wait (GST_peer_list[id]->details.local.peer);
-        GNUNET_TESTING_peer_destroy (GST_peer_list[id]->details.local.peer);
-        GNUNET_CONFIGURATION_destroy (GST_peer_list[id]->details.local.cfg);
-      }
-      GNUNET_free (GST_peer_list[id]);
-    }
-  GNUNET_free_non_null (GST_peer_list);
+  destroy_peers ();
   /* Clear host list */
   for (id = 0; id < GST_host_list_size; id++)
     if (NULL != GST_host_list[id])
@@ -2242,9 +2416,11 @@ testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
      sizeof (struct GNUNET_TESTBED_OverlayConnectMessage)},
     {&GST_handle_remote_overlay_connect, NULL,
      GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT, 0},
-    {handle_slave_get_config, NULL,
+    {&handle_slave_get_config, NULL,
      GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION,
      sizeof (struct GNUNET_TESTBED_SlaveGetConfigurationMessage)},
+    {&handle_shutdown_peers, NULL, GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS,
+     sizeof (struct GNUNET_TESTBED_ShutdownPeersMessage)},
     {NULL}
   };
   char *logfile;
index 9cad74a7b37565f1c3da84ca525884475a18a01c..10317b489d9ff2cf2f68ccf4177fcfb1643ab2e5 100644 (file)
@@ -31,7 +31,7 @@
 /**
  * Number of peers we want to start
  */
-#define NUM_PEERS 5
+#define NUM_PEERS 2
 
 /**
  * The array of peers; we fill this as the peers are given to us by the testbed
index 282e4af88125a5bfcf6fae0bc5b0f5564899ece2..c54ef3e19e7cab2c2de8df7a546ee9ed3dfca1aa 100644 (file)
@@ -103,15 +103,20 @@ enum State
    */
   RC_READY,
 
-  /**
-   * Peers are stopped
-   */
-  RC_PEERS_STOPPED,
+  /* /\** */
+  /*  * Peers are stopped */
+  /*  *\/ */
+  /* RC_PEERS_STOPPED, */
+
+  /* /\** */
+  /*  * Peers are destroyed */
+  /*  *\/ */
+  /* RC_PEERS_DESTROYED */
 
   /**
-   * Peers are destroyed
+   * All peers shutdown (stopped and destroyed)
    */
-  RC_PEERS_DESTROYED
+  RC_PEERS_SHUTDOWN
 };
 
 
@@ -377,7 +382,7 @@ cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   GNUNET_assert (NULL == rc->reg_handle);
   GNUNET_assert (NULL == rc->peers);
   GNUNET_assert (NULL == rc->hc_handles);
-  GNUNET_assert (RC_PEERS_DESTROYED == rc->state);
+  GNUNET_assert (RC_PEERS_SHUTDOWN == rc->state);
   if (NULL != rc->dll_op_head)
   {                             /* cancel our pending operations */
     while (NULL != (dll_op = rc->dll_op_head))
@@ -441,8 +446,6 @@ shutdown_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   struct RunContext *rc = cls;
   struct DLLOperation *dll_op;
-  int all_peers_destroyed;
-  unsigned int peer;
   unsigned int nhost;
 
   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != rc->shutdown_run_task);
@@ -479,61 +482,17 @@ shutdown_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
       }
       if (RC_INIT == rc->state)
         rc->state = RC_READY;   /* Even though we haven't called the master callback */
-      rc->peer_count = 0;
-      /* Check if some peers are stopped */
-      for (peer = 0; peer < rc->num_peers; peer++)
-      {
-        if (NULL == rc->peers[peer])
-          continue;
-        if (PS_STOPPED != rc->peers[peer]->state)
-          break;
-      }
-      if (peer == rc->num_peers)
-      {
-        /* All peers are stopped */
-        rc->state = RC_PEERS_STOPPED;
-        all_peers_destroyed = GNUNET_YES;
-        for (peer = 0; peer < rc->num_peers; peer++)
-        {
-          if (NULL == rc->peers[peer])
-            continue;
-          all_peers_destroyed = GNUNET_NO;
-          dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
-          dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer]);
-          GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
-                                            dll_op);
-        }
-        if (all_peers_destroyed == GNUNET_NO)
-        {
-          DEBUG ("Destroying peers\n");
-          rc->pstart_time = GNUNET_TIME_absolute_get ();
-          return;
-        }
-      }
-      /* Some peers are stopped */
-      DEBUG ("Stopping peers\n");
+      dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
+      dll_op->op = GNUNET_TESTBED_shutdown_peers (rc->c, dll_op, NULL, NULL);
+      DEBUG ("Shutting down peers\n");
       rc->pstart_time = GNUNET_TIME_absolute_get ();
-      for (peer = 0; peer < rc->num_peers; peer++)
-      {
-        if ((NULL == rc->peers[peer]) || (PS_STARTED != rc->peers[peer]->state))
-        {
-          rc->peer_count++;
-          continue;
-        }
-        dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
-        dll_op->op = GNUNET_TESTBED_peer_stop (rc->peers[peer], NULL, NULL);
-        dll_op->cls = rc->peers[peer];
-        GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
-                                          dll_op);
-      }
-      if (rc->peer_count != rc->num_peers)
-        return;
-      GNUNET_free (rc->peers);
-      rc->peers = NULL;
+      GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
+                                        dll_op);
+      return;
     }
   }
-  rc->state = RC_PEERS_DESTROYED;       /* No peers are present so we consider the
-                                         * state where all peers are destroyed  */
+  rc->state = RC_PEERS_SHUTDOWN;       /* No peers are present so we consider the
+                                        * state where all peers are SHUTDOWN  */
   GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
 }
 
@@ -625,7 +584,6 @@ event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
 {
   struct RunContext *rc = cls;
   struct DLLOperation *dll_op;
-  unsigned int peer_id;
 
   if (RC_INIT == rc->state)
   {
@@ -661,40 +619,20 @@ event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
     if ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type) &&
         (event->details.operation_finished.operation == dll_op->op))
       break;
-    if ((GNUNET_TESTBED_ET_PEER_STOP == event->type) &&
-        (event->details.peer_stop.peer == dll_op->cls))
-      break;
   }
   if (NULL == dll_op)
     goto call_cc;
   GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
   GNUNET_TESTBED_operation_done (dll_op->op);
   GNUNET_free (dll_op);
-  rc->peer_count++;
-  if (rc->peer_count < rc->num_peers)
-    return;
   switch (rc->state)
   {
   case RC_PEERS_CREATED:
   case RC_READY:
-    rc->state = RC_PEERS_STOPPED;
-    DEBUG ("Peers stopped in %s\n", prof_time (rc));
-    DEBUG ("Destroying peers\n");
-    rc->pstart_time = GNUNET_TIME_absolute_get ();
-    rc->peer_count = 0;
-    for (peer_id = 0; peer_id < rc->num_peers; peer_id++)
-    {
-      dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
-      dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer_id]);
-      GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
-                                        dll_op);
-    }
-    break;
-  case RC_PEERS_STOPPED:
-    rc->state = RC_PEERS_DESTROYED;
+    rc->state = RC_PEERS_SHUTDOWN;
     GNUNET_free (rc->peers);
     rc->peers = NULL;
-    DEBUG ("Peers destroyed in %s\n", prof_time (rc));
+    DEBUG ("Peers shut down in %s\n", prof_time (rc));
     GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
     break;
   default:
@@ -876,7 +814,6 @@ controller_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
   GNUNET_CONFIGURATION_destroy (rc->cfg);
   rc->cfg = GNUNET_CONFIGURATION_dup (cfg);
   event_mask = rc->event_mask;
-  event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_STOP);
   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
   event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
   if (rc->topology < GNUNET_TESTBED_TOPOLOGY_NONE)
index 6bb1e5d733f647e1c73c0e856f577fa3ec313a60..c68d336e58ccf79a7e86c8127a180138c5876ef4 100644 (file)
@@ -429,6 +429,8 @@ gen_topo_ring (struct TopologyContext *tc)
  * @param rows number of rows in the 2d torus. Can be NULL
  * @param rows_len the length of each row. This array will be allocated
  *          fresh. The caller should free it. Can be NULL
+ * @return the number of links that are required to generate a 2d torus for the
+ *           given number of peers
  */
 unsigned int
 GNUNET_TESTBED_2dtorus_calc_links (unsigned int num_peers, unsigned int *rows,
@@ -451,7 +453,7 @@ GNUNET_TESTBED_2dtorus_calc_links (unsigned int num_peers, unsigned int *rows,
   for (y = 0; y < _rows - 1; y++)
     _rows_len[y] = sq_floor;
   _num_peers = sq_floor * sq_floor;
-  cnt = 2 * _num_peers;
+  cnt = (_num_peers < 2) ? _num_peers : 2 * _num_peers;
   x = 0;
   y = 0;
   while (_num_peers < num_peers)