]>
Commit | Line | Data |
---|---|---|
4d6d905e | 1 | /* |
7847e1fb | 2 | * $Id: ufscommon.cc,v 1.12 2007/08/01 23:21:07 amosjeffries Exp $ |
c8f4eac4 | 3 | * vim: set et : |
4d6d905e | 4 | * |
5 | * DEBUG: section 47 Store Directory Routines | |
51ee7c82 | 6 | * AUTHOR: Robert Collins |
4d6d905e | 7 | * |
8 | * SQUID Web Proxy Cache http://www.squid-cache.org/ | |
9 | * ---------------------------------------------------------- | |
10 | * | |
11 | * Squid is the result of efforts by numerous individuals from | |
12 | * the Internet community; see the CONTRIBUTORS file for full | |
13 | * details. Many organizations have provided support for Squid's | |
14 | * development; see the SPONSORS file for full details. Squid is | |
15 | * Copyrighted (C) 2001 by the Regents of the University of | |
16 | * California; see the COPYRIGHT file for full details. Squid | |
17 | * incorporates software developed and/or copyrighted by other | |
18 | * sources; see the CREDITS file for full details. | |
19 | * | |
20 | * This program is free software; you can redistribute it and/or modify | |
21 | * it under the terms of the GNU General Public License as published by | |
22 | * the Free Software Foundation; either version 2 of the License, or | |
23 | * (at your option) any later version. | |
24 | * | |
25 | * This program is distributed in the hope that it will be useful, | |
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
28 | * GNU General Public License for more details. | |
29 | * | |
30 | * You should have received a copy of the GNU General Public License | |
31 | * along with this program; if not, write to the Free Software | |
32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. | |
33 | * | |
51ee7c82 | 34 | * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org> |
4d6d905e | 35 | */ |
36 | ||
37 | #include "ufscommon.h" | |
e6ccf245 | 38 | #include "Store.h" |
528b2c61 | 39 | #include "fde.h" |
40 | #include "StoreMeta.h" | |
41 | #include "Generic.h" | |
42 | #include "StoreMetaUnpacker.h" | |
d3b3ab85 | 43 | #include "RefCount.h" |
51ee7c82 | 44 | #include "StoreSwapLogData.h" |
4d6d905e | 45 | |
d3b3ab85 | 46 | CBDATA_CLASS_INIT(RebuildState); |
4d6d905e | 47 | |
c8f4eac4 | 48 | RebuildState::RebuildState (RefCount<UFSSwapDir> aSwapDir) : sd (aSwapDir), e(NULL), fromLog(true), _done (false) |
4d6d905e | 49 | { |
c8f4eac4 | 50 | speed = opt_foreground_rebuild ? 1 << 30 : 50; |
51 | /* | |
52 | * If the swap.state file exists in the cache_dir, then | |
53 | * we'll use commonUfsDirRebuildFromSwapLog(), otherwise we'll | |
54 | * use commonUfsDirRebuildFromDirectory() to open up each file | |
55 | * and suck in the meta data. | |
56 | */ | |
57 | int clean = 0; | |
58 | int zeroLengthLog = 0; | |
59 | FILE *fp = sd->openTmpSwapLog(&clean, &zeroLengthLog); | |
60 | ||
61 | if (fp == NULL || zeroLengthLog) { | |
62 | fromLog = false; | |
63 | ||
64 | if (fp != NULL) | |
65 | fclose(fp); | |
66 | ||
67 | } else { | |
68 | fromLog = true; | |
69 | log = fp; | |
70 | flags.clean = (unsigned int) clean; | |
71 | } | |
62e76326 | 72 | |
c8f4eac4 | 73 | if (!clean) |
74 | flags.need_to_validate = 1; | |
75 | ||
bf8fe701 | 76 | debugs(47, 1, "Rebuilding storage in " << sd->path << " (" << (clean ? "CLEAN" : "DIRTY") << ")"); |
4d6d905e | 77 | } |
78 | ||
d3b3ab85 | 79 | RebuildState::~RebuildState() |
4d6d905e | 80 | { |
d3b3ab85 | 81 | sd->closeTmpSwapLog(); |
7847e1fb | 82 | /* now thats closed we DONT want to keep our secondary pointer to it */ |
83 | log = NULL; | |
4d6d905e | 84 | } |
85 | ||
86 | void | |
c8f4eac4 | 87 | RebuildState::RebuildStep(void *data) |
4d6d905e | 88 | { |
d3b3ab85 | 89 | RebuildState *rb = (RebuildState *)data; |
c8f4eac4 | 90 | rb->rebuildStep(); |
91 | ||
92 | if (!rb->isDone()) | |
93 | eventAdd("storeRebuild", RebuildStep, rb, 0.0, 1); | |
94 | else { | |
bef81ea5 | 95 | StoreController::store_dirs_rebuilding--; |
c8f4eac4 | 96 | storeRebuildComplete(&rb->counts); |
97 | delete rb; | |
98 | } | |
99 | } | |
100 | ||
101 | void | |
102 | RebuildState::rebuildStep() | |
103 | { | |
104 | if (fromLog) | |
105 | rebuildFromSwapLog(); | |
106 | else | |
107 | rebuildFromDirectory(); | |
4d6d905e | 108 | } |
109 | ||
528b2c61 | 110 | struct InitStoreEntry : public unary_function<StoreMeta, void> |
111 | { | |
112 | InitStoreEntry(StoreEntry *anEntry, cache_key *aKey):what(anEntry),index(aKey){} | |
62e76326 | 113 | |
114 | void operator()(StoreMeta const &x) | |
115 | { | |
116 | switch (x.getType()) { | |
117 | ||
118 | case STORE_META_KEY: | |
119 | assert(x.length == MD5_DIGEST_CHARS); | |
120 | xmemcpy(index, x.value, MD5_DIGEST_CHARS); | |
121 | break; | |
122 | ||
123 | case STORE_META_STD: | |
124 | assert(x.length == STORE_HDR_METASIZE); | |
125 | xmemcpy(&what->timestamp, x.value, STORE_HDR_METASIZE); | |
126 | break; | |
127 | ||
128 | default: | |
129 | break; | |
130 | } | |
528b2c61 | 131 | } |
62e76326 | 132 | |
528b2c61 | 133 | StoreEntry *what; |
134 | cache_key *index; | |
135 | }; | |
136 | ||
4d6d905e | 137 | void |
d3b3ab85 | 138 | RebuildState::rebuildFromDirectory() |
4d6d905e | 139 | { |
4d6d905e | 140 | LOCAL_ARRAY(char, hdr_buf, SM_PAGE_SIZE); |
822b78b5 | 141 | currentEntry(NULL); |
4d6d905e | 142 | StoreEntry tmpe; |
143 | cache_key key[MD5_DIGEST_CHARS]; | |
62e76326 | 144 | |
4d6d905e | 145 | struct stat sb; |
146 | int swap_hdr_len; | |
147 | int fd = -1; | |
528b2c61 | 148 | StoreMeta *tlv_list; |
d3b3ab85 | 149 | assert(this != NULL); |
bf8fe701 | 150 | debugs(47, 3, "commonUfsDirRebuildFromDirectory: DIR #" << sd->index); |
62e76326 | 151 | |
d3b3ab85 | 152 | for (int count = 0; count < speed; count++) { |
62e76326 | 153 | assert(fd == -1); |
154 | sfileno filn = 0; | |
155 | int size; | |
156 | fd = getNextFile(&filn, &size); | |
157 | ||
158 | if (fd == -2) { | |
bf8fe701 | 159 | debugs(47, 1, "Done scanning " << sd->path << " swaplog (" << n_read << " entries)"); |
c8f4eac4 | 160 | _done = true; |
62e76326 | 161 | return; |
162 | } else if (fd < 0) { | |
163 | continue; | |
164 | } | |
165 | ||
166 | assert(fd > -1); | |
167 | /* lets get file stats here */ | |
168 | ||
169 | if (fstat(fd, &sb) < 0) { | |
bf8fe701 | 170 | debugs(47, 1, "commonUfsDirRebuildFromDirectory: fstat(FD " << fd << "): " << xstrerror()); |
62e76326 | 171 | file_close(fd); |
172 | store_open_disk_fd--; | |
173 | fd = -1; | |
174 | continue; | |
175 | } | |
176 | ||
177 | if ((++counts.scancount & 0xFFFF) == 0) | |
bf8fe701 | 178 | debugs(47, 3, " " << sd->path << " " << std::setw(7) << counts.scancount << " files opened so far."); |
179 | debugs(47, 9, "file_in: fd=" << fd << " "<< std::setfill('0') << std::hex << std::uppercase << std::setw(8) << filn); | |
62e76326 | 180 | |
62e76326 | 181 | |
182 | statCounter.syscalls.disk.reads++; | |
183 | ||
184 | int len; | |
185 | ||
186 | if ((len = FD_READ_METHOD(fd, hdr_buf, SM_PAGE_SIZE)) < 0) { | |
bf8fe701 | 187 | debugs(47, 1, "commonUfsDirRebuildFromDirectory: read(FD " << fd << "): " << xstrerror()); |
62e76326 | 188 | file_close(fd); |
189 | store_open_disk_fd--; | |
190 | fd = -1; | |
191 | continue; | |
192 | } | |
193 | ||
194 | file_close(fd); | |
195 | store_open_disk_fd--; | |
196 | fd = -1; | |
197 | swap_hdr_len = 0; | |
62e76326 | 198 | |
528b2c61 | 199 | StoreMetaUnpacker aBuilder(hdr_buf, len, &swap_hdr_len); |
62e76326 | 200 | |
201 | if (!aBuilder.isBufferSane()) { | |
bf8fe701 | 202 | debugs(47, 1, "commonUfsDirRebuildFromDirectory: Swap data buffer length is not sane."); |
62e76326 | 203 | /* XXX shouldn't this be a call to commonUfsUnlink ? */ |
204 | sd->unlinkFile ( filn); | |
205 | continue; | |
206 | } | |
207 | ||
528b2c61 | 208 | tlv_list = aBuilder.createStoreMeta (); |
62e76326 | 209 | |
210 | if (tlv_list == NULL) { | |
bf8fe701 | 211 | debugs(47, 1, "commonUfsDirRebuildFromDirectory: failed to get meta data"); |
62e76326 | 212 | /* XXX shouldn't this be a call to commonUfsUnlink ? */ |
213 | sd->unlinkFile (filn); | |
214 | continue; | |
215 | } | |
216 | ||
bf8fe701 | 217 | debugs(47, 3, "commonUfsDirRebuildFromDirectory: successful swap meta unpacking"); |
62e76326 | 218 | memset(key, '\0', MD5_DIGEST_CHARS); |
219 | memset(&tmpe, '\0', sizeof(StoreEntry)); | |
220 | InitStoreEntry visitor(&tmpe, key); | |
221 | for_each(*tlv_list, visitor); | |
222 | storeSwapTLVFree(tlv_list); | |
223 | tlv_list = NULL; | |
224 | ||
225 | if (storeKeyNull(key)) { | |
bf8fe701 | 226 | debugs(47, 1, "commonUfsDirRebuildFromDirectory: NULL key"); |
62e76326 | 227 | sd->unlinkFile(filn); |
228 | continue; | |
229 | } | |
230 | ||
231 | tmpe.key = key; | |
232 | /* check sizes */ | |
233 | ||
234 | if (tmpe.swap_file_sz == 0) { | |
235 | tmpe.swap_file_sz = (size_t) sb.st_size; | |
236 | } else if (tmpe.swap_file_sz == (size_t)(sb.st_size - swap_hdr_len)) { | |
237 | tmpe.swap_file_sz = (size_t) sb.st_size; | |
238 | } else if (tmpe.swap_file_sz != (size_t)sb.st_size) { | |
bf8fe701 | 239 | debugs(47, 1, "commonUfsDirRebuildFromDirectory: SIZE MISMATCH " << |
240 | (long int) tmpe.swap_file_sz << "!=" << | |
241 | (long int) sb.st_size); | |
242 | ||
62e76326 | 243 | sd->unlinkFile(filn); |
244 | continue; | |
245 | } | |
246 | ||
247 | if (EBIT_TEST(tmpe.flags, KEY_PRIVATE)) { | |
248 | sd->unlinkFile(filn); | |
249 | counts.badflags++; | |
250 | continue; | |
251 | } | |
252 | ||
c8f4eac4 | 253 | /* this needs to become |
254 | * 1) unpack url | |
255 | * 2) make synthetic request with headers ?? or otherwise search | |
256 | * for a matching object in the store | |
257 | * TODO FIXME change to new async api | |
258 | * TODO FIXME I think there is a race condition here with the | |
259 | * async api : | |
260 | * store A reads in object foo, searchs for it, and finds nothing. | |
261 | * store B reads in object foo, searchs for it, finds nothing. | |
262 | * store A gets called back with nothing, so registers the object | |
263 | * store B gets called back with nothing, so registers the object, | |
264 | * which will conflict when the in core index gets around to scanning | |
265 | * store B. | |
266 | * | |
267 | * this suggests that rather than searching for duplicates, the | |
268 | * index rebuild should just assume its the most recent accurate | |
269 | * store entry and whoever indexes the stores handles duplicates. | |
270 | */ | |
271 | e = Store::Root().get(key); | |
62e76326 | 272 | |
273 | if (e && e->lastref >= tmpe.lastref) { | |
274 | /* key already exists, current entry is newer */ | |
275 | /* keep old, ignore new */ | |
276 | counts.dupcount++; | |
277 | continue; | |
278 | } else if (NULL != e) { | |
279 | /* URL already exists, this swapfile not being used */ | |
280 | /* junk old, load new */ | |
5f33b71d | 281 | e->release(); /* release old entry */ |
62e76326 | 282 | counts.dupcount++; |
283 | } | |
284 | ||
285 | counts.objcount++; | |
3900307b | 286 | tmpe.dump(5); |
c8f4eac4 | 287 | currentEntry(sd->addDiskRestore(key, |
288 | filn, | |
289 | tmpe.swap_file_sz, | |
290 | tmpe.expires, | |
291 | tmpe.timestamp, | |
292 | tmpe.lastref, | |
293 | tmpe.lastmod, | |
294 | tmpe.refcount, /* refcount */ | |
295 | tmpe.flags, /* flags */ | |
296 | (int) flags.clean)); | |
297 | storeDirSwapLog(currentEntry(), SWAP_LOG_ADD); | |
4d6d905e | 298 | } |
62e76326 | 299 | |
d3b3ab85 | 300 | } |
301 | ||
822b78b5 | 302 | StoreEntry * |
303 | RebuildState::currentEntry() const | |
304 | { | |
305 | return e; | |
306 | } | |
307 | ||
308 | void | |
309 | RebuildState::currentEntry(StoreEntry *newValue) | |
310 | { | |
311 | e = newValue; | |
312 | } | |
313 | ||
d3b3ab85 | 314 | void |
315 | RebuildState::rebuildFromSwapLog() | |
316 | { | |
822b78b5 | 317 | currentEntry (NULL); |
4d6d905e | 318 | double x; |
4d6d905e | 319 | /* load a number of objects per invocation */ |
62e76326 | 320 | |
d3b3ab85 | 321 | for (int count = 0; count < speed; count++) { |
c8f4eac4 | 322 | StoreSwapLogData swapData; |
51ee7c82 | 323 | size_t ss = sizeof(StoreSwapLogData); |
62e76326 | 324 | |
c8f4eac4 | 325 | if (fread(&swapData, ss, 1, log) != 1) { |
bf8fe701 | 326 | debugs(47, 1, "Done reading " << sd->path << " swaplog (" << n_read << " entries)"); |
62e76326 | 327 | fclose(log); |
328 | log = NULL; | |
c8f4eac4 | 329 | _done = true; |
62e76326 | 330 | return; |
331 | } | |
332 | ||
333 | n_read++; | |
334 | ||
c8f4eac4 | 335 | if (swapData.op <= SWAP_LOG_NOP) |
62e76326 | 336 | continue; |
337 | ||
c8f4eac4 | 338 | if (swapData.op >= SWAP_LOG_MAX) |
62e76326 | 339 | continue; |
340 | ||
341 | /* | |
342 | * BC: during 2.4 development, we changed the way swap file | |
343 | * numbers are assigned and stored. The high 16 bits used | |
344 | * to encode the SD index number. There used to be a call | |
345 | * to storeDirProperFileno here that re-assigned the index | |
346 | * bits. Now, for backwards compatibility, we just need | |
347 | * to mask it off. | |
348 | */ | |
c8f4eac4 | 349 | swapData.swap_filen &= 0x00FFFFFF; |
62e76326 | 350 | |
bf8fe701 | 351 | debugs(47, 3, "commonUfsDirRebuildFromSwapLog: " << |
352 | swap_log_op_str[(int) swapData.op] << " " << | |
353 | storeKeyText(swapData.key) << " "<< std::setfill('0') << | |
354 | std::hex << std::uppercase << std::setw(8) << | |
355 | swapData.swap_filen); | |
62e76326 | 356 | |
c8f4eac4 | 357 | if (swapData.op == SWAP_LOG_ADD) { |
62e76326 | 358 | (void) 0; |
c8f4eac4 | 359 | } else if (swapData.op == SWAP_LOG_DEL) { |
360 | /* Delete unless we already have a newer copy anywhere in any store */ | |
361 | /* this needs to become | |
362 | * 1) unpack url | |
363 | * 2) make synthetic request with headers ?? or otherwise search | |
364 | * for a matching object in the store | |
365 | * TODO FIXME change to new async api | |
366 | */ | |
367 | currentEntry (Store::Root().get(swapData.key)); | |
368 | ||
77fde53f | 369 | if (currentEntry() != NULL && swapData.lastref >= e->lastref) { |
62e76326 | 370 | /* |
371 | * Make sure we don't unlink the file, it might be | |
372 | * in use by a subsequent entry. Also note that | |
373 | * we don't have to subtract from store_swap_size | |
374 | * because adding to store_swap_size happens in | |
375 | * the cleanup procedure. | |
376 | */ | |
d88e3c49 | 377 | currentEntry()->expireNow(); |
378 | currentEntry()->releaseRequest(); | |
62e76326 | 379 | |
380 | if (currentEntry()->swap_filen > -1) { | |
381 | UFSSwapDir *sdForThisEntry = dynamic_cast<UFSSwapDir *>(INDEXSD(currentEntry()->swap_dirn)); | |
382 | assert (sdForThisEntry); | |
383 | sdForThisEntry->replacementRemove(currentEntry()); | |
384 | sdForThisEntry->mapBitReset(currentEntry()->swap_filen); | |
385 | currentEntry()->swap_filen = -1; | |
386 | currentEntry()->swap_dirn = -1; | |
387 | } | |
388 | ||
5f33b71d | 389 | currentEntry()->release(); |
62e76326 | 390 | counts.objcount--; |
391 | counts.cancelcount++; | |
392 | } | |
393 | ||
394 | continue; | |
395 | } else { | |
411c6ea3 | 396 | x = ::log(static_cast<double>(++counts.bad_log_op)) / ::log(10.0); |
62e76326 | 397 | |
398 | if (0.0 == x - (double) (int) x) | |
bf8fe701 | 399 | debugs(47, 1, "WARNING: " << counts.bad_log_op << " invalid swap log entries found"); |
62e76326 | 400 | |
401 | counts.invalid++; | |
402 | ||
403 | continue; | |
404 | } | |
405 | ||
406 | if ((++counts.scancount & 0xFFF) == 0) { | |
407 | ||
408 | struct stat sb; | |
409 | ||
410 | if (0 == fstat(fileno(log), &sb)) | |
411 | storeRebuildProgress(sd->index, | |
412 | (int) sb.st_size / ss, n_read); | |
413 | } | |
414 | ||
c8f4eac4 | 415 | if (!sd->validFileno(swapData.swap_filen, 0)) { |
62e76326 | 416 | counts.invalid++; |
417 | continue; | |
418 | } | |
419 | ||
c8f4eac4 | 420 | if (EBIT_TEST(swapData.flags, KEY_PRIVATE)) { |
62e76326 | 421 | counts.badflags++; |
422 | continue; | |
423 | } | |
424 | ||
c8f4eac4 | 425 | /* this needs to become |
426 | * 1) unpack url | |
427 | * 2) make synthetic request with headers ?? or otherwise search | |
428 | * for a matching object in the store | |
429 | * TODO FIXME change to new async api | |
430 | */ | |
431 | currentEntry (Store::Root().get(swapData.key)); | |
432 | ||
d3b3ab85 | 433 | int used; /* is swapfile already in use? */ |
c8f4eac4 | 434 | |
435 | used = sd->mapBitTest(swapData.swap_filen); | |
436 | ||
62e76326 | 437 | /* If this URL already exists in the cache, does the swap log |
438 | * appear to have a newer entry? Compare 'lastref' from the | |
439 | * swap log to e->lastref. */ | |
440 | /* is the log entry newer than current entry? */ | |
c8f4eac4 | 441 | int disk_entry_newer = currentEntry() ? (swapData.lastref > currentEntry()->lastref ? 1 : 0) : 0; |
62e76326 | 442 | |
443 | if (used && !disk_entry_newer) { | |
444 | /* log entry is old, ignore it */ | |
445 | counts.clashcount++; | |
446 | continue; | |
c8f4eac4 | 447 | } else if (used && currentEntry() && currentEntry()->swap_filen == swapData.swap_filen && currentEntry()->swap_dirn == sd->index) { |
62e76326 | 448 | /* swapfile taken, same URL, newer, update meta */ |
449 | ||
450 | if (currentEntry()->store_status == STORE_OK) { | |
c8f4eac4 | 451 | currentEntry()->lastref = swapData.timestamp; |
452 | currentEntry()->timestamp = swapData.timestamp; | |
453 | currentEntry()->expires = swapData.expires; | |
454 | currentEntry()->lastmod = swapData.lastmod; | |
455 | currentEntry()->flags = swapData.flags; | |
456 | currentEntry()->refcount += swapData.refcount; | |
62e76326 | 457 | sd->dereference(*currentEntry()); |
458 | } else { | |
459 | debug_trap("commonUfsDirRebuildFromSwapLog: bad condition"); | |
bf8fe701 | 460 | debugs(47, 1, "\tSee " << __FILE__ << ":" << __LINE__); |
62e76326 | 461 | } |
462 | ||
463 | continue; | |
464 | } else if (used) { | |
465 | /* swapfile in use, not by this URL, log entry is newer */ | |
466 | /* This is sorta bad: the log entry should NOT be newer at this | |
467 | * point. If the log is dirty, the filesize check should have | |
468 | * caught this. If the log is clean, there should never be a | |
469 | * newer entry. */ | |
bf8fe701 | 470 | debugs(47, 1, "WARNING: newer swaplog entry for dirno " << |
471 | sd->index << ", fileno "<< std::setfill('0') << std::hex << | |
472 | std::uppercase << std::setw(8) << swapData.swap_filen); | |
473 | ||
62e76326 | 474 | /* I'm tempted to remove the swapfile here just to be safe, |
475 | * but there is a bad race condition in the NOVM version if | |
476 | * the swapfile has recently been opened for writing, but | |
477 | * not yet opened for reading. Because we can't map | |
478 | * swapfiles back to StoreEntrys, we don't know the state | |
479 | * of the entry using that file. */ | |
480 | /* We'll assume the existing entry is valid, probably because | |
481 | * were in a slow rebuild and the the swap file number got taken | |
482 | * and the validation procedure hasn't run. */ | |
483 | assert(flags.need_to_validate); | |
484 | counts.clashcount++; | |
485 | continue; | |
486 | } else if (currentEntry() && !disk_entry_newer) { | |
487 | /* key already exists, current entry is newer */ | |
488 | /* keep old, ignore new */ | |
489 | counts.dupcount++; | |
490 | continue; | |
491 | } else if (currentEntry()) { | |
492 | /* key already exists, this swapfile not being used */ | |
493 | /* junk old, load new */ | |
d88e3c49 | 494 | currentEntry()->expireNow(); |
495 | currentEntry()->releaseRequest(); | |
62e76326 | 496 | |
497 | if (currentEntry()->swap_filen > -1) { | |
498 | UFSSwapDir *sdForThisEntry = dynamic_cast<UFSSwapDir *>(INDEXSD(currentEntry()->swap_dirn)); | |
499 | sdForThisEntry->replacementRemove(currentEntry()); | |
500 | /* Make sure we don't actually unlink the file */ | |
501 | sdForThisEntry->mapBitReset(currentEntry()->swap_filen); | |
502 | currentEntry()->swap_filen = -1; | |
503 | currentEntry()->swap_dirn = -1; | |
504 | } | |
505 | ||
5f33b71d | 506 | currentEntry()->release(); |
62e76326 | 507 | counts.dupcount++; |
508 | } else { | |
509 | /* URL doesnt exist, swapfile not in use */ | |
510 | /* load new */ | |
511 | (void) 0; | |
512 | } | |
513 | ||
514 | /* update store_swap_size */ | |
515 | counts.objcount++; | |
516 | ||
c8f4eac4 | 517 | currentEntry(sd->addDiskRestore(swapData.key, |
518 | swapData.swap_filen, | |
519 | swapData.swap_file_sz, | |
520 | swapData.expires, | |
521 | swapData.timestamp, | |
522 | swapData.lastref, | |
523 | swapData.lastmod, | |
524 | swapData.refcount, | |
525 | swapData.flags, | |
62e76326 | 526 | (int) flags.clean)); |
527 | ||
528 | storeDirSwapLog(currentEntry(), SWAP_LOG_ADD); | |
4d6d905e | 529 | } |
62e76326 | 530 | |
4d6d905e | 531 | } |
532 | ||
533 | int | |
d3b3ab85 | 534 | RebuildState::getNextFile(sfileno * filn_p, int *size) |
4d6d905e | 535 | { |
4d6d905e | 536 | int fd = -1; |
4d6d905e | 537 | int dirs_opened = 0; |
bf8fe701 | 538 | debugs(47, 3, "commonUfsDirGetNextFile: flag=" << flags.init << ", " << |
539 | sd->index << ": /"<< std::setfill('0') << std::hex << | |
540 | std::uppercase << std::setw(2) << curlvl1 << "/" << std::setw(2) << | |
541 | curlvl2); | |
62e76326 | 542 | |
d3b3ab85 | 543 | if (done) |
62e76326 | 544 | return -2; |
545 | ||
d3b3ab85 | 546 | while (fd < 0 && done == 0) { |
62e76326 | 547 | fd = -1; |
548 | ||
549 | if (0 == flags.init) { /* initialize, open first file */ | |
550 | done = 0; | |
551 | curlvl1 = 0; | |
552 | curlvl2 = 0; | |
553 | in_dir = 0; | |
554 | flags.init = 1; | |
555 | assert(Config.cacheSwap.n_configured > 0); | |
556 | } | |
557 | ||
558 | if (0 == in_dir) { /* we need to read in a new directory */ | |
559 | snprintf(fullpath, SQUID_MAXPATHLEN, "%s/%02X/%02X", | |
560 | sd->path, | |
561 | curlvl1, curlvl2); | |
562 | ||
563 | if (dirs_opened) | |
564 | return -1; | |
565 | ||
566 | td = opendir(fullpath); | |
567 | ||
568 | dirs_opened++; | |
569 | ||
570 | if (td == NULL) { | |
bf8fe701 | 571 | debugs(47, 1, "commonUfsDirGetNextFile: opendir: " << fullpath << ": " << xstrerror()); |
62e76326 | 572 | } else { |
573 | entry = readdir(td); /* skip . and .. */ | |
574 | entry = readdir(td); | |
575 | ||
576 | if (entry == NULL && errno == ENOENT) | |
bf8fe701 | 577 | debugs(47, 1, "commonUfsDirGetNextFile: directory does not exist!."); |
578 | debugs(47, 3, "commonUfsDirGetNextFile: Directory " << fullpath); | |
62e76326 | 579 | } |
580 | } | |
581 | ||
582 | if (td != NULL && (entry = readdir(td)) != NULL) { | |
583 | in_dir++; | |
584 | ||
585 | if (sscanf(entry->d_name, "%x", &fn) != 1) { | |
bf8fe701 | 586 | debugs(47, 3, "commonUfsDirGetNextFile: invalid " << entry->d_name); |
62e76326 | 587 | continue; |
588 | } | |
589 | ||
590 | if (!UFSSwapDir::FilenoBelongsHere(fn, sd->index, curlvl1, curlvl2)) { | |
bf8fe701 | 591 | debugs(47, 3, "commonUfsDirGetNextFile: "<< std::setfill('0') << |
592 | std::hex << std::uppercase << std::setw(8) << fn << | |
593 | " does not belong in " << std::dec << sd->index << "/" << | |
594 | curlvl1 << "/" << curlvl2); | |
595 | ||
62e76326 | 596 | continue; |
597 | } | |
598 | ||
599 | if (sd->mapBitTest(fn)) { | |
bf8fe701 | 600 | debugs(47, 3, "commonUfsDirGetNextFile: Locked, continuing with next."); |
62e76326 | 601 | continue; |
602 | } | |
603 | ||
604 | snprintf(fullfilename, SQUID_MAXPATHLEN, "%s/%s", | |
605 | fullpath, entry->d_name); | |
bf8fe701 | 606 | debugs(47, 3, "commonUfsDirGetNextFile: Opening " << fullfilename); |
62e76326 | 607 | fd = file_open(fullfilename, O_RDONLY | O_BINARY); |
608 | ||
609 | if (fd < 0) | |
bf8fe701 | 610 | debugs(47, 1, "commonUfsDirGetNextFile: " << fullfilename << ": " << xstrerror()); |
62e76326 | 611 | else |
612 | store_open_disk_fd++; | |
613 | ||
614 | continue; | |
615 | } | |
616 | ||
617 | if (td != NULL) | |
618 | closedir(td); | |
619 | ||
620 | td = NULL; | |
621 | ||
622 | in_dir = 0; | |
623 | ||
624 | if (sd->validL2(++curlvl2)) | |
625 | continue; | |
626 | ||
627 | curlvl2 = 0; | |
628 | ||
629 | if (sd->validL1(++curlvl1)) | |
630 | continue; | |
631 | ||
632 | curlvl1 = 0; | |
633 | ||
634 | done = 1; | |
4d6d905e | 635 | } |
62e76326 | 636 | |
d3b3ab85 | 637 | *filn_p = fn; |
4d6d905e | 638 | return fd; |
639 | } | |
528b2c61 | 640 | |
c8f4eac4 | 641 | void |
642 | RebuildState::next(void (callback)(void *cbdata), void *cbdata) | |
643 | { | |
644 | /* for now, we don't cache at all */ | |
645 | speed = 1; | |
646 | currentEntry(NULL); | |
647 | ||
648 | while (!isDone() && currentEntry() == NULL) | |
649 | rebuildStep(); | |
650 | ||
651 | callback(cbdata); | |
652 | } | |
653 | ||
654 | bool | |
655 | RebuildState::next() | |
656 | { | |
657 | return false; | |
658 | } | |
659 | ||
660 | bool | |
661 | RebuildState::error() const | |
662 | { | |
663 | return false; | |
664 | } | |
665 | ||
666 | bool | |
667 | RebuildState::isDone() const | |
668 | { | |
669 | return _done; | |
670 | } | |
671 | ||
672 | StoreEntry * | |
673 | RebuildState::currentItem() | |
674 | { | |
675 | return currentEntry(); | |
676 | } | |
677 | ||
528b2c61 | 678 | #ifndef _USE_INLINE_ |
679 | #include "ufscommon.cci" | |
680 | #endif |