From 1507f56c8d52496562390e4a621891f1e457889f Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Tue, 3 Jul 2018 10:08:28 +0100 Subject: [PATCH] control: add command for removing dependencies. --- src/control.cc | 66 ++++++++++++++++++++++++++++++++++++++---- src/includes/control.h | 2 ++ src/includes/service.h | 20 +++++++++++++ 3 files changed, 82 insertions(+), 6 deletions(-) diff --git a/src/control.cc b/src/control.cc index 39a26f2..dfb9a1d 100644 --- a/src/control.cc +++ b/src/control.cc @@ -72,13 +72,15 @@ bool control_conn_t::process_packet() if (pktType == DINIT_CP_ADD_DEP) { return add_service_dep(); } - else { - // Unrecognized: give error response - char outbuf[] = { DINIT_RP_BADREQ }; - if (! queue_packet(outbuf, 1)) return false; - bad_conn_close = true; - iob.set_watches(OUT_EVENTS); + if (pktType == DINIT_CP_REM_DEP) { + return rm_service_dep(); } + + // Unrecognized: give error response + char outbuf[] = { DINIT_RP_BADREQ }; + if (! queue_packet(outbuf, 1)) return false; + bad_conn_close = true; + iob.set_watches(OUT_EVENTS); return true; } @@ -487,6 +489,58 @@ bool control_conn_t::add_service_dep() return true; } +bool control_conn_t::rm_service_dep() +{ + // 1 byte packet type + // 1 byte dependency type + // handle: "from" + // handle: "to" + + constexpr int pkt_size = 2 + sizeof(handle_t) * 2; + + if (rbuf.get_length() < pkt_size) { + chklen = pkt_size; + return true; + } + + handle_t from_handle; + handle_t to_handle; + rbuf.extract((char *) &from_handle, 2, sizeof(from_handle)); + rbuf.extract((char *) &to_handle, 2 + sizeof(from_handle), sizeof(to_handle)); + + service_record *from_service = find_service_for_key(from_handle); + service_record *to_service = find_service_for_key(to_handle); + if (from_service == nullptr || to_service == nullptr || from_service == to_service) { + // Service handle is bad + char badreq_rep[] = { DINIT_RP_BADREQ }; + if (! queue_packet(badreq_rep, 1)) return false; + bad_conn_close = true; + iob.set_watches(OUT_EVENTS); + return true; + } + + // Check dependency type is valid: + int dep_type_int = rbuf[1]; + if (! contains({(int)dependency_type::MILESTONE, (int)dependency_type::REGULAR, + (int)dependency_type::WAITS_FOR}, dep_type_int)) { + char badreqRep[] = { DINIT_RP_BADREQ }; + if (! queue_packet(badreqRep, 1)) return false; + bad_conn_close = true; + iob.set_watches(OUT_EVENTS); + } + dependency_type dep_type = static_cast(dep_type_int); + + // Remove dependency: + from_service->rm_dep(to_service, dep_type); + services->process_queues(); + + char ack_rep[] = { DINIT_RP_ACK }; + if (! queue_packet(ack_rep, 1)) return false; + rbuf.consume(pkt_size); + chklen = 0; + return true; +} + control_conn_t::handle_t control_conn_t::allocate_service_handle(service_record *record) { // Try to find a unique handle (integer) in a single pass. Since the map is ordered, we can search until diff --git a/src/includes/control.h b/src/includes/control.h index e1cfd5c..be24864 100644 --- a/src/includes/control.h +++ b/src/includes/control.h @@ -148,6 +148,8 @@ class control_conn_t : private service_listener bool add_service_dep(); + bool rm_service_dep(); + // Notify that data is ready to be read from the socket. Returns true if the connection should // be closed. bool data_ready() noexcept; diff --git a/src/includes/service.h b/src/includes/service.h index 4c3c982..53f4ba2 100644 --- a/src/includes/service.h +++ b/src/includes/service.h @@ -680,6 +680,26 @@ class service_record } } } + + // Remove a dependency, of the given type, to the given service. Propagation queues should be processed + // after calling. + void rm_dep(service_record *to, dependency_type dep_type) noexcept + { + for (auto i = depends_on.begin(); i != depends_on.end(); i++) { + auto & dep = *i; + if (dep.get_to() == to && dep.dep_type == dep_type) { + for (auto j = to->dependents.begin(); ; j++) { + if (*j == &dep) { + dependents.erase(j); + break; + } + } + depends_on.erase(i); + to->release(); + break; + } + } + } }; inline auto extract_prop_queue(service_record *sr) -> decltype(sr->prop_queue_node) & -- 2.25.1