From ea2d90b6f87d2f11d4160babcd8ee0d17e49a0bb Mon Sep 17 00:00:00 2001 From: Ted Ross Date: Wed, 7 Oct 2015 16:58:50 -0400 Subject: [PATCH 01/22] DISPATCH-179 - WIP, added core framework and began work on the core API --- include/qpid/dispatch/ctools.h | 1 + include/qpid/dispatch/router_core.h | 147 +++++++++++++++++ python/qpid_dispatch/management/qdrouter.json | 1 + src/CMakeLists.txt | 1 + src/router_core.c | 151 ++++++++++++++++++ src/router_node.c | 26 +-- src/router_private.h | 7 +- 7 files changed, 312 insertions(+), 22 deletions(-) create mode 100644 include/qpid/dispatch/router_core.h create mode 100644 src/router_core.c diff --git a/include/qpid/dispatch/ctools.h b/include/qpid/dispatch/ctools.h index 698c5b946f..3ac5998a14 100644 --- a/include/qpid/dispatch/ctools.h +++ b/include/qpid/dispatch/ctools.h @@ -52,6 +52,7 @@ #define DEQ_SIZE(d) ((d).size) #define DEQ_NEXT(i) (i)->next #define DEQ_PREV(i) (i)->prev +#define DEQ_MOVE(d1,d2) do {d2 = d1; DEQ_INIT(d1);} while (0) /** *@pre ptr points to first element of deq *@post ptr points to first element of deq that passes test, or 0. Test should involve ptr. diff --git a/include/qpid/dispatch/router_core.h b/include/qpid/dispatch/router_core.h new file mode 100644 index 0000000000..b2e4aacf70 --- /dev/null +++ b/include/qpid/dispatch/router_core.h @@ -0,0 +1,147 @@ +#ifndef __router_core_h__ +#define __router_core_h__ 1 +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include + +typedef struct qdr_core_t qdr_core_t; +typedef struct qdr_connection_t qdr_connection_t; +typedef struct qdr_link_t qdr_link_t; +typedef struct qdr_delivery_t qdr_delivery_t; + +/** + * Allocate and start an instance of the router core module. + */ +qdr_core_t *qdr_core(void); + +/** + * Stop and deallocate an instance of the router core. + */ +void qdr_core_free(qdr_core_t *core); + +/** + ****************************************************************************** + * Route table maintenance functions + ****************************************************************************** + */ +typedef enum { + QD_WAYPOINT_SOURCE, + QD_WAYPOINT_SINK, + QD_WAYPOINT_THROUGH, + QD_WAYPOINT_BYPASS, + QD_WAYPOINT_TAP +} qd_waypoint_style_t; + +void qdr_core_add_router(qdr_core_t *core, const char *address, int router_maskbit); +void qdr_core_del_router(qdr_core_t *core, int router_maskbit); +void qdr_core_set_link(qdr_core_t *core, int router_maskbit, int link_maskbit); +void qdr_core_remove_link(qdr_core_t *core, int router_maskbit); +void qdr_core_set_next_hop(qdr_core_t *core, int router_maskbit, int nh_router_maskbit); +void qdr_core_remove_next_hop(qdr_core_t *core, int router_maskbit); +void qdr_core_set_valid_origins(qdr_core_t *core, const qd_bitmask_t *routers); +void qdr_core_map_destination(qdr_core_t *core, int router_maskbit, const char *address, char phase); +void qdr_core_unmap_destination(qdr_core_t *core, int router_maskbit, const char *address, char phase); + +void qdr_core_add_link_route(qdr_core_t *core, qd_field_iterator_t *conn_label, qd_field_iterator_t *prefix); +void qdr_core_del_link_route(qdr_core_t *core, qd_field_iterator_t *conn_label, qd_field_iterator_t *prefix); + +void qdr_core_add_waypoint(qdr_core_t *core, qd_field_iterator_t *conn_label, qd_field_iterator_t *address, qd_waypoint_style_t style, char in_phase, char out_phase); + +// +// The following callbacks shall be invoked on a connection thread from the server thread pool. +// +typedef void (*qdr_mobile_added_t) (void *context, qd_field_iterator_t *address); +typedef void (*qdr_mobile_removed_t) (void *context, qd_field_iterator_t *address); +typedef void (*qdr_link_lost_t) (void *context, int link_maskbit); +typedef void (*qdr_connection_activate_t) (void *context, const qdr_connection_t *connection); +typedef void (*qdr_receive_t) (void *context, qd_message_t *msg, int link_maskbit); + +void qdr_core_route_table_handlers(void *context, + qdr_mobile_added_t mobile_added, + qdr_mobile_removed_t mobile_removed, + qdr_link_lost_t link_lost, + qdr_connection_activate_t connection_activate); + +void qdr_core_subscribe(qdr_core_t *core, const char *address, bool local, bool mobile, qdr_receive_t on_message, void *context); + + +/** + ****************************************************************************** + * Connection functions + ****************************************************************************** + */ +typedef enum { + QDR_WORK_FIRST_ATTACH, // Core is initiating a first-attach + QDR_WORK_SECOND_ATTACH, // Core is sending a second-attach + QDR_WORK_DETACH, // Core is sending a detach + QDR_WORK_DELIVERY // Core is updating a delivery for in-thread processing +} qdr_work_type_t; + +typedef struct { + qdr_work_type_t work_type; + pn_terminus_t *source; // For FIRST_ATTACH + pn_terminus_t *target; // For FIRST_ATTACH + qdr_link_t *link; // For SECOND_ATTACH, DETACH + qdr_delivery_t *delivery; // For DELIVERY +} qdr_work_t; + +qdr_connection_t *qdr_connection_opened(qdr_core_t *core, qd_field_iterator_t *label); +void qdr_connection_closed(qdr_connection_t *conn); +void qdr_connection_set_context(qdr_connection_t *conn, void *context); +void *qdr_connection_get_context(qdr_connection_t *conn); +qdr_work_t *qdr_connection_work(qdr_connection_t *conn); + +/** + ****************************************************************************** + * Link functions + ****************************************************************************** + */ +qdr_link_t *qdr_link_first_attach(qdr_connection_t *conn, qd_direction_t dir, pn_terminus_t *source, pn_terminus_t *target); +void qdr_link_second_attach(qdr_link_t *link, pn_terminus_t *source, pn_terminus_t *target); +void qdr_link_detach(qdr_link_t *link, pn_condition_t *condition); + +qdr_delivery_t *qdr_link_deliver(qdr_link_t *link, pn_delivery_t *delivery, qd_message_t *msg); +qdr_delivery_t *qdr_link_deliver_to(qdr_link_t *link, pn_delivery_t *delivery, qd_message_t *msg, qd_field_iterator_t *addr); + + +/** + ****************************************************************************** + * Delivery functions + ****************************************************************************** + */ +void qdr_delivery_update_disposition(qdr_delivery_t *delivery); +void qdr_delivery_update_flow(qdr_delivery_t *delivery); +void qdr_delivery_process(qdr_delivery_t *delivery); + +/** + ****************************************************************************** + * Management instrumentation functions + ****************************************************************************** + */ +typedef enum { + QD_ROUTER_CONNECTION, + QD_ROUTER_LINK, + QD_ROUTER_ADDRESS +} qd_router_entity_type_t; + +void qdr_core_query(qdr_core_t *core, qd_router_entity_type_t type, const char *filter, void *context); + +#endif diff --git a/python/qpid_dispatch/management/qdrouter.json b/python/qpid_dispatch/management/qdrouter.json index 31032247a8..e447f19801 100644 --- a/python/qpid_dispatch/management/qdrouter.json +++ b/python/qpid_dispatch/management/qdrouter.json @@ -690,6 +690,7 @@ "module": { "type":[ "ROUTER", + "ROUTER_CORE", "ROUTER_HELLO", "ROUTER_LS", "ROUTER_MA", diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 63ccd602fc..4b3bd07f79 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -65,6 +65,7 @@ set(qpid_dispatch_SOURCES python_embedded.c router_agent.c router_config.c + router_core.c router_delivery.c router_node.c router_forwarders.c diff --git a/src/router_core.c b/src/router_core.c new file mode 100644 index 0000000000..fd5e22d519 --- /dev/null +++ b/src/router_core.c @@ -0,0 +1,151 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "dispatch_private.h" +#include +#include +#include +#include + +/** + * Creates a thread that is dedicated to managing and using the routing table. + * The purpose of moving this function into one thread is to remove the widespread + * lock contention that happens with synchrounous multi-threaded routing. + * + * This module owns, manages, and uses the router-link list and the address hash table + */ + + +/** + * The following data structures are private to the core module. They are defined + * here to ensure their invisibiliy outside the core. + */ + +typedef struct qdr_core_work_t { + DEQ_LINKS(struct qdr_core_work_t); +} qdr_core_work_t; + +ALLOC_DECLARE(qdr_core_work_t); +ALLOC_DEFINE(qdr_core_work_t); +DEQ_DECLARE(qdr_core_work_t, qdr_core_work_list_t); + +struct qdr_core_t { + qd_log_source_t *log; + sys_cond_t *cond; + sys_mutex_t *lock; + sys_thread_t *thread; + bool running; + qdr_core_work_list_t work_list; +}; + + +static void router_core_do_work(qdr_core_t *core, qdr_core_work_t *work) +{ +} + + +static void *router_core_thread(void *arg) +{ + qdr_core_t *core = (qdr_core_t*) arg; + qdr_core_work_list_t work_list; + qdr_core_work_t *work; + + qd_log(core->log, QD_LOG_INFO, "Router Core thread running"); + while (core->running) { + // + // Use the lock only to protect the condition variable and the work list + // + sys_mutex_lock(core->lock); + + // + // Block on the condition variable when there is no work to do + // + while (core->running && DEQ_IS_EMPTY(core->work_list)) + sys_cond_wait(core->cond, core->lock); + + // + // Move the entire work list to a private list so we can process it without + // holding the lock + // + DEQ_MOVE(core->work_list, work_list); + sys_mutex_unlock(core->lock); + + // + // Process and free all of the work items in the list + // + work = DEQ_HEAD(work_list); + while (work) { + DEQ_REMOVE_HEAD(work_list); + + if (core->running) + router_core_do_work(core, work); + + free_qdr_core_work_t(work); + work = DEQ_HEAD(work_list); + } + } + + qd_log(core->log, QD_LOG_INFO, "Router Core thread exited"); + return 0; +} + + +qdr_core_t *qdr_core(void) +{ + qdr_core_t *core = NEW(qdr_core_t); + ZERO(core); + + // + // Set up the logging source for the router core + // + core->log = qd_log_source("ROUTER_CORE"); + + // + // Set up the threading support + // + core->cond = sys_cond(); + core->lock = sys_mutex(); + core->running = true; + DEQ_INIT(core->work_list); + core->thread = sys_thread(router_core_thread, core); + + return core; +} + + +void qdr_core_free(qdr_core_t *core) +{ + // + // Stop and join the thread + // + core->running = false; + sys_cond_signal(core->cond); + sys_thread_join(core->thread); + + // + // Free the core resources + // + sys_thread_free(core->thread); + sys_cond_free(core->cond); + sys_mutex_free(core->lock); + free(core); +} + + + diff --git a/src/router_node.c b/src/router_node.c index 361cd44b1d..c2eb6d99cd 100644 --- a/src/router_node.c +++ b/src/router_node.c @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -745,6 +746,10 @@ static void router_rx_handler(void* context, qd_link_t *link, pn_delivery_t *pnd // pn_link_advance(pn_link); + // + // If there's no router link, free the message and finish. It's likely that the link + // is closing. + // if (!rlink) { qd_message_free(msg); return; @@ -1802,6 +1807,7 @@ qd_router_t *qd_router(qd_dispatch_t *qd, qd_router_mode_t mode, const char *are qd->router = router; router->qd = qd; + router->router_core = 0; router->log_source = qd_log_source("ROUTER"); router->router_mode = mode; router->router_area = area; @@ -1863,6 +1869,7 @@ qd_router_t *qd_router(qd_dispatch_t *qd, qd_router_mode_t mode, const char *are void qd_router_setup_late(qd_dispatch_t *qd) { qd_router_python_setup(qd->router); + qd->router->router_core = qdr_core(); qd_timer_schedule(qd->router->timer, 1000); } @@ -1889,6 +1896,7 @@ void qd_router_free(qd_router_t *router) free_qd_address_t(addr); } + qdr_core_free(router->router_core); qd_timer_free(router->timer); sys_mutex_free(router->lock); qd_bitmask_free(router->neighbor_free_mask); @@ -1960,24 +1968,6 @@ void qd_router_unregister_address(qd_address_t *ad) } -void qd_address_set_redirect(qd_address_t *address, qd_address_t *redirect) -{ - address->redirect = redirect; -} - - -void qd_address_set_static_cc(qd_address_t *address, qd_address_t *cc) -{ - address->static_cc = cc; -} - - -void qd_address_set_dynamic_cc(qd_address_t *address, qd_address_t *cc) -{ - address->dynamic_cc = cc; -} - - qd_address_t *qd_router_address_lookup_LH(qd_router_t *router, qd_field_iterator_t *addr_iter, bool *is_local, bool *is_direct) diff --git a/src/router_private.h b/src/router_private.h index eee402fed1..a8ae67a0b6 100644 --- a/src/router_private.h +++ b/src/router_private.h @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -87,7 +88,7 @@ struct qd_router_link_t { qd_router_link_ref_t *ref; ///< Pointer to a containing reference object char *target; ///< Target address for incoming links qd_routed_event_list_t event_fifo; ///< FIFO of outgoing delivery/link events (no messages) - qd_routed_event_list_t msg_fifo; ///< FIFO of outgoing message deliveries + qd_routed_event_list_t msg_fifo; ///< FIFO of incoming or outgoing message deliveries qd_router_delivery_list_t deliveries; ///< [own] outstanding unsettled deliveries bool strip_inbound_annotations; /// Date: Tue, 20 Oct 2015 14:35:25 -0400 Subject: [PATCH 02/22] DISPATCH-179 - Rearranged the source files to make the core more modular. --- include/qpid/dispatch/router_core.h | 65 ++++++----- src/CMakeLists.txt | 3 +- src/router_core.c | 151 -------------------------- src/router_core/router_core.c | 65 +++++++++++ src/router_core/router_core_private.h | 90 +++++++++++++++ src/router_core/router_core_thread.c | 81 ++++++++++++++ 6 files changed, 275 insertions(+), 180 deletions(-) delete mode 100644 src/router_core.c create mode 100644 src/router_core/router_core.c create mode 100644 src/router_core/router_core_private.h create mode 100644 src/router_core/router_core_thread.c diff --git a/include/qpid/dispatch/router_core.h b/include/qpid/dispatch/router_core.h index b2e4aacf70..a78da0205e 100644 --- a/include/qpid/dispatch/router_core.h +++ b/include/qpid/dispatch/router_core.h @@ -22,6 +22,10 @@ #include #include +// +// All callbacks in this module shall be invoked on a connection thread from the server thread pool. +// + typedef struct qdr_core_t qdr_core_t; typedef struct qdr_connection_t qdr_connection_t; typedef struct qdr_link_t qdr_link_t; @@ -42,14 +46,6 @@ void qdr_core_free(qdr_core_t *core); * Route table maintenance functions ****************************************************************************** */ -typedef enum { - QD_WAYPOINT_SOURCE, - QD_WAYPOINT_SINK, - QD_WAYPOINT_THROUGH, - QD_WAYPOINT_BYPASS, - QD_WAYPOINT_TAP -} qd_waypoint_style_t; - void qdr_core_add_router(qdr_core_t *core, const char *address, int router_maskbit); void qdr_core_del_router(qdr_core_t *core, int router_maskbit); void qdr_core_set_link(qdr_core_t *core, int router_maskbit, int link_maskbit); @@ -60,25 +56,21 @@ void qdr_core_set_valid_origins(qdr_core_t *core, const qd_bitmask_t *routers); void qdr_core_map_destination(qdr_core_t *core, int router_maskbit, const char *address, char phase); void qdr_core_unmap_destination(qdr_core_t *core, int router_maskbit, const char *address, char phase); -void qdr_core_add_link_route(qdr_core_t *core, qd_field_iterator_t *conn_label, qd_field_iterator_t *prefix); -void qdr_core_del_link_route(qdr_core_t *core, qd_field_iterator_t *conn_label, qd_field_iterator_t *prefix); +typedef void (*qdr_mobile_added_t) (void *context, const char *address); +typedef void (*qdr_mobile_removed_t) (void *context, const char *address); +typedef void (*qdr_link_lost_t) (void *context, int link_maskbit); -void qdr_core_add_waypoint(qdr_core_t *core, qd_field_iterator_t *conn_label, qd_field_iterator_t *address, qd_waypoint_style_t style, char in_phase, char out_phase); - -// -// The following callbacks shall be invoked on a connection thread from the server thread pool. -// -typedef void (*qdr_mobile_added_t) (void *context, qd_field_iterator_t *address); -typedef void (*qdr_mobile_removed_t) (void *context, qd_field_iterator_t *address); -typedef void (*qdr_link_lost_t) (void *context, int link_maskbit); -typedef void (*qdr_connection_activate_t) (void *context, const qdr_connection_t *connection); -typedef void (*qdr_receive_t) (void *context, qd_message_t *msg, int link_maskbit); +void qdr_core_route_table_handlers(void *context, + qdr_mobile_added_t mobile_added, + qdr_mobile_removed_t mobile_removed, + qdr_link_lost_t link_lost); -void qdr_core_route_table_handlers(void *context, - qdr_mobile_added_t mobile_added, - qdr_mobile_removed_t mobile_removed, - qdr_link_lost_t link_lost, - qdr_connection_activate_t connection_activate); +/** + ****************************************************************************** + * In-process message-receiver functions + ****************************************************************************** + */ +typedef void (*qdr_receive_t) (void *context, qd_message_t *msg, int link_maskbit); void qdr_core_subscribe(qdr_core_t *core, const char *address, bool local, bool mobile, qdr_receive_t on_message, void *context); @@ -109,6 +101,9 @@ void qdr_connection_set_context(qdr_connection_t *conn, void *context); void *qdr_connection_get_context(qdr_connection_t *conn); qdr_work_t *qdr_connection_work(qdr_connection_t *conn); +typedef void (*qdr_connection_activate_t) (void *context, const qdr_connection_t *connection); +void qdr_connection_activate_handler(qdr_core_t *core, qdr_connection_activate_t handler, void *context); + /** ****************************************************************************** * Link functions @@ -133,15 +128,29 @@ void qdr_delivery_process(qdr_delivery_t *delivery); /** ****************************************************************************** - * Management instrumentation functions + * Management functions ****************************************************************************** */ typedef enum { QD_ROUTER_CONNECTION, QD_ROUTER_LINK, - QD_ROUTER_ADDRESS + QD_ROUTER_ADDRESS, + QD_ROUTER_WAYPOINT, + QD_ROUTER_EXCHANGE, + QD_ROUTER_BINDING } qd_router_entity_type_t; -void qdr_core_query(qdr_core_t *core, qd_router_entity_type_t type, const char *filter, void *context); +typedef struct qdr_query_t qdr_query_t; + +void qdr_manage_create(qdr_core_t *core, void *context, qd_router_entity_type_t type, qd_parsed_field_t *attributes); +void qdr_manage_delete(qdr_core_t *core, void *context, qd_router_entity_type_t type, qd_parsed_field_t *attributes); +void qdr_manage_read(qdr_core_t *core, void *context, qd_router_entity_type_t type, qd_parsed_field_t *attributes); + +qdr_query_t *qdr_manage_get_first(qdr_core_t *core, void *context, qd_router_entity_type_t type, int offset); +void qdr_manage_get_next(qdr_query_t *query); +void qdr_query_cancel(qdr_query_t *query); + +typedef void (*qdr_manage_response_t) (void *context, int status_code, qd_composed_field_t *body); +void qdr_manage_handler(qdr_core_t *core, qdr_manage_response_t response_handler); #endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4b3bd07f79..b20a1a53bb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -65,7 +65,8 @@ set(qpid_dispatch_SOURCES python_embedded.c router_agent.c router_config.c - router_core.c + router_core/router_core.c + router_core/router_core_thread.c router_delivery.c router_node.c router_forwarders.c diff --git a/src/router_core.c b/src/router_core.c deleted file mode 100644 index fd5e22d519..0000000000 --- a/src/router_core.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "dispatch_private.h" -#include -#include -#include -#include - -/** - * Creates a thread that is dedicated to managing and using the routing table. - * The purpose of moving this function into one thread is to remove the widespread - * lock contention that happens with synchrounous multi-threaded routing. - * - * This module owns, manages, and uses the router-link list and the address hash table - */ - - -/** - * The following data structures are private to the core module. They are defined - * here to ensure their invisibiliy outside the core. - */ - -typedef struct qdr_core_work_t { - DEQ_LINKS(struct qdr_core_work_t); -} qdr_core_work_t; - -ALLOC_DECLARE(qdr_core_work_t); -ALLOC_DEFINE(qdr_core_work_t); -DEQ_DECLARE(qdr_core_work_t, qdr_core_work_list_t); - -struct qdr_core_t { - qd_log_source_t *log; - sys_cond_t *cond; - sys_mutex_t *lock; - sys_thread_t *thread; - bool running; - qdr_core_work_list_t work_list; -}; - - -static void router_core_do_work(qdr_core_t *core, qdr_core_work_t *work) -{ -} - - -static void *router_core_thread(void *arg) -{ - qdr_core_t *core = (qdr_core_t*) arg; - qdr_core_work_list_t work_list; - qdr_core_work_t *work; - - qd_log(core->log, QD_LOG_INFO, "Router Core thread running"); - while (core->running) { - // - // Use the lock only to protect the condition variable and the work list - // - sys_mutex_lock(core->lock); - - // - // Block on the condition variable when there is no work to do - // - while (core->running && DEQ_IS_EMPTY(core->work_list)) - sys_cond_wait(core->cond, core->lock); - - // - // Move the entire work list to a private list so we can process it without - // holding the lock - // - DEQ_MOVE(core->work_list, work_list); - sys_mutex_unlock(core->lock); - - // - // Process and free all of the work items in the list - // - work = DEQ_HEAD(work_list); - while (work) { - DEQ_REMOVE_HEAD(work_list); - - if (core->running) - router_core_do_work(core, work); - - free_qdr_core_work_t(work); - work = DEQ_HEAD(work_list); - } - } - - qd_log(core->log, QD_LOG_INFO, "Router Core thread exited"); - return 0; -} - - -qdr_core_t *qdr_core(void) -{ - qdr_core_t *core = NEW(qdr_core_t); - ZERO(core); - - // - // Set up the logging source for the router core - // - core->log = qd_log_source("ROUTER_CORE"); - - // - // Set up the threading support - // - core->cond = sys_cond(); - core->lock = sys_mutex(); - core->running = true; - DEQ_INIT(core->work_list); - core->thread = sys_thread(router_core_thread, core); - - return core; -} - - -void qdr_core_free(qdr_core_t *core) -{ - // - // Stop and join the thread - // - core->running = false; - sys_cond_signal(core->cond); - sys_thread_join(core->thread); - - // - // Free the core resources - // - sys_thread_free(core->thread); - sys_cond_free(core->cond); - sys_mutex_free(core->lock); - free(core); -} - - - diff --git a/src/router_core/router_core.c b/src/router_core/router_core.c new file mode 100644 index 0000000000..eba6150d12 --- /dev/null +++ b/src/router_core/router_core.c @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "router_core_private.h" + + +qdr_core_t *qdr_core(void) +{ + qdr_core_t *core = NEW(qdr_core_t); + ZERO(core); + + // + // Set up the logging source for the router core + // + core->log = qd_log_source("ROUTER_CORE"); + + // + // Set up the threading support + // + core->cond = sys_cond(); + core->lock = sys_mutex(); + core->running = true; + DEQ_INIT(core->action_list); + core->thread = sys_thread(router_core_thread, core); + + return core; +} + + +void qdr_core_free(qdr_core_t *core) +{ + // + // Stop and join the thread + // + core->running = false; + sys_cond_signal(core->cond); + sys_thread_join(core->thread); + + // + // Free the core resources + // + sys_thread_free(core->thread); + sys_cond_free(core->cond); + sys_mutex_free(core->lock); + free(core); +} + + + diff --git a/src/router_core/router_core_private.h b/src/router_core/router_core_private.h new file mode 100644 index 0000000000..673ae684a2 --- /dev/null +++ b/src/router_core/router_core_private.h @@ -0,0 +1,90 @@ +#ifndef qd_router_core_private +#define qd_router_core_private 1 +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "dispatch_private.h" +#include +#include +#include +#include + +typedef struct { + qd_buffer_t *buffer; + qd_field_iterator_t *iterator; +} qdr_field_t; + +typedef enum { + QDR_ACTION_ADD_ROUTER, + QDR_ACTION_DEL_ROUTER, + QDR_ACTION_SET_LINK, + QDR_ACTION_REMOVE_LINK, + QDR_ACTION_SET_NEXT_HOP, + QDR_ACTION_REMOVE_NEXT_HOP, + QDR_ACTION_SET_VALID_ORIGINS, + QDR_ACTION_MAP_DESTINATION, + QDR_ACTION_UNMAP_DESTINATION, + QDR_ACTION_SUBSCRIBE, + QDR_ACTION_CONNECTION_OPENED, + QDR_ACTION_CONNECTION_CLOSED, + QDR_ACTION_LINK_FIRST_ATTACH, + QDR_ACTION_LINK_SECOND_ATTACH, + QDR_ACTION_LINK_DETACH, + QDR_ACTION_DELIVER, + QDR_ACTION_DELIVER_TO, + QDR_ACTION_DISPOSITION_CHANGE, + QDR_ACTION_FLOW_CHANGE, + QDR_ACTION_MANAGE_CREATE, + QDR_ACTION_MANAGE_DELETE, + QDR_ACTION_MANAGE_READ, + QDR_ACTION_MANAGE_GET_FIRST, + QDR_ACTION_MANAGE_GET_NEXT +} qdr_action_type_t; + +typedef struct qdr_action_t { + DEQ_LINKS(struct qdr_action_t); + qdr_action_type_t action_type; + union { + struct { + int link_maskbit; + int router_maskbit; + int nh_router_maskbit; + qd_bitmask_t *router_set; + qdr_field_t *address; + char address_class; + char address_phase; + } route_table; + } args; +} qdr_action_t; + +ALLOC_DECLARE(qdr_action_t); +DEQ_DECLARE(qdr_action_t, qdr_action_list_t); + +struct qdr_core_t { + qd_log_source_t *log; + sys_cond_t *cond; + sys_mutex_t *lock; + sys_thread_t *thread; + bool running; + qdr_action_list_t action_list; +}; + +void *router_core_thread(void *arg); + +#endif diff --git a/src/router_core/router_core_thread.c b/src/router_core/router_core_thread.c new file mode 100644 index 0000000000..1d08bd36dd --- /dev/null +++ b/src/router_core/router_core_thread.c @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "router_core_private.h" + +/** + * Creates a thread that is dedicated to managing and using the routing table. + * The purpose of moving this function into one thread is to remove the widespread + * lock contention that happens with synchrounous multi-threaded routing. + * + * This module owns, manages, and uses the router-link list and the address hash table + */ + +ALLOC_DEFINE(qdr_action_t); + + +static void router_core_do_action(qdr_core_t *core, qdr_action_t *action) +{ +} + + +void *router_core_thread(void *arg) +{ + qdr_core_t *core = (qdr_core_t*) arg; + qdr_action_list_t action_list; + qdr_action_t *action; + + qd_log(core->log, QD_LOG_INFO, "Router Core thread running"); + while (core->running) { + // + // Use the lock only to protect the condition variable and the action list + // + sys_mutex_lock(core->lock); + + // + // Block on the condition variable when there is no action to do + // + while (core->running && DEQ_IS_EMPTY(core->action_list)) + sys_cond_wait(core->cond, core->lock); + + // + // Move the entire action list to a private list so we can process it without + // holding the lock + // + DEQ_MOVE(core->action_list, action_list); + sys_mutex_unlock(core->lock); + + // + // Process and free all of the action items in the list + // + action = DEQ_HEAD(action_list); + while (action) { + DEQ_REMOVE_HEAD(action_list); + + if (core->running) + router_core_do_action(core, action); + + free_qdr_action_t(action); + action = DEQ_HEAD(action_list); + } + } + + qd_log(core->log, QD_LOG_INFO, "Router Core thread exited"); + return 0; +} From f03cca6bbb64aa142326ab35a51716d16d696181 Mon Sep 17 00:00:00 2001 From: Ted Ross Date: Tue, 20 Oct 2015 17:34:38 -0400 Subject: [PATCH 03/22] DISPATCH-179 - Added framework for route table management. --- include/qpid/dispatch/router_core.h | 9 +- src/CMakeLists.txt | 1 + src/router_core/route_tables.c | 203 ++++++++++++++++++++++++++ src/router_core/route_tables.h | 22 +++ src/router_core/router_core.c | 34 +++++ src/router_core/router_core_private.h | 46 ++---- src/router_core/router_core_thread.c | 7 +- 7 files changed, 281 insertions(+), 41 deletions(-) create mode 100644 src/router_core/route_tables.c create mode 100644 src/router_core/route_tables.h diff --git a/include/qpid/dispatch/router_core.h b/include/qpid/dispatch/router_core.h index a78da0205e..87bcd5c768 100644 --- a/include/qpid/dispatch/router_core.h +++ b/include/qpid/dispatch/router_core.h @@ -52,15 +52,16 @@ void qdr_core_set_link(qdr_core_t *core, int router_maskbit, int link_maskbit); void qdr_core_remove_link(qdr_core_t *core, int router_maskbit); void qdr_core_set_next_hop(qdr_core_t *core, int router_maskbit, int nh_router_maskbit); void qdr_core_remove_next_hop(qdr_core_t *core, int router_maskbit); -void qdr_core_set_valid_origins(qdr_core_t *core, const qd_bitmask_t *routers); -void qdr_core_map_destination(qdr_core_t *core, int router_maskbit, const char *address, char phase); -void qdr_core_unmap_destination(qdr_core_t *core, int router_maskbit, const char *address, char phase); +void qdr_core_set_valid_origins(qdr_core_t *core, int router_maskbit, qd_bitmask_t *routers); +void qdr_core_map_destination(qdr_core_t *core, int router_maskbit, const char *address, char aclass, char phase); +void qdr_core_unmap_destination(qdr_core_t *core, int router_maskbit, const char *address, char aclass, char phase); typedef void (*qdr_mobile_added_t) (void *context, const char *address); typedef void (*qdr_mobile_removed_t) (void *context, const char *address); typedef void (*qdr_link_lost_t) (void *context, int link_maskbit); -void qdr_core_route_table_handlers(void *context, +void qdr_core_route_table_handlers(qdr_core_t *core, + void *context, qdr_mobile_added_t mobile_added, qdr_mobile_removed_t mobile_removed, qdr_link_lost_t link_lost); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b20a1a53bb..a9136b193b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -67,6 +67,7 @@ set(qpid_dispatch_SOURCES router_config.c router_core/router_core.c router_core/router_core_thread.c + router_core/route_tables.c router_delivery.c router_node.c router_forwarders.c diff --git a/src/router_core/route_tables.c b/src/router_core/route_tables.c new file mode 100644 index 0000000000..bd102f040e --- /dev/null +++ b/src/router_core/route_tables.c @@ -0,0 +1,203 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "router_core_private.h" +//#include "route_tables.h" + +static qdr_action_t *qdr_action(qdr_action_handler_t action_handler); +static void qdr_action_enqueue(qdr_core_t *core, qdr_action_t *action); + +static void qdrh_add_router(qdr_core_t *core, qdr_action_t *action); +static void qdrh_del_router(qdr_core_t *core, qdr_action_t *action); +static void qdrh_set_link(qdr_core_t *core, qdr_action_t *action); +static void qdrh_remove_link(qdr_core_t *core, qdr_action_t *action); +static void qdrh_set_next_hop(qdr_core_t *core, qdr_action_t *action); +static void qdrh_remove_next_hop(qdr_core_t *core, qdr_action_t *action); +static void qdrh_set_valid_origins(qdr_core_t *core, qdr_action_t *action); +static void qdrh_map_destination(qdr_core_t *core, qdr_action_t *action); +static void qdrh_unmap_destination(qdr_core_t *core, qdr_action_t *action); + + +//================================================================================== +// Interface Functions +//================================================================================== + +void qdr_core_add_router(qdr_core_t *core, const char *address, int router_maskbit) +{ + qdr_action_t *action = qdr_action(qdrh_add_router); + action->args.route_table.router_maskbit = router_maskbit; + action->args.route_table.address = qdr_field(address); + qdr_action_enqueue(core, action); +} + + +void qdr_core_del_router(qdr_core_t *core, int router_maskbit) +{ + qdr_action_t *action = qdr_action(qdrh_del_router); + action->args.route_table.router_maskbit = router_maskbit; + qdr_action_enqueue(core, action); +} + + +void qdr_core_set_link(qdr_core_t *core, int router_maskbit, int link_maskbit) +{ + qdr_action_t *action = qdr_action(qdrh_set_link); + action->args.route_table.router_maskbit = router_maskbit; + action->args.route_table.link_maskbit = link_maskbit; + qdr_action_enqueue(core, action); +} + + +void qdr_core_remove_link(qdr_core_t *core, int router_maskbit) +{ + qdr_action_t *action = qdr_action(qdrh_remove_link); + action->args.route_table.router_maskbit = router_maskbit; + qdr_action_enqueue(core, action); +} + + +void qdr_core_set_next_hop(qdr_core_t *core, int router_maskbit, int nh_router_maskbit) +{ + qdr_action_t *action = qdr_action(qdrh_set_next_hop); + action->args.route_table.router_maskbit = router_maskbit; + action->args.route_table.nh_router_maskbit = nh_router_maskbit; + qdr_action_enqueue(core, action); +} + + +void qdr_core_remove_next_hop(qdr_core_t *core, int router_maskbit) +{ + qdr_action_t *action = qdr_action(qdrh_remove_next_hop); + action->args.route_table.router_maskbit = router_maskbit; + qdr_action_enqueue(core, action); +} + + +void qdr_core_set_valid_origins(qdr_core_t *core, int router_maskbit, qd_bitmask_t *routers) +{ + qdr_action_t *action = qdr_action(qdrh_set_valid_origins); + action->args.route_table.router_maskbit = router_maskbit; + action->args.route_table.router_set = routers; + qdr_action_enqueue(core, action); +} + + +void qdr_core_map_destination(qdr_core_t *core, int router_maskbit, const char *address, char aclass, char phase) +{ + qdr_action_t *action = qdr_action(qdrh_map_destination); + action->args.route_table.router_maskbit = router_maskbit; + action->args.route_table.address = qdr_field(address); + action->args.route_table.address_phase = phase; + action->args.route_table.address_class = aclass; + qdr_action_enqueue(core, action); +} + + +void qdr_core_unmap_destination(qdr_core_t *core, int router_maskbit, const char *address, char aclass, char phase) +{ + qdr_action_t *action = qdr_action(qdrh_unmap_destination); + action->args.route_table.router_maskbit = router_maskbit; + action->args.route_table.address = qdr_field(address); + action->args.route_table.address_phase = phase; + action->args.route_table.address_class = aclass; + qdr_action_enqueue(core, action); +} + +void qdr_core_route_table_handlers(qdr_core_t *core, + void *context, + qdr_mobile_added_t mobile_added, + qdr_mobile_removed_t mobile_removed, + qdr_link_lost_t link_lost) +{ + core->rt_context = context; + core->rt_mobile_added = mobile_added; + core->rt_mobile_removed = mobile_removed; + core->rt_link_lost = link_lost; +} + + +//================================================================================== +// Internal Functions +//================================================================================== + +static qdr_action_t *qdr_action(qdr_action_handler_t action_handler) +{ + qdr_action_t *action = new_qdr_action_t(); + ZERO(action); + action->action_handler = action_handler; + return action; +} + +static void qdr_action_enqueue(qdr_core_t *core, qdr_action_t *action) +{ + sys_mutex_lock(core->lock); + DEQ_INSERT_TAIL(core->action_list, action); + sys_mutex_unlock(core->lock); +} + + +//================================================================================== +// In-Thread Functions +//================================================================================== + +static void qdrh_add_router(qdr_core_t *core, qdr_action_t *action) +{ +} + + +static void qdrh_del_router(qdr_core_t *core, qdr_action_t *action) +{ +} + + +static void qdrh_set_link(qdr_core_t *core, qdr_action_t *action) +{ +} + + +static void qdrh_remove_link(qdr_core_t *core, qdr_action_t *action) +{ +} + + +static void qdrh_set_next_hop(qdr_core_t *core, qdr_action_t *action) +{ +} + + +static void qdrh_remove_next_hop(qdr_core_t *core, qdr_action_t *action) +{ +} + + +static void qdrh_set_valid_origins(qdr_core_t *core, qdr_action_t *action) +{ +} + + +static void qdrh_map_destination(qdr_core_t *core, qdr_action_t *action) +{ +} + + +static void qdrh_unmap_destination(qdr_core_t *core, qdr_action_t *action) +{ +} + + diff --git a/src/router_core/route_tables.h b/src/router_core/route_tables.h new file mode 100644 index 0000000000..13980c406a --- /dev/null +++ b/src/router_core/route_tables.h @@ -0,0 +1,22 @@ +#ifndef __core_route_tables_h__ +#define __core_route_tables_h__ 1 +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#endif diff --git a/src/router_core/router_core.c b/src/router_core/router_core.c index eba6150d12..7293caf0de 100644 --- a/src/router_core/router_core.c +++ b/src/router_core/router_core.c @@ -62,4 +62,38 @@ void qdr_core_free(qdr_core_t *core) } +ALLOC_DECLARE(qdr_field_t); +ALLOC_DEFINE(qdr_field_t); + +qdr_field_t *qdr_field(const char *text) +{ + size_t length = strlen(text); + size_t ilength = length; + qdr_field_t *field = new_qdr_field_t(); + qd_buffer_t *buf; + ZERO(field); + + while (length > 0) { + buf = qd_buffer(); + size_t cap = qd_buffer_capacity(buf); + size_t copy = length > cap ? cap : length; + memcpy(qd_buffer_cursor(buf), text, copy); + qd_buffer_insert(buf, copy); + length -= copy; + text += copy; + DEQ_INSERT_TAIL(field->buffers, buf); + } + + field->iterator = qd_field_iterator_buffer(DEQ_HEAD(field->buffers), 0, ilength); + + return field; +} + + +void qdr_field_free(qdr_field_t *field) +{ + qd_field_iterator_free(field->iterator); + qd_buffer_list_free_buffers(&field->buffers); + free_qdr_field_t(field); +} diff --git a/src/router_core/router_core_private.h b/src/router_core/router_core_private.h index 673ae684a2..94ec4a13b6 100644 --- a/src/router_core/router_core_private.h +++ b/src/router_core/router_core_private.h @@ -26,40 +26,19 @@ #include typedef struct { - qd_buffer_t *buffer; + qd_buffer_list_t buffers; qd_field_iterator_t *iterator; } qdr_field_t; -typedef enum { - QDR_ACTION_ADD_ROUTER, - QDR_ACTION_DEL_ROUTER, - QDR_ACTION_SET_LINK, - QDR_ACTION_REMOVE_LINK, - QDR_ACTION_SET_NEXT_HOP, - QDR_ACTION_REMOVE_NEXT_HOP, - QDR_ACTION_SET_VALID_ORIGINS, - QDR_ACTION_MAP_DESTINATION, - QDR_ACTION_UNMAP_DESTINATION, - QDR_ACTION_SUBSCRIBE, - QDR_ACTION_CONNECTION_OPENED, - QDR_ACTION_CONNECTION_CLOSED, - QDR_ACTION_LINK_FIRST_ATTACH, - QDR_ACTION_LINK_SECOND_ATTACH, - QDR_ACTION_LINK_DETACH, - QDR_ACTION_DELIVER, - QDR_ACTION_DELIVER_TO, - QDR_ACTION_DISPOSITION_CHANGE, - QDR_ACTION_FLOW_CHANGE, - QDR_ACTION_MANAGE_CREATE, - QDR_ACTION_MANAGE_DELETE, - QDR_ACTION_MANAGE_READ, - QDR_ACTION_MANAGE_GET_FIRST, - QDR_ACTION_MANAGE_GET_NEXT -} qdr_action_type_t; +qdr_field_t *qdr_field(const char *string); +void qdr_field_free(qdr_field_t *field); -typedef struct qdr_action_t { - DEQ_LINKS(struct qdr_action_t); - qdr_action_type_t action_type; +typedef struct qdr_action_t qdr_action_t; +typedef void (*qdr_action_handler_t) (qdr_core_t *core, qdr_action_t *action); + +struct qdr_action_t { + DEQ_LINKS(qdr_action_t); + qdr_action_handler_t action_handler; union { struct { int link_maskbit; @@ -71,7 +50,7 @@ typedef struct qdr_action_t { char address_phase; } route_table; } args; -} qdr_action_t; +}; ALLOC_DECLARE(qdr_action_t); DEQ_DECLARE(qdr_action_t, qdr_action_list_t); @@ -83,6 +62,11 @@ struct qdr_core_t { sys_thread_t *thread; bool running; qdr_action_list_t action_list; + + void *rt_context; + qdr_mobile_added_t rt_mobile_added; + qdr_mobile_removed_t rt_mobile_removed; + qdr_link_lost_t rt_link_lost; }; void *router_core_thread(void *arg); diff --git a/src/router_core/router_core_thread.c b/src/router_core/router_core_thread.c index 1d08bd36dd..87f8c02b8e 100644 --- a/src/router_core/router_core_thread.c +++ b/src/router_core/router_core_thread.c @@ -30,11 +30,6 @@ ALLOC_DEFINE(qdr_action_t); -static void router_core_do_action(qdr_core_t *core, qdr_action_t *action) -{ -} - - void *router_core_thread(void *arg) { qdr_core_t *core = (qdr_core_t*) arg; @@ -69,7 +64,7 @@ void *router_core_thread(void *arg) DEQ_REMOVE_HEAD(action_list); if (core->running) - router_core_do_action(core, action); + action->action_handler(core, action); free_qdr_action_t(action); action = DEQ_HEAD(action_list); From 382fb1b030115bc173edd81119ececd76c215c3e Mon Sep 17 00:00:00 2001 From: Ted Ross Date: Wed, 21 Oct 2015 11:57:27 -0400 Subject: [PATCH 04/22] DISPATCH-179 - Ported in the first handler: add_router --- src/router_core/route_tables.c | 82 +++++++++++++++- src/router_core/route_tables.h | 22 ----- src/router_core/router_core.c | 81 ++++++++++++++-- src/router_core/router_core_private.h | 134 ++++++++++++++++++++++++++ 4 files changed, 290 insertions(+), 29 deletions(-) delete mode 100644 src/router_core/route_tables.h diff --git a/src/router_core/route_tables.c b/src/router_core/route_tables.c index bd102f040e..d039ff16b6 100644 --- a/src/router_core/route_tables.c +++ b/src/router_core/route_tables.c @@ -18,7 +18,6 @@ */ #include "router_core_private.h" -//#include "route_tables.h" static qdr_action_t *qdr_action(qdr_action_handler_t action_handler); static void qdr_action_enqueue(qdr_core_t *core, qdr_action_t *action); @@ -33,6 +32,8 @@ static void qdrh_set_valid_origins(qdr_core_t *core, qdr_action_t *action); static void qdrh_map_destination(qdr_core_t *core, qdr_action_t *action); static void qdrh_unmap_destination(qdr_core_t *core, qdr_action_t *action); +static qd_address_semantics_t router_addr_semantics = QD_FANOUT_SINGLE | QD_BIAS_CLOSEST | QD_CONGESTION_DROP | QD_DROP_FOR_SLOW_CONSUMERS | QD_BYPASS_VALID_ORIGINS; + //================================================================================== // Interface Functions @@ -156,8 +157,87 @@ static void qdr_action_enqueue(qdr_core_t *core, qdr_action_t *action) // In-Thread Functions //================================================================================== +void qdr_route_table_setup(qdr_core_t *core) +{ + DEQ_INIT(core->addrs); + //DEQ_INIT(core->links); + DEQ_INIT(core->routers); + core->addr_hash = qd_hash(10, 32, 0); + + core->router_addr = qdr_add_local_address(core, "qdrouter", QD_SEMANTICS_ROUTER_CONTROL); + core->routerma_addr = qdr_add_local_address(core, "qdrouter.ma", QD_SEMANTICS_DEFAULT); + core->hello_addr = qdr_add_local_address(core, "qdhello", QD_SEMANTICS_ROUTER_CONTROL); + + core->routers_by_mask_bit = NEW_PTR_ARRAY(qdr_node_t, qd_bitmask_width()); + for (int idx = 0; idx < qd_bitmask_width(); idx++) + core->routers_by_mask_bit[idx] = 0; +} + + static void qdrh_add_router(qdr_core_t *core, qdr_action_t *action) { + int router_maskbit = action->args.route_table.router_maskbit; + + if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { + qd_log(core->log, QD_LOG_CRITICAL, "add_router: Router maskbit out of range: %d", router_maskbit); + return; + } + + if (core->routers_by_mask_bit[router_maskbit] != 0) { + qd_log(core->log, QD_LOG_CRITICAL, "add_router: Router maskbit already in use: %d", router_maskbit); + return; + } + + // + // Hash lookup the address to ensure there isn't an existing router address. + // + qd_field_iterator_t *iter = action->args.route_table.address->iterator; + qdr_address_t *addr; + + qd_address_iterator_reset_view(iter, ITER_VIEW_ADDRESS_HASH); + qd_hash_retrieve(core->addr_hash, iter, (void**) &addr); + assert(addr == 0); + + // + // Create an address record for this router and insert it in the hash table. + // This record will be found whenever a "foreign" topological address to this + // remote router is looked up. + // + addr = qdr_address(router_addr_semantics); + qd_hash_insert(core->addr_hash, iter, addr, &addr->hash_handle); + DEQ_INSERT_TAIL(core->addrs, addr); + + // + // Create a router-node record to represent the remote router. + // + qdr_node_t *rnode = new_qdr_node_t(); + DEQ_ITEM_INIT(rnode); + rnode->owning_addr = addr; + rnode->mask_bit = router_maskbit; + rnode->next_hop = 0; + rnode->peer_link = 0; + rnode->ref_count = 0; + rnode->valid_origins = qd_bitmask(0); + + DEQ_INSERT_TAIL(core->routers, rnode); + + // + // Link the router record to the address record. + // + qdr_add_node_ref(&addr->rnodes, rnode); + + // + // Link the router record to the router address records. + // + qdr_add_node_ref(&core->router_addr->rnodes, rnode); + qdr_add_node_ref(&core->routerma_addr->rnodes, rnode); + + // + // Add the router record to the mask-bit index. + // + core->routers_by_mask_bit[router_maskbit] = rnode; + + qdr_field_free(action->args.route_table.address); } diff --git a/src/router_core/route_tables.h b/src/router_core/route_tables.h deleted file mode 100644 index 13980c406a..0000000000 --- a/src/router_core/route_tables.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __core_route_tables_h__ -#define __core_route_tables_h__ 1 -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#endif diff --git a/src/router_core/router_core.c b/src/router_core/router_core.c index 7293caf0de..d7135837f9 100644 --- a/src/router_core/router_core.c +++ b/src/router_core/router_core.c @@ -18,6 +18,12 @@ */ #include "router_core_private.h" +#include + + +ALLOC_DEFINE(qdr_address_t); +ALLOC_DEFINE(qdr_node_t); +ALLOC_DEFINE(qdr_link_ref_t); qdr_core_t *qdr_core(void) @@ -67,12 +73,16 @@ ALLOC_DEFINE(qdr_field_t); qdr_field_t *qdr_field(const char *text) { - size_t length = strlen(text); - size_t ilength = length; + size_t length = strlen(text); + size_t ilength = length; + + if (length == 0) + return 0; + qdr_field_t *field = new_qdr_field_t(); qd_buffer_t *buf; - ZERO(field); + ZERO(field); while (length > 0) { buf = qd_buffer(); size_t cap = qd_buffer_capacity(buf); @@ -92,8 +102,67 @@ qdr_field_t *qdr_field(const char *text) void qdr_field_free(qdr_field_t *field) { - qd_field_iterator_free(field->iterator); - qd_buffer_list_free_buffers(&field->buffers); - free_qdr_field_t(field); + if (field) { + qd_field_iterator_free(field->iterator); + qd_buffer_list_free_buffers(&field->buffers); + free_qdr_field_t(field); + } +} + + +qdr_address_t *qdr_address(qd_address_semantics_t semantics) +{ + qdr_address_t *addr = new_qdr_address_t(); + ZERO(addr); + addr->semantics = semantics; + addr->forwarder = qd_router_get_forwarder(semantics); + return addr; +} + + +qdr_address_t *qdr_add_local_address(qdr_core_t *core, const char *address, qd_address_semantics_t semantics) +{ + char addr_string[1000]; + qdr_address_t *addr = 0; + qd_field_iterator_t *iter = 0; + + snprintf(addr_string, sizeof(addr_string), "L%s", address); + iter = qd_address_iterator_string(addr_string, ITER_VIEW_ALL); + + qd_hash_retrieve(core->addr_hash, iter, (void**) &addr); + if (!addr) { + addr = qdr_address(semantics); + qd_hash_insert(core->addr_hash, iter, addr, &addr->hash_handle); + DEQ_ITEM_INIT(addr); + DEQ_INSERT_TAIL(core->addrs, addr); + addr->block_deletion = true; + } + qd_field_iterator_free(iter); + return addr; +} + + +void qdr_add_link_ref(qdr_link_ref_list_t *ref_list, qdr_link_t *link) +{ + qdr_link_ref_t *ref = new_qdr_link_ref_t(); + DEQ_ITEM_INIT(ref); + ref->link = link; + link->ref = ref; + DEQ_INSERT_TAIL(*ref_list, ref); +} + + +void qdr_del_link_ref(qdr_link_ref_list_t *ref_list, qdr_link_t *link) +{ +} + + +void qdr_add_node_ref(qdr_router_ref_list_t *ref_list, qdr_node_t *rnode) +{ +} + + +void qdr_del_node_ref(qdr_router_ref_list_t *ref_list, qdr_node_t *rnode) +{ } diff --git a/src/router_core/router_core_private.h b/src/router_core/router_core_private.h index 94ec4a13b6..580329993a 100644 --- a/src/router_core/router_core_private.h +++ b/src/router_core/router_core_private.h @@ -25,6 +25,10 @@ #include #include +/** + * qdr_field_t - This type is used to pass variable-length fields (strings, etc.) into + * and out of the router-core thread. + */ typedef struct { qd_buffer_list_t buffers; qd_field_iterator_t *iterator; @@ -33,6 +37,10 @@ typedef struct { qdr_field_t *qdr_field(const char *string); void qdr_field_free(qdr_field_t *field); + +/** + * qdr_action_t - This type represents one work item to be performed by the router-core thread. + */ typedef struct qdr_action_t qdr_action_t; typedef void (*qdr_action_handler_t) (qdr_core_t *core, qdr_action_t *action); @@ -55,6 +63,119 @@ struct qdr_action_t { ALLOC_DECLARE(qdr_action_t); DEQ_DECLARE(qdr_action_t, qdr_action_list_t); +typedef struct qdr_address_t qdr_address_t; +typedef struct qdr_node_t qdr_node_t; +typedef struct qdr_router_ref_t qdr_router_ref_t; +typedef struct qdr_link_ref_t qdr_link_ref_t; +typedef struct qdr_lrp_t qdr_lrp_t; +typedef struct qdr_lrp_ref_t qdr_lrp_ref_t; + +struct qdr_node_t { + DEQ_LINKS(qdr_node_t); + qdr_address_t *owning_addr; + int mask_bit; + qdr_node_t *next_hop; ///< Next hop node _if_ this is not a neighbor node + qdr_link_t *peer_link; ///< Outgoing link _if_ this is a neighbor node + uint32_t ref_count; + qd_bitmask_t *valid_origins; +}; + +ALLOC_DECLARE(qdr_node_t); +DEQ_DECLARE(qdr_node_t, qdr_node_list_t); + + +struct qdr_router_ref_t { + DEQ_LINKS(qdr_router_ref_t); + qdr_node_t *router; +}; + +ALLOC_DECLARE(qdr_router_ref_t); +DEQ_DECLARE(qdr_router_ref_t, qdr_router_ref_list_t); + + +struct qdr_link_t { + DEQ_LINKS(qdr_link_t); + int mask_bit; ///< Unique mask bit if this is an inter-router link + qd_link_type_t link_type; + qd_direction_t link_direction; + qdr_address_t *owning_addr; ///< [ref] Address record that owns this link + //qd_waypoint_t *waypoint; ///< [ref] Waypoint that owns this link + qd_link_t *link; ///< [own] Link pointer + qdr_link_t *connected_link; ///< [ref] If this is a link-route, reference the connected link + qdr_link_ref_t *ref; ///< Pointer to a containing reference object + char *target; ///< Target address for incoming links + qd_routed_event_list_t event_fifo; ///< FIFO of outgoing delivery/link events (no messages) + qd_routed_event_list_t msg_fifo; ///< FIFO of incoming or outgoing message deliveries + qd_router_delivery_list_t deliveries; ///< [own] outstanding unsettled deliveries + bool strip_inbound_annotations; /// Date: Wed, 21 Oct 2015 17:42:07 -0400 Subject: [PATCH 05/22] DISPATCH-179 - Added the remainder of the router-engine functions. --- include/qpid/dispatch/router_core.h | 2 +- src/router_core/route_tables.c | 337 ++++++++++++++++++++++---- src/router_core/router_core.c | 1 + src/router_core/router_core_private.h | 21 +- 4 files changed, 300 insertions(+), 61 deletions(-) diff --git a/include/qpid/dispatch/router_core.h b/include/qpid/dispatch/router_core.h index 87bcd5c768..11f030f622 100644 --- a/include/qpid/dispatch/router_core.h +++ b/include/qpid/dispatch/router_core.h @@ -53,7 +53,7 @@ void qdr_core_remove_link(qdr_core_t *core, int router_maskbit); void qdr_core_set_next_hop(qdr_core_t *core, int router_maskbit, int nh_router_maskbit); void qdr_core_remove_next_hop(qdr_core_t *core, int router_maskbit); void qdr_core_set_valid_origins(qdr_core_t *core, int router_maskbit, qd_bitmask_t *routers); -void qdr_core_map_destination(qdr_core_t *core, int router_maskbit, const char *address, char aclass, char phase); +void qdr_core_map_destination(qdr_core_t *core, int router_maskbit, const char *address, char aclass, char phase, qd_address_semantics_t sem); void qdr_core_unmap_destination(qdr_core_t *core, int router_maskbit, const char *address, char aclass, char phase); typedef void (*qdr_mobile_added_t) (void *context, const char *address); diff --git a/src/router_core/route_tables.c b/src/router_core/route_tables.c index d039ff16b6..137d0e6aa3 100644 --- a/src/router_core/route_tables.c +++ b/src/router_core/route_tables.c @@ -99,13 +99,14 @@ void qdr_core_set_valid_origins(qdr_core_t *core, int router_maskbit, qd_bitmask } -void qdr_core_map_destination(qdr_core_t *core, int router_maskbit, const char *address, char aclass, char phase) +void qdr_core_map_destination(qdr_core_t *core, int router_maskbit, const char *address, char aclass, char phase, qd_address_semantics_t sem) { qdr_action_t *action = qdr_action(qdrh_map_destination); action->args.route_table.router_maskbit = router_maskbit; action->args.route_table.address = qdr_field(address); action->args.route_table.address_phase = phase; action->args.route_table.address_class = aclass; + action->args.route_table.semantics = sem; qdr_action_enqueue(core, action); } @@ -160,7 +161,7 @@ static void qdr_action_enqueue(qdr_core_t *core, qdr_action_t *action) void qdr_route_table_setup(qdr_core_t *core) { DEQ_INIT(core->addrs); - //DEQ_INIT(core->links); + DEQ_INIT(core->links); DEQ_INIT(core->routers); core->addr_hash = qd_hash(10, 32, 0); @@ -168,116 +169,348 @@ void qdr_route_table_setup(qdr_core_t *core) core->routerma_addr = qdr_add_local_address(core, "qdrouter.ma", QD_SEMANTICS_DEFAULT); core->hello_addr = qdr_add_local_address(core, "qdhello", QD_SEMANTICS_ROUTER_CONTROL); - core->routers_by_mask_bit = NEW_PTR_ARRAY(qdr_node_t, qd_bitmask_width()); - for (int idx = 0; idx < qd_bitmask_width(); idx++) - core->routers_by_mask_bit[idx] = 0; + core->routers_by_mask_bit = NEW_PTR_ARRAY(qdr_node_t, qd_bitmask_width()); + core->out_links_by_mask_bit = NEW_PTR_ARRAY(qdr_link_t, qd_bitmask_width()); + for (int idx = 0; idx < qd_bitmask_width(); idx++) { + core->routers_by_mask_bit[idx] = 0; + core->out_links_by_mask_bit[idx] = 0; + } } static void qdrh_add_router(qdr_core_t *core, qdr_action_t *action) +{ + int router_maskbit = action->args.route_table.router_maskbit; + qdr_field_t *address = action->args.route_table.address; + + do { + if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { + qd_log(core->log, QD_LOG_CRITICAL, "add_router: Router maskbit out of range: %d", router_maskbit); + break; + } + + if (core->routers_by_mask_bit[router_maskbit] != 0) { + qd_log(core->log, QD_LOG_CRITICAL, "add_router: Router maskbit already in use: %d", router_maskbit); + break; + } + + // + // Hash lookup the address to ensure there isn't an existing router address. + // + qd_field_iterator_t *iter = address->iterator; + qdr_address_t *addr; + + qd_address_iterator_reset_view(iter, ITER_VIEW_ADDRESS_HASH); + qd_hash_retrieve(core->addr_hash, iter, (void**) &addr); + + if (addr) { + qd_log(core->log, QD_LOG_CRITICAL, "add_router: Data inconsistency for router-maskbit %d", router_maskbit); + assert(addr == 0); // Crash in debug mode. This should never happen + break; + } + + // + // Create an address record for this router and insert it in the hash table. + // This record will be found whenever a "foreign" topological address to this + // remote router is looked up. + // + addr = qdr_address(router_addr_semantics); + qd_hash_insert(core->addr_hash, iter, addr, &addr->hash_handle); + DEQ_INSERT_TAIL(core->addrs, addr); + + // + // Create a router-node record to represent the remote router. + // + qdr_node_t *rnode = new_qdr_node_t(); + DEQ_ITEM_INIT(rnode); + rnode->owning_addr = addr; + rnode->mask_bit = router_maskbit; + rnode->next_hop = 0; + rnode->peer_link = 0; + rnode->ref_count = 0; + rnode->valid_origins = qd_bitmask(0); + + DEQ_INSERT_TAIL(core->routers, rnode); + + // + // Link the router record to the address record. + // + qdr_add_node_ref(&addr->rnodes, rnode); + + // + // Link the router record to the router address records. + // + qdr_add_node_ref(&core->router_addr->rnodes, rnode); + qdr_add_node_ref(&core->routerma_addr->rnodes, rnode); + + // + // Add the router record to the mask-bit index. + // + core->routers_by_mask_bit[router_maskbit] = rnode; + } while (false); + + qdr_field_free(address); +} + + +static void qdrh_del_router(qdr_core_t *core, qdr_action_t *action) { int router_maskbit = action->args.route_table.router_maskbit; if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { - qd_log(core->log, QD_LOG_CRITICAL, "add_router: Router maskbit out of range: %d", router_maskbit); + qd_log(core->log, QD_LOG_CRITICAL, "del_router: Router maskbit out of range: %d", router_maskbit); return; } - if (core->routers_by_mask_bit[router_maskbit] != 0) { - qd_log(core->log, QD_LOG_CRITICAL, "add_router: Router maskbit already in use: %d", router_maskbit); + if (core->routers_by_mask_bit[router_maskbit] == 0) { + qd_log(core->log, QD_LOG_CRITICAL, "del_router: Deleting nonexistent router: %d", router_maskbit); return; } - // - // Hash lookup the address to ensure there isn't an existing router address. - // - qd_field_iterator_t *iter = action->args.route_table.address->iterator; - qdr_address_t *addr; - - qd_address_iterator_reset_view(iter, ITER_VIEW_ADDRESS_HASH); - qd_hash_retrieve(core->addr_hash, iter, (void**) &addr); - assert(addr == 0); + qdr_node_t *rnode = core->routers_by_mask_bit[router_maskbit]; + qdr_address_t *oaddr = rnode->owning_addr; + assert(oaddr); // - // Create an address record for this router and insert it in the hash table. - // This record will be found whenever a "foreign" topological address to this - // remote router is looked up. + // Unlink the router node from the address record // - addr = qdr_address(router_addr_semantics); - qd_hash_insert(core->addr_hash, iter, addr, &addr->hash_handle); - DEQ_INSERT_TAIL(core->addrs, addr); + qdr_del_node_ref(&oaddr->rnodes, rnode); // - // Create a router-node record to represent the remote router. + // While the router node has a non-zero reference count, look for addresses + // to unlink the node from. // - qdr_node_t *rnode = new_qdr_node_t(); - DEQ_ITEM_INIT(rnode); - rnode->owning_addr = addr; - rnode->mask_bit = router_maskbit; - rnode->next_hop = 0; - rnode->peer_link = 0; - rnode->ref_count = 0; - rnode->valid_origins = qd_bitmask(0); - - DEQ_INSERT_TAIL(core->routers, rnode); + qdr_address_t *addr = DEQ_HEAD(core->addrs); + while (addr && rnode->ref_count > 0) { + qdr_del_node_ref(&addr->rnodes, rnode); + addr = DEQ_NEXT(addr); + } + assert(rnode->ref_count == 0); // - // Link the router record to the address record. + // Free the router node and the owning address records. // - qdr_add_node_ref(&addr->rnodes, rnode); + qd_bitmask_free(rnode->valid_origins); + DEQ_REMOVE(core->routers, rnode); + free_qdr_node_t(rnode); + + qd_hash_remove_by_handle(core->addr_hash, oaddr->hash_handle); + DEQ_REMOVE(core->addrs, oaddr); + qd_hash_handle_free(oaddr->hash_handle); + core->routers_by_mask_bit[router_maskbit] = 0; + free_qdr_address_t(oaddr); +} - // - // Link the router record to the router address records. - // - qdr_add_node_ref(&core->router_addr->rnodes, rnode); - qdr_add_node_ref(&core->routerma_addr->rnodes, rnode); - // - // Add the router record to the mask-bit index. - // - core->routers_by_mask_bit[router_maskbit] = rnode; +static void qdrh_set_link(qdr_core_t *core, qdr_action_t *action) +{ + int router_maskbit = action->args.route_table.router_maskbit; + int link_maskbit = action->args.route_table.link_maskbit; - qdr_field_free(action->args.route_table.address); -} + if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { + qd_log(core->log, QD_LOG_CRITICAL, "set_link: Router maskbit out of range: %d", router_maskbit); + return; + } + if (link_maskbit >= qd_bitmask_width() || link_maskbit < 0) { + qd_log(core->log, QD_LOG_CRITICAL, "set_link: Link maskbit out of range: %d", link_maskbit); + return; + } -static void qdrh_del_router(qdr_core_t *core, qdr_action_t *action) -{ -} + if (core->out_links_by_mask_bit[link_maskbit] == 0) { + qd_log(core->log, QD_LOG_CRITICAL, "set_link: Invalid link reference: %d", link_maskbit); + return; + } + if (core->routers_by_mask_bit[router_maskbit] == 0) { + qd_log(core->log, QD_LOG_CRITICAL, "set_link: Router not found"); + return; + } -static void qdrh_set_link(qdr_core_t *core, qdr_action_t *action) -{ + // + // Add the peer_link reference to the router record. + // + qdr_node_t *rnode = core->routers_by_mask_bit[router_maskbit]; + rnode->peer_link = core->out_links_by_mask_bit[link_maskbit]; } static void qdrh_remove_link(qdr_core_t *core, qdr_action_t *action) { + int router_maskbit = action->args.route_table.router_maskbit; + + if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { + qd_log(core->log, QD_LOG_CRITICAL, "remove_link: Router maskbit out of range: %d", router_maskbit); + return; + } + + if (core->routers_by_mask_bit[router_maskbit] == 0) { + qd_log(core->log, QD_LOG_CRITICAL, "remove_link: Router not found"); + return; + } + + qdr_node_t *rnode = core->routers_by_mask_bit[router_maskbit]; + rnode->peer_link = 0; } static void qdrh_set_next_hop(qdr_core_t *core, qdr_action_t *action) { + int router_maskbit = action->args.route_table.router_maskbit; + int nh_router_maskbit = action->args.route_table.nh_router_maskbit; + + if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { + qd_log(core->log, QD_LOG_CRITICAL, "set_next_hop: Router maskbit out of range: %d", router_maskbit); + return; + } + + if (nh_router_maskbit >= qd_bitmask_width() || nh_router_maskbit < 0) { + qd_log(core->log, QD_LOG_CRITICAL, "set_next_hop: Next hop router maskbit out of range: %d", router_maskbit); + return; + } + + if (core->routers_by_mask_bit[router_maskbit] == 0) { + qd_log(core->log, QD_LOG_CRITICAL, "set_next_hop: Router not found"); + return; + } + + if (core->routers_by_mask_bit[nh_router_maskbit] == 0) { + qd_log(core->log, QD_LOG_CRITICAL, "set_next_hop: Next hop router not found"); + return; + } + + if (router_maskbit != nh_router_maskbit) { + qdr_node_t *rnode = core->routers_by_mask_bit[router_maskbit]; + rnode->next_hop = core->routers_by_mask_bit[nh_router_maskbit]; + } } static void qdrh_remove_next_hop(qdr_core_t *core, qdr_action_t *action) { + int router_maskbit = action->args.route_table.router_maskbit; + + if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { + qd_log(core->log, QD_LOG_CRITICAL, "remove_next_hop: Router maskbit out of range: %d", router_maskbit); + return; + } + + qdr_node_t *rnode = core->routers_by_mask_bit[router_maskbit]; + rnode->next_hop = 0; } static void qdrh_set_valid_origins(qdr_core_t *core, qdr_action_t *action) { + int router_maskbit = action->args.route_table.router_maskbit; + qd_bitmask_t *valid_origins = action->args.route_table.router_set; + + do { + if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { + qd_log(core->log, QD_LOG_CRITICAL, "set_valid_origins: Router maskbit out of range: %d", router_maskbit); + break; + } + + if (core->routers_by_mask_bit[router_maskbit] == 0) { + qd_log(core->log, QD_LOG_CRITICAL, "set_valid_origins: Router not found"); + break; + } + + qdr_node_t *rnode = core->routers_by_mask_bit[router_maskbit]; + if (rnode->valid_origins) + qd_bitmask_free(rnode->valid_origins); + rnode->valid_origins = valid_origins; + valid_origins = 0; + } while (false); + + if (valid_origins) + qd_bitmask_free(valid_origins); } static void qdrh_map_destination(qdr_core_t *core, qdr_action_t *action) { + // + // TODO - handle the class-prefix and phase explicitly + // + + int router_maskbit = action->args.route_table.router_maskbit; + qdr_field_t *address = action->args.route_table.address; + + do { + if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { + qd_log(core->log, QD_LOG_CRITICAL, "map_destination: Router maskbit out of range: %d", router_maskbit); + break; + } + + if (core->routers_by_mask_bit[router_maskbit] == 0) { + qd_log(core->log, QD_LOG_CRITICAL, "map_destination: Router not found"); + break; + } + + qd_field_iterator_t *iter = address->iterator; + qdr_address_t *addr = 0; + + qd_hash_retrieve(core->addr_hash, iter, (void**) &addr); + if (!addr) { + addr = qdr_address(action->args.route_table.semantics); + qd_hash_insert(core->addr_hash, iter, addr, &addr->hash_handle); + DEQ_ITEM_INIT(addr); + DEQ_INSERT_TAIL(core->addrs, addr); + } + + qdr_node_t *rnode = core->routers_by_mask_bit[router_maskbit]; + qdr_add_node_ref(&addr->rnodes, rnode); + + // + // TODO - If this affects a waypoint, create the proper side effects + // + } while (false); + + qdr_field_free(address); } static void qdrh_unmap_destination(qdr_core_t *core, qdr_action_t *action) { + int router_maskbit = action->args.route_table.router_maskbit; + qdr_field_t *address = action->args.route_table.address; + + do { + if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { + qd_log(core->log, QD_LOG_CRITICAL, "unmap_destination: Router maskbit out of range: %d", router_maskbit); + break; + } + + if (core->routers_by_mask_bit[router_maskbit] == 0) { + qd_log(core->log, QD_LOG_CRITICAL, "unmap_destination: Router not found"); + break; + } + + qdr_node_t *rnode = core->routers_by_mask_bit[router_maskbit]; + qd_field_iterator_t *iter = address->iterator; + qdr_address_t *addr = 0; + + qd_hash_retrieve(core->addr_hash, iter, (void**) &addr); + + if (!addr) { + qd_log(core->log, QD_LOG_CRITICAL, "unmap_destination: Address not found"); + break; + } + + qdr_del_node_ref(&addr->rnodes, rnode); + + // + // TODO - If this affects a waypoint, create the proper side effects + // + + // + // TODO - Port "check-addr" into this module + // + //qd_router_check_addr(router, addr, 0); + } while (false); + + qdr_field_free(address); } diff --git a/src/router_core/router_core.c b/src/router_core/router_core.c index d7135837f9..0b94b4e3f1 100644 --- a/src/router_core/router_core.c +++ b/src/router_core/router_core.c @@ -23,6 +23,7 @@ ALLOC_DEFINE(qdr_address_t); ALLOC_DEFINE(qdr_node_t); +ALLOC_DEFINE(qdr_link_t); ALLOC_DEFINE(qdr_link_ref_t); diff --git a/src/router_core/router_core_private.h b/src/router_core/router_core_private.h index 580329993a..0837f58d4e 100644 --- a/src/router_core/router_core_private.h +++ b/src/router_core/router_core_private.h @@ -49,13 +49,14 @@ struct qdr_action_t { qdr_action_handler_t action_handler; union { struct { - int link_maskbit; - int router_maskbit; - int nh_router_maskbit; - qd_bitmask_t *router_set; - qdr_field_t *address; - char address_class; - char address_phase; + int link_maskbit; + int router_maskbit; + int nh_router_maskbit; + qd_bitmask_t *router_set; + qdr_field_t *address; + char address_class; + char address_phase; + qd_address_semantics_t semantics; } route_table; } args; }; @@ -111,6 +112,9 @@ struct qdr_link_t { bool strip_outbound_annotations; /// Date: Wed, 21 Oct 2015 21:04:52 -0400 Subject: [PATCH 06/22] DISPATCH-179 - Filled in more missing function bodies. --- src/router_core/route_tables.c | 63 +++++++++++++++++++++++++++++++--- src/router_core/router_core.c | 21 ++++++++++++ 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/src/router_core/route_tables.c b/src/router_core/route_tables.c index 137d0e6aa3..e1095fb45b 100644 --- a/src/router_core/route_tables.c +++ b/src/router_core/route_tables.c @@ -178,6 +178,64 @@ void qdr_route_table_setup(qdr_core_t *core) } +/** + * Check an address to see if it no longer has any associated destinations. + * Depending on its policy, the address may be eligible for being closed out + * (i.e. Logging its terminal statistics and freeing its resources). + */ +static void qdr_check_addr(qdr_core_t *core, qdr_address_t *addr, bool was_local) +{ + if (addr == 0) + return; + + bool to_delete = false; + bool no_more_locals = false; + qdr_field_t *key_field = 0; + + // + // If the address has no in-process consumer or destinations, it should be + // deleted. + // + if (addr->on_message == 0 && + DEQ_SIZE(addr->rlinks) == 0 && DEQ_SIZE(addr->rnodes) == 0 && + !addr->waypoint && !addr->block_deletion) + to_delete = true; + + // + // If we have just removed a local linkage and it was the last local linkage, + // we need to notify the router module that there is no longer a local + // presence of this address. + // + if (was_local && DEQ_SIZE(addr->rlinks) == 0) { + no_more_locals = true; + const unsigned char *key = qd_hash_key_by_handle(addr->hash_handle); + if (key && (key[0] == 'M' || key[0] == 'C' || key[0] == 'D')) + key_field = qdr_field((const char*) key); + } + + if (to_delete) { + // + // Delete the address but grab the hash key so we can use it outside the + // critical section. + // + qd_hash_remove_by_handle(core->addr_hash, addr->hash_handle); + DEQ_REMOVE(core->addrs, addr); + qd_hash_handle_free(addr->hash_handle); + free_qdr_address_t(addr); + } + + // + // If the address is mobile-class and it was just removed from a local link, + // tell the router module that it is no longer attached locally. + // + if (no_more_locals && key_field) { + // + // TODO - Defer-call mobile-removed + // + } +} + + static void qdrh_add_router(qdr_core_t *core, qdr_action_t *action) { int router_maskbit = action->args.route_table.router_maskbit; @@ -504,10 +562,7 @@ static void qdrh_unmap_destination(qdr_core_t *core, qdr_action_t *action) // TODO - If this affects a waypoint, create the proper side effects // - // - // TODO - Port "check-addr" into this module - // - //qd_router_check_addr(router, addr, 0); + qdr_check_addr(core, addr, false); } while (false); qdr_field_free(address); diff --git a/src/router_core/router_core.c b/src/router_core/router_core.c index 0b94b4e3f1..8f31b7a8e2 100644 --- a/src/router_core/router_core.c +++ b/src/router_core/router_core.c @@ -24,6 +24,7 @@ ALLOC_DEFINE(qdr_address_t); ALLOC_DEFINE(qdr_node_t); ALLOC_DEFINE(qdr_link_t); +ALLOC_DEFINE(qdr_router_ref_t); ALLOC_DEFINE(qdr_link_ref_t); @@ -155,15 +156,35 @@ void qdr_add_link_ref(qdr_link_ref_list_t *ref_list, qdr_link_t *link) void qdr_del_link_ref(qdr_link_ref_list_t *ref_list, qdr_link_t *link) { + if (link->ref) { + DEQ_REMOVE(*ref_list, link->ref); + free_qdr_link_ref_t(link->ref); + link->ref = 0; + } } void qdr_add_node_ref(qdr_router_ref_list_t *ref_list, qdr_node_t *rnode) { + qdr_router_ref_t *ref = new_qdr_router_ref_t(); + DEQ_ITEM_INIT(ref); + ref->router = rnode; + rnode->ref_count++; + DEQ_INSERT_TAIL(*ref_list, ref); } void qdr_del_node_ref(qdr_router_ref_list_t *ref_list, qdr_node_t *rnode) { + qdr_router_ref_t *ref = DEQ_HEAD(*ref_list); + while (ref) { + if (ref->router == rnode) { + DEQ_REMOVE(*ref_list, ref); + free_qdr_router_ref_t(ref); + rnode->ref_count--; + break; + } + ref = DEQ_NEXT(ref); + } } From 98e9682db09c5c8d7443f07317204c17862c3f3c Mon Sep 17 00:00:00 2001 From: Ted Ross Date: Thu, 22 Oct 2015 15:28:53 -0400 Subject: [PATCH 07/22] DISPATCH-179 - Wired the new core handlers into pyrouter. Verified basic operation. --- include/qpid/dispatch.h | 1 + src/router_core/route_tables.c | 2 ++ src/router_core/router_core_private.h | 1 + src/router_core/router_core_thread.c | 4 +++- src/router_pynode.c | 12 ++++++++++++ 5 files changed, 19 insertions(+), 1 deletion(-) diff --git a/include/qpid/dispatch.h b/include/qpid/dispatch.h index 68f4dd5ae9..156f831824 100644 --- a/include/qpid/dispatch.h +++ b/include/qpid/dispatch.h @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include diff --git a/src/router_core/route_tables.c b/src/router_core/route_tables.c index e1095fb45b..5560dc1a3d 100644 --- a/src/router_core/route_tables.c +++ b/src/router_core/route_tables.c @@ -18,6 +18,7 @@ */ #include "router_core_private.h" +#include static qdr_action_t *qdr_action(qdr_action_handler_t action_handler); static void qdr_action_enqueue(qdr_core_t *core, qdr_action_t *action); @@ -150,6 +151,7 @@ static void qdr_action_enqueue(qdr_core_t *core, qdr_action_t *action) { sys_mutex_lock(core->lock); DEQ_INSERT_TAIL(core->action_list, action); + sys_cond_signal(core->cond); sys_mutex_unlock(core->lock); } diff --git a/src/router_core/router_core_private.h b/src/router_core/router_core_private.h index 0837f58d4e..e186092865 100644 --- a/src/router_core/router_core_private.h +++ b/src/router_core/router_core_private.h @@ -209,5 +209,6 @@ struct qdr_core_t { }; void *router_core_thread(void *arg); +void qdr_route_table_setup(qdr_core_t *core); #endif diff --git a/src/router_core/router_core_thread.c b/src/router_core/router_core_thread.c index 87f8c02b8e..07c7ab2666 100644 --- a/src/router_core/router_core_thread.c +++ b/src/router_core/router_core_thread.c @@ -32,10 +32,12 @@ ALLOC_DEFINE(qdr_action_t); void *router_core_thread(void *arg) { - qdr_core_t *core = (qdr_core_t*) arg; + qdr_core_t *core = (qdr_core_t*) arg; qdr_action_list_t action_list; qdr_action_t *action; + qdr_route_table_setup(core); + qd_log(core->log, QD_LOG_INFO, "Router Core thread running"); while (core->running) { // diff --git a/src/router_pynode.c b/src/router_pynode.c index 2003779fe7..361064a0c6 100644 --- a/src/router_pynode.c +++ b/src/router_pynode.c @@ -54,6 +54,8 @@ static PyObject *qd_add_router(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "si", &address, &router_maskbit)) return 0; + qdr_core_add_router(router->router_core, address, router_maskbit); + do { if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { error = "Router bit mask out of range"; @@ -140,6 +142,8 @@ static PyObject* qd_del_router(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "i", &router_maskbit)) return 0; + qdr_core_del_router(router->router_core, router_maskbit); + do { if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { error = "Router bit mask out of range"; @@ -212,6 +216,8 @@ static PyObject* qd_set_link(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "ii", &router_maskbit, &link_maskbit)) return 0; + qdr_core_set_link(router->router_core, router_maskbit, link_maskbit); + do { if (link_maskbit >= qd_bitmask_width() || link_maskbit < 0) { error = "Link bit mask out of range"; @@ -254,6 +260,8 @@ static PyObject* qd_remove_link(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "i", &router_maskbit)) return 0; + qdr_core_remove_link(router->router_core, router_maskbit); + do { sys_mutex_lock(router->lock); qd_router_node_t *rnode = router->routers_by_mask_bit[router_maskbit]; @@ -282,6 +290,8 @@ static PyObject* qd_set_next_hop(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "ii", &router_maskbit, &next_hop_maskbit)) return 0; + qdr_core_set_next_hop(router->router_core, router_maskbit, next_hop_maskbit); + do { if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { error = "Router bit mask out of range"; @@ -333,6 +343,8 @@ static PyObject* qd_remove_next_hop(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "i", &router_maskbit)) return 0; + qdr_core_remove_next_hop(router->router_core, router_maskbit); + do { if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { error = "Router bit mask out of range"; From 995e5ad4c288bcb4a6277927ead36caa3616a6f8 Mon Sep 17 00:00:00 2001 From: Ted Ross Date: Fri, 23 Oct 2015 12:11:10 -0400 Subject: [PATCH 08/22] DISPATCH-179 - Added discard argument to properly free action data during thread shutdown Hooked in set_valid_origins --- src/router_core/route_tables.c | 56 ++++++++++++++++++--------- src/router_core/router_core_private.h | 2 +- src/router_core/router_core_thread.c | 5 +-- src/router_pynode.c | 4 ++ 4 files changed, 44 insertions(+), 23 deletions(-) diff --git a/src/router_core/route_tables.c b/src/router_core/route_tables.c index 5560dc1a3d..2ea108bb62 100644 --- a/src/router_core/route_tables.c +++ b/src/router_core/route_tables.c @@ -23,15 +23,15 @@ static qdr_action_t *qdr_action(qdr_action_handler_t action_handler); static void qdr_action_enqueue(qdr_core_t *core, qdr_action_t *action); -static void qdrh_add_router(qdr_core_t *core, qdr_action_t *action); -static void qdrh_del_router(qdr_core_t *core, qdr_action_t *action); -static void qdrh_set_link(qdr_core_t *core, qdr_action_t *action); -static void qdrh_remove_link(qdr_core_t *core, qdr_action_t *action); -static void qdrh_set_next_hop(qdr_core_t *core, qdr_action_t *action); -static void qdrh_remove_next_hop(qdr_core_t *core, qdr_action_t *action); -static void qdrh_set_valid_origins(qdr_core_t *core, qdr_action_t *action); -static void qdrh_map_destination(qdr_core_t *core, qdr_action_t *action); -static void qdrh_unmap_destination(qdr_core_t *core, qdr_action_t *action); +static void qdrh_add_router (qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdrh_del_router (qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdrh_set_link (qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdrh_remove_link (qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdrh_set_next_hop (qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdrh_remove_next_hop (qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdrh_set_valid_origins(qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdrh_map_destination (qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdrh_unmap_destination(qdr_core_t *core, qdr_action_t *action, bool discard); static qd_address_semantics_t router_addr_semantics = QD_FANOUT_SINGLE | QD_BIAS_CLOSEST | QD_CONGESTION_DROP | QD_DROP_FOR_SLOW_CONSUMERS | QD_BYPASS_VALID_ORIGINS; @@ -238,11 +238,16 @@ static void qdr_check_addr(qdr_core_t *core, qdr_address_t *addr, bool was_local } -static void qdrh_add_router(qdr_core_t *core, qdr_action_t *action) +static void qdrh_add_router(qdr_core_t *core, qdr_action_t *action, bool discard) { int router_maskbit = action->args.route_table.router_maskbit; qdr_field_t *address = action->args.route_table.address; + if (discard) { + qdr_field_free(address); + return; + } + do { if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { qd_log(core->log, QD_LOG_CRITICAL, "add_router: Router maskbit out of range: %d", router_maskbit); @@ -313,7 +318,7 @@ static void qdrh_add_router(qdr_core_t *core, qdr_action_t *action) } -static void qdrh_del_router(qdr_core_t *core, qdr_action_t *action) +static void qdrh_del_router(qdr_core_t *core, qdr_action_t *action, bool discard) { int router_maskbit = action->args.route_table.router_maskbit; @@ -362,7 +367,7 @@ static void qdrh_del_router(qdr_core_t *core, qdr_action_t *action) } -static void qdrh_set_link(qdr_core_t *core, qdr_action_t *action) +static void qdrh_set_link(qdr_core_t *core, qdr_action_t *action, bool discard) { int router_maskbit = action->args.route_table.router_maskbit; int link_maskbit = action->args.route_table.link_maskbit; @@ -395,7 +400,7 @@ static void qdrh_set_link(qdr_core_t *core, qdr_action_t *action) } -static void qdrh_remove_link(qdr_core_t *core, qdr_action_t *action) +static void qdrh_remove_link(qdr_core_t *core, qdr_action_t *action, bool discard) { int router_maskbit = action->args.route_table.router_maskbit; @@ -414,7 +419,7 @@ static void qdrh_remove_link(qdr_core_t *core, qdr_action_t *action) } -static void qdrh_set_next_hop(qdr_core_t *core, qdr_action_t *action) +static void qdrh_set_next_hop(qdr_core_t *core, qdr_action_t *action, bool discard) { int router_maskbit = action->args.route_table.router_maskbit; int nh_router_maskbit = action->args.route_table.nh_router_maskbit; @@ -446,7 +451,7 @@ static void qdrh_set_next_hop(qdr_core_t *core, qdr_action_t *action) } -static void qdrh_remove_next_hop(qdr_core_t *core, qdr_action_t *action) +static void qdrh_remove_next_hop(qdr_core_t *core, qdr_action_t *action, bool discard) { int router_maskbit = action->args.route_table.router_maskbit; @@ -460,11 +465,16 @@ static void qdrh_remove_next_hop(qdr_core_t *core, qdr_action_t *action) } -static void qdrh_set_valid_origins(qdr_core_t *core, qdr_action_t *action) +static void qdrh_set_valid_origins(qdr_core_t *core, qdr_action_t *action, bool discard) { int router_maskbit = action->args.route_table.router_maskbit; qd_bitmask_t *valid_origins = action->args.route_table.router_set; + if (discard) { + qd_bitmask_free(valid_origins); + return; + } + do { if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { qd_log(core->log, QD_LOG_CRITICAL, "set_valid_origins: Router maskbit out of range: %d", router_maskbit); @@ -488,7 +498,7 @@ static void qdrh_set_valid_origins(qdr_core_t *core, qdr_action_t *action) } -static void qdrh_map_destination(qdr_core_t *core, qdr_action_t *action) +static void qdrh_map_destination(qdr_core_t *core, qdr_action_t *action, bool discard) { // // TODO - handle the class-prefix and phase explicitly @@ -497,6 +507,11 @@ static void qdrh_map_destination(qdr_core_t *core, qdr_action_t *action) int router_maskbit = action->args.route_table.router_maskbit; qdr_field_t *address = action->args.route_table.address; + if (discard) { + qdr_field_free(address); + return; + } + do { if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { qd_log(core->log, QD_LOG_CRITICAL, "map_destination: Router maskbit out of range: %d", router_maskbit); @@ -531,11 +546,16 @@ static void qdrh_map_destination(qdr_core_t *core, qdr_action_t *action) } -static void qdrh_unmap_destination(qdr_core_t *core, qdr_action_t *action) +static void qdrh_unmap_destination(qdr_core_t *core, qdr_action_t *action, bool discard) { int router_maskbit = action->args.route_table.router_maskbit; qdr_field_t *address = action->args.route_table.address; + if (discard) { + qdr_field_free(address); + return; + } + do { if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { qd_log(core->log, QD_LOG_CRITICAL, "unmap_destination: Router maskbit out of range: %d", router_maskbit); diff --git a/src/router_core/router_core_private.h b/src/router_core/router_core_private.h index e186092865..697d7c9ebb 100644 --- a/src/router_core/router_core_private.h +++ b/src/router_core/router_core_private.h @@ -42,7 +42,7 @@ void qdr_field_free(qdr_field_t *field); * qdr_action_t - This type represents one work item to be performed by the router-core thread. */ typedef struct qdr_action_t qdr_action_t; -typedef void (*qdr_action_handler_t) (qdr_core_t *core, qdr_action_t *action); +typedef void (*qdr_action_handler_t) (qdr_core_t *core, qdr_action_t *action, bool discard); struct qdr_action_t { DEQ_LINKS(qdr_action_t); diff --git a/src/router_core/router_core_thread.c b/src/router_core/router_core_thread.c index 07c7ab2666..093052c356 100644 --- a/src/router_core/router_core_thread.c +++ b/src/router_core/router_core_thread.c @@ -64,10 +64,7 @@ void *router_core_thread(void *arg) action = DEQ_HEAD(action_list); while (action) { DEQ_REMOVE_HEAD(action_list); - - if (core->running) - action->action_handler(core, action); - + action->action_handler(core, action, !core->running); free_qdr_action_t(action); action = DEQ_HEAD(action_list); } diff --git a/src/router_pynode.c b/src/router_pynode.c index 361064a0c6..77ac6017b3 100644 --- a/src/router_pynode.c +++ b/src/router_pynode.c @@ -406,6 +406,7 @@ static PyObject* qd_set_valid_origins(PyObject *self, PyObject *args) Py_ssize_t origin_count = PyList_Size(origin_list); qd_router_node_t *rnode = router->routers_by_mask_bit[router_maskbit]; + qd_bitmask_t *core_bitmask = qd_bitmask(0); int maskbit; for (idx = 0; idx < origin_count; idx++) { @@ -428,10 +429,13 @@ static PyObject* qd_set_valid_origins(PyObject *self, PyObject *args) for (idx = 0; idx < origin_count; idx++) { maskbit = PyInt_AS_LONG(PyList_GetItem(origin_list, idx)); qd_bitmask_set_bit(rnode->valid_origins, maskbit); + qd_bitmask_set_bit(core_bitmask, maskbit); } } sys_mutex_unlock(router->lock); + + qdr_core_set_valid_origins(router->router_core, router_maskbit, core_bitmask); } while (0); if (error) { From f733be6e9fed5ad793bf9e5162cf2632753b2470 Mon Sep 17 00:00:00 2001 From: Ted Ross Date: Fri, 23 Oct 2015 17:31:14 -0400 Subject: [PATCH 09/22] DISPATCH-179 - Added agent submodule in the router core to handle management requests. --- include/qpid/dispatch/router_core.h | 7 +- src/CMakeLists.txt | 1 + src/router_core/agent.c | 177 ++++++++++++++++++++++++++ src/router_core/route_tables.c | 24 ---- src/router_core/router_core.c | 41 ++++-- src/router_core/router_core_private.h | 39 +++++- src/router_core/router_core_thread.c | 7 +- src/router_node.c | 2 +- 8 files changed, 255 insertions(+), 43 deletions(-) create mode 100644 src/router_core/agent.c diff --git a/include/qpid/dispatch/router_core.h b/include/qpid/dispatch/router_core.h index 11f030f622..d50eb7c758 100644 --- a/include/qpid/dispatch/router_core.h +++ b/include/qpid/dispatch/router_core.h @@ -20,6 +20,7 @@ */ #include +#include #include // @@ -34,7 +35,7 @@ typedef struct qdr_delivery_t qdr_delivery_t; /** * Allocate and start an instance of the router core module. */ -qdr_core_t *qdr_core(void); +qdr_core_t *qdr_core(qd_dispatch_t *qd); /** * Stop and deallocate an instance of the router core. @@ -147,11 +148,11 @@ void qdr_manage_create(qdr_core_t *core, void *context, qd_router_entity_type_t void qdr_manage_delete(qdr_core_t *core, void *context, qd_router_entity_type_t type, qd_parsed_field_t *attributes); void qdr_manage_read(qdr_core_t *core, void *context, qd_router_entity_type_t type, qd_parsed_field_t *attributes); -qdr_query_t *qdr_manage_get_first(qdr_core_t *core, void *context, qd_router_entity_type_t type, int offset); +qdr_query_t *qdr_manage_get_first(qdr_core_t *core, void *context, qd_router_entity_type_t type, int offset, qd_composed_field_t *body); void qdr_manage_get_next(qdr_query_t *query); void qdr_query_cancel(qdr_query_t *query); -typedef void (*qdr_manage_response_t) (void *context, int status_code, qd_composed_field_t *body); +typedef void (*qdr_manage_response_t) (void *context, const qd_amqp_error_t *status, bool more); void qdr_manage_handler(qdr_core_t *core, qdr_manage_response_t response_handler); #endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a9136b193b..eee2b10e28 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -65,6 +65,7 @@ set(qpid_dispatch_SOURCES python_embedded.c router_agent.c router_config.c + router_core/agent.c router_core/router_core.c router_core/router_core_thread.c router_core/route_tables.c diff --git a/src/router_core/agent.c b/src/router_core/agent.c new file mode 100644 index 0000000000..2787ae5570 --- /dev/null +++ b/src/router_core/agent.c @@ -0,0 +1,177 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include "router_core_private.h" +#include + +static void qdrh_manage_get_first(qdr_core_t *core, qdr_action_t *action, bool discard); + +//================================================================================== +// Interface Functions +//================================================================================== + +void qdr_manage_create(qdr_core_t *core, void *context, qd_router_entity_type_t type, qd_parsed_field_t *attributes) +{ +} + + +void qdr_manage_delete(qdr_core_t *core, void *context, qd_router_entity_type_t type, qd_parsed_field_t *attributes) +{ +} + + +void qdr_manage_read(qdr_core_t *core, void *context, qd_router_entity_type_t type, qd_parsed_field_t *attributes) +{ +} + + +qdr_query_t *qdr_manage_get_first(qdr_core_t *core, void *context, qd_router_entity_type_t type, + int offset, qd_composed_field_t *body) +{ + qdr_action_t *action = qdr_action(qdrh_manage_get_first); + qdr_query_t *query = new_qdr_query_t(); + + query->entity_type = type; + query->context = context; + query->body = body; + query->next_key = 0; + query->more = false; + query->status = 0; + + action->args.agent.query = query; + action->args.agent.offset = offset; + + qdr_action_enqueue(core, action); + + return query; +} + + +void qdr_manage_get_next(qdr_query_t *query) +{ +} + + +void qdr_query_cancel(qdr_query_t *query) +{ +} + + +void qdr_manage_handler(qdr_core_t *core, qdr_manage_response_t response_handler) +{ + core->agent_response_handler = response_handler; +} + + +//================================================================================== +// Internal Functions +//================================================================================== + +static void qdr_agent_response_handler(void *context) +{ + qdr_core_t *core = (qdr_core_t*) context; + qdr_query_t *query; + bool done = false; + + while (!done) { + sys_mutex_lock(core->query_lock); + query = DEQ_HEAD(core->outgoing_query_list); + if (query) + DEQ_REMOVE_HEAD(core->outgoing_query_list); + done = DEQ_SIZE(core->outgoing_query_list) == 0; + sys_mutex_unlock(core->query_lock); + + if (query) { + core->agent_response_handler(query->context, query->status, query->more); + if (!query->more) { + if (query->next_key) + qdr_field_free(query->next_key); + free_qdr_query_t(query); + } + } + } +} + + +static void qdr_agent_enqueue_response(qdr_core_t *core, qdr_query_t *query) +{ + sys_mutex_lock(core->query_lock); + DEQ_INSERT_TAIL(core->outgoing_query_list, query); + bool notify = DEQ_SIZE(core->outgoing_query_list) == 1; + sys_mutex_unlock(core->query_lock); + + if (notify) + qd_timer_schedule(core->agent_timer, 0); +} + + +static void qdr_manage_get_first_address(qdr_core_t *core, qdr_query_t *query, int offset) +{ + if (offset >= DEQ_SIZE(core->addrs)) { + query->more = false; + query->status = &QD_AMQP_OK; + qdr_agent_enqueue_response(core, query); + return; + } +} + + +//================================================================================== +// In-Thread Functions +//================================================================================== + +void qdr_agent_setup(qdr_core_t *core) +{ + DEQ_INIT(core->outgoing_query_list); + core->query_lock = sys_mutex(); + core->agent_timer = qd_timer(core->qd, qdr_agent_response_handler, core); +} + + +static void qdrh_manage_get_first(qdr_core_t *core, qdr_action_t *action, bool discard) +{ + qdr_query_t *query = action->args.agent.query; + int offset = action->args.agent.offset; + + if (!discard) + switch (query->entity_type) { + case QD_ROUTER_CONNECTION : + break; + + case QD_ROUTER_LINK : + break; + + case QD_ROUTER_ADDRESS : + qdr_manage_get_first_address(core, query, offset); + break; + + case QD_ROUTER_WAYPOINT : + break; + + case QD_ROUTER_EXCHANGE : + break; + + case QD_ROUTER_BINDING : + break; + } +} + + + diff --git a/src/router_core/route_tables.c b/src/router_core/route_tables.c index 2ea108bb62..c4deb7f985 100644 --- a/src/router_core/route_tables.c +++ b/src/router_core/route_tables.c @@ -20,9 +20,6 @@ #include "router_core_private.h" #include -static qdr_action_t *qdr_action(qdr_action_handler_t action_handler); -static void qdr_action_enqueue(qdr_core_t *core, qdr_action_t *action); - static void qdrh_add_router (qdr_core_t *core, qdr_action_t *action, bool discard); static void qdrh_del_router (qdr_core_t *core, qdr_action_t *action, bool discard); static void qdrh_set_link (qdr_core_t *core, qdr_action_t *action, bool discard); @@ -135,27 +132,6 @@ void qdr_core_route_table_handlers(qdr_core_t *core, } -//================================================================================== -// Internal Functions -//================================================================================== - -static qdr_action_t *qdr_action(qdr_action_handler_t action_handler) -{ - qdr_action_t *action = new_qdr_action_t(); - ZERO(action); - action->action_handler = action_handler; - return action; -} - -static void qdr_action_enqueue(qdr_core_t *core, qdr_action_t *action) -{ - sys_mutex_lock(core->lock); - DEQ_INSERT_TAIL(core->action_list, action); - sys_cond_signal(core->cond); - sys_mutex_unlock(core->lock); -} - - //================================================================================== // In-Thread Functions //================================================================================== diff --git a/src/router_core/router_core.c b/src/router_core/router_core.c index 8f31b7a8e2..99edccc9ef 100644 --- a/src/router_core/router_core.c +++ b/src/router_core/router_core.c @@ -20,7 +20,7 @@ #include "router_core_private.h" #include - +ALLOC_DEFINE(qdr_query_t); ALLOC_DEFINE(qdr_address_t); ALLOC_DEFINE(qdr_node_t); ALLOC_DEFINE(qdr_link_t); @@ -28,11 +28,13 @@ ALLOC_DEFINE(qdr_router_ref_t); ALLOC_DEFINE(qdr_link_ref_t); -qdr_core_t *qdr_core(void) +qdr_core_t *qdr_core(qd_dispatch_t *qd) { qdr_core_t *core = NEW(qdr_core_t); ZERO(core); + core->qd = qd; + // // Set up the logging source for the router core // @@ -41,11 +43,15 @@ qdr_core_t *qdr_core(void) // // Set up the threading support // - core->cond = sys_cond(); - core->lock = sys_mutex(); - core->running = true; + core->action_cond = sys_cond(); + core->action_lock = sys_mutex(); + core->running = true; DEQ_INIT(core->action_list); - core->thread = sys_thread(router_core_thread, core); + + // + // Launch the core thread + // + core->thread = sys_thread(router_core_thread, core); return core; } @@ -57,15 +63,15 @@ void qdr_core_free(qdr_core_t *core) // Stop and join the thread // core->running = false; - sys_cond_signal(core->cond); + sys_cond_signal(core->action_cond); sys_thread_join(core->thread); // // Free the core resources // sys_thread_free(core->thread); - sys_cond_free(core->cond); - sys_mutex_free(core->lock); + sys_cond_free(core->action_cond); + sys_mutex_free(core->action_lock); free(core); } @@ -112,6 +118,23 @@ void qdr_field_free(qdr_field_t *field) } +qdr_action_t *qdr_action(qdr_action_handler_t action_handler) +{ + qdr_action_t *action = new_qdr_action_t(); + ZERO(action); + action->action_handler = action_handler; + return action; +} + +void qdr_action_enqueue(qdr_core_t *core, qdr_action_t *action) +{ + sys_mutex_lock(core->action_lock); + DEQ_INSERT_TAIL(core->action_list, action); + sys_cond_signal(core->action_cond); + sys_mutex_unlock(core->action_lock); +} + + qdr_address_t *qdr_address(qd_address_semantics_t semantics) { qdr_address_t *addr = new_qdr_address_t(); diff --git a/src/router_core/router_core_private.h b/src/router_core/router_core_private.h index 697d7c9ebb..de5566bb30 100644 --- a/src/router_core/router_core_private.h +++ b/src/router_core/router_core_private.h @@ -58,12 +58,30 @@ struct qdr_action_t { char address_phase; qd_address_semantics_t semantics; } route_table; + struct { + qdr_query_t *query; + int offset; + } agent; } args; }; ALLOC_DECLARE(qdr_action_t); DEQ_DECLARE(qdr_action_t, qdr_action_list_t); +struct qdr_query_t { + DEQ_LINKS(qdr_query_t); + qd_router_entity_type_t entity_type; + void *context; + qd_composed_field_t *body; + qdr_field_t *next_key; + bool more; + const qd_amqp_error_t *status; +}; + +ALLOC_DECLARE(qdr_query_t); +DEQ_DECLARE(qdr_query_t, qdr_query_list_t); + + typedef struct qdr_address_t qdr_address_t; typedef struct qdr_node_t qdr_node_t; typedef struct qdr_router_ref_t qdr_router_ref_t; @@ -181,13 +199,25 @@ void qdr_del_node_ref(qdr_router_ref_list_t *ref_list, qdr_node_t *rnode); struct qdr_core_t { + qd_dispatch_t *qd; qd_log_source_t *log; - sys_cond_t *cond; - sys_mutex_t *lock; sys_thread_t *thread; bool running; qdr_action_list_t action_list; - + sys_cond_t *action_cond; + sys_mutex_t *action_lock; + + // + // Agent section + // + qdr_query_list_t outgoing_query_list; + sys_mutex_t *query_lock; + qd_timer_t *agent_timer; + qdr_manage_response_t agent_response_handler; + + // + // Route table section + // void *rt_context; qdr_mobile_added_t rt_mobile_added; qdr_mobile_removed_t rt_mobile_removed; @@ -210,5 +240,8 @@ struct qdr_core_t { void *router_core_thread(void *arg); void qdr_route_table_setup(qdr_core_t *core); +void qdr_agent_setup(qdr_core_t *core); +qdr_action_t *qdr_action(qdr_action_handler_t action_handler); +void qdr_action_enqueue(qdr_core_t *core, qdr_action_t *action); #endif diff --git a/src/router_core/router_core_thread.c b/src/router_core/router_core_thread.c index 093052c356..7ef11bad25 100644 --- a/src/router_core/router_core_thread.c +++ b/src/router_core/router_core_thread.c @@ -37,26 +37,27 @@ void *router_core_thread(void *arg) qdr_action_t *action; qdr_route_table_setup(core); + qdr_agent_setup(core); qd_log(core->log, QD_LOG_INFO, "Router Core thread running"); while (core->running) { // // Use the lock only to protect the condition variable and the action list // - sys_mutex_lock(core->lock); + sys_mutex_lock(core->action_lock); // // Block on the condition variable when there is no action to do // while (core->running && DEQ_IS_EMPTY(core->action_list)) - sys_cond_wait(core->cond, core->lock); + sys_cond_wait(core->action_cond, core->action_lock); // // Move the entire action list to a private list so we can process it without // holding the lock // DEQ_MOVE(core->action_list, action_list); - sys_mutex_unlock(core->lock); + sys_mutex_unlock(core->action_lock); // // Process and free all of the action items in the list diff --git a/src/router_node.c b/src/router_node.c index c2eb6d99cd..a45e9bbbb5 100644 --- a/src/router_node.c +++ b/src/router_node.c @@ -1869,7 +1869,7 @@ qd_router_t *qd_router(qd_dispatch_t *qd, qd_router_mode_t mode, const char *are void qd_router_setup_late(qd_dispatch_t *qd) { qd_router_python_setup(qd->router); - qd->router->router_core = qdr_core(); + qd->router->router_core = qdr_core(qd); qd_timer_schedule(qd->router->timer, 1000); } From 61be97fdf7c776e5b9ceefc4f3cae94dc9a12333 Mon Sep 17 00:00:00 2001 From: Ted Ross Date: Wed, 28 Oct 2015 13:28:46 -0400 Subject: [PATCH 10/22] DISPATCH-179 - Added agent support for the address table. Adopted a function-name suffix of _CT for core-thread functions. --- include/qpid/dispatch/router_core.h | 9 +- python/qpid_dispatch/management/qdrouter.json | 3 +- src/CMakeLists.txt | 1 + src/router_core/agent.c | 159 +++++------ src/router_core/agent_address.c | 258 ++++++++++++++++++ src/router_core/agent_address.h | 28 ++ src/router_core/route_tables.c | 66 ++--- src/router_core/router_core.c | 2 +- src/router_core/router_core_private.h | 14 +- src/router_core/router_core_thread.c | 4 +- 10 files changed, 424 insertions(+), 120 deletions(-) create mode 100644 src/router_core/agent_address.c create mode 100644 src/router_core/agent_address.h diff --git a/include/qpid/dispatch/router_core.h b/include/qpid/dispatch/router_core.h index d50eb7c758..2e11139608 100644 --- a/include/qpid/dispatch/router_core.h +++ b/include/qpid/dispatch/router_core.h @@ -22,6 +22,8 @@ #include #include #include +#include +#include // // All callbacks in this module shall be invoked on a connection thread from the server thread pool. @@ -148,9 +150,10 @@ void qdr_manage_create(qdr_core_t *core, void *context, qd_router_entity_type_t void qdr_manage_delete(qdr_core_t *core, void *context, qd_router_entity_type_t type, qd_parsed_field_t *attributes); void qdr_manage_read(qdr_core_t *core, void *context, qd_router_entity_type_t type, qd_parsed_field_t *attributes); -qdr_query_t *qdr_manage_get_first(qdr_core_t *core, void *context, qd_router_entity_type_t type, int offset, qd_composed_field_t *body); -void qdr_manage_get_next(qdr_query_t *query); -void qdr_query_cancel(qdr_query_t *query); +qdr_query_t *qdr_manage_get_first(qdr_core_t *core, void *context, qd_router_entity_type_t type, int offset, + qd_parsed_field_t *attribute_names, qd_composed_field_t *body); +void qdr_manage_get_next(qdr_core_t *core, qdr_query_t *query); +void qdr_query_cancel(qdr_core_t *core, qdr_query_t *query); typedef void (*qdr_manage_response_t) (void *context, const qd_amqp_error_t *status, bool more); void qdr_manage_handler(qdr_core_t *core, qdr_manage_response_t response_handler); diff --git a/python/qpid_dispatch/management/qdrouter.json b/python/qpid_dispatch/management/qdrouter.json index e447f19801..00e247f51d 100644 --- a/python/qpid_dispatch/management/qdrouter.json +++ b/python/qpid_dispatch/management/qdrouter.json @@ -857,7 +857,8 @@ "key": { "description": "Internal unique (to this router) key to identify the address", "type": "string" - } + }, + "hostRouters": {"type": "list", "description": "List of remote routers on which there is a destination for this address."} } }, diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eee2b10e28..42c9fc9ba4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -66,6 +66,7 @@ set(qpid_dispatch_SOURCES router_agent.c router_config.c router_core/agent.c + router_core/agent_address.c router_core/router_core.c router_core/router_core_thread.c router_core/route_tables.c diff --git a/src/router_core/agent.c b/src/router_core/agent.c index 2787ae5570..a42232b983 100644 --- a/src/router_core/agent.c +++ b/src/router_core/agent.c @@ -18,10 +18,53 @@ */ #include -#include "router_core_private.h" +#include "agent_address.h" #include -static void qdrh_manage_get_first(qdr_core_t *core, qdr_action_t *action, bool discard); +//================================================================================== +// Internal Functions +//================================================================================== + +static void qdr_agent_response_handler(void *context) +{ + qdr_core_t *core = (qdr_core_t*) context; + qdr_query_t *query; + bool done = false; + + while (!done) { + sys_mutex_lock(core->query_lock); + query = DEQ_HEAD(core->outgoing_query_list); + if (query) + DEQ_REMOVE_HEAD(core->outgoing_query_list); + done = DEQ_SIZE(core->outgoing_query_list) == 0; + sys_mutex_unlock(core->query_lock); + + if (query) { + core->agent_response_handler(query->context, query->status, query->more); + if (!query->more) { + if (query->next_key) + qdr_field_free(query->next_key); + free_qdr_query_t(query); + } + } + } +} + + +void qdr_agent_enqueue_response_CT(qdr_core_t *core, qdr_query_t *query) +{ + sys_mutex_lock(core->query_lock); + DEQ_INSERT_TAIL(core->outgoing_query_list, query); + bool notify = DEQ_SIZE(core->outgoing_query_list) == 1; + sys_mutex_unlock(core->query_lock); + + if (notify) + qd_timer_schedule(core->agent_timer, 0); +} + +static void qdrh_manage_get_first_CT(qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdrh_manage_get_next_CT(qdr_core_t *core, qdr_action_t *action, bool discard); + //================================================================================== // Interface Functions @@ -43,18 +86,28 @@ void qdr_manage_read(qdr_core_t *core, void *context, qd_router_entity_type_t ty qdr_query_t *qdr_manage_get_first(qdr_core_t *core, void *context, qd_router_entity_type_t type, - int offset, qd_composed_field_t *body) + int offset, qd_parsed_field_t *attribute_names, qd_composed_field_t *body) { - qdr_action_t *action = qdr_action(qdrh_manage_get_first); + qdr_action_t *action = qdr_action(qdrh_manage_get_first_CT); qdr_query_t *query = new_qdr_query_t(); query->entity_type = type; query->context = context; query->body = body; query->next_key = 0; + query->next_offset = 0; query->more = false; query->status = 0; + switch (query->entity_type) { + case QD_ROUTER_CONNECTION: break; + case QD_ROUTER_LINK: break; + case QD_ROUTER_ADDRESS: qdra_address_set_columns(query, attribute_names); + case QD_ROUTER_WAYPOINT: break; + case QD_ROUTER_EXCHANGE: break; + case QD_ROUTER_BINDING: break; + } + action->args.agent.query = query; action->args.agent.offset = offset; @@ -64,12 +117,15 @@ qdr_query_t *qdr_manage_get_first(qdr_core_t *core, void *context, qd_router_ent } -void qdr_manage_get_next(qdr_query_t *query) +void qdr_manage_get_next(qdr_core_t *core, qdr_query_t *query) { + qdr_action_t *action = qdr_action(qdrh_manage_get_next_CT); + action->args.agent.query = query; + qdr_action_enqueue(core, action); } -void qdr_query_cancel(qdr_query_t *query) +void qdr_query_cancel(qdr_core_t *core, qdr_query_t *query) { } @@ -80,64 +136,11 @@ void qdr_manage_handler(qdr_core_t *core, qdr_manage_response_t response_handler } -//================================================================================== -// Internal Functions -//================================================================================== - -static void qdr_agent_response_handler(void *context) -{ - qdr_core_t *core = (qdr_core_t*) context; - qdr_query_t *query; - bool done = false; - - while (!done) { - sys_mutex_lock(core->query_lock); - query = DEQ_HEAD(core->outgoing_query_list); - if (query) - DEQ_REMOVE_HEAD(core->outgoing_query_list); - done = DEQ_SIZE(core->outgoing_query_list) == 0; - sys_mutex_unlock(core->query_lock); - - if (query) { - core->agent_response_handler(query->context, query->status, query->more); - if (!query->more) { - if (query->next_key) - qdr_field_free(query->next_key); - free_qdr_query_t(query); - } - } - } -} - - -static void qdr_agent_enqueue_response(qdr_core_t *core, qdr_query_t *query) -{ - sys_mutex_lock(core->query_lock); - DEQ_INSERT_TAIL(core->outgoing_query_list, query); - bool notify = DEQ_SIZE(core->outgoing_query_list) == 1; - sys_mutex_unlock(core->query_lock); - - if (notify) - qd_timer_schedule(core->agent_timer, 0); -} - - -static void qdr_manage_get_first_address(qdr_core_t *core, qdr_query_t *query, int offset) -{ - if (offset >= DEQ_SIZE(core->addrs)) { - query->more = false; - query->status = &QD_AMQP_OK; - qdr_agent_enqueue_response(core, query); - return; - } -} - - //================================================================================== // In-Thread Functions //================================================================================== -void qdr_agent_setup(qdr_core_t *core) +void qdr_agent_setup_CT(qdr_core_t *core) { DEQ_INIT(core->outgoing_query_list); core->query_lock = sys_mutex(); @@ -145,31 +148,35 @@ void qdr_agent_setup(qdr_core_t *core) } -static void qdrh_manage_get_first(qdr_core_t *core, qdr_action_t *action, bool discard) +static void qdrh_manage_get_first_CT(qdr_core_t *core, qdr_action_t *action, bool discard) { qdr_query_t *query = action->args.agent.query; int offset = action->args.agent.offset; if (!discard) switch (query->entity_type) { - case QD_ROUTER_CONNECTION : - break; - - case QD_ROUTER_LINK : - break; - - case QD_ROUTER_ADDRESS : - qdr_manage_get_first_address(core, query, offset); - break; + case QD_ROUTER_CONNECTION: break; + case QD_ROUTER_LINK: break; + case QD_ROUTER_ADDRESS: qdra_address_get_first_CT(core, query, offset); break; + case QD_ROUTER_WAYPOINT: break; + case QD_ROUTER_EXCHANGE: break; + case QD_ROUTER_BINDING: break; + } +} - case QD_ROUTER_WAYPOINT : - break; - case QD_ROUTER_EXCHANGE : - break; +static void qdrh_manage_get_next_CT(qdr_core_t *core, qdr_action_t *action, bool discard) +{ + qdr_query_t *query = action->args.agent.query; - case QD_ROUTER_BINDING : - break; + if (!discard) + switch (query->entity_type) { + case QD_ROUTER_CONNECTION: break; + case QD_ROUTER_LINK: break; + case QD_ROUTER_ADDRESS: qdra_address_get_next_CT(core, query); break; + case QD_ROUTER_WAYPOINT: break; + case QD_ROUTER_EXCHANGE: break; + case QD_ROUTER_BINDING: break; } } diff --git a/src/router_core/agent_address.c b/src/router_core/agent_address.c new file mode 100644 index 0000000000..5ede5d1113 --- /dev/null +++ b/src/router_core/agent_address.c @@ -0,0 +1,258 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "agent_address.h" + +static const char *qdr_address_columns[] = + {"name", + "identity", + "type", + "key", + "inProcess", + "subscriberCount", + "remoteCount", + "hostRouters", + "deliveriesIngress", + "deliveriesEgress", + "deliveriesTransit", + "deliveriesToContainer", + "deliveriesFromContainer", + 0}; + +#define QDR_ADDRESS_NAME 0 +#define QDR_ADDRESS_IDENTITY 1 +#define QDR_ADDRESS_TYPE 2 +#define QDR_ADDRESS_KEY 3 +#define QDR_ADDRESS_IN_PROCESS 4 +#define QDR_ADDRESS_SUBSCRIBER_COUNT 5 +#define QDR_ADDRESS_REMOTE_COUNT 6 +#define QDR_ADDRESS_HOST_ROUTERS 7 +#define QDR_ADDRESS_DELIVERIES_INGRESS 8 +#define QDR_ADDRESS_DELIVERIES_EGRESS 9 +#define QDR_ADDRESS_DELIVERIES_TRANSIT 10 +#define QDR_ADDRESS_DELIVERIES_TO_CONTAINER 11 +#define QDR_ADDRESS_DELIVERIES_FROM_CONTAINER 12 +#define QDR_ADDRESS_COLUMN_COUNT 13 + +static void qdr_manage_write_address_CT(qdr_query_t *query, qdr_address_t *addr) +{ + qd_composed_field_t *body = query->body; + + qd_compose_start_list(body); + int i = 0; + while (query->columns[i] >= 0) { + switch(query->columns[i]) { + case QDR_ADDRESS_NAME: + case QDR_ADDRESS_IDENTITY: + break; + + case QDR_ADDRESS_TYPE: + qd_compose_insert_string(body, "org.apache.qpid.dispatch.router.address"); + break; + + case QDR_ADDRESS_KEY: + if (addr->hash_handle) + qd_compose_insert_string(body, (const char*) qd_hash_key_by_handle(addr->hash_handle)); + else + qd_compose_insert_null(body); + break; + + case QDR_ADDRESS_IN_PROCESS: + qd_compose_insert_bool(body, addr->on_message != 0); + break; + + case QDR_ADDRESS_SUBSCRIBER_COUNT: + qd_compose_insert_uint(body, DEQ_SIZE(addr->rlinks)); + break; + + case QDR_ADDRESS_REMOTE_COUNT: + qd_compose_insert_uint(body, DEQ_SIZE(addr->rnodes)); + break; + + case QDR_ADDRESS_HOST_ROUTERS: + qd_compose_insert_null(body); // TEMP + break; + + case QDR_ADDRESS_DELIVERIES_INGRESS: + qd_compose_insert_ulong(body, addr->deliveries_ingress); + break; + + case QDR_ADDRESS_DELIVERIES_EGRESS: + qd_compose_insert_ulong(body, addr->deliveries_egress); + break; + + case QDR_ADDRESS_DELIVERIES_TRANSIT: + qd_compose_insert_ulong(body, addr->deliveries_transit); + break; + + case QDR_ADDRESS_DELIVERIES_TO_CONTAINER: + qd_compose_insert_ulong(body, addr->deliveries_to_container); + break; + + case QDR_ADDRESS_DELIVERIES_FROM_CONTAINER: + qd_compose_insert_ulong(body, addr->deliveries_from_container); + break; + + default: + qd_compose_insert_null(body); + break; + } + } + qd_compose_end_list(body); +} + + +static void qdr_manage_advance_address_CT(qdr_query_t *query, qdr_address_t *addr) +{ + query->next_offset++; + addr = DEQ_NEXT(addr); + if (addr) { + query->more = true; + query->next_key = qdr_field((const char*) qd_hash_key_by_handle(addr->hash_handle)); + } else + query->more = false; +} + + +void qdra_address_set_columns(qdr_query_t *query, qd_parsed_field_t *attribute_names) +{ + if (!attribute_names || + (qd_parse_tag(attribute_names) != QD_AMQP_LIST8 && + qd_parse_tag(attribute_names) != QD_AMQP_LIST32) || + qd_parse_sub_count(attribute_names) == 0) { + // + // Either the attribute_names field is absent, it's not a list, or it's an empty list. + // In this case, we will include all available attributes. + // + int i; + for (i = 0; i < QDR_ADDRESS_COLUMN_COUNT; i++) + query->columns[i] = i; + query->columns[i] = -1; + return; + } + + // + // We have a valid, non-empty attribute list. Set the columns appropriately. + // + uint32_t count = qd_parse_sub_count(attribute_names); + uint32_t idx; + + for (idx = 0; idx < count; idx++) { + qd_parsed_field_t *name = qd_parse_sub_value(attribute_names, idx); + if (!name || (qd_parse_tag(name) != QD_AMQP_STR8_UTF8 && qd_parse_tag(name) != QD_AMQP_STR32_UTF8)) + query->columns[idx] = QDR_AGENT_COLUMN_NULL; + else { + int j = 0; + while (qdr_address_columns[j]) { + qd_field_iterator_t *iter = qd_parse_raw(name); + if (qd_field_iterator_equal(iter, (const unsigned char*) qdr_address_columns[j])) { + query->columns[idx] = j; + break; + } + } + } + } +} + + +void qdra_address_get_first_CT(qdr_core_t *core, qdr_query_t *query, int offset) +{ + // + // Queries that get this far will always succeed. + // + query->status = &QD_AMQP_OK; + + // + // If the offset goes beyond the set of addresses, end the query now. + // + if (offset >= DEQ_SIZE(core->addrs)) { + query->more = false; + qdr_agent_enqueue_response_CT(core, query); + return; + } + + // + // Run to the address at the offset. + // + qdr_address_t *addr = DEQ_HEAD(core->addrs); + for (int i = 0; i < offset && addr; i++) + addr = DEQ_NEXT(addr); + assert(addr != 0); + + // + // Write the columns of the address entity into the response body. + // + qdr_manage_write_address_CT(query, addr); + + // + // Advance to the next address + // + query->next_offset = offset; + qdr_manage_advance_address_CT(query, addr); + + // + // Enqueue the response. + // + qdr_agent_enqueue_response_CT(core, query); +} + + +void qdra_address_get_next_CT(qdr_core_t *core, qdr_query_t *query) +{ + qdr_address_t *addr = 0; + + // + // Use the stored key to try to find the next entry in the table. + // + if (query->next_key) { + qd_hash_retrieve(core->addr_hash, query->next_key->iterator, (void**) &addr); + qdr_field_free(query->next_key); + query->next_key = 0; + } + if (!addr) { + // + // If the address was removed in the time between this get and the previous one, + // we need to use the saved offset, which is less efficient. + // + if (query->next_offset < DEQ_SIZE(core->addrs)) { + addr = DEQ_HEAD(core->addrs); + for (int i = 0; i < query->next_offset && addr; i++) + addr = DEQ_NEXT(addr); + } + } + + if (addr) { + // + // Write the columns of the address entity into the response body. + // + qdr_manage_write_address_CT(query, addr); + + // + // Advance to the next address + // + qdr_manage_advance_address_CT(query, addr); + } else + query->more = false; + + // + // Enqueue the response. + // + qdr_agent_enqueue_response_CT(core, query); +} + diff --git a/src/router_core/agent_address.h b/src/router_core/agent_address.h new file mode 100644 index 0000000000..9d6c078e73 --- /dev/null +++ b/src/router_core/agent_address.h @@ -0,0 +1,28 @@ +#ifndef qdr_agent_address +#define qdr_agent_address 1 +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "router_core_private.h" + +void qdra_address_set_columns(qdr_query_t *query, qd_parsed_field_t *attribute_names); +void qdra_address_get_first_CT(qdr_core_t *core, qdr_query_t *query, int offset); +void qdra_address_get_next_CT(qdr_core_t *core, qdr_query_t *query); + +#endif diff --git a/src/router_core/route_tables.c b/src/router_core/route_tables.c index c4deb7f985..b71564ecce 100644 --- a/src/router_core/route_tables.c +++ b/src/router_core/route_tables.c @@ -20,15 +20,15 @@ #include "router_core_private.h" #include -static void qdrh_add_router (qdr_core_t *core, qdr_action_t *action, bool discard); -static void qdrh_del_router (qdr_core_t *core, qdr_action_t *action, bool discard); -static void qdrh_set_link (qdr_core_t *core, qdr_action_t *action, bool discard); -static void qdrh_remove_link (qdr_core_t *core, qdr_action_t *action, bool discard); -static void qdrh_set_next_hop (qdr_core_t *core, qdr_action_t *action, bool discard); -static void qdrh_remove_next_hop (qdr_core_t *core, qdr_action_t *action, bool discard); -static void qdrh_set_valid_origins(qdr_core_t *core, qdr_action_t *action, bool discard); -static void qdrh_map_destination (qdr_core_t *core, qdr_action_t *action, bool discard); -static void qdrh_unmap_destination(qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdrh_add_router_CT (qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdrh_del_router_CT (qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdrh_set_link_CT (qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdrh_remove_link_CT (qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdrh_set_next_hop_CT (qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdrh_remove_next_hop_CT (qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdrh_set_valid_origins_CT (qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdrh_map_destination_CT (qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdrh_unmap_destination_CT (qdr_core_t *core, qdr_action_t *action, bool discard); static qd_address_semantics_t router_addr_semantics = QD_FANOUT_SINGLE | QD_BIAS_CLOSEST | QD_CONGESTION_DROP | QD_DROP_FOR_SLOW_CONSUMERS | QD_BYPASS_VALID_ORIGINS; @@ -39,7 +39,7 @@ static qd_address_semantics_t router_addr_semantics = QD_FANOUT_SINGLE | QD_BIAS void qdr_core_add_router(qdr_core_t *core, const char *address, int router_maskbit) { - qdr_action_t *action = qdr_action(qdrh_add_router); + qdr_action_t *action = qdr_action(qdrh_add_router_CT); action->args.route_table.router_maskbit = router_maskbit; action->args.route_table.address = qdr_field(address); qdr_action_enqueue(core, action); @@ -48,7 +48,7 @@ void qdr_core_add_router(qdr_core_t *core, const char *address, int router_maskb void qdr_core_del_router(qdr_core_t *core, int router_maskbit) { - qdr_action_t *action = qdr_action(qdrh_del_router); + qdr_action_t *action = qdr_action(qdrh_del_router_CT); action->args.route_table.router_maskbit = router_maskbit; qdr_action_enqueue(core, action); } @@ -56,7 +56,7 @@ void qdr_core_del_router(qdr_core_t *core, int router_maskbit) void qdr_core_set_link(qdr_core_t *core, int router_maskbit, int link_maskbit) { - qdr_action_t *action = qdr_action(qdrh_set_link); + qdr_action_t *action = qdr_action(qdrh_set_link_CT); action->args.route_table.router_maskbit = router_maskbit; action->args.route_table.link_maskbit = link_maskbit; qdr_action_enqueue(core, action); @@ -65,7 +65,7 @@ void qdr_core_set_link(qdr_core_t *core, int router_maskbit, int link_maskbit) void qdr_core_remove_link(qdr_core_t *core, int router_maskbit) { - qdr_action_t *action = qdr_action(qdrh_remove_link); + qdr_action_t *action = qdr_action(qdrh_remove_link_CT); action->args.route_table.router_maskbit = router_maskbit; qdr_action_enqueue(core, action); } @@ -73,7 +73,7 @@ void qdr_core_remove_link(qdr_core_t *core, int router_maskbit) void qdr_core_set_next_hop(qdr_core_t *core, int router_maskbit, int nh_router_maskbit) { - qdr_action_t *action = qdr_action(qdrh_set_next_hop); + qdr_action_t *action = qdr_action(qdrh_set_next_hop_CT); action->args.route_table.router_maskbit = router_maskbit; action->args.route_table.nh_router_maskbit = nh_router_maskbit; qdr_action_enqueue(core, action); @@ -82,7 +82,7 @@ void qdr_core_set_next_hop(qdr_core_t *core, int router_maskbit, int nh_router_m void qdr_core_remove_next_hop(qdr_core_t *core, int router_maskbit) { - qdr_action_t *action = qdr_action(qdrh_remove_next_hop); + qdr_action_t *action = qdr_action(qdrh_remove_next_hop_CT); action->args.route_table.router_maskbit = router_maskbit; qdr_action_enqueue(core, action); } @@ -90,7 +90,7 @@ void qdr_core_remove_next_hop(qdr_core_t *core, int router_maskbit) void qdr_core_set_valid_origins(qdr_core_t *core, int router_maskbit, qd_bitmask_t *routers) { - qdr_action_t *action = qdr_action(qdrh_set_valid_origins); + qdr_action_t *action = qdr_action(qdrh_set_valid_origins_CT); action->args.route_table.router_maskbit = router_maskbit; action->args.route_table.router_set = routers; qdr_action_enqueue(core, action); @@ -99,7 +99,7 @@ void qdr_core_set_valid_origins(qdr_core_t *core, int router_maskbit, qd_bitmask void qdr_core_map_destination(qdr_core_t *core, int router_maskbit, const char *address, char aclass, char phase, qd_address_semantics_t sem) { - qdr_action_t *action = qdr_action(qdrh_map_destination); + qdr_action_t *action = qdr_action(qdrh_map_destination_CT); action->args.route_table.router_maskbit = router_maskbit; action->args.route_table.address = qdr_field(address); action->args.route_table.address_phase = phase; @@ -111,7 +111,7 @@ void qdr_core_map_destination(qdr_core_t *core, int router_maskbit, const char * void qdr_core_unmap_destination(qdr_core_t *core, int router_maskbit, const char *address, char aclass, char phase) { - qdr_action_t *action = qdr_action(qdrh_unmap_destination); + qdr_action_t *action = qdr_action(qdrh_unmap_destination_CT); action->args.route_table.router_maskbit = router_maskbit; action->args.route_table.address = qdr_field(address); action->args.route_table.address_phase = phase; @@ -136,16 +136,16 @@ void qdr_core_route_table_handlers(qdr_core_t *core, // In-Thread Functions //================================================================================== -void qdr_route_table_setup(qdr_core_t *core) +void qdr_route_table_setup_CT(qdr_core_t *core) { DEQ_INIT(core->addrs); DEQ_INIT(core->links); DEQ_INIT(core->routers); core->addr_hash = qd_hash(10, 32, 0); - core->router_addr = qdr_add_local_address(core, "qdrouter", QD_SEMANTICS_ROUTER_CONTROL); - core->routerma_addr = qdr_add_local_address(core, "qdrouter.ma", QD_SEMANTICS_DEFAULT); - core->hello_addr = qdr_add_local_address(core, "qdhello", QD_SEMANTICS_ROUTER_CONTROL); + core->router_addr = qdr_add_local_address_CT(core, "qdrouter", QD_SEMANTICS_ROUTER_CONTROL); + core->routerma_addr = qdr_add_local_address_CT(core, "qdrouter.ma", QD_SEMANTICS_DEFAULT); + core->hello_addr = qdr_add_local_address_CT(core, "qdhello", QD_SEMANTICS_ROUTER_CONTROL); core->routers_by_mask_bit = NEW_PTR_ARRAY(qdr_node_t, qd_bitmask_width()); core->out_links_by_mask_bit = NEW_PTR_ARRAY(qdr_link_t, qd_bitmask_width()); @@ -161,7 +161,7 @@ void qdr_route_table_setup(qdr_core_t *core) * Depending on its policy, the address may be eligible for being closed out * (i.e. Logging its terminal statistics and freeing its resources). */ -static void qdr_check_addr(qdr_core_t *core, qdr_address_t *addr, bool was_local) +static void qdr_check_addr_CT(qdr_core_t *core, qdr_address_t *addr, bool was_local) { if (addr == 0) return; @@ -214,7 +214,7 @@ static void qdr_check_addr(qdr_core_t *core, qdr_address_t *addr, bool was_local } -static void qdrh_add_router(qdr_core_t *core, qdr_action_t *action, bool discard) +static void qdrh_add_router_CT(qdr_core_t *core, qdr_action_t *action, bool discard) { int router_maskbit = action->args.route_table.router_maskbit; qdr_field_t *address = action->args.route_table.address; @@ -294,7 +294,7 @@ static void qdrh_add_router(qdr_core_t *core, qdr_action_t *action, bool discard } -static void qdrh_del_router(qdr_core_t *core, qdr_action_t *action, bool discard) +static void qdrh_del_router_CT(qdr_core_t *core, qdr_action_t *action, bool discard) { int router_maskbit = action->args.route_table.router_maskbit; @@ -343,7 +343,7 @@ static void qdrh_del_router(qdr_core_t *core, qdr_action_t *action, bool discard } -static void qdrh_set_link(qdr_core_t *core, qdr_action_t *action, bool discard) +static void qdrh_set_link_CT(qdr_core_t *core, qdr_action_t *action, bool discard) { int router_maskbit = action->args.route_table.router_maskbit; int link_maskbit = action->args.route_table.link_maskbit; @@ -376,7 +376,7 @@ static void qdrh_set_link(qdr_core_t *core, qdr_action_t *action, bool discard) } -static void qdrh_remove_link(qdr_core_t *core, qdr_action_t *action, bool discard) +static void qdrh_remove_link_CT(qdr_core_t *core, qdr_action_t *action, bool discard) { int router_maskbit = action->args.route_table.router_maskbit; @@ -395,7 +395,7 @@ static void qdrh_remove_link(qdr_core_t *core, qdr_action_t *action, bool discar } -static void qdrh_set_next_hop(qdr_core_t *core, qdr_action_t *action, bool discard) +static void qdrh_set_next_hop_CT(qdr_core_t *core, qdr_action_t *action, bool discard) { int router_maskbit = action->args.route_table.router_maskbit; int nh_router_maskbit = action->args.route_table.nh_router_maskbit; @@ -427,7 +427,7 @@ static void qdrh_set_next_hop(qdr_core_t *core, qdr_action_t *action, bool disca } -static void qdrh_remove_next_hop(qdr_core_t *core, qdr_action_t *action, bool discard) +static void qdrh_remove_next_hop_CT(qdr_core_t *core, qdr_action_t *action, bool discard) { int router_maskbit = action->args.route_table.router_maskbit; @@ -441,7 +441,7 @@ static void qdrh_remove_next_hop(qdr_core_t *core, qdr_action_t *action, bool di } -static void qdrh_set_valid_origins(qdr_core_t *core, qdr_action_t *action, bool discard) +static void qdrh_set_valid_origins_CT(qdr_core_t *core, qdr_action_t *action, bool discard) { int router_maskbit = action->args.route_table.router_maskbit; qd_bitmask_t *valid_origins = action->args.route_table.router_set; @@ -474,7 +474,7 @@ static void qdrh_set_valid_origins(qdr_core_t *core, qdr_action_t *action, bool } -static void qdrh_map_destination(qdr_core_t *core, qdr_action_t *action, bool discard) +static void qdrh_map_destination_CT(qdr_core_t *core, qdr_action_t *action, bool discard) { // // TODO - handle the class-prefix and phase explicitly @@ -522,7 +522,7 @@ static void qdrh_map_destination(qdr_core_t *core, qdr_action_t *action, bool di } -static void qdrh_unmap_destination(qdr_core_t *core, qdr_action_t *action, bool discard) +static void qdrh_unmap_destination_CT(qdr_core_t *core, qdr_action_t *action, bool discard) { int router_maskbit = action->args.route_table.router_maskbit; qdr_field_t *address = action->args.route_table.address; @@ -560,7 +560,7 @@ static void qdrh_unmap_destination(qdr_core_t *core, qdr_action_t *action, bool // TODO - If this affects a waypoint, create the proper side effects // - qdr_check_addr(core, addr, false); + qdr_check_addr_CT(core, addr, false); } while (false); qdr_field_free(address); diff --git a/src/router_core/router_core.c b/src/router_core/router_core.c index 99edccc9ef..b7f24e307f 100644 --- a/src/router_core/router_core.c +++ b/src/router_core/router_core.c @@ -145,7 +145,7 @@ qdr_address_t *qdr_address(qd_address_semantics_t semantics) } -qdr_address_t *qdr_add_local_address(qdr_core_t *core, const char *address, qd_address_semantics_t semantics) +qdr_address_t *qdr_add_local_address_CT(qdr_core_t *core, const char *address, qd_address_semantics_t semantics) { char addr_string[1000]; qdr_address_t *addr = 0; diff --git a/src/router_core/router_core_private.h b/src/router_core/router_core_private.h index de5566bb30..5dd1d84f2b 100644 --- a/src/router_core/router_core_private.h +++ b/src/router_core/router_core_private.h @@ -60,7 +60,7 @@ struct qdr_action_t { } route_table; struct { qdr_query_t *query; - int offset; + int offset; } agent; } args; }; @@ -68,12 +68,17 @@ struct qdr_action_t { ALLOC_DECLARE(qdr_action_t); DEQ_DECLARE(qdr_action_t, qdr_action_list_t); +#define QDR_AGENT_MAX_COLUMNS 64 +#define QDR_AGENT_COLUMN_NULL (QDR_AGENT_MAX_COLUMNS + 1) + struct qdr_query_t { DEQ_LINKS(qdr_query_t); qd_router_entity_type_t entity_type; void *context; + int columns[QDR_AGENT_MAX_COLUMNS]; qd_composed_field_t *body; qdr_field_t *next_key; + int next_offset; bool more; const qd_amqp_error_t *status; }; @@ -189,7 +194,7 @@ ALLOC_DECLARE(qdr_address_t); DEQ_DECLARE(qdr_address_t, qdr_address_list_t); qdr_address_t *qdr_address(qd_address_semantics_t semantics); -qdr_address_t *qdr_add_local_address(qdr_core_t *core, const char *addr, qd_address_semantics_t semantics); +qdr_address_t *qdr_add_local_address_CT(qdr_core_t *core, const char *addr, qd_address_semantics_t semantics); void qdr_add_link_ref(qdr_link_ref_list_t *ref_list, qdr_link_t *link); void qdr_del_link_ref(qdr_link_ref_list_t *ref_list, qdr_link_t *link); @@ -239,9 +244,10 @@ struct qdr_core_t { }; void *router_core_thread(void *arg); -void qdr_route_table_setup(qdr_core_t *core); -void qdr_agent_setup(qdr_core_t *core); +void qdr_route_table_setup_CT(qdr_core_t *core); +void qdr_agent_setup_CT(qdr_core_t *core); qdr_action_t *qdr_action(qdr_action_handler_t action_handler); void qdr_action_enqueue(qdr_core_t *core, qdr_action_t *action); +void qdr_agent_enqueue_response_CT(qdr_core_t *core, qdr_query_t *query); #endif diff --git a/src/router_core/router_core_thread.c b/src/router_core/router_core_thread.c index 7ef11bad25..42126645f9 100644 --- a/src/router_core/router_core_thread.c +++ b/src/router_core/router_core_thread.c @@ -36,8 +36,8 @@ void *router_core_thread(void *arg) qdr_action_list_t action_list; qdr_action_t *action; - qdr_route_table_setup(core); - qdr_agent_setup(core); + qdr_route_table_setup_CT(core); + qdr_agent_setup_CT(core); qd_log(core->log, QD_LOG_INFO, "Router Core thread running"); while (core->running) { From 22c856834295f24c2c66e1614619b337267afb70 Mon Sep 17 00:00:00 2001 From: Ted Ross Date: Wed, 28 Oct 2015 17:56:23 -0400 Subject: [PATCH 11/22] DISPATCH-179 - Implemented the core_subscribe action. --- include/qpid/dispatch/router_core.h | 3 +- src/router_core/route_tables.c | 48 +++++++++++++++++++++++++++ src/router_core/router_core_private.h | 21 +++++++++++- 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/include/qpid/dispatch/router_core.h b/include/qpid/dispatch/router_core.h index 2e11139608..fd19c825eb 100644 --- a/include/qpid/dispatch/router_core.h +++ b/include/qpid/dispatch/router_core.h @@ -76,7 +76,8 @@ void qdr_core_route_table_handlers(qdr_core_t *core, */ typedef void (*qdr_receive_t) (void *context, qd_message_t *msg, int link_maskbit); -void qdr_core_subscribe(qdr_core_t *core, const char *address, bool local, bool mobile, qdr_receive_t on_message, void *context); +void qdr_core_subscribe(qdr_core_t *core, const char *address, char aclass, char phase, + qd_address_semantics_t sem, qdr_receive_t on_message, void *context); /** diff --git a/src/router_core/route_tables.c b/src/router_core/route_tables.c index b71564ecce..1c96657f56 100644 --- a/src/router_core/route_tables.c +++ b/src/router_core/route_tables.c @@ -29,6 +29,7 @@ static void qdrh_remove_next_hop_CT (qdr_core_t *core, qdr_action_t *action, b static void qdrh_set_valid_origins_CT (qdr_core_t *core, qdr_action_t *action, bool discard); static void qdrh_map_destination_CT (qdr_core_t *core, qdr_action_t *action, bool discard); static void qdrh_unmap_destination_CT (qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdrh_subscribe_CT (qdr_core_t *core, qdr_action_t *action, bool discard); static qd_address_semantics_t router_addr_semantics = QD_FANOUT_SINGLE | QD_BIAS_CLOSEST | QD_CONGESTION_DROP | QD_DROP_FOR_SLOW_CONSUMERS | QD_BYPASS_VALID_ORIGINS; @@ -132,6 +133,20 @@ void qdr_core_route_table_handlers(qdr_core_t *core, } +void qdr_core_subscribe(qdr_core_t *core, const char *address, char aclass, char phase, + qd_address_semantics_t sem, qdr_receive_t on_message, void *context) +{ + qdr_action_t *action = qdr_action(qdrh_subscribe_CT); + action->args.subscribe.address = qdr_field(address); + action->args.subscribe.semantics = sem; + action->args.subscribe.aclass = aclass; + action->args.subscribe.phase = phase; + action->args.subscribe.on_message = on_message; + action->args.subscribe.context = context; + qdr_action_enqueue(core, action); +} + + //================================================================================== // In-Thread Functions //================================================================================== @@ -567,3 +582,36 @@ static void qdrh_unmap_destination_CT(qdr_core_t *core, qdr_action_t *action, bo } +static void qdrh_subscribe_CT(qdr_core_t *core, qdr_action_t *action, bool discard) +{ + qdr_field_t *address = action->args.subscribe.address; + + if (!discard) { + char aclass = action->args.subscribe.aclass; + char phase = action->args.subscribe.phase; + qdr_address_t *addr = 0; + + qd_address_iterator_override_prefix(address->iterator, aclass); + if (aclass == 'M') + qd_address_iterator_set_phase(address->iterator, phase); + qd_address_iterator_reset_view(address->iterator, ITER_VIEW_ADDRESS_HASH); + + qd_hash_retrieve(core->addr_hash, address->iterator, (void**) &addr); + if (!addr) { + addr = qdr_address(action->args.subscribe.semantics); + qd_hash_insert(core->addr_hash, address->iterator, addr, &addr->hash_handle); + DEQ_ITEM_INIT(addr); + DEQ_INSERT_TAIL(core->addrs, addr); + } + + if (!addr->on_message) { + addr->on_message = action->args.subscribe.on_message; + addr->on_message_context = action->args.subscribe.context; + } else + qd_log(core->log, QD_LOG_CRITICAL, + "qdr_core_subscribe: Multiple in-process subscriptions on the same address"); + } + + qdr_field_free(address); +} + diff --git a/src/router_core/router_core_private.h b/src/router_core/router_core_private.h index 5dd1d84f2b..5cb14a863d 100644 --- a/src/router_core/router_core_private.h +++ b/src/router_core/router_core_private.h @@ -48,6 +48,9 @@ struct qdr_action_t { DEQ_LINKS(qdr_action_t); qdr_action_handler_t action_handler; union { + // + // Arguments for router control-plane actions + // struct { int link_maskbit; int router_maskbit; @@ -58,9 +61,25 @@ struct qdr_action_t { char address_phase; qd_address_semantics_t semantics; } route_table; + + // + // Arguments for in-process subscriptions + // + struct { + qdr_field_t *address; + qd_address_semantics_t semantics; + char aclass; + char phase; + qdr_receive_t on_message; + void *context; + } subscribe; + + // + // Arguments for management-agent actions + // struct { qdr_query_t *query; - int offset; + int offset; } agent; } args; }; From afd9a04ed31901b1b34671671bb0aefbc5659091 Mon Sep 17 00:00:00 2001 From: Ted Ross Date: Mon, 2 Nov 2015 10:16:47 -0500 Subject: [PATCH 12/22] DISPATCH-179 - Minor edits --- src/router_core/route_tables.c | 16 ++++++++-------- src/router_core/router_core_private.h | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/router_core/route_tables.c b/src/router_core/route_tables.c index 1c96657f56..05a6bd3b2b 100644 --- a/src/router_core/route_tables.c +++ b/src/router_core/route_tables.c @@ -137,12 +137,12 @@ void qdr_core_subscribe(qdr_core_t *core, const char *address, char aclass, char qd_address_semantics_t sem, qdr_receive_t on_message, void *context) { qdr_action_t *action = qdr_action(qdrh_subscribe_CT); - action->args.subscribe.address = qdr_field(address); - action->args.subscribe.semantics = sem; - action->args.subscribe.aclass = aclass; - action->args.subscribe.phase = phase; - action->args.subscribe.on_message = on_message; - action->args.subscribe.context = context; + action->args.subscribe.address = qdr_field(address); + action->args.subscribe.semantics = sem; + action->args.subscribe.address_class = aclass; + action->args.subscribe.address_phase = phase; + action->args.subscribe.on_message = on_message; + action->args.subscribe.context = context; qdr_action_enqueue(core, action); } @@ -587,8 +587,8 @@ static void qdrh_subscribe_CT(qdr_core_t *core, qdr_action_t *action, bool disca qdr_field_t *address = action->args.subscribe.address; if (!discard) { - char aclass = action->args.subscribe.aclass; - char phase = action->args.subscribe.phase; + char aclass = action->args.subscribe.address_class; + char phase = action->args.subscribe.address_phase; qdr_address_t *addr = 0; qd_address_iterator_override_prefix(address->iterator, aclass); diff --git a/src/router_core/router_core_private.h b/src/router_core/router_core_private.h index 5cb14a863d..c7cff0c44b 100644 --- a/src/router_core/router_core_private.h +++ b/src/router_core/router_core_private.h @@ -68,8 +68,8 @@ struct qdr_action_t { struct { qdr_field_t *address; qd_address_semantics_t semantics; - char aclass; - char phase; + char address_class; + char address_phase; qdr_receive_t on_message; void *context; } subscribe; From 65231431a2fa7459f138b0cf0d839cf12c44cd23 Mon Sep 17 00:00:00 2001 From: Ted Ross Date: Wed, 4 Nov 2015 15:26:27 -0500 Subject: [PATCH 13/22] DISPATCH-179 - Updated and refined the core api for management queries --- include/qpid/dispatch/router_core.h | 26 +++++++++++--- src/router_core/agent.c | 49 ++++++++++++++++++--------- src/router_core/agent_address.c | 11 ++++++ src/router_core/agent_address.h | 1 + src/router_core/router_core_private.h | 1 + 5 files changed, 68 insertions(+), 20 deletions(-) diff --git a/include/qpid/dispatch/router_core.h b/include/qpid/dispatch/router_core.h index fd19c825eb..ad06cb0cc3 100644 --- a/include/qpid/dispatch/router_core.h +++ b/include/qpid/dispatch/router_core.h @@ -151,10 +151,28 @@ void qdr_manage_create(qdr_core_t *core, void *context, qd_router_entity_type_t void qdr_manage_delete(qdr_core_t *core, void *context, qd_router_entity_type_t type, qd_parsed_field_t *attributes); void qdr_manage_read(qdr_core_t *core, void *context, qd_router_entity_type_t type, qd_parsed_field_t *attributes); -qdr_query_t *qdr_manage_get_first(qdr_core_t *core, void *context, qd_router_entity_type_t type, int offset, - qd_parsed_field_t *attribute_names, qd_composed_field_t *body); -void qdr_manage_get_next(qdr_core_t *core, qdr_query_t *query); -void qdr_query_cancel(qdr_core_t *core, qdr_query_t *query); +/** + * Sequence for running a query: + * + * 1) Locate the attributeNames field in the body of the QUERY request + * 2) Create a composed field for the body of the reply message + * 3) Call qdr_manage_query with the attributeNames field and the response body + * 4) Start the body map, add the "attributeNames" key, start the value list + * 5) Call qdr_query_add_attribute_names. This will fill in the attribute names + * 6) Close out the list + * 7) Add the "results" key, start the outer list + * 8) Call qdr_query_get_first. This will asynchronously add the first inner list. + * 9) When the qdr_manage_response_t callback is invoked: + * a) if more is true and count is not exceeded, call qdr_query_get_next + * b) if more is false or count is exceeded, call qdr_query_free, close the outer list, close the map + */ + +qdr_query_t *qdr_manage_query(qdr_core_t *core, void *context, qd_router_entity_type_t type, + qd_parsed_field_t *attribute_names, qd_composed_field_t *body); +void qdr_query_add_attribute_names(qdr_query_t *query); +void qdr_query_get_first(qdr_query_t *query, int offset); +void qdr_query_get_next(qdr_query_t *query); +void qdr_query_free(qdr_query_t *query); typedef void (*qdr_manage_response_t) (void *context, const qd_amqp_error_t *status, bool more); void qdr_manage_handler(qdr_core_t *core, qdr_manage_response_t response_handler); diff --git a/src/router_core/agent.c b/src/router_core/agent.c index a42232b983..11f8fc239f 100644 --- a/src/router_core/agent.c +++ b/src/router_core/agent.c @@ -62,8 +62,8 @@ void qdr_agent_enqueue_response_CT(qdr_core_t *core, qdr_query_t *query) qd_timer_schedule(core->agent_timer, 0); } -static void qdrh_manage_get_first_CT(qdr_core_t *core, qdr_action_t *action, bool discard); -static void qdrh_manage_get_next_CT(qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdrh_query_get_first_CT(qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdrh_query_get_next_CT(qdr_core_t *core, qdr_action_t *action, bool discard); //================================================================================== @@ -85,12 +85,12 @@ void qdr_manage_read(qdr_core_t *core, void *context, qd_router_entity_type_t ty } -qdr_query_t *qdr_manage_get_first(qdr_core_t *core, void *context, qd_router_entity_type_t type, - int offset, qd_parsed_field_t *attribute_names, qd_composed_field_t *body) +qdr_query_t *qdr_manage_query(qdr_core_t *core, void *context, qd_router_entity_type_t type, + qd_parsed_field_t *attribute_names, qd_composed_field_t *body) { - qdr_action_t *action = qdr_action(qdrh_manage_get_first_CT); - qdr_query_t *query = new_qdr_query_t(); + qdr_query_t *query = new_qdr_query_t(); + query->core = core; query->entity_type = type; query->context = context; query->body = body; @@ -108,24 +108,41 @@ qdr_query_t *qdr_manage_get_first(qdr_core_t *core, void *context, qd_router_ent case QD_ROUTER_BINDING: break; } - action->args.agent.query = query; - action->args.agent.offset = offset; + return query; +} - qdr_action_enqueue(core, action); - return query; +void qdr_query_add_attribute_names(qdr_query_t *query) +{ + switch (query->entity_type) { + case QD_ROUTER_CONNECTION: break; + case QD_ROUTER_LINK: break; + case QD_ROUTER_ADDRESS: qdra_address_emit_columns(query); + case QD_ROUTER_WAYPOINT: break; + case QD_ROUTER_EXCHANGE: break; + case QD_ROUTER_BINDING: break; + } +} + + +void qdr_query_get_first(qdr_query_t *query, int offset) +{ + qdr_action_t *action = qdr_action(qdrh_query_get_first_CT); + action->args.agent.query = query; + action->args.agent.offset = offset; + qdr_action_enqueue(query->core, action); } -void qdr_manage_get_next(qdr_core_t *core, qdr_query_t *query) +void qdr_query_get_next(qdr_query_t *query) { - qdr_action_t *action = qdr_action(qdrh_manage_get_next_CT); + qdr_action_t *action = qdr_action(qdrh_query_get_next_CT); action->args.agent.query = query; - qdr_action_enqueue(core, action); + qdr_action_enqueue(query->core, action); } -void qdr_query_cancel(qdr_core_t *core, qdr_query_t *query) +void qdr_query_free(qdr_query_t *query) { } @@ -148,7 +165,7 @@ void qdr_agent_setup_CT(qdr_core_t *core) } -static void qdrh_manage_get_first_CT(qdr_core_t *core, qdr_action_t *action, bool discard) +static void qdrh_query_get_first_CT(qdr_core_t *core, qdr_action_t *action, bool discard) { qdr_query_t *query = action->args.agent.query; int offset = action->args.agent.offset; @@ -165,7 +182,7 @@ static void qdrh_manage_get_first_CT(qdr_core_t *core, qdr_action_t *action, boo } -static void qdrh_manage_get_next_CT(qdr_core_t *core, qdr_action_t *action, bool discard) +static void qdrh_query_get_next_CT(qdr_core_t *core, qdr_action_t *action, bool discard) { qdr_query_t *query = action->args.agent.query; diff --git a/src/router_core/agent_address.c b/src/router_core/agent_address.c index 5ede5d1113..4dd2845bfa 100644 --- a/src/router_core/agent_address.c +++ b/src/router_core/agent_address.c @@ -171,6 +171,17 @@ void qdra_address_set_columns(qdr_query_t *query, qd_parsed_field_t *attribute_n } +void qdra_address_emit_columns(qdr_query_t *query) +{ + int i = 0; + while (query->columns[i] >= 0) { + assert(query->columns[i] < QDR_ADDRESS_COLUMN_COUNT); + qd_compose_insert_string(query->body, qdr_address_columns[query->columns[i]]); + i++; + } +} + + void qdra_address_get_first_CT(qdr_core_t *core, qdr_query_t *query, int offset) { // diff --git a/src/router_core/agent_address.h b/src/router_core/agent_address.h index 9d6c078e73..53d383adfa 100644 --- a/src/router_core/agent_address.h +++ b/src/router_core/agent_address.h @@ -22,6 +22,7 @@ #include "router_core_private.h" void qdra_address_set_columns(qdr_query_t *query, qd_parsed_field_t *attribute_names); +void qdra_address_emit_columns(qdr_query_t *query); void qdra_address_get_first_CT(qdr_core_t *core, qdr_query_t *query, int offset); void qdra_address_get_next_CT(qdr_core_t *core, qdr_query_t *query); diff --git a/src/router_core/router_core_private.h b/src/router_core/router_core_private.h index c7cff0c44b..11393a3fa5 100644 --- a/src/router_core/router_core_private.h +++ b/src/router_core/router_core_private.h @@ -92,6 +92,7 @@ DEQ_DECLARE(qdr_action_t, qdr_action_list_t); struct qdr_query_t { DEQ_LINKS(qdr_query_t); + qdr_core_t *core; qd_router_entity_type_t entity_type; void *context; int columns[QDR_AGENT_MAX_COLUMNS]; From 2ce036b91adb05c42769e40fff9bef94cf9cc781 Mon Sep 17 00:00:00 2001 From: Ted Ross Date: Wed, 4 Nov 2015 15:32:18 -0500 Subject: [PATCH 14/22] DISPATCH-179 - Emit the start and end of the attributeNames list in the core function. --- include/qpid/dispatch/router_core.h | 11 +++++------ src/router_core/agent_address.c | 2 ++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/include/qpid/dispatch/router_core.h b/include/qpid/dispatch/router_core.h index ad06cb0cc3..13a3246df4 100644 --- a/include/qpid/dispatch/router_core.h +++ b/include/qpid/dispatch/router_core.h @@ -157,12 +157,11 @@ void qdr_manage_read(qdr_core_t *core, void *context, qd_router_entity_type_t ty * 1) Locate the attributeNames field in the body of the QUERY request * 2) Create a composed field for the body of the reply message * 3) Call qdr_manage_query with the attributeNames field and the response body - * 4) Start the body map, add the "attributeNames" key, start the value list - * 5) Call qdr_query_add_attribute_names. This will fill in the attribute names - * 6) Close out the list - * 7) Add the "results" key, start the outer list - * 8) Call qdr_query_get_first. This will asynchronously add the first inner list. - * 9) When the qdr_manage_response_t callback is invoked: + * 4) Start the body map, add the "attributeNames" key + * 5) Call qdr_query_add_attribute_names. This will add the attribute names list + * 6) Add the "results" key, start the outer list + * 7) Call qdr_query_get_first. This will asynchronously add the first inner list. + * 8) When the qdr_manage_response_t callback is invoked: * a) if more is true and count is not exceeded, call qdr_query_get_next * b) if more is false or count is exceeded, call qdr_query_free, close the outer list, close the map */ diff --git a/src/router_core/agent_address.c b/src/router_core/agent_address.c index 4dd2845bfa..60f46a3aaf 100644 --- a/src/router_core/agent_address.c +++ b/src/router_core/agent_address.c @@ -173,12 +173,14 @@ void qdra_address_set_columns(qdr_query_t *query, qd_parsed_field_t *attribute_n void qdra_address_emit_columns(qdr_query_t *query) { + qd_compose_start_list(query->body); int i = 0; while (query->columns[i] >= 0) { assert(query->columns[i] < QDR_ADDRESS_COLUMN_COUNT); qd_compose_insert_string(query->body, qdr_address_columns[query->columns[i]]); i++; } + qd_compose_end_list(query->body); } From 8c48073d226bea31e2b0bfdd0eab7d74c01089f4 Mon Sep 17 00:00:00 2001 From: Ted Ross Date: Wed, 4 Nov 2015 16:16:09 -0500 Subject: [PATCH 15/22] DISPATCH-179 - Added missing ID and NAME fields for addresses in the core agent --- src/router_core/agent_address.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/router_core/agent_address.c b/src/router_core/agent_address.c index 60f46a3aaf..94a0659fcf 100644 --- a/src/router_core/agent_address.c +++ b/src/router_core/agent_address.c @@ -60,12 +60,6 @@ static void qdr_manage_write_address_CT(qdr_query_t *query, qdr_address_t *addr) switch(query->columns[i]) { case QDR_ADDRESS_NAME: case QDR_ADDRESS_IDENTITY: - break; - - case QDR_ADDRESS_TYPE: - qd_compose_insert_string(body, "org.apache.qpid.dispatch.router.address"); - break; - case QDR_ADDRESS_KEY: if (addr->hash_handle) qd_compose_insert_string(body, (const char*) qd_hash_key_by_handle(addr->hash_handle)); @@ -73,6 +67,10 @@ static void qdr_manage_write_address_CT(qdr_query_t *query, qdr_address_t *addr) qd_compose_insert_null(body); break; + case QDR_ADDRESS_TYPE: + qd_compose_insert_string(body, "org.apache.qpid.dispatch.router.address"); + break; + case QDR_ADDRESS_IN_PROCESS: qd_compose_insert_bool(body, addr->on_message != 0); break; From df2bf5de9fe715c19bba55e48349341f90370610 Mon Sep 17 00:00:00 2001 From: Ted Ross Date: Thu, 5 Nov 2015 10:16:25 -0500 Subject: [PATCH 16/22] DISPATCH-179 - Added core-connection handling --- include/qpid/dispatch/router.h | 4 + include/qpid/dispatch/router_core.h | 16 +++- src/CMakeLists.txt | 1 + src/router_core/connections.c | 127 ++++++++++++++++++++++++++ src/router_core/router_core_private.h | 20 ++++ src/router_node.c | 7 +- 6 files changed, 169 insertions(+), 6 deletions(-) create mode 100644 src/router_core/connections.c diff --git a/include/qpid/dispatch/router.h b/include/qpid/dispatch/router.h index b1e4cedc61..30b9022436 100644 --- a/include/qpid/dispatch/router.h +++ b/include/qpid/dispatch/router.h @@ -37,6 +37,8 @@ typedef struct qd_address_t qd_address_t; typedef uint8_t qd_address_semantics_t; typedef struct qd_router_delivery_t qd_router_delivery_t; +#include + /** * @name Address fanout semantics * @{ @@ -140,6 +142,8 @@ typedef void (*qd_router_message_cb_t)(void *context, qd_message_t *msg, int lin const char *qd_router_id(const qd_dispatch_t *qd); +qdr_core_t *qd_router_core(qd_dispatch_t *qd); + /** Register an address in the router's hash table. * @param qd Pointer to the dispatch instance. * @param address String form of address diff --git a/include/qpid/dispatch/router_core.h b/include/qpid/dispatch/router_core.h index 13a3246df4..5180996123 100644 --- a/include/qpid/dispatch/router_core.h +++ b/include/qpid/dispatch/router_core.h @@ -19,15 +19,16 @@ * under the License. */ -#include #include #include #include #include +#include -// -// All callbacks in this module shall be invoked on a connection thread from the server thread pool. -// + +/** + * All callbacks in this module shall be invoked on a connection thread from the server thread pool. + */ typedef struct qdr_core_t qdr_core_t; typedef struct qdr_connection_t qdr_connection_t; @@ -100,7 +101,12 @@ typedef struct { qdr_delivery_t *delivery; // For DELIVERY } qdr_work_t; -qdr_connection_t *qdr_connection_opened(qdr_core_t *core, qd_field_iterator_t *label); +/** + * qdr_connection_opened + * + * This function must be called once for every + */ +qdr_connection_t *qdr_connection_opened(qdr_core_t *core, const char *label); void qdr_connection_closed(qdr_connection_t *conn); void qdr_connection_set_context(qdr_connection_t *conn, void *context); void *qdr_connection_get_context(qdr_connection_t *conn); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 42c9fc9ba4..5168803dad 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -67,6 +67,7 @@ set(qpid_dispatch_SOURCES router_config.c router_core/agent.c router_core/agent_address.c + router_core/connections.c router_core/router_core.c router_core/router_core_thread.c router_core/route_tables.c diff --git a/src/router_core/connections.c b/src/router_core/connections.c new file mode 100644 index 0000000000..14e95fd03a --- /dev/null +++ b/src/router_core/connections.c @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "router_core_private.h" + +static void qdr_connection_opened_CT(qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdr_connection_closed_CT(qdr_core_t *core, qdr_action_t *action, bool discard); + +ALLOC_DEFINE(qdr_connection_t); + +//================================================================================== +// Internal Functions +//================================================================================== + + +//================================================================================== +// Interface Functions +//================================================================================== + +qdr_connection_t *qdr_connection_opened(qdr_core_t *core, const char *label) +{ + qdr_action_t *action = qdr_action(qdr_connection_opened_CT); + qdr_connection_t *conn = new_qdr_connection_t(); + + conn->core = core; + conn->user_context = 0; + conn->label = label; + + action->args.connection.conn = conn; + qdr_action_enqueue(core, action); + + return conn; +} + + +void qdr_connection_closed(qdr_connection_t *conn) +{ + qdr_action_t *action = qdr_action(qdr_connection_closed_CT); + action->args.connection.conn = conn; + qdr_action_enqueue(conn->core, action); +} + + +void qdr_connection_set_context(qdr_connection_t *conn, void *context) +{ + if (conn) + conn->user_context = context; +} + + +void *qdr_connection_get_context(qdr_connection_t *conn) +{ + return conn ? conn->user_context : 0; +} + + +qdr_work_t *qdr_connection_work(qdr_connection_t *conn) +{ + return 0; +} + + +void qdr_connection_activate_handler(qdr_core_t *core, qdr_connection_activate_t handler, void *context) +{ +} + + +//================================================================================== +// In-Thread Functions +//================================================================================== + +static void qdr_connection_opened_CT(qdr_core_t *core, qdr_action_t *action, bool discard) +{ + if (discard) + return; + + qdr_connection_t *conn = action->args.connection.conn; + DEQ_ITEM_INIT(conn); + DEQ_INSERT_TAIL(core->open_connections, conn); + + // + // TODO - Look for waypoints that need to be activated now that their connection + // is open. + // + + // + // TODO - Look for link-route destinations to be activated now that their connection + // is open. + // +} + + +static void qdr_connection_closed_CT(qdr_core_t *core, qdr_action_t *action, bool discard) +{ + if (discard) + return; + + qdr_connection_t *conn = action->args.connection.conn; + + // + // TODO - Deactivate waypoints and link-route destinations for this connection + // + + // + // TODO - Clean up links associated with this connection + // + + DEQ_REMOVE(core->open_connections, conn); + free_qdr_connection_t(conn); +} + diff --git a/src/router_core/router_core_private.h b/src/router_core/router_core_private.h index 11393a3fa5..54ff4cfedf 100644 --- a/src/router_core/router_core_private.h +++ b/src/router_core/router_core_private.h @@ -62,6 +62,13 @@ struct qdr_action_t { qd_address_semantics_t semantics; } route_table; + // + // Arguments for connection-level actions + // + struct { + qdr_connection_t *conn; + } connection; + // // Arguments for in-process subscriptions // @@ -223,6 +230,17 @@ void qdr_add_node_ref(qdr_router_ref_list_t *ref_list, qdr_node_t *rnode); void qdr_del_node_ref(qdr_router_ref_list_t *ref_list, qdr_node_t *rnode); +struct qdr_connection_t { + DEQ_LINKS(qdr_connection_t); + qdr_core_t *core; + void *user_context; + const char *label; +}; + +ALLOC_DECLARE(qdr_connection_t); +DEQ_DECLARE(qdr_connection_t, qdr_connection_list_t); + + struct qdr_core_t { qd_dispatch_t *qd; qd_log_source_t *log; @@ -232,6 +250,8 @@ struct qdr_core_t { sys_cond_t *action_cond; sys_mutex_t *action_lock; + qdr_connection_list_t open_connections; + // // Agent section // diff --git a/src/router_node.c b/src/router_node.c index a45e9bbbb5..677981721c 100644 --- a/src/router_node.c +++ b/src/router_node.c @@ -18,7 +18,6 @@ */ #include -#include #include #include #include @@ -1918,6 +1917,12 @@ const char *qd_router_id(const qd_dispatch_t *qd) } +qdr_core_t *qd_router_core(qd_dispatch_t *qd) +{ + return qd->router->router_core; +} + + qd_address_t *qd_router_register_address(qd_dispatch_t *qd, const char *address, qd_router_message_cb_t on_message, From b3b3d79df1ac6319c54ff03f2ba55d6daa82d433 Mon Sep 17 00:00:00 2001 From: Ted Ross Date: Fri, 6 Nov 2015 15:01:14 -0500 Subject: [PATCH 17/22] DISPATCH-179 - Updated the core-API for connections and links --- include/qpid/dispatch/router_core.h | 96 ++++++++++++++++++++++----- src/router_core/connections.c | 56 +++++++++++++++- src/router_core/router_core_private.h | 9 +++ 3 files changed, 140 insertions(+), 21 deletions(-) diff --git a/include/qpid/dispatch/router_core.h b/include/qpid/dispatch/router_core.h index 5180996123..553d0dad85 100644 --- a/include/qpid/dispatch/router_core.h +++ b/include/qpid/dispatch/router_core.h @@ -28,6 +28,8 @@ /** * All callbacks in this module shall be invoked on a connection thread from the server thread pool. + * If the callback needs to perform work on a connection, it will be invoked on a thread that has + * exclusive access to that connection. */ typedef struct qdr_core_t qdr_core_t; @@ -86,47 +88,105 @@ void qdr_core_subscribe(qdr_core_t *core, const char *address, char aclass, char * Connection functions ****************************************************************************** */ -typedef enum { - QDR_WORK_FIRST_ATTACH, // Core is initiating a first-attach - QDR_WORK_SECOND_ATTACH, // Core is sending a second-attach - QDR_WORK_DETACH, // Core is sending a detach - QDR_WORK_DELIVERY // Core is updating a delivery for in-thread processing -} qdr_work_type_t; - -typedef struct { - qdr_work_type_t work_type; - pn_terminus_t *source; // For FIRST_ATTACH - pn_terminus_t *target; // For FIRST_ATTACH - qdr_link_t *link; // For SECOND_ATTACH, DETACH - qdr_delivery_t *delivery; // For DELIVERY -} qdr_work_t; /** * qdr_connection_opened * - * This function must be called once for every + * This function must be called once for every connection that is opened in the router. + * Once a new connection has been both remotely and locally opened, the core must be notified. + * + * @param core Pointer to the core object + * @param label Optional label provided in the connection's configuration. This is used to + * correlate the connection with waypoints and link-route destinations that use the connection. + * @return Pointer to a connection object that can be used to refer to this connection over its lifetime. */ qdr_connection_t *qdr_connection_opened(qdr_core_t *core, const char *label); + +/** + * qdr_connection_closed + * + * This function must be called when a connection is closed, either cleanly by protocol + * or uncleanly by lost connectivity. Once this functino is called, the caller must never + * again refer to or use the connection pointer. + * + * @param conn The pointer returned by qdr_connection_opened + */ void qdr_connection_closed(qdr_connection_t *conn); + +/** + * qdr_connection_set_context + * + * Store an arbitrary void pointer in the connection object. + */ void qdr_connection_set_context(qdr_connection_t *conn, void *context); + +/** + * qdr_connection_get_context + * + * Retrieve the stored void pointer from the connection object. + */ void *qdr_connection_get_context(qdr_connection_t *conn); -qdr_work_t *qdr_connection_work(qdr_connection_t *conn); -typedef void (*qdr_connection_activate_t) (void *context, const qdr_connection_t *connection); -void qdr_connection_activate_handler(qdr_core_t *core, qdr_connection_activate_t handler, void *context); +/** + * qdr_connection_activate_t callback + * + * Activate a connection for transmission (socket write). This is called whenever + * the core has deliveries on links, disposition updates on deliveries, or flow updates + * to be sent across the connection. + * + * @param context The context supplied when the callback was registered + * @param conn The connection object to be activated + */ +typedef void (*qdr_connection_activate_t) (void *context, qdr_connection_t *conn); /** ****************************************************************************** * Link functions ****************************************************************************** */ + +/** + * qdr_link_first_attach + * + * This function is invoked when a first-attach (not a response to an earlier attach) + * arrives for a connection. + * + * @param conn Connection pointer returned by qdr_connection_opened + * @param dir Direction of the new link, incoming or outgoing + * @param source Source terminus of the attach + * @param target Target terminus of the attach + * @return A pointer to a new qdr_link_t object to track the link + */ qdr_link_t *qdr_link_first_attach(qdr_connection_t *conn, qd_direction_t dir, pn_terminus_t *source, pn_terminus_t *target); + +/** + * qdr_link_second_attach + * + * This function is invoked when a second-attach (a response to an attach we sent) + * arrives for a connection. + * + * @param link The link pointer returned by qdr_link_first_attach or in a FIRST_ATTACH event. + * @param source Source terminus of the attach + * @param target Target terminus of the attach + */ void qdr_link_second_attach(qdr_link_t *link, pn_terminus_t *source, pn_terminus_t *target); + +/** + * qdr_link_detach + * + * This function is invoked when a link detach arrives. + * + * @param link The link pointer returned by qdr_link_first_attach or in a FIRST_ATTACH event. + * @param condition The link condition from the detach frame. + */ void qdr_link_detach(qdr_link_t *link, pn_condition_t *condition); qdr_delivery_t *qdr_link_deliver(qdr_link_t *link, pn_delivery_t *delivery, qd_message_t *msg); qdr_delivery_t *qdr_link_deliver_to(qdr_link_t *link, pn_delivery_t *delivery, qd_message_t *msg, qd_field_iterator_t *addr); +typedef void (*qdr_link_first_attach_t) (void *context, qdr_connection_t *conn, qd_direction_t dir, pn_terminus_t *source, pn_terminus_t *target); +typedef void (*qdr_link_second_attach_t) (void *context, qdr_link_t *link, pn_terminus_t *source, pn_terminus_t *target); +typedef void (*qdr_link_detach_t) (void *context, qdr_link_t *link, pn_condition_t *condition); /** ****************************************************************************** diff --git a/src/router_core/connections.c b/src/router_core/connections.c index 14e95fd03a..2d7fdc0d74 100644 --- a/src/router_core/connections.c +++ b/src/router_core/connections.c @@ -21,6 +21,9 @@ static void qdr_connection_opened_CT(qdr_core_t *core, qdr_action_t *action, bool discard); static void qdr_connection_closed_CT(qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdr_link_first_attach_CT(qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdr_link_second_attach_CT(qdr_core_t *core, qdr_action_t *action, bool discard); +static void qdr_link_detach_CT(qdr_core_t *core, qdr_action_t *action, bool discard); ALLOC_DEFINE(qdr_connection_t); @@ -70,14 +73,43 @@ void *qdr_connection_get_context(qdr_connection_t *conn) } -qdr_work_t *qdr_connection_work(qdr_connection_t *conn) +qdr_link_t *qdr_link_first_attach(qdr_connection_t *conn, qd_direction_t dir, pn_terminus_t *source, pn_terminus_t *target) { - return 0; + qdr_action_t *action = qdr_action(qdr_link_first_attach_CT); + qdr_link_t *link = new_qdr_link_t(); + + link->core = conn->core; + link->conn = conn; + + action->args.connection.conn = conn; + action->args.connection.link = link; + action->args.connection.dir = dir; + action->args.connection.source = source; + action->args.connection.target = target; + qdr_action_enqueue(conn->core, action); + + return link; +} + + +void qdr_link_second_attach(qdr_link_t *link, pn_terminus_t *source, pn_terminus_t *target) +{ + qdr_action_t *action = qdr_action(qdr_link_second_attach_CT); + + action->args.connection.link = link; + action->args.connection.source = source; + action->args.connection.target = target; + qdr_action_enqueue(link->core, action); } -void qdr_connection_activate_handler(qdr_core_t *core, qdr_connection_activate_t handler, void *context) +void qdr_link_detach(qdr_link_t *link, pn_condition_t *condition) { + qdr_action_t *action = qdr_action(qdr_link_detach_CT); + + action->args.connection.link = link; + action->args.connection.condition = condition; + qdr_action_enqueue(link->core, action); } @@ -119,9 +151,27 @@ static void qdr_connection_closed_CT(qdr_core_t *core, qdr_action_t *action, boo // // TODO - Clean up links associated with this connection + // This involves the links and the dispositions of deliveries stored + // with the links. // DEQ_REMOVE(core->open_connections, conn); free_qdr_connection_t(conn); } + +static void qdr_link_first_attach_CT(qdr_core_t *core, qdr_action_t *action, bool discard) +{ +} + + +static void qdr_link_second_attach_CT(qdr_core_t *core, qdr_action_t *action, bool discard) +{ +} + + +static void qdr_link_detach_CT(qdr_core_t *core, qdr_action_t *action, bool discard) +{ +} + + diff --git a/src/router_core/router_core_private.h b/src/router_core/router_core_private.h index 54ff4cfedf..69b990a7bc 100644 --- a/src/router_core/router_core_private.h +++ b/src/router_core/router_core_private.h @@ -67,6 +67,13 @@ struct qdr_action_t { // struct { qdr_connection_t *conn; + qdr_link_t *link; + qdr_delivery_t *delivery; + qd_message_t *msg; + qd_direction_t dir; + pn_terminus_t *source; + pn_terminus_t *target; + pn_condition_t *condition; } connection; // @@ -146,6 +153,8 @@ DEQ_DECLARE(qdr_router_ref_t, qdr_router_ref_list_t); struct qdr_link_t { DEQ_LINKS(qdr_link_t); + qdr_core_t *core; + qdr_connection_t *conn; int mask_bit; ///< Unique mask bit if this is an inter-router link qd_link_type_t link_type; qd_direction_t link_direction; From cf319fd215e8d2f4e4b09d5333dbc75fc2a96d22 Mon Sep 17 00:00:00 2001 From: ganeshmurthy Date: Fri, 6 Nov 2015 15:28:20 -0500 Subject: [PATCH 18/22] DISPATCH-179 - Initial coding to introduce a C agent that will handle certain requests and forward the rest to the Python Agent --- .../management/config.py | 3 +- src/CMakeLists.txt | 1 + src/router_core/agent.c | 4 +- src/router_core/agent_address.c | 1 + src/router_core/management_agent.c | 349 ++++++++++++++++++ src/router_core/management_agent_private.h | 25 ++ src/router_node.c | 8 + src/server.c | 1 + 8 files changed, 389 insertions(+), 3 deletions(-) create mode 100644 src/router_core/management_agent.c create mode 100644 src/router_core/management_agent_private.h diff --git a/python/qpid_dispatch_internal/management/config.py b/python/qpid_dispatch_internal/management/config.py index 73725c1c52..0ab9bbb5d4 100644 --- a/python/qpid_dispatch_internal/management/config.py +++ b/python/qpid_dispatch_internal/management/config.py @@ -138,6 +138,7 @@ def configure(attributes): for l in config.by_type('log'): configure(l) modules.remove(l["module"]) + # Add default entities for any log modules not configured. for m in modules: agent.configure(attributes=dict(type="log", module=m)) @@ -145,7 +146,7 @@ def configure(attributes): configure(config.by_type('container')[0]) configure(config.by_type('router')[0]) qd.qd_dispatch_prepare(dispatch) - agent.activate("$management") + #agent.activate("$management_internal") qd.qd_router_setup_late(dispatch) # Actions requiring active management agent. # Remaining configuration diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5168803dad..a55b73b954 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -71,6 +71,7 @@ set(qpid_dispatch_SOURCES router_core/router_core.c router_core/router_core_thread.c router_core/route_tables.c + router_core/management_agent.c router_delivery.c router_node.c router_forwarders.c diff --git a/src/router_core/agent.c b/src/router_core/agent.c index 11f8fc239f..9eabf6b213 100644 --- a/src/router_core/agent.c +++ b/src/router_core/agent.c @@ -102,7 +102,7 @@ qdr_query_t *qdr_manage_query(qdr_core_t *core, void *context, qd_router_entity_ switch (query->entity_type) { case QD_ROUTER_CONNECTION: break; case QD_ROUTER_LINK: break; - case QD_ROUTER_ADDRESS: qdra_address_set_columns(query, attribute_names); + case QD_ROUTER_ADDRESS: qdra_address_set_columns(query, attribute_names);break; case QD_ROUTER_WAYPOINT: break; case QD_ROUTER_EXCHANGE: break; case QD_ROUTER_BINDING: break; @@ -117,7 +117,7 @@ void qdr_query_add_attribute_names(qdr_query_t *query) switch (query->entity_type) { case QD_ROUTER_CONNECTION: break; case QD_ROUTER_LINK: break; - case QD_ROUTER_ADDRESS: qdra_address_emit_columns(query); + case QD_ROUTER_ADDRESS: qdra_address_emit_columns(query); break; case QD_ROUTER_WAYPOINT: break; case QD_ROUTER_EXCHANGE: break; case QD_ROUTER_BINDING: break; diff --git a/src/router_core/agent_address.c b/src/router_core/agent_address.c index 94a0659fcf..88a60f72ca 100644 --- a/src/router_core/agent_address.c +++ b/src/router_core/agent_address.c @@ -111,6 +111,7 @@ static void qdr_manage_write_address_CT(qdr_query_t *query, qdr_address_t *addr) qd_compose_insert_null(body); break; } + i++; } qd_compose_end_list(body); } diff --git a/src/router_core/management_agent.c b/src/router_core/management_agent.c new file mode 100644 index 0000000000..848ca6659f --- /dev/null +++ b/src/router_core/management_agent.c @@ -0,0 +1,349 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "management_agent_private.h" +#include "dispatch_private.h" +#include "alloc.h" + +const char *entity_type_key = "entityType"; +const char *count_key = "count"; +const char *offset_key = "offset"; + +const char *operation_type_key = "operation"; +const char *attribute_names_key = "attributeNames"; + +const unsigned char *address_entity_type = (unsigned char*) "org.apache.qpid.dispatch.router.address"; +const unsigned char *link_entity_type = (unsigned char*) "org.apache.qpid.dispatch.router.link"; + +const char * const status_description = "statusDescription"; +const char * const correlation_id = "correlation-id"; +const char * const results = "results"; +const char * const status_code = "statusCode"; + +const char * MANAGEMENT_INTERNAL = "$management_internal"; + +//TODO - Move these to amqp.h +const unsigned char *MANAGEMENT_QUERY = (unsigned char*) "QUERY"; +const unsigned char *MANAGEMENT_CREATE = (unsigned char*) "CREATE"; +const unsigned char *MANAGEMENT_READ = (unsigned char*) "READ"; +const unsigned char *MANAGEMENT_UPDATE = (unsigned char*) "UPDATE"; +const unsigned char *MANAGEMENT_DELETE = (unsigned char*) "DELETE"; + + +typedef enum { + QD_ROUTER_OPERATION_QUERY, + QD_ROUTER_OPERATION_CREATE, + QD_ROUTER_OPERATION_READ, + QD_ROUTER_OPERATION_UPDATE, + QD_ROUTER_OPERATION_DELETE, +} qd_router_operation_type_t; + + +typedef struct qd_management_context_t { + qd_message_t *msg; + qd_composed_field_t *field; + qdr_query_t *query; + qd_dispatch_t *qd; + qd_field_iterator_t *to; + int count; + int current_count; +} qd_management_context_t ; + +ALLOC_DECLARE(qd_management_context_t); +ALLOC_DEFINE(qd_management_context_t); + +/** + * Convenience function to create and initialize context (qd_management_context_t) + */ +static qd_management_context_t* qd_management_context(qd_message_t *msg, + qd_composed_field_t *field, + qdr_query_t *query, + qd_field_iterator_t *to, + qd_dispatch_t *qd, + int count) +{ + qd_management_context_t *ctx = new_qd_management_context_t(); + ctx->count = count; + ctx->field = field; + ctx->msg = msg; + if (query) + ctx->query = query; + else + ctx->query = 0; + ctx->current_count = 0; + ctx->qd = qd; + ctx->to = to; + + return ctx; +} + +static void qd_compose_send(qd_management_context_t *ctx) +{ + qd_compose_end_list(ctx->field); + qd_compose_end_map(ctx->field); + qd_message_compose_2(ctx->msg, ctx->field); + qd_router_send(ctx->qd, ctx->to, ctx->msg); + + //We have come to the very end. Free the appropriate memory. + //ctx->field has already been freed in the call to qd_compose_end_list(ctx->field) + //ctx->query has also been already freed + qd_message_free(ctx->msg); + qd_field_iterator_free(ctx->to); + free_qd_management_context_t(ctx); +} + + +static void manage_response_handler (void *context, const qd_amqp_error_t *status, bool more) +{ + qd_management_context_t *ctx = (qd_management_context_t*) context; + + //TODO - Check the status (qd_amqp_error_t) here first. If the status is anything other that 200, you need to send it back the message with the status. + + if (!more || ctx->count == 0) { + // If Count is zero or there are no more rows to process or the status returned is something other than + // QD_AMQP_OK, we will close the list, send the message and + qd_compose_send(ctx); + } + else { + ctx->current_count++; // Increment how many you have at hand + + if (ctx->count == ctx->current_count) //The count has matched, we are done, close the list and send out the message + qd_compose_send(ctx); + else + qdr_query_get_next(ctx->query); + } +} + +static void core_agent_query_handler(qd_dispatch_t *qd, + qd_router_entity_type_t entity_type, + qd_message_t *msg, + int *count, + int *offset) +{ + qdr_core_t *core = qd_router_core(qd); + + // Create a new message + qd_message_t *message = qd_message(); + qd_field_iterator_t *correlation_id = qd_message_field_iterator_typed(msg, QD_FIELD_CORRELATION_ID); + // Grab the reply_to field from the incoming message. This is the address we will send the response to. + qd_field_iterator_t *reply_to = qd_message_field_iterator(msg, QD_FIELD_REPLY_TO); + + qd_composed_field_t *field = qd_compose(QD_PERFORMATIVE_PROPERTIES, 0); + qd_compose_start_list(field); + qd_compose_insert_null(field); // message-id + qd_compose_insert_null(field); // user-id + qd_compose_insert_string_iterator(field, reply_to); // to + qd_compose_insert_null(field); // subject + qd_compose_insert_null(field); + qd_compose_insert_typed_iterator(field, correlation_id); + qd_compose_end_list(field); + + + // Get the attributeNames + qd_parsed_field_t *attribute_names_parsed_field = 0; + + qd_parsed_field_t *body = qd_parse(qd_message_field_iterator(msg, QD_FIELD_BODY)); + + if (body != 0 && qd_parse_is_map(body)) + attribute_names_parsed_field = qd_parse_value_by_key(body, attribute_names_key); + + // + // Insert application property map with statusDescription of OK and status code of 200 + // + field = qd_compose(QD_PERFORMATIVE_APPLICATION_PROPERTIES, field); + qd_compose_start_map(field); + + // Insert {'statusDescription': 'OK'} + qd_compose_insert_string(field, status_description); + qd_compose_insert_string(field, QD_AMQP_OK.description); + + // Insert {'statusCode': '200'} + qd_compose_insert_string(field, status_code); + qd_compose_insert_uint(field, QD_AMQP_OK.status); + + qd_compose_end_map(field); + + // + // Add Body + // + field = qd_compose(QD_PERFORMATIVE_BODY_AMQP_VALUE, field); + + // Start a map in the body + qd_compose_start_map(field); + + qd_compose_insert_string(field, attribute_names_key); //add a "attributeNames" key + + // Set the callback function. + qdr_manage_handler(core, manage_response_handler); + + qd_management_context_t *ctx = qd_management_context(message, field, 0, reply_to, qd, (*count)); + + ctx->query = qdr_manage_query(core, ctx, entity_type, attribute_names_parsed_field, field); + + //Add the attribute names + qdr_query_add_attribute_names(ctx->query); + + qd_compose_insert_string(field, results); //add a "results" key + qd_compose_start_list(field); //start the list for results + + qdr_query_get_first(ctx->query, (*offset)); +} + +static void core_agent_create_handler() +{ + +} + +static void core_agent_read_handler() +{ + +} + +static void core_agent_update_handler() +{ + +} + +static void core_agent_delete_handler() +{ + +} + +/** + * Checks the content of the message to see if this can be handled by this agent. + */ +static bool can_handle_request(qd_field_iterator_t *props, + qd_router_entity_type_t *entity_type, + qd_router_operation_type_t *operation_type, + int *count, + int *offset) +{ + qd_parsed_field_t *fld = qd_parse(props); + + // The must be a property field and that property field should be a AMQP map. This is true for QUERY but I need + // to check if it true for CREATE, UPDATE and DELETE + if (fld == 0 || !qd_parse_is_map(fld)) + return false; + + // + // Only certain entity types can be handled by this agent. + // 'entityType': 'org.apache.qpid.dispatch.router.address + // 'entityType': 'org.apache.qpid.dispatch.router.link' + // TODO - Add more entity types here. The above is not a complete list. + + qd_parsed_field_t *parsed_field = qd_parse_value_by_key(fld, entity_type_key); + + if (parsed_field == 0) + return false; + + if (qd_field_iterator_equal(qd_parse_raw(parsed_field), address_entity_type)) + (*entity_type) = QD_ROUTER_ADDRESS; + else if(qd_field_iterator_equal(qd_parse_raw(parsed_field), link_entity_type)) + (*entity_type) = QD_ROUTER_LINK; + else + return false; + + + parsed_field = qd_parse_value_by_key(fld, operation_type_key); + + if (parsed_field == 0) + return false; + + if (qd_field_iterator_equal(qd_parse_raw(parsed_field), MANAGEMENT_QUERY)) + (*operation_type) = QD_ROUTER_OPERATION_QUERY; + else if (qd_field_iterator_equal(qd_parse_raw(parsed_field), MANAGEMENT_CREATE)) + (*operation_type) = QD_ROUTER_OPERATION_CREATE; + else if (qd_field_iterator_equal(qd_parse_raw(parsed_field), MANAGEMENT_READ)) + (*operation_type) = QD_ROUTER_OPERATION_READ; + else if (qd_field_iterator_equal(qd_parse_raw(parsed_field), MANAGEMENT_UPDATE)) + (*operation_type) = QD_ROUTER_OPERATION_UPDATE; + else if (qd_field_iterator_equal(qd_parse_raw(parsed_field), MANAGEMENT_DELETE)) + (*operation_type) = QD_ROUTER_OPERATION_DELETE; + else + // This is an unknown operation type. cannot be handled, return false. + return false; + + // Obtain the count and offset. + parsed_field = qd_parse_value_by_key(fld, count_key); + if (parsed_field) + (*count) = qd_parse_as_int(parsed_field); + else + (*count) = -1; + + parsed_field = qd_parse_value_by_key(fld, offset_key); + if (parsed_field) + (*offset) = qd_parse_as_int(parsed_field); + else + (*offset) = 0; + + qd_parse_free(parsed_field); + + return true; +} + +/** + * + * Handler for the management agent. + * + */ +void management_agent_handler(void *context, qd_message_t *msg, int link_id) +{ + qd_dispatch_t *qd = (qd_dispatch_t*) context; + qd_field_iterator_t *iter = qd_message_field_iterator(msg, QD_FIELD_APPLICATION_PROPERTIES); + + qd_router_entity_type_t entity_type = 0; + qd_router_operation_type_t operation_type = 0; + + int32_t count = 0; + int32_t offset = 0; + + if (can_handle_request(iter, &entity_type, &operation_type, &count, &offset)) { + switch (operation_type) { + case QD_ROUTER_OPERATION_QUERY: + core_agent_query_handler(qd, entity_type, msg, &count, &offset); + break; + case QD_ROUTER_OPERATION_CREATE: + core_agent_create_handler(); + break; + case QD_ROUTER_OPERATION_READ: + core_agent_read_handler(); + break; + case QD_ROUTER_OPERATION_UPDATE: + core_agent_update_handler(); + break; + case QD_ROUTER_OPERATION_DELETE: + core_agent_delete_handler(); + break; + } + } + else + qd_router_send2(qd, MANAGEMENT_INTERNAL, msg); //the C management agent is not going to handle this request. Forward it off to Python. + // TODO - This is wrong. Need to find out how I can forward off the message to $management_internal so it can be handled by Python. + + qd_field_iterator_free(iter); + +} + diff --git a/src/router_core/management_agent_private.h b/src/router_core/management_agent_private.h new file mode 100644 index 0000000000..c321ca8308 --- /dev/null +++ b/src/router_core/management_agent_private.h @@ -0,0 +1,25 @@ +#ifndef qd_router_core_agent_private +#define qd_router_core_agent_private 1 + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +void management_agent_handler(void *context, qd_message_t *msg, int link_id); + +#endif diff --git a/src/router_node.c b/src/router_node.c index 677981721c..8057f2baef 100644 --- a/src/router_node.c +++ b/src/router_node.c @@ -27,10 +27,12 @@ #include "entity_cache.h" #include "router_private.h" #include "waypoint_private.h" +#include "router_core/management_agent_private.h" const char *QD_ROUTER_NODE_TYPE = "router.node"; const char *QD_ROUTER_ADDRESS_TYPE = "router.address"; const char *QD_ROUTER_LINK_TYPE = "router.link"; +const char *CORE_AGENT_ADDRESS = "$management"; static char *router_role = "inter-router"; static char *on_demand_role = "on-demand"; @@ -1870,6 +1872,10 @@ void qd_router_setup_late(qd_dispatch_t *qd) qd_router_python_setup(qd->router); qd->router->router_core = qdr_core(qd); qd_timer_schedule(qd->router->timer, 1000); + + //Register the C management agent + qd_router_register_address(qd, CORE_AGENT_ADDRESS, management_agent_handler, (void *) qd, QD_SEMANTICS_DEFAULT, true, 0/*forwarder*/); + qd_router_register_address(qd, CORE_AGENT_ADDRESS, management_agent_handler, (void *) qd, QD_SEMANTICS_DEFAULT, false, 0/*forwarder*/); } void qd_router_free(qd_router_t *router) @@ -1991,12 +1997,14 @@ void qd_router_send(qd_dispatch_t *qd, qd_field_iterator_t *address, qd_message_t *msg) { + qd_router_t *router = qd->router; qd_address_t *addr; qd_address_iterator_reset_view(address, ITER_VIEW_ADDRESS_HASH); sys_mutex_lock(router->lock); qd_hash_retrieve(router->addr_hash, address, (void*) &addr); + if (addr) { // // Forward to all of the local links receiving this address. diff --git a/src/server.c b/src/server.c index 623a587bc6..96703bc108 100644 --- a/src/server.c +++ b/src/server.c @@ -1403,6 +1403,7 @@ bool qd_user_fd_is_writeable(qd_user_fd_t *ufd) void qd_server_timer_pending_LH(qd_timer_t *timer) { DEQ_INSERT_TAIL(timer->server->pending_timers, timer); + qdpn_driver_wakeup(timer->server->driver); } From 8642a7be18f3f5e65284ac5162aa7dda53e07efa Mon Sep 17 00:00:00 2001 From: Ted Ross Date: Mon, 9 Nov 2015 12:25:44 -0500 Subject: [PATCH 19/22] DISPATCH-179 - Added missing DEQ initialization --- src/router_core/agent.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/router_core/agent.c b/src/router_core/agent.c index 9eabf6b213..39502839ad 100644 --- a/src/router_core/agent.c +++ b/src/router_core/agent.c @@ -90,6 +90,7 @@ qdr_query_t *qdr_manage_query(qdr_core_t *core, void *context, qd_router_entity_ { qdr_query_t *query = new_qdr_query_t(); + DEQ_ITEM_INIT(query); query->core = core; query->entity_type = type; query->context = context; From 511d31bf6445e591322d4b72a2c7204b90afbced Mon Sep 17 00:00:00 2001 From: Ted Ross Date: Mon, 9 Nov 2015 16:45:44 -0500 Subject: [PATCH 20/22] DISPATCH-193 - Updated the Container API with regard to connection lifecycle. --- include/qpid/dispatch/container.h | 11 ++-- include/qpid/dispatch/server.h | 9 ++++ src/container.c | 88 +++++++++++++++++++++---------- src/router_node.c | 14 +++-- src/server.c | 6 +++ 5 files changed, 92 insertions(+), 36 deletions(-) diff --git a/include/qpid/dispatch/container.h b/include/qpid/dispatch/container.h index f8faf9df99..c88f79660e 100644 --- a/include/qpid/dispatch/container.h +++ b/include/qpid/dispatch/container.h @@ -127,11 +127,14 @@ typedef struct { /** Invoked when an instance of the node type is destroyed. */ qd_container_node_handler_t node_destroyed_handler; - /** Invoked when an incoming connection (via listener) is established. */ - qd_container_conn_handler_t inbound_conn_open_handler; + /** Invoked when an incoming connection (via listener) is opened. */ + qd_container_conn_handler_t inbound_conn_opened_handler; - /** Invoked when an outgoing connection (via connector) is established. */ - qd_container_conn_handler_t outbound_conn_open_handler; + /** Invoked when an outgoing connection (via connector) is opened. */ + qd_container_conn_handler_t outbound_conn_opened_handler; + + /** Invoked when a connection is closed. */ + qd_container_conn_handler_t conn_closed_handler; } qd_node_type_t; diff --git a/include/qpid/dispatch/server.h b/include/qpid/dispatch/server.h index 3eca75c92d..2fb237d90c 100644 --- a/include/qpid/dispatch/server.h +++ b/include/qpid/dispatch/server.h @@ -487,6 +487,15 @@ void qd_server_activate(qd_connection_t *conn); pn_connection_t *qd_connection_pn(qd_connection_t *conn); +/** + * Get the direction of establishment for this connection. + * + * @param conn Connection object supplied in QD_CONN_EVENT_{LISTENER,CONNETOR}_OPEN + * @return true if connection came through a listener, false if through a connector. + */ +bool qd_connection_inbound(qd_connection_t *conn); + + /** * Get the event collector for a connection. * diff --git a/src/container.c b/src/container.c index 2be163d705..ace94e05bb 100644 --- a/src/container.c +++ b/src/container.c @@ -252,7 +252,62 @@ static void do_updated(pn_delivery_t *pnd) } -static int close_handler(void* unused, pn_connection_t *conn, qd_connection_t* qd_conn) +static void notify_opened(qd_container_t *container, qd_connection_t *conn, void *context) +{ + const qd_node_type_t *nt; + + // + // Note the locking structure in this function. Generally this would be unsafe, but since + // this particular list is only ever appended to and never has items inserted or deleted, + // this usage is safe in this case. + // + sys_mutex_lock(container->lock); + qdc_node_type_t *nt_item = DEQ_HEAD(container->node_type_list); + sys_mutex_unlock(container->lock); + + while (nt_item) { + nt = nt_item->ntype; + if (qd_connection_inbound(conn)) { + if (nt->inbound_conn_opened_handler) + nt->inbound_conn_opened_handler(nt->type_context, conn, context); + } else { + if (nt->outbound_conn_opened_handler) + nt->outbound_conn_opened_handler(nt->type_context, conn, context); + } + + sys_mutex_lock(container->lock); + nt_item = DEQ_NEXT(nt_item); + sys_mutex_unlock(container->lock); + } +} + + +static void notify_closed(qd_container_t *container, qd_connection_t *conn, void *context) +{ + const qd_node_type_t *nt; + + // + // Note the locking structure in this function. Generally this would be unsafe, but since + // this particular list is only ever appended to and never has items inserted or deleted, + // this usage is safe in this case. + // + sys_mutex_lock(container->lock); + qdc_node_type_t *nt_item = DEQ_HEAD(container->node_type_list); + sys_mutex_unlock(container->lock); + + while (nt_item) { + nt = nt_item->ntype; + if (nt->conn_closed_handler) + nt->conn_closed_handler(nt->type_context, conn, context); + + sys_mutex_lock(container->lock); + nt_item = DEQ_NEXT(nt_item); + sys_mutex_unlock(container->lock); + } +} + + +static int close_handler(qd_container_t *container, void* conn_context, pn_connection_t *conn, qd_connection_t* qd_conn) { qd_connection_manager_connection_closed(qd_conn); @@ -280,8 +335,9 @@ static int close_handler(void* unused, pn_connection_t *conn, qd_connection_t* q ssn = pn_session_next(ssn, 0); } - // teardown the connection + // close the connection pn_connection_close(conn); + notify_closed(container, qd_conn, conn_context); return 0; } @@ -323,6 +379,7 @@ int pn_event_handler(void *handler_context, void *conn_context, pn_event_t *even if (pn_connection_state(conn) & PN_LOCAL_UNINIT) pn_connection_open(conn); qd_connection_manager_connection_opened(qd_conn); + notify_opened(container, qd_conn, conn_context); break; case PN_CONNECTION_REMOTE_CLOSE : @@ -454,31 +511,6 @@ int pn_event_handler(void *handler_context, void *conn_context, pn_event_t *even static void open_handler(qd_container_t *container, qd_connection_t *conn, qd_direction_t dir, void *context) { - const qd_node_type_t *nt; - - // - // Note the locking structure in this function. Generally this would be unsafe, but since - // this particular list is only ever appended to and never has items inserted or deleted, - // this usage is safe in this case. - // - sys_mutex_lock(container->lock); - qdc_node_type_t *nt_item = DEQ_HEAD(container->node_type_list); - sys_mutex_unlock(container->lock); - - while (nt_item) { - nt = nt_item->ntype; - if (dir == QD_INCOMING) { - if (nt->inbound_conn_open_handler) - nt->inbound_conn_open_handler(nt->type_context, conn, context); - } else { - if (nt->outbound_conn_open_handler) - nt->outbound_conn_open_handler(nt->type_context, conn, context); - } - - sys_mutex_lock(container->lock); - nt_item = DEQ_NEXT(nt_item); - sys_mutex_unlock(container->lock); - } } @@ -490,7 +522,7 @@ static int handler(void *handler_context, void *conn_context, qd_conn_event_t ev switch (event) { case QD_CONN_EVENT_LISTENER_OPEN: open_handler(container, qd_conn, QD_INCOMING, conn_context); break; case QD_CONN_EVENT_CONNECTOR_OPEN: open_handler(container, qd_conn, QD_OUTGOING, conn_context); break; - case QD_CONN_EVENT_CLOSE: return close_handler(conn_context, conn, qd_conn); + case QD_CONN_EVENT_CLOSE: return close_handler(container, conn_context, conn, qd_conn); case QD_CONN_EVENT_WRITABLE: return writable_handler(conn_context, conn, qd_conn); } diff --git a/src/router_node.c b/src/router_node.c index 8057f2baef..639a9bf926 100644 --- a/src/router_node.c +++ b/src/router_node.c @@ -1663,12 +1663,12 @@ static int router_link_detach_handler(void* context, qd_link_t *link, qd_detach_ } -static void router_inbound_open_handler(void *type_context, qd_connection_t *conn, void *context) +static void router_inbound_opened_handler(void *type_context, qd_connection_t *conn, void *context) { } -static void router_outbound_open_handler(void *type_context, qd_connection_t *conn, void *context) +static void router_outbound_opened_handler(void *type_context, qd_connection_t *conn, void *context) { qd_router_t *router = (qd_router_t*) type_context; @@ -1753,6 +1753,11 @@ static void router_outbound_open_handler(void *type_context, qd_connection_t *co } +static void router_closed_handler(void *type_context, qd_connection_t *conn, void *context) +{ +} + + static void qd_router_timer_handler(void *context) { qd_router_t *router = (qd_router_t*) context; @@ -1776,8 +1781,9 @@ static qd_node_type_t router_node = {"router", 0, 0, router_link_flow_handler, 0, // node_created_handler 0, // node_destroyed_handler - router_inbound_open_handler, - router_outbound_open_handler }; + router_inbound_opened_handler, + router_outbound_opened_handler, + router_closed_handler}; static int type_registered = 0; diff --git a/src/server.c b/src/server.c index 96703bc108..b7303b2ac4 100644 --- a/src/server.c +++ b/src/server.c @@ -1222,6 +1222,12 @@ pn_connection_t *qd_connection_pn(qd_connection_t *conn) } +bool qd_connection_inbound(qd_connection_t *conn) +{ + return conn->listener != 0; +} + + pn_collector_t *qd_connection_collector(qd_connection_t *conn) { return conn->collector; From c50da0faf00ff9984de9118296895d987e45e89c Mon Sep 17 00:00:00 2001 From: Ted Ross Date: Mon, 9 Nov 2015 17:10:18 -0500 Subject: [PATCH 21/22] DISPATCH-179 - Hook the connection lifecycle into the router_node. --- src/router_node.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/router_node.c b/src/router_node.c index 639a9bf926..7d6635b53a 100644 --- a/src/router_node.c +++ b/src/router_node.c @@ -1665,12 +1665,19 @@ static int router_link_detach_handler(void* context, qd_link_t *link, qd_detach_ static void router_inbound_opened_handler(void *type_context, qd_connection_t *conn, void *context) { + qd_router_t *router = (qd_router_t*) type_context; + qdr_connection_t *qdrc = qdr_connection_opened(router->router_core, 0); // TODO - get label + qd_connection_set_context(conn, qdrc); + qdr_connection_set_context(qdrc, conn); } static void router_outbound_opened_handler(void *type_context, qd_connection_t *conn, void *context) { qd_router_t *router = (qd_router_t*) type_context; + qdr_connection_t *qdrc = qdr_connection_opened(router->router_core, 0); // TODO - get label + qd_connection_set_context(conn, qdrc); + qdr_connection_set_context(qdrc, conn); // // If the connection is on-demand, visit all waypoints that are waiting for their @@ -1755,6 +1762,9 @@ static void router_outbound_opened_handler(void *type_context, qd_connection_t * static void router_closed_handler(void *type_context, qd_connection_t *conn, void *context) { + qdr_connection_t *qdrc = (qdr_connection_t*) qd_connection_get_context(conn); + qdr_connection_closed(qdrc); + qd_connection_set_context(conn, 0); } From 41c6e23e31227ecf57a3678506071fc4fba5ce2a Mon Sep 17 00:00:00 2001 From: ganeshmurthy Date: Thu, 12 Nov 2015 13:01:19 -0500 Subject: [PATCH 22/22] DISPATCH-179 - Added code to display links when requested through a management link query (like qdstat -l) --- src/CMakeLists.txt | 1 + src/router_agent.c | 4 +- src/router_core/agent.c | 107 ++++++++++++++-- src/router_core/agent_address.c | 71 ----------- src/router_core/agent_address.h | 2 - src/router_core/agent_link.c | 194 +++++++++++++++++++++++++++++ src/router_core/agent_link.h | 27 ++++ src/router_core/management_agent.c | 1 + src/router_core/router_core.c | 1 - 9 files changed, 326 insertions(+), 82 deletions(-) create mode 100644 src/router_core/agent_link.c create mode 100644 src/router_core/agent_link.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a55b73b954..4dd221adbe 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -67,6 +67,7 @@ set(qpid_dispatch_SOURCES router_config.c router_core/agent.c router_core/agent_address.c + router_core/agent_link.c router_core/connections.c router_core/router_core.c router_core/router_core_thread.c diff --git a/src/router_agent.c b/src/router_agent.c index b9632e2a2f..2b006b95ca 100644 --- a/src/router_agent.c +++ b/src/router_agent.c @@ -74,6 +74,7 @@ qd_error_t qd_entity_refresh_router_address(qd_entity_t* entity, void *impl) { return qd_error_code(); } +/* static const char *qd_link_type_names[] = { "endpoint", "waypoint", "inter-router", "inter-area" }; ENUM_DEFINE(qd_link_type, qd_link_type_names); @@ -90,6 +91,7 @@ static const char* qd_router_link_name(qd_router_link_t* link) { return pn_link_name(qd_link_pn(link->link)); } +//TODO - Remove this function and the functions that it calls since this is not used anymore. qd_error_t qd_entity_refresh_router_link(qd_entity_t* entity, void *impl) { qd_router_link_t *link = (qd_router_link_t*) impl; @@ -104,7 +106,7 @@ qd_error_t qd_entity_refresh_router_link(qd_entity_t* entity, void *impl) return QD_ERROR_NONE; return qd_error_code(); } - +*/ void qd_router_build_node_list(qd_dispatch_t *qd, qd_composed_field_t *field) { qd_router_t *router = qd->router; diff --git a/src/router_core/agent.c b/src/router_core/agent.c index 39502839ad..d3a56cb50f 100644 --- a/src/router_core/agent.c +++ b/src/router_core/agent.c @@ -19,8 +19,45 @@ #include #include "agent_address.h" +#include "agent_link.h" +#include "router_core_private.h" #include + +static const char *qdr_address_columns[] = + {"name", + "identity", + "type", + "key", + "inProcess", + "subscriberCount", + "remoteCount", + "hostRouters", + "deliveriesIngress", + "deliveriesEgress", + "deliveriesTransit", + "deliveriesToContainer", + "deliveriesFromContainer", + 0}; + + +static const char *qdr_link_columns[] = + {"linkType", + "name", + "linkDir", + "msgFifoDepth", + "owningAddr", + "remoteContainer", + "linkName", + "eventFifoDepth", + "type", + "identity", + 0}; + +#define QDR_ADDRESS_COLUMN_COUNT 13 +#define QDR_LINK_COLUMN_COUNT 10 + + //================================================================================== // Internal Functions //================================================================================== @@ -64,8 +101,8 @@ void qdr_agent_enqueue_response_CT(qdr_core_t *core, qdr_query_t *query) static void qdrh_query_get_first_CT(qdr_core_t *core, qdr_action_t *action, bool discard); static void qdrh_query_get_next_CT(qdr_core_t *core, qdr_action_t *action, bool discard); - - +static void qdr_agent_emit_columns(qdr_query_t *query, const char *qdr_columns[], int column_count); +static void qdr_agent_set_columns(qdr_query_t *query, qd_parsed_field_t *attribute_names, const char *qdr_columns[], int column_count); //================================================================================== // Interface Functions //================================================================================== @@ -102,8 +139,8 @@ qdr_query_t *qdr_manage_query(qdr_core_t *core, void *context, qd_router_entity_ switch (query->entity_type) { case QD_ROUTER_CONNECTION: break; - case QD_ROUTER_LINK: break; - case QD_ROUTER_ADDRESS: qdra_address_set_columns(query, attribute_names);break; + case QD_ROUTER_LINK: qdr_agent_set_columns(query, attribute_names, qdr_link_columns, QDR_LINK_COLUMN_COUNT);break; + case QD_ROUTER_ADDRESS: qdr_agent_set_columns(query, attribute_names, qdr_address_columns, QDR_ADDRESS_COLUMN_COUNT);break; case QD_ROUTER_WAYPOINT: break; case QD_ROUTER_EXCHANGE: break; case QD_ROUTER_BINDING: break; @@ -117,8 +154,8 @@ void qdr_query_add_attribute_names(qdr_query_t *query) { switch (query->entity_type) { case QD_ROUTER_CONNECTION: break; - case QD_ROUTER_LINK: break; - case QD_ROUTER_ADDRESS: qdra_address_emit_columns(query); break; + case QD_ROUTER_LINK: qdr_agent_emit_columns(query, qdr_link_columns, QDR_LINK_COLUMN_COUNT);break; + case QD_ROUTER_ADDRESS: qdr_agent_emit_columns(query, qdr_address_columns, QDR_ADDRESS_COLUMN_COUNT); break; case QD_ROUTER_WAYPOINT: break; case QD_ROUTER_EXCHANGE: break; case QD_ROUTER_BINDING: break; @@ -147,6 +184,62 @@ void qdr_query_free(qdr_query_t *query) { } +static void qdr_agent_emit_columns(qdr_query_t *query, const char *qdr_columns[], int column_count) +{ + qd_compose_start_list(query->body); + int i = 0; + while (query->columns[i] >= 0) { + assert(query->columns[i] < column_count); + qd_compose_insert_string(query->body, qdr_columns[query->columns[i]]); + i++; + } + qd_compose_end_list(query->body); +} + +static void qdr_agent_set_columns(qdr_query_t *query, + qd_parsed_field_t *attribute_names, + const char *qdr_columns[], + int column_count) +{ + if (!attribute_names || + (qd_parse_tag(attribute_names) != QD_AMQP_LIST8 && + qd_parse_tag(attribute_names) != QD_AMQP_LIST32) || + qd_parse_sub_count(attribute_names) == 0) { + // + // Either the attribute_names field is absent, it's not a list, or it's an empty list. + // In this case, we will include all available attributes. + // + int i; + for (i = 0; i < column_count; i++) + query->columns[i] = i; + query->columns[i] = -1; + return; + } + + // + // We have a valid, non-empty attribute list. Set the columns appropriately. + // + uint32_t count = qd_parse_sub_count(attribute_names); + uint32_t idx; + + for (idx = 0; idx < count; idx++) { + qd_parsed_field_t *name = qd_parse_sub_value(attribute_names, idx); + if (!name || (qd_parse_tag(name) != QD_AMQP_STR8_UTF8 && qd_parse_tag(name) != QD_AMQP_STR32_UTF8)) + query->columns[idx] = QDR_AGENT_COLUMN_NULL; + else { + int j = 0; + while (qdr_columns[j]) { + qd_field_iterator_t *iter = qd_parse_raw(name); + if (qd_field_iterator_equal(iter, (const unsigned char*) qdr_columns[j])) { + query->columns[idx] = j; + break; + } + } + } + } +} + + void qdr_manage_handler(qdr_core_t *core, qdr_manage_response_t response_handler) { @@ -174,7 +267,7 @@ static void qdrh_query_get_first_CT(qdr_core_t *core, qdr_action_t *action, bool if (!discard) switch (query->entity_type) { case QD_ROUTER_CONNECTION: break; - case QD_ROUTER_LINK: break; + case QD_ROUTER_LINK: qdrl_link_get_first_CT(core, query, offset); break; case QD_ROUTER_ADDRESS: qdra_address_get_first_CT(core, query, offset); break; case QD_ROUTER_WAYPOINT: break; case QD_ROUTER_EXCHANGE: break; diff --git a/src/router_core/agent_address.c b/src/router_core/agent_address.c index 88a60f72ca..08af140158 100644 --- a/src/router_core/agent_address.c +++ b/src/router_core/agent_address.c @@ -19,22 +19,6 @@ #include "agent_address.h" -static const char *qdr_address_columns[] = - {"name", - "identity", - "type", - "key", - "inProcess", - "subscriberCount", - "remoteCount", - "hostRouters", - "deliveriesIngress", - "deliveriesEgress", - "deliveriesTransit", - "deliveriesToContainer", - "deliveriesFromContainer", - 0}; - #define QDR_ADDRESS_NAME 0 #define QDR_ADDRESS_IDENTITY 1 #define QDR_ADDRESS_TYPE 2 @@ -48,7 +32,6 @@ static const char *qdr_address_columns[] = #define QDR_ADDRESS_DELIVERIES_TRANSIT 10 #define QDR_ADDRESS_DELIVERIES_TO_CONTAINER 11 #define QDR_ADDRESS_DELIVERIES_FROM_CONTAINER 12 -#define QDR_ADDRESS_COLUMN_COUNT 13 static void qdr_manage_write_address_CT(qdr_query_t *query, qdr_address_t *addr) { @@ -129,60 +112,6 @@ static void qdr_manage_advance_address_CT(qdr_query_t *query, qdr_address_t *add } -void qdra_address_set_columns(qdr_query_t *query, qd_parsed_field_t *attribute_names) -{ - if (!attribute_names || - (qd_parse_tag(attribute_names) != QD_AMQP_LIST8 && - qd_parse_tag(attribute_names) != QD_AMQP_LIST32) || - qd_parse_sub_count(attribute_names) == 0) { - // - // Either the attribute_names field is absent, it's not a list, or it's an empty list. - // In this case, we will include all available attributes. - // - int i; - for (i = 0; i < QDR_ADDRESS_COLUMN_COUNT; i++) - query->columns[i] = i; - query->columns[i] = -1; - return; - } - - // - // We have a valid, non-empty attribute list. Set the columns appropriately. - // - uint32_t count = qd_parse_sub_count(attribute_names); - uint32_t idx; - - for (idx = 0; idx < count; idx++) { - qd_parsed_field_t *name = qd_parse_sub_value(attribute_names, idx); - if (!name || (qd_parse_tag(name) != QD_AMQP_STR8_UTF8 && qd_parse_tag(name) != QD_AMQP_STR32_UTF8)) - query->columns[idx] = QDR_AGENT_COLUMN_NULL; - else { - int j = 0; - while (qdr_address_columns[j]) { - qd_field_iterator_t *iter = qd_parse_raw(name); - if (qd_field_iterator_equal(iter, (const unsigned char*) qdr_address_columns[j])) { - query->columns[idx] = j; - break; - } - } - } - } -} - - -void qdra_address_emit_columns(qdr_query_t *query) -{ - qd_compose_start_list(query->body); - int i = 0; - while (query->columns[i] >= 0) { - assert(query->columns[i] < QDR_ADDRESS_COLUMN_COUNT); - qd_compose_insert_string(query->body, qdr_address_columns[query->columns[i]]); - i++; - } - qd_compose_end_list(query->body); -} - - void qdra_address_get_first_CT(qdr_core_t *core, qdr_query_t *query, int offset) { // diff --git a/src/router_core/agent_address.h b/src/router_core/agent_address.h index 53d383adfa..753c37d3c0 100644 --- a/src/router_core/agent_address.h +++ b/src/router_core/agent_address.h @@ -21,8 +21,6 @@ #include "router_core_private.h" -void qdra_address_set_columns(qdr_query_t *query, qd_parsed_field_t *attribute_names); -void qdra_address_emit_columns(qdr_query_t *query); void qdra_address_get_first_CT(qdr_core_t *core, qdr_query_t *query, int offset); void qdra_address_get_next_CT(qdr_core_t *core, qdr_query_t *query); diff --git a/src/router_core/agent_link.c b/src/router_core/agent_link.c new file mode 100644 index 0000000000..0cced7bcc2 --- /dev/null +++ b/src/router_core/agent_link.c @@ -0,0 +1,194 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "agent_link.h" + +#define QDR_LINK_LINK_TYPE 0 +#define QDR_LINK_LINK_NAME 1 +#define QDR_LINK_LINK_DIR 2 //done +#define QDR_LINK_MSG_FIFO_DEPTH 3 //done +#define QDR_LINK_OWNING_ADDR 4 //done +#define QDR_LINK_REMOTE_CONTAINER 5 +#define QDR_LINK_NAME 6 +#define QDR_LINK_EVENT_FIFO_DEPTH 7 //done +#define QDR_LINK_TYPE 8 +#define QDR_LINK_IDENTITY 9 + +static const char *qd_link_type_names[] = { "endpoint", "waypoint", "inter-router", "inter-area" }; +ENUM_DEFINE(qd_link_type, qd_link_type_names); + +static const char *address_key(qdr_address_t *addr) { + return addr && addr->hash_handle ? (const char*) qd_hash_key_by_handle(addr->hash_handle) : NULL; +} + +static const char* qd_router_link_remote_container(qdr_link_t *link) { + if (!link->link || !qd_link_pn(link->link)) + return ""; + return pn_connection_remote_container( + pn_session_connection(qd_link_pn_session(link->link))); +} + +static const char* qd_router_link_name(qdr_link_t *link) { + if (!link->link || !qd_link_pn(link->link)) + return ""; + return pn_link_name(qd_link_pn(link->link)); +} + +static void qdr_agent_write_link_CT(qdr_query_t *query, qdr_link_t *link ) +{ + qd_composed_field_t *body = query->body; + + qd_compose_start_list(body); + int i = 0; + while (query->columns[i] >= 0) { + switch(query->columns[i]) { + case QDR_LINK_IDENTITY: + case QDR_LINK_NAME: + // TODO - This needs to be fixed (use connection_id + link_name) + qd_compose_insert_string(body, "fix-me-hardcoded-for-now" ); + break; + case QDR_LINK_TYPE: + qd_compose_insert_string(body, "org.apache.qpid.dispatch.router.link"); + break; + + case QDR_LINK_REMOTE_CONTAINER: + qd_compose_insert_string(body, qd_router_link_remote_container(link)); + break; + + case QDR_LINK_LINK_NAME: + qd_compose_insert_string(body, qd_router_link_name(link)); + break; + + case QDR_LINK_LINK_TYPE: + qd_compose_insert_string(body, qd_link_type_name(link->link_type)); + break; + + case QDR_LINK_OWNING_ADDR: + qd_compose_insert_string(body, address_key(link->owning_addr)); + break; + + case QDR_LINK_LINK_DIR: + qd_compose_insert_string(body, link->link_direction == QD_INCOMING ? "in" : "out"); + break; + + case QDR_LINK_MSG_FIFO_DEPTH: + qd_compose_insert_ulong(body, DEQ_SIZE(link->msg_fifo)); + break; + + case QDR_LINK_EVENT_FIFO_DEPTH: + qd_compose_insert_ulong(body, DEQ_SIZE(link->event_fifo)); + break; + + default: + qd_compose_insert_null(body); + break; + } + i++; + } + qd_compose_end_list(body); +} + +static void qdr_manage_advance_link_CT(qdr_query_t *query, qdr_link_t *link) +{ + query->next_offset++; + link = DEQ_NEXT(link); + if (link) + query->more = true; + //query->next_key = qdr_field((const char*) qd_hash_key_by_handle(link->owning_addr->hash_handle)); + else + query->more = false; +} + + +void qdrl_link_get_first_CT(qdr_core_t *core, qdr_query_t *query, int offset) +{ + // + // Queries that get this far will always succeed. + // + query->status = &QD_AMQP_OK; + + // + // If the offset goes beyond the set of links, end the query now. + // + if (offset >= DEQ_SIZE(core->links)) { + query->more = false; + qdr_agent_enqueue_response_CT(core, query); + return; + } + + // + // Run to the address at the offset. + // + qdr_link_t *link = DEQ_HEAD(core->links); + for (int i = 0; i < offset && link; i++) + link = DEQ_NEXT(link); + assert(link); + + // + // Write the columns of the link into the response body. + // + qdr_agent_write_link_CT(query, link); + + // + // Advance to the next address + // + query->next_offset = offset; + qdr_manage_advance_link_CT(query, link); + + // + // Enqueue the response. + // + qdr_agent_enqueue_response_CT(core, query); +} + + +void qdrl_link_get_next_CT(qdr_core_t *core, qdr_query_t *query) +{ + qdr_link_t *link = 0; + + if (!link) { + // + // If the address was removed in the time between this get and the previous one, + // we need to use the saved offset, which is less efficient. + // + if (query->next_offset < DEQ_SIZE(core->links)) { + link = DEQ_HEAD(core->links); + for (int i = 0; i < query->next_offset && link; i++) + link = DEQ_NEXT(link); + } + } + + if (link) { + // + // Write the columns of the link entity into the response body. + // + qdr_agent_write_link_CT(query, link); + + // + // Advance to the next link + // + qdr_manage_advance_link_CT(query, link); + } else + query->more = false; + + // + // Enqueue the response. + // + qdr_agent_enqueue_response_CT(core, query); +} diff --git a/src/router_core/agent_link.h b/src/router_core/agent_link.h new file mode 100644 index 0000000000..aaafa069f0 --- /dev/null +++ b/src/router_core/agent_link.h @@ -0,0 +1,27 @@ +#ifndef qdr_agent_link +#define qdr_agent_link 1 +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "router_core_private.h" + +void qdrl_link_get_first_CT(qdr_core_t *core, qdr_query_t *query, int offset); +void qdrl_link_get_next_CT(qdr_core_t *core, qdr_query_t *query); + +#endif diff --git a/src/router_core/management_agent.c b/src/router_core/management_agent.c index 848ca6659f..2d93cb5dda 100644 --- a/src/router_core/management_agent.c +++ b/src/router_core/management_agent.c @@ -199,6 +199,7 @@ static void core_agent_query_handler(qd_dispatch_t *qd, // Set the callback function. qdr_manage_handler(core, manage_response_handler); + // Local local function that creates and returns a qd_management_context_t qd_management_context_t *ctx = qd_management_context(message, field, 0, reply_to, qd, (*count)); ctx->query = qdr_manage_query(core, ctx, entity_type, attribute_names_parsed_field, field); diff --git a/src/router_core/router_core.c b/src/router_core/router_core.c index b7f24e307f..a747572cca 100644 --- a/src/router_core/router_core.c +++ b/src/router_core/router_core.c @@ -210,4 +210,3 @@ void qdr_del_node_ref(qdr_router_ref_list_t *ref_list, qdr_node_t *rnode) ref = DEQ_NEXT(ref); } } -