To combat typos, warn if there are identical adaptation services in a group. We check both service names (keys) and service URIs for uniqueness. There is no special runtime treatment for duplicates because they might be configured that way intentionally. === modified file 'src/adaptation/ServiceGroups.cc' --- src/adaptation/ServiceGroups.cc 2009-06-18 05:53:09 +0000 +++ src/adaptation/ServiceGroups.cc 2009-06-27 22:03:29 +0000 @@ -38,14 +38,15 @@ { // 1) warn if services have different methods or vectoring point // 2) warn if all-same services have different bypass status + // 3) warn if there are seemingly identical services in the group // TODO: optimize by remembering ServicePointers rather than IDs String baselineKey; bool baselineBypass = false; - for (Store::iterator i = services.begin(); i != services.end(); ++i) { - const String &sid = *i; + for (Pos pos = 0; has(pos); ++pos) { // TODO: quit on all errors - ServicePointer service = FindService(sid); + const String &sid = services[pos]; + ServicePointer service = at(pos); if (service != NULL) { if (method == methodNone) { // optimization: cache values that should be the same @@ -53,11 +54,13 @@ point = service->cfg().point; } else { if (method != service->cfg().method) - finalizeError("Inconsistent service method for", sid); + finalizeMsg("Inconsistent service method for", sid, true); if (point != service->cfg().point) - finalizeError("Inconsistent vectoring point for", sid); + finalizeMsg("Inconsistent vectoring point for", sid, true); } + checkUniqueness(pos); + if (allServicesSame) { if (!baselineKey.size()) { baselineKey = service->cfg().key; @@ -70,17 +73,39 @@ } } } else { - finalizeError("Unknown adaptation name", sid); + finalizeMsg("ERROR: Unknown adaptation name", sid, true); } } debugs(93,7, HERE << "finalized " << kind << ": " << id); } -void -Adaptation::ServiceGroup::finalizeError(const char *msg, const String &culprit) -{ - debugs(93,0, "ERROR: " << msg << ' ' << culprit << " in " << kind << - " '" << id << "'"); +/// checks that the service name or URI is not repeated later in the group +void +Adaptation::ServiceGroup::checkUniqueness(const Pos checkedPos) const +{ + ServicePointer checkedService = at(checkedPos); + if (!checkedService) // should not happen but be robust + return; + + for (Pos p = checkedPos + 1; has(p); ++p) { + ServicePointer s = at(p); + if (s != NULL && s->cfg().key == checkedService->cfg().key) + finalizeMsg("duplicate service name", s->cfg().key, false); + else + if (s != NULL && s->cfg().uri == checkedService->cfg().uri) + finalizeMsg("duplicate service URI", s->cfg().uri, false); + } +} + +/// emits a formatted warning or error message at the appropriate dbg level +void +Adaptation::ServiceGroup::finalizeMsg(const char *msg, const String &culprit, + bool error) const +{ + const int level = error ? DBG_CRITICAL : DBG_IMPORTANT; + const char *pfx = error ? "ERROR: " : "WARNING: "; + debugs(93,level, pfx << msg << ' ' << culprit << " in " << kind << " '" << + id << "'"); } Adaptation::ServicePointer Adaptation::ServiceGroup::at(const Pos pos) const { === modified file 'src/adaptation/ServiceGroups.h' --- src/adaptation/ServiceGroups.h 2009-06-18 05:53:09 +0000 +++ src/adaptation/ServiceGroups.h 2009-06-27 21:58:20 +0000 @@ -48,7 +48,9 @@ private: ServicePointer at(const Pos pos) const; bool findService(const ServiceFilter &filter, Pos &pos) const; - void finalizeError(const char *msg, const String &culprit); + + void checkUniqueness(const Pos checkedPos) const; + void finalizeMsg(const char *msg, const String &culprit, bool error) const; public: String kind;