From: Alex Rousskov Date: Wed, 30 Mar 2011 17:43:55 +0000 (-0600) Subject: Support dynamic adaptation plans that cover multiple vectoring points. X-Git-Tag: take06~27^2~52 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=53340485c36f6d7eba9a88a1365bc0ed2824d5e7;p=thirdparty%2Fsquid.git Support dynamic adaptation plans that cover multiple vectoring points. The dynamic adaptation plan is specified using X-Next-Services ICAP header or eCAP meta-info, as usual. A REQMOD adaptation service may construct an adaptation plan that starts with REQMOD and ends with RESPMOD. Multiple adaptations may be planned at each point. The natural transaction handling order must be preserved: the plan cannot go from RESPMOD back to REQMOD. Adaptation::History object is used to keep future plan steps when crossing vectoring points. --- diff --git a/src/adaptation/AccessCheck.cc b/src/adaptation/AccessCheck.cc index 1f880ba52a..d63199e01f 100644 --- a/src/adaptation/AccessCheck.cc +++ b/src/adaptation/AccessCheck.cc @@ -65,7 +65,31 @@ void Adaptation::AccessCheck::start() { AsyncJob::start(); - check(); + + if (!usedDynamicRules()) + check(); +} + +/// returns true if previous services configured dynamic chaining "rules" +bool +Adaptation::AccessCheck::usedDynamicRules() +{ + Adaptation::History::Pointer ah = filter.request->adaptHistory(); + if (!ah) + return false; // dynamic rules not enabled or not triggered + + DynamicGroupCfg services; + if (!ah->extractFutureServices(services)) { // clears history + debugs(85,9, HERE << "no service-proposed rules stored"); + return false; // earlier service did not plan for the future + } + + debugs(85,3, HERE << "using stored service-proposed rules: " << services); + + ServiceGroupPointer g = new DynamicServiceChain(services, filter); + callBack(g); + Must(done()); + return true; } /// Walk the access rules list to find rules with applicable service groups diff --git a/src/adaptation/AccessCheck.h b/src/adaptation/AccessCheck.h index 11f89af5df..e0e4793daf 100644 --- a/src/adaptation/AccessCheck.h +++ b/src/adaptation/AccessCheck.h @@ -55,6 +55,7 @@ protected: virtual void start(); virtual bool doneAll() const { return false; } /// not done until mustStop + bool usedDynamicRules(); void check(); private: diff --git a/src/adaptation/DynamicGroupCfg.cc b/src/adaptation/DynamicGroupCfg.cc new file mode 100644 index 0000000000..9bcba5c0b3 --- /dev/null +++ b/src/adaptation/DynamicGroupCfg.cc @@ -0,0 +1,22 @@ +#include "config.h" + +#include "adaptation/DynamicGroupCfg.h" + +void +Adaptation::DynamicGroupCfg::add(const String &item) +{ + if (services.empty()) { // first item + id = item; + } else { + id.append(','); + id.append(item); + } + services.push_back(item); +} + +void +Adaptation::DynamicGroupCfg::clear() +{ + id.clean(); + services.clean(); +} diff --git a/src/adaptation/DynamicGroupCfg.h b/src/adaptation/DynamicGroupCfg.h new file mode 100644 index 0000000000..a2ec4b61d4 --- /dev/null +++ b/src/adaptation/DynamicGroupCfg.h @@ -0,0 +1,34 @@ +#ifndef SQUID_ADAPTATION__DYNAMIC_GROUP_CFG_H +#define SQUID_ADAPTATION__DYNAMIC_GROUP_CFG_H + +#include "Array.h" +#include "SquidString.h" + +namespace Adaptation +{ + +/// DynamicServiceGroup configuration to remember future dynamic chains +class DynamicGroupCfg +{ +public: + typedef Vector Store; + typedef String Id; + + Id id; ///< group id + Store services; ///< services in the group + + bool empty() const { return services.empty(); } ///< no services added + void add(const String &item); ///< updates group id and services + void clear(); ///< makes the config empty +}; + +inline +std::ostream &operator <<(std::ostream &os, const DynamicGroupCfg &cfg) +{ + return os << cfg.id; +} + +} // namespace Adaptation + +#endif /* SQUID_ADAPTATION__DYNAMIC_GROUP_CFG_H */ + diff --git a/src/adaptation/History.cc b/src/adaptation/History.cc index d106603f4c..dd97cda398 100644 --- a/src/adaptation/History.cc +++ b/src/adaptation/History.cc @@ -148,3 +148,22 @@ void Adaptation::History::recordMeta(const HttpHeader *lm) allMeta.update(lm, NULL); allMeta.compact(); } + +void +Adaptation::History::setFutureServices(const DynamicGroupCfg &services) +{ + if (!theFutureServices.empty()) + debugs(93,3, HERE << "old future services: " << theFutureServices); + debugs(93,3, HERE << "new future services: " << services); + theFutureServices = services; // may be empty +} + +bool Adaptation::History::extractFutureServices(DynamicGroupCfg &value) +{ + if (theFutureServices.empty()) + return false; + + value = theFutureServices; + theFutureServices.clear(); + return true; +} diff --git a/src/adaptation/History.h b/src/adaptation/History.h index ec254e18a6..ffe3198f45 100644 --- a/src/adaptation/History.h +++ b/src/adaptation/History.h @@ -1,6 +1,7 @@ #ifndef SQUID_ADAPT_HISTORY_H #define SQUID_ADAPT_HISTORY_H +#include "adaptation/DynamicGroupCfg.h" #include "Array.h" #include "HttpHeader.h" #include "RefCount.h" @@ -51,6 +52,12 @@ public: /// All REQMOD and RESPMOD meta headers merged. Last field wins conflicts. HttpHeader allMeta; + /// sets future services for the Adaptation::AccessCheck to notice + void setFutureServices(const DynamicGroupCfg &services); + + /// returns true, fills the value, and resets iff future services were set + bool extractFutureServices(DynamicGroupCfg &services); + private: /// single Xaction stats (i.e., a historical record entry) class Entry @@ -80,6 +87,7 @@ private: String theXxValue; ///< value part of the cross-xactional database record String theNextServices; ///< services Adaptation::Iterator must use next + DynamicGroupCfg theFutureServices; ///< services AccessCheck must use }; } // namespace Adaptation diff --git a/src/adaptation/Iterator.cc b/src/adaptation/Iterator.cc index 4ca0301e4f..74b713dfc6 100644 --- a/src/adaptation/Iterator.cc +++ b/src/adaptation/Iterator.cc @@ -209,8 +209,19 @@ bool Adaptation::Iterator::updatePlan(bool adopt) } debugs(85,3, HERE << "retiring old plan: " << thePlan); - theGroup = new DynamicServiceChain(services, theGroup); // refcounted - thePlan = ServicePlan(theGroup, filter()); + + Adaptation::ServiceFilter filter = this->filter(); + DynamicGroupCfg current, future; + DynamicServiceChain::Split(filter, services, current, future); + + if (!future.empty()) { + ah->setFutureServices(future); + debugs(85,3, HERE << "noted future service-proposed plan: " << future); + } + + // use the current config even if it is empty; we must replace the old plan + theGroup = new DynamicServiceChain(current, filter); // refcounted + thePlan = ServicePlan(theGroup, filter); debugs(85,3, HERE << "adopted service-proposed plan: " << thePlan); return true; } diff --git a/src/adaptation/Makefile.am b/src/adaptation/Makefile.am index 03f2facbc3..70c735b747 100644 --- a/src/adaptation/Makefile.am +++ b/src/adaptation/Makefile.am @@ -24,6 +24,8 @@ libadaptation_la_SOURCES = \ Answer.h \ Config.cc \ Config.h \ + DynamicGroupCfg.cc \ + DynamicGroupCfg.h \ Elements.cc \ Elements.h \ forward.h \ diff --git a/src/adaptation/ServiceGroups.cc b/src/adaptation/ServiceGroups.cc index a680b17e9c..4716b4c393 100644 --- a/src/adaptation/ServiceGroups.cc +++ b/src/adaptation/ServiceGroups.cc @@ -1,14 +1,13 @@ #include "squid.h" #include "ConfigParser.h" -#include "Array.h" // really Vector #include "adaptation/Config.h" #include "adaptation/AccessRule.h" +#include "adaptation/DynamicGroupCfg.h" #include "adaptation/Service.h" #include "adaptation/ServiceFilter.h" #include "adaptation/ServiceGroups.h" -#define ServiceGroup ServiceGroup Adaptation::ServiceGroup::ServiceGroup(const String &aKind, bool allSame): kind(aKind), method(methodNone), point(pointNone), @@ -209,28 +208,51 @@ Adaptation::ServiceChain::ServiceChain(): ServiceGroup("adaptation chain", false } -/* ServiceChain */ +/* DynamicServiceChain */ -Adaptation::DynamicServiceChain::DynamicServiceChain(const String &ids, - const ServiceGroupPointer prev) +Adaptation::DynamicServiceChain::DynamicServiceChain( + const DynamicGroupCfg &cfg, const ServiceFilter &filter) { kind = "dynamic adaptation chain"; // TODO: optimize by using String const - id = ids; // use services ids as the dynamic group ID + id = cfg.id; // use services ids as the dynamic group ID + services = cfg.services; // initialize cache to improve consistency checks in finalize() - if (prev != NULL) { - method = prev->method; - point = prev->point; - } + method = filter.method; + point = filter.point; + + finalize(); // will report [dynamic] config errors +} - // populate services storage with supplied service ids +void +Adaptation::DynamicServiceChain::Split(const ServiceFilter &filter, + const String &ids, DynamicGroupCfg ¤t, + DynamicGroupCfg &future) +{ + // walk the list of services and split it into two parts: + // services that are applicable now and future services + bool doingCurrent = true; const char *item = NULL; int ilen = 0; const char *pos = NULL; - while (strListGetItem(&ids, ',', &item, &ilen, &pos)) - services.push_back(item); + while (strListGetItem(&ids, ',', &item, &ilen, &pos)) { + String id; + id.limitInit(item, ilen); + ServicePointer service = FindService(id); + if (doingCurrent) { + if (!service || // cannot tell or matches current location + (service->cfg().method == filter.method && + service->cfg().point == filter.point)) { + current.add(id); + continue; + } else { + doingCurrent = false; + } + } - finalize(); // will report [dynamic] config errors + if (!doingCurrent) + future.add(id); + } } /* ServicePlan */ diff --git a/src/adaptation/ServiceGroups.h b/src/adaptation/ServiceGroups.h index 30b03234f6..3cf5c99e25 100644 --- a/src/adaptation/ServiceGroups.h +++ b/src/adaptation/ServiceGroups.h @@ -100,7 +100,11 @@ protected: class DynamicServiceChain: public ServiceChain { public: - DynamicServiceChain(const String &srvcs, const ServiceGroupPointer prev); + DynamicServiceChain(const DynamicGroupCfg &cfg, const ServiceFilter &f); + + /// separates dynamic services matching current location from future ones + static void Split(const ServiceFilter &filter, const String &ids, + DynamicGroupCfg ¤t, DynamicGroupCfg &future); }; diff --git a/src/adaptation/forward.h b/src/adaptation/forward.h index 6b9b621a97..7a41ad5644 100644 --- a/src/adaptation/forward.h +++ b/src/adaptation/forward.h @@ -16,6 +16,7 @@ namespace Adaptation class Service; class ServiceConfig; +class DynamicGroupCfg; class Class; class Initiate; class Initiator;