]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Support dynamic adaptation plans that cover multiple vectoring points.
authorAlex Rousskov <rousskov@measurement-factory.com>
Wed, 30 Mar 2011 17:43:55 +0000 (11:43 -0600)
committerAlex Rousskov <rousskov@measurement-factory.com>
Wed, 30 Mar 2011 17:43:55 +0000 (11:43 -0600)
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.

src/adaptation/AccessCheck.cc
src/adaptation/AccessCheck.h
src/adaptation/DynamicGroupCfg.cc [new file with mode: 0644]
src/adaptation/DynamicGroupCfg.h [new file with mode: 0644]
src/adaptation/History.cc
src/adaptation/History.h
src/adaptation/Iterator.cc
src/adaptation/Makefile.am
src/adaptation/ServiceGroups.cc
src/adaptation/ServiceGroups.h
src/adaptation/forward.h

index 1f880ba52a6155190647e2bf1ac7e78f168fe343..d63199e01f1668d857080a80ba67b3a7e8aaeca9 100644 (file)
@@ -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
index 11f89af5df2b033b3f4de0c8250272b338652914..e0e4793daf8c7deece85b6e57b1c1f3a718eb7e5 100644 (file)
@@ -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 (file)
index 0000000..9bcba5c
--- /dev/null
@@ -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 (file)
index 0000000..a2ec4b6
--- /dev/null
@@ -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<String> 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 */
+
index d106603f4c53bdc3cfed399206acf14e0457f7fd..dd97cda39825d70993332d6a65201ae100fd9a0f 100644 (file)
@@ -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;
+}
index ec254e18a6d1bd45b10a6b5aa36625dda1df97dc..ffe3198f455ae21e202f0cd98a42521d3654c377 100644 (file)
@@ -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
index 4ca0301e4ffa9b733319fcd7bd9124fc3061361f..74b713dfc68b1a5238f525ff38b27796d57ce9d3 100644 (file)
@@ -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;
 }
index 03f2facbc3ac5b031b35df98205dd935bb522461..70c735b7475c1b56a17fff84eb868484d7bd8632 100644 (file)
@@ -24,6 +24,8 @@ libadaptation_la_SOURCES = \
        Answer.h \
        Config.cc \
        Config.h \
+       DynamicGroupCfg.cc \
+       DynamicGroupCfg.h \
        Elements.cc \
        Elements.h \
        forward.h \
index a680b17e9c66ae323cfe4f5cc8d8a78569845990..4716b4c393e622dfb4ccbbf925308f5f3520434f 100644 (file)
@@ -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 &current,
+                                       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 */
index 30b03234f64c5b3c633a299640b71eecfea9ed5b..3cf5c99e25a3afb7540412ca2205b5ece2b21cef 100644 (file)
@@ -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 &current, DynamicGroupCfg &future);
 };
 
 
index 6b9b621a976d8b0f22a27172ef3bec349c7936f3..7a41ad56443dfa54f333fda2e4959a1b95cb29c8 100644 (file)
@@ -16,6 +16,7 @@ namespace Adaptation
 
 class Service;
 class ServiceConfig;
+class DynamicGroupCfg;
 class Class;
 class Initiate;
 class Initiator;