From 19b4dacf08575bd188f9010558e8299c6c8eb56e Mon Sep 17 00:00:00 2001 From: Sree Harsha Totakura Date: Fri, 8 Mar 2013 15:34:45 +0000 Subject: [PATCH] - fix (case where peers <= 2) --- src/testbed/gnunet-service-testbed.c | 228 ++++++++++++++++++--- src/testbed/test_testbed_api_testbed_run.c | 2 +- src/testbed/testbed_api_testbed.c | 107 ++-------- src/testbed/testbed_api_topology.c | 4 +- 4 files changed, 228 insertions(+), 113 deletions(-) diff --git a/src/testbed/gnunet-service-testbed.c b/src/testbed/gnunet-service-testbed.c index 2435ba50e..a7af7b99c 100644 --- a/src/testbed/gnunet-service-testbed.c +++ b/src/testbed/gnunet-service-testbed.c @@ -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; diff --git a/src/testbed/test_testbed_api_testbed_run.c b/src/testbed/test_testbed_api_testbed_run.c index 9cad74a7b..10317b489 100644 --- a/src/testbed/test_testbed_api_testbed_run.c +++ b/src/testbed/test_testbed_api_testbed_run.c @@ -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 diff --git a/src/testbed/testbed_api_testbed.c b/src/testbed/testbed_api_testbed.c index 282e4af88..c54ef3e19 100644 --- a/src/testbed/testbed_api_testbed.c +++ b/src/testbed/testbed_api_testbed.c @@ -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) diff --git a/src/testbed/testbed_api_topology.c b/src/testbed/testbed_api_topology.c index 6bb1e5d73..c68d336e5 100644 --- a/src/testbed/testbed_api_topology.c +++ b/src/testbed/testbed_api_topology.c @@ -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) -- 2.25.1