=== modified file 'src/adaptation/AccessRule.cc' --- src/adaptation/AccessRule.cc 2013-05-13 22:48:23 +0000 +++ src/adaptation/AccessRule.cc 2014-04-08 12:48:07 +0000 @@ -31,45 +31,58 @@ // try to add a one-service group if (FindService(groupId) != NULL) { ServiceGroupPointer g = new SingleService(groupId); g->finalize(); // explicit groups were finalized before rules AllGroups().push_back(g); } } if (!group()) { debugs(93, DBG_CRITICAL, "ERROR: Unknown adaptation service or group name: '" << groupId << "'"); // TODO: fail on failures } } Adaptation::ServiceGroupPointer Adaptation::AccessRule::group() { return FindGroup(groupId); } +class RulesCfg { +public: + Adaptation::AccessRules rules; + ~RulesCfg() { + while (!rules.empty()) { + Adaptation::AccessRule *r = rules.back(); + rules.pop_back(); + delete r; + } + } +}; + +static RulesCfg TheRulesCfg; + Adaptation::AccessRules & Adaptation::AllRules() { - static AccessRules TheRules; - return TheRules; + return TheRulesCfg.rules; } // TODO: make AccessRules::find work Adaptation::AccessRule * Adaptation::FindRule(const AccessRule::Id &id) { typedef AccessRules::iterator ARI; for (ARI i = AllRules().begin(); i != AllRules().end(); ++i) { if ((*i)->id == id) return *i; } return NULL; } Adaptation::AccessRule * Adaptation::FindRuleByGroupId(const String &groupId) { typedef AccessRules::iterator ARI; for (ARI i = AllRules().begin(); i != AllRules().end(); ++i) { === modified file 'src/adaptation/Config.cc' --- src/adaptation/Config.cc 2014-02-19 17:01:30 +0000 +++ src/adaptation/Config.cc 2014-04-08 12:40:23 +0000 @@ -148,45 +148,40 @@ removeService((*cfg)->key); serviceConfigs.clear(); debugs(93, 3, HERE << "rules: " << AllRules().size() << ", groups: " << AllGroups().size() << ", services: " << serviceConfigs.size()); } void Adaptation::Config::parseService() { ServiceConfigPointer cfg = newServiceConfig(); if (!cfg->parse()) { fatalf("%s:%d: malformed adaptation service configuration", cfg_filename, config_lineno); } serviceConfigs.push_back(cfg); } void Adaptation::Config::freeService() { - FreeAccess(); - FreeServiceGroups(); - - DetachServices(); - serviceConfigs.clear(); } void Adaptation::Config::dumpService(StoreEntry *entry, const char *name) const { typedef Services::iterator SCI; for (SCI i = AllServices().begin(); i != AllServices().end(); ++i) { const ServiceConfig &cfg = (*i)->cfg(); storeAppendPrintf(entry, "%s " SQUIDSTRINGPH "_%s %s %d " SQUIDSTRINGPH "\n", name, SQUIDSTRINGPRINT(cfg.key), cfg.methodStr(), cfg.vectPointStr(), cfg.bypass, SQUIDSTRINGPRINT(cfg.uri)); } } bool Adaptation::Config::finalize() { @@ -308,20 +303,27 @@ LOCAL_ARRAY(char, nom, 64); typedef AccessRules::iterator CI; for (CI i = AllRules().begin(); i != AllRules().end(); ++i) { snprintf(nom, 64, "%s " SQUIDSTRINGPH, name, SQUIDSTRINGPRINT((*i)->groupId)); dump_acl_access(entry, nom, (*i)->acl); } } Adaptation::Config::Config() : onoff(0), service_failure_limit(0), oldest_service_failure(0), service_revival_delay(0) {} // XXX: this is called for ICAP and eCAP configs, but deals mostly // with global arrays shared by those individual configs Adaptation::Config::~Config() { freeService(); } + +void Adaptation::Config::Clear() +{ + FreeAccess(); + FreeServiceGroups(); + DetachServices(); +} === modified file 'src/adaptation/Config.h' --- src/adaptation/Config.h 2014-02-10 16:39:10 +0000 +++ src/adaptation/Config.h 2014-04-08 12:39:30 +0000 @@ -10,40 +10,41 @@ #include "SquidString.h" class ConfigParser; class HttpRequest; class HttpReply; namespace Adaptation { class Config { public: static void Finalize(bool enable); static void ParseServiceSet(void); static void ParseServiceChain(void); static void ParseAccess(ConfigParser &parser); static void FreeAccess(void); static void DumpAccess(StoreEntry *, const char *); + static void Clear(); friend class AccessCheck; public: static bool Enabled; // true if at least one adaptation mechanism is // these are global squid.conf options, documented elsewhere static char *masterx_shared_name; // global TODO: do we need TheConfig? static int service_iteration_limit; static int send_client_ip; static int send_username; static int use_indirect_client; // Options below are accessed via Icap::TheConfig or Ecap::TheConfig // TODO: move ICAP-specific options to Icap::Config and add TheConfig int onoff; int service_failure_limit; time_t oldest_service_failure; int service_revival_delay; === modified file 'src/adaptation/Service.cc' --- src/adaptation/Service.cc 2014-02-04 19:47:14 +0000 +++ src/adaptation/Service.cc 2014-04-08 12:55:11 +0000 @@ -34,45 +34,57 @@ if (cfg().point != filter.point) return false; // sending a message to a broken service is likely to cause errors if (cfg().bypass && broken()) return false; if (up()) { // Sending a message to a service that does not want it is useless. // note that we cannot check wantsUrl for service that is not "up" // note that even essential services are skipped on unwanted URLs! return wantsUrl(filter.request->urlpath); } // The service is down and is either not bypassable or not probed due // to the bypass && broken() test above. Thus, we want to use it! return true; } +class ServicesCfg{ +public: + Adaptation::Services services; + void detach(){ + while (!services.empty()) { + services.back()->detach(); + services.pop_back(); + } + } + ~ServicesCfg() { + detach(); + } +}; + +static ServicesCfg TheServicesCfg; + Adaptation::Services & Adaptation::AllServices() { - static Services TheServices; - return TheServices; + return TheServicesCfg.services; } Adaptation::ServicePointer Adaptation::FindService(const Service::Id& key) { typedef Services::iterator SI; for (SI i = AllServices().begin(); i != AllServices().end(); ++i) { if ((*i)->cfg().key == key) return *i; } return NULL; } void Adaptation::DetachServices() { - while (!AllServices().empty()) { - AllServices().back()->detach(); - AllServices().pop_back(); - } + TheServicesCfg.detach(); } === modified file 'src/adaptation/ServiceGroups.cc' --- src/adaptation/ServiceGroups.cc 2014-02-02 09:42:23 +0000 +++ src/adaptation/ServiceGroups.cc 2014-04-08 12:43:40 +0000 @@ -294,39 +294,50 @@ Adaptation::ServicePointer Adaptation::ServicePlan::next(const ServiceFilter &filter) { if (!atEof && !group->findLink(filter, ++pos)) atEof = true; return current(); } std::ostream & Adaptation::ServicePlan::print(std::ostream &os) const { if (!group) return os << "[nil]"; return os << group->id << '[' << pos << ".." << group->services.size() << (atEof ? ".]" : "]"); } /* globals */ +class GroupsCfg { +public: + Adaptation::Groups groups; + ~GroupsCfg() { + while (!groups.empty()) { + // groups are refcounted so we do not explicitly delete them + groups.pop_back(); + } + } +}; + +static GroupsCfg TheGroupsCfg; Adaptation::Groups & Adaptation::AllGroups() { - static Groups TheGroups; - return TheGroups; + return TheGroupsCfg.groups; } Adaptation::ServiceGroupPointer Adaptation::FindGroup(const ServiceGroup::Id &id) { typedef Groups::iterator GI; for (GI i = AllGroups().begin(); i != AllGroups().end(); ++i) { if ((*i)->id == id) return *i; } return NULL; } === modified file 'src/cache_cf.cc' --- src/cache_cf.cc 2014-03-30 12:00:34 +0000 +++ src/cache_cf.cc 2014-04-08 12:44:33 +0000 @@ -4362,78 +4362,80 @@ } static void parse_adaptation_access_type() { Adaptation::Config::ParseAccess(LegacyParser); } #endif /* USE_ADAPTATION */ #if ICAP_CLIENT static void parse_icap_service_type(Adaptation::Icap::Config * cfg) { cfg->parseService(); } static void free_icap_service_type(Adaptation::Icap::Config * cfg) { + Adaptation::Config::Clear(); cfg->freeService(); } static void dump_icap_service_type(StoreEntry * entry, const char *name, const Adaptation::Icap::Config &cfg) { cfg.dumpService(entry, name); } static void parse_icap_class_type() { debugs(93, DBG_CRITICAL, "WARNING: 'icap_class' is depricated. " << "Use 'adaptation_service_set' instead"); Adaptation::Config::ParseServiceSet(); } static void parse_icap_access_type() { debugs(93, DBG_CRITICAL, "WARNING: 'icap_access' is depricated. " << "Use 'adaptation_access' instead"); Adaptation::Config::ParseAccess(LegacyParser); } #endif #if USE_ECAP static void parse_ecap_service_type(Adaptation::Ecap::Config * cfg) { cfg->parseService(); } static void free_ecap_service_type(Adaptation::Ecap::Config * cfg) { + Adaptation::Config::Clear(); cfg->freeService(); } static void dump_ecap_service_type(StoreEntry * entry, const char *name, const Adaptation::Ecap::Config &cfg) { cfg.dumpService(entry, name); } #endif /* USE_ECAP */ #if ICAP_CLIENT static void parse_icap_service_failure_limit(Adaptation::Icap::Config *cfg) { char *token; time_t d; time_t m; cfg->service_failure_limit = GetInteger(); if ((token = ConfigParser::NextToken()) == NULL)