]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
eCAP: (A) Support optional adapter parameters and (B) fix virgin body handling. take1
authorAlex Rousskov <rousskov@measurement-factory.com>
Sat, 18 Dec 2010 00:31:53 +0000 (17:31 -0700)
committerAlex Rousskov <rousskov@measurement-factory.com>
Sat, 18 Dec 2010 00:31:53 +0000 (17:31 -0700)
(A): Optional adapter-specific eCAP service parameters can be specified after
the Squid-recognized ones:

    ecap_service s1 respmod_precache ecap://...  name1=value1 name2=...

These extra parameters are passed as (name, opaque value) pairs to the
adapter, using the newly added libecap::Config API. Adapters should throw if
they cannot understand the parameters to protect users from typos in optional
Squid-recognized parameters.

Squid-recognized service parameters can also be passed to adapters. Adapters
can distinguish them from custom ones or typos because their names have host
IDs set. We currently only pass one Squid recognized service parameter called
"bypassable", with a boolean values of "1" or "0". This tells Adapter whether
Squid can try to bypass the adapter in case of problems. In our experience,
many real adapters benefit from such knowledge because they can be less strict
and more forgiving if Squid might ignore their decisions anyway.

To support optional adapter parameters for eCAP without bothering ICAP,
we now allow ICAP and eCAP to create protocol-specific configuration objects.
ICAP code uses old defaults. eCAP implements parsing of optional adapter
parameters and sharing them with adapters

As a side effect, service configuration objects are now refcounted and each
service (once created) is responsible for its config. The global collection of
configs is emptied once the services are created.

(B) eCAP transaction wrapper code (Ecap::XactionRep) failed to pass a few test
cases when dealing with virgin bodies. The code used complex state and
mishandled several proxyingVb, nil body_pipe, and stillConsuming value
combinations. proxyingVb was especially troubling because it was not clear
whether it refers to us receiving vb from Squid core or sending vb to the
adapter. The two states are related but different because we could be
receiving vb from core but not sending it to the adapter and vice versa.

I have removed proxyingVb completely as the body pipe state alone is
sufficient to understand our dealings with Squid core. I added makingVb to
track adapter vb needs.

Also improved Ecap::XactionRep status debugging.

17 files changed:
src/adaptation/Config.cc
src/adaptation/Config.h
src/adaptation/Service.cc
src/adaptation/Service.h
src/adaptation/ServiceConfig.cc
src/adaptation/ServiceConfig.h
src/adaptation/ecap/Config.cc
src/adaptation/ecap/Config.h
src/adaptation/ecap/ServiceRep.cc
src/adaptation/ecap/ServiceRep.h
src/adaptation/ecap/XactionRep.cc
src/adaptation/ecap/XactionRep.h
src/adaptation/forward.h
src/adaptation/icap/Config.cc
src/adaptation/icap/Config.h
src/adaptation/icap/ServiceRep.cc
src/adaptation/icap/ServiceRep.h

index 2bdce463f1ee6883da12941de131b6187b942811..612a1f3367f35e005e1736b070620bd71366bdc3 100644 (file)
@@ -48,10 +48,17 @@ bool Adaptation::Config::Enabled = false;
 char *Adaptation::Config::masterx_shared_name = NULL;
 int Adaptation::Config::service_iteration_limit = 16;
 
