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"
8 #include "adaptation/ServiceFilter.h"
9 #include "adaptation/ServiceGroups.h"
11 #define ServiceGroup ServiceGroup
13 Adaptation::ServiceGroup::ServiceGroup(const String
&aKind
, bool allSame
):
14 kind(aKind
), method(methodNone
), point(pointNone
),
15 allServicesSame(allSame
)
19 Adaptation::ServiceGroup::~ServiceGroup()
24 Adaptation::ServiceGroup::parse()
26 ConfigParser::ParseString(&id
);
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
);
35 // Note: configuration code aside, this method is called by DynamicServiceChain
37 Adaptation::ServiceGroup::finalize()
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
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
) {
51 if (method
== methodNone
) {
52 // optimization: cache values that should be the same
53 method
= service
->cfg().method
;
54 point
= service
->cfg().point
;
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);
64 if (allServicesSame
) {
65 if (!baselineKey
.size()) {
66 baselineKey
= service
->cfg().key
;
67 baselineBypass
= service
->cfg().bypass
;
68 } else if (baselineBypass
!= service
->cfg().bypass
) {
69 debugs(93,0, "WARNING: Inconsistent bypass in " << kind
<<
70 ' ' << id
<< " may produce surprising results: " <<
71 baselineKey
<< " vs. " << sid
);
75 finalizeMsg("ERROR: Unknown adaptation name", sid
, true);
78 debugs(93,7, HERE
<< "finalized " << kind
<< ": " << id
);
81 /// checks that the service name or URI is not repeated later in the group
83 Adaptation::ServiceGroup::checkUniqueness(const Pos checkedPos
) const
85 ServicePointer checkedService
= at(checkedPos
);
86 if (!checkedService
) // should not happen but be robust
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);
93 else if (s
!= NULL
&& s
->cfg().uri
== checkedService
->cfg().uri
)
94 finalizeMsg("duplicate service URI", s
->cfg().uri
, false);
98 /// emits a formatted warning or error message at the appropriate dbg level
100 Adaptation::ServiceGroup::finalizeMsg(const char *msg
, const String
&culprit
,
103 const int level
= error
? DBG_CRITICAL
:DBG_IMPORTANT
;
104 const char *pfx
= error
? "ERROR: " : "WARNING: ";
105 debugs(93,level
, pfx
<< msg
<< ' ' << culprit
<< " in " << kind
<< " '" <<
109 Adaptation::ServicePointer
Adaptation::ServiceGroup::at(const Pos pos
) const
111 return FindService(services
[pos
]);
114 /// \todo: optimize to cut search short instead of looking for the best svc
116 Adaptation::ServiceGroup::wants(const ServiceFilter
&filter
) const
119 return findService(filter
, pos
);
123 Adaptation::ServiceGroup::findService(const ServiceFilter
&filter
, Pos
&pos
) const
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
130 // find the next interested service, skipping problematic ones if possible
131 bool foundEssential
= false;
133 for (; has(pos
); ++pos
) {
134 debugs(93,9,HERE
<< id
<< " checks service at " << pos
);
135 ServicePointer service
= at(pos
);
138 continue; // the service was lost due to reconfiguration
140 if (!service
->wants(filter
))
141 continue; // the service is not interested
143 if (service
->up() || !service
->probed()) {
144 debugs(93,9,HERE
<< id
<< " has matching service at " << pos
);
148 if (service
->cfg().bypass
) { // we can safely ignore bypassable downers
149 debugs(93,9,HERE
<< id
<< " has bypassable service at " << pos
);
153 if (!allServicesSame
) { // cannot skip (i.e., find best) service
154 debugs(93,9,HERE
<< id
<< " has essential service at " << pos
);
158 if (!foundEssential
) {
159 debugs(93,9,HERE
<< id
<< " searches for best essential service from " << pos
);
160 foundEssential
= true;
165 if (foundEssential
) {
166 debugs(93,9,HERE
<< id
<< " has best essential service at " << essPos
);
171 debugs(93,5,HERE
<< id
<< " has no matching services");
176 Adaptation::ServiceGroup::findReplacement(const ServiceFilter
&filter
, Pos
&pos
) const
178 return allServicesSame
&& findService(filter
, pos
);
182 Adaptation::ServiceGroup::findLink(const ServiceFilter
&filter
, Pos
&pos
) const
184 return !allServicesSame
&& findService(filter
, pos
);
190 Adaptation::ServiceSet::ServiceSet(): ServiceGroup("adaptation set", true)
197 Adaptation::SingleService::SingleService(const String
&aServiceId
):
198 ServiceGroup("single-service group", false)
201 services
.push_back(aServiceId
);
207 Adaptation::ServiceChain::ServiceChain(): ServiceGroup("adaptation chain", false)
214 Adaptation::DynamicServiceChain::DynamicServiceChain(const String
&ids
,
215 const ServiceGroupPointer prev
)
217 kind
= "dynamic adaptation chain"; // TODO: optimize by using String const
218 id
= ids
; // use services ids as the dynamic group ID
220 // initialize cache to improve consistency checks in finalize()
222 method
= prev
->method
;
226 // populate services storage with supplied service ids
227 const char *item
= NULL
;
229 const char *pos
= NULL
;
230 while (strListGetItem(&ids
, ',', &item
, &ilen
, &pos
))
231 services
.push_back(item
);
233 finalize(); // will report [dynamic] config errors
238 Adaptation::ServicePlan::ServicePlan(): pos(0), atEof(true)
242 Adaptation::ServicePlan::ServicePlan(const ServiceGroupPointer
&g
,
243 const ServiceFilter
&filter
):
244 group(g
), pos(0), atEof(!g
|| !g
->has(pos
))
246 // this will find the first service because starting pos is zero
247 if (!atEof
&& !group
->findService(filter
, pos
))
251 Adaptation::ServicePointer
252 Adaptation::ServicePlan::current() const
254 // may return NULL even if not atEof
255 return atEof
? Adaptation::ServicePointer() : group
->at(pos
);
258 Adaptation::ServicePointer
259 Adaptation::ServicePlan::replacement(const ServiceFilter
&filter
)
261 if (!atEof
&& !group
->findReplacement(filter
, ++pos
))
266 Adaptation::ServicePointer
267 Adaptation::ServicePlan::next(const ServiceFilter
&filter
)
269 if (!atEof
&& !group
->findLink(filter
, ++pos
))
275 Adaptation::ServicePlan::print(std::ostream
&os
) const
278 return os
<< "[nil]";
280 return os
<< group
->id
<< '[' << pos
<< ".." << group
->services
.size() <<
281 (atEof
? ".]" : "]");
288 Adaptation::AllGroups()
290 static Groups TheGroups
;
294 Adaptation::ServiceGroupPointer
295 Adaptation::FindGroup(const ServiceGroup::Id
&id
)
297 typedef Groups::iterator GI
;
298 for (GI i
= AllGroups().begin(); i
!= AllGroups().end(); ++i
) {