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