+
+Adaptation::ServiceConfig*
+Adaptation::Config::newServiceConfig() const
+{
+    return new ServiceConfig();
+}
+
 void
 Adaptation::Config::parseService()
 {
-    ServiceConfig *cfg = new ServiceConfig;
+    ServiceConfigPointer cfg = newServiceConfig();
     if (!cfg->parse()) {
         fatalf("%s:%d: malformed adaptation service configuration",
                cfg_filename, config_lineno);
@@ -67,10 +74,7 @@ Adaptation::Config::freeService()
 
     DetachServices();
 
-    while (!serviceConfigs.empty()) {
-        delete serviceConfigs.back();
-        serviceConfigs.pop_back();
-    }
+    serviceConfigs.clean();
 }
 
 void
@@ -91,23 +95,28 @@ void
 Adaptation::Config::finalize()
 {
     // create service reps from service configs
-    typedef Vector<ServiceConfig*>::const_iterator VISCI;
-    const Vector<ServiceConfig*> &configs = serviceConfigs;
-    debugs(93,3, HERE << "Found " << configs.size() << " service configs.");
+    int created = 0;
+
+    typedef ServiceConfigs::const_iterator VISCI;
+    const ServiceConfigs &configs = serviceConfigs;
     for (VISCI i = configs.begin(); i != configs.end(); ++i) {
-        const ServiceConfig &cfg = **i;
-        if (FindService(cfg.key) != NULL) {
+        const ServiceConfigPointer cfg = *i;
+        if (FindService(cfg->key) != NULL) {
             debugs(93,0, "ERROR: Duplicate adaptation service name: " <<
-                   cfg.key);
+                   cfg->key);
             continue; // TODO: make fatal
         }
-        ServicePointer s = createService(**i);
-        if (s != NULL)
+        ServicePointer s = createService(cfg);
+        if (s != NULL) {
             AllServices().push_back(s);
+            created++;
+        }
     }
 
-    debugs(93,3, HERE << "Created " << configs.size() <<
-           " message adaptation services.");
+    debugs(93,3, HERE << "Created " << created << " adaptation services");
+
+    // services remember their configs; we do not have to
+    serviceConfigs.clean();
 }
 
 // poor man for_each
index cdc177797e2703ef9cb2b4980305c016db33fd56..6ae34a481736a8a8de791dfea0ac01376be4fe8e 100644 (file)
@@ -42,7 +42,8 @@ public:
     int service_revival_delay;
     int icap_uses_indirect_client;
 
-    Vector<ServiceConfig*> serviceConfigs;
+    typedef Vector<ServiceConfigPointer> ServiceConfigs;
+    ServiceConfigs serviceConfigs;
 
     Config();
     virtual ~Config();
@@ -54,11 +55,15 @@ public:
 
     virtual void finalize();
 
+protected:
+    /// creates service configuration object that will parse and keep cfg info
+    virtual ServiceConfig *newServiceConfig() const;
+
 private:
     Config(const Config &); // unsupported
     Config &operator =(const Config &); // unsupported
 
-    virtual ServicePointer createService(const ServiceConfig &cfg) = 0;
+    virtual ServicePointer createService(ServiceConfigPointer cfg) = 0;
 
     static void ParseServiceGroup(ServiceGroupPointer group);
     static void FreeServiceGroups(void);
index 7b9729a2214fb49fd5d718af62d709ca4e49323f..9f446361df5ea8d2fb3b36a895a19a505096dc34 100644 (file)
@@ -7,9 +7,10 @@
 #include "adaptation/ServiceFilter.h"
 #include "adaptation/Service.h"
 
-Adaptation::Service::Service(const ServiceConfig &aConfig): theConfig(aConfig)
+Adaptation::Service::Service(ServiceConfigPointer aConfig): theConfig(aConfig)
 {
-    debugs(93,3, HERE << "creating adaptation service " << theConfig.key);
+    Must(theConfig != NULL);
+    debugs(93,3, HERE << "creating adaptation service " << cfg().key);
 }
 
 Adaptation::Service::~Service()
index 59ea039f4c778e51732e3e017f9ee4b8913c66ae..3b9f47b0a0b58a8122f760e936a7aef4f8f01312 100644 (file)
@@ -24,7 +24,7 @@ public:
     typedef String Id;
 
 public:
-    Service(const ServiceConfig &aConfig);
+    explicit Service(ServiceConfigPointer aConfig);
     virtual ~Service();
 
     virtual bool probed() const = 0; // see comments above
@@ -41,7 +41,7 @@ public:
     // called by transactions to report service failure
     virtual void noteFailure() = 0;
 
-    const ServiceConfig &cfg() const { return theConfig; }
+    const ServiceConfig &cfg() const { return *theConfig; }
 
     virtual void finalize(); // called after creation
 
@@ -52,10 +52,10 @@ public:
     virtual bool detached() const = 0;
 
 protected:
-    ServiceConfig &writeableCfg() { return theConfig; }
+    ServiceConfig &writeableCfg() { return *theConfig; }
 
 private:
-    ServiceConfig theConfig;
+    ServiceConfigPointer theConfig;
 };
 
 typedef Service::Pointer ServicePointer;
