]> git.pld-linux.org Git - packages/squid.git/blame - ecap-1p0-t2.patch
- up to 3.5.20
[packages/squid.git] / ecap-1p0-t2.patch
CommitLineData
98801e83
JR
1Support libecap v1.0, allowing asynchronous adapters and eCAP version checks.
2
3After these changes, Squid can support eCAP adapters built with libecap v1.0,
4but stops supporting adapters built with earlier libecap versions (due to API
5changes). The new libecap version allows Squid to better check the version of
6the eCAP adapter being loaded as well as the version of the eCAP library being
7used. This should help with migration to libecap v1.0.
8
9
10Expose [running] main event loop as a global so that modules can add engines.
11
12=== modified file 'configure.ac'
13--- configure.ac 2013-07-09 11:15:51 +0000
14+++ configure.ac 2013-09-12 23:08:18 +0000
15@@ -1035,10 +1035,10 @@
16
17 if test -n "$PKG_CONFIG"; then
18 dnl eCAP support requires libecap.
19- dnl This Squid supports libecap v0.2.x.
20+ dnl This Squid supports libecap v1.0.x.
21 dnl Use EXT_ prefix to distinguish external libecap (that we check for
22 dnl here) from our own convenience ecap library in Makefiles.
23- PKG_CHECK_MODULES([EXT_LIBECAP],[libecap >= 0.2.0 libecap < 0.3])
24+ PKG_CHECK_MODULES([EXT_LIBECAP],[libecap >= 1.0 libecap < 1.1])
25 else
26 AC_MSG_NOTICE([eCAP support requires pkg-config to verify the correct library version. Trouble may follow.])
27 fi
28
29=== modified file 'src/EventLoop.cc'
30--- src/EventLoop.cc 2013-02-17 02:09:16 +0000
31+++ src/EventLoop.cc 2013-09-16 00:07:51 +0000
32@@ -37,6 +37,8 @@
33 #include "base/AsyncCallQueue.h"
34 #include "SquidTime.h"
35
36+EventLoop *EventLoop::Running = NULL;
37+
38 EventLoop::EventLoop() : errcount(0), last_loop(false), timeService(NULL),
39 primaryEngine(NULL),
40 loop_delay(EVENT_LOOP_TIMEOUT),
41@@ -96,7 +98,12 @@
42 {
43 prepareToRun();
44
45+ assert(!Running);
46+ Running = this;
47+
48 while (!runOnce());
49+
50+ Running = NULL;
51 }
52
53 bool
54
55=== modified file 'src/EventLoop.h'
56--- src/EventLoop.h 2013-05-04 11:50:26 +0000
57+++ src/EventLoop.h 2013-09-16 00:07:51 +0000
58@@ -89,6 +89,10 @@
59
60 int errcount;
61
62+ /// the [main program] loop running now; may be nil
63+ /// for simplicity, we assume there are no concurrent loops
64+ static EventLoop *Running;
65+
66 private:
67 /** setup state variables prior to running */
68 void prepareToRun();
69
70=== modified file 'src/adaptation/ecap/Host.cc'
71--- src/adaptation/ecap/Host.cc 2012-08-28 13:00:30 +0000
72+++ src/adaptation/ecap/Host.cc 2013-09-16 18:04:34 +0000
73@@ -70,11 +70,55 @@
74 os << PACKAGE_NAME << " v" << PACKAGE_VERSION;
75 }
76
77+/// Strips libecap version components not affecting compatibility decisions.
78+static std::string
79+EssentialVersion(const std::string &raw)
80+{
81+ // all libecap x.y.* releases are supposed to be compatible so we strip
82+ // everything after the second period
83+ const std::string::size_type minorPos = raw.find('.');
84+ const std::string::size_type microPos = minorPos == std::string::npos ?
85+ std::string::npos : raw.find('.', minorPos+1);
86+ return raw.substr(0, microPos); // becomes raw if microPos is npos
87+}
88+
89+/// If "their" libecap version is not compatible with what Squid has been built
90+/// with, then complain and return false.
91+static bool
92+SupportedVersion(const char *vTheir, const std::string &them)
93+{
94+ if (!vTheir || !*vTheir) {
95+ debugs(93, DBG_CRITICAL, "ERROR: Cannot use " << them <<
96+ " with libecap prior to v1.0.");
97+ return false;
98+ }
99+
100+ // we support what we are built with
101+ const std::string vSupported(LIBECAP_VERSION);
102+ debugs(93, 2, them << " with libecap v" << vTheir << "; us: v" << vSupported);
103+
104+ if (EssentialVersion(vTheir) == EssentialVersion(vSupported))
105+ return true; // their version is supported
106+
107+ debugs(93, DBG_CRITICAL, "ERROR: Cannot use " << them <<
108+ " with libecap v" << vTheir <<
109+ ": incompatible with supported libecap v" << vSupported);
110+ return false;
111+}
112+
113 void
114-Adaptation::Ecap::Host::noteService(const libecap::weak_ptr<libecap::adapter::Service> &weak)
115+Adaptation::Ecap::Host::noteVersionedService(const char *vGiven, const libecap::weak_ptr<libecap::adapter::Service> &weak)
116 {
117- Must(!weak.expired());
118- RegisterAdapterService(weak.lock());
119+ /*
120+ * Check that libecap used to build the service is compatible with ours.
121+ * This has to be done using vGiven string and not Service object itself
122+ * because dereferencing a Service pointer coming from an unsupported
123+ * version is unsafe.
124+ */
125+ if (SupportedVersion(vGiven, "eCAP service built")) {
126+ Must(!weak.expired());
127+ RegisterAdapterService(weak.lock());
128+ }
129 }
130
131 static int
132@@ -126,7 +170,8 @@
133 void
134 Adaptation::Ecap::Host::Register()
135 {
136- if (!TheHost) {
137+ if (!TheHost && SupportedVersion(libecap::VersionString(),
138+ "Squid executable dynamically linked")) {
139 TheHost.reset(new Adaptation::Ecap::Host);
140 libecap::RegisterHost(TheHost);
141 }
142
143=== modified file 'src/adaptation/ecap/Host.h'
144--- src/adaptation/ecap/Host.h 2012-10-04 11:10:17 +0000
145+++ src/adaptation/ecap/Host.h 2013-09-16 18:04:34 +0000
146@@ -19,7 +19,7 @@
147 /* libecap::host::Host API */
148 virtual std::string uri() const; // unique across all vendors
149 virtual void describe(std::ostream &os) const; // free-format info
150- virtual void noteService(const libecap::weak_ptr<libecap::adapter::Service> &s);
151+ virtual void noteVersionedService(const char *libEcapVersion, const libecap::weak_ptr<libecap::adapter::Service> &s);
152 virtual std::ostream *openDebug(libecap::LogVerbosity lv);
153 virtual void closeDebug(std::ostream *debug);
154 typedef libecap::shared_ptr<libecap::Message> MessagePtr;
155
156=== modified file 'src/adaptation/ecap/ServiceRep.cc'
157--- src/adaptation/ecap/ServiceRep.cc 2012-08-28 13:00:30 +0000
158+++ src/adaptation/ecap/ServiceRep.cc 2013-09-16 18:04:34 +0000
159@@ -2,20 +2,29 @@
160 * DEBUG: section 93 eCAP Interface
161 */
162 #include "squid.h"
163+#include "adaptation/ecap/Config.h"
164+#include "adaptation/ecap/Host.h"
165+#include "adaptation/ecap/ServiceRep.h"
166+#include "adaptation/ecap/XactionRep.h"
167+#include "AsyncEngine.h"
168+#include "base/TextException.h"
169 #include "Debug.h"
170-#include <list>
171+#include "EventLoop.h"
172 #include <libecap/adapter/service.h>
173 #include <libecap/common/options.h>
174 #include <libecap/common/name.h>
175 #include <libecap/common/named_values.h>
176-#include "adaptation/ecap/Config.h"
177-#include "adaptation/ecap/Host.h"
178-#include "adaptation/ecap/ServiceRep.h"
179-#include "adaptation/ecap/XactionRep.h"
180-#include "base/TextException.h"
181+#if HAVE_LIMITS
182+#include <limits>
183+#endif
184+#include <map>
185
186-// configured eCAP service wrappers
187-static std::list<Adaptation::Ecap::ServiceRep::AdapterService> TheServices;
188+/// libecap::adapter::services indexed by their URI
189+typedef std::map<std::string, Adaptation::Ecap::ServiceRep::AdapterService> AdapterServices;
190+/// all loaded services
191+static AdapterServices TheServices;
192+/// configured services producing async transactions
193+static AdapterServices AsyncServices;
194
195 namespace Adaptation
196 {
197@@ -39,6 +48,17 @@
198 const Master &master; ///< the configuration being wrapped
199 };
200
201+/// manages async eCAP transactions
202+class Engine: public AsyncEngine
203+{
204+public:
205+ /* AsyncEngine API */
206+ virtual int checkEvents(int timeout);
207+
208+private:
209+ void kickAsyncServices(timeval &timeout);
210+};
211+
212 } // namespace Ecap
213 } // namespace Adaptation
214
215@@ -76,6 +96,55 @@
216 visitor.visit(Name(i->first), Area::FromTempString(i->second));
217 }
218
219+/* Adaptation::Ecap::Engine */
220+
221+int
222+Adaptation::Ecap::Engine::checkEvents(int)
223+{
224+ // Start with the default I/O loop timeout, convert from milliseconds.
225+ static const struct timeval maxTimeout {
226+ EVENT_LOOP_TIMEOUT/1000, // seconds
227+ (EVENT_LOOP_TIMEOUT % 1000)*1000
228+ }; // microseconds
229+ struct timeval timeout = maxTimeout;
230+
231+ kickAsyncServices(timeout);
232+ if (timeout.tv_sec == maxTimeout.tv_sec && timeout.tv_usec == maxTimeout.tv_usec)
233+ return EVENT_IDLE;
234+
235+ debugs(93, 7, "timeout: " << timeout.tv_sec << "s+" << timeout.tv_usec << "us");
236+
237+ // convert back to milliseconds, avoiding int overflows
238+ if (timeout.tv_sec >= std::numeric_limits<int>::max()/1000 - 1000)
239+ return std::numeric_limits<int>::max();
240+ else
241+ return timeout.tv_sec*1000 + timeout.tv_usec/1000;
242+}
243+
244+/// resumes async transactions (if any) and returns true if they set a timeout
245+void
246+Adaptation::Ecap::Engine::kickAsyncServices(timeval &timeout)
247+{
248+ if (AsyncServices.empty())
249+ return;
250+
251+ debugs(93, 3, "async services: " << AsyncServices.size());
252+
253+ // Activate waiting async transactions, if any.
254+ typedef AdapterServices::iterator ASI;
255+ for (ASI s = AsyncServices.begin(); s != AsyncServices.end(); ++s) {
256+ assert(s->second);
257+ s->second->resume(); // may call Ecap::Xaction::resume()
258+ }
259+
260+ // Give services a chance to decrease the default timeout.
261+ for (ASI s = AsyncServices.begin(); s != AsyncServices.end(); ++s) {
262+ s->second->suspend(timeout);
263+ }
264+}
265+
266+/* Adaptation::Ecap::ServiceRep */
267+
268 Adaptation::Ecap::ServiceRep::ServiceRep(const ServiceConfigPointer &cfg):
269 /*AsyncJob("Adaptation::Ecap::ServiceRep"),*/ Adaptation::Service(cfg),
270 isDetached(false)
271@@ -123,6 +192,11 @@
272
273 debugs(93,DBG_IMPORTANT, "Starting eCAP service: " << theService->uri());
274 theService->start();
275+
276+ if (theService->makesAsyncXactions()) {
277+ AsyncServices[theService->uri()] = theService;
278+ debugs(93, 5, "asyncs: " << AsyncServices.size());
279+ }
280 }
281
282 /// handles failures while configuring or starting an eCAP service;
283@@ -168,6 +242,16 @@
284 HttpRequest *cause)
285 {
286 Must(up());
287+
288+ // register now because (a) we need EventLoop::Running and (b) we do not
289+ // want to add more main loop overheads unless an async service is used.
290+ static AsyncEngine *TheEngine = NULL;
291+ if (AsyncServices.size() && !TheEngine && EventLoop::Running) {
292+ TheEngine = new Engine;
293+ EventLoop::Running->registerEngine(TheEngine);
294+ debugs(93, 3, "asyncs: " << AsyncServices.size() << ' ' << TheEngine);
295+ }
296+
297 XactionRep *rep = new XactionRep(virgin, cause, Pointer(this));
298 XactionRep::AdapterXaction x(theService->makeXaction(rep));
299 rep->master(x);
300@@ -210,11 +294,10 @@
301 Adaptation::Ecap::ServiceRep::AdapterService
302 Adaptation::Ecap::FindAdapterService(const String& serviceUri)
303 {
304- typedef std::list<ServiceRep::AdapterService>::const_iterator ASCI;
305- for (ASCI s = TheServices.begin(); s != TheServices.end(); ++s) {
306- Must(*s);
307- if (serviceUri == (*s)->uri().c_str())
308- return *s;
309+ AdapterServices::const_iterator pos = TheServices.find(serviceUri.termedBuf());
310+ if (pos != TheServices.end()) {
311+ Must(pos->second);
312+ return pos->second;
313 }
314 return ServiceRep::AdapterService();
315 }
316@@ -222,30 +305,18 @@
317 void
318 Adaptation::Ecap::RegisterAdapterService(const Adaptation::Ecap::ServiceRep::AdapterService& adapterService)
319 {
320- typedef std::list<ServiceRep::AdapterService>::iterator ASI;
321- for (ASI s = TheServices.begin(); s != TheServices.end(); ++s) {
322- Must(*s);
323- if (adapterService->uri() == (*s)->uri()) {
324- *s = adapterService;
325- debugs(93, 3, "updated eCAP module service: " <<
326- adapterService->uri());
327- return;
328- }
329- }
330- TheServices.push_back(adapterService);
331- debugs(93, 3, "registered eCAP module service: " << adapterService->uri());
332+ TheServices[adapterService->uri()] = adapterService; // may update old one
333+ debugs(93, 3, "stored eCAP module service: " << adapterService->uri());
334+ // We do not update AsyncServices here in case they are not configured.
335 }
336
337 void
338 Adaptation::Ecap::UnregisterAdapterService(const String& serviceUri)
339 {
340- typedef std::list<ServiceRep::AdapterService>::iterator ASI;
341- for (ASI s = TheServices.begin(); s != TheServices.end(); ++s) {
342- if (serviceUri == (*s)->uri().c_str()) {
343- TheServices.erase(s);
344- debugs(93, 3, "unregistered eCAP module service: " << serviceUri);
345- return;
346- }
347+ if (TheServices.erase(serviceUri.termedBuf())) {
348+ debugs(93, 3, "unregistered eCAP module service: " << serviceUri);
349+ AsyncServices.erase(serviceUri.termedBuf()); // no-op for non-async
350+ return;
351 }
352 debugs(93, 3, "failed to unregister eCAP module service: " << serviceUri);
353 }
354@@ -253,16 +324,16 @@
355 void
356 Adaptation::Ecap::CheckUnusedAdapterServices(const Adaptation::Services& cfgs)
357 {
358- typedef std::list<ServiceRep::AdapterService>::const_iterator ASCI;
359+ typedef AdapterServices::const_iterator ASCI;
360 for (ASCI loaded = TheServices.begin(); loaded != TheServices.end();
361 ++loaded) {
362 bool found = false;
363 for (Services::const_iterator cfged = cfgs.begin();
364 cfged != cfgs.end() && !found; ++cfged) {
365- found = (*cfged)->cfg().uri == (*loaded)->uri().c_str();
366+ found = (*cfged)->cfg().uri == loaded->second->uri().c_str();
367 }
368 if (!found)
369 debugs(93, DBG_IMPORTANT, "Warning: loaded eCAP service has no matching " <<
370- "ecap_service config option: " << (*loaded)->uri());
371+ "ecap_service config option: " << loaded->second->uri());
372 }
373 }
374
375=== modified file 'src/adaptation/ecap/XactionRep.cc'
376--- src/adaptation/ecap/XactionRep.cc 2013-06-03 14:05:16 +0000
377+++ src/adaptation/ecap/XactionRep.cc 2013-09-23 16:22:57 +0000
378@@ -2,19 +2,20 @@
379 * DEBUG: section 93 eCAP Interface
380 */
381 #include "squid.h"
382+#include "adaptation/Answer.h"
383+#include "adaptation/ecap/XactionRep.h"
384+#include "adaptation/ecap/Config.h"
385+#include "adaptation/Initiator.h"
386+#include "base/AsyncJobCalls.h"
387+#include "base/TextException.h"
388+#include "HttpRequest.h"
389+#include "HttpReply.h"
390+#include "SquidTime.h"
391 #include <libecap/common/area.h>
392 #include <libecap/common/delay.h>
393 #include <libecap/common/named_values.h>
394 #include <libecap/common/names.h>
395 #include <libecap/adapter/xaction.h>
396-#include "HttpRequest.h"
397-#include "HttpReply.h"
398-#include "SquidTime.h"
399-#include "adaptation/Answer.h"
400-#include "adaptation/ecap/XactionRep.h"
401-#include "adaptation/ecap/Config.h"
402-#include "adaptation/Initiator.h"
403-#include "base/TextException.h"
404
405 CBDATA_NAMESPACED_CLASS_INIT(Adaptation::Ecap::XactionRep, XactionRep);
406
407@@ -273,6 +274,25 @@
408 Adaptation::Initiate::swanSong();
409 }
410
411+void
412+Adaptation::Ecap::XactionRep::resume()
413+{
414+ // go async to gain exception protection and done()-based job destruction
415+ typedef NullaryMemFunT<Adaptation::Ecap::XactionRep> Dialer;
416+ AsyncCall::Pointer call = asyncCall(93, 5, "Adaptation::Ecap::XactionRep::doResume",
417+ Dialer(this, &Adaptation::Ecap::XactionRep::doResume));
418+ ScheduleCallHere(call);
419+}
420+
421+/// the guts of libecap::host::Xaction::resume() API implementation
422+/// which just goes async in Adaptation::Ecap::XactionRep::resume().
423+void
424+Adaptation::Ecap::XactionRep::doResume()
425+{
426+ Must(theMaster);
427+ theMaster->resume();
428+}
429+
430 libecap::Message &
431 Adaptation::Ecap::XactionRep::virgin()
432 {
433@@ -595,12 +615,6 @@
434 mustStop("adaptationAborted");
435 }
436
437-bool
438-Adaptation::Ecap::XactionRep::callable() const
439-{
440- return !done();
441-}
442-
443 void
444 Adaptation::Ecap::XactionRep::noteMoreBodySpaceAvailable(RefCount<BodyPipe> bp)
445 {
446
447=== modified file 'src/adaptation/ecap/XactionRep.h'
448--- src/adaptation/ecap/XactionRep.h 2012-10-04 11:10:17 +0000
449+++ src/adaptation/ecap/XactionRep.h 2013-09-23 16:22:57 +0000
450@@ -44,6 +44,7 @@
451 virtual void blockVirgin();
452 virtual void adaptationDelayed(const libecap::Delay &);
453 virtual void adaptationAborted();
454+ virtual void resume();
455 virtual void vbDiscard();
456 virtual void vbMake();
457 virtual void vbStopMaking();
458@@ -53,9 +54,6 @@
459 virtual void noteAbContentDone(bool atEnd);
460 virtual void noteAbContentAvailable();
461
462- // libecap::Callable API, via libecap::host::Xaction
463- virtual bool callable() const;
464-
465 // BodyProducer API
466 virtual void noteMoreBodySpaceAvailable(RefCount<BodyPipe> bp);
467 virtual void noteBodyConsumerAborted(RefCount<BodyPipe> bp);
468@@ -97,6 +95,8 @@
469 /// Return the adaptation meta headers and their values
470 void visitEachMetaHeader(libecap::NamedValueVisitor &visitor) const;
471
472+ void doResume();
473+
474 private:
475 AdapterXaction theMaster; // the actual adaptation xaction we represent
476 Adaptation::ServicePointer theService; ///< xaction's adaptation service
477
478=== modified file 'src/main.cc'
479--- src/main.cc 2013-06-07 04:35:25 +0000
480+++ src/main.cc 2013-09-16 00:12:40 +0000
481@@ -225,17 +225,15 @@
482 {
483
484 public:
485- SignalEngine(EventLoop &evtLoop) : loop(evtLoop) {}
486 virtual int checkEvents(int timeout);
487
488 private:
489- static void StopEventLoop(void * data) {
490- static_cast<SignalEngine *>(data)->loop.stop();
491+ static void StopEventLoop(void *) {
492+ if (EventLoop::Running)
493+ EventLoop::Running->stop();
494 }
495
496 void doShutdown(time_t wait);
497-
498- EventLoop &loop;
499 };
500
501 int
502@@ -1506,7 +1504,7 @@
503 /* main loop */
504 EventLoop mainLoop;
505
506- SignalEngine signalEngine(mainLoop);
507+ SignalEngine signalEngine;
508
509 mainLoop.registerEngine(&signalEngine);
510
511
512
This page took 0.130893 seconds and 4 git commands to generate.