]> git.ipfire.org Git - thirdparty/squid.git/blob - src/helper.h
CI: Remove unnecessary test-functionality test wrappers (#1393)
[thirdparty/squid.git] / src / helper.h
1 /*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3 *
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.
7 */
8
9 /* DEBUG: section 84 Helper process maintenance */
10
11 #ifndef SQUID_HELPER_H
12 #define SQUID_HELPER_H
13
14 #include "base/AsyncCall.h"
15 #include "base/InstanceId.h"
16 #include "cbdata.h"
17 #include "comm/forward.h"
18 #include "dlink.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"
26
27 #include <list>
28 #include <map>
29 #include <queue>
30 #include <unordered_map>
31
32 class Packable;
33 class wordlist;
34
35 namespace Helper
36 {
37 /// Holds the required data to serve a helper request.
38 class Xaction {
39 MEMPROXY_CLASS(Helper::Xaction);
40 public:
41 Xaction(HLPCB *c, void *d, const char *b): request(c, d, b) {}
42 Helper::Request request;
43 Helper::Reply reply;
44 };
45 }
46
47 class HelperServerBase;
48 /**
49 * Managers a set of individual helper processes with a common queue of requests.
50 *
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.
56 *
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.
62 */
63 class helper
64 {
65 CBDATA_CLASS(helper);
66
67 public:
68 /// \param name admin-visible helper category (with this process lifetime)
69 inline helper(const char *name) :
70 cmdline(nullptr),
71 id_name(name),
72 ipc_type(0),
73 droppedRequests(0),
74 overloadStart(0),
75 last_queue_warn(0),
76 last_restart(0),
77 timeout(0),
78 retryTimedOut(false),
79 retryBrokenHelper(false),
80 eom('\n') {
81 memset(&stats, 0, sizeof(stats));
82 }
83 ~helper();
84
85 /// \returns next request in the queue, or nil.
86 Helper::Xaction *nextRequest();
87
88 /// If possible, submit request. Otherwise, either kill Squid or return false.
89 bool trySubmit(const char *buf, HLPCB * callback, void *data);
90
91 /// Submits a request to the helper or add it to the queue if none of
92 /// the servers is available.
93 void submitRequest(Helper::Xaction *r);
94
95 /// Dump some stats about the helper state to a Packable object
96 void packStatsInto(Packable *p, const char *label = nullptr) const;
97 /// whether the helper will be in "overloaded" state after one more request
98 /// already overloaded helpers return true
99 bool willOverload() const;
100
101 /// Updates interall statistics and start new helper server processes after
102 /// an unexpected server exit
103 /// \param needsNewServers true if new servers must started, false otherwise
104 void handleKilledServer(HelperServerBase *srv, bool &needsNewServers);
105
106 public:
107 wordlist *cmdline;
108 dlink_list servers;
109 std::queue<Helper::Xaction *> queue;
110 const char *id_name;
111 Helper::ChildConfig childs; ///< Configuration settings for number running.
112 int ipc_type;
113 Ip::Address addr;
114 unsigned int droppedRequests; ///< requests not sent during helper overload
115 time_t overloadStart; ///< when the helper became overloaded (zero if it is not)
116 time_t last_queue_warn;
117 time_t last_restart;
118 time_t timeout; ///< Requests timeout
119 bool retryTimedOut; ///< Whether the timed-out requests must retried
120 bool retryBrokenHelper; ///< Whether the requests must retried on BH replies
121 SBuf onTimedOutResponse; ///< The response to use when helper response timedout
122 char eom; ///< The char which marks the end of (response) message, normally '\n'
123
124 struct _stats {
125 int requests;
126 int replies;
127 int timedout;
128 int queue_size;
129 int avg_svc_time;
130 } stats;
131
132 protected:
133 friend void helperSubmit(helper * hlp, const char *buf, HLPCB * callback, void *data);
134 bool queueFull() const;
135 bool overloaded() const;
136 void syncQueueStats();
137 bool prepSubmit();
138 void submit(const char *buf, HLPCB * callback, void *data);
139 };
140
141 class statefulhelper : public helper
142 {
143 CBDATA_CLASS(statefulhelper);
144
145 public:
146 typedef std::unordered_map<Helper::ReservationId, helper_stateful_server *> Reservations;
147
148 inline statefulhelper(const char *name) : helper(name) {}
149 inline ~statefulhelper() {}
150
151 public:
152 /// reserve the given server
153 void reserveServer(helper_stateful_server * srv);
154
155 /// undo reserveServer(), clear the reservation and kick the queue
156 void cancelReservation(const Helper::ReservationId reservation);
157
158 private:
159 friend void helperStatefulSubmit(statefulhelper * hlp, const char *buf, HLPCB * callback, void *data, const Helper::ReservationId & reservation);
160
161 /// \return the previously reserved server (if the reservation is still valid) or nil
162 helper_stateful_server *findServer(const Helper::ReservationId & reservation);
163
164 void submit(const char *buf, HLPCB * callback, void *data, const Helper::ReservationId & reservation);
165 bool trySubmit(const char *buf, HLPCB * callback, void *data, const Helper::ReservationId & reservation);
166
167 ///< reserved servers indexed by reservation IDs
168 Reservations reservations;
169 };
170
171 /// represents a single helper process abstraction
172 class HelperServerBase: public CbdataParent
173 {
174 public:
175 ~HelperServerBase() override;
176 /** Closes pipes to the helper safely.
177 * Handles the case where the read and write pipes are the same FD.
178 *
179 * \param name displayed for the helper being shutdown if logging an error
180 */
181 void closePipesSafely(const char *name);
182
183 /** Closes the reading pipe.
184 * If the read and write sockets are the same the write pipe will
185 * also be closed. Otherwise its left open for later handling.
186 *
187 * \param name displayed for the helper being shutdown if logging an error
188 */
189 void closeWritePipeSafely(const char *name);
190
191 // TODO: Teach each child to report its child-specific state instead.
192 /// whether the server is locked for exclusive use by a client
193 virtual bool reserved() = 0;
194
195 /// dequeues and sends a Helper::Unknown answer to all queued requests
196 virtual void dropQueued();
197
198 /// the helper object that created this server
199 virtual helper *getParent() const = 0;
200
201 public:
202 /// Helper program identifier; does not change when contents do,
203 /// including during assignment
204 const InstanceId<HelperServerBase> index;
205 int pid;
206 Ip::Address addr;
207 Comm::ConnectionPointer readPipe;
208 Comm::ConnectionPointer writePipe;
209 void *hIpc;
210
211 char *rbuf;
212 size_t rbuf_sz;
213 size_t roffset;
214
215 struct timeval dispatch_time;
216 struct timeval answer_time;
217
218 dlink_node link;
219
220 struct _helper_flags {
221 bool writing;
222 bool closing;
223 bool shutdown;
224 } flags;
225
226 typedef std::list<Helper::Xaction *> Requests;
227 Requests requests; ///< requests in order of submission/expiration
228
229 struct {
230 uint64_t uses; //< requests sent to this helper
231 uint64_t replies; //< replies received from this helper
232 uint64_t pending; //< queued lookups waiting to be sent to this helper
233 uint64_t releases; //< times release() has been called on this helper (if stateful)
234 uint64_t timedout; //< requests which timed-out
235 } stats;
236 void initStats();
237 };
238
239 class MemBuf;
240 class CommTimeoutCbParams;
241
242 // TODO: Rename to StatelessHelperServer and rename HelperServerBase to HelperServer.
243 /// represents a single "stateless helper" process
244 class helper_server : public HelperServerBase
245 {
246 CBDATA_CHILD(helper_server);
247
248 public:
249 uint64_t nextRequestId;
250
251 MemBuf *wqueue;
252 MemBuf *writebuf;
253
254 helper *parent;
255
256 /// The helper request Xaction object for the current reply .
257 /// A helper reply may be distributed to more than one of the retrieved
258 /// packets from helper. This member stores the Xaction object as long as
259 /// the end-of-message for current reply is not retrieved.
260 Helper::Xaction *replyXaction;
261
262 /// Whether to ignore current message, because it is timed-out or other reason
263 bool ignoreToEom;
264
265 // STL says storing std::list iterators is safe when changing the list
266 typedef std::map<uint64_t, Requests::iterator> RequestIndex;
267 RequestIndex requestsIndex; ///< maps request IDs to requests
268
269 ~helper_server() override;
270 /// Search in queue for the request with requestId, return the related
271 /// Xaction object and remove it from queue.
272 /// If concurrency is disabled then the requestId is ignored and the
273 /// Xaction of the next request in queue is retrieved.
274 Helper::Xaction *popRequest(int requestId);
275
276 /// Run over the active requests lists and forces a retry, or timedout reply
277 /// or the configured "on timeout response" for timedout requests.
278 void checkForTimedOutRequests(bool const retry);
279
280 /*HelperServerBase API*/
281 bool reserved() override {return false;}
282 void dropQueued() override;
283 helper *getParent() const override {return parent;}
284
285 /// Read timeout handler
286 static void requestTimeout(const CommTimeoutCbParams &io);
287
288 /// close handler to handle exited server processes
289 static void HelperServerClosed(helper_server *srv);
290 };
291
292 // TODO: Rename to StatefulHelperServer and rename HelperServerBase to HelperServer.
293 /// represents a single "stateful helper" process
294 class helper_stateful_server : public HelperServerBase
295 {
296 CBDATA_CHILD(helper_stateful_server);
297
298 public:
299 ~helper_stateful_server() override;
300 void reserve();
301 void clearReservation();
302
303 /* HelperServerBase API */
304 bool reserved() override {return reservationId.reserved();}
305 helper *getParent() const override {return parent;}
306
307 /// close handler to handle exited server processes
308 static void HelperServerClosed(helper_stateful_server *srv);
309
310 statefulhelper *parent;
311
312 // Reservations temporary lock the server for an exclusive "client" use. The
313 // client keeps the reservation ID as a proof of her reservation. If a
314 // reservation expires, and the server is reserved for another client, then
315 // the reservation ID presented by the late client will not match ours.
316 Helper::ReservationId reservationId; ///< "confirmation ID" of the last
317 time_t reservationStart; ///< when the last `reservation` was made
318 };
319
320 /* helper.c */
321 void helperOpenServers(helper * hlp);
322 void helperStatefulOpenServers(statefulhelper * hlp);
323 void helperSubmit(helper * hlp, const char *buf, HLPCB * callback, void *data);
324 void helperStatefulSubmit(statefulhelper * hlp, const char *buf, HLPCB * callback, void *data, uint64_t reservation);
325 void helperShutdown(helper * hlp);
326 void helperStatefulShutdown(statefulhelper * hlp);
327
328 #endif /* SQUID_HELPER_H */
329