index cb39b99c6d8a182cac397e80ebc8dcdd8a6cca75..cdc085090461e4dfa3d6d17a6e8fd02070495bd4 100644 (file)
@@ -101,10 +101,9 @@ Adaptation::ServiceConfig::parse()
             grokked = grokBool(ipv6, name, value);
             if (grokked && ipv6 && !Ip::EnableIpv6)
                 debugs(3, DBG_IMPORTANT, "WARNING: IPv6 is disabled. ICAP service option ignored.");
-        } else {
-            debugs(3, 0, cfg_filename << ':' << config_lineno << ": " <<
-                   "unknown adaptation service option: " << name << '=' << value);
-        }
+        } else
+            grokked = grokExtension(name, value);
+
         if (!grokked)
             return false;
     }
@@ -246,3 +245,12 @@ Adaptation::ServiceConfig::grokBool(bool &var, const char *name, const char *val
 
     return true;
 }
+
+bool
+Adaptation::ServiceConfig::grokExtension(const char *name, const char *value)
+{
+    // we do not accept extensions by default
+    debugs(3, 0, cfg_filename << ':' << config_lineno << ": " <<
+           "unknown adaptation service option: " << name << '=' << value);
+    return false;
+}
index ceff004743d1824f5bf8c6eefcb5134be266dc10..9adbf37d0fb67bc9e5ef27db75b6eb5dd89b7cbf 100644 (file)
@@ -9,7 +9,7 @@ namespace Adaptation
 {
 
 // manages adaptation service configuration in squid.conf
-class ServiceConfig
+class ServiceConfig: public RefCountable
 {
 public:
     ServiceConfig();
@@ -42,6 +42,8 @@ protected:
     /// interpret parsed values
     bool grokBool(bool &var, const char *name, const char *value);
     bool grokUri(const char *value);
+    /// handle name=value configuration option with name unknown to Squid
+    virtual bool grokExtension(const char *name, const char *value);
 };
 
 } // namespace Adaptation
index c6ed5df8ca7246c108ce2c7b78220c584c98ee14..dcdcc11d4b535c1b901f61ee148f34b54e1f60aa 100644 (file)
@@ -26,10 +26,25 @@ Adaptation::Ecap::Config::finalize()
     CheckUnusedAdapterServices(AllServices());
 }
 
+Adaptation::ServiceConfig *
+Adaptation::Ecap::Config::newServiceConfig() const
+{
+    return new ServiceConfig();
+}
+
 Adaptation::ServicePointer
-Adaptation::Ecap::Config::createService(const Adaptation::ServiceConfig &cfg)
+Adaptation::Ecap::Config::createService(ServiceConfigPointer cfg)
+{
+    return new Adaptation::Ecap::ServiceRep(cfg);
+}
+
+
+/* ServiceConfig */
+
+bool
+Adaptation::Ecap::ServiceConfig::grokExtension(const char *name, const char *value)
 {
-    Adaptation::ServicePointer s = new Adaptation::Ecap::ServiceRep(cfg);
-    return s.getRaw();
+    extensions.push_back(std::make_pair(name, value));
+    return true;
 }
 
index 3b0618a0cd4d2e7469b4f407698edd6d517661fe..ae16ad3033737cc1ed90d6912e51662a37a7c18a 100644 (file)
@@ -7,12 +7,27 @@
 #define SQUID_ECAP_CONFIG_H
 
 #include "adaptation/Config.h"
