2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
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.
9 /* DEBUG: section 84 Helper process maintenance */
11 #ifndef SQUID_HELPER_H
12 #define SQUID_HELPER_H
14 #include "base/AsyncCall.h"
15 #include "base/InstanceId.h"
17 #include "comm/forward.h"
19 #include "helper/ChildConfig.h"
20 #include "helper/forward.h"
21 #include "helper/Reply.h"
22 #include "helper/Request.h"
23 #include "helper/ReservationId.h"
24 #include "ip/Address.h"
25 #include "sbuf/SBuf.h"
30 #include <unordered_map>
37 /// Holds the required data to serve a helper request.
39 MEMPROXY_CLASS(Helper::Xaction
);
41 Xaction(HLPCB
*c
, void *d
, const char *b
): request(c
, d
, b
) {}
42 Helper::Request request
;
47 class HelperServerBase
;
49 * Managers a set of individual helper processes with a common queue of requests.
51 * With respect to load, a helper goes through these states (roughly):
52 * idle: no processes are working on requests (and no requests are queued);
53 * normal: some, but not all processes are working (and no requests are queued);
54 * busy: all processes are working (and some requests are possibly queued);
55 * overloaded: a busy helper with more than queue-size requests in the queue.
57 * A busy helper queues new requests and issues a WARNING every 10 minutes or so.
58 * An overloaded helper either drops new requests or keeps queuing them, depending on
59 * whether the caller can handle dropped requests (trySubmit vs helperSubmit APIs).
60 * If an overloaded helper has been overloaded for 3+ minutes, an attempt to use
61 * it results in on-persistent-overload action, which may kill worker.
68 inline helper(const char *name
) :
78 retryBrokenHelper(false),
80 memset(&stats
, 0, sizeof(stats
));
84 /// \returns next request in the queue, or nil.
85 Helper::Xaction
*nextRequest();
87 /// If possible, submit request. Otherwise, either kill Squid or return false.
88 bool trySubmit(const char *buf
, HLPCB
* callback
, void *data
);
90 /// Submits a request to the helper or add it to the queue if none of
91 /// the servers is available.
92 void submitRequest(Helper::Xaction
*r
);
94 /// Dump some stats about the helper state to a Packable object
95 void packStatsInto(Packable
*p
, const char *label
= NULL
) const;
96 /// whether the helper will be in "overloaded" state after one more request
97 /// already overloaded helpers return true
98 bool willOverload() const;
100 /// Updates interall statistics and start new helper server processes after
101 /// an unexpected server exit
102 /// \param needsNewServers true if new servers must started, false otherwise
103 void handleKilledServer(HelperServerBase
*srv
, bool &needsNewServers
);
108 std::queue
<Helper::Xaction
*> queue
;
110 Helper::ChildConfig childs
; ///< Configuration settings for number running.
113 unsigned int droppedRequests
; ///< requests not sent during helper overload
114 time_t overloadStart
; ///< when the helper became overloaded (zero if it is not)
115 time_t last_queue_warn
;
117 time_t timeout
; ///< Requests timeout
118 bool retryTimedOut
; ///< Whether the timed-out requests must retried
119 bool retryBrokenHelper
; ///< Whether the requests must retried on BH replies
120 SBuf onTimedOutResponse
; ///< The response to use when helper response timedout
121 char eom
; ///< The char which marks the end of (response) message, normally '\n'
132 friend void helperSubmit(helper
* hlp
, const char *buf
, HLPCB
* callback
, void *data
);
133 bool queueFull() const;
134 bool overloaded() const;
135 void syncQueueStats();
137 void submit(const char *buf
, HLPCB
* callback
, void *data
);
140 class statefulhelper
: public helper
142 CBDATA_CLASS(statefulhelper
);
145 typedef std::unordered_map
<Helper::ReservationId
, helper_stateful_server
*> Reservations
;
147 inline statefulhelper(const char *name
) : helper(name
) {}
148 inline ~statefulhelper() {}
151 /// reserve the given server
152 void reserveServer(helper_stateful_server
* srv
);
154 /// undo reserveServer(), clear the reservation and kick the queue
155 void cancelReservation(const Helper::ReservationId reservation
);
158 friend void helperStatefulSubmit(statefulhelper
* hlp
, const char *buf
, HLPCB
* callback
, void *data
, const Helper::ReservationId
& reservation
);
160 /// \return the previously reserved server (if the reservation is still valid) or nil
161 helper_stateful_server
*findServer(const Helper::ReservationId
& reservation
);
163 void submit(const char *buf
, HLPCB
* callback
, void *data
, const Helper::ReservationId
& reservation
);
164 bool trySubmit(const char *buf
, HLPCB
* callback
, void *data
, const Helper::ReservationId
& reservation
);
166 ///< reserved servers indexed by reservation IDs
167 Reservations reservations
;
170 /// represents a single helper process abstraction
171 class HelperServerBase
: public CbdataParent
174 virtual ~HelperServerBase();
175 /** Closes pipes to the helper safely.
176 * Handles the case where the read and write pipes are the same FD.
178 * \param name displayed for the helper being shutdown if logging an error
180 void closePipesSafely(const char *name
);
182 /** Closes the reading pipe.
183 * If the read and write sockets are the same the write pipe will
184 * also be closed. Otherwise its left open for later handling.
186 * \param name displayed for the helper being shutdown if logging an error
188 void closeWritePipeSafely(const char *name
);
190 // TODO: Teach each child to report its child-specific state instead.
191 /// whether the server is locked for exclusive use by a client
192 virtual bool reserved() = 0;
194 /// dequeues and sends a Helper::Unknown answer to all queued requests
195 virtual void dropQueued();
197 /// the helper object that created this server
198 virtual helper
*getParent() const = 0;
201 /// Helper program identifier; does not change when contents do,
202 /// including during assignment
203 const InstanceId
<HelperServerBase
> index
;
206 Comm::ConnectionPointer readPipe
;
207 Comm::ConnectionPointer writePipe
;
214 struct timeval dispatch_time
;
215 struct timeval answer_time
;
219 struct _helper_flags
{
225 typedef std::list
<Helper::Xaction
*> Requests
;
226 Requests requests
; ///< requests in order of submission/expiration
229 uint64_t uses
; //< requests sent to this helper
230 uint64_t replies
; //< replies received from this helper
231 uint64_t pending
; //< queued lookups waiting to be sent to this helper
232 uint64_t releases
; //< times release() has been called on this helper (if stateful)
233 uint64_t timedout
; //< requests which timed-out
239 class CommTimeoutCbParams
;
241 // TODO: Rename to StatelessHelperServer and rename HelperServerBase to HelperServer.
242 /// represents a single "stateless helper" process
243 class helper_server
: public HelperServerBase
245 CBDATA_CHILD(helper_server
);
248 uint64_t nextRequestId
;
255 /// The helper request Xaction object for the current reply .
256 /// A helper reply may be distributed to more than one of the retrieved
257 /// packets from helper. This member stores the Xaction object as long as
258 /// the end-of-message for current reply is not retrieved.
259 Helper::Xaction
*replyXaction
;
261 /// Whether to ignore current message, because it is timed-out or other reason
264 // STL says storing std::list iterators is safe when changing the list
265 typedef std::map
<uint64_t, Requests::iterator
> RequestIndex
;
266 RequestIndex requestsIndex
; ///< maps request IDs to requests
268 virtual ~helper_server();
269 /// Search in queue for the request with requestId, return the related
270 /// Xaction object and remove it from queue.
271 /// If concurrency is disabled then the requestId is ignored and the
272 /// Xaction of the next request in queue is retrieved.
273 Helper::Xaction
*popRequest(int requestId
);
275 /// Run over the active requests lists and forces a retry, or timedout reply
276 /// or the configured "on timeout response" for timedout requests.
277 void checkForTimedOutRequests(bool const retry
);
279 /*HelperServerBase API*/
280 virtual bool reserved() override
{return false;}
281 virtual void dropQueued() override
;
282 virtual helper
*getParent() const override
{return parent
;}
284 /// Read timeout handler
285 static void requestTimeout(const CommTimeoutCbParams
&io
);
287 /// close handler to handle exited server processes
288 static void HelperServerClosed(helper_server
*srv
);
291 // TODO: Rename to StatefulHelperServer and rename HelperServerBase to HelperServer.
292 /// represents a single "stateful helper" process
293 class helper_stateful_server
: public HelperServerBase
295 CBDATA_CHILD(helper_stateful_server
);
298 virtual ~helper_stateful_server();
300 void clearReservation();
302 /* HelperServerBase API */
303 virtual bool reserved() override
{return reservationId
.reserved();}
304 virtual helper
*getParent() const override
{return parent
;}
306 /// close handler to handle exited server processes
307 static void HelperServerClosed(helper_stateful_server
*srv
);
309 statefulhelper
*parent
;
311 // Reservations temporary lock the server for an exclusive "client" use. The
312 // client keeps the reservation ID as a proof of her reservation. If a
313 // reservation expires, and the server is reserved for another client, then
314 // the reservation ID presented by the late client will not match ours.
315 Helper::ReservationId reservationId
; ///< "confirmation ID" of the last
316 time_t reservationStart
; ///< when the last `reservation` was made
320 void helperOpenServers(helper
* hlp
);
321 void helperStatefulOpenServers(statefulhelper
* hlp
);
322 void helperSubmit(helper
* hlp
, const char *buf
, HLPCB
* callback
, void *data
);
323 void helperStatefulSubmit(statefulhelper
* hlp
, const char *buf
, HLPCB
* callback
, void *data
, uint64_t reservation
);
324 void helperShutdown(helper
* hlp
);
325 void helperStatefulShutdown(statefulhelper
* hlp
);
327 #endif /* SQUID_HELPER_H */