소스 검색

control: add command for removing dependencies.

Davin McCall 5 년 전
부모
커밋
1507f56c8d
3개의 변경된 파일82개의 추가작업 그리고 6개의 파일을 삭제
  1. 60 6
      src/control.cc
  2. 2 0
      src/includes/control.h
  3. 20 0
      src/includes/service.h

+ 60 - 6
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<dependency_type>(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

+ 2 - 0
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;

+ 20 - 0
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) &