+#include "adaptation/ServiceConfig.h"
+#include <list>
+#include <utility>
 
 namespace Adaptation
 {
 namespace Ecap
 {
 
+class ServiceConfig: public Adaptation::ServiceConfig {
+public:
+    // Adaptation::ServiceConfig API
+    virtual bool grokExtension(const char *name, const char *value);
+
+public:
+    typedef std::pair<std::string, std::string> Extension; // name=value in cfg
+    typedef std::list<Extension> Extensions;
+    Extensions extensions;
+};
+
+
 class Config: public Adaptation::Config
 {
 
@@ -22,11 +37,14 @@ public:
 
     virtual void finalize();
 
+protected:
+    virtual Adaptation::ServiceConfig *newServiceConfig() const;
+
 private:
     Config(const Config &); // not implemented
     Config &operator =(const Config &); // not implemented
 
-    virtual Adaptation::ServicePointer createService(const Adaptation::ServiceConfig &cfg);
+    virtual Adaptation::ServicePointer createService(ServiceConfigPointer cfg);
 };
 
 extern Config TheConfig;
index 6d8566d4c6142d870b3d73055d06a34cf278a535..e95296c81d2509d0bceee2aacbc3c313f85d04e2 100644 (file)
@@ -4,6 +4,10 @@
 #include "squid.h"
 #include <list>
 #include <libecap/adapter/service.h>
+#include <libecap/common/config.h>
+#include <libecap/common/name.h>
+#include <libecap/common/named_values.h>
+#include "adaptation/ecap/Config.h"
 #include "adaptation/ecap/ServiceRep.h"
 #include "adaptation/ecap/XactionRep.h"
 #include "base/TextException.h"
 // configured eCAP service wrappers
 static std::list<Adaptation::Ecap::ServiceRep::AdapterService> TheServices;
 
-Adaptation::Ecap::ServiceRep::ServiceRep(const Adaptation::ServiceConfig &cfg):
+/// wraps Adaptation::Ecap::ServiceConfig to allow eCAP visitors
+class ConfigRep: public libecap::Config
+{
+public:
+    typedef Adaptation::Ecap::ServiceConfig Master;
+    typedef libecap::Name Name;
+    typedef libecap::Area Area;
+
+    ConfigRep(const Master &aMaster): master(aMaster) {}
+
+    // libecap::Config API
+    virtual void visitEach(libecap::NamedValueVisitor &visitor) const;
+
+    const Master &master; ///< the configuration being wrapped
+};
+
+void
+ConfigRep::visitEach(libecap::NamedValueVisitor &visitor) const
+{
+    // we may supply the params we know about too, but only if we set host ID
+    static const Name optBypass("bypassable");
+    if (!optBypass.assignedHostId())
+         optBypass.assignHostId(1); // allows adapter to safely ignore this
+    visitor.visit(optBypass, Area(master.bypass ? "1" : "0", 1));
+
+    // visit adapter-specific options (i.e., those not recognized by Squid)
+    typedef Master::Extensions::const_iterator MECI;
+    for (MECI i = master.extensions.begin(); i != master.extensions.end(); ++i)
+        visitor.visit(Name(i->first), Area::FromTempString(i->second));
+}
+
+
+
+Adaptation::Ecap::ServiceRep::ServiceRep(ServiceConfigPointer cfg):
         /*AsyncJob("Adaptation::Ecap::ServiceRep"),*/ Adaptation::Service(cfg),
         isDetached(false)
 {
@@ -32,6 +69,10 @@ Adaptation::Ecap::ServiceRep::finalize()
     Adaptation::Service::finalize();
     theService = FindAdapterService(cfg().uri);
     if (theService) {
+        debugs(93,3, HERE << "configuring eCAP service: " << theService->uri());
+        ConfigRep cfgRep(dynamic_cast<const ServiceConfig&>(cfg()));
+        theService->configure(cfgRep);
+
         debugs(93,3, HERE << "starting eCAP service: " << theService->uri());
         theService->start();
     } else {
index 9c858ccf268835fce6a28a336f1ab2a410bbb274..a531b7693da9feaed98f7f87ca05a28efc497429 100644 (file)
@@ -23,7 +23,7 @@ namespace Ecap
 class ServiceRep : public Adaptation::Service
 {
 public:
-    ServiceRep(const Adaptation::ServiceConfig &config);
+    ServiceRep(ServiceConfigPointer aConfig);
     virtual ~ServiceRep();
 
     typedef libecap::shared_ptr<libecap::adapter::Service> AdapterService;
index 39786d813aef9acd88320c8d65c2e56cedb85bc8..7a0876a49e71daadcddd80c8b07da521f39f733b 100644 (file)
@@ -22,9 +22,9 @@ Adaptation::Ecap::XactionRep::XactionRep(
         Adaptation::Initiate("Adaptation::Ecap::XactionRep"),
         theService(aService),
         theVirginRep(virginHeader), theCauseRep(NULL),
-        proxyingVb(opUndecided), proxyingAb(opUndecided),
+        makingVb(opUndecided), proxyingAb(opUndecided),
         adaptHistoryId(-1),
-        canAccessVb(false),
+        vbProductionFinished(false),
         abProductionFinished(false), abProductionAtEnd(false)
 {
     if (virginCause)
@@ -58,10 +58,8 @@ Adaptation::Ecap::XactionRep::start()
 {
     Must(theMaster);
 
-    if (theVirginRep.raw().body_pipe != NULL)
-        canAccessVb = true; /// assumes nobody is consuming; \todo check
-    else
-        proxyingVb = opNever;
+    if (!theVirginRep.raw().body_pipe)
+        makingVb = opNever; // there is nothing to deliver
 
     const HttpRequest *request = dynamic_cast<const HttpRequest*> (theCauseRep ?
                                  theCauseRep->raw().header : theVirginRep.raw().header);
@@ -89,13 +87,9 @@ Adaptation::Ecap::XactionRep::swanSong()
         }
     }
 
-    if (proxyingVb == opOn) {
-        BodyPipe::Pointer body_pipe = theVirginRep.raw().body_pipe;
-        if (body_pipe != NULL) {
-            Must(body_pipe->stillConsuming(this));
-            stopConsumingFrom(body_pipe);
-        }
-    }
+    BodyPipe::Pointer &body_pipe = theVirginRep.raw().body_pipe;
+    if (body_pipe != NULL && body_pipe->stillConsuming(this))
+        stopConsumingFrom(body_pipe);
 
     terminateMaster();
 
@@ -150,33 +144,54 @@ Adaptation::Ecap::XactionRep::terminateMaster()
 bool
 Adaptation::Ecap::XactionRep::doneAll() const
 {
-    return proxyingVb >= opComplete && proxyingAb >= opComplete &&
+    return makingVb >= opComplete && proxyingAb >= opComplete &&
            Adaptation::Initiate::doneAll();
 }
 
-// stops receiving virgin and enables auto-consumption
+// stops receiving virgin and enables auto-consumption, dropping any vb bytes
 void
-Adaptation::Ecap::XactionRep::dropVirgin(const char *reason)
+Adaptation::Ecap::XactionRep::sinkVb(const char *reason)
 {
-    debugs(93,4, HERE << "because " << reason << "; status:" << status());
+    debugs(93,4, HERE << "sink for " << reason << "; status:" << status());
 
-    BodyPipePointer &p = theVirginRep.raw().body_pipe;
-    Must(p != NULL);
-    p->enableAutoConsumption();
+    // we reset raw().body_pipe when we are done, so use this one for checking
+    const BodyPipePointer &permPipe = theVirginRep.raw().header->body_pipe;
+    if (permPipe != NULL)
+        permPipe->enableAutoConsumption();
 
-    if (proxyingVb == opOn) {
-        Must(p->stillConsuming(this));
-        stopConsumingFrom(p);
-        proxyingVb = opComplete;
-    } else {
-        Must(!p->stillConsuming(this));
-        if (proxyingVb == opUndecided)
-            proxyingVb = opNever;
+    forgetVb(reason);
+}
+
+// stops receiving virgin but preserves it for others to use
+void
+Adaptation::Ecap::XactionRep::preserveVb(const char *reason)
+{
+    debugs(93,4, HERE << "preserve for " << reason << "; status:" << status());
+
+    // we reset raw().body_pipe when we are done, so use this one for checking
+    const BodyPipePointer &permPipe = theVirginRep.raw().header->body_pipe;
+    if (permPipe != NULL) {
+        // if libecap consumed, we cannot preserve
+        Must(!permPipe->consumedSize());
     }
 
-    canAccessVb = false;
+    forgetVb(reason);
+}
+
+// disassociates us from vb; the last step of sinking or preserving vb
+void
+Adaptation::Ecap::XactionRep::forgetVb(const char *reason)
+{
+    debugs(93,9, HERE << "forget vb " << reason << "; status:" << status());
 
-    // called from adapter handler so does not inform adapter
+    BodyPipePointer &p = theVirginRep.raw().body_pipe;
+    if (p != NULL && p->stillConsuming(this))
+        stopConsumingFrom(p);
+
+    if (makingVb == opUndecided)
+        makingVb = opNever;
+    else if (makingVb == opOn)
+        makingVb = opComplete;
 }
 
 void
@@ -186,23 +201,11 @@ Adaptation::Ecap::XactionRep::useVirgin()
     Must(proxyingAb == opUndecided);
     proxyingAb = opNever;
 
-    BodyPipePointer &vbody_pipe = theVirginRep.raw().body_pipe;
+    preserveVb("useVirgin");
 
     HttpMsg *clone = theVirginRep.raw().header->clone();
     // check that clone() copies the pipe so that we do not have to
-    Must(!vbody_pipe == !clone->body_pipe);
-
-    if (proxyingVb == opOn) {
-        Must(vbody_pipe->stillConsuming(this));
-        // if libecap consumed, we cannot shortcircuit
-        Must(!vbody_pipe->consumedSize());
-        stopConsumingFrom(vbody_pipe);
-        canAccessVb = false;
-        proxyingVb = opComplete;
-    } else if (proxyingVb == opUndecided) {
-        vbody_pipe = NULL; // it is not our pipe anymore
-        proxyingVb = opNever;
-    }
+    Must(!theVirginRep.raw().header->body_pipe == !clone->body_pipe);
 
     sendAnswer(Answer::Forward(clone));
     Must(done());
@@ -242,7 +245,7 @@ Adaptation::Ecap::XactionRep::blockVirgin()
     Must(proxyingAb == opUndecided);
     proxyingAb = opNever;
 
-    dropVirgin("blockVirgin");
+    sinkVb("blockVirgin");
 
     sendAnswer(Answer::Block(service().cfg().key));
     Must(done());
@@ -251,43 +254,45 @@ Adaptation::Ecap::XactionRep::blockVirgin()
 void
 Adaptation::Ecap::XactionRep::vbDiscard()
 {
-    Must(proxyingVb == opUndecided);
+    Must(makingVb == opUndecided);
     // if adapter does not need vb, we do not need to send it
-    dropVirgin("vbDiscard");
-    Must(proxyingVb == opNever);
+    sinkVb("vbDiscard");
+    Must(makingVb == opNever);
 }
 
 void
 Adaptation::Ecap::XactionRep::vbMake()
 {
-    Must(proxyingVb == opUndecided);
+    Must(makingVb == opUndecided);
     BodyPipePointer &p = theVirginRep.raw().body_pipe;
     Must(p != NULL);
-    Must(p->setConsumerIfNotLate(this)); // to make vb, we must receive vb
-    proxyingVb = opOn;
+    Must(p->setConsumerIfNotLate(this)); // to deliver vb, we must receive vb
+    makingVb = opOn;
 }
 
 void
 Adaptation::Ecap::XactionRep::vbStopMaking()
 {
+    Must(makingVb == opOn);
     // if adapter does not need vb, we do not need to receive it
-    dropVirgin("vbStopMaking");
-    Must(proxyingVb == opComplete);
+    sinkVb("vbStopMaking");
+    Must(makingVb == opComplete);
 }
 
 void
 Adaptation::Ecap::XactionRep::vbMakeMore()
 {
-    Must(proxyingVb == opOn); // cannot make more if done proxying
+    Must(makingVb == opOn); // cannot make more if done proxying
     // we cannot guarantee more vb, but we can check that there is a chance
-    Must(!theVirginRep.raw().body_pipe->exhausted());
+    const BodyPipePointer &p = theVirginRep.raw().body_pipe;
+    Must(p != NULL && p->stillConsuming(this)); // we are plugged in
+    Must(!p->productionEnded() && p->mayNeedMoreData()); // and may get more
 }
 
 libecap::Area
 Adaptation::Ecap::XactionRep::vbContent(libecap::size_type o, libecap::size_type s)
 {
-    Must(canAccessVb);
-    // We may not be proxyingVb yet. It should be OK, but see vbContentShift().
+    // We may not be makingVb yet. It should be OK, but see vbContentShift().
 
     const BodyPipePointer &p = theVirginRep.raw().body_pipe;
     Must(p != NULL);
@@ -311,8 +316,7 @@ Adaptation::Ecap::XactionRep::vbContent(libecap::size_type o, libecap::size_type
 void
 Adaptation::Ecap::XactionRep::vbContentShift(libecap::size_type n)
 {
-    Must(canAccessVb);
-    // We may not be proxyingVb yet. It should be OK now, but if BodyPipe
+    // We may not be makingVb yet. It should be OK now, but if BodyPipe
     // consume() requirements change, we would have to return empty vbContent
     // until the adapter registers as a consumer
 
@@ -392,7 +396,7 @@ Adaptation::Ecap::XactionRep::noteBodyConsumerAborted(RefCount<BodyPipe> bp)
 void
 Adaptation::Ecap::XactionRep::noteMoreBodyDataAvailable(RefCount<BodyPipe> bp)
 {
-    Must(proxyingVb == opOn);
+    Must(makingVb == opOn); // or we would not be registered as a consumer
     Must(theMaster);
     theMaster->noteVbContentAvailable();
 }
@@ -400,19 +404,19 @@ Adaptation::Ecap::XactionRep::noteMoreBodyDataAvailable(RefCount<BodyPipe> bp)
 void
 Adaptation::Ecap::XactionRep::noteBodyProductionEnded(RefCount<BodyPipe> bp)
 {
-    Must(proxyingVb == opOn);
+    Must(makingVb == opOn); // or we would not be registered as a consumer
     Must(theMaster);
     theMaster->noteVbContentDone(true);
-    proxyingVb = opComplete;
+    vbProductionFinished = true;
 }
 
 void
 Adaptation::Ecap::XactionRep::noteBodyProducerAborted(RefCount<BodyPipe> bp)
 {
-    Must(proxyingVb == opOn);
+    Must(makingVb == opOn); // or we would not be registered as a consumer
     Must(theMaster);
     theMaster->noteVbContentDone(false);
-    proxyingVb = opComplete;
+    vbProductionFinished = true;
 }
 
 void
@@ -446,24 +450,34 @@ Adaptation::Ecap::XactionRep::status() const
 
     buf.append(" [", 2);
 
-    if (proxyingVb == opOn) {
-        const BodyPipePointer &vp = theVirginRep.raw().body_pipe;
-        if (!canAccessVb)
-            buf.append("x", 1);
-        if (vp != NULL) { // XXX: but may not be stillConsuming()
-            buf.append("Vb", 2);
-        } else
-            buf.append("V.", 2);
-    }
+    if (makingVb)
+        buf.Printf("M%d", static_cast<int>(makingVb));
+
+    const BodyPipePointer &vp = theVirginRep.raw().body_pipe;
+    if (!vp)
+        buf.append(" !V", 3);
+    else
+    if (vp->stillConsuming(const_cast<XactionRep*>(this)))
+        buf.append(" Vc", 3);
+    else
+        buf.append(" V?", 3);
+
+    if (vbProductionFinished)
+        buf.append(".", 1);
+
+
+    buf.Printf(" A%d", static_cast<int>(proxyingAb));
 
     if (proxyingAb == opOn) {
         MessageRep *rep = dynamic_cast<MessageRep*>(theAnswerRep.get());
         Must(rep);
         const BodyPipePointer &ap = rep->raw().body_pipe;
-        if (ap != NULL) { // XXX: but may not be stillProducing()
-            buf.append(" Ab", 3);
-        } else
-            buf.append(" A.", 3);
+        if (!ap)
+            buf.append(" !A", 3);
+        else if (ap->stillProducing(const_cast<XactionRep*>(this)))
+            buf.append(" Ap", 3);
+        else
+            buf.append(" A?", 3);
     }
 
     buf.Printf(" %s%u]", id.Prefix, id.value);
index a55f9e1df53d649929ead42cdbe551cd4788fa6a..1a073502c1ac73f0247a7b9ab42c1d2765fb38f3 100644 (file)
@@ -78,7 +78,10 @@ protected:
 
     Adaptation::Message &answer();
 
-    void dropVirgin(const char *reason);
+    void sinkVb(const char *reason);
+    void preserveVb(const char *reason);
+    void forgetVb(const char *reason);
+
     void moveAbContent();
 
     void terminateMaster();
@@ -95,10 +98,10 @@ private:
     MessagePtr theAnswerRep;
 
     typedef enum { opUndecided, opOn, opComplete, opNever } OperationState;
-    OperationState proxyingVb; // delivering virgin body from core to adapter
+    OperationState makingVb; //< delivering virgin body from pipe to adapter
     OperationState proxyingAb; // delivering adapted body from adapter to core
     int adaptHistoryId;        ///< adaptation history slot reservation
-    bool canAccessVb;          // virgin BodyPipe content is accessible
+    bool vbProductionFinished; // whether there can be no more vb bytes
     bool abProductionFinished; // whether adapter has finished producing ab
     bool abProductionAtEnd;    // whether adapter produced a complete ab
 
index c9ddf65ad3ef259c8e341fd295a66f45dfdefffd..6b9b621a976d8b0f22a27172ef3bec349c7936f3 100644 (file)
@@ -28,6 +28,7 @@ class Message;
 class Answer;
 
 typedef RefCount<Service> ServicePointer;
+typedef RefCount<ServiceConfig> ServiceConfigPointer;
 typedef RefCount<ServiceGroup> ServiceGroupPointer;
 
 } // namespace Adaptation
index 126a11f777490d2ff9689cd9f0db650dbb01748f..3f6b5dcd200d5eed4d9019448e51d7195a51f27c 100644 (file)
@@ -58,7 +58,7 @@ Adaptation::Icap::Config::~Config()
 }
 
 Adaptation::ServicePointer
-Adaptation::Icap::Config::createService(const Adaptation::ServiceConfig &cfg)
+Adaptation::Icap::Config::createService(ServiceConfigPointer cfg)
 {
     return new Adaptation::Icap::ServiceRep(cfg);
 }
index ffe5892f27e84c37389576ee032bd3b96e6e1dbc..ad423c2619f271b4c8277cdb599d2cc73426e4a3 100644 (file)
@@ -76,7 +76,7 @@ private:
     Config(const Config &); // not implemented
     Config &operator =(const Config &); // not implemented
 
-    virtual Adaptation::ServicePointer createService(const Adaptation::ServiceConfig &cfg);
+    virtual Adaptation::ServicePointer createService(ServiceConfigPointer cfg);
 };
 
 extern Config TheConfig;
index cb6131cbdcd6bfc505ec982772264cce9b4ab681..243be4d2faf89044b4a9a72ecd31b8689587a38b 100644 (file)
@@ -15,7 +15,7 @@
 
 CBDATA_NAMESPACED_CLASS_INIT(Adaptation::Icap, ServiceRep);
 
-Adaptation::Icap::ServiceRep::ServiceRep(const Adaptation::ServiceConfig &svcCfg):
+Adaptation::Icap::ServiceRep::ServiceRep(ServiceConfigPointer svcCfg):
         AsyncJob("Adaptation::Icap::ServiceRep"), Adaptation::Service(svcCfg),
         theOptions(NULL), theOptionsFetcher(0), theLastUpdate(0),
         isSuspended(0), notifying(false),
index 67c746f78c7c9c8ba2e76315dd2b98d8d77cbdf9..6039baec187d9d859b033a290adfa8143f29ef63 100644 (file)
@@ -87,7 +87,7 @@ public:
     typedef RefCount<ServiceRep> Pointer;
 
 public:
-    ServiceRep(const Adaptation::ServiceConfig &config);
+    ServiceRep(ServiceConfigPointer aConfig);
     virtual ~ServiceRep();
 
     virtual void finalize();