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

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: store_dir.c,v 1.84.2.1 1999/02/14 00:23:11 wessels Exp $
  3.  *
  4.  * DEBUG: section 47    Store Directory 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. #if HAVE_STATVFS
  36. #if HAVE_SYS_STATVFS_H
  37. #include <sys/statvfs.h>
  38. #endif
  39. #endif
  40. #define SWAP_DIR_SHIFT 24
  41. #define SWAP_FILE_MASK 0x00FFFFFF
  42. #define DefaultLevelOneDirs     16
  43. #define DefaultLevelTwoDirs     256
  44. static char *storeSwapSubDir(int dirn, int subdirn);
  45. static int storeDirSelectSwapDir(void);
  46. static int storeVerifyDirectory(const char *path);
  47. static int storeCreateDirectory(const char *path, int);
  48. static void storeCreateSwapSubDirs(int j);
  49. /* return full name to swapfile */
  50. char *
  51. storeSwapFullPath(int fn, char *fullpath)
  52. {
  53.     LOCAL_ARRAY(char, fullfilename, SQUID_MAXPATHLEN);
  54.     int dirn = (fn >> SWAP_DIR_SHIFT) % Config.cacheSwap.n_configured;
  55.     int filn = fn & SWAP_FILE_MASK;
  56.     int L1 = Config.cacheSwap.swapDirs[dirn].l1;
  57.     int L2 = Config.cacheSwap.swapDirs[dirn].l2;
  58.     if (!fullpath)
  59. fullpath = fullfilename;
  60.     fullpath[0] = '';
  61.     snprintf(fullpath, SQUID_MAXPATHLEN, "%s/%02X/%02X/%08X",
  62. Config.cacheSwap.swapDirs[dirn].path,
  63. ((filn / L2) / L2) % L1,
  64. (filn / L2) % L2,
  65. filn);
  66.     return fullpath;
  67. }
  68. static char *
  69. storeSwapSubDir(int dirn, int subdirn)
  70. {
  71.     LOCAL_ARRAY(char, fullfilename, SQUID_MAXPATHLEN);
  72.     SwapDir *SD;
  73.     assert(0 <= dirn && dirn < Config.cacheSwap.n_configured);
  74.     SD = &Config.cacheSwap.swapDirs[dirn];
  75.     assert(0 <= subdirn && subdirn < SD->l1);
  76.     snprintf(fullfilename, SQUID_MAXPATHLEN, "%s/%02X",
  77. Config.cacheSwap.swapDirs[dirn].path,
  78. subdirn);
  79.     return fullfilename;
  80. }
  81. char *
  82. storeSwapSubSubDir(int fn, char *fullpath)
  83. {
  84.     LOCAL_ARRAY(char, fullfilename, SQUID_MAXPATHLEN);
  85.     int dirn = (fn >> SWAP_DIR_SHIFT) % Config.cacheSwap.n_configured;
  86.     int filn = fn & SWAP_FILE_MASK;
  87.     int L1 = Config.cacheSwap.swapDirs[dirn].l1;
  88.     int L2 = Config.cacheSwap.swapDirs[dirn].l2;
  89.     if (!fullpath)
  90. fullpath = fullfilename;
  91.     fullpath[0] = '';
  92.     snprintf(fullpath, SQUID_MAXPATHLEN, "%s/%02X/%02X",
  93. Config.cacheSwap.swapDirs[dirn].path,
  94. ((filn / L2) / L2) % L1,
  95. (filn / L2) % L2);
  96.     return fullpath;
  97. }
  98. /*
  99.  * Does swapfile number 'fn' belong in cachedir #F0,
  100.  * level1 dir #F1, level2 dir #F2?
  101.  *
  102.  * This is called by storeDirClean(), but placed here because
  103.  * the algorithm needs to match storeSwapSubSubDir().
  104.  *
  105.  * Don't check that (fn >> SWAP_DIR_SHIFT) == F0 because
  106.  * 'fn' may not have the directory bits set.
  107.  */
  108. int
  109. storeFilenoBelongsHere(int fn, int F0, int F1, int F2)
  110. {
  111.     int D1, D2;
  112.     int L1, L2;
  113.     int filn = fn & SWAP_FILE_MASK;
  114.     assert(F0 < Config.cacheSwap.n_configured);
  115.     L1 = Config.cacheSwap.swapDirs[F0].l1;
  116.     L2 = Config.cacheSwap.swapDirs[F0].l2;
  117.     D1 = ((filn / L2) / L2) % L1;
  118.     if (F1 != D1)
  119. return 0;
  120.     D2 = (filn / L2) % L2;
  121.     if (F2 != D2)
  122. return 0;
  123.     return 1;
  124. }
  125. static int
  126. storeCreateDirectory(const char *path, int should_exist)
  127. {
  128.     int created = 0;
  129.     struct stat st;
  130.     getCurrentTime();
  131.     if (0 == stat(path, &st)) {
  132. if (S_ISDIR(st.st_mode)) {
  133.     debug(20, should_exist ? 3 : 1) ("%s existsn", path);
  134. } else {
  135.     fatalf("Swap directory %s is not a directory.", path);
  136. }
  137.     } else if (0 == mkdir(path, 0755)) {
  138. debug(20, should_exist ? 1 : 3) ("%s createdn", path);
  139. created = 1;
  140.     } else {
  141. fatalf("Failed to make swap directory %s: %s",
  142.     path, xstrerror());
  143.     }
  144.     return created;
  145. }
  146. static int
  147. storeVerifyDirectory(const char *path)
  148. {
  149.     struct stat sb;
  150.     if (stat(path, &sb) < 0) {
  151. debug(20, 0) ("%s: %sn", path, xstrerror());
  152. return -1;
  153.     }
  154.     if (S_ISDIR(sb.st_mode) == 0) {
  155. debug(20, 0) ("%s is not a directoryn", path);
  156. return -1;
  157.     }
  158.     return 0;
  159. }
  160. /*
  161.  * This function is called by storeInit().  If this returns < 0,
  162.  * then Squid exits, complains about swap directories not
  163.  * existing, and instructs the admin to run 'squid -z'
  164.  */
  165. int
  166. storeVerifyCacheDirs(void)
  167. {
  168.     int i;
  169.     int j;
  170.     const char *path;
  171.     for (i = 0; i < Config.cacheSwap.n_configured; i++) {
  172. path = Config.cacheSwap.swapDirs[i].path;
  173. if (storeVerifyDirectory(path) < 0)
  174.     return -1;
  175. for (j = 0; j < Config.cacheSwap.swapDirs[i].l1; j++) {
  176.     path = storeSwapSubDir(i, j);
  177.     if (storeVerifyDirectory(path) < 0)
  178. return -1;
  179. }
  180.     }
  181.     return 0;
  182. }
  183. void
  184. storeCreateSwapDirectories(void)
  185. {
  186.     int i;
  187.     const char *path = NULL;
  188.     for (i = 0; i < Config.cacheSwap.n_configured; i++) {
  189. path = Config.cacheSwap.swapDirs[i].path;
  190. debug(47, 3) ("Creating swap space in %sn", path);
  191. storeCreateDirectory(path, 0);
  192. storeCreateSwapSubDirs(i);
  193.     }
  194. }
  195. static void
  196. storeCreateSwapSubDirs(int j)
  197. {
  198.     int i, k;
  199.     int should_exist;
  200.     SwapDir *SD = &Config.cacheSwap.swapDirs[j];
  201.     LOCAL_ARRAY(char, name, MAXPATHLEN);
  202.     for (i = 0; i < SD->l1; i++) {
  203. snprintf(name, MAXPATHLEN, "%s/%02X", SD->path, i);
  204. if (storeCreateDirectory(name, 0))
  205.     should_exist = 0;
  206. else
  207.     should_exist = 1;
  208. debug(47, 1) ("Making directories in %sn", name);
  209. for (k = 0; k < SD->l2; k++) {
  210.     snprintf(name, MAXPATHLEN, "%s/%02X/%02X", SD->path, i, k);
  211.     storeCreateDirectory(name, should_exist);
  212. }
  213.     }
  214. }
  215. /*
  216.  *Spread load across least 3/4 of the store directories
  217.  */
  218. static int
  219. storeDirSelectSwapDir(void)
  220. {
  221.     double least_used = 1.0;
  222.     double high = (double) Config.Swap.highWaterMark / 100.0;
  223.     double u;
  224.     int dirn;
  225.     int i, j;
  226.     SwapDir *SD;
  227.     static int nleast = 0;
  228.     static int nconf = 0;
  229.     static int *dirq = NULL;
  230.     static double *diru = NULL;
  231.     /*
  232.      * Handle simplest case of a single swap directory immediately
  233.      */
  234.     if (Config.cacheSwap.n_configured == 1)
  235. return 0;
  236.     /*
  237.      * Initialise dirq on the first call or on change of number of dirs
  238.      */
  239.     if (nconf != Config.cacheSwap.n_configured) {
  240. nconf = Config.cacheSwap.n_configured;
  241. nleast = (nconf * 3) / 4;
  242. safe_free(dirq);
  243. dirq = (int *) xmalloc(sizeof(int) * nleast);
  244. safe_free(diru);
  245. diru = (double *) xmalloc(sizeof(double) * nconf);
  246. for (j = 0; j < nleast; j++)
  247.     dirq[j] = -1;
  248.     }
  249.     /*
  250.      * Scan for a non-negative dirn in the dirq array and return that one
  251.      */
  252.     dirn = -1;
  253.     for (j = 0; j < nleast; j++) {
  254. dirn = dirq[j];
  255. if (dirn < 0)
  256.     continue;
  257. dirq[j] = -1;
  258. break;
  259.     }
  260.     /*
  261.      * If we found a valid dirn return it
  262.      */
  263.     if (dirn >= 0)
  264. return dirn;
  265.     /*
  266.      * Now for the real guts of the algorithm - building the dirq array
  267.      */
  268.     for (i = 0; i < nconf; i++) {
  269. diru[i] = 1.1;
  270. SD = &Config.cacheSwap.swapDirs[i];
  271. SD->flags.selected = 0;
  272. if (SD->flags.read_only)
  273.     continue;
  274. u = (double) SD->cur_size / SD->max_size;
  275. if (u > high)
  276.     continue;
  277. diru[i] = u;
  278.     }
  279.     for (j = 0; j < nleast; j++) {
  280. dirq[j] = -1;
  281. least_used = 1.0;
  282. dirn = -1;
  283. for (i = 0; i < nconf; i++) {
  284.     if (diru[i] < least_used) {
  285. least_used = diru[i];
  286. dirn = i;
  287.     }
  288. }
  289. if (dirn < 0)
  290.     break;
  291. dirq[j] = dirn;
  292. diru[dirn] = 1.1;
  293. /* set selected flag for debugging/cachemgr only */
  294. Config.cacheSwap.swapDirs[dirn].flags.selected = 1;
  295.     }
  296.     /*
  297.      * Setup default return of 0 if no least found
  298.      */
  299.     if (dirq[0] < 0)
  300. dirq[0] = 0;
  301.     dirn = dirq[0];
  302.     dirq[0] = -1;
  303.     return dirn;
  304. }
  305. int
  306. storeDirValidFileno(int fn)
  307. {
  308.     int dirn = fn >> SWAP_DIR_SHIFT;
  309.     int filn = fn & SWAP_FILE_MASK;
  310.     if (dirn > Config.cacheSwap.n_configured)
  311. return 0;
  312.     if (dirn < 0)
  313. return 0;
  314.     if (filn < 0)
  315. return 0;
  316.     if (filn > Config.cacheSwap.swapDirs[dirn].map->max_n_files)
  317. return 0;
  318.     return 1;
  319. }
  320. int
  321. storeDirMapBitTest(int fn)
  322. {
  323.     int dirn = fn >> SWAP_DIR_SHIFT;
  324.     int filn = fn & SWAP_FILE_MASK;
  325.     return file_map_bit_test(Config.cacheSwap.swapDirs[dirn].map, filn);
  326. }
  327. void
  328. storeDirMapBitSet(int fn)
  329. {
  330.     int dirn = fn >> SWAP_DIR_SHIFT;
  331.     int filn = fn & SWAP_FILE_MASK;
  332.     file_map_bit_set(Config.cacheSwap.swapDirs[dirn].map, filn);
  333. }
  334. void
  335. storeDirMapBitReset(int fn)
  336. {
  337.     int dirn = fn >> SWAP_DIR_SHIFT;
  338.     int filn = fn & SWAP_FILE_MASK;
  339.     file_map_bit_reset(Config.cacheSwap.swapDirs[dirn].map, filn);
  340. }
  341. int
  342. storeDirMapAllocate(void)
  343. {
  344.     int dirn = storeDirSelectSwapDir();
  345.     SwapDir *SD = &Config.cacheSwap.swapDirs[dirn];
  346.     int filn = file_map_allocate(SD->map, SD->suggest);
  347.     SD->suggest = filn + 1;
  348.     return (dirn << SWAP_DIR_SHIFT) | (filn & SWAP_FILE_MASK);
  349. }
  350. char *
  351. storeSwapDir(int dirn)
  352. {
  353.     assert(0 <= dirn && dirn < Config.cacheSwap.n_configured);
  354.     return Config.cacheSwap.swapDirs[dirn].path;
  355. }
  356. int
  357. storeDirNumber(int swap_file_number)
  358. {
  359.     return swap_file_number >> SWAP_DIR_SHIFT;
  360. }
  361. int
  362. storeDirProperFileno(int dirn, int fn)
  363. {
  364.     return (dirn << SWAP_DIR_SHIFT) | (fn & SWAP_FILE_MASK);
  365. }
  366. /*
  367.  * An entry written to the swap log MUST have the following
  368.  * properties.
  369.  *   1.  It MUST be a public key.  It does no good to log
  370.  *       a public ADD, change the key, then log a private
  371.  *       DEL.  So we need to log a DEL before we change a
  372.  *       key from public to private.
  373.  *   2.  It MUST have a valid (> -1) swap_file_number.
  374.  */
  375. void
  376. storeDirSwapLog(const StoreEntry * e, int op)
  377. {
  378.     storeSwapLogData *s;
  379.     int dirn;
  380.     dirn = e->swap_file_number >> SWAP_DIR_SHIFT;
  381.     assert(dirn < Config.cacheSwap.n_configured);
  382.     assert(!EBIT_TEST(e->flags, KEY_PRIVATE));
  383.     assert(e->swap_file_number >= 0);
  384.     /*
  385.      * icons and such; don't write them to the swap log
  386.      */
  387.     if (EBIT_TEST(e->flags, ENTRY_SPECIAL))
  388. return;
  389.     assert(op > SWAP_LOG_NOP && op < SWAP_LOG_MAX);
  390.     debug(20, 3) ("storeDirSwapLog: %s %s %08Xn",
  391. swap_log_op_str[op],
  392. storeKeyText(e->key),
  393. e->swap_file_number);
  394.     s = xcalloc(1, sizeof(storeSwapLogData));
  395.     s->op = (char) op;
  396.     s->swap_file_number = e->swap_file_number;
  397.     s->timestamp = e->timestamp;
  398.     s->lastref = e->lastref;
  399.     s->expires = e->expires;
  400.     s->lastmod = e->lastmod;
  401.     s->swap_file_sz = e->swap_file_sz;
  402.     s->refcount = e->refcount;
  403.     s->flags = e->flags;
  404.     xmemcpy(s->key, e->key, MD5_DIGEST_CHARS);
  405.     file_write(Config.cacheSwap.swapDirs[dirn].swaplog_fd,
  406. -1,
  407. s,
  408. sizeof(storeSwapLogData),
  409. NULL,
  410. NULL,
  411. xfree);
  412. }
  413. char *
  414. storeDirSwapLogFile(int dirn, const char *ext)
  415. {
  416.     LOCAL_ARRAY(char, path, SQUID_MAXPATHLEN);
  417.     LOCAL_ARRAY(char, digit, 32);
  418.     if (Config.Log.swap) {
  419. xstrncpy(path, Config.Log.swap, SQUID_MAXPATHLEN - 64);
  420. strcat(path, ".");
  421. snprintf(digit, 32, "%02d", dirn);
  422. strncat(path, digit, 3);
  423.     } else {
  424. xstrncpy(path, storeSwapDir(dirn), SQUID_MAXPATHLEN - 64);
  425. strcat(path, "/swap.state");
  426.     }
  427.     if (ext)
  428. strncat(path, ext, 16);
  429.     return path;
  430. }
  431. void
  432. storeDirOpenSwapLogs(void)
  433. {
  434.     int i;
  435.     char *path;
  436.     int fd;
  437.     SwapDir *SD;
  438.     for (i = 0; i < Config.cacheSwap.n_configured; i++) {
  439. SD = &Config.cacheSwap.swapDirs[i];
  440. path = storeDirSwapLogFile(i, NULL);
  441. fd = file_open(path, O_WRONLY | O_CREAT, NULL, NULL, NULL);
  442. if (fd < 0) {
  443.     debug(50, 1) ("%s: %sn", path, xstrerror());
  444.     fatal("storeDirOpenSwapLogs: Failed to open swap log.");
  445. }
  446. debug(47, 3) ("Cache Dir #%d log opened on FD %dn", i, fd);
  447. SD->swaplog_fd = fd;
  448.     }
  449. }
  450. void
  451. storeDirCloseSwapLogs(void)
  452. {
  453.     int i;
  454.     SwapDir *SD;
  455.     for (i = 0; i < Config.cacheSwap.n_configured; i++) {
  456. SD = &Config.cacheSwap.swapDirs[i];
  457. if (SD->swaplog_fd < 0) /* not open */
  458.     continue;
  459. file_close(SD->swaplog_fd);
  460. debug(47, 3) ("Cache Dir #%d log closed on FD %dn", i, SD->swaplog_fd);
  461. SD->swaplog_fd = -1;
  462.     }
  463. }
  464. FILE *
  465. storeDirOpenTmpSwapLog(int dirn, int *clean_flag, int *zero_flag)
  466. {
  467.     char *swaplog_path = xstrdup(storeDirSwapLogFile(dirn, NULL));
  468.     char *clean_path = xstrdup(storeDirSwapLogFile(dirn, ".last-clean"));
  469.     char *new_path = xstrdup(storeDirSwapLogFile(dirn, ".new"));
  470.     struct stat log_sb;
  471.     struct stat clean_sb;
  472.     SwapDir *SD = &Config.cacheSwap.swapDirs[dirn];
  473.     FILE *fp;
  474.     int fd;
  475.     if (stat(swaplog_path, &log_sb) < 0) {
  476. debug(47, 1) ("Cache Dir #%d: No log filen", dirn);
  477. safe_free(swaplog_path);
  478. safe_free(clean_path);
  479. safe_free(new_path);
  480. return NULL;
  481.     }
  482.     *zero_flag = log_sb.st_size == 0 ? 1 : 0;
  483.     /* close the existing write-only FD */
  484.     if (SD->swaplog_fd >= 0)
  485. file_close(SD->swaplog_fd);
  486.     /* open a write-only FD for the new log */
  487.     fd = file_open(new_path, O_WRONLY | O_CREAT | O_TRUNC, NULL, NULL, NULL);
  488.     if (fd < 0) {
  489. debug(50, 1) ("%s: %sn", new_path, xstrerror());
  490. fatal("storeDirOpenTmpSwapLog: Failed to open swap log.");
  491.     }
  492.     SD->swaplog_fd = fd;
  493.     /* open a read-only stream of the old log */
  494.     fp = fopen(swaplog_path, "r");
  495.     if (fp == NULL) {
  496. debug(50, 0) ("%s: %sn", swaplog_path, xstrerror());
  497. fatal("Failed to open swap log for reading");
  498.     }
  499.     memset(&clean_sb, '', sizeof(struct stat));
  500.     if (stat(clean_path, &clean_sb) < 0)
  501. *clean_flag = 0;
  502.     else if (clean_sb.st_mtime < log_sb.st_mtime)
  503. *clean_flag = 0;
  504.     else
  505. *clean_flag = 1;
  506.     safeunlink(clean_path, 1);
  507.     safe_free(swaplog_path);
  508.     safe_free(clean_path);
  509.     safe_free(new_path);
  510.     return fp;
  511. }
  512. void
  513. storeDirCloseTmpSwapLog(int dirn)
  514. {
  515.     char *swaplog_path = xstrdup(storeDirSwapLogFile(dirn, NULL));
  516.     char *new_path = xstrdup(storeDirSwapLogFile(dirn, ".new"));
  517.     SwapDir *SD = &Config.cacheSwap.swapDirs[dirn];
  518.     int fd;
  519.     file_close(SD->swaplog_fd);
  520. #ifdef _SQUID_OS2_
  521.     if (unlink(swaplog_path) < 0) {
  522. debug(50, 0) ("%s: %sn", swaplog_path, xstrerror());
  523. fatal("storeDirCloseTmpSwapLog: unlink failed");
  524.     }
  525. #endif
  526.     if (rename(new_path, swaplog_path) < 0) {
  527. debug(50, 0) ("%s,%s: %sn", new_path, swaplog_path, xstrerror());
  528. fatal("storeDirCloseTmpSwapLog: rename failed");
  529.     }
  530.     fd = file_open(swaplog_path, O_WRONLY | O_CREAT, NULL, NULL, NULL);
  531.     if (fd < 0) {
  532. debug(50, 1) ("%s: %sn", swaplog_path, xstrerror());
  533. fatal("storeDirCloseTmpSwapLog: Failed to open swap log.");
  534.     }
  535.     safe_free(swaplog_path);
  536.     safe_free(new_path);
  537.     SD->swaplog_fd = fd;
  538.     debug(47, 3) ("Cache Dir #%d log opened on FD %dn", dirn, fd);
  539. }
  540. void
  541. storeDirUpdateSwapSize(int fn, size_t size, int sign)
  542. {
  543.     int dirn = (fn >> SWAP_DIR_SHIFT) % Config.cacheSwap.n_configured;
  544.     int k = ((size + 1023) >> 10) * sign;
  545.     Config.cacheSwap.swapDirs[dirn].cur_size += k;
  546.     store_swap_size += k;
  547.     if (sign > 0)
  548. n_disk_objects++;
  549.     else if (sign < 0)
  550. n_disk_objects--;
  551. }
  552. void
  553. storeDirStats(StoreEntry * sentry)
  554. {
  555.     int i;
  556.     SwapDir *SD;
  557. #if HAVE_STATVFS
  558.     struct statvfs sfs;
  559. #endif
  560.     storeAppendPrintf(sentry, "Store Directory Statistics:n");
  561.     storeAppendPrintf(sentry, "Store Entries          : %dn",
  562. memInUse(MEM_STOREENTRY));
  563.     storeAppendPrintf(sentry, "Maximum Swap Size      : %8d KBn",
  564. Config.Swap.maxSize);
  565.     storeAppendPrintf(sentry, "Current Store Swap Size: %8d KBn",
  566. store_swap_size);
  567.     storeAppendPrintf(sentry, "Current Capacity       : %d%% used, %d%% freen",
  568. percent((int) store_swap_size, (int) Config.Swap.maxSize),
  569. percent((int) (Config.Swap.maxSize - store_swap_size), (int) Config.Swap.maxSize));
  570.     for (i = 0; i < Config.cacheSwap.n_configured; i++) {
  571. SD = &Config.cacheSwap.swapDirs[i];
  572. storeAppendPrintf(sentry, "n");
  573. storeAppendPrintf(sentry, "Store Directory #%d: %sn", i, SD->path);
  574. storeAppendPrintf(sentry, "First level subdirectories: %dn", SD->l1);
  575. storeAppendPrintf(sentry, "Second level subdirectories: %dn", SD->l2);
  576. storeAppendPrintf(sentry, "Maximum Size: %d KBn", SD->max_size);
  577. storeAppendPrintf(sentry, "Current Size: %d KBn", SD->cur_size);
  578. storeAppendPrintf(sentry, "Percent Used: %0.2f%%n",
  579.     100.0 * SD->cur_size / SD->max_size);
  580. storeAppendPrintf(sentry, "Filemap bits in use: %d of %d (%d%%)n",
  581.     SD->map->n_files_in_map, SD->map->max_n_files,
  582.     percent(SD->map->n_files_in_map, SD->map->max_n_files));
  583. #if HAVE_STATVFS
  584. #define fsbtoblk(num, fsbs, bs) 
  585.         (((fsbs) != 0 && (fsbs) < (bs)) ? 
  586.                 (num) / ((bs) / (fsbs)) : (num) * ((fsbs) / (bs)))
  587. if (!statvfs(SD->path, &sfs)) {
  588.     storeAppendPrintf(sentry, "Filesystem Space in use: %d/%d KB (%d%%)n",
  589. fsbtoblk((sfs.f_blocks - sfs.f_bfree), sfs.f_frsize, 1024),
  590. fsbtoblk(sfs.f_blocks, sfs.f_frsize, 1024),
  591. percent(sfs.f_blocks - sfs.f_bfree, sfs.f_blocks));
  592.     storeAppendPrintf(sentry, "Filesystem Inodes in use: %d/%d (%d%%)n",
  593. sfs.f_files - sfs.f_ffree, sfs.f_files,
  594. percent(sfs.f_files - sfs.f_ffree, sfs.f_files));
  595. }
  596. #endif
  597. storeAppendPrintf(sentry, "Flags:");
  598. if (SD->flags.selected)
  599.     storeAppendPrintf(sentry, " SELECTED");
  600. if (SD->flags.read_only)
  601.     storeAppendPrintf(sentry, " READ-ONLY");
  602. storeAppendPrintf(sentry, "n");
  603.     }
  604. }
  605. int
  606. storeDirMapBitsInUse(void)
  607. {
  608.     int i;
  609.     int n = 0;
  610.     for (i = 0; i < Config.cacheSwap.n_configured; i++)
  611. n += Config.cacheSwap.swapDirs[i].map->n_files_in_map;
  612.     return n;
  613. }
  614. /*
  615.  *  storeDirWriteCleanLogs
  616.  * 
  617.  *  Writes a "clean" swap log file from in-memory metadata.
  618.  */
  619. #define CLEAN_BUF_SZ 16384
  620. int
  621. storeDirWriteCleanLogs(int reopen)
  622. {
  623.     StoreEntry *e = NULL;
  624.     int *fd;
  625.     int n = 0;
  626.     time_t start, stop, r;
  627.     struct stat sb;
  628.     char **cur;
  629.     char **new;
  630.     char **cln;
  631.     int dirn;
  632.     int N = Config.cacheSwap.n_configured;
  633.     dlink_node *m;
  634.     char **outbuf;
  635.     off_t *outbufoffset;
  636.     storeSwapLogData s;
  637.     size_t ss = sizeof(storeSwapLogData);
  638.     if (store_rebuilding) {
  639. debug(20, 1) ("Not currently OK to rewrite swap log.n");
  640. debug(20, 1) ("storeDirWriteCleanLogs: Operation aborted.n");
  641. return 0;
  642.     }
  643.     debug(20, 1) ("storeDirWriteCleanLogs: Starting...n");
  644.     start = squid_curtime;
  645.     fd = xcalloc(N, sizeof(int));
  646.     cur = xcalloc(N, sizeof(char *));
  647.     new = xcalloc(N, sizeof(char *));
  648.     cln = xcalloc(N, sizeof(char *));
  649.     for (dirn = 0; dirn < N; dirn++) {
  650. fd[dirn] = -1;
  651. cur[dirn] = xstrdup(storeDirSwapLogFile(dirn, NULL));
  652. new[dirn] = xstrdup(storeDirSwapLogFile(dirn, ".clean"));
  653. cln[dirn] = xstrdup(storeDirSwapLogFile(dirn, ".last-clean"));
  654. unlink(new[dirn]);
  655. unlink(cln[dirn]);
  656. fd[dirn] = file_open(new[dirn],
  657.     O_WRONLY | O_CREAT | O_TRUNC,
  658.     NULL,
  659.     NULL,
  660.     NULL);
  661. if (fd[dirn] < 0) {
  662.     debug(50, 0) ("storeDirWriteCleanLogs: %s: %sn", new[dirn], xstrerror());
  663.     continue;
  664. }
  665. debug(20, 3) ("storeDirWriteCleanLogs: opened %s, FD %dn",
  666.     new[dirn], fd[dirn]);
  667. #if HAVE_FCHMOD
  668. if (stat(cur[dirn], &sb) == 0)
  669.     fchmod(fd[dirn], sb.st_mode);
  670. #endif
  671.     }
  672.     outbuf = xcalloc(N, sizeof(char *));
  673.     outbufoffset = xcalloc(N, sizeof(*outbufoffset));
  674.     for (dirn = 0; dirn < N; dirn++) {
  675. outbuf[dirn] = xcalloc(CLEAN_BUF_SZ, 1);
  676. outbufoffset[dirn] = 0;
  677.     }
  678.     for (m = store_list.tail; m; m = m->prev) {
  679. e = m->data;
  680. if (e->swap_file_number < 0)
  681.     continue;
  682. if (e->swap_status != SWAPOUT_DONE)
  683.     continue;
  684. if (e->swap_file_sz <= 0)
  685.     continue;
  686. if (EBIT_TEST(e->flags, RELEASE_REQUEST))
  687.     continue;
  688. if (EBIT_TEST(e->flags, KEY_PRIVATE))
  689.     continue;
  690. if (EBIT_TEST(e->flags, ENTRY_SPECIAL))
  691.     continue;
  692. dirn = storeDirNumber(e->swap_file_number);
  693. assert(dirn < N);
  694. if (fd[dirn] < 0)
  695.     continue;
  696. memset(&s, '', ss);
  697. s.op = (char) SWAP_LOG_ADD;
  698. s.swap_file_number = e->swap_file_number;
  699. s.timestamp = e->timestamp;
  700. s.lastref = e->lastref;
  701. s.expires = e->expires;
  702. s.lastmod = e->lastmod;
  703. s.swap_file_sz = e->swap_file_sz;
  704. s.refcount = e->refcount;
  705. s.flags = e->flags;
  706. xmemcpy(&s.key, e->key, MD5_DIGEST_CHARS);
  707. xmemcpy(outbuf[dirn] + outbufoffset[dirn], &s, ss);
  708. outbufoffset[dirn] += ss;
  709. /* buffered write */
  710. if (outbufoffset[dirn] + ss > CLEAN_BUF_SZ) {
  711.     if (write(fd[dirn], outbuf[dirn], outbufoffset[dirn]) < 0) {
  712. debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %sn",
  713.     new[dirn], xstrerror());
  714. debug(20, 0) ("storeDirWriteCleanLogs: Current swap logfile not replaced.n");
  715. file_close(fd[dirn]);
  716. fd[dirn] = -1;
  717. unlink(new[dirn]);
  718. continue;
  719.     }
  720.     outbufoffset[dirn] = 0;
  721. }
  722. if ((++n & 0xFFFF) == 0) {
  723.     getCurrentTime();
  724.     debug(20, 1) ("  %7d entries written so far.n", n);
  725. }
  726.     }
  727.     /* flush */
  728.     for (dirn = 0; dirn < N; dirn++) {
  729. if (outbufoffset[dirn] == 0)
  730.     continue;
  731. if (fd[dirn] < 0)
  732.     continue;
  733. if (write(fd[dirn], outbuf[dirn], outbufoffset[dirn]) < 0) {
  734.     debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %sn",
  735. new[dirn], xstrerror());
  736.     debug(20, 0) ("storeDirWriteCleanLogs: Current swap logfile not replaced.n");
  737.     file_close(fd[dirn]);
  738.     fd[dirn] = -1;
  739.     unlink(new[dirn]);
  740.     continue;
  741. }
  742. safe_free(outbuf[dirn]);
  743.     }
  744.     safe_free(outbuf);
  745.     safe_free(outbufoffset);
  746.     /*
  747.      * You can't rename open files on Microsoft "operating systems"
  748.      * so we have to close before renaming.
  749.      */
  750.     storeDirCloseSwapLogs();
  751.     /* rename */
  752.     for (dirn = 0; dirn < N; dirn++) {
  753. if (fd[dirn] < 0)
  754.     continue;
  755. #ifdef _SQUID_OS2_
  756. file_close(fd[dirn]);
  757. fd[dirn] = -1;
  758. if (unlink(cur[dirn]) < 0)
  759.     debug(50, 0) ("storeDirWriteCleanLogs: unlinkd failed: %s, %sn",
  760. xstrerror(), cur[dirn]);
  761. #endif
  762. if (rename(new[dirn], cur[dirn]) < 0) {
  763.     debug(50, 0) ("storeDirWriteCleanLogs: rename failed: %s, %s -> %sn",
  764. xstrerror(), new[dirn], cur[dirn]);
  765. }
  766.     }
  767.     if (reopen)
  768. storeDirOpenSwapLogs();
  769.     stop = squid_curtime;
  770.     r = stop - start;
  771.     debug(20, 1) ("  Finished.  Wrote %d entries.n", n);
  772.     debug(20, 1) ("  Took %d seconds (%6.1f entries/sec).n",
  773. r > 0 ? (int) r : 0,
  774. (double) n / (r > 0 ? r : 1));
  775.     /* touch a timestamp file if we're not still validating */
  776.     if (!store_rebuilding) {
  777. for (dirn = 0; dirn < N; dirn++) {
  778.     if (fd[dirn] < 0)
  779. continue;
  780.     file_close(file_open(cln[dirn],
  781.     O_WRONLY | O_CREAT | O_TRUNC, NULL, NULL, NULL));
  782. }
  783.     }
  784.     /* close */
  785.     for (dirn = 0; dirn < N; dirn++) {
  786. safe_free(cur[dirn]);
  787. safe_free(new[dirn]);
  788. safe_free(cln[dirn]);
  789. if (fd[dirn] < 0)
  790.     continue;
  791. file_close(fd[dirn]);
  792. fd[dirn] = -1;
  793.     }
  794.     safe_free(cur);
  795.     safe_free(new);
  796.     safe_free(cln);
  797.     safe_free(fd);
  798.     return n;
  799. }
  800. #undef CLEAN_BUF_SZ
  801. void
  802. storeDirConfigure(void)
  803. {
  804.     SwapDir *SD;
  805.     int n;
  806.     int i;
  807.     fileMap *fm;
  808.     Config.Swap.maxSize = 0;
  809.     for (i = 0; i < Config.cacheSwap.n_configured; i++) {
  810. SD = &Config.cacheSwap.swapDirs[i];;
  811. Config.Swap.maxSize += SD->max_size;
  812. n = 2 * SD->max_size / Config.Store.avgObjectSize;
  813. if (NULL == SD->map) {
  814.     /* first time */
  815.     SD->map = file_map_create(n);
  816. } else if (n > SD->map->max_n_files) {
  817.     /* it grew, need to expand */
  818.     fm = file_map_create(n);
  819.     filemapCopy(SD->map, fm);
  820.     filemapFreeMemory(SD->map);
  821.     SD->map = fm;
  822. }
  823. /* else it shrunk, and we leave the old one in place */
  824.     }
  825. }
  826. void
  827. storeDirDiskFull(int fn)
  828. {
  829.     int dirn = fn >> SWAP_DIR_SHIFT;
  830.     SwapDir *SD = &Config.cacheSwap.swapDirs[dirn];
  831.     assert(0 <= dirn && dirn < Config.cacheSwap.n_configured);
  832.     SD->max_size = SD->cur_size;
  833.     debug(20, 1) ("WARNING: Shrinking cache_dir #%d to %d KBn",
  834. dirn, SD->cur_size);
  835. }