]>
| Commit | Line | Data |
|---|---|---|
| 51ee7c82 | 1 | /* |
| 1f7b830e | 2 | * Copyright (C) 1996-2025 The Squid Software Foundation and contributors |
| 51ee7c82 | 3 | * |
| bbc27441 AJ |
4 | * Squid software is distributed under GPLv2+ license and includes |
| 5 | * contributions from numerous individuals and organizations. | |
| 6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
| 51ee7c82 | 7 | */ |
| 8 | ||
| bbc27441 AJ |
9 | /* DEBUG: section 84 Helper process maintenance */ |
| 10 | ||
| ff9d9458 FC |
11 | #ifndef SQUID_SRC_HELPER_H |
| 12 | #define SQUID_SRC_HELPER_H | |
| 51ee7c82 | 13 | |
| 37dedc58 | 14 | #include "base/AsyncCall.h" |
| e237d339 | 15 | #include "base/InstanceId.h" |
| 3bd118d6 | 16 | #include "base/RefCount.h" |
| aa839030 | 17 | #include "cbdata.h" |
| e0d28505 | 18 | #include "comm/forward.h" |
| 582c2af2 | 19 | #include "dlink.h" |
| 76d9b994 | 20 | #include "helper/ChildConfig.h" |
| 24438ec5 | 21 | #include "helper/forward.h" |
| ddc77a2e | 22 | #include "helper/Reply.h" |
| c8f9dea2 | 23 | #include "helper/Request.h" |
| a56fcf0b | 24 | #include "helper/ReservationId.h" |
| 602d9612 | 25 | #include "ip/Address.h" |
| 65e41a45 | 26 | #include "sbuf/SBuf.h" |
| 32fd6d8a CT |
27 | |
| 28 | #include <list> | |
| a8067a2e | 29 | #include <map> |
| 6215dc18 | 30 | #include <queue> |
| a8067a2e | 31 | #include <unordered_map> |
| aa839030 | 32 | |
| e05a9d51 EB |
33 | class CommTimeoutCbParams; |
| 34 | class MemBuf; | |
| bf3e8d5a | 35 | class Packable; |
| 541b581e | 36 | class wordlist; |
| bf3e8d5a | 37 | |
| ddc77a2e CT |
38 | namespace Helper |
| 39 | { | |
| 40 | /// Holds the required data to serve a helper request. | |
| 41 | class Xaction { | |
| 42 | MEMPROXY_CLASS(Helper::Xaction); | |
| 43 | public: | |
| 44 | Xaction(HLPCB *c, void *d, const char *b): request(c, d, b) {} | |
| 45 | Helper::Request request; | |
| 46 | Helper::Reply reply; | |
| 47 | }; | |
| ddc77a2e | 48 | |
| e05a9d51 EB |
49 | class SessionBase; |
| 50 | ||
| 6825b101 CT |
51 | /** |
| 52 | * Managers a set of individual helper processes with a common queue of requests. | |
| 53 | * | |
| 54 | * With respect to load, a helper goes through these states (roughly): | |
| 55 | * idle: no processes are working on requests (and no requests are queued); | |
| 56 | * normal: some, but not all processes are working (and no requests are queued); | |
| 57 | * busy: all processes are working (and some requests are possibly queued); | |
| 6082a0e2 | 58 | * overloaded: a busy helper with more than queue-size requests in the queue. |
| 6825b101 | 59 | * |
| 6082a0e2 EB |
60 | * A busy helper queues new requests and issues a WARNING every 10 minutes or so. |
| 61 | * An overloaded helper either drops new requests or keeps queuing them, depending on | |
| 6825b101 | 62 | * whether the caller can handle dropped requests (trySubmit vs helperSubmit APIs). |
| 6082a0e2 EB |
63 | * If an overloaded helper has been overloaded for 3+ minutes, an attempt to use |
| 64 | * it results in on-persistent-overload action, which may kill worker. | |
| 6825b101 | 65 | */ |
| e05a9d51 | 66 | class Client: public RefCountable |
| 10044c9b | 67 | { |
| 48d54e4d | 68 | public: |
| e05a9d51 | 69 | using Pointer = RefCount<Client>; |
| 3bd118d6 | 70 | |
| e05a9d51 | 71 | /// \returns a newly created instance of the named helper client |
| 91ce75c9 | 72 | /// \param name admin-visible helper category (with this process lifetime) |
| 3bd118d6 EB |
73 | static Pointer Make(const char *name); |
| 74 | ||
| e05a9d51 | 75 | virtual ~Client(); |
| 48d54e4d | 76 | |
| 6215dc18 | 77 | /// \returns next request in the queue, or nil. |
| e05a9d51 | 78 | Xaction *nextRequest(); |
| 6215dc18 | 79 | |
| 6082a0e2 | 80 | /// If possible, submit request. Otherwise, either kill Squid or return false. |
| 6825b101 CT |
81 | bool trySubmit(const char *buf, HLPCB * callback, void *data); |
| 82 | ||
| f53969cc | 83 | /// Submits a request to the helper or add it to the queue if none of |
| 32fd6d8a | 84 | /// the servers is available. |
| e05a9d51 | 85 | void submitRequest(Xaction *); |
| bf3e8d5a AJ |
86 | |
| 87 | /// Dump some stats about the helper state to a Packable object | |
| aee3523a | 88 | void packStatsInto(Packable *p, const char *label = nullptr) const; |
| 6082a0e2 EB |
89 | /// whether the helper will be in "overloaded" state after one more request |
| 90 | /// already overloaded helpers return true | |
| 91 | bool willOverload() const; | |
| bf3e8d5a | 92 | |
| e05a9d51 | 93 | /// Updates internal statistics and starts new helper processes after |
| a56fcf0b | 94 | /// an unexpected server exit |
| 569605b9 | 95 | void handleKilledServer(SessionBase *); |
| a56fcf0b | 96 | |
| e05a9d51 EB |
97 | /// Reacts to unexpected helper process death(s), including a failure to start helper(s) |
| 98 | /// and an unexpected exit of a previously started helper. \sa handleKilledServer() | |
| 99 | /// \param madeProgress whether the died helper(s) responded to any requests | |
| 654835f0 EB |
100 | void handleFewerServers(bool madeProgress); |
| 101 | ||
| 569605b9 EB |
102 | /// satisfies all queued requests with a Helper::Unknown answer |
| 103 | /// \prec no existing servers will be able to process queued requests | |
| 104 | /// \sa SessionBase::dropQueued() | |
| 105 | void dropQueued(); | |
| 106 | ||
| 26b6afaf EB |
107 | /// sends transaction response to the transaction initiator |
| 108 | void callBack(Xaction &); | |
| 109 | ||
| bd71920d EB |
110 | /// Starts required helper process(es). |
| 111 | /// The caller is responsible for checking that new processes are needed. | |
| 112 | virtual void openSessions(); | |
| 113 | ||
| 48d54e4d | 114 | public: |
| 3bd118d6 | 115 | wordlist *cmdline = nullptr; |
| aa839030 | 116 | dlink_list servers; |
| e05a9d51 | 117 | std::queue<Xaction *> queue; |
| 3bd118d6 | 118 | const char *id_name = nullptr; |
| e05a9d51 | 119 | ChildConfig childs; ///< Configuration settings for number running. |
| 3bd118d6 | 120 | int ipc_type = 0; |
| b7ac5457 | 121 | Ip::Address addr; |
| 3bd118d6 EB |
122 | unsigned int droppedRequests = 0; ///< requests not sent during helper overload |
| 123 | time_t overloadStart = 0; ///< when the helper became overloaded (zero if it is not) | |
| 124 | time_t last_queue_warn = 0; | |
| 125 | time_t last_restart = 0; | |
| 126 | time_t timeout = 0; ///< Requests timeout | |
| 127 | bool retryTimedOut = false; ///< Whether the timed-out requests must retried | |
| 128 | bool retryBrokenHelper = false; ///< Whether the requests must retried on BH replies | |
| 895dba0a | 129 | SBuf onTimedOutResponse; ///< The response to use when helper response timedout |
| 3bd118d6 | 130 | char eom = '\n'; ///< The char which marks the end of (response) message, normally '\n' |
| aa839030 | 131 | |
| 48d54e4d | 132 | struct _stats { |
| 3bd118d6 EB |
133 | int requests = 0; |
| 134 | int replies = 0; | |
| 135 | int timedout = 0; | |
| 136 | int queue_size = 0; | |
| 137 | int avg_svc_time = 0; | |
| 2fadd50d | 138 | } stats; |
| 6825b101 CT |
139 | |
| 140 | protected: | |
| 3bd118d6 | 141 | /// \param name admin-visible helper category (with this process lifetime) |
| e05a9d51 | 142 | explicit Client(const char * const name): id_name(name) {} |
| 3bd118d6 | 143 | |
| 6082a0e2 EB |
144 | bool queueFull() const; |
| 145 | bool overloaded() const; | |
| 146 | void syncQueueStats(); | |
| 147 | bool prepSubmit(); | |
| 6825b101 | 148 | void submit(const char *buf, HLPCB * callback, void *data); |
| aa839030 | 149 | }; |
| 150 | ||
| e05a9d51 EB |
151 | } // namespace Helper |
| 152 | ||
| 153 | // TODO: Rename to a *Client. | |
| 154 | class statefulhelper: public Helper::Client | |
| 10044c9b | 155 | { |
| 48d54e4d | 156 | public: |
| 3bd118d6 | 157 | using Pointer = RefCount<statefulhelper>; |
| a56fcf0b CT |
158 | typedef std::unordered_map<Helper::ReservationId, helper_stateful_server *> Reservations; |
| 159 | ||
| e05a9d51 | 160 | ~statefulhelper() override = default; |
| 48d54e4d | 161 | |
| 3bd118d6 EB |
162 | static Pointer Make(const char *name); |
| 163 | ||
| a56fcf0b CT |
164 | /// reserve the given server |
| 165 | void reserveServer(helper_stateful_server * srv); | |
| 166 | ||
| 167 | /// undo reserveServer(), clear the reservation and kick the queue | |
| 168 | void cancelReservation(const Helper::ReservationId reservation); | |
| 169 | ||
| bd71920d EB |
170 | /* Helper::Client API */ |
| 171 | void openSessions() override; | |
| 172 | ||
| 6825b101 | 173 | private: |
| 3bd118d6 EB |
174 | friend void helperStatefulSubmit(const statefulhelper::Pointer &, const char *buf, HLPCB *, void *cbData, const Helper::ReservationId &); |
| 175 | ||
| e05a9d51 | 176 | explicit statefulhelper(const char * const name): Helper::Client(name) {} |
| a56fcf0b CT |
177 | |
| 178 | /// \return the previously reserved server (if the reservation is still valid) or nil | |
| 179 | helper_stateful_server *findServer(const Helper::ReservationId & reservation); | |
| 180 | ||
| 181 | void submit(const char *buf, HLPCB * callback, void *data, const Helper::ReservationId & reservation); | |
| 182 | bool trySubmit(const char *buf, HLPCB * callback, void *data, const Helper::ReservationId & reservation); | |
| 183 | ||
| 895dba0a | 184 | ///< reserved servers indexed by reservation IDs |
| a56fcf0b | 185 | Reservations reservations; |
| aa839030 | 186 | }; |
| 187 | ||
| e05a9d51 EB |
188 | namespace Helper |
| 189 | { | |
| 190 | ||
| 191 | /// represents a single helper process | |
| 192 | class SessionBase: public CbdataParent | |
| 10044c9b | 193 | { |
| e0d28505 | 194 | public: |
| e05a9d51 EB |
195 | ~SessionBase() override; |
| 196 | ||
| 0a958e42 EB |
197 | /// close handler to handle exited server processes |
| 198 | static void HelperServerClosed(SessionBase *); | |
| 199 | ||
| e0d28505 AJ |
200 | /** Closes pipes to the helper safely. |
| 201 | * Handles the case where the read and write pipes are the same FD. | |
| 202 | */ | |
| 0a958e42 | 203 | void closePipesSafely(); |
| e0d28505 AJ |
204 | |
| 205 | /** Closes the reading pipe. | |
| 206 | * If the read and write sockets are the same the write pipe will | |
| 207 | * also be closed. Otherwise its left open for later handling. | |
| 208 | */ | |
| 0a958e42 | 209 | void closeWritePipeSafely(); |
| e0d28505 | 210 | |
| a56fcf0b CT |
211 | // TODO: Teach each child to report its child-specific state instead. |
| 212 | /// whether the server is locked for exclusive use by a client | |
| 213 | virtual bool reserved() = 0; | |
| 214 | ||
| 0a958e42 EB |
215 | /// our creator (parent) object |
| 216 | virtual Client &helper() const = 0; | |
| 217 | ||
| e05a9d51 | 218 | /// dequeues and sends an Unknown answer to all queued requests |
| 0a958e42 | 219 | virtual void dropQueued(); |
| a56fcf0b | 220 | |
| 48d54e4d | 221 | public: |
| e237d339 AJ |
222 | /// Helper program identifier; does not change when contents do, |
| 223 | /// including during assignment | |
| e05a9d51 EB |
224 | const InstanceId<SessionBase> index; |
| 225 | ||
| 895dba0a | 226 | int pid; |
| b7ac5457 | 227 | Ip::Address addr; |
| e0d28505 AJ |
228 | Comm::ConnectionPointer readPipe; |
| 229 | Comm::ConnectionPointer writePipe; | |
| 895dba0a | 230 | void *hIpc; |
| 48d54e4d | 231 | |
| 895dba0a CT |
232 | char *rbuf; |
| 233 | size_t rbuf_sz; | |
| 234 | size_t roffset; | |
| aa839030 | 235 | |
| 236 | struct timeval dispatch_time; | |
| aa839030 | 237 | struct timeval answer_time; |
| 238 | ||
| 239 | dlink_node link; | |
| e0d28505 AJ |
240 | |
| 241 | struct _helper_flags { | |
| 895dba0a CT |
242 | bool writing; |
| 243 | bool closing; | |
| 244 | bool shutdown; | |
| e0d28505 AJ |
245 | } flags; |
| 246 | ||
| e05a9d51 | 247 | using Requests = std::list<Xaction *>; |
| bf3e8d5a AJ |
248 | Requests requests; ///< requests in order of submission/expiration |
| 249 | ||
| 1f7ba0b4 | 250 | struct { |
| 895dba0a CT |
251 | uint64_t uses; //< requests sent to this helper |
| 252 | uint64_t replies; //< replies received from this helper | |
| 253 | uint64_t pending; //< queued lookups waiting to be sent to this helper | |
| 254 | uint64_t releases; //< times release() has been called on this helper (if stateful) | |
| 255 | uint64_t timedout; //< requests which timed-out | |
| 1f7ba0b4 | 256 | } stats; |
| 895dba0a | 257 | void initStats(); |
| 48d54e4d AJ |
258 | }; |
| 259 | ||
| e05a9d51 EB |
260 | /// represents a single "stateless helper" process; |
| 261 | /// supports concurrent helper requests | |
| 262 | class Session: public SessionBase | |
| 10044c9b | 263 | { |
| e05a9d51 | 264 | CBDATA_CHILD(Session); |
| 5c2f68b7 | 265 | |
| 48d54e4d | 266 | public: |
| 895dba0a | 267 | uint64_t nextRequestId; |
| 017a2d1f | 268 | |
| 895dba0a CT |
269 | MemBuf *wqueue; |
| 270 | MemBuf *writebuf; | |
| 32fd6d8a | 271 | |
| e05a9d51 | 272 | Client::Pointer parent; |
| 32fd6d8a | 273 | |
| ddc77a2e CT |
274 | /// The helper request Xaction object for the current reply . |
| 275 | /// A helper reply may be distributed to more than one of the retrieved | |
| 276 | /// packets from helper. This member stores the Xaction object as long as | |
| 277 | /// the end-of-message for current reply is not retrieved. | |
| e05a9d51 | 278 | Xaction *replyXaction; |
| ddc77a2e | 279 | |
| 1176e456 | 280 | /// Whether to ignore current message, because it is timed-out or other reason |
| 895dba0a | 281 | bool ignoreToEom; |
| 1176e456 | 282 | |
| 32fd6d8a CT |
283 | // STL says storing std::list iterators is safe when changing the list |
| 284 | typedef std::map<uint64_t, Requests::iterator> RequestIndex; | |
| 285 | RequestIndex requestsIndex; ///< maps request IDs to requests | |
| 286 | ||
| e05a9d51 EB |
287 | ~Session() override; |
| 288 | ||
| ddc77a2e CT |
289 | /// Search in queue for the request with requestId, return the related |
| 290 | /// Xaction object and remove it from queue. | |
| 291 | /// If concurrency is disabled then the requestId is ignored and the | |
| 292 | /// Xaction of the next request in queue is retrieved. | |
| e05a9d51 | 293 | Xaction *popRequest(int requestId); |
| ddc77a2e | 294 | |
| 32fd6d8a CT |
295 | /// Run over the active requests lists and forces a retry, or timedout reply |
| 296 | /// or the configured "on timeout response" for timedout requests. | |
| 297 | void checkForTimedOutRequests(bool const retry); | |
| 298 | ||
| e05a9d51 | 299 | /* SessionBase API */ |
| 337b9aa4 | 300 | bool reserved() override {return false;} |
| 0a958e42 EB |
301 | void dropQueued() override; |
| 302 | Client &helper() const override { return *parent; } | |
| a56fcf0b | 303 | |
| f53969cc | 304 | /// Read timeout handler |
| 32fd6d8a | 305 | static void requestTimeout(const CommTimeoutCbParams &io); |
| aa839030 | 306 | }; |
| 307 | ||
| e05a9d51 EB |
308 | } // namespace Helper |
| 309 | ||
| 310 | // TODO: Rename to a *Session, matching renamed statefulhelper. | |
| 311 | /// represents a single "stateful helper" process; | |
| 312 | /// supports exclusive transaction reservations | |
| 313 | class helper_stateful_server: public Helper::SessionBase | |
| 10044c9b | 314 | { |
| a56fcf0b | 315 | CBDATA_CHILD(helper_stateful_server); |
| 5c2f68b7 | 316 | |
| 48d54e4d | 317 | public: |
| 337b9aa4 | 318 | ~helper_stateful_server() override; |
| a56fcf0b CT |
319 | void reserve(); |
| 320 | void clearReservation(); | |
| 321 | ||
| 0a958e42 | 322 | /* Helper::SessionBase API */ |
| 337b9aa4 | 323 | bool reserved() override {return reservationId.reserved();} |
| 0a958e42 | 324 | Helper::Client &helper() const override { return *parent; } |
| a56fcf0b | 325 | |
| 3bd118d6 | 326 | statefulhelper::Pointer parent; |
| a56fcf0b CT |
327 | |
| 328 | // Reservations temporary lock the server for an exclusive "client" use. The | |
| 329 | // client keeps the reservation ID as a proof of her reservation. If a | |
| 330 | // reservation expires, and the server is reserved for another client, then | |
| 331 | // the reservation ID presented by the late client will not match ours. | |
| 332 | Helper::ReservationId reservationId; ///< "confirmation ID" of the last | |
| 895dba0a | 333 | time_t reservationStart; ///< when the last `reservation` was made |
| aa839030 | 334 | }; |
| 51ee7c82 | 335 | |
| e05a9d51 | 336 | void helperSubmit(const Helper::Client::Pointer &, const char *buf, HLPCB *, void *cbData); |
| 3bd118d6 | 337 | void helperStatefulSubmit(const statefulhelper::Pointer &, const char *buf, HLPCB *, void *cbData, uint64_t reservation); |
| e05a9d51 | 338 | void helperShutdown(const Helper::Client::Pointer &); |
| 3bd118d6 | 339 | void helperStatefulShutdown(const statefulhelper::Pointer &); |
| aa839030 | 340 | |
| ff9d9458 | 341 | #endif /* SQUID_SRC_HELPER_H */ |
| 70ac5b29 | 342 |