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