]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ufscommon.cc
add range header, Range objects represent [start,end)
[thirdparty/squid.git] / src / ufscommon.cc
CommitLineData
4d6d905e 1/*
0aa2c37c 2 * $Id: ufscommon.cc,v 1.6 2003/01/09 11:49:35 hno Exp $
4d6d905e 3 *
4 * DEBUG: section 47 Store Directory Routines
5 * AUTHOR: Duane Wessels
6 *
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
9 *
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
32 *
33 */
34
35#include "ufscommon.h"
e6ccf245 36#include "Store.h"
d3b3ab85 37#include "RefCount.h"
4d6d905e 38
d3b3ab85 39CBDATA_CLASS_INIT(RebuildState);
4d6d905e 40
d3b3ab85 41void *
42RebuildState::operator new (size_t size)
4d6d905e 43{
d3b3ab85 44 assert (size == sizeof(RebuildState));
45 CBDATA_INIT_TYPE(RebuildState);
46 RebuildState *result = cbdataAlloc(RebuildState);
47 /* Mark result as being owned - we want the refcounter to do the delete
48 * call */
49 cbdataReference(result);
50 return result;
4d6d905e 51}
d3b3ab85 52
4d6d905e 53void
d3b3ab85 54RebuildState::operator delete (void *address)
4d6d905e 55{
d3b3ab85 56 RebuildState *t = static_cast<RebuildState *>(address);
57 cbdataFree(address);
58 /* And allow the memory to be freed */
59 cbdataReferenceDone (t);
4d6d905e 60}
61
62void
d3b3ab85 63RebuildState::deleteSelf() const
4d6d905e 64{
d3b3ab85 65 delete this;
4d6d905e 66}
67
d3b3ab85 68RebuildState::~RebuildState()
4d6d905e 69{
d3b3ab85 70 store_dirs_rebuilding--;
71 sd->closeTmpSwapLog();
72 storeRebuildComplete(&counts);
4d6d905e 73}
74
75void
d3b3ab85 76RebuildState::RebuildFromDirectory(void *data)
4d6d905e 77{
d3b3ab85 78 RebuildState *rb = (RebuildState *)data;
79 rb->rebuildFromDirectory();
4d6d905e 80}
81
82void
d3b3ab85 83RebuildState::rebuildFromDirectory()
4d6d905e 84{
4d6d905e 85 LOCAL_ARRAY(char, hdr_buf, SM_PAGE_SIZE);
86 StoreEntry *e = NULL;
87 StoreEntry tmpe;
88 cache_key key[MD5_DIGEST_CHARS];
4d6d905e 89 struct stat sb;
90 int swap_hdr_len;
91 int fd = -1;
92 tlv *tlv_list;
93 tlv *t;
d3b3ab85 94 assert(this != NULL);
95 debug(47, 3) ("commonUfsDirRebuildFromDirectory: DIR #%d\n", sd->index);
96 for (int count = 0; count < speed; count++) {
4d6d905e 97 assert(fd == -1);
d3b3ab85 98 sfileno filn = 0;
99 int size;
100 fd = getNextFile(&filn, &size);
4d6d905e 101 if (fd == -2) {
102 debug(47, 1) ("Done scanning %s swaplog (%d entries)\n",
d3b3ab85 103 sd->path, n_read);
104 deleteSelf();
4d6d905e 105 return;
106 } else if (fd < 0) {
107 continue;
108 }
109 assert(fd > -1);
110 /* lets get file stats here */
111 if (fstat(fd, &sb) < 0) {
112 debug(47, 1) ("commonUfsDirRebuildFromDirectory: fstat(FD %d): %s\n",
113 fd, xstrerror());
114 file_close(fd);
115 store_open_disk_fd--;
116 fd = -1;
117 continue;
118 }
d3b3ab85 119 if ((++counts.scancount & 0xFFFF) == 0)
4d6d905e 120 debug(47, 3) (" %s %7d files opened so far.\n",
d3b3ab85 121 sd->path, counts.scancount);
4d6d905e 122 debug(47, 9) ("file_in: fd=%d %08X\n", fd, filn);
123 statCounter.syscalls.disk.reads++;
124 if (FD_READ_METHOD(fd, hdr_buf, SM_PAGE_SIZE) < 0) {
125 debug(47, 1) ("commonUfsDirRebuildFromDirectory: read(FD %d): %s\n",
126 fd, xstrerror());
127 file_close(fd);
128 store_open_disk_fd--;
129 fd = -1;
130 continue;
131 }
132 file_close(fd);
133 store_open_disk_fd--;
134 fd = -1;
135 swap_hdr_len = 0;
136#if USE_TRUNCATE
137 if (sb.st_size == 0)
138 continue;
139#endif
140 tlv_list = storeSwapMetaUnpack(hdr_buf, &swap_hdr_len);
141 if (tlv_list == NULL) {
142 debug(47, 1) ("commonUfsDirRebuildFromDirectory: failed to get meta data\n");
143 /* XXX shouldn't this be a call to commonUfsUnlink ? */
d3b3ab85 144 sd->unlinkFile (filn);
4d6d905e 145 continue;
146 }
147 debug(47, 3) ("commonUfsDirRebuildFromDirectory: successful swap meta unpacking\n");
148 memset(key, '\0', MD5_DIGEST_CHARS);
149 memset(&tmpe, '\0', sizeof(StoreEntry));
150 for (t = tlv_list; t; t = t->next) {
151 switch (t->type) {
152 case STORE_META_KEY:
153 assert(t->length == MD5_DIGEST_CHARS);
154 xmemcpy(key, t->value, MD5_DIGEST_CHARS);
155 break;
156 case STORE_META_STD:
157 assert(t->length == STORE_HDR_METASIZE);
158 xmemcpy(&tmpe.timestamp, t->value, STORE_HDR_METASIZE);
159 break;
160 default:
161 break;
162 }
163 }
164 storeSwapTLVFree(tlv_list);
165 tlv_list = NULL;
166 if (storeKeyNull(key)) {
167 debug(47, 1) ("commonUfsDirRebuildFromDirectory: NULL key\n");
d3b3ab85 168 sd->unlinkFile(filn);
4d6d905e 169 continue;
170 }
332dafa2 171 tmpe.key = key;
4d6d905e 172 /* check sizes */
173 if (tmpe.swap_file_sz == 0) {
933c4a31 174 tmpe.swap_file_sz = (size_t) sb.st_size;
e6ccf245 175 } else if (tmpe.swap_file_sz == (size_t)(sb.st_size - swap_hdr_len)) {
933c4a31 176 tmpe.swap_file_sz = (size_t) sb.st_size;
e6ccf245 177 } else if (tmpe.swap_file_sz != (size_t)sb.st_size) {
4d6d905e 178 debug(47, 1) ("commonUfsDirRebuildFromDirectory: SIZE MISMATCH %ld!=%ld\n",
179 (long int) tmpe.swap_file_sz, (long int) sb.st_size);
d3b3ab85 180 sd->unlinkFile(filn);
4d6d905e 181 continue;
182 }
183 if (EBIT_TEST(tmpe.flags, KEY_PRIVATE)) {
d3b3ab85 184 sd->unlinkFile(filn);
185 counts.badflags++;
4d6d905e 186 continue;
187 }
188 e = storeGet(key);
189 if (e && e->lastref >= tmpe.lastref) {
190 /* key already exists, current entry is newer */
191 /* keep old, ignore new */
d3b3ab85 192 counts.dupcount++;
4d6d905e 193 continue;
194 } else if (NULL != e) {
195 /* URL already exists, this swapfile not being used */
196 /* junk old, load new */
197 storeRelease(e); /* release old entry */
d3b3ab85 198 counts.dupcount++;
4d6d905e 199 }
d3b3ab85 200 counts.objcount++;
4d6d905e 201 storeEntryDump(&tmpe, 5);
d3b3ab85 202 e = sd->addDiskRestore(key,
4d6d905e 203 filn,
204 tmpe.swap_file_sz,
205 tmpe.expires,
206 tmpe.timestamp,
207 tmpe.lastref,
208 tmpe.lastmod,
209 tmpe.refcount, /* refcount */
210 tmpe.flags, /* flags */
d3b3ab85 211 (int) flags.clean);
4d6d905e 212 storeDirSwapLog(e, SWAP_LOG_ADD);
213 }
d3b3ab85 214 eventAdd("storeRebuild", RebuildFromDirectory, this, 0.0, 1);
4d6d905e 215}
216
217void
d3b3ab85 218RebuildState::RebuildFromSwapLog(void *data)
4d6d905e 219{
e6ccf245 220 RebuildState *rb = (RebuildState *)data;
d3b3ab85 221 rb->rebuildFromSwapLog();
222}
223
224void
225RebuildState::rebuildFromSwapLog()
226{
4d6d905e 227 StoreEntry *e = NULL;
4d6d905e 228 double x;
4d6d905e 229 /* load a number of objects per invocation */
d3b3ab85 230 for (int count = 0; count < speed; count++) {
231 storeSwapLogData s;
232 size_t ss = sizeof(storeSwapLogData);
233 if (fread(&s, ss, 1, log) != 1) {
4d6d905e 234 debug(47, 1) ("Done reading %s swaplog (%d entries)\n",
d3b3ab85 235 sd->path, n_read);
236 fclose(log);
237 log = NULL;
238 delete this;
4d6d905e 239 return;
240 }
d3b3ab85 241 n_read++;
4d6d905e 242 if (s.op <= SWAP_LOG_NOP)
243 continue;
244 if (s.op >= SWAP_LOG_MAX)
245 continue;
246 /*
247 * BC: during 2.4 development, we changed the way swap file
248 * numbers are assigned and stored. The high 16 bits used
249 * to encode the SD index number. There used to be a call
250 * to storeDirProperFileno here that re-assigned the index
251 * bits. Now, for backwards compatibility, we just need
252 * to mask it off.
253 */
254 s.swap_filen &= 0x00FFFFFF;
255 debug(47, 3) ("commonUfsDirRebuildFromSwapLog: %s %s %08X\n",
256 swap_log_op_str[(int) s.op],
257 storeKeyText(s.key),
258 s.swap_filen);
259 if (s.op == SWAP_LOG_ADD) {
260 (void) 0;
261 } else if (s.op == SWAP_LOG_DEL) {
0aa2c37c 262 /* Delete unless we already have a newer copy */
263 if ((e = storeGet(s.key)) != NULL && s.lastref > e->lastref) {
4d6d905e 264 /*
265 * Make sure we don't unlink the file, it might be
266 * in use by a subsequent entry. Also note that
267 * we don't have to subtract from store_swap_size
268 * because adding to store_swap_size happens in
269 * the cleanup procedure.
270 */
271 storeExpireNow(e);
272 storeReleaseRequest(e);
273 if (e->swap_filen > -1) {
d3b3ab85 274 sd->replacementRemove(e);
275 sd->mapBitReset(e->swap_filen);
4d6d905e 276 e->swap_filen = -1;
277 e->swap_dirn = -1;
278 }
279 storeRelease(e);
d3b3ab85 280 counts.objcount--;
281 counts.cancelcount++;
4d6d905e 282 }
283 continue;
284 } else {
d3b3ab85 285 x = ::log(++counts.bad_log_op) / ::log(10.0);
4d6d905e 286 if (0.0 == x - (double) (int) x)
287 debug(47, 1) ("WARNING: %d invalid swap log entries found\n",
d3b3ab85 288 counts.bad_log_op);
289 counts.invalid++;
4d6d905e 290 continue;
291 }
d3b3ab85 292 if ((++counts.scancount & 0xFFF) == 0) {
4d6d905e 293 struct stat sb;
d3b3ab85 294 if (0 == fstat(fileno(log), &sb))
295 storeRebuildProgress(sd->index,
296 (int) sb.st_size / ss, n_read);
4d6d905e 297 }
d3b3ab85 298 if (!sd->validFileno(s.swap_filen, 0)) {
299 counts.invalid++;
4d6d905e 300 continue;
301 }
302 if (EBIT_TEST(s.flags, KEY_PRIVATE)) {
d3b3ab85 303 counts.badflags++;
4d6d905e 304 continue;
305 }
306 e = storeGet(s.key);
d3b3ab85 307 int used; /* is swapfile already in use? */
308 used = sd->mapBitTest(s.swap_filen);
4d6d905e 309 /* If this URL already exists in the cache, does the swap log
310 * appear to have a newer entry? Compare 'lastref' from the
311 * swap log to e->lastref. */
d3b3ab85 312 /* is the log entry newer than current entry? */
313 int disk_entry_newer = e ? (s.lastref > e->lastref ? 1 : 0) : 0;
4d6d905e 314 if (used && !disk_entry_newer) {
315 /* log entry is old, ignore it */
d3b3ab85 316 counts.clashcount++;
4d6d905e 317 continue;
d3b3ab85 318 } else if (used && e && e->swap_filen == s.swap_filen && e->swap_dirn == sd->index) {
4d6d905e 319 /* swapfile taken, same URL, newer, update meta */
320 if (e->store_status == STORE_OK) {
321 e->lastref = s.timestamp;
322 e->timestamp = s.timestamp;
323 e->expires = s.expires;
324 e->lastmod = s.lastmod;
325 e->flags = s.flags;
326 e->refcount += s.refcount;
d3b3ab85 327 sd->dereference(*e);
4d6d905e 328 } else {
329 debug_trap("commonUfsDirRebuildFromSwapLog: bad condition");
330 debug(47, 1) ("\tSee %s:%d\n", __FILE__, __LINE__);
331 }
332 continue;
333 } else if (used) {
334 /* swapfile in use, not by this URL, log entry is newer */
335 /* This is sorta bad: the log entry should NOT be newer at this
336 * point. If the log is dirty, the filesize check should have
337 * caught this. If the log is clean, there should never be a
338 * newer entry. */
339 debug(47, 1) ("WARNING: newer swaplog entry for dirno %d, fileno %08X\n",
d3b3ab85 340 sd->index, s.swap_filen);
4d6d905e 341 /* I'm tempted to remove the swapfile here just to be safe,
342 * but there is a bad race condition in the NOVM version if
343 * the swapfile has recently been opened for writing, but
344 * not yet opened for reading. Because we can't map
345 * swapfiles back to StoreEntrys, we don't know the state
346 * of the entry using that file. */
347 /* We'll assume the existing entry is valid, probably because
348 * were in a slow rebuild and the the swap file number got taken
349 * and the validation procedure hasn't run. */
d3b3ab85 350 assert(flags.need_to_validate);
351 counts.clashcount++;
4d6d905e 352 continue;
353 } else if (e && !disk_entry_newer) {
354 /* key already exists, current entry is newer */
355 /* keep old, ignore new */
d3b3ab85 356 counts.dupcount++;
4d6d905e 357 continue;
358 } else if (e) {
359 /* key already exists, this swapfile not being used */
360 /* junk old, load new */
361 storeExpireNow(e);
362 storeReleaseRequest(e);
363 if (e->swap_filen > -1) {
d3b3ab85 364 sd->replacementRemove(e);
4d6d905e 365 /* Make sure we don't actually unlink the file */
d3b3ab85 366 sd->mapBitReset(e->swap_filen);
4d6d905e 367 e->swap_filen = -1;
368 e->swap_dirn = -1;
369 }
370 storeRelease(e);
d3b3ab85 371 counts.dupcount++;
4d6d905e 372 } else {
373 /* URL doesnt exist, swapfile not in use */
374 /* load new */
375 (void) 0;
376 }
377 /* update store_swap_size */
d3b3ab85 378 counts.objcount++;
379 e = sd->addDiskRestore(s.key,
4d6d905e 380 s.swap_filen,
381 s.swap_file_sz,
382 s.expires,
383 s.timestamp,
384 s.lastref,
385 s.lastmod,
386 s.refcount,
387 s.flags,
d3b3ab85 388 (int) flags.clean);
4d6d905e 389 storeDirSwapLog(e, SWAP_LOG_ADD);
390 }
d3b3ab85 391 eventAdd("storeRebuild", RebuildFromSwapLog, this, 0.0, 1);
4d6d905e 392}
393
394int
d3b3ab85 395RebuildState::getNextFile(sfileno * filn_p, int *size)
4d6d905e 396{
4d6d905e 397 int fd = -1;
4d6d905e 398 int dirs_opened = 0;
399 debug(47, 3) ("commonUfsDirGetNextFile: flag=%d, %d: /%02X/%02X\n",
d3b3ab85 400 flags.init,
401 sd->index,
402 curlvl1,
403 curlvl2);
404 if (done)
4d6d905e 405 return -2;
d3b3ab85 406 while (fd < 0 && done == 0) {
4d6d905e 407 fd = -1;
d3b3ab85 408 if (0 == flags.init) { /* initialize, open first file */
409 done = 0;
410 curlvl1 = 0;
411 curlvl2 = 0;
412 in_dir = 0;
413 flags.init = 1;
4d6d905e 414 assert(Config.cacheSwap.n_configured > 0);
415 }
d3b3ab85 416 if (0 == in_dir) { /* we need to read in a new directory */
417 snprintf(fullpath, SQUID_MAXPATHLEN, "%s/%02X/%02X",
418 sd->path,
419 curlvl1, curlvl2);
4d6d905e 420 if (dirs_opened)
421 return -1;
d3b3ab85 422 td = opendir(fullpath);
4d6d905e 423 dirs_opened++;
d3b3ab85 424 if (td == NULL) {
4d6d905e 425 debug(47, 1) ("commonUfsDirGetNextFile: opendir: %s: %s\n",
d3b3ab85 426 fullpath, xstrerror());
4d6d905e 427 } else {
d3b3ab85 428 entry = readdir(td); /* skip . and .. */
429 entry = readdir(td);
430 if (entry == NULL && errno == ENOENT)
4d6d905e 431 debug(47, 1) ("commonUfsDirGetNextFile: directory does not exist!.\n");
d3b3ab85 432 debug(47, 3) ("commonUfsDirGetNextFile: Directory %s\n", fullpath);
4d6d905e 433 }
434 }
d3b3ab85 435 if (td != NULL && (entry = readdir(td)) != NULL) {
436 in_dir++;
437 if (sscanf(entry->d_name, "%x", &fn) != 1) {
4d6d905e 438 debug(47, 3) ("commonUfsDirGetNextFile: invalid %s\n",
d3b3ab85 439 entry->d_name);
4d6d905e 440 continue;
441 }
d3b3ab85 442 if (!UFSSwapDir::FilenoBelongsHere(fn, sd->index, curlvl1, curlvl2)) {
4d6d905e 443 debug(47, 3) ("commonUfsDirGetNextFile: %08X does not belong in %d/%d/%d\n",
d3b3ab85 444 fn, sd->index, curlvl1, curlvl2);
4d6d905e 445 continue;
446 }
d3b3ab85 447 if (sd->mapBitTest(fn)) {
4d6d905e 448 debug(47, 3) ("commonUfsDirGetNextFile: Locked, continuing with next.\n");
449 continue;
450 }
d3b3ab85 451 snprintf(fullfilename, SQUID_MAXPATHLEN, "%s/%s",
452 fullpath, entry->d_name);
453 debug(47, 3) ("commonUfsDirGetNextFile: Opening %s\n", fullfilename);
454 fd = file_open(fullfilename, O_RDONLY | O_BINARY);
4d6d905e 455 if (fd < 0)
d3b3ab85 456 debug(47, 1) ("commonUfsDirGetNextFile: %s: %s\n", fullfilename, xstrerror());
4d6d905e 457 else
458 store_open_disk_fd++;
459 continue;
460 }
d3b3ab85 461 if (td != NULL)
462 closedir(td);
463 td = NULL;
464 in_dir = 0;
465 if (sd->validL2(++curlvl2))
4d6d905e 466 continue;
d3b3ab85 467 curlvl2 = 0;
468 if (sd->validL1(++curlvl1))
4d6d905e 469 continue;
d3b3ab85 470 curlvl1 = 0;
471 done = 1;
4d6d905e 472 }
d3b3ab85 473 *filn_p = fn;
4d6d905e 474 return fd;
475}