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

 

Introduction

Documentation

Support

Miscellaneous