]>
Commit | Line | Data |
---|---|---|
4d6d905e | 1 | /* |
ef57eb7b | 2 | * Copyright (C) 1996-2016 The Squid Software Foundation and contributors |
4d6d905e | 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. | |
4d6d905e | 7 | */ |
8 | ||
bbc27441 AJ |
9 | /* DEBUG: section 47 Store Directory Routines */ |
10 | ||
f7f3304a | 11 | #include "squid.h" |
2745fea5 | 12 | #include "fs_io.h" |
67679543 | 13 | #include "globals.h" |
58373ff8 | 14 | #include "RebuildState.h" |
4d5904f7 | 15 | #include "SquidConfig.h" |
cbc676b9 | 16 | #include "SquidTime.h" |
2745fea5 | 17 | #include "store/Disks.h" |
fb548aaf | 18 | #include "store_key_md5.h" |
687f5275 | 19 | #include "store_rebuild.h" |
67679543 | 20 | #include "StoreSwapLogData.h" |
5bed43d6 | 21 | #include "tools.h" |
58373ff8 | 22 | #include "UFSSwapLogParser.h" |
4b981814 | 23 | |
074d6a40 AJ |
24 | #include <cerrno> |
25 | #include <cmath> | |
582c2af2 FC |
26 | #if HAVE_SYS_STAT_H |
27 | #include <sys/stat.h> | |
28 | #endif | |
29 | ||
58373ff8 | 30 | CBDATA_NAMESPACED_CLASS_INIT(Fs::Ufs,RebuildState); |
4d6d905e | 31 | |
58373ff8 | 32 | Fs::Ufs::RebuildState::RebuildState(RefCount<UFSSwapDir> aSwapDir) : |
cc8c4af2 AJ |
33 | sd(aSwapDir), |
34 | n_read(0), | |
35 | LogParser(NULL), | |
36 | curlvl1(0), | |
37 | curlvl2(0), | |
38 | in_dir(0), | |
39 | done(0), | |
40 | fn(0), | |
41 | entry(NULL), | |
42 | td(NULL), | |
43 | e(NULL), | |
44 | fromLog(true), | |
45 | _done(false), | |
46 | cbdata(NULL) | |
4d6d905e | 47 | { |
cc8c4af2 AJ |
48 | *fullpath = 0; |
49 | *fullfilename = 0; | |
50 | ||
c8f4eac4 | 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 | */ | |
1a6347cd | 57 | int clean = 0; //TODO: change to bool |
c8f4eac4 | 58 | int zeroLengthLog = 0; |
59 | FILE *fp = sd->openTmpSwapLog(&clean, &zeroLengthLog); | |
60 | ||
47f6e231 | 61 | if (fp && !zeroLengthLog) |
58373ff8 | 62 | LogParser = Fs::Ufs::UFSSwapLogParser::GetUFSSwapLogParser(fp); |
47f6e231 | 63 | |
64 | if (LogParser == NULL ) { | |
c8f4eac4 | 65 | fromLog = false; |
66 | ||
67 | if (fp != NULL) | |
68 | fclose(fp); | |
69 | ||
70 | } else { | |
26ac0430 | 71 | fromLog = true; |
1a6347cd | 72 | flags.clean = (clean != 0); |
c8f4eac4 | 73 | } |
62e76326 | 74 | |
c8f4eac4 | 75 | if (!clean) |
1a6347cd | 76 | flags.need_to_validate = true; |
c8f4eac4 | 77 | |
786f6516 | 78 | debugs(47, DBG_IMPORTANT, "Rebuilding storage in " << sd->path << " (" << |
d178daf7 | 79 | (clean ? "clean log" : (LogParser ? "dirty log" : "no log")) << ")"); |
4d6d905e | 80 | } |
81 | ||
58373ff8 | 82 | Fs::Ufs::RebuildState::~RebuildState() |
4d6d905e | 83 | { |
d3b3ab85 | 84 | sd->closeTmpSwapLog(); |
47f6e231 | 85 | |
86 | if (LogParser) | |
26ac0430 | 87 | delete LogParser; |
4d6d905e | 88 | } |
89 | ||
90 | void | |
58373ff8 | 91 | Fs::Ufs::RebuildState::RebuildStep(void *data) |
4d6d905e | 92 | { |
d3b3ab85 | 93 | RebuildState *rb = (RebuildState *)data; |
c8f4eac4 | 94 | rb->rebuildStep(); |
95 | ||
96 | if (!rb->isDone()) | |
cbc676b9 | 97 | eventAdd("storeRebuild", RebuildStep, rb, 0.01, 1); |
c8f4eac4 | 98 | else { |
cb4185f1 | 99 | -- StoreController::store_dirs_rebuilding; |
c8f4eac4 | 100 | storeRebuildComplete(&rb->counts); |
101 | delete rb; | |
102 | } | |
103 | } | |
104 | ||
cbc676b9 | 105 | /// load entries from swap.state or files until we run out of entries or time |
c8f4eac4 | 106 | void |
58373ff8 | 107 | Fs::Ufs::RebuildState::rebuildStep() |
c8f4eac4 | 108 | { |
cbc676b9 AR |
109 | currentEntry(NULL); |
110 | ||
111 | // Balance our desire to maximize the number of entries processed at once | |
112 | // (and, hence, minimize overheads and total rebuild time) with a | |
113 | // requirement to also process Coordinator events, disk I/Os, etc. | |
114 | const int maxSpentMsec = 50; // keep small: most RAM I/Os are under 1ms | |
115 | const timeval loopStart = current_time; | |
116 | ||
117 | const int totalEntries = LogParser ? LogParser->SwapLogEntries() : -1; | |
118 | ||
119 | while (!isDone()) { | |
120 | if (fromLog) | |
121 | rebuildFromSwapLog(); | |
122 | else | |
123 | rebuildFromDirectory(); | |
124 | ||
125 | // TODO: teach storeRebuildProgress to handle totalEntries <= 0 | |
126 | if (totalEntries > 0 && (n_read % 4000 == 0)) | |
127 | storeRebuildProgress(sd->index, totalEntries, n_read); | |
128 | ||
129 | if (opt_foreground_rebuild) | |
130 | continue; // skip "few entries at a time" check below | |
131 | ||
132 | getCurrentTime(); | |
133 | const double elapsedMsec = tvSubMsec(loopStart, current_time); | |
134 | if (elapsedMsec > maxSpentMsec || elapsedMsec < 0) { | |
135 | debugs(47, 5, HERE << "pausing after " << n_read << " entries in " << | |
136 | elapsedMsec << "ms; " << (elapsedMsec/n_read) << "ms per entry"); | |
137 | break; | |
138 | } | |
139 | } | |
4d6d905e | 140 | } |
141 | ||
cbc676b9 | 142 | /// process one cache file |
4d6d905e | 143 | void |
58373ff8 | 144 | Fs::Ufs::RebuildState::rebuildFromDirectory() |
4d6d905e | 145 | { |
c3031d67 | 146 | cache_key key[SQUID_MD5_DIGEST_LENGTH]; |
62e76326 | 147 | |
4d6d905e | 148 | struct stat sb; |
4d6d905e | 149 | int fd = -1; |
58373ff8 | 150 | debugs(47, 3, HERE << "DIR #" << sd->index); |
62e76326 | 151 | |
e901206a A |
152 | assert(fd == -1); |
153 | sfileno filn = 0; | |
154 | int size; | |
155 | fd = getNextFile(&filn, &size); | |
156 | ||
157 | if (fd == -2) { | |
786f6516 AR |
158 | debugs(47, DBG_IMPORTANT, "Done scanning " << sd->path << " dir (" << |
159 | n_read << " entries)"); | |
e901206a A |
160 | _done = true; |
161 | return; | |
162 | } else if (fd < 0) { | |
163 | return; | |
164 | } | |
aa1a691e | 165 | |
e901206a A |
166 | assert(fd > -1); |
167 | /* lets get file stats here */ | |
62e76326 | 168 | |
cb4185f1 | 169 | ++n_read; |
786f6516 | 170 | |
e901206a | 171 | if (fstat(fd, &sb) < 0) { |
58373ff8 | 172 | debugs(47, DBG_IMPORTANT, HERE << "fstat(FD " << fd << "): " << xstrerror()); |
62e76326 | 173 | file_close(fd); |
cb4185f1 | 174 | --store_open_disk_fd; |
62e76326 | 175 | fd = -1; |
e901206a A |
176 | return; |
177 | } | |
62e76326 | 178 | |
e901206a A |
179 | MemBuf buf; |
180 | buf.init(SM_PAGE_SIZE, SM_PAGE_SIZE); | |
181 | if (!storeRebuildLoadEntry(fd, sd->index, buf, counts)) | |
182 | return; | |
183 | ||
52dce2fe | 184 | const uint64_t expectedSize = sb.st_size > 0 ? |
9d4e9cfb | 185 | static_cast<uint64_t>(sb.st_size) : 0; |
52dce2fe | 186 | |
e901206a | 187 | StoreEntry tmpe; |
52dce2fe AR |
188 | const bool parsed = storeRebuildParseEntry(buf, tmpe, key, counts, |
189 | expectedSize); | |
e901206a A |
190 | |
191 | file_close(fd); | |
cb4185f1 | 192 | --store_open_disk_fd; |
e901206a | 193 | fd = -1; |
62e76326 | 194 | |
52dce2fe AR |
195 | bool accepted = parsed && tmpe.swap_file_sz > 0; |
196 | if (parsed && !accepted) { | |
197 | debugs(47, DBG_IMPORTANT, "WARNING: Ignoring ufs cache entry with " << | |
198 | "unknown size: " << tmpe); | |
199 | accepted = false; | |
200 | } | |
201 | ||
202 | if (!accepted) { | |
e901206a A |
203 | // XXX: shouldn't this be a call to commonUfsUnlink? |
204 | sd->unlinkFile(filn); // should we unlink in all failure cases? | |
205 | return; | |
206 | } | |
207 | ||
208 | if (!storeRebuildKeepEntry(tmpe, key, counts)) | |
209 | return; | |
210 | ||
cb4185f1 | 211 | ++counts.objcount; |
e901206a A |
212 | // tmpe.dump(5); |
213 | currentEntry(sd->addDiskRestore(key, | |
214 | filn, | |
215 | tmpe.swap_file_sz, | |
216 | tmpe.expires, | |
217 | tmpe.timestamp, | |
218 | tmpe.lastref, | |
219 | tmpe.lastmod, | |
58373ff8 FC |
220 | tmpe.refcount, /* refcount */ |
221 | tmpe.flags, /* flags */ | |
e901206a A |
222 | (int) flags.clean)); |
223 | storeDirSwapLog(currentEntry(), SWAP_LOG_ADD); | |
d3b3ab85 | 224 | } |
225 | ||
822b78b5 | 226 | StoreEntry * |
58373ff8 | 227 | Fs::Ufs::RebuildState::currentEntry() const |
822b78b5 | 228 | { |
229 | return e; | |
230 | } | |
231 | ||
232 | void | |
58373ff8 | 233 | Fs::Ufs::RebuildState::currentEntry(StoreEntry *newValue) |
822b78b5 | 234 | { |
235 | e = newValue; | |
236 | } | |
237 | ||
cbc676b9 | 238 | /// process one swap log entry |
d3b3ab85 | 239 | void |
58373ff8 | 240 | Fs::Ufs::RebuildState::rebuildFromSwapLog() |
d3b3ab85 | 241 | { |
e901206a | 242 | StoreSwapLogData swapData; |
62e76326 | 243 | |
e901206a | 244 | if (LogParser->ReadRecord(swapData) != 1) { |
58373ff8 | 245 | debugs(47, DBG_IMPORTANT, "Done reading " << sd->path << " swaplog (" << n_read << " entries)"); |
e901206a A |
246 | LogParser->Close(); |
247 | delete LogParser; | |
248 | LogParser = NULL; | |
249 | _done = true; | |
250 | return; | |
251 | } | |
62e76326 | 252 | |
cb4185f1 | 253 | ++n_read; |
62e76326 | 254 | |
3f9d4dc2 | 255 | if (!swapData.sane()) { |
cb4185f1 | 256 | ++counts.invalid; |
e901206a | 257 | return; |
3f9d4dc2 | 258 | } |
62e76326 | 259 | |
e901206a A |
260 | /* |
261 | * BC: during 2.4 development, we changed the way swap file | |
262 | * numbers are assigned and stored. The high 16 bits used | |
263 | * to encode the SD index number. There used to be a call | |
264 | * to storeDirProperFileno here that re-assigned the index | |
265 | * bits. Now, for backwards compatibility, we just need | |
266 | * to mask it off. | |
267 | */ | |
268 | swapData.swap_filen &= 0x00FFFFFF; | |
269 | ||
58373ff8 | 270 | debugs(47, 3, HERE << swap_log_op_str[(int) swapData.op] << " " << |
e901206a A |
271 | storeKeyText(swapData.key) << " "<< std::setfill('0') << |
272 | std::hex << std::uppercase << std::setw(8) << | |
273 | swapData.swap_filen); | |
274 | ||
275 | if (swapData.op == SWAP_LOG_ADD) { | |
276 | (void) 0; | |
277 | } else if (swapData.op == SWAP_LOG_DEL) { | |
278 | /* Delete unless we already have a newer copy anywhere in any store */ | |
c8f4eac4 | 279 | /* this needs to become |
280 | * 1) unpack url | |
281 | * 2) make synthetic request with headers ?? or otherwise search | |
282 | * for a matching object in the store | |
283 | * TODO FIXME change to new async api | |
284 | */ | |
285 | currentEntry (Store::Root().get(swapData.key)); | |
286 | ||
e901206a | 287 | if (currentEntry() != NULL && swapData.lastref >= e->lastref) { |
c6e51aff | 288 | undoAdd(); |
cb4185f1 FC |
289 | --counts.objcount; |
290 | ++counts.cancelcount; | |
e901206a A |
291 | } |
292 | return; | |
293 | } else { | |
294 | const double | |
295 | x = ::log(static_cast<double>(++counts.bad_log_op)) / ::log(10.0); | |
296 | ||
297 | if (0.0 == x - (double) (int) x) | |
58373ff8 | 298 | debugs(47, DBG_IMPORTANT, "WARNING: " << counts.bad_log_op << " invalid swap log entries found"); |
e901206a | 299 | |
cb4185f1 | 300 | ++counts.invalid; |
e901206a A |
301 | |
302 | return; | |
303 | } | |
304 | ||
305 | ++counts.scancount; // XXX: should not this be incremented earlier? | |
306 | ||
307 | if (!sd->validFileno(swapData.swap_filen, 0)) { | |
cb4185f1 | 308 | ++counts.invalid; |
e901206a A |
309 | return; |
310 | } | |
311 | ||
312 | if (EBIT_TEST(swapData.flags, KEY_PRIVATE)) { | |
cb4185f1 | 313 | ++counts.badflags; |
e901206a A |
314 | return; |
315 | } | |
316 | ||
317 | /* this needs to become | |
318 | * 1) unpack url | |
319 | * 2) make synthetic request with headers ?? or otherwise search | |
320 | * for a matching object in the store | |
321 | * TODO FIXME change to new async api | |
322 | */ | |
323 | currentEntry (Store::Root().get(swapData.key)); | |
324 | ||
58373ff8 | 325 | int used; /* is swapfile already in use? */ |
e901206a A |
326 | |
327 | used = sd->mapBitTest(swapData.swap_filen); | |
328 | ||
329 | /* If this URL already exists in the cache, does the swap log | |
330 | * appear to have a newer entry? Compare 'lastref' from the | |
331 | * swap log to e->lastref. */ | |
332 | /* is the log entry newer than current entry? */ | |
333 | int disk_entry_newer = currentEntry() ? (swapData.lastref > currentEntry()->lastref ? 1 : 0) : 0; | |
334 | ||
335 | if (used && !disk_entry_newer) { | |
336 | /* log entry is old, ignore it */ | |
cb4185f1 | 337 | ++counts.clashcount; |
e901206a A |
338 | return; |
339 | } else if (used && currentEntry() && currentEntry()->swap_filen == swapData.swap_filen && currentEntry()->swap_dirn == sd->index) { | |
340 | /* swapfile taken, same URL, newer, update meta */ | |
341 | ||
342 | if (currentEntry()->store_status == STORE_OK) { | |
343 | currentEntry()->lastref = swapData.timestamp; | |
344 | currentEntry()->timestamp = swapData.timestamp; | |
345 | currentEntry()->expires = swapData.expires; | |
346 | currentEntry()->lastmod = swapData.lastmod; | |
347 | currentEntry()->flags = swapData.flags; | |
348 | currentEntry()->refcount += swapData.refcount; | |
2745fea5 | 349 | sd->dereference(*currentEntry()); |
62e76326 | 350 | } else { |
e901206a | 351 | debug_trap("commonUfsDirRebuildFromSwapLog: bad condition"); |
58373ff8 | 352 | debugs(47, DBG_IMPORTANT, HERE << "bad condition"); |
e901206a A |
353 | } |
354 | return; | |
355 | } else if (used) { | |
356 | /* swapfile in use, not by this URL, log entry is newer */ | |
357 | /* This is sorta bad: the log entry should NOT be newer at this | |
358 | * point. If the log is dirty, the filesize check should have | |
359 | * caught this. If the log is clean, there should never be a | |
360 | * newer entry. */ | |
58373ff8 | 361 | debugs(47, DBG_IMPORTANT, "WARNING: newer swaplog entry for dirno " << |
e901206a A |
362 | sd->index << ", fileno "<< std::setfill('0') << std::hex << |
363 | std::uppercase << std::setw(8) << swapData.swap_filen); | |
364 | ||
365 | /* I'm tempted to remove the swapfile here just to be safe, | |
366 | * but there is a bad race condition in the NOVM version if | |
367 | * the swapfile has recently been opened for writing, but | |
368 | * not yet opened for reading. Because we can't map | |
369 | * swapfiles back to StoreEntrys, we don't know the state | |
370 | * of the entry using that file. */ | |
371 | /* We'll assume the existing entry is valid, probably because | |
372 | * were in a slow rebuild and the the swap file number got taken | |
373 | * and the validation procedure hasn't run. */ | |
374 | assert(flags.need_to_validate); | |
cb4185f1 | 375 | ++counts.clashcount; |
e901206a A |
376 | return; |
377 | } else if (currentEntry() && !disk_entry_newer) { | |
378 | /* key already exists, current entry is newer */ | |
379 | /* keep old, ignore new */ | |
cb4185f1 | 380 | ++counts.dupcount; |
e901206a A |
381 | return; |
382 | } else if (currentEntry()) { | |
383 | /* key already exists, this swapfile not being used */ | |
384 | /* junk old, load new */ | |
c6e51aff | 385 | undoAdd(); |
133c3ad6 | 386 | --counts.objcount; |
cb4185f1 | 387 | ++counts.dupcount; |
e901206a A |
388 | } else { |
389 | /* URL doesnt exist, swapfile not in use */ | |
390 | /* load new */ | |
391 | (void) 0; | |
392 | } | |
393 | ||
cb4185f1 | 394 | ++counts.objcount; |
62e76326 | 395 | |
e901206a A |
396 | currentEntry(sd->addDiskRestore(swapData.key, |
397 | swapData.swap_filen, | |
398 | swapData.swap_file_sz, | |
399 | swapData.expires, | |
400 | swapData.timestamp, | |
401 | swapData.lastref, | |
402 | swapData.lastmod, | |
403 | swapData.refcount, | |
404 | swapData.flags, | |
405 | (int) flags.clean)); | |
62e76326 | 406 | |
e901206a | 407 | storeDirSwapLog(currentEntry(), SWAP_LOG_ADD); |
4d6d905e | 408 | } |
409 | ||
c6e51aff AR |
410 | /// undo the effects of adding an entry in rebuildFromSwapLog() |
411 | void | |
58373ff8 | 412 | Fs::Ufs::RebuildState::undoAdd() |
c6e51aff AR |
413 | { |
414 | StoreEntry *added = currentEntry(); | |
415 | assert(added); | |
416 | currentEntry(NULL); | |
417 | ||
418 | // TODO: Why bother with these two if we are going to release?! | |
419 | added->expireNow(); | |
420 | added->releaseRequest(); | |
421 | ||
422 | if (added->swap_filen > -1) { | |
128122d1 AR |
423 | SwapDir *someDir = INDEXSD(added->swap_dirn); |
424 | assert(someDir); | |
425 | if (UFSSwapDir *ufsDir = dynamic_cast<UFSSwapDir*>(someDir)) | |
426 | ufsDir->undoAddDiskRestore(added); | |
427 | // else the entry was loaded from and/or is currently in a non-UFS dir | |
428 | // Thus, there is no use in preserving its disk file (the only purpose | |
429 | // of undoAddDiskRestore!), even if we could. Instead, we release the | |
430 | // the entry and [eventually] unlink its disk file or free its slot. | |
c6e51aff AR |
431 | } |
432 | ||
433 | added->release(); | |
434 | } | |
435 | ||
4d6d905e | 436 | int |
ced8def3 | 437 | Fs::Ufs::RebuildState::getNextFile(sfileno * filn_p, int *) |
4d6d905e | 438 | { |
4d6d905e | 439 | int fd = -1; |
4d6d905e | 440 | int dirs_opened = 0; |
58373ff8 | 441 | debugs(47, 3, HERE << "flag=" << flags.init << ", " << |
bf8fe701 | 442 | sd->index << ": /"<< std::setfill('0') << std::hex << |
443 | std::uppercase << std::setw(2) << curlvl1 << "/" << std::setw(2) << | |
444 | curlvl2); | |
62e76326 | 445 | |
d3b3ab85 | 446 | if (done) |
62e76326 | 447 | return -2; |
448 | ||
d3b3ab85 | 449 | while (fd < 0 && done == 0) { |
62e76326 | 450 | fd = -1; |
451 | ||
1a6347cd | 452 | if (!flags.init) { /* initialize, open first file */ |
cc8c4af2 | 453 | // XXX: 0's should not be needed, constructor inits now |
62e76326 | 454 | done = 0; |
455 | curlvl1 = 0; | |
456 | curlvl2 = 0; | |
457 | in_dir = 0; | |
1a6347cd | 458 | flags.init = true; |
62e76326 | 459 | assert(Config.cacheSwap.n_configured > 0); |
460 | } | |
461 | ||
58373ff8 | 462 | if (0 == in_dir) { /* we need to read in a new directory */ |
ef364f64 | 463 | snprintf(fullpath, MAXPATHLEN, "%s/%02X/%02X", |
62e76326 | 464 | sd->path, |
465 | curlvl1, curlvl2); | |
466 | ||
467 | if (dirs_opened) | |
468 | return -1; | |
469 | ||
470 | td = opendir(fullpath); | |
471 | ||
cb4185f1 | 472 | ++dirs_opened; |
62e76326 | 473 | |
474 | if (td == NULL) { | |
58373ff8 | 475 | debugs(47, DBG_IMPORTANT, HERE << "error in opendir (" << fullpath << "): " << xstrerror()); |
62e76326 | 476 | } else { |
58373ff8 | 477 | entry = readdir(td); /* skip . and .. */ |
62e76326 | 478 | entry = readdir(td); |
479 | ||
480 | if (entry == NULL && errno == ENOENT) | |
58373ff8 FC |
481 | debugs(47, DBG_IMPORTANT, HERE << "WARNING: directory does not exist!"); |
482 | debugs(47, 3, HERE << "Directory " << fullpath); | |
62e76326 | 483 | } |
484 | } | |
485 | ||
486 | if (td != NULL && (entry = readdir(td)) != NULL) { | |
cb4185f1 | 487 | ++in_dir; |
62e76326 | 488 | |
489 | if (sscanf(entry->d_name, "%x", &fn) != 1) { | |
58373ff8 | 490 | debugs(47, 3, HERE << "invalid entry " << entry->d_name); |
62e76326 | 491 | continue; |
492 | } | |
493 | ||
494 | if (!UFSSwapDir::FilenoBelongsHere(fn, sd->index, curlvl1, curlvl2)) { | |
58373ff8 | 495 | debugs(47, 3, HERE << std::setfill('0') << |
bf8fe701 | 496 | std::hex << std::uppercase << std::setw(8) << fn << |
497 | " does not belong in " << std::dec << sd->index << "/" << | |
498 | curlvl1 << "/" << curlvl2); | |
499 | ||
62e76326 | 500 | continue; |
501 | } | |
502 | ||
503 | if (sd->mapBitTest(fn)) { | |
58373ff8 | 504 | debugs(47, 3, HERE << "Locked, continuing with next."); |
62e76326 | 505 | continue; |
506 | } | |
507 | ||
ef364f64 | 508 | snprintf(fullfilename, MAXPATHLEN, "%s/%s", |
62e76326 | 509 | fullpath, entry->d_name); |
58373ff8 | 510 | debugs(47, 3, HERE << "Opening " << fullfilename); |
62e76326 | 511 | fd = file_open(fullfilename, O_RDONLY | O_BINARY); |
512 | ||
513 | if (fd < 0) | |
58373ff8 | 514 | debugs(47, DBG_IMPORTANT, HERE << "error opening " << fullfilename << ": " << xstrerror()); |
62e76326 | 515 | else |
cb4185f1 | 516 | ++store_open_disk_fd; |
62e76326 | 517 | |
518 | continue; | |
519 | } | |
520 | ||
521 | if (td != NULL) | |
522 | closedir(td); | |
523 | ||
524 | td = NULL; | |
525 | ||
526 | in_dir = 0; | |
527 | ||
528 | if (sd->validL2(++curlvl2)) | |
529 | continue; | |
530 | ||
531 | curlvl2 = 0; | |
532 | ||
533 | if (sd->validL1(++curlvl1)) | |
534 | continue; | |
535 | ||
536 | curlvl1 = 0; | |
537 | ||
538 | done = 1; | |
4d6d905e | 539 | } |
62e76326 | 540 | |
d3b3ab85 | 541 | *filn_p = fn; |
4d6d905e | 542 | return fd; |
543 | } | |
528b2c61 | 544 | |
c8f4eac4 | 545 | bool |
58373ff8 | 546 | Fs::Ufs::RebuildState::error() const |
c8f4eac4 | 547 | { |
548 | return false; | |
549 | } | |
550 | ||
551 | bool | |
58373ff8 | 552 | Fs::Ufs::RebuildState::isDone() const |
c8f4eac4 | 553 | { |
554 | return _done; | |
555 | } | |
556 | ||
557 | StoreEntry * | |
58373ff8 | 558 | Fs::Ufs::RebuildState::currentItem() |
c8f4eac4 | 559 | { |
560 | return currentEntry(); | |
561 | } | |
f53969cc | 562 |