]> git.ipfire.org Git - thirdparty/squid.git/blame - src/adaptation/Iterator.cc
Remove remainder of EXTERNNEW hackup.
[thirdparty/squid.git] / src / adaptation / Iterator.cc
CommitLineData
a22e6cd3
AR
1/*
2 * DEBUG: section 93 Adaptation
3 */
4
5#include "squid.h"
6#include "TextException.h"
7#include "HttpRequest.h"
8#include "HttpReply.h"
9#include "HttpMsg.h"
10#include "adaptation/Config.h"
11#include "adaptation/Iterator.h"
12#include "adaptation/Service.h"
13#include "adaptation/ServiceFilter.h"
14#include "adaptation/ServiceGroups.h"
15
16
17Adaptation::Iterator::Iterator(Adaptation::Initiator *anInitiator,
e1381638
AJ
18 HttpMsg *aMsg, HttpRequest *aCause,
19 const ServiceGroupPointer &aGroup):
20 AsyncJob("Iterator"),
21 Adaptation::Initiate("Iterator", anInitiator),
22 theGroup(aGroup),
23 theMsg(HTTPMSGLOCK(aMsg)),
24 theCause(aCause ? HTTPMSGLOCK(aCause) : NULL),
25 theLauncher(0),
26 iterations(0),
27 adapted(false)
a22e6cd3
AR
28{
29}
30
31Adaptation::Iterator::~Iterator()
32{
33 assert(!theLauncher);
34 HTTPMSGUNLOCK(theMsg);
35 HTTPMSGUNLOCK(theCause);
36}
37
38void Adaptation::Iterator::start()
39{
40 Adaptation::Initiate::start();
41
42 thePlan = ServicePlan(theGroup, filter());
43 step();
44}
45
46void Adaptation::Iterator::step()
47{
48 ++iterations;
49 debugs(93,5, HERE << '#' << iterations << " plan: " << thePlan);
50
51 Must(!theLauncher);
52
53 if (thePlan.exhausted()) { // nothing more to do
54 sendAnswer(theMsg);
55 Must(done());
56 return;
57 }
58
59 if (iterations > Adaptation::Config::service_iteration_limit) {
60 debugs(93,DBG_CRITICAL, "Adaptation iterations limit (" <<
e1381638
AJ
61 Adaptation::Config::service_iteration_limit << ") exceeded:\n" <<
62 "\tPossible service loop with " <<
63 theGroup->kind << " " << theGroup->id << ", plan=" << thePlan);
a22e6cd3
AR
64 throw TexcHere("too many adaptations");
65 }
66
67 ServicePointer service = thePlan.current();
68 Must(service != NULL);
69 debugs(93,5, HERE << "using adaptation service: " << service->cfg().key);
70
71 theLauncher = initiateAdaptation(
e1381638 72 service->makeXactLauncher(this, theMsg, theCause));
a22e6cd3
AR
73 Must(theLauncher);
74 Must(!done());
75}
76
77void Adaptation::Iterator::noteAdaptationAnswer(HttpMsg *aMsg)
78{
79 // set theCause if we switched to request satisfaction mode
80 if (!theCause) { // probably sent a request message
81 if (dynamic_cast<HttpReply*>(aMsg)) { // we got a response message
82 if (HttpRequest *cause = dynamic_cast<HttpRequest*>(theMsg)) {
83 // definately sent request, now use it as the cause
84 theCause = cause; // moving the lock
85 theMsg = 0;
86 debugs(93,3, HERE << "in request satisfaction mode");
87 }
88 }
89 }
90
91 Must(aMsg);
92 HTTPMSGUNLOCK(theMsg);
93 theMsg = HTTPMSGLOCK(aMsg);
94 adapted = true;
95
96 clearAdaptation(theLauncher);
97 if (!updatePlan(true)) // do not immediatelly advance the new plan
98 thePlan.next(filter());
99 step();
100}
101
102void Adaptation::Iterator::noteInitiatorAborted()
103{
104 announceInitiatorAbort(theLauncher); // propogate to the transaction
105 clearInitiator();
106 mustStop("initiator gone");
107}
108
109void Adaptation::Iterator::noteAdaptationQueryAbort(bool final)
110{
111 debugs(93,5, HERE << "final: " << final << " plan: " << thePlan);
112 clearAdaptation(theLauncher);
113 updatePlan(false);
114
115 // can we replace the failed service (group-level bypass)?
e1381638
AJ
116 const bool srcIntact = !theMsg->body_pipe ||
117 !theMsg->body_pipe->consumedSize();
a22e6cd3
AR
118 // can we ignore the failure (compute while thePlan is not exhausted)?
119 Must(!thePlan.exhausted());
120 const bool canIgnore = thePlan.current()->cfg().bypass;
121 debugs(85,5, HERE << "flags: " << srcIntact << canIgnore << adapted);
122
123 if (srcIntact) {
124 if (thePlan.replacement(filter()) != NULL) {
125 debugs(93,3, HERE << "trying a replacement service");
126 step();
127 return;
128 }
129 }
130
131 if (canIgnore && srcIntact && adapted) {
132 debugs(85,3, HERE << "responding with older adapted msg");
133 sendAnswer(theMsg);
134 mustStop("sent older adapted msg");
135 return;
136 }
137
138 // caller may recover if we can ignore the error and virgin msg is intact
139 const bool useVirgin = canIgnore && !adapted && srcIntact;
140 tellQueryAborted(!useVirgin);
141 mustStop("group failure");
142}
143
144bool Adaptation::Iterator::doneAll() const
145{
146 return Adaptation::Initiate::doneAll() && thePlan.exhausted();
147}
148
149void Adaptation::Iterator::swanSong()
150{
151 if (theInitiator)
152 tellQueryAborted(true); // abnormal condition that should not happen
153
154 if (theLauncher)
155 clearAdaptation(theLauncher);
156
157 Adaptation::Initiate::swanSong();
158}
159
160bool Adaptation::Iterator::updatePlan(bool adopt)
161{
162 HttpRequest *r = theCause ? theCause : dynamic_cast<HttpRequest*>(theMsg);
163 Must(r);
164
165 Adaptation::History::Pointer ah = r->adaptHistory();
166 if (!ah)
167 return false; // the feature is not enabled or is not triggered
168
169 String services;
170 if (!ah->extractNextServices(services)) { // clears history
171 debugs(85,9, HERE << "no service-proposed plan received");
172 return false; // the service did not provide a new plan
173 }
174
175 if (!adopt) {
176 debugs(85,3, HERE << "rejecting service-proposed plan");
177 return false;
178 }
e1381638 179
a22e6cd3
AR
180 debugs(85,3, HERE << "retiring old plan: " << thePlan);
181 theGroup = new DynamicServiceChain(services, theGroup); // refcounted
182 thePlan = ServicePlan(theGroup, filter());
183 debugs(85,3, HERE << "adopted service-proposed plan: " << thePlan);
184 return true;
185}
186
187Adaptation::ServiceFilter Adaptation::Iterator::filter() const
188{
189 // the method may differ from theGroup->method due to request satisfaction
190 Method method = methodNone;
191 // temporary variables, no locking needed
192 HttpRequest *req = NULL;
193 HttpReply *rep = NULL;
194
195 if (HttpRequest *r = dynamic_cast<HttpRequest*>(theMsg)) {
196 method = methodReqmod;
197 req = r;
198 rep = NULL;
b0365bd9 199 } else if (HttpReply *theReply = dynamic_cast<HttpReply*>(theMsg)) {
a22e6cd3
AR
200 method = methodRespmod;
201 req = theCause;
b0365bd9 202 rep = theReply;
a22e6cd3
AR
203 } else {
204 Must(false); // should not happen
205 }
206
207 return ServiceFilter(method, theGroup->point, req, rep);
208}
209
210CBDATA_NAMESPACED_CLASS_INIT(Adaptation, Iterator);