]> git.ipfire.org Git - thirdparty/squid.git/blame - src/adaptation/ServiceGroups.cc
Renamed squid.h to squid-old.h and config.h to squid.h
[thirdparty/squid.git] / src / adaptation / ServiceGroups.cc
CommitLineData
f7f3304a 1#include "squid-old.h"
62c7f90e
AR
2
3#include "ConfigParser.h"
62c7f90e
AR
4#include "adaptation/Config.h"
5#include "adaptation/AccessRule.h"
53340485 6#include "adaptation/DynamicGroupCfg.h"
62c7f90e 7#include "adaptation/Service.h"
a22e6cd3 8#include "adaptation/ServiceFilter.h"
62c7f90e
AR
9#include "adaptation/ServiceGroups.h"
10
11
a22e6cd3 12Adaptation::ServiceGroup::ServiceGroup(const String &aKind, bool allSame):
e1381638
AJ
13 kind(aKind), method(methodNone), point(pointNone),
14 allServicesSame(allSame)
62c7f90e
AR
15{
16}
17
18Adaptation::ServiceGroup::~ServiceGroup()
19{
20}
21
22void
23Adaptation::ServiceGroup::parse()
24{
25 ConfigParser::ParseString(&id);
26
27 wordlist *names = NULL;
28 ConfigParser::ParseWordList(&names);
29 for (wordlist *i = names; i; i = i->next)
30 services.push_back(i->key);
31 wordlistDestroy(&names);
32}
33
a22e6cd3 34// Note: configuration code aside, this method is called by DynamicServiceChain
62c7f90e
AR
35void
36Adaptation::ServiceGroup::finalize()
37{
a22e6cd3
AR
38 // 1) warn if services have different methods or vectoring point
39 // 2) warn if all-same services have different bypass status
40 // 3) warn if there are seemingly identical services in the group
41 // TODO: optimize by remembering ServicePointers rather than IDs
7e8c4ee9
CT
42 if (!removedServices.empty()) {
43 String s;
44 for (Store::iterator it = removedServices.begin(); it != removedServices.end(); ++it) {
45 s.append(*it);
46 s.append(',');
47 }
48 s.cut(s.size() - 1);
49 debugs(93, DBG_IMPORTANT, "Adaptation group '" << id << "' contains disabled member(s) after reconfiguration: " << s);
50 removedServices.clean();
51 }
a22e6cd3
AR
52
53 String baselineKey;
54 bool baselineBypass = false;
55 for (Pos pos = 0; has(pos); ++pos) {
56 // TODO: quit on all errors
b0365bd9 57 const String &serviceId = services[pos];
a22e6cd3
AR
58 ServicePointer service = at(pos);
59 if (service != NULL) {
e1381638 60 if (method == methodNone) {
a22e6cd3
AR
61 // optimization: cache values that should be the same
62 method = service->cfg().method;
63 point = service->cfg().point;
64 } else {
65 if (method != service->cfg().method)
b0365bd9 66 finalizeMsg("Inconsistent service method for", serviceId, true);
a22e6cd3 67 if (point != service->cfg().point)
b0365bd9 68 finalizeMsg("Inconsistent vectoring point for", serviceId, true);
a22e6cd3
AR
69 }
70
71 checkUniqueness(pos);
72
e1381638 73 if (allServicesSame) {
a22e6cd3
AR
74 if (!baselineKey.size()) {
75 baselineKey = service->cfg().key;
76 baselineBypass = service->cfg().bypass;
e1381638 77 } else if (baselineBypass != service->cfg().bypass) {
a22e6cd3 78 debugs(93,0, "WARNING: Inconsistent bypass in " << kind <<
e1381638 79 ' ' << id << " may produce surprising results: " <<
b0365bd9 80 baselineKey << " vs. " << serviceId);
a22e6cd3
AR
81 }
82 }
e1381638 83 } else {
b0365bd9 84 finalizeMsg("ERROR: Unknown adaptation name", serviceId, true);
a22e6cd3 85 }
26ac0430 86 }
bed1aa51 87 debugs(93,7, HERE << "finalized " << kind << ": " << id);
62c7f90e
AR
88}
89
a22e6cd3
AR
90/// checks that the service name or URI is not repeated later in the group
91void
92Adaptation::ServiceGroup::checkUniqueness(const Pos checkedPos) const
93{
94 ServicePointer checkedService = at(checkedPos);
95 if (!checkedService) // should not happen but be robust
96 return;
97
98 for (Pos p = checkedPos + 1; has(p); ++p) {
99 ServicePointer s = at(p);
100 if (s != NULL && s->cfg().key == checkedService->cfg().key)
101 finalizeMsg("duplicate service name", s->cfg().key, false);
e1381638 102 else if (s != NULL && s->cfg().uri == checkedService->cfg().uri)
a22e6cd3
AR
103 finalizeMsg("duplicate service URI", s->cfg().uri, false);
104 }
105}
62c7f90e 106
a22e6cd3
AR
107/// emits a formatted warning or error message at the appropriate dbg level
108void
109Adaptation::ServiceGroup::finalizeMsg(const char *msg, const String &culprit,
e1381638 110 bool error) const
62c7f90e 111{
e1381638 112 const int level = error ? DBG_CRITICAL :DBG_IMPORTANT;
a22e6cd3
AR
113 const char *pfx = error ? "ERROR: " : "WARNING: ";
114 debugs(93,level, pfx << msg << ' ' << culprit << " in " << kind << " '" <<
e1381638 115 id << "'");
a22e6cd3
AR
116}
117
e1381638
AJ
118Adaptation::ServicePointer Adaptation::ServiceGroup::at(const Pos pos) const
119{
a22e6cd3 120 return FindService(services[pos]);
62c7f90e
AR
121}
122
a22e6cd3
AR
123/// \todo: optimize to cut search short instead of looking for the best svc
124bool
125Adaptation::ServiceGroup::wants(const ServiceFilter &filter) const
62c7f90e 126{
a22e6cd3
AR
127 Pos pos = 0;
128 return findService(filter, pos);
62c7f90e
AR
129}
130
a22e6cd3
AR
131bool
132Adaptation::ServiceGroup::findService(const ServiceFilter &filter, Pos &pos) const
62c7f90e 133{
a22e6cd3
AR
134 if (method != filter.method || point != filter.point) {
135 debugs(93,5,HERE << id << " serves another location");
136 return false; // assume other services have the same wrong location
137 }
138
139 // find the next interested service, skipping problematic ones if possible
140 bool foundEssential = false;
141 Pos essPos = 0;
142 for (; has(pos); ++pos) {
143 debugs(93,9,HERE << id << " checks service at " << pos);
144 ServicePointer service = at(pos);
145
146 if (!service)
147 continue; // the service was lost due to reconfiguration
62c7f90e 148
a22e6cd3
AR
149 if (!service->wants(filter))
150 continue; // the service is not interested
151
152 if (service->up() || !service->probed()) {
153 debugs(93,9,HERE << id << " has matching service at " << pos);
154 return true;
155 }
156
157 if (service->cfg().bypass) { // we can safely ignore bypassable downers
158 debugs(93,9,HERE << id << " has bypassable service at " << pos);
159 continue;
160 }
161
162 if (!allServicesSame) { // cannot skip (i.e., find best) service
163 debugs(93,9,HERE << id << " has essential service at " << pos);
164 return true;
165 }
166
167 if (!foundEssential) {
168 debugs(93,9,HERE << id << " searches for best essential service from " << pos);
169 foundEssential = true;
170 essPos = pos;
171 }
62c7f90e 172 }
a22e6cd3
AR
173
174 if (foundEssential) {
175 debugs(93,9,HERE << id << " has best essential service at " << essPos);
176 pos = essPos;
177 return true;
178 }
179
180 debugs(93,5,HERE << id << " has no matching services");
181 return false;
182}
183
184bool
185Adaptation::ServiceGroup::findReplacement(const ServiceFilter &filter, Pos &pos) const
186{
187 return allServicesSame && findService(filter, pos);
188}
189
190bool
191Adaptation::ServiceGroup::findLink(const ServiceFilter &filter, Pos &pos) const
192{
193 return !allServicesSame && findService(filter, pos);
194}
195
196
197/* ServiceSet */
198
199Adaptation::ServiceSet::ServiceSet(): ServiceGroup("adaptation set", true)
200{
62c7f90e 201}
62c7f90e 202
bed1aa51
AR
203
204/* SingleService */
205
206Adaptation::SingleService::SingleService(const String &aServiceId):
a22e6cd3 207 ServiceGroup("single-service group", false)
bed1aa51
AR
208{
209 id = aServiceId;
210 services.push_back(aServiceId);
211}
212
a22e6cd3
AR
213
214/* ServiceChain */
215
216Adaptation::ServiceChain::ServiceChain(): ServiceGroup("adaptation chain", false)
217{
218}
219
220
53340485 221/* DynamicServiceChain */
a22e6cd3 222
53340485
AR
223Adaptation::DynamicServiceChain::DynamicServiceChain(
224 const DynamicGroupCfg &cfg, const ServiceFilter &filter)
a22e6cd3
AR
225{
226 kind = "dynamic adaptation chain"; // TODO: optimize by using String const
53340485
AR
227 id = cfg.id; // use services ids as the dynamic group ID
228 services = cfg.services;
a22e6cd3
AR
229
230 // initialize cache to improve consistency checks in finalize()
53340485
AR
231 method = filter.method;
232 point = filter.point;
233
234 finalize(); // will report [dynamic] config errors
235}
a22e6cd3 236
53340485
AR
237void
238Adaptation::DynamicServiceChain::Split(const ServiceFilter &filter,
239 const String &ids, DynamicGroupCfg &current,
240 DynamicGroupCfg &future)
241{
242 // walk the list of services and split it into two parts:
243 // services that are applicable now and future services
244 bool doingCurrent = true;
a22e6cd3
AR
245 const char *item = NULL;
246 int ilen = 0;
247 const char *pos = NULL;
53340485
AR
248 while (strListGetItem(&ids, ',', &item, &ilen, &pos)) {
249 String id;
250 id.limitInit(item, ilen);
251 ServicePointer service = FindService(id);
252 if (doingCurrent) {
253 if (!service || // cannot tell or matches current location
254 (service->cfg().method == filter.method &&
255 service->cfg().point == filter.point)) {
256 current.add(id);
257 continue;
258 } else {
259 doingCurrent = false;
260 }
261 }
a22e6cd3 262
53340485
AR
263 if (!doingCurrent)
264 future.add(id);
265 }
a22e6cd3
AR
266}
267
268/* ServicePlan */
269
270Adaptation::ServicePlan::ServicePlan(): pos(0), atEof(true)
271{
272}
273
274Adaptation::ServicePlan::ServicePlan(const ServiceGroupPointer &g,
e1381638
AJ
275 const ServiceFilter &filter):
276 group(g), pos(0), atEof(!g || !g->has(pos))
a22e6cd3
AR
277{
278 // this will find the first service because starting pos is zero
279 if (!atEof && !group->findService(filter, pos))
280 atEof = true;
281}
282
283Adaptation::ServicePointer
284Adaptation::ServicePlan::current() const
bed1aa51 285{
a22e6cd3
AR
286 // may return NULL even if not atEof
287 return atEof ? Adaptation::ServicePointer() : group->at(pos);
288}
289
290Adaptation::ServicePointer
e1381638
AJ
291Adaptation::ServicePlan::replacement(const ServiceFilter &filter)
292{
a22e6cd3
AR
293 if (!atEof && !group->findReplacement(filter, ++pos))
294 atEof = true;
295 return current();
296}
297
298Adaptation::ServicePointer
e1381638
AJ
299Adaptation::ServicePlan::next(const ServiceFilter &filter)
300{
a22e6cd3
AR
301 if (!atEof && !group->findLink(filter, ++pos))
302 atEof = true;
303 return current();
304}
305
306std::ostream &
307Adaptation::ServicePlan::print(std::ostream &os) const
308{
309 if (!group)
310 return os << "[nil]";
311
312 return os << group->id << '[' << pos << ".." << group->services.size() <<
e1381638 313 (atEof ? ".]" : "]");
bed1aa51
AR
314}
315
316
317/* globals */
318
62c7f90e
AR
319Adaptation::Groups &
320Adaptation::AllGroups()
321{
322 static Groups TheGroups;
323 return TheGroups;
324}
325
a22e6cd3 326Adaptation::ServiceGroupPointer
62c7f90e
AR
327Adaptation::FindGroup(const ServiceGroup::Id &id)
328{
329 typedef Groups::iterator GI;
330 for (GI i = AllGroups().begin(); i != AllGroups().end(); ++i) {
331 if ((*i)->id == id)
332 return *i;
333 }
334
335 return NULL;
336}