Merged from the 3p1-rock branch (r9630).
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
virtual void start();
virtual bool doneAll() const { return false; } /// not done until mustStop
+ bool usedDynamicRules();
void check();
private:
theNextServices = TheNullServices; // prevents resetting the plan twice
return true;
}
+
+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;
+}
#include "RefCount.h"
#include "Array.h"
#include "SquidString.h"
+#include "adaptation/DynamicGroupCfg.h"
namespace Adaptation
{
/// returns true, fills the value, and resets iff next services were set
bool extractNextServices(String &value);
+ /// 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
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
}
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;
}
AccessRule.h \
Config.cc \
Config.h \
+ DynamicGroupCfg.cc \
+ DynamicGroupCfg.h \
Elements.cc \
Elements.h \
forward.h \
#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),
}
-/* 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 */
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);
};
class Service;
class ServiceConfig;
+class DynamicGroupCfg;
class Class;
class Initiate;
class Initiator;