/*
- * DEBUG: section 93 Adaptation
+ * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
*/
+/* DEBUG: section 93 Adaptation */
+
#include "squid.h"
+#include "adaptation/Answer.h"
#include "adaptation/Config.h"
#include "adaptation/Iterator.h"
#include "adaptation/Service.h"
#include "adaptation/ServiceFilter.h"
#include "adaptation/ServiceGroups.h"
#include "base/TextException.h"
-#include "HttpRequest.h"
-#include "HttpReply.h"
#include "HttpMsg.h"
-
-
-Adaptation::Iterator::Iterator(Adaptation::Initiator *anInitiator,
- HttpMsg *aMsg, HttpRequest *aCause,
- const ServiceGroupPointer &aGroup):
- AsyncJob("Iterator"),
- Adaptation::Initiate("Iterator", anInitiator),
- theGroup(aGroup),
- theMsg(HTTPMSGLOCK(aMsg)),
- theCause(aCause ? HTTPMSGLOCK(aCause) : NULL),
- theLauncher(0),
- iterations(0),
- adapted(false)
+#include "HttpReply.h"
+#include "HttpRequest.h"
+#include "sbuf/StringConvert.h"
+
+Adaptation::Iterator::Iterator(
+ HttpMsg *aMsg, HttpRequest *aCause,
+ AccessLogEntry::Pointer &alp,
+ const ServiceGroupPointer &aGroup):
+ AsyncJob("Iterator"),
+ Adaptation::Initiate("Iterator"),
+ theGroup(aGroup),
+ theMsg(aMsg),
+ theCause(aCause),
+ al(alp),
+ theLauncher(0),
+ iterations(0),
+ adapted(false)
{
+ if (theCause != NULL)
+ HTTPMSGLOCK(theCause);
+
+ if (theMsg != NULL)
+ HTTPMSGLOCK(theMsg);
}
Adaptation::Iterator::~Iterator()
Adaptation::Initiate::start();
thePlan = ServicePlan(theGroup, filter());
+
+ // Add adaptation group name once and now, before
+ // dynamic groups change it at step() time.
+ if (Adaptation::Config::needHistory && !thePlan.exhausted() && (dynamic_cast<ServiceSet *>(theGroup.getRaw()) || dynamic_cast<ServiceChain *>(theGroup.getRaw()))) {
+ HttpRequest *request = dynamic_cast<HttpRequest*>(theMsg);
+ if (!request)
+ request = theCause;
+ Must(request);
+ Adaptation::History::Pointer ah = request->adaptHistory(true);
+ auto gid = StringToSBuf(theGroup->id);
+ ah->recordAdaptationService(gid);
+ }
+
step();
}
Must(!theLauncher);
if (thePlan.exhausted()) { // nothing more to do
- sendAnswer(theMsg);
+ sendAnswer(Answer::Forward(theMsg));
Must(done());
return;
}
+ HttpRequest *request = dynamic_cast<HttpRequest*>(theMsg);
+ if (!request)
+ request = theCause;
+ assert(request);
+ request->clearError();
+
if (iterations > Adaptation::Config::service_iteration_limit) {
debugs(93,DBG_CRITICAL, "Adaptation iterations limit (" <<
Adaptation::Config::service_iteration_limit << ") exceeded:\n" <<
Must(service != NULL);
debugs(93,5, HERE << "using adaptation service: " << service->cfg().key);
+ if (Adaptation::Config::needHistory) {
+ Adaptation::History::Pointer ah = request->adaptHistory(true);
+ auto uid = StringToSBuf(thePlan.current()->cfg().key);
+ ah->recordAdaptationService(uid);
+ }
+
theLauncher = initiateAdaptation(
- service->makeXactLauncher(this, theMsg, theCause));
- Must(theLauncher);
+ service->makeXactLauncher(theMsg, theCause, al));
+ Must(initiated(theLauncher));
Must(!done());
}
-void Adaptation::Iterator::noteAdaptationAnswer(HttpMsg *aMsg)
+void
+Adaptation::Iterator::noteAdaptationAnswer(const Answer &answer)
+{
+ switch (answer.kind) {
+ case Answer::akForward:
+ handleAdaptedHeader(const_cast<HttpMsg*>(answer.message.getRaw()));
+ break;
+
+ case Answer::akBlock:
+ handleAdaptationBlock(answer);
+ break;
+
+ case Answer::akError:
+ handleAdaptationError(answer.final);
+ break;
+ }
+}
+
+void
+Adaptation::Iterator::handleAdaptedHeader(HttpMsg *aMsg)
{
// set theCause if we switched to request satisfaction mode
if (!theCause) { // probably sent a request message
Must(aMsg);
HTTPMSGUNLOCK(theMsg);
- theMsg = HTTPMSGLOCK(aMsg);
+ theMsg = aMsg;
+ HTTPMSGLOCK(theMsg);
adapted = true;
clearAdaptation(theLauncher);
mustStop("initiator gone");
}
-void Adaptation::Iterator::noteAdaptationQueryAbort(bool final)
+void Adaptation::Iterator::handleAdaptationBlock(const Answer &answer)
+{
+ debugs(93,5, HERE << "blocked by " << answer);
+ clearAdaptation(theLauncher);
+ updatePlan(false);
+ sendAnswer(answer);
+ mustStop("blocked");
+}
+
+void Adaptation::Iterator::handleAdaptationError(bool final)
{
debugs(93,5, HERE << "final: " << final << " plan: " << thePlan);
clearAdaptation(theLauncher);
if (canIgnore && srcIntact && adapted) {
debugs(85,3, HERE << "responding with older adapted msg");
- sendAnswer(theMsg);
+ sendAnswer(Answer::Forward(theMsg));
mustStop("sent older adapted msg");
return;
}
void Adaptation::Iterator::swanSong()
{
- if (theInitiator)
+ if (theInitiator.set())
tellQueryAborted(true); // abnormal condition that should not happen
- if (theLauncher)
+ if (initiated(theLauncher))
clearAdaptation(theLauncher);
Adaptation::Initiate::swanSong();
Must(r);
Adaptation::History::Pointer ah = r->adaptHistory();
- if (!ah)
+ if (!ah) {
+ debugs(85,9, HERE << "no history to store a service-proposed plan");
return false; // the feature is not enabled or is not triggered
+ }
String services;
if (!ah->extractNextServices(services)) { // clears history
}
debugs(85,3, HERE << "retiring old plan: " << thePlan);
- theGroup = new DynamicServiceChain(services, theGroup); // refcounted
- thePlan = ServicePlan(theGroup, filter());
+
+ Adaptation::ServiceFilter f = this->filter();
+ DynamicGroupCfg current, future;
+ DynamicServiceChain::Split(f, 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, f); // refcounted
+ thePlan = ServicePlan(theGroup, f);
debugs(85,3, HERE << "adopted service-proposed plan: " << thePlan);
return true;
}
Must(false); // should not happen
}
- return ServiceFilter(method, theGroup->point, req, rep);
+ return ServiceFilter(method, theGroup->point, req, rep, al);
}
CBDATA_NAMESPACED_CLASS_INIT(Adaptation, Iterator);
+