From e1e90d26a3ffc69ba87262a25d23e6fa08bd5a0e Mon Sep 17 00:00:00 2001 From: Alex Rousskov Date: Fri, 17 Dec 2010 17:31:53 -0700 Subject: [PATCH] eCAP: (A) Support optional adapter parameters and (B) fix virgin body handling. (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. --- src/adaptation/Config.cc | 39 ++++--- src/adaptation/Config.h | 9 +- src/adaptation/Service.cc | 5 +- src/adaptation/Service.h | 8 +- src/adaptation/ServiceConfig.cc | 16 ++- src/adaptation/ServiceConfig.h | 4 +- src/adaptation/ecap/Config.cc | 21 +++- src/adaptation/ecap/Config.h | 20 +++- src/adaptation/ecap/ServiceRep.cc | 43 +++++++- src/adaptation/ecap/ServiceRep.h | 2 +- src/adaptation/ecap/XactionRep.cc | 168 ++++++++++++++++-------------- src/adaptation/ecap/XactionRep.h | 9 +- src/adaptation/forward.h | 1 + src/adaptation/icap/Config.cc | 2 +- src/adaptation/icap/Config.h | 2 +- src/adaptation/icap/ServiceRep.cc | 2 +- src/adaptation/icap/ServiceRep.h | 2 +- 17 files changed, 235 insertions(+), 118 deletions(-) diff --git a/src/adaptation/Config.cc b/src/adaptation/Config.cc index 2bdce463f1..612a1f3367 100644 --- a/src/adaptation/Config.cc +++ b/src/adaptation/Config.cc @@ -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::const_iterator VISCI; - const Vector &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 diff --git a/src/adaptation/Config.h b/src/adaptation/Config.h index cdc177797e..6ae34a4817 100644 --- a/src/adaptation/Config.h +++ b/src/adaptation/Config.h @@ -42,7 +42,8 @@ public: int service_revival_delay; int icap_uses_indirect_client; - Vector serviceConfigs; + typedef Vector 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); diff --git a/src/adaptation/Service.cc b/src/adaptation/Service.cc index 7b9729a221..9f446361df 100644 --- a/src/adaptation/Service.cc +++ b/src/adaptation/Service.cc @@ -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() diff --git a/src/adaptation/Service.h b/src/adaptation/Service.h index 59ea039f4c..3b9f47b0a0 100644 --- a/src/adaptation/Service.h +++ b/src/adaptation/Service.h @@ -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; diff --git a/src/adaptation/ServiceConfig.cc b/src/adaptation/ServiceConfig.cc index cb39b99c6d..cdc0850904 100644 --- a/src/adaptation/ServiceConfig.cc +++ b/src/adaptation/ServiceConfig.cc @@ -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; +} diff --git a/src/adaptation/ServiceConfig.h b/src/adaptation/ServiceConfig.h index ceff004743..9adbf37d0f 100644 --- a/src/adaptation/ServiceConfig.h +++ b/src/adaptation/ServiceConfig.h @@ -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 diff --git a/src/adaptation/ecap/Config.cc b/src/adaptation/ecap/Config.cc index c6ed5df8ca..dcdcc11d4b 100644 --- a/src/adaptation/ecap/Config.cc +++ b/src/adaptation/ecap/Config.cc @@ -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; } diff --git a/src/adaptation/ecap/Config.h b/src/adaptation/ecap/Config.h index 3b0618a0cd..ae16ad3033 100644 --- a/src/adaptation/ecap/Config.h +++ b/src/adaptation/ecap/Config.h @@ -7,12 +7,27 @@ #define SQUID_ECAP_CONFIG_H #include "adaptation/Config.h" +#include "adaptation/ServiceConfig.h" +#include +#include 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 Extension; // name=value in cfg + typedef std::list 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; diff --git a/src/adaptation/ecap/ServiceRep.cc b/src/adaptation/ecap/ServiceRep.cc index 6d8566d4c6..e95296c81d 100644 --- a/src/adaptation/ecap/ServiceRep.cc +++ b/src/adaptation/ecap/ServiceRep.cc @@ -4,6 +4,10 @@ #include "squid.h" #include #include +#include +#include +#include +#include "adaptation/ecap/Config.h" #include "adaptation/ecap/ServiceRep.h" #include "adaptation/ecap/XactionRep.h" #include "base/TextException.h" @@ -11,7 +15,40 @@ // configured eCAP service wrappers static std::list 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(cfg())); + theService->configure(cfgRep); + debugs(93,3, HERE << "starting eCAP service: " << theService->uri()); theService->start(); } else { diff --git a/src/adaptation/ecap/ServiceRep.h b/src/adaptation/ecap/ServiceRep.h index 9c858ccf26..a531b7693d 100644 --- a/src/adaptation/ecap/ServiceRep.h +++ b/src/adaptation/ecap/ServiceRep.h @@ -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 AdapterService; diff --git a/src/adaptation/ecap/XactionRep.cc b/src/adaptation/ecap/XactionRep.cc index 39786d813a..7a0876a49e 100644 --- a/src/adaptation/ecap/XactionRep.cc +++ b/src/adaptation/ecap/XactionRep.cc @@ -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 (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 bp) void Adaptation::Ecap::XactionRep::noteMoreBodyDataAvailable(RefCount 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 bp) void Adaptation::Ecap::XactionRep::noteBodyProductionEnded(RefCount 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 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(makingVb)); + + const BodyPipePointer &vp = theVirginRep.raw().body_pipe; + if (!vp) + buf.append(" !V", 3); + else + if (vp->stillConsuming(const_cast(this))) + buf.append(" Vc", 3); + else + buf.append(" V?", 3); + + if (vbProductionFinished) + buf.append(".", 1); + + + buf.Printf(" A%d", static_cast(proxyingAb)); if (proxyingAb == opOn) { MessageRep *rep = dynamic_cast(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(this))) + buf.append(" Ap", 3); + else + buf.append(" A?", 3); } buf.Printf(" %s%u]", id.Prefix, id.value); diff --git a/src/adaptation/ecap/XactionRep.h b/src/adaptation/ecap/XactionRep.h index a55f9e1df5..1a073502c1 100644 --- a/src/adaptation/ecap/XactionRep.h +++ b/src/adaptation/ecap/XactionRep.h @@ -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 diff --git a/src/adaptation/forward.h b/src/adaptation/forward.h index c9ddf65ad3..6b9b621a97 100644 --- a/src/adaptation/forward.h +++ b/src/adaptation/forward.h @@ -28,6 +28,7 @@ class Message; class Answer; typedef RefCount ServicePointer; +typedef RefCount ServiceConfigPointer; typedef RefCount ServiceGroupPointer; } // namespace Adaptation diff --git a/src/adaptation/icap/Config.cc b/src/adaptation/icap/Config.cc index 126a11f777..3f6b5dcd20 100644 --- a/src/adaptation/icap/Config.cc +++ b/src/adaptation/icap/Config.cc @@ -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); } diff --git a/src/adaptation/icap/Config.h b/src/adaptation/icap/Config.h index ffe5892f27..ad423c2619 100644 --- a/src/adaptation/icap/Config.h +++ b/src/adaptation/icap/Config.h @@ -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; diff --git a/src/adaptation/icap/ServiceRep.cc b/src/adaptation/icap/ServiceRep.cc index cb6131cbdc..243be4d2fa 100644 --- a/src/adaptation/icap/ServiceRep.cc +++ b/src/adaptation/icap/ServiceRep.cc @@ -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), diff --git a/src/adaptation/icap/ServiceRep.h b/src/adaptation/icap/ServiceRep.h index 67c746f78c..6039baec18 100644 --- a/src/adaptation/icap/ServiceRep.h +++ b/src/adaptation/icap/ServiceRep.h @@ -87,7 +87,7 @@ public: typedef RefCount Pointer; public: - ServiceRep(const Adaptation::ServiceConfig &config); + ServiceRep(ServiceConfigPointer aConfig); virtual ~ServiceRep(); virtual void finalize(); -- 2.47.2