]>
Commit | Line | Data |
---|---|---|
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 | 12 | Adaptation::ServiceGroup::ServiceGroup(const String &aKind, bool allSame): |
e1381638 AJ |
13 | kind(aKind), method(methodNone), point(pointNone), |
14 | allServicesSame(allSame) | |
62c7f90e AR |
15 | { |
16 | } | |
17 | ||
18 | Adaptation::ServiceGroup::~ServiceGroup() | |
19 | { | |
20 | } | |
21 | ||
22 | void | |
23 | Adaptation::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 |
35 | void |
36 | Adaptation::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 |
91 | void | |
92 | Adaptation::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 |
108 | void | |
109 | Adaptation::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 |
118 | Adaptation::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 |
124 | bool | |
125 | Adaptation::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 |
131 | bool |
132 | Adaptation::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 | ||
184 | bool | |
185 | Adaptation::ServiceGroup::findReplacement(const ServiceFilter &filter, Pos &pos) const | |
186 | { | |
187 | return allServicesSame && findService(filter, pos); | |
188 | } | |
189 | ||
190 | bool | |
191 | Adaptation::ServiceGroup::findLink(const ServiceFilter &filter, Pos &pos) const | |
192 | { | |
193 | return !allServicesSame && findService(filter, pos); | |
194 | } | |
195 | ||
196 | ||
197 | /* ServiceSet */ | |
198 | ||
199 | Adaptation::ServiceSet::ServiceSet(): ServiceGroup("adaptation set", true) | |
200 | { | |
62c7f90e | 201 | } |
62c7f90e | 202 | |
bed1aa51 AR |
203 | |
204 | /* SingleService */ | |
205 | ||
206 | Adaptation::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 | ||
216 | Adaptation::ServiceChain::ServiceChain(): ServiceGroup("adaptation chain", false) | |
217 | { | |
218 | } | |
219 | ||
220 | ||
53340485 | 221 | /* DynamicServiceChain */ |
a22e6cd3 | 222 | |
53340485 AR |
223 | Adaptation::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 |
237 | void |
238 | Adaptation::DynamicServiceChain::Split(const ServiceFilter &filter, | |
239 | const String &ids, DynamicGroupCfg ¤t, | |
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 | ||
270 | Adaptation::ServicePlan::ServicePlan(): pos(0), atEof(true) | |
271 | { | |
272 | } | |
273 | ||
274 | Adaptation::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 | ||
283 | Adaptation::ServicePointer | |
284 | Adaptation::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 | ||
290 | Adaptation::ServicePointer | |
e1381638 AJ |
291 | Adaptation::ServicePlan::replacement(const ServiceFilter &filter) |
292 | { | |
a22e6cd3 AR |
293 | if (!atEof && !group->findReplacement(filter, ++pos)) |
294 | atEof = true; | |
295 | return current(); | |
296 | } | |
297 | ||
298 | Adaptation::ServicePointer | |
e1381638 AJ |
299 | Adaptation::ServicePlan::next(const ServiceFilter &filter) |
300 | { | |
a22e6cd3 AR |
301 | if (!atEof && !group->findLink(filter, ++pos)) |
302 | atEof = true; | |
303 | return current(); | |
304 | } | |
305 | ||
306 | std::ostream & | |
307 | Adaptation::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 |
319 | Adaptation::Groups & |
320 | Adaptation::AllGroups() | |
321 | { | |
322 | static Groups TheGroups; | |
323 | return TheGroups; | |
324 | } | |
325 | ||
a22e6cd3 | 326 | Adaptation::ServiceGroupPointer |
62c7f90e AR |
327 | Adaptation::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 | } |