Iterator.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 93 Adaptation */
10 
11 #include "squid.h"
12 #include "adaptation/Answer.h"
13 #include "adaptation/Config.h"
14 #include "adaptation/Iterator.h"
15 #include "adaptation/Service.h"
18 #include "base/TextException.h"
19 #include "HttpReply.h"
20 #include "sbuf/StringConvert.h"
21 
23  Http::Message *aMsg, HttpRequest *aCause,
25  const ServiceGroupPointer &aGroup):
26  AsyncJob("Iterator"),
27  Adaptation::Initiate("Iterator"),
28  theGroup(aGroup),
29  theMsg(aMsg),
30  theCause(aCause),
31  al(alp),
32  theLauncher(0),
33  iterations(0),
34  adapted(false)
35 {
36  if (theCause != NULL)
38 
39  if (theMsg != NULL)
41 }
42 
44 {
45  assert(!theLauncher);
46  HTTPMSGUNLOCK(theMsg);
47  HTTPMSGUNLOCK(theCause);
48 }
49 
51 {
53 
54  thePlan = ServicePlan(theGroup, filter());
55 
56  // Add adaptation group name once and now, before
57  // dynamic groups change it at step() time.
58  if (Adaptation::Config::needHistory && !thePlan.exhausted() && (dynamic_cast<ServiceSet *>(theGroup.getRaw()) || dynamic_cast<ServiceChain *>(theGroup.getRaw()))) {
59  HttpRequest *request = dynamic_cast<HttpRequest*>(theMsg);
60  if (!request)
61  request = theCause;
62  Must(request);
63  Adaptation::History::Pointer ah = request->adaptHistory(true);
64  auto gid = StringToSBuf(theGroup->id);
65  ah->recordAdaptationService(gid);
66  }
67 
68  step();
69 }
70 
72 {
73  ++iterations;
74  debugs(93,5, HERE << '#' << iterations << " plan: " << thePlan);
75 
76  Must(!theLauncher);
77 
78  if (thePlan.exhausted()) { // nothing more to do
79  sendAnswer(Answer::Forward(theMsg));
80  Must(done());
81  return;
82  }
83 
84  HttpRequest *request = dynamic_cast<HttpRequest*>(theMsg);
85  if (!request)
86  request = theCause;
87  assert(request);
88  request->clearError();
89 
91  debugs(93,DBG_CRITICAL, "Adaptation iterations limit (" <<
93  "\tPossible service loop with " <<
94  theGroup->kind << " " << theGroup->id << ", plan=" << thePlan);
95  throw TexcHere("too many adaptations");
96  }
97 
98  ServicePointer service = thePlan.current();
99  Must(service != NULL);
100  debugs(93,5, HERE << "using adaptation service: " << service->cfg().key);
101 
103  Adaptation::History::Pointer ah = request->adaptHistory(true);
104  auto uid = StringToSBuf(thePlan.current()->cfg().key);
105  ah->recordAdaptationService(uid);
106  }
107 
108  theLauncher = initiateAdaptation(
109  service->makeXactLauncher(theMsg, theCause, al));
110  Must(initiated(theLauncher));
111  Must(!done());
112 }
113 
114 void
116 {
117  switch (answer.kind) {
118  case Answer::akForward:
119  handleAdaptedHeader(const_cast<Http::Message*>(answer.message.getRaw()));
120  break;
121 
122  case Answer::akBlock:
123  handleAdaptationBlock(answer);
124  break;
125 
126  case Answer::akError:
127  handleAdaptationError(answer.final);
128  break;
129  }
130 }
131 
132 void
134 {
135  // set theCause if we switched to request satisfaction mode
136  if (!theCause) { // probably sent a request message
137  if (dynamic_cast<HttpReply*>(aMsg)) { // we got a response message
138  if (HttpRequest *cause = dynamic_cast<HttpRequest*>(theMsg)) {
139  // definately sent request, now use it as the cause
140  theCause = cause; // moving the lock
141  theMsg = 0;
142  debugs(93,3, HERE << "in request satisfaction mode");
143  }
144  }
145  }
146 
147  Must(aMsg);
148  HTTPMSGUNLOCK(theMsg);
149  theMsg = aMsg;
150  HTTPMSGLOCK(theMsg);
151  adapted = true;
152 
153  clearAdaptation(theLauncher);
154  if (!updatePlan(true)) // do not immediatelly advance the new plan
155  thePlan.next(filter());
156  step();
157 }
158 
160 {
161  announceInitiatorAbort(theLauncher); // propogate to the transaction
162  clearInitiator();
163  mustStop("initiator gone");
164 }
165 
167 {
168  debugs(93,5, HERE << "blocked by " << answer);
169  clearAdaptation(theLauncher);
170  updatePlan(false);
171  sendAnswer(answer);
172  mustStop("blocked");
173 }
174 
176 {
177  debugs(93,5, HERE << "final: " << final << " plan: " << thePlan);
178  clearAdaptation(theLauncher);
179  updatePlan(false);
180 
181  // can we replace the failed service (group-level bypass)?
182  const bool srcIntact = !theMsg->body_pipe ||
183  !theMsg->body_pipe->consumedSize();
184  // can we ignore the failure (compute while thePlan is not exhausted)?
185  Must(!thePlan.exhausted());
186  const bool canIgnore = thePlan.current()->cfg().bypass;
187  debugs(85,5, HERE << "flags: " << srcIntact << canIgnore << adapted);
188 
189  if (srcIntact) {
190  if (thePlan.replacement(filter()) != NULL) {
191  debugs(93,3, HERE << "trying a replacement service");
192  step();
193  return;
194  }
195  }
196 
197  if (canIgnore && srcIntact && adapted) {
198  debugs(85,3, HERE << "responding with older adapted msg");
199  sendAnswer(Answer::Forward(theMsg));
200  mustStop("sent older adapted msg");
201  return;
202  }
203 
204  // caller may recover if we can ignore the error and virgin msg is intact
205  const bool useVirgin = canIgnore && !adapted && srcIntact;
206  tellQueryAborted(!useVirgin);
207  mustStop("group failure");
208 }
209 
211 {
212  return Adaptation::Initiate::doneAll() && thePlan.exhausted();
213 }
214 
216 {
217  if (theInitiator.set())
218  tellQueryAborted(true); // abnormal condition that should not happen
219 
220  if (initiated(theLauncher))
221  clearAdaptation(theLauncher);
222 
224 }
225 
227 {
228  HttpRequest *r = theCause ? theCause : dynamic_cast<HttpRequest*>(theMsg);
229  Must(r);
230 
232  if (!ah) {
233  debugs(85,9, HERE << "no history to store a service-proposed plan");
234  return false; // the feature is not enabled or is not triggered
235  }
236 
237  String services;
238  if (!ah->extractNextServices(services)) { // clears history
239  debugs(85,9, HERE << "no service-proposed plan received");
240  return false; // the service did not provide a new plan
241  }
242 
243  if (!adopt) {
244  debugs(85,3, HERE << "rejecting service-proposed plan");
245  return false;
246  }
247 
248  debugs(85,3, HERE << "retiring old plan: " << thePlan);
249 
250  Adaptation::ServiceFilter f = this->filter();
251  DynamicGroupCfg current, future;
252  DynamicServiceChain::Split(f, services, current, future);
253 
254  if (!future.empty()) {
255  ah->setFutureServices(future);
256  debugs(85,3, HERE << "noted future service-proposed plan: " << future);
257  }
258 
259  // use the current config even if it is empty; we must replace the old plan
260  theGroup = new DynamicServiceChain(current, f); // refcounted
261  thePlan = ServicePlan(theGroup, f);
262  debugs(85,3, HERE << "adopted service-proposed plan: " << thePlan);
263  return true;
264 }
265 
267 {
268  // the method may differ from theGroup->method due to request satisfaction
270  // temporary variables, no locking needed
271  HttpRequest *req = NULL;
272  HttpReply *rep = NULL;
273 
274  if (HttpRequest *r = dynamic_cast<HttpRequest*>(theMsg)) {
275  method = methodReqmod;
276  req = r;
277  rep = NULL;
278  } else if (HttpReply *theReply = dynamic_cast<HttpReply*>(theMsg)) {
279  method = methodRespmod;
280  req = theCause;
281  rep = theReply;
282  } else {
283  Must(false); // should not happen
284  }
285 
286  return ServiceFilter(method, theGroup->point, req, rep, al);
287 }
288 
290 
iterates services in ServiceGroup, starting adaptation launchers
Definition: Iterator.h:31
summarizes adaptation service answer for the noteAdaptationAnswer() API
Definition: Answer.h:22
virtual bool doneAll() const
whether positive goal has been reached
Definition: AsyncJob.cc:96
void handleAdaptationError(bool final)
Definition: Iterator.cc:175
CBDATA_NAMESPACED_CLASS_INIT(Adaptation, Iterator)
virtual void swanSong()
Definition: Iterator.cc:215
#define assert(EX)
Definition: assert.h:17
static bool needHistory
HttpRequest adaptation history should recorded.
Definition: Config.h:60
Iterator(Http::Message *virginHeader, HttpRequest *virginCause, AccessLogEntry::Pointer &alp, const Adaptation::ServiceGroupPointer &aGroup)
Definition: Iterator.cc:22
static Answer Forward(Http::Message *aMsg)
create an akForward answer
Definition: Answer.cc:26
void recordAdaptationService(SBuf &srvId)
Definition: History.cc:149
bool extractNextServices(String &value)
returns true, fills the value, and resets iff next services were set
Definition: History.cc:129
static void Split(const ServiceFilter &filter, const String &ids, DynamicGroupCfg &current, DynamicGroupCfg &future)
separates dynamic services matching current location from future ones
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
Http::MessagePointer message
HTTP request or response to forward.
Definition: Answer.h:39
const ServiceConfig & cfg() const
Definition: Service.h:51
void HTTPMSGLOCK(Http::Message *a)
Definition: Message.h:154
#define DBG_CRITICAL
Definition: Debug.h:44
DynamicServiceGroup configuration to remember future dynamic chains.
no adapted message will come; see bypassable
Definition: Answer.h:29
void step()
launches adaptation for the service selected by the plan
Definition: Iterator.cc:71
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:123
Adaptation::History::Pointer adaptHistory(bool createIfNone=false) const
Returns possibly nil history, creating it if requested.
Definition: HttpRequest.cc:414
Http::Message * theMsg
the message being adapted (virgin for each step)
Definition: Iterator.h:68
bool updatePlan(bool adopt)
replace the current group and plan with service-proposed ones if needed
Definition: Iterator.cc:226
virtual void noteAdaptationAnswer(const Answer &answer)
Definition: Iterator.cc:115
common parts of HttpRequest and HttpReply
Definition: Message.h:24
virtual Initiate * makeXactLauncher(Http::Message *virginHeader, HttpRequest *virginCause, AccessLogEntry::Pointer &alp)=0
ServiceFilter filter() const
creates service filter for the current step
Definition: Iterator.cc:266
HttpRequest * theCause
the cause of the original virgin message
Definition: Iterator.h:69
void clearError()
clear error details, useful for retries/repeats
Definition: HttpRequest.cc:470
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:147
#define Must(cond)
Definition: TextException.h:89
bool empty() const
no services added
information used to search for adaptation services
Definition: ServiceFilter.h:22
virtual void start()
called by AsyncStart; do not call directly
Definition: Iterator.cc:50
virtual ~Iterator()
Definition: Iterator.cc:43
bool final
whether the error, if any, cannot be bypassed
Definition: Answer.h:41
virtual bool doneAll() const
whether positive goal has been reached
Definition: Iterator.cc:210
Kind kind
the type of the answer
Definition: Answer.h:42
void handleAdaptationBlock(const Answer &answer)
Definition: Iterator.cc:166
forward the supplied adapted HTTP message
Definition: Answer.h:27
block or deny the master xaction; see authority
Definition: Answer.h:28
void handleAdaptedHeader(Http::Message *msg)
Definition: Iterator.cc:133
static int service_iteration_limit
Definition: Config.h:46
size_t HttpReply *STUB StoreEntry const KeyScope scope const HttpRequestMethod & method
Definition: stub_store.cc:126
#define TexcHere(msg)
Definition: TextException.h:81
void noteInitiatorAborted()
Definition: Iterator.cc:159
SBuf StringToSBuf(const String &s)
create a new SBuf from a String by copying contents
Definition: StringConvert.h:17
a temporary service chain built upon another service request
virtual void start()
called by AsyncStart; do not call directly
Definition: AsyncJob.cc:43
void setFutureServices(const DynamicGroupCfg &services)
sets future services for the Adaptation::AccessCheck to notice
Definition: History.cc:155
C * getRaw() const
Definition: RefCount.h:74
#define NULL
Definition: types.h:166
void HTTPMSGUNLOCK(Http::Message *a)
Definition: Message.h:144
virtual void swanSong()
Definition: Initiate.cc:62
#define false
Definition: GnuRegex.c:233

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors