store_rebuild.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:23k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: store_rebuild.c,v 1.56 1999/01/24 02:26:25 wessels Exp $
  3.  *
  4.  * DEBUG: section 20    Store Rebuild Routines
  5.  * AUTHOR: Duane Wessels
  6.  *
  7.  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
  8.  * ----------------------------------------------------------
  9.  *
  10.  *  Squid is the result of efforts by numerous individuals from the
  11.  *  Internet community.  Development is led by Duane Wessels of the
  12.  *  National Laboratory for Applied Network Research and funded by the
  13.  *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
  14.  *  Duane Wessels and the University of California San Diego.  Please
  15.  *  see the COPYRIGHT file for full details.  Squid incorporates
  16.  *  software developed and/or copyrighted by other sources.  Please see
  17.  *  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. #include "squid.h"
  35. #define STORE_META_BUFSZ 4096
  36. typedef struct _rebuild_dir rebuild_dir;
  37. typedef int RBHD(rebuild_dir * d);
  38. struct _rebuild_dir {
  39.     int dirn;
  40.     int n_read;
  41.     FILE *log;
  42.     int speed;
  43.     int clean;
  44.     int curlvl1;
  45.     int curlvl2;
  46.     int flag;
  47.     int done;
  48.     int in_dir;
  49.     int fn;
  50.     struct dirent *entry;
  51.     DIR *td;
  52.     RBHD *rebuild_func;
  53.     rebuild_dir *next;
  54.     char fullpath[SQUID_MAXPATHLEN];
  55.     char fullfilename[SQUID_MAXPATHLEN];
  56. };
  57. struct storeRebuildState {
  58.     rebuild_dir *rebuild_dir;
  59.     int objcount; /* # objects successfully reloaded */
  60.     int expcount; /* # objects expired */
  61.     int linecount; /* # lines parsed from cache logfile */
  62.     int statcount; /* # entries from directory walking */
  63.     int clashcount; /* # swapfile clashes avoided */
  64.     int dupcount; /* # duplicates purged */
  65.     int cancelcount; /* # SWAP_LOG_DEL objects purged */
  66.     int invalid; /* # bad lines */
  67.     int badflags; /* # bad e->flags */
  68.     int need_to_validate;
  69.     int bad_log_op;
  70.     int zero_object_sz;
  71.     time_t start;
  72.     time_t stop;
  73. } RebuildState;
  74. typedef struct valid_ctrl_t {
  75.     struct stat *sb;
  76.     StoreEntry *e;
  77.     STVLDCB *callback;
  78.     void *callback_data;
  79. } valid_ctrl_t;
  80. static RBHD storeRebuildFromDirectory;
  81. static RBHD storeRebuildFromSwapLog;
  82. static void storeRebuildComplete(void);
  83. static EVH storeRebuildADirectory;
  84. static int storeGetNextFile(rebuild_dir *, int *sfileno, int *size);
  85. static StoreEntry *storeAddDiskRestore(const cache_key * key,
  86.     int file_number,
  87.     size_t swap_file_sz,
  88.     time_t expires,
  89.     time_t timestamp,
  90.     time_t lastref,
  91.     time_t lastmod,
  92.     u_num32 refcount,
  93.     u_short flags,
  94.     int clean);
  95. static AIOCB storeValidateComplete;
  96. static int
  97. storeRebuildFromDirectory(rebuild_dir * d)
  98. {
  99.     LOCAL_ARRAY(char, hdr_buf, DISK_PAGE_SIZE);
  100.     StoreEntry *e = NULL;
  101.     StoreEntry tmpe;
  102.     cache_key key[MD5_DIGEST_CHARS];
  103.     int sfileno = 0;
  104.     int count;
  105.     int size;
  106.     struct stat sb;
  107.     int swap_hdr_len;
  108.     int fd = -1;
  109.     tlv *tlv_list;
  110.     tlv *t;
  111.     assert(d != NULL);
  112.     debug(20, 3) ("storeRebuildFromDirectory: DIR #%dn", d->dirn);
  113.     for (count = 0; count < d->speed; count++) {
  114. assert(fd == -1);
  115. fd = storeGetNextFile(d, &sfileno, &size);
  116. if (fd == -2) {
  117.     debug(20, 1) ("storeRebuildFromDirectory: DIR #%d done!n", d->dirn);
  118.     storeDirCloseTmpSwapLog(d->dirn);
  119.     store_rebuilding = 0;
  120.     return -1;
  121. } else if (fd < 0) {
  122.     continue;
  123. }
  124. assert(fd > -1);
  125. /* lets get file stats here */
  126. if (fstat(fd, &sb) < 0) {
  127.     debug(20, 1) ("storeRebuildFromDirectory: fstat(FD %d): %sn",
  128. fd, xstrerror());
  129.     file_close(fd);
  130.     store_open_disk_fd--;
  131.     fd = -1;
  132.     continue;
  133. }
  134. if ((++RebuildState.statcount & 0xFFFF) == 0)
  135.     debug(20, 1) ("  %7d files opened so far.n",
  136. RebuildState.statcount);
  137. debug(20, 9) ("file_in: fd=%d %08Xn", fd, sfileno);
  138. Counter.syscalls.disk.reads++;
  139. if (read(fd, hdr_buf, DISK_PAGE_SIZE) < 0) {
  140.     debug(20, 1) ("storeRebuildFromDirectory: read(FD %d): %sn",
  141. fd, xstrerror());
  142.     file_close(fd);
  143.     store_open_disk_fd--;
  144.     fd = -1;
  145.     continue;
  146. }
  147. file_close(fd);
  148. store_open_disk_fd--;
  149. fd = -1;
  150. swap_hdr_len = 0;
  151. #if USE_TRUNCATE_NOT_UNLINK
  152. if (sb.st_size == 0)
  153.     continue;
  154. #endif
  155. tlv_list = storeSwapMetaUnpack(hdr_buf, &swap_hdr_len);
  156. if (tlv_list == NULL) {
  157.     debug(20, 1) ("storeRebuildFromDirectory: failed to get meta datan");
  158.     storeUnlinkFileno(sfileno);
  159.     continue;
  160. }
  161. debug(20, 3) ("storeRebuildFromDirectory: successful swap meta unpackingn");
  162. memset(key, '', MD5_DIGEST_CHARS);
  163. memset(&tmpe, '', sizeof(StoreEntry));
  164. for (t = tlv_list; t; t = t->next) {
  165.     switch (t->type) {
  166.     case STORE_META_KEY:
  167. assert(t->length == MD5_DIGEST_CHARS);
  168. xmemcpy(key, t->value, MD5_DIGEST_CHARS);
  169. break;
  170.     case STORE_META_STD:
  171. assert(t->length == STORE_HDR_METASIZE);
  172. xmemcpy(&tmpe.timestamp, t->value, STORE_HDR_METASIZE);
  173. break;
  174.     default:
  175. break;
  176.     }
  177. }
  178. storeSwapTLVFree(tlv_list);
  179. tlv_list = NULL;
  180. if (storeKeyNull(key)) {
  181.     debug(20, 1) ("storeRebuildFromDirectory: NULL keyn");
  182.     storeUnlinkFileno(sfileno);
  183.     continue;
  184. }
  185. tmpe.key = key;
  186. /* check sizes */
  187. if (tmpe.swap_file_sz == 0) {
  188.     tmpe.swap_file_sz = sb.st_size;
  189. } else if (tmpe.swap_file_sz == sb.st_size - swap_hdr_len) {
  190.     tmpe.swap_file_sz = sb.st_size;
  191. } else if (tmpe.swap_file_sz != sb.st_size) {
  192.     debug(20, 1) ("storeRebuildFromDirectory: SIZE MISMATCH %d!=%dn",
  193. tmpe.swap_file_sz, (int) sb.st_size);
  194.     storeUnlinkFileno(sfileno);
  195.     continue;
  196. }
  197. if (EBIT_TEST(tmpe.flags, KEY_PRIVATE)) {
  198.     storeUnlinkFileno(sfileno);
  199.     RebuildState.badflags++;
  200.     continue;
  201. }
  202. e = storeGet(key);
  203. if (e && e->lastref >= tmpe.lastref) {
  204.     /* key already exists, current entry is newer */
  205.     /* keep old, ignore new */
  206.     RebuildState.dupcount++;
  207.     continue;
  208. } else if (NULL != e) {
  209.     /* URL already exists, this swapfile not being used */
  210.     /* junk old, load new */
  211.     storeRelease(e); /* release old entry */
  212.     RebuildState.dupcount++;
  213. }
  214. RebuildState.objcount++;
  215. storeEntryDump(&tmpe, 5);
  216. e = storeAddDiskRestore(key,
  217.     sfileno,
  218.     tmpe.swap_file_sz,
  219.     tmpe.expires,
  220.     tmpe.timestamp,
  221.     tmpe.lastref,
  222.     tmpe.lastmod,
  223.     tmpe.refcount, /* refcount */
  224.     tmpe.flags, /* flags */
  225.     d->clean);
  226.     }
  227.     return count;
  228. }
  229. static int
  230. storeRebuildFromSwapLog(rebuild_dir * d)
  231. {
  232.     StoreEntry *e = NULL;
  233.     storeSwapLogData s;
  234.     size_t ss = sizeof(storeSwapLogData);
  235.     int count;
  236.     int used; /* is swapfile already in use? */
  237.     int disk_entry_newer; /* is the log entry newer than current entry? */
  238.     double x;
  239.     assert(d != NULL);
  240.     /* load a number of objects per invocation */
  241.     for (count = 0; count < d->speed; count++) {
  242. if (fread(&s, ss, 1, d->log) != 1) {
  243.     debug(20, 1) ("Done reading Cache Dir #%d swaplog (%d entries)n",
  244. d->dirn, d->n_read);
  245.     fclose(d->log);
  246.     d->log = NULL;
  247.     storeDirCloseTmpSwapLog(d->dirn);
  248.     return -1;
  249. }
  250. d->n_read++;
  251. if (s.op <= SWAP_LOG_NOP)
  252.     continue;
  253. if (s.op >= SWAP_LOG_MAX)
  254.     continue;
  255. s.swap_file_number = storeDirProperFileno(d->dirn, s.swap_file_number);
  256. debug(20, 3) ("storeRebuildFromSwapLog: %s %s %08Xn",
  257.     swap_log_op_str[(int) s.op],
  258.     storeKeyText(s.key),
  259.     s.swap_file_number);
  260. if (s.op == SWAP_LOG_ADD) {
  261.     (void) 0;
  262. } else if (s.op == SWAP_LOG_DEL) {
  263.     if ((e = storeGet(s.key)) != NULL) {
  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_file_number > -1) {
  274.     storeDirMapBitReset(e->swap_file_number);
  275.     e->swap_file_number = -1;
  276. }
  277. RebuildState.objcount--;
  278. RebuildState.cancelcount++;
  279.     }
  280.     continue;
  281. } else {
  282.     x = log(++RebuildState.bad_log_op) / log(10.0);
  283.     if (0.0 == x - (double) (int) x)
  284. debug(20, 1) ("WARNING: %d invalid swap log entries foundn",
  285.     RebuildState.bad_log_op);
  286.     RebuildState.invalid++;
  287.     continue;
  288. }
  289. if ((++RebuildState.linecount & 0xFFFF) == 0)
  290.     debug(20, 1) ("  %7d Entries read so far.n",
  291. RebuildState.linecount);
  292. if (!storeDirValidFileno(s.swap_file_number)) {
  293.     RebuildState.invalid++;
  294.     continue;
  295. }
  296. if (EBIT_TEST(s.flags, KEY_PRIVATE)) {
  297.     RebuildState.badflags++;
  298.     continue;
  299. }
  300. e = storeGet(s.key);
  301. used = storeDirMapBitTest(s.swap_file_number);
  302. /* If this URL already exists in the cache, does the swap log
  303.  * appear to have a newer entry?  Compare 'lastref' from the
  304.  * swap log to e->lastref. */
  305. disk_entry_newer = e ? (s.lastref > e->lastref ? 1 : 0) : 0;
  306. if (used && !disk_entry_newer) {
  307.     /* log entry is old, ignore it */
  308.     RebuildState.clashcount++;
  309.     continue;
  310. } else if (used && e && e->swap_file_number == s.swap_file_number) {
  311.     /* swapfile taken, same URL, newer, update meta */
  312.     if (e->store_status == STORE_OK) {
  313. e->lastref = s.timestamp;
  314. e->timestamp = s.timestamp;
  315. e->expires = s.expires;
  316. e->lastmod = s.lastmod;
  317. e->flags = s.flags;
  318. e->refcount += s.refcount;
  319.     } else {
  320. debug_trap("storeRebuildFromSwapLog: bad condition");
  321. debug(20, 1) ("tSee %s:%dn", __FILE__, __LINE__);
  322.     }
  323.     continue;
  324. } else if (used) {
  325.     /* swapfile in use, not by this URL, log entry is newer */
  326.     /* This is sorta bad: the log entry should NOT be newer at this
  327.      * point.  If the log is dirty, the filesize check should have
  328.      * caught this.  If the log is clean, there should never be a
  329.      * newer entry. */
  330.     debug(20, 1) ("WARNING: newer swaplog entry for fileno %08Xn",
  331. s.swap_file_number);
  332.     /* I'm tempted to remove the swapfile here just to be safe,
  333.      * but there is a bad race condition in the NOVM version if
  334.      * the swapfile has recently been opened for writing, but
  335.      * not yet opened for reading.  Because we can't map
  336.      * swapfiles back to StoreEntrys, we don't know the state
  337.      * of the entry using that file.  */
  338.     /* We'll assume the existing entry is valid, probably because
  339.      * were in a slow rebuild and the the swap file number got taken
  340.      * and the validation procedure hasn't run. */
  341.     assert(RebuildState.need_to_validate);
  342.     RebuildState.clashcount++;
  343.     continue;
  344. } else if (e && !disk_entry_newer) {
  345.     /* key already exists, current entry is newer */
  346.     /* keep old, ignore new */
  347.     RebuildState.dupcount++;
  348.     continue;
  349. } else if (e) {
  350.     /* key already exists, this swapfile not being used */
  351.     /* junk old, load new */
  352.     storeExpireNow(e);
  353.     storeReleaseRequest(e);
  354.     if (e->swap_file_number > -1) {
  355. storeDirMapBitReset(e->swap_file_number);
  356. e->swap_file_number = -1;
  357.     }
  358.     RebuildState.dupcount++;
  359. } else {
  360.     /* URL doesnt exist, swapfile not in use */
  361.     /* load new */
  362.     (void) 0;
  363. }
  364. /* update store_swap_size */
  365. RebuildState.objcount++;
  366. e = storeAddDiskRestore(s.key,
  367.     s.swap_file_number,
  368.     s.swap_file_sz,
  369.     s.expires,
  370.     s.timestamp,
  371.     s.lastref,
  372.     s.lastmod,
  373.     s.refcount,
  374.     s.flags,
  375.     d->clean);
  376. storeDirSwapLog(e, SWAP_LOG_ADD);
  377.     }
  378.     return count;
  379. }
  380. static void
  381. storeRebuildADirectory(void *unused)
  382. {
  383.     int count;
  384.     rebuild_dir *d;
  385.     rebuild_dir **D;
  386.     if ((d = RebuildState.rebuild_dir) == NULL) {
  387. storeRebuildComplete();
  388. return;
  389.     }
  390.     count = d->rebuild_func(d);
  391.     RebuildState.rebuild_dir = d->next;
  392.     if (count < 0) {
  393. xfree(d);
  394.     } else {
  395. for (D = &RebuildState.rebuild_dir; *D; D = &(*D)->next);
  396. *D = d;
  397. d->next = NULL;
  398.     }
  399.     if (opt_foreground_rebuild)
  400. storeRebuildADirectory(NULL);
  401.     else
  402. eventAdd("storeRebuild", storeRebuildADirectory, NULL, 0.0, 1);
  403. }
  404. #if TEMP_UNUSED_CODE
  405. static void
  406. storeConvertFile(const cache_key * key,
  407.     int file_number,
  408.     size_t swap_file_sz,
  409.     time_t expires,
  410.     time_t timestamp,
  411.     time_t lastref,
  412.     time_t lastmod,
  413.     u_short refcount,
  414.     u_short flags,
  415.     int clean)
  416. {
  417.     int fd_r, fd_w;
  418.     int hdr_len, x, y;
  419.     LOCAL_ARRAY(char, swapfilename, SQUID_MAXPATHLEN);
  420.     LOCAL_ARRAY(char, copybuf, DISK_PAGE_SIZE);
  421.     char *buf;
  422.     tlv *tlv_list;
  423.     StoreEntry e;
  424.     e.key = key;
  425.     e.swap_file_sz = swap_file_sz;
  426.     e.expires = expires;
  427.     e.lastref = lastref;
  428.     e.refcount = refcount;
  429.     e.flag = flags;
  430.     storeSwapFullPath(file_number, swapfilename);
  431.     fd_r = file_open(swapfilename, O_RDONLY, NULL, NULL, NULL);
  432.     if (fd_r < 0)
  433. return;
  434.     safeunlink(swapfilename, 1);
  435.     fd_w = file_open(swapfilename, O_CREAT | O_WRONLY | O_TRUNC, NULL, NULL, NULL);
  436.     tlv_list = storeSwapMetaBuild(&e);
  437.     buf = storeSwapMetaPack(tlv_list, &hdr_len);
  438.     x = write(fd_w, buf, hdr_len);
  439.     while (x > 0) {
  440. y = read(fd_r, copybuf, DISK_PAGE_SIZE);
  441. x = write(fd_w, copybuf, y);
  442.     }
  443.     file_close(fd_r);
  444.     file_close(fd_w);
  445.     xfree(buf);
  446.     storeSwapTLVFree(tlv_list);
  447. }
  448. #endif
  449. static int
  450. storeGetNextFile(rebuild_dir * d, int *sfileno, int *size)
  451. {
  452.     int fd = -1;
  453.     int used = 0;
  454.     debug(20, 3) ("storeGetNextFile: flag=%d, %d: /%02X/%02Xn",
  455. d->flag,
  456. d->dirn,
  457. d->curlvl1,
  458. d->curlvl2);
  459.     if (d->done)
  460. return -2;
  461.     while (fd < 0 && d->done == 0) {
  462. fd = -1;
  463. if (0 == d->flag) { /* initialize, open first file */
  464.     d->done = 0;
  465.     d->curlvl1 = 0;
  466.     d->curlvl2 = 0;
  467.     d->in_dir = 0;
  468.     d->flag = 1;
  469.     assert(Config.cacheSwap.n_configured > 0);
  470. }
  471. if (0 == d->in_dir) { /* we need to read in a new directory */
  472.     snprintf(d->fullpath, SQUID_MAXPATHLEN, "%s/%02X/%02X",
  473. Config.cacheSwap.swapDirs[d->dirn].path,
  474. d->curlvl1, d->curlvl2);
  475.     if (d->flag && d->td != NULL)
  476. closedir(d->td);
  477.     d->td = opendir(d->fullpath);
  478.     if (d->td == NULL) {
  479. debug(50, 1) ("storeGetNextFile: opendir: %s: %sn",
  480.     d->fullpath, xstrerror());
  481. break;
  482.     }
  483.     d->entry = readdir(d->td); /* skip . and .. */
  484.     d->entry = readdir(d->td);
  485.     if (d->entry == NULL && errno == ENOENT)
  486. debug(20, 1) ("storeGetNextFile: directory does not exist!.n");
  487.     debug(20, 3) ("storeGetNextFile: Directory %sn", d->fullpath);
  488. }
  489. if (d->td != NULL && (d->entry = readdir(d->td)) != NULL) {
  490.     d->in_dir++;
  491.     if (sscanf(d->entry->d_name, "%x", &d->fn) != 1) {
  492. debug(20, 3) ("storeGetNextFile: invalid %sn",
  493.     d->entry->d_name);
  494. continue;
  495.     }
  496.     if (!storeFilenoBelongsHere(d->fn, d->dirn, d->curlvl1, d->curlvl2)) {
  497. debug(20, 3) ("storeGetNextFile: %08X does not belong in %d/%d/%dn",
  498.     d->fn, d->dirn, d->curlvl1, d->curlvl2);
  499. continue;
  500.     }
  501.     d->fn = storeDirProperFileno(d->dirn, d->fn);
  502.     used = storeDirMapBitTest(d->fn);
  503.     if (used) {
  504. debug(20, 3) ("storeGetNextFile: Locked, continuing with next.n");
  505. continue;
  506.     }
  507.     snprintf(d->fullfilename, SQUID_MAXPATHLEN, "%s/%s",
  508. d->fullpath, d->entry->d_name);
  509.     debug(20, 3) ("storeGetNextFile: Opening %sn", d->fullfilename);
  510.     fd = file_open(d->fullfilename, O_RDONLY, NULL, NULL, NULL);
  511.     if (fd < 0)
  512. debug(50, 1) ("storeGetNextFile: %s: %sn", d->fullfilename, xstrerror());
  513.     continue;
  514.     store_open_disk_fd++;
  515. }
  516. d->in_dir = 0;
  517. if (++d->curlvl2 < Config.cacheSwap.swapDirs[d->dirn].l2)
  518.     continue;
  519. d->curlvl2 = 0;
  520. if (++d->curlvl1 < Config.cacheSwap.swapDirs[d->dirn].l1)
  521.     continue;
  522. d->curlvl1 = 0;
  523. d->done = 1;
  524.     }
  525.     *sfileno = d->fn;
  526.     return fd;
  527. }
  528. /* Add a new object to the cache with empty memory copy and pointer to disk
  529.  * use to rebuild store from disk. */
  530. static StoreEntry *
  531. storeAddDiskRestore(const cache_key * key,
  532.     int file_number,
  533.     size_t swap_file_sz,
  534.     time_t expires,
  535.     time_t timestamp,
  536.     time_t lastref,
  537.     time_t lastmod,
  538.     u_num32 refcount,
  539.     u_short flags,
  540.     int clean)
  541. {
  542.     StoreEntry *e = NULL;
  543.     debug(20, 5) ("StoreAddDiskRestore: %s, fileno=%08Xn", storeKeyText(key), file_number);
  544.     /* if you call this you'd better be sure file_number is not 
  545.      * already in use! */
  546.     e = new_StoreEntry(STORE_ENTRY_WITHOUT_MEMOBJ, NULL, NULL);
  547.     e->store_status = STORE_OK;
  548.     storeSetMemStatus(e, NOT_IN_MEMORY);
  549.     e->swap_status = SWAPOUT_DONE;
  550.     e->swap_file_number = file_number;
  551.     e->swap_file_sz = swap_file_sz;
  552.     e->lock_count = 0;
  553.     e->refcount = 0;
  554.     e->lastref = lastref;
  555.     e->timestamp = timestamp;
  556.     e->expires = expires;
  557.     e->lastmod = lastmod;
  558.     e->refcount = refcount;
  559.     e->flags = flags;
  560.     EBIT_SET(e->flags, ENTRY_CACHABLE);
  561.     EBIT_CLR(e->flags, RELEASE_REQUEST);
  562.     EBIT_CLR(e->flags, KEY_PRIVATE);
  563.     e->ping_status = PING_NONE;
  564.     EBIT_CLR(e->flags, ENTRY_VALIDATED);
  565.     storeDirMapBitSet(e->swap_file_number);
  566.     storeHashInsert(e, key); /* do it after we clear KEY_PRIVATE */
  567.     return e;
  568. }
  569. static void
  570. storeCleanup(void *datanotused)
  571. {
  572.     static int bucketnum = -1;
  573.     static int validnum = 0;
  574.     static int store_errors = 0;
  575.     StoreEntry *e;
  576.     hash_link *link_ptr = NULL;
  577.     hash_link *link_next = NULL;
  578.     if (++bucketnum >= store_hash_buckets) {
  579. debug(20, 1) ("  Completed Validation Proceduren");
  580. debug(20, 1) ("  Validated %d Entriesn", validnum);
  581. debug(20, 1) ("  store_swap_size = %dkn", store_swap_size);
  582. store_rebuilding = 0;
  583. if (opt_store_doublecheck)
  584.     assert(store_errors == 0);
  585. if (store_digest)
  586.     storeDigestNoteStoreReady();
  587. return;
  588.     }
  589.     link_next = hash_get_bucket(store_table, bucketnum);
  590.     while (NULL != (link_ptr = link_next)) {
  591. link_next = link_ptr->next;
  592. e = (StoreEntry *) link_ptr;
  593. if (EBIT_TEST(e->flags, ENTRY_VALIDATED))
  594.     continue;
  595. /*
  596.  * Calling storeRelease() has no effect because we're
  597.  * still in 'store_rebuilding' state
  598.  */
  599. if (e->swap_file_number < 0)
  600.     continue;
  601. if (opt_store_doublecheck) {
  602.     struct stat sb;
  603.     if (stat(storeSwapFullPath(e->swap_file_number, NULL), &sb) < 0) {
  604. store_errors++;
  605. debug(20, 0) ("storeCleanup: MISSING SWAP FILEn");
  606. debug(20, 0) ("storeCleanup: FILENO %08Xn", e->swap_file_number);
  607. debug(20, 0) ("storeCleanup: PATH %sn",
  608.     storeSwapFullPath(e->swap_file_number, NULL));
  609. storeEntryDump(e, 0);
  610. continue;
  611.     }
  612.     if (e->swap_file_sz != sb.st_size) {
  613. store_errors++;
  614. debug(20, 0) ("storeCleanup: SIZE MISMATCHn");
  615. debug(20, 0) ("storeCleanup: FILENO %08Xn", e->swap_file_number);
  616. debug(20, 0) ("storeCleanup: PATH %sn",
  617.     storeSwapFullPath(e->swap_file_number, NULL));
  618. debug(20, 0) ("storeCleanup: ENTRY SIZE: %d, FILE SIZE: %dn",
  619.     e->swap_file_sz, (int) sb.st_size);
  620. storeEntryDump(e, 0);
  621. continue;
  622.     }
  623. }
  624. EBIT_SET(e->flags, ENTRY_VALIDATED);
  625. /* Only set the file bit if we know its a valid entry */
  626. /* otherwise, set it in the validation procedure */
  627. storeDirUpdateSwapSize(e->swap_file_number, e->swap_file_sz, 1);
  628. if ((++validnum & 0xFFFF) == 0)
  629.     debug(20, 1) ("  %7d Entries Validated so far.n", validnum);
  630.     }
  631.     eventAdd("storeCleanup", storeCleanup, NULL, 0.0, 1);
  632. }
  633. void
  634. storeValidate(StoreEntry * e, STVLDCB * callback, void *callback_data, void *tag)
  635. {
  636.     valid_ctrl_t *ctrlp;
  637.     char *path;
  638.     struct stat *sb;
  639. #if !USE_ASYNC_IO
  640.     int x;
  641. #endif
  642.     assert(!EBIT_TEST(e->flags, ENTRY_VALIDATED));
  643.     if (e->swap_file_number < 0) {
  644. EBIT_CLR(e->flags, ENTRY_VALIDATED);
  645. callback(callback_data, 0, 0);
  646. return;
  647.     }
  648.     path = storeSwapFullPath(e->swap_file_number, NULL);
  649.     sb = xmalloc(sizeof(struct stat));
  650.     ctrlp = xmalloc(sizeof(valid_ctrl_t));
  651.     ctrlp->sb = sb;
  652.     ctrlp->e = e;
  653.     ctrlp->callback = callback;
  654.     ctrlp->callback_data = callback_data;
  655. #if USE_ASYNC_IO
  656.     aioStat(path, sb, storeValidateComplete, ctrlp, tag);
  657. #else
  658.     /*
  659.      * When evaluating the actual arguments in a function call, the order
  660.      * in which the arguments and the function expression are evaluated is
  661.      * not specified;
  662.      */
  663.     x = stat(path, sb);
  664.     storeValidateComplete(-1, ctrlp, x, errno);
  665. #endif
  666.     return;
  667. }
  668. static void
  669. storeValidateComplete(int fd, void *data, int retcode, int errcode)
  670. {
  671.     valid_ctrl_t *ctrlp = data;
  672.     struct stat *sb = ctrlp->sb;
  673.     StoreEntry *e = ctrlp->e;
  674.     char *path;
  675.     if (retcode == -2 && errcode == -2) {
  676. xfree(sb);
  677. xfree(ctrlp);
  678. ctrlp->callback(ctrlp->callback_data, retcode, errcode);
  679. return;
  680.     }
  681.     if (retcode < 0 && errcode == EWOULDBLOCK) {
  682. path = storeSwapFullPath(e->swap_file_number, NULL);
  683. retcode = stat(path, sb);
  684.     }
  685.     if (retcode < 0 || sb->st_size == 0 || sb->st_size != e->swap_file_sz) {
  686. EBIT_CLR(e->flags, ENTRY_VALIDATED);
  687.     } else {
  688. EBIT_SET(e->flags, ENTRY_VALIDATED);
  689. storeDirUpdateSwapSize(e->swap_file_number, e->swap_file_sz, 1);
  690.     }
  691.     errno = errcode;
  692.     ctrlp->callback(ctrlp->callback_data, retcode, errcode);
  693.     xfree(sb);
  694.     xfree(ctrlp);
  695. }
  696. /* meta data recreated from disk image in swap directory */
  697. static void
  698. storeRebuildComplete(void)
  699. {
  700.     time_t r;
  701.     time_t stop;
  702.     stop = squid_curtime;
  703.     r = stop - RebuildState.start;
  704.     debug(20, 1) ("Finished rebuilding storage disk.n");
  705.     debug(20, 1) ("  %7d Entries read from previous logfile.n",
  706. RebuildState.linecount);
  707.     debug(20, 1) ("  %7d Entries scanned from swap files.n",
  708. RebuildState.statcount);
  709.     debug(20, 1) ("  %7d Invalid entries.n", RebuildState.invalid);
  710.     debug(20, 1) ("  %7d With invalid flags.n", RebuildState.badflags);
  711.     debug(20, 1) ("  %7d Objects loaded.n", RebuildState.objcount);
  712.     debug(20, 1) ("  %7d Objects expired.n", RebuildState.expcount);
  713.     debug(20, 1) ("  %7d Objects cancelled.n", RebuildState.cancelcount);
  714.     debug(20, 1) ("  %7d Duplicate URLs purged.n", RebuildState.dupcount);
  715.     debug(20, 1) ("  %7d Swapfile clashes avoided.n", RebuildState.clashcount);
  716.     debug(20, 1) ("  Took %d seconds (%6.1f objects/sec).n",
  717. r > 0 ? (int) r : 0,
  718. (double) RebuildState.objcount / (r > 0 ? r : 1));
  719.     debug(20, 1) ("Beginning Validation Proceduren");
  720.     eventAdd("storeCleanup", storeCleanup, NULL, 0.0, 1);
  721. }
  722. void
  723. storeRebuildStart(void)
  724. {
  725.     rebuild_dir *d;
  726.     int clean = 0;
  727.     int zero = 0;
  728.     FILE *fp;
  729.     int i;
  730.     memset(&RebuildState, '', sizeof(RebuildState));
  731.     RebuildState.start = squid_curtime;
  732.     for (i = 0; i < Config.cacheSwap.n_configured; i++) {
  733. d = xcalloc(1, sizeof(rebuild_dir));
  734. d->dirn = i;
  735. d->speed = opt_foreground_rebuild ? 1 << 30 : 50;
  736. /*
  737.  * If the swap.state file exists in the cache_dir, then
  738.  * we'll use storeRebuildFromSwapLog(), otherwise we'll
  739.  * use storeRebuildFromDirectory() to open up each file
  740.  * and suck in the meta data.
  741.  */
  742. fp = storeDirOpenTmpSwapLog(i, &clean, &zero);
  743. if (fp == NULL || zero) {
  744.     if (fp != NULL)
  745. fclose(fp);
  746.     d->rebuild_func = storeRebuildFromDirectory;
  747. } else {
  748.     d->rebuild_func = storeRebuildFromSwapLog;
  749.     d->log = fp;
  750.     d->clean = clean;
  751. }
  752. d->next = RebuildState.rebuild_dir;
  753. RebuildState.rebuild_dir = d;
  754. if (!clean)
  755.     RebuildState.need_to_validate = 1;
  756. debug(20, 1) ("Rebuilding storage in Cache Dir #%d (%s)n",
  757.     i, clean ? "CLEAN" : "DIRTY");
  758.     }
  759.     eventAdd("storeRebuild", storeRebuildADirectory, NULL, 0.0, 1);
  760. }