]> git.pld-linux.org Git - packages/squid.git/blob - ecap-1p0-t2.patch
85e149e860950decc2ec50d01f8a410810f20f4b
[packages/squid.git] / ecap-1p0-t2.patch
1 Support libecap v1.0, allowing asynchronous adapters and eCAP version checks.
2
3 After these changes, Squid can support eCAP adapters built with libecap v1.0,
4 but stops supporting adapters built with earlier libecap versions (due to API
5 changes). The new libecap version allows Squid to better check the version of
6 the eCAP adapter being loaded as well as the version of the eCAP library being
7 used. This should help with migration to libecap v1.0.
8
9
10 Expose [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.11458 seconds and 2 git commands to generate.