]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/helper.h
Source Format Enforcement (#763)
[thirdparty/squid.git] / src / helper.h
index 04e79cde9bf9ac0bab5cc9b1e67ee239f1051037..1233dff7a79756d79cbcfed8850a2f28d4babff7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
  *
  * Squid software is distributed under GPLv2+ license and includes
  * contributions from numerous individuals and organizations.
 #include "helper/forward.h"
 #include "helper/Reply.h"
 #include "helper/Request.h"
+#include "helper/ReservationId.h"
 #include "ip/Address.h"
 #include "sbuf/SBuf.h"
 
 #include <list>
 #include <map>
 #include <queue>
+#include <unordered_map>
 
 class Packable;
 class wordlist;
@@ -42,6 +44,7 @@ public:
 };
 }
 
+class HelperServerBase;
 /**
  * Managers a set of individual helper processes with a common queue of requests.
  *
@@ -49,13 +52,13 @@ public:
  *   idle:   no processes are working on requests (and no requests are queued);
  *   normal: some, but not all processes are working (and no requests are queued);
  *   busy:   all processes are working (and some requests are possibly queued);
- *   full:   all processes are working and at least 2*#processes requests are queued.
+ *   overloaded: a busy helper with more than queue-size requests in the queue.
  *
- * A "busy" helper queues new requests and issues a WARNING every 10 minutes or so.
- * A "full" helper either drops new requests or keeps queuing them, depending on
+ * A busy helper queues new requests and issues a WARNING every 10 minutes or so.
+ * An overloaded helper either drops new requests or keeps queuing them, depending on
  *   whether the caller can handle dropped requests (trySubmit vs helperSubmit APIs).
- * An attempt to use a "full" helper that has been "full" for 3+ minutes kills worker.
- *   Given enough load, all helpers except for external ACL will make such attempts.
+ * If an overloaded helper has been overloaded for 3+ minutes, an attempt to use
+ *   it results in on-persistent-overload action, which may kill worker.
  */
 class helper
 {
@@ -66,7 +69,8 @@ public:
         cmdline(NULL),
         id_name(name),
         ipc_type(0),
-        full_time(0),
+        droppedRequests(0),
+        overloadStart(0),
         last_queue_warn(0),
         last_restart(0),
         timeout(0),
@@ -77,13 +81,10 @@ public:
     }
     ~helper();
 
-    /// whether at least one more request can be successfully submitted
-    bool queueFull() const;
-
     /// \returns next request in the queue, or nil.
     Helper::Xaction *nextRequest();
 
-    ///< If not full, submit request. Otherwise, either kill Squid or return false.
+    /// If possible, submit request. Otherwise, either kill Squid or return false.
     bool trySubmit(const char *buf, HLPCB * callback, void *data);
 
     /// Submits a request to the helper or add it to the queue if none of
@@ -92,6 +93,14 @@ public:
 
     /// Dump some stats about the helper state to a Packable object
     void packStatsInto(Packable *p, const char *label = NULL) const;
+    /// whether the helper will be in "overloaded" state after one more request
+    /// already overloaded helpers return true
+    bool willOverload() const;
+
+    /// Updates interall statistics and start new helper server processes after
+    /// an unexpected server exit
+    /// \param needsNewServers true if new servers must started, false otherwise
+    void handleKilledServer(HelperServerBase *srv, bool &needsNewServers);
 
 public:
     wordlist *cmdline;
@@ -101,7 +110,8 @@ public:
     Helper::ChildConfig childs;    ///< Configuration settings for number running.
     int ipc_type;
     Ip::Address addr;
-    time_t full_time; ///< when a full helper became full (zero for non-full helpers)
+    unsigned int droppedRequests; ///< requests not sent during helper overload
+    time_t overloadStart; ///< when the helper became overloaded (zero if it is not)
     time_t last_queue_warn;
     time_t last_restart;
     time_t timeout; ///< Requests timeout
@@ -120,7 +130,10 @@ public:
 
 protected:
     friend void helperSubmit(helper * hlp, const char *buf, HLPCB * callback, void *data);
-    void prepSubmit();
+    bool queueFull() const;
+    bool overloaded() const;
+    void syncQueueStats();
+    bool prepSubmit();
     void submit(const char *buf, HLPCB * callback, void *data);
 };
 
@@ -129,23 +142,36 @@ class statefulhelper : public helper
     CBDATA_CLASS(statefulhelper);
 
 public:
-    inline statefulhelper(const char *name) : helper(name), datapool(NULL) {}
+    typedef std::unordered_map<Helper::ReservationId, helper_stateful_server *> Reservations;
+
+    inline statefulhelper(const char *name) : helper(name) {}
     inline ~statefulhelper() {}
 
 public:
-    MemAllocator *datapool;
+    /// reserve the given server
+    void reserveServer(helper_stateful_server * srv);
+
+    /// undo reserveServer(), clear the reservation and kick the queue
+    void cancelReservation(const Helper::ReservationId reservation);
 
 private:
-    friend void helperStatefulSubmit(statefulhelper * hlp, const char *buf, HLPCB * callback, void *data, helper_stateful_server * lastserver);
-    void submit(const char *buf, HLPCB * callback, void *data, helper_stateful_server *lastserver);
+    friend void helperStatefulSubmit(statefulhelper * hlp, const char *buf, HLPCB * callback, void *data, const Helper::ReservationId & reservation);
+
+    /// \return the previously reserved server (if the reservation is still valid) or nil
+    helper_stateful_server *findServer(const Helper::ReservationId & reservation);
+
+    void submit(const char *buf, HLPCB * callback, void *data, const Helper::ReservationId & reservation);
+    bool trySubmit(const char *buf, HLPCB * callback, void *data, const Helper::ReservationId & reservation);
+
+    ///< reserved servers indexed by reservation IDs
+    Reservations reservations;
 };
 
-/**
- * Fields shared between stateless and stateful helper servers.
- */
-class HelperServerBase
+/// represents a single helper process abstraction
+class HelperServerBase: public CbdataParent
 {
 public:
+    virtual ~HelperServerBase();
     /** Closes pipes to the helper safely.
      * Handles the case where the read and write pipes are the same FD.
      *
@@ -161,6 +187,16 @@ public:
      */
     void closeWritePipeSafely(const char *name);
 
+    // TODO: Teach each child to report its child-specific state instead.
+    /// whether the server is locked for exclusive use by a client
+    virtual bool reserved() = 0;
+
+    /// dequeues and sends a Helper::Unknown answer to all queued requests
+    virtual void dropQueued();
+
+    /// the helper object that created this server
+    virtual helper *getParent() const = 0;
+
 public:
     /// Helper program identifier; does not change when contents do,
     ///   including during assignment
@@ -184,7 +220,6 @@ public:
         bool writing;
         bool closing;
         bool shutdown;
-        bool reserved;
     } flags;
 
     typedef std::list<Helper::Xaction *> Requests;
@@ -203,9 +238,11 @@ public:
 class MemBuf;
 class CommTimeoutCbParams;
 
+// TODO: Rename to StatelessHelperServer and rename HelperServerBase to HelperServer.
+/// represents a single "stateless helper" process
 class helper_server : public HelperServerBase
 {
-    CBDATA_CLASS(helper_server);
+    CBDATA_CHILD(helper_server);
 
 public:
     uint64_t nextRequestId;
@@ -228,6 +265,7 @@ public:
     typedef std::map<uint64_t, Requests::iterator> RequestIndex;
     RequestIndex requestsIndex; ///< maps request IDs to requests
 
+    virtual ~helper_server();
     /// Search in queue for the request with requestId, return the related
     /// Xaction object and remove it from queue.
     /// If concurrency is disabled then the requestId is ignored and the
@@ -238,32 +276,53 @@ public:
     /// or the configured "on timeout response" for timedout requests.
     void checkForTimedOutRequests(bool const retry);
 
+    /*HelperServerBase API*/
+    virtual bool reserved() override {return false;}
+    virtual void dropQueued() override;
+    virtual helper *getParent() const override {return parent;}
+
     /// Read timeout handler
     static void requestTimeout(const CommTimeoutCbParams &io);
+
+    /// close handler to handle exited server processes
+    static void HelperServerClosed(helper_server *srv);
 };
 
+// TODO: Rename to StatefulHelperServer and rename HelperServerBase to HelperServer.
+/// represents a single "stateful helper" process
 class helper_stateful_server : public HelperServerBase
 {
-    CBDATA_CLASS(helper_stateful_server);
+    CBDATA_CHILD(helper_stateful_server);
 
 public:
-    /* MemBuf wqueue; */
-    /* MemBuf writebuf; */
+    virtual ~helper_stateful_server();
+    void reserve();
+    void clearReservation();
+
+    /* HelperServerBase API */
+    virtual bool reserved() override {return reservationId.reserved();}
+    virtual helper *getParent() const override {return parent;}
+
+    /// close handler to handle exited server processes
+    static void HelperServerClosed(helper_stateful_server *srv);
 
     statefulhelper *parent;
 
-    void *data;         /* State data used by the calling routines */
+    // Reservations temporary lock the server for an exclusive "client" use. The
+    // client keeps the reservation ID as a proof of her reservation. If a
+    // reservation expires, and the server is reserved for another client, then
+    // the reservation ID presented by the late client will not match ours.
+    Helper::ReservationId reservationId; ///< "confirmation ID" of the last
+    time_t reservationStart; ///< when the last `reservation` was made
 };
 
 /* helper.c */
 void helperOpenServers(helper * hlp);
 void helperStatefulOpenServers(statefulhelper * hlp);
 void helperSubmit(helper * hlp, const char *buf, HLPCB * callback, void *data);
-void helperStatefulSubmit(statefulhelper * hlp, const char *buf, HLPCB * callback, void *data, helper_stateful_server * lastserver);
+void helperStatefulSubmit(statefulhelper * hlp, const char *buf, HLPCB * callback, void *data, uint64_t reservation);
 void helperShutdown(helper * hlp);
 void helperStatefulShutdown(statefulhelper * hlp);
-void helperStatefulReleaseServer(helper_stateful_server * srv);
-void *helperStatefulServerGetData(helper_stateful_server * srv);
 
 #endif /* SQUID_HELPER_H */