]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/adaptation/Iterator.cc
2 * DEBUG: section 93 Adaptation
6 #include "adaptation/Config.h"
7 #include "adaptation/Iterator.h"
8 #include "adaptation/Service.h"
9 #include "adaptation/ServiceFilter.h"
10 #include "adaptation/ServiceGroups.h"
11 #include "base/TextException.h"
12 #include "HttpRequest.h"
13 #include "HttpReply.h"
17 Adaptation::Iterator::Iterator(Adaptation::Initiator
*anInitiator
,
18 HttpMsg
*aMsg
, HttpRequest
*aCause
,
19 const ServiceGroupPointer
&aGroup
):
21 Adaptation::Initiate("Iterator", anInitiator
),
23 theMsg(HTTPMSGLOCK(aMsg
)),
24 theCause(aCause
? HTTPMSGLOCK(aCause
) : NULL
),
31 Adaptation::Iterator::~Iterator()
34 HTTPMSGUNLOCK(theMsg
);
35 HTTPMSGUNLOCK(theCause
);
38 void Adaptation::Iterator::start()
40 Adaptation::Initiate::start();
42 thePlan
= ServicePlan(theGroup
, filter());
46 void Adaptation::Iterator::step()
49 debugs(93,5, HERE
<< '#' << iterations
<< " plan: " << thePlan
);
53 if (thePlan
.exhausted()) { // nothing more to do
59 if (iterations
> Adaptation::Config::service_iteration_limit
) {
60 debugs(93,DBG_CRITICAL
, "Adaptation iterations limit (" <<
61 Adaptation::Config::service_iteration_limit
<< ") exceeded:\n" <<
62 "\tPossible service loop with " <<
63 theGroup
->kind
<< " " << theGroup
->id
<< ", plan=" << thePlan
);
64 throw TexcHere("too many adaptations");
67 ServicePointer service
= thePlan
.current();
68 Must(service
!= NULL
);
69 debugs(93,5, HERE
<< "using adaptation service: " << service
->cfg().key
);
71 theLauncher
= initiateAdaptation(
72 service
->makeXactLauncher(this, theMsg
, theCause
));
77 void Adaptation::Iterator::noteAdaptationAnswer(HttpMsg
*aMsg
)
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
86 debugs(93,3, HERE
<< "in request satisfaction mode");
92 HTTPMSGUNLOCK(theMsg
);
93 theMsg
= HTTPMSGLOCK(aMsg
);
96 clearAdaptation(theLauncher
);
97 if (!updatePlan(true)) // do not immediatelly advance the new plan
98 thePlan
.next(filter());
102 void Adaptation::Iterator::noteInitiatorAborted()
104 announceInitiatorAbort(theLauncher
); // propogate to the transaction
106 mustStop("initiator gone");
109 void Adaptation::Iterator::noteAdaptationQueryAbort(bool final
)
111 debugs(93,5, HERE
<< "final: " << final
<< " plan: " << thePlan
);
112 clearAdaptation(theLauncher
);
115 // can we replace the failed service (group-level bypass)?
116 const bool srcIntact
= !theMsg
->body_pipe
||
117 !theMsg
->body_pipe
->consumedSize();
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
);
124 if (thePlan
.replacement(filter()) != NULL
) {
125 debugs(93,3, HERE
<< "trying a replacement service");
131 if (canIgnore
&& srcIntact
&& adapted
) {
132 debugs(85,3, HERE
<< "responding with older adapted msg");
134 mustStop("sent older adapted msg");
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");
144 bool Adaptation::Iterator::doneAll() const
146 return Adaptation::Initiate::doneAll() && thePlan
.exhausted();
149 void Adaptation::Iterator::swanSong()
152 tellQueryAborted(true); // abnormal condition that should not happen
155 clearAdaptation(theLauncher
);
157 Adaptation::Initiate::swanSong();
160 bool Adaptation::Iterator::updatePlan(bool adopt
)
162 HttpRequest
*r
= theCause
? theCause
: dynamic_cast<HttpRequest
*>(theMsg
);
165 Adaptation::History::Pointer ah
= r
->adaptHistory();
167 return false; // the feature is not enabled or is not triggered
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
176 debugs(85,3, HERE
<< "rejecting service-proposed plan");
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
);
187 Adaptation::ServiceFilter
Adaptation::Iterator::filter() const
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
;
195 if (HttpRequest
*r
= dynamic_cast<HttpRequest
*>(theMsg
)) {
196 method
= methodReqmod
;
199 } else if (HttpReply
*theReply
= dynamic_cast<HttpReply
*>(theMsg
)) {
200 method
= methodRespmod
;
204 Must(false); // should not happen
207 return ServiceFilter(method
, theGroup
->point
, req
, rep
);
210 CBDATA_NAMESPACED_CLASS_INIT(Adaptation
, Iterator
);