]> git.ipfire.org Git - thirdparty/squid.git/blame - src/store/Disk.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / store / Disk.cc
CommitLineData
d3b3ab85 1/*
4ac4a490 2 * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
d3b3ab85 3 *
bbc27441
AJ
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.
d3b3ab85 7 */
8
bbc27441
AJ
9/* DEBUG: section 20 Swap Dir base object */
10
582c2af2 11#include "squid.h"
8a01b99e 12#include "cache_cf.h"
27bc2077 13#include "compat/strtoll.h"
b9ae18aa 14#include "ConfigOption.h"
2eceb328 15#include "ConfigParser.h"
af69c635 16#include "globals.h"
8a01b99e 17#include "Parsing.h"
4d5904f7 18#include "SquidConfig.h"
2745fea5
AR
19#include "Store.h"
20#include "store/Disk.h"
b3f7fd88 21#include "StoreFileSystem.h"
5bed43d6 22#include "tools.h"
d3b3ab85 23
2745fea5 24Store::Disk::Disk(char const *aType): theType(aType),
5ca027f0 25 max_size(0), min_objsize(-1), max_objsize (-1),
f53969cc
SM
26 path(NULL), index(-1), disker(-1),
27 repl(NULL), removals(0), scanned(0),
28 cleanLog(NULL)
e2851fe7
AR
29{
30 fs.blksize = 1024;
31}
32
2745fea5 33Store::Disk::~Disk()
62e76326 34{
e2851fe7 35 // TODO: should we delete repl?
d3b3ab85 36 xfree(path);
37}
38
39void
2745fea5 40Store::Disk::create() {}
d3b3ab85 41
42void
2745fea5 43Store::Disk::dump(StoreEntry &)const {}
d3b3ab85 44
45bool
2745fea5 46Store::Disk::doubleCheck(StoreEntry &)
d3b3ab85 47{
48 return false;
49}
50
51void
2745fea5 52Store::Disk::getStats(StoreInfoStats &stats) const
93bc1434
AR
53{
54 if (!doReportStat())
55 return;
56
57 stats.swap.size = currentSize();
58 stats.swap.capacity = maxSize();
59 stats.swap.count = currentCount();
60}
61
c8f4eac4 62void
2745fea5 63Store::Disk::stat(StoreEntry &output) const
c8f4eac4 64{
39c1e1d9
DK
65 if (!doReportStat())
66 return;
67
c8f4eac4 68 storeAppendPrintf(&output, "Store Directory #%d (%s): %s\n", index, type(),
69 path);
70 storeAppendPrintf(&output, "FS Block Size %d Bytes\n",
71 fs.blksize);
72 statfs(output);
73
74 if (repl) {
75 storeAppendPrintf(&output, "Removal policy: %s\n", repl->_type);
76
77 if (repl->Stats)
78 repl->Stats(repl, &output);
79 }
80}
81
d3b3ab85 82void
2745fea5 83Store::Disk::statfs(StoreEntry &)const {}
d3b3ab85 84
85void
2745fea5 86Store::Disk::maintain() {}
c8f4eac4 87
12e11a5c 88uint64_t
2745fea5 89Store::Disk::minSize() const
c8f4eac4 90{
2745fea5 91 // XXX: Not all disk stores use Config.Swap.lowWaterMark
12e11a5c 92 return ((maxSize() * Config.Swap.lowWaterMark) / 100);
c8f4eac4 93}
d3b3ab85 94
5ca027f0
AR
95int64_t
96Store::Disk::minObjectSize() const
97{
98 // per-store min-size=N value is authoritative
99 return min_objsize > -1 ? min_objsize : Config.Store.minObjectSize;
100}
101
b51ec8c8 102int64_t
2745fea5 103Store::Disk::maxObjectSize() const
b51ec8c8
AJ
104{
105 // per-store max-size=N value is authoritative
106 if (max_objsize > -1)
107 return max_objsize;
108
109 // store with no individual max limit is limited by configured maximum_object_size
110 // or the total store size, whichever is smaller
111 return min(static_cast<int64_t>(maxSize()), Config.Store.maxObjectSize);
112}
113
114void
2745fea5 115Store::Disk::maxObjectSize(int64_t newMax)
b51ec8c8
AJ
116{
117 // negative values mean no limit (-1)
118 if (newMax < 0) {
119 max_objsize = -1; // set explicitly in case it had a non-default value previously
120 return;
121 }
122
123 // prohibit values greater than total storage area size
124 // but set max_objsize to the maximum allowed to override maximum_object_size global config
125 if (static_cast<uint64_t>(newMax) > maxSize()) {
126 debugs(47, DBG_PARSE_NOTE(2), "WARNING: Ignoring 'max-size' option for " << path <<
127 " which is larger than total cache_dir size of " << maxSize() << " bytes.");
128 max_objsize = maxSize();
129 return;
130 }
131
132 max_objsize = newMax;
133}
134
d3b3ab85 135void
2745fea5 136Store::Disk::reference(StoreEntry &) {}
d3b3ab85 137
4c973beb 138bool
2745fea5 139Store::Disk::dereference(StoreEntry &)
4c973beb
AR
140{
141 return true; // keep in global store_table
142}
d3b3ab85 143
2745fea5
AR
144void
145Store::Disk::diskFull()
d3b3ab85 146{
2745fea5
AR
147 if (currentSize() >= maxSize())
148 return;
149
150 max_size = currentSize();
151
152 debugs(20, DBG_IMPORTANT, "WARNING: Shrinking cache_dir #" << index << " to " << currentSize() / 1024.0 << " KB");
153}
154
155bool
156Store::Disk::objectSizeIsAcceptable(int64_t objsize) const
157{
5ca027f0
AR
158 // need either the expected or the already accumulated object size
159 assert(objsize >= 0);
160 return minObjectSize() <= objsize && objsize <= maxObjectSize();
d3b3ab85 161}
162
aa1a691e 163bool
2745fea5 164Store::Disk::canStore(const StoreEntry &e, int64_t diskSpaceNeeded, int &load) const
aa1a691e
AR
165{
166 debugs(47,8, HERE << "cache_dir[" << index << "]: needs " <<
167 diskSpaceNeeded << " <? " << max_objsize);
168
169 if (EBIT_TEST(e.flags, ENTRY_SPECIAL))
170 return false; // we do not store Squid-generated entries
171
172 if (!objectSizeIsAcceptable(diskSpaceNeeded))
173 return false; // does not satisfy size limits
174
175 if (flags.read_only)
176 return false; // cannot write at all
177
cc34568d 178 if (currentSize() > maxSize())
aa1a691e
AR
179 return false; // already overflowing
180
181 /* Return 999 (99.9%) constant load; TODO: add a named constant for this */
182 load = 999;
183 return true; // kids may provide more tests and should report true load
184}
185
d3b3ab85 186/* Move to StoreEntry ? */
187bool
2745fea5 188Store::Disk::canLog(StoreEntry const &e)const
d3b3ab85 189{
190 if (e.swap_filen < 0)
62e76326 191 return false;
192
d3b3ab85 193 if (e.swap_status != SWAPOUT_DONE)
62e76326 194 return false;
195
d3b3ab85 196 if (e.swap_file_sz <= 0)
62e76326 197 return false;
198
d3b3ab85 199 if (EBIT_TEST(e.flags, RELEASE_REQUEST))
62e76326 200 return false;
201
d3b3ab85 202 if (EBIT_TEST(e.flags, KEY_PRIVATE))
62e76326 203 return false;
204
d3b3ab85 205 if (EBIT_TEST(e.flags, ENTRY_SPECIAL))
62e76326 206 return false;
207
d3b3ab85 208 return true;
209}
210
211void
2745fea5 212Store::Disk::openLog() {}
d3b3ab85 213
214void
2745fea5 215Store::Disk::closeLog() {}
d3b3ab85 216
217int
2745fea5 218Store::Disk::writeCleanStart()
d3b3ab85 219{
220 return 0;
221}
222
223void
2745fea5 224Store::Disk::writeCleanDone() {}
d3b3ab85 225
226void
2745fea5 227Store::Disk::logEntry(const StoreEntry &, int) const {}
59b2d47f 228
229char const *
2745fea5 230Store::Disk::type() const
59b2d47f 231{
232 return theType;
233}
234
14911a4e 235bool
2745fea5 236Store::Disk::active() const
14911a4e
AR
237{
238 if (IamWorkerProcess())
239 return true;
240
241 // we are inside a disker dedicated to this disk
3b581957 242 if (KidIdentifier == disker)
14911a4e
AR
243 return true;
244
245 return false; // Coordinator, wrong disker, etc.
246}
247
248bool
2745fea5 249Store::Disk::needsDiskStrand() const
14911a4e
AR
250{
251 return false;
252}
253
59b2d47f 254/* NOT performance critical. Really. Don't bother optimising for speed
26ac0430 255 * - RBC 20030718
59b2d47f 256 */
b9ae18aa 257ConfigOption *
2745fea5 258Store::Disk::getOptionTree() const
59b2d47f 259{
b9ae18aa 260 ConfigOptionVector *result = new ConfigOptionVector;
2745fea5
AR
261 result->options.push_back(new ConfigOptionAdapter<Disk>(*const_cast<Disk*>(this), &Store::Disk::optionReadOnlyParse, &Store::Disk::optionReadOnlyDump));
262 result->options.push_back(new ConfigOptionAdapter<Disk>(*const_cast<Disk*>(this), &Store::Disk::optionObjectSizeParse, &Store::Disk::optionObjectSizeDump));
59b2d47f 263 return result;
264}
265
266void
2745fea5 267Store::Disk::parseOptions(int isaReconfig)
59b2d47f 268{
1a6347cd 269 const bool old_read_only = flags.read_only;
59b2d47f 270 char *name, *value;
271
b9ae18aa 272 ConfigOption *newOption = getOptionTree();
59b2d47f 273
2eceb328 274 while ((name = ConfigParser::NextToken()) != NULL) {
59b2d47f 275 value = strchr(name, '=');
276
f412b2d6 277 if (value) {
f53969cc 278 *value = '\0'; /* cut on = */
f412b2d6
FC
279 ++value;
280 }
59b2d47f 281
2745fea5 282 debugs(3,2, "cache_dir " << name << '=' << (value ? value : ""));
d9e04dc7 283
59b2d47f 284 if (newOption)
e053c141 285 if (!newOption->parse(name, value, isaReconfig))
59b2d47f 286 self_destruct();
287 }
288
289 delete newOption;
290
291 /*
292 * Handle notifications about reconfigured single-options with no value
293 * where the removal of the option cannot be easily detected in the
294 * parsing...
295 */
296
e053c141 297 if (isaReconfig) {
59b2d47f 298 if (old_read_only != flags.read_only) {
e0236918 299 debugs(3, DBG_IMPORTANT, "Cache dir '" << path << "' now " << (flags.read_only ? "No-Store" : "Read-Write"));
59b2d47f 300 }
301 }
302}
303
304void
2745fea5 305Store::Disk::dumpOptions(StoreEntry * entry) const
59b2d47f 306{
b9ae18aa 307 ConfigOption *newOption = getOptionTree();
59b2d47f 308
309 if (newOption)
310 newOption->dump(entry);
311
312 delete newOption;
313}
314
315bool
2745fea5 316Store::Disk::optionReadOnlyParse(char const *option, const char *value, int)
59b2d47f 317{
7f42bc3e 318 if (strcmp(option, "no-store") != 0 && strcmp(option, "read-only") != 0)
59b2d47f 319 return false;
320
3b31a711
AJ
321 if (strcmp(option, "read-only") == 0) {
322 debugs(3, DBG_PARSE_NOTE(3), "UPGRADE WARNING: Replace cache_dir option 'read-only' with 'no-store'.");
323 }
324
1a6347cd 325 bool read_only = 0;
59b2d47f 326
327 if (value)
1a6347cd 328 read_only = (xatoi(value) != 0);
59b2d47f 329 else
1a6347cd 330 read_only = true;
59b2d47f 331
332 flags.read_only = read_only;
333
334 return true;
335}
336
337void
2745fea5 338Store::Disk::optionReadOnlyDump(StoreEntry * e) const
59b2d47f 339{
340 if (flags.read_only)
7f42bc3e 341 storeAppendPrintf(e, " no-store");
59b2d47f 342}
343
344bool
2745fea5 345Store::Disk::optionObjectSizeParse(char const *option, const char *value, int isaReconfig)
59b2d47f 346{
a8a33c46
A
347 int64_t *val;
348 if (strcmp(option, "max-size") == 0) {
349 val = &max_objsize;
350 } else if (strcmp(option, "min-size") == 0) {
351 val = &min_objsize;
352 } else
59b2d47f 353 return false;
354
355 if (!value)
356 self_destruct();
357
47f6e231 358 int64_t size = strtoll(value, NULL, 10);
59b2d47f 359
24063512
DK
360 if (isaReconfig && *val != size) {
361 if (allowOptionReconfigure(option)) {
362 debugs(3, DBG_IMPORTANT, "cache_dir '" << path << "' object " <<
363 option << " now " << size << " Bytes");
364 } else {
365 debugs(3, DBG_IMPORTANT, "WARNING: cache_dir '" << path << "' "
366 "object " << option << " cannot be changed dynamically, " <<
367 "value left unchanged (" << *val << " Bytes)");
368 return true;
369 }
370 }
59b2d47f 371
a8a33c46 372 *val = size;
59b2d47f 373
374 return true;
375}
376
377void
2745fea5 378Store::Disk::optionObjectSizeDump(StoreEntry * e) const
59b2d47f 379{
5ca027f0 380 if (min_objsize != -1)
c91ca3ce 381 storeAppendPrintf(e, " min-size=%" PRId64, min_objsize);
a8a33c46 382
59b2d47f 383 if (max_objsize != -1)
c91ca3ce 384 storeAppendPrintf(e, " max-size=%" PRId64, max_objsize);
59b2d47f 385}
c8f4eac4 386
44def0f9 387// some SwapDirs may maintain their indexes and be able to lookup an entry key
c8f4eac4 388StoreEntry *
2745fea5 389Store::Disk::get(const cache_key *)
c8f4eac4 390{
44def0f9 391 return NULL;
c8f4eac4 392}
7d84d4ca 393