]> git.ipfire.org Git - thirdparty/squid.git/blob - src/MessageDelayPools.cc
7b5d6c44e1a13435b19a0df50d62af91f862a108
[thirdparty/squid.git] / src / MessageDelayPools.cc
1 /*
2 * Copyright (C) 1996-2022 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
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"
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; });
42 return it == pools.end() ? nullptr : *it;
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):
65 access(nullptr),
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();
135 return;
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();
144 return;
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();
150 return;
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();
164 return;
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
197 MessageDelayConfig::dumpResponseDelayPoolParameters(StoreEntry *entry)
198 {
199 auto &pools = MessageDelayPools::Instance()->pools;
200 for (auto pool: pools)
201 pool->dump(entry);
202 }
203
204 #endif
205