]> git.ipfire.org Git - thirdparty/squid.git/blob - src/SwapDir.cc
Bug 3686: cache_dir max-size default fails
[thirdparty/squid.git] / src / SwapDir.cc
1 /*
2 * DEBUG: section 20 Swap Dir base object
3 * AUTHOR: Robert Collins
4 *
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
7 *
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
30 *
31 */
32
33 #include "squid.h"
34 #include "cache_cf.h"
35 #include "compat/strtoll.h"
36 #include "ConfigOption.h"
37 #include "globals.h"
38 #include "Parsing.h"
39 #include "SquidConfig.h"
40 #include "StoreFileSystem.h"
41 #include "SwapDir.h"
42 #include "tools.h"
43
44 SwapDir::SwapDir(char const *aType): theType(aType),
45 max_size(0), min_objsize(0), max_objsize (-1),
46 path(NULL), index(-1), disker(-1),
47 repl(NULL), removals(0), scanned(0),
48 cleanLog(NULL)
49 {
50 fs.blksize = 1024;
51 }
52
53 SwapDir::~SwapDir()
54 {
55 // TODO: should we delete repl?
56 xfree(path);
57 }
58
59 void
60 SwapDir::create() {}
61
62 void
63 SwapDir::dump(StoreEntry &)const {}
64
65 bool
66 SwapDir::doubleCheck(StoreEntry &)
67 {
68 return false;
69 }
70
71 void
72 SwapDir::unlink(StoreEntry &) {}
73
74 void
75 SwapDir::getStats(StoreInfoStats &stats) const
76 {
77 if (!doReportStat())
78 return;
79
80 stats.swap.size = currentSize();
81 stats.swap.capacity = maxSize();
82 stats.swap.count = currentCount();
83 }
84
85 void
86 SwapDir::stat(StoreEntry &output) const
87 {
88 if (!doReportStat())
89 return;
90
91 storeAppendPrintf(&output, "Store Directory #%d (%s): %s\n", index, type(),
92 path);
93 storeAppendPrintf(&output, "FS Block Size %d Bytes\n",
94 fs.blksize);
95 statfs(output);
96
97 if (repl) {
98 storeAppendPrintf(&output, "Removal policy: %s\n", repl->_type);
99
100 if (repl->Stats)
101 repl->Stats(repl, &output);
102 }
103 }
104
105 void
106 SwapDir::statfs(StoreEntry &)const {}
107
108 void
109 SwapDir::maintain() {}
110
111 uint64_t
112 SwapDir::minSize() const
113 {
114 return ((maxSize() * Config.Swap.lowWaterMark) / 100);
115 }
116
117 int64_t
118 SwapDir::maxObjectSize() const
119 {
120 // per-store max-size=N value is authoritative
121 if (max_objsize > -1)
122 return max_objsize;
123
124 // store with no individual max limit is limited by configured maximum_object_size
125 // or the total store size, whichever is smaller
126 return min(static_cast<int64_t>(maxSize()), Config.Store.maxObjectSize);
127 }
128
129 void
130 SwapDir::maxObjectSize(int64_t newMax)
131 {
132 // negative values mean no limit (-1)
133 if (newMax < 0) {
134 max_objsize = -1; // set explicitly in case it had a non-default value previously
135 return;
136 }
137
138 // prohibit values greater than total storage area size
139 // but set max_objsize to the maximum allowed to override maximum_object_size global config
140 if (static_cast<uint64_t>(newMax) > maxSize()) {
141 debugs(47, DBG_PARSE_NOTE(2), "WARNING: Ignoring 'max-size' option for " << path <<
142 " which is larger than total cache_dir size of " << maxSize() << " bytes.");
143 max_objsize = maxSize();
144 return;
145 }
146
147 max_objsize = newMax;
148 }
149
150 void
151 SwapDir::reference(StoreEntry &) {}
152
153 bool
154 SwapDir::dereference(StoreEntry &, bool)
155 {
156 return true; // keep in global store_table
157 }
158
159 int
160 SwapDir::callback()
161 {
162 return 0;
163 }
164
165 bool
166 SwapDir::canStore(const StoreEntry &e, int64_t diskSpaceNeeded, int &load) const
167 {
168 debugs(47,8, HERE << "cache_dir[" << index << "]: needs " <<
169 diskSpaceNeeded << " <? " << max_objsize);
170
171 if (EBIT_TEST(e.flags, ENTRY_SPECIAL))
172 return false; // we do not store Squid-generated entries
173
174 if (!objectSizeIsAcceptable(diskSpaceNeeded))
175 return false; // does not satisfy size limits
176
177 if (flags.read_only)
178 return false; // cannot write at all
179
180 if (currentSize() > maxSize())
181 return false; // already overflowing
182
183 /* Return 999 (99.9%) constant load; TODO: add a named constant for this */
184 load = 999;
185 return true; // kids may provide more tests and should report true load
186 }
187
188 void
189 SwapDir::sync() {}
190
191 /* Move to StoreEntry ? */
192 bool
193 SwapDir::canLog(StoreEntry const &e)const
194 {
195 if (e.swap_filen < 0)
196 return false;
197
198 if (e.swap_status != SWAPOUT_DONE)
199 return false;
200
201 if (e.swap_file_sz <= 0)
202 return false;
203
204 if (EBIT_TEST(e.flags, RELEASE_REQUEST))
205 return false;
206
207 if (EBIT_TEST(e.flags, KEY_PRIVATE))
208 return false;
209
210 if (EBIT_TEST(e.flags, ENTRY_SPECIAL))
211 return false;
212
213 return true;
214 }
215
216 void
217 SwapDir::openLog() {}
218
219 void
220 SwapDir::closeLog() {}
221
222 int
223 SwapDir::writeCleanStart()
224 {
225 return 0;
226 }
227
228 void
229 SwapDir::writeCleanDone() {}
230
231 void
232 SwapDir::logEntry(const StoreEntry & e, int op) const {}
233
234 char const *
235 SwapDir::type() const
236 {
237 return theType;
238 }
239
240 bool
241 SwapDir::active() const
242 {
243 if (IamWorkerProcess())
244 return true;
245
246 // we are inside a disker dedicated to this disk
247 if (KidIdentifier == disker)
248 return true;
249
250 return false; // Coordinator, wrong disker, etc.
251 }
252
253 bool
254 SwapDir::needsDiskStrand() const
255 {
256 return false;
257 }
258
259 /* NOT performance critical. Really. Don't bother optimising for speed
260 * - RBC 20030718
261 */
262 ConfigOption *
263 SwapDir::getOptionTree() const
264 {
265 ConfigOptionVector *result = new ConfigOptionVector;
266 result->options.push_back(new ConfigOptionAdapter<SwapDir>(*const_cast<SwapDir *>(this), &SwapDir::optionReadOnlyParse, &SwapDir::optionReadOnlyDump));
267 result->options.push_back(new ConfigOptionAdapter<SwapDir>(*const_cast<SwapDir *>(this), &SwapDir::optionObjectSizeParse, &SwapDir::optionObjectSizeDump));
268 return result;
269 }
270
271 void
272 SwapDir::parseOptions(int isaReconfig)
273 {
274 const bool old_read_only = flags.read_only;
275 char *name, *value;
276
277 ConfigOption *newOption = getOptionTree();
278
279 while ((name = strtok(NULL, w_space)) != NULL) {
280 value = strchr(name, '=');
281
282 if (value) {
283 *value = '\0'; /* cut on = */
284 ++value;
285 }
286
287 debugs(3,2, "SwapDir::parseOptions: parsing store option '" << name << "'='" << (value ? value : "") << "'");
288
289 if (newOption)
290 if (!newOption->parse(name, value, isaReconfig))
291 self_destruct();
292 }
293
294 delete newOption;
295
296 /*
297 * Handle notifications about reconfigured single-options with no value
298 * where the removal of the option cannot be easily detected in the
299 * parsing...
300 */
301
302 if (isaReconfig) {
303 if (old_read_only != flags.read_only) {
304 debugs(3, DBG_IMPORTANT, "Cache dir '" << path << "' now " << (flags.read_only ? "No-Store" : "Read-Write"));
305 }
306 }
307 }
308
309 void
310 SwapDir::dumpOptions(StoreEntry * entry) const
311 {
312 ConfigOption *newOption = getOptionTree();
313
314 if (newOption)
315 newOption->dump(entry);
316
317 delete newOption;
318 }
319
320 bool
321 SwapDir::optionReadOnlyParse(char const *option, const char *value, int isaReconfig)
322 {
323 if (strcmp(option, "no-store") != 0 && strcmp(option, "read-only") != 0)
324 return false;
325
326 if (strcmp(option, "read-only") == 0) {
327 debugs(3, DBG_PARSE_NOTE(3), "UPGRADE WARNING: Replace cache_dir option 'read-only' with 'no-store'.");
328 }
329
330 bool read_only = 0;
331
332 if (value)
333 read_only = (xatoi(value) != 0);
334 else
335 read_only = true;
336
337 flags.read_only = read_only;
338
339 return true;
340 }
341
342 void
343 SwapDir::optionReadOnlyDump(StoreEntry * e) const
344 {
345 if (flags.read_only)
346 storeAppendPrintf(e, " no-store");
347 }
348
349 bool
350 SwapDir::optionObjectSizeParse(char const *option, const char *value, int isaReconfig)
351 {
352 int64_t *val;
353 if (strcmp(option, "max-size") == 0) {
354 val = &max_objsize;
355 } else if (strcmp(option, "min-size") == 0) {
356 val = &min_objsize;
357 } else
358 return false;
359
360 if (!value)
361 self_destruct();
362
363 int64_t size = strtoll(value, NULL, 10);
364
365 if (isaReconfig && *val != size) {
366 if (allowOptionReconfigure(option)) {
367 debugs(3, DBG_IMPORTANT, "cache_dir '" << path << "' object " <<
368 option << " now " << size << " Bytes");
369 } else {
370 debugs(3, DBG_IMPORTANT, "WARNING: cache_dir '" << path << "' "
371 "object " << option << " cannot be changed dynamically, " <<
372 "value left unchanged (" << *val << " Bytes)");
373 return true;
374 }
375 }
376
377 *val = size;
378
379 return true;
380 }
381
382 void
383 SwapDir::optionObjectSizeDump(StoreEntry * e) const
384 {
385 if (min_objsize != 0)
386 storeAppendPrintf(e, " min-size=%" PRId64, min_objsize);
387
388 if (max_objsize != -1)
389 storeAppendPrintf(e, " max-size=%" PRId64, max_objsize);
390 }
391
392 // some SwapDirs may maintain their indexes and be able to lookup an entry key
393 StoreEntry *
394 SwapDir::get(const cache_key *key)
395 {
396 return NULL;
397 }
398
399 void
400 SwapDir::get(String const key, STOREGETCLIENT aCallback, void *aCallbackData)
401 {
402 fatal("not implemented");
403 }