]>
Commit | Line | Data |
---|---|---|
b27668ec | 1 | /* |
b8ae064d | 2 | * Copyright (C) 1996-2023 The Squid Software Foundation and contributors |
b27668ec EB |
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 | ||
11 | #if USE_DELAY_POOLS | |
12 | #include "acl/Gadgets.h" | |
13 | #include "cache_cf.h" | |
14 | #include "ConfigParser.h" | |
15 | #include "DelaySpec.h" | |
16 | #include "event.h" | |
17 | #include "MessageBucket.h" | |
18 | #include "MessageDelayPools.h" | |
19 | #include "Parsing.h" | |
b27668ec EB |
20 | #include "Store.h" |
21 | ||
22 | #include <algorithm> | |
23 | #include <map> | |
24 | ||
25 | MessageDelayPools::~MessageDelayPools() | |
26 | { | |
27 | freePools(); | |
28 | } | |
29 | ||
30 | MessageDelayPools * | |
31 | MessageDelayPools::Instance() | |
32 | { | |
33 | static MessageDelayPools pools; | |
34 | return &pools; | |
35 | } | |
36 | ||
37 | MessageDelayPool::Pointer | |
38 | MessageDelayPools::pool(const SBuf &name) | |
39 | { | |
40 | auto it = std::find_if(pools.begin(), pools.end(), | |
41 | [&name](const MessageDelayPool::Pointer p) { return p->poolName == name; }); | |
aee3523a | 42 | return it == pools.end() ? nullptr : *it; |
b27668ec EB |
43 | } |
44 | ||
45 | void | |
46 | MessageDelayPools::add(MessageDelayPool *p) | |
47 | { | |
48 | const auto it = std::find_if(pools.begin(), pools.end(), | |
49 | [&p](const MessageDelayPool::Pointer mp) { return mp->poolName == p->poolName; }); | |
50 | if (it != pools.end()) { | |
51 | debugs(3, DBG_CRITICAL, "WARNING: Ignoring duplicate " << p->poolName << " response delay pool"); | |
52 | return; | |
53 | } | |
54 | pools.push_back(p); | |
55 | } | |
56 | ||
57 | void | |
58 | MessageDelayPools::freePools() | |
59 | { | |
60 | pools.clear(); | |
61 | } | |
62 | ||
63 | MessageDelayPool::MessageDelayPool(const SBuf &name, int64_t bucketSpeed, int64_t bucketSize, | |
64 | int64_t aggregateSpeed, int64_t aggregateSize, uint16_t initialBucketPercent): | |
aee3523a | 65 | access(nullptr), |
b27668ec EB |
66 | poolName(name), |
67 | individualRestore(bucketSpeed), | |
68 | individualMaximum(bucketSize), | |
69 | aggregateRestore(aggregateSpeed), | |
70 | aggregateMaximum(aggregateSize), | |
71 | initialBucketLevel(initialBucketPercent), | |
72 | lastUpdate(squid_curtime) | |
73 | { | |
74 | theBucket.level() = aggregateMaximum; | |
75 | } | |
76 | ||
77 | MessageDelayPool::~MessageDelayPool() | |
78 | { | |
79 | if (access) | |
80 | aclDestroyAccessList(&access); | |
81 | } | |
82 | ||
83 | void | |
84 | MessageDelayPool::refillBucket() | |
85 | { | |
86 | if (noLimit()) | |
87 | return; | |
88 | const int incr = squid_curtime - lastUpdate; | |
89 | if (incr >= 1) { | |
90 | lastUpdate = squid_curtime; | |
91 | DelaySpec spec; | |
92 | spec.restore_bps = aggregateRestore; | |
93 | spec.max_bytes = aggregateMaximum; | |
94 | theBucket.update(spec, incr); | |
95 | } | |
96 | } | |
97 | ||
98 | void | |
99 | MessageDelayPool::dump(StoreEntry *entry) const | |
100 | { | |
101 | SBuf name("response_delay_pool_access "); | |
102 | name.append(poolName); | |
103 | dump_acl_access(entry, name.c_str(), access); | |
104 | storeAppendPrintf(entry, "response_delay_pool parameters %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %d\n", | |
105 | individualRestore, individualMaximum, aggregateRestore, aggregateMaximum, initialBucketLevel); | |
106 | storeAppendPrintf(entry, "\n"); | |
107 | } | |
108 | ||
109 | MessageBucket::Pointer | |
110 | MessageDelayPool::createBucket() | |
111 | { | |
112 | return new MessageBucket(individualRestore, initialBucketLevel, individualMaximum, this); | |
113 | } | |
114 | ||
115 | void | |
116 | MessageDelayConfig::parseResponseDelayPool() | |
117 | { | |
118 | static const SBuf bucketSpeedLimit("individual-restore"); | |
119 | static const SBuf maxBucketSize("individual-maximum"); | |
120 | static const SBuf aggregateSpeedLimit("aggregate-restore"); | |
121 | static const SBuf maxAggregateSize("aggregate-maximum"); | |
122 | static const SBuf initialBucketPercent("initial-bucket-level"); | |
123 | ||
124 | static std::map<SBuf, int64_t> params; | |
125 | params[bucketSpeedLimit] = -1; | |
126 | params[maxBucketSize] = -1; | |
127 | params[aggregateSpeedLimit] = -1; | |
128 | params[maxAggregateSize] = -1; | |
129 | params[initialBucketPercent] = 50; | |
130 | ||
131 | const SBuf name(ConfigParser::NextToken()); | |
132 | if (name.isEmpty()) { | |
133 | debugs(3, DBG_CRITICAL, "FATAL: response_delay_pool missing required \"name\" parameter."); | |
134 | self_destruct(); | |
941bcba7 | 135 | return; |
b27668ec EB |
136 | } |
137 | ||
138 | char *key = nullptr; | |
139 | char *value = nullptr; | |
140 | while (ConfigParser::NextKvPair(key, value)) { | |
141 | if (!value) { | |
142 | debugs(3, DBG_CRITICAL, "FATAL: '" << key << "' option missing value"); | |
143 | self_destruct(); | |
941bcba7 | 144 | return; |
b27668ec EB |
145 | } |
146 | auto it = params.find(SBuf(key)); | |
147 | if (it == params.end()) { | |
148 | debugs(3, DBG_CRITICAL, "FATAL: response_delay_pool unknown option '" << key << "'"); | |
149 | self_destruct(); | |
941bcba7 | 150 | return; |
b27668ec EB |
151 | } |
152 | it->second = (it->first == initialBucketPercent) ? xatos(value) : xatoll(value, 10); | |
153 | } | |
154 | ||
155 | const char *fatalMsg = nullptr; | |
156 | if ((params[bucketSpeedLimit] < 0) != (params[maxBucketSize] < 0)) | |
157 | fatalMsg = "'individual-restore' and 'individual-maximum'"; | |
158 | else if ((params[aggregateSpeedLimit] < 0) != (params[maxAggregateSize] < 0)) | |
159 | fatalMsg = "'aggregate-restore' and 'aggregate-maximum'"; | |
160 | ||
161 | if (fatalMsg) { | |
162 | debugs(3, DBG_CRITICAL, "FATAL: must use " << fatalMsg << " options in conjunction"); | |
163 | self_destruct(); | |
941bcba7 | 164 | return; |
b27668ec EB |
165 | } |
166 | ||
167 | MessageDelayPool *pool = new MessageDelayPool(name, | |
168 | params[bucketSpeedLimit], | |
169 | params[maxBucketSize], | |
170 | params[aggregateSpeedLimit], | |
171 | params[maxAggregateSize], | |
172 | static_cast<uint16_t>(params[initialBucketPercent]) | |
173 | ); | |
174 | MessageDelayPools::Instance()->add(pool); | |
175 | } | |
176 | ||
177 | void | |
178 | MessageDelayConfig::parseResponseDelayPoolAccess() { | |
179 | const char *token = ConfigParser::NextToken(); | |
180 | if (!token) { | |
181 | debugs(3, DBG_CRITICAL, "ERROR: required pool_name option missing"); | |
182 | return; | |
183 | } | |
184 | MessageDelayPool::Pointer pool = MessageDelayPools::Instance()->pool(SBuf(token)); | |
185 | static ConfigParser parser; | |
186 | if (pool) | |
187 | aclParseAccessLine("response_delay_pool_access", parser, &pool->access); | |
188 | } | |
189 | ||
190 | void | |
191 | MessageDelayConfig::freePools() | |
192 | { | |
193 | MessageDelayPools::Instance()->freePools(); | |
194 | } | |
195 | ||
196 | void | |
8b082ed9 | 197 | MessageDelayConfig::dumpResponseDelayPoolParameters(StoreEntry *entry) |
b27668ec EB |
198 | { |
199 | auto &pools = MessageDelayPools::Instance()->pools; | |
200 | for (auto pool: pools) | |
201 | pool->dump(entry); | |
202 | } | |
203 | ||
204 | #endif | |
205 |