--------------------- PatchSet 5353 Date: 2002/10/12 12:21:42 Author: rbcollins Branch: rbcollins_cxxtest Tag: (none) Log: store modules to .cc Members: src/Makefile.am:1.29.2.27->1.29.2.28 src/ufscommon.c:1.1.4.1->1.1.4.2(DEAD) src/ufscommon.cc:1.1->1.1.2.1 src/fs/Makefile.am:1.3.18.2->1.3.18.3 src/fs/aufs/aiops.c:1.12.14.1->1.12.14.2(DEAD) src/fs/aufs/aiops.cc:1.1->1.1.2.1 src/fs/aufs/async_io.c:1.11.10.2->1.11.10.3(DEAD) src/fs/aufs/async_io.cc:1.1->1.1.2.1 src/fs/aufs/store_dir_aufs.c:1.32.10.2->1.32.10.3(DEAD) src/fs/aufs/store_dir_aufs.cc:1.1->1.1.2.1 src/fs/aufs/store_io_aufs.c:1.19.10.2->1.19.10.3(DEAD) src/fs/aufs/store_io_aufs.cc:1.1->1.1.2.1 src/fs/coss/async_io.c:1.6->1.6.14.1(DEAD) src/fs/coss/async_io.cc:1.1->1.1.2.1 src/fs/coss/store_dir_coss.c:1.24.10.1->1.24.10.2(DEAD) src/fs/coss/store_dir_coss.cc:1.1->1.1.2.1 src/fs/coss/store_io_coss.c:1.14.10.1->1.14.10.2(DEAD) src/fs/coss/store_io_coss.cc:1.1->1.1.2.1 src/fs/diskd/Makefile.am:1.2->1.2.72.1 src/fs/diskd/diskd.c:1.6->1.6.92.1(DEAD) src/fs/diskd/diskd.cc:1.1->1.1.2.1 src/fs/diskd/store_dir_diskd.c:1.42.10.2->1.42.10.3(DEAD) src/fs/diskd/store_dir_diskd.cc:1.1->1.1.2.1 src/fs/diskd/store_io_diskd.c:1.12.10.2->1.12.10.3(DEAD) src/fs/diskd/store_io_diskd.cc:1.1->1.1.2.1 src/fs/null/store_null.c:1.3->1.3.16.1(DEAD) src/fs/null/store_null.cc:1.1->1.1.2.1 src/fs/ufs/store_dir_ufs.c:1.31.6.2->1.31.6.3(DEAD) src/fs/ufs/store_dir_ufs.cc:1.1->1.1.2.1 src/fs/ufs/store_io_ufs.c:1.9.10.2->1.9.10.3(DEAD) src/fs/ufs/store_io_ufs.cc:1.1->1.1.2.1 Index: squid/src/Makefile.am =================================================================== RCS file: /cvsroot/squid-sf//squid/src/Makefile.am,v retrieving revision 1.29.2.27 retrieving revision 1.29.2.28 diff -u -r1.29.2.27 -r1.29.2.28 --- squid/src/Makefile.am 12 Oct 2002 10:35:54 -0000 1.29.2.27 +++ squid/src/Makefile.am 12 Oct 2002 12:21:42 -0000 1.29.2.28 @@ -219,7 +219,7 @@ structs.h \ tools.cc \ typedefs.h \ - ufscommon.c \ + ufscommon.cc \ ufscommon.h \ $(UNLINKDSOURCE) \ url.cc \ @@ -233,7 +233,7 @@ nodist_squid_SOURCES = \ repl_modules.cc \ auth_modules.cc \ - store_modules.c \ + store_modules.cc \ cf_parser.h \ globals.c \ string_arrays.c @@ -275,7 +275,7 @@ string_arrays.c \ repl_modules.cc \ auth_modules.cc \ - store_modules.c + store_modules.cc sysconf_DATA = \ squid.conf.default \ @@ -367,8 +367,8 @@ s%@DEFAULT_HOSTS@%$(DEFAULT_HOSTS)%g;"\ < $(srcdir)/cf.data.pre >$@ -store_modules.c: store_modules.sh Makefile - $(SHELL) $(srcdir)/store_modules.sh $(STORE_MODULES) >store_modules.c +store_modules.cc: store_modules.sh Makefile + $(SHELL) $(srcdir)/store_modules.sh $(STORE_MODULES) >store_modules.cc repl_modules.cc: repl_modules.sh Makefile $(SHELL) $(srcdir)/repl_modules.sh $(REPL_POLICIES) > repl_modules.cc @@ -402,7 +402,7 @@ fi DISTCLEANFILES = cf_gen_defines.h cf.data cf_parser.h squid.conf.default \ - globals.c string_arrays.c repl_modules.cc auth_modules.cc store_modules.c + globals.c string_arrays.c repl_modules.cc auth_modules.cc store_modules.cc ##install-pinger: ## @f=$(PINGER_EXE); \ --- squid/src/ufscommon.c Wed Feb 14 01:07:42 2007 +++ /dev/null Wed Feb 14 01:07:22 2007 @@ -1,1734 +0,0 @@ -/* - * $Id: ufscommon.c,v 1.1.4.1 2002/10/12 10:35:54 rbcollins Exp $ - * - * DEBUG: section 47 Store Directory Routines - * AUTHOR: Duane Wessels - * - * SQUID Web Proxy Cache http://www.squid-cache.org/ - * ---------------------------------------------------------- - * - * Squid is the result of efforts by numerous individuals from - * the Internet community; see the CONTRIBUTORS file for full - * details. Many organizations have provided support for Squid's - * development; see the SPONSORS file for full details. Squid is - * Copyrighted (C) 2001 by the Regents of the University of - * California; see the COPYRIGHT file for full details. Squid - * incorporates software developed and/or copyrighted by other - * sources; see the CREDITS file for full details. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. - * - */ - -#include "ufscommon.h" -#include "Store.h" - -typedef struct _RebuildState RebuildState; -struct _RebuildState { - SwapDir *sd; - int n_read; - FILE *log; - int speed; - int curlvl1; - int curlvl2; - struct { - unsigned int need_to_validate:1; - unsigned int clean:1; - unsigned int init:1; - } flags; - int done; - int in_dir; - int fn; - struct dirent *entry; - DIR *td; - char fullpath[SQUID_MAXPATHLEN]; - char fullfilename[SQUID_MAXPATHLEN]; - struct _store_rebuild_data counts; -}; - -static int n_dirs = 0; -static int *dir_index = NULL; -#if 0 -MemPool *squidaio_state_pool = NULL; -MemPool *aufs_qread_pool = NULL; -MemPool *aufs_qwrite_pool = NULL; -static int asyncufs_initialised = 0; -#endif -static int commonUfsFilenoBelongsHere(int fn, int F0, int F1, int F2); -static char *commonUfsDirSwapSubDir(SwapDir *, int subdirn); -static int commonUfsDirCreateDirectory(const char *path, int); -static int commonUfsDirVerifyCacheDirs(SwapDir * sd); -static int commonUfsDirVerifyDirectory(const char *path); -static void commonUfsDirCreateSwapSubDirs(SwapDir *); -static int commonUfsDirMapBitTest(SwapDir * SD, sfileno filn); -static char *commonUfsDirSwapLogFile(SwapDir *, const char *); -static EVH commonUfsDirRebuildFromDirectory; -static EVH commonUfsDirRebuildFromSwapLog; -static int commonUfsDirGetNextFile(RebuildState *, sfileno *, int *size); -static StoreEntry *commonUfsDirAddDiskRestore(SwapDir * SD, const cache_key * key, - sfileno file_number, - size_t swap_file_sz, - time_t expires, - time_t timestamp, - time_t lastref, - time_t lastmod, - u_int32_t refcount, - u_int16_t flags, - int clean); -static void commonUfsDirRebuild(SwapDir * sd); -static void commonUfsDirCloseTmpSwapLog(SwapDir * sd); -static FILE *commonUfsDirOpenTmpSwapLog(SwapDir *, int *, int *); -#if 0 -static STLOGOPEN commonUfsDirOpenSwapLog; -static STINIT commonUfsDirInit; -static STFREE commonUfsDirFree; -static STLOGCLEANSTART commonUfsDirWriteCleanStart; -static STLOGCLEANNEXTENTRY commonUfsDirCleanLogNextEntry; -#endif -static STLOGCLEANWRITE commonUfsDirWriteCleanEntry; -#if 0 -static STLOGCLEANDONE commonUfsDirWriteCleanDone; -static STLOGCLOSE commonUfsDirCloseSwapLog; -static STLOGWRITE commonUfsDirSwapLog; -static STNEWFS commonUfsDirNewfs; -static STCHECKOBJ commonUfsDirCheckObj; -#endif -static QS rev_int_sort; -static void commonUfsDirMapBitSet(SwapDir * SD, sfileno filn); -static EVH commonUfsDirCleanEvent; -static int commonUfsDirClean(int swap_index); -static int commonUfsDirIs(SwapDir * sd); -#if 0 -static int commonUfsCleanupDoubleCheck(SwapDir *, StoreEntry *); -#endif -static void commonUfsDirInitBitmap(SwapDir *); -static int commonUfsDirValidFileno(SwapDir * SD, sfileno filn, int flag); -static int commonUfsDirMapBitTest(SwapDir * SD, sfileno filn); -void commonUfsDirMapBitReset(SwapDir * SD, sfileno filn); - -#if 0 - -/* The MAIN externally visible function */ -STSETUP storeFsSetup_aufs; - -/* - * These functions were ripped straight out of the heart of store_dir.c. - * They assume that the given filenum is on a asyncufs partiton, which may or - * may not be true.. - * XXX this evilness should be tidied up at a later date! - */ - -#endif -int -commonUfsDirMapBitTest(SwapDir * SD, sfileno filn) -{ - squidufsinfo_t *ioinfo; - ioinfo = (squidufsinfo_t *) SD->fsdata; - return file_map_bit_test(ioinfo->map, filn); -} - -void -commonUfsDirMapBitSet(SwapDir * SD, sfileno filn) -{ - squidufsinfo_t *ioinfo; - ioinfo = (squidufsinfo_t *) SD->fsdata; - file_map_bit_set(ioinfo->map, filn); -} - -void -commonUfsDirMapBitReset(SwapDir * SD, sfileno filn) -{ - squidufsinfo_t *ioinfo; - ioinfo = (squidufsinfo_t *) SD->fsdata; - /* - * We have to test the bit before calling file_map_bit_reset. - * file_map_bit_reset doesn't do bounds checking. It assumes - * filn is a valid file number, but it might not be because - * the map is dynamic in size. Also clearing an already clear - * bit puts the map counter of-of-whack. - */ - if (file_map_bit_test(ioinfo->map, filn)) - file_map_bit_reset(ioinfo->map, filn); -} - -int -commonUfsDirMapBitAllocate(SwapDir * SD) -{ - squidufsinfo_t *ioinfo = (squidufsinfo_t *) SD->fsdata; - int fn; - fn = file_map_allocate(ioinfo->map, ioinfo->suggest); - file_map_bit_set(ioinfo->map, fn); - ioinfo->suggest = fn + 1; - return fn; -} - -/* - * Initialise the asyncufs bitmap - * - * If there already is a bitmap, and the numobjects is larger than currently - * configured, we allocate a new bitmap and 'grow' the old one into it. - */ -void -commonUfsDirInitBitmap(SwapDir * sd) -{ - squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata; - - if (ioinfo->map == NULL) { - /* First time */ - ioinfo->map = file_map_create(); - } else if (ioinfo->map->max_n_files) { - /* it grew, need to expand */ - /* XXX We don't need it anymore .. */ - } - /* else it shrunk, and we leave the old one in place */ -} - -char * -commonUfsDirSwapSubDir(SwapDir * sd, int subdirn) -{ - squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata; - - LOCAL_ARRAY(char, fullfilename, SQUID_MAXPATHLEN); - assert(0 <= subdirn && subdirn < ioinfo->l1); - snprintf(fullfilename, SQUID_MAXPATHLEN, "%s/%02X", sd->path, subdirn); - return fullfilename; -} - -int -commonUfsDirCreateDirectory(const char *path, int should_exist) -{ - int created = 0; - struct stat st; - getCurrentTime(); - if (0 == stat(path, &st)) { - if (S_ISDIR(st.st_mode)) { - debug(47, should_exist ? 3 : 1) ("%s exists\n", path); - } else { - fatalf("Swap directory %s is not a directory.", path); - } -#ifdef _SQUID_MSWIN_ - } else if (0 == mkdir(path)) { -#else - } else if (0 == mkdir(path, 0755)) { -#endif - debug(47, should_exist ? 1 : 3) ("%s created\n", path); - created = 1; - } else { - fatalf("Failed to make swap directory %s: %s", - path, xstrerror()); - } - return created; -} - -int -commonUfsDirVerifyDirectory(const char *path) -{ - struct stat sb; - if (stat(path, &sb) < 0) { - debug(47, 0) ("%s: %s\n", path, xstrerror()); - return -1; - } - if (S_ISDIR(sb.st_mode) == 0) { - debug(47, 0) ("%s is not a directory\n", path); - return -1; - } - return 0; -} - -/* - * This function is called by commonUfsDirInit(). If this returns < 0, - * then Squid exits, complains about swap directories not - * existing, and instructs the admin to run 'squid -z' - */ -int -commonUfsDirVerifyCacheDirs(SwapDir * sd) -{ - squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata; - int j; - const char *path = sd->path; - - if (commonUfsDirVerifyDirectory(path) < 0) - return -1; - for (j = 0; j < ioinfo->l1; j++) { - path = commonUfsDirSwapSubDir(sd, j); - if (commonUfsDirVerifyDirectory(path) < 0) - return -1; - } - return 0; -} - -void -commonUfsDirCreateSwapSubDirs(SwapDir * sd) -{ - squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata; - int i, k; - int should_exist; - LOCAL_ARRAY(char, name, MAXPATHLEN); - for (i = 0; i < ioinfo->l1; i++) { - snprintf(name, MAXPATHLEN, "%s/%02X", sd->path, i); - if (commonUfsDirCreateDirectory(name, 0)) - should_exist = 0; - else - should_exist = 1; - debug(47, 1) ("Making directories in %s\n", name); - for (k = 0; k < ioinfo->l2; k++) { - snprintf(name, MAXPATHLEN, "%s/%02X/%02X", sd->path, i, k); - commonUfsDirCreateDirectory(name, should_exist); - } - } -} - -char * -commonUfsDirSwapLogFile(SwapDir * sd, const char *ext) -{ - LOCAL_ARRAY(char, path, SQUID_MAXPATHLEN); - LOCAL_ARRAY(char, pathtmp, SQUID_MAXPATHLEN); - LOCAL_ARRAY(char, digit, 32); - char *pathtmp2; - if (Config.Log.swap) { - xstrncpy(pathtmp, sd->path, SQUID_MAXPATHLEN - 64); - pathtmp2 = pathtmp; - while ((pathtmp2 = strchr(pathtmp2, '/')) != NULL) - *pathtmp2 = '.'; - while (strlen(pathtmp) && pathtmp[strlen(pathtmp) - 1] == '.') - pathtmp[strlen(pathtmp) - 1] = '\0'; - for (pathtmp2 = pathtmp; *pathtmp2 == '.'; pathtmp2++); - snprintf(path, SQUID_MAXPATHLEN - 64, Config.Log.swap, pathtmp2); - if (strncmp(path, Config.Log.swap, SQUID_MAXPATHLEN - 64) == 0) { - strcat(path, "."); - snprintf(digit, 32, "%02d", sd->index); - strncat(path, digit, 3); - } - } else { - xstrncpy(path, sd->path, SQUID_MAXPATHLEN - 64); - strcat(path, "/swap.state"); - } - if (ext) - strncat(path, ext, 16); - return path; -} - -void -commonUfsDirOpenSwapLog(SwapDir * sd) -{ - squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata; - char *path; - int fd; - path = commonUfsDirSwapLogFile(sd, NULL); - fd = file_open(path, O_WRONLY | O_CREAT | O_BINARY); - if (fd < 0) { - debug(50, 1) ("%s: %s\n", path, xstrerror()); - fatal("commonUfsDirOpenSwapLog: Failed to open swap log."); - } - debug(50, 3) ("Cache Dir #%d log opened on FD %d\n", sd->index, fd); - ioinfo->swaplog_fd = fd; - if (0 == n_dirs) - assert(NULL == dir_index); - ++n_dirs; - assert(n_dirs <= Config.cacheSwap.n_configured); -} - -void -commonUfsDirCloseSwapLog(SwapDir * sd) -{ - squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata; - if (ioinfo->swaplog_fd < 0) /* not open */ - return; - file_close(ioinfo->swaplog_fd); - debug(47, 3) ("Cache Dir #%d log closed on FD %d\n", - sd->index, ioinfo->swaplog_fd); - ioinfo->swaplog_fd = -1; - n_dirs--; - assert(n_dirs >= 0); - if (0 == n_dirs) - safe_free(dir_index); -} - -void -commonUfsDirInit(SwapDir * sd) -{ - static int started_clean_event = 0; - static const char *errmsg = - "\tFailed to verify one of the swap directories, Check cache.log\n" - "\tfor details. Run 'squid -z' to create swap directories\n" - "\tif needed, or if running Squid for the first time."; - commonUfsDirInitBitmap(sd); - if (commonUfsDirVerifyCacheDirs(sd) < 0) - fatal(errmsg); - commonUfsDirOpenSwapLog(sd); - commonUfsDirRebuild(sd); - if (!started_clean_event) { - eventAdd("storeDirClean", commonUfsDirCleanEvent, NULL, 15.0, 1); - started_clean_event = 1; - } - (void) storeDirGetBlkSize(sd->path, &sd->fs.blksize); -} - -void -commonUfsDirRebuildFromDirectory(void *data) -{ - RebuildState *rb = data; - SwapDir *SD = rb->sd; - LOCAL_ARRAY(char, hdr_buf, SM_PAGE_SIZE); - StoreEntry *e = NULL; - StoreEntry tmpe; - cache_key key[MD5_DIGEST_CHARS]; - sfileno filn = 0; - int count; - int size; - struct stat sb; - int swap_hdr_len; - int fd = -1; - tlv *tlv_list; - tlv *t; - assert(rb != NULL); - debug(47, 3) ("commonUfsDirRebuildFromDirectory: DIR #%d\n", rb->sd->index); - for (count = 0; count < rb->speed; count++) { - assert(fd == -1); - fd = commonUfsDirGetNextFile(rb, &filn, &size); - if (fd == -2) { - debug(47, 1) ("Done scanning %s swaplog (%d entries)\n", - rb->sd->path, rb->n_read); - store_dirs_rebuilding--; - commonUfsDirCloseTmpSwapLog(rb->sd); - storeRebuildComplete(&rb->counts); - cbdataFree(rb); - return; - } else if (fd < 0) { - continue; - } - assert(fd > -1); - /* lets get file stats here */ - if (fstat(fd, &sb) < 0) { - debug(47, 1) ("commonUfsDirRebuildFromDirectory: fstat(FD %d): %s\n", - fd, xstrerror()); - file_close(fd); - store_open_disk_fd--; - fd = -1; - continue; - } - if ((++rb->counts.scancount & 0xFFFF) == 0) - debug(47, 3) (" %s %7d files opened so far.\n", - rb->sd->path, rb->counts.scancount); - debug(47, 9) ("file_in: fd=%d %08X\n", fd, filn); - statCounter.syscalls.disk.reads++; - if (FD_READ_METHOD(fd, hdr_buf, SM_PAGE_SIZE) < 0) { - debug(47, 1) ("commonUfsDirRebuildFromDirectory: read(FD %d): %s\n", - fd, xstrerror()); - file_close(fd); - store_open_disk_fd--; - fd = -1; - continue; - } - file_close(fd); - store_open_disk_fd--; - fd = -1; - swap_hdr_len = 0; -#if USE_TRUNCATE - if (sb.st_size == 0) - continue; -#endif - tlv_list = storeSwapMetaUnpack(hdr_buf, &swap_hdr_len); - if (tlv_list == NULL) { - debug(47, 1) ("commonUfsDirRebuildFromDirectory: failed to get meta data\n"); - /* XXX shouldn't this be a call to commonUfsUnlink ? */ - commonUfsDirUnlinkFile(SD, filn); - continue; - } - debug(47, 3) ("commonUfsDirRebuildFromDirectory: successful swap meta unpacking\n"); - memset(key, '\0', MD5_DIGEST_CHARS); - memset(&tmpe, '\0', sizeof(StoreEntry)); - for (t = tlv_list; t; t = t->next) { - switch (t->type) { - case STORE_META_KEY: - assert(t->length == MD5_DIGEST_CHARS); - xmemcpy(key, t->value, MD5_DIGEST_CHARS); - break; - case STORE_META_STD: - assert(t->length == STORE_HDR_METASIZE); - xmemcpy(&tmpe.timestamp, t->value, STORE_HDR_METASIZE); - break; - default: - break; - } - } - storeSwapTLVFree(tlv_list); - tlv_list = NULL; - if (storeKeyNull(key)) { - debug(47, 1) ("commonUfsDirRebuildFromDirectory: NULL key\n"); - commonUfsDirUnlinkFile(SD, filn); - continue; - } - tmpe.hash.key = key; - /* check sizes */ - if (tmpe.swap_file_sz == 0) { - tmpe.swap_file_sz = (size_t) sb.st_size; - } else if (tmpe.swap_file_sz == sb.st_size - swap_hdr_len) { - tmpe.swap_file_sz = (size_t) sb.st_size; - } else if (tmpe.swap_file_sz != sb.st_size) { - debug(47, 1) ("commonUfsDirRebuildFromDirectory: SIZE MISMATCH %ld!=%ld\n", - (long int) tmpe.swap_file_sz, (long int) sb.st_size); - commonUfsDirUnlinkFile(SD, filn); - continue; - } - if (EBIT_TEST(tmpe.flags, KEY_PRIVATE)) { - commonUfsDirUnlinkFile(SD, filn); - rb->counts.badflags++; - continue; - } - e = storeGet(key); - if (e && e->lastref >= tmpe.lastref) { - /* key already exists, current entry is newer */ - /* keep old, ignore new */ - rb->counts.dupcount++; - continue; - } else if (NULL != e) { - /* URL already exists, this swapfile not being used */ - /* junk old, load new */ - storeRelease(e); /* release old entry */ - rb->counts.dupcount++; - } - rb->counts.objcount++; - storeEntryDump(&tmpe, 5); - e = commonUfsDirAddDiskRestore(SD, key, - filn, - tmpe.swap_file_sz, - tmpe.expires, - tmpe.timestamp, - tmpe.lastref, - tmpe.lastmod, - tmpe.refcount, /* refcount */ - tmpe.flags, /* flags */ - (int) rb->flags.clean); - storeDirSwapLog(e, SWAP_LOG_ADD); - } - eventAdd("storeRebuild", commonUfsDirRebuildFromDirectory, rb, 0.0, 1); -} - -void -commonUfsDirRebuildFromSwapLog(void *data) -{ - RebuildState *rb = data; - SwapDir *SD = rb->sd; - StoreEntry *e = NULL; - storeSwapLogData s; - size_t ss = sizeof(storeSwapLogData); - int count; - int used; /* is swapfile already in use? */ - int disk_entry_newer; /* is the log entry newer than current entry? */ - double x; - assert(rb != NULL); - /* load a number of objects per invocation */ - for (count = 0; count < rb->speed; count++) { - if (fread(&s, ss, 1, rb->log) != 1) { - debug(47, 1) ("Done reading %s swaplog (%d entries)\n", - rb->sd->path, rb->n_read); - fclose(rb->log); - rb->log = NULL; - store_dirs_rebuilding--; - commonUfsDirCloseTmpSwapLog(rb->sd); - storeRebuildComplete(&rb->counts); - cbdataFree(rb); - return; - } - rb->n_read++; - if (s.op <= SWAP_LOG_NOP) - continue; - if (s.op >= SWAP_LOG_MAX) - continue; - /* - * BC: during 2.4 development, we changed the way swap file - * numbers are assigned and stored. The high 16 bits used - * to encode the SD index number. There used to be a call - * to storeDirProperFileno here that re-assigned the index - * bits. Now, for backwards compatibility, we just need - * to mask it off. - */ - s.swap_filen &= 0x00FFFFFF; - debug(47, 3) ("commonUfsDirRebuildFromSwapLog: %s %s %08X\n", - swap_log_op_str[(int) s.op], - storeKeyText(s.key), - s.swap_filen); - if (s.op == SWAP_LOG_ADD) { - (void) 0; - } else if (s.op == SWAP_LOG_DEL) { - if ((e = storeGet(s.key)) != NULL) { - /* - * Make sure we don't unlink the file, it might be - * in use by a subsequent entry. Also note that - * we don't have to subtract from store_swap_size - * because adding to store_swap_size happens in - * the cleanup procedure. - */ - storeExpireNow(e); - storeReleaseRequest(e); - if (e->swap_filen > -1) { - commonUfsDirReplRemove(e); - commonUfsDirMapBitReset(SD, e->swap_filen); - e->swap_filen = -1; - e->swap_dirn = -1; - } - storeRelease(e); - rb->counts.objcount--; - rb->counts.cancelcount++; - } - continue; - } else { - x = log(++rb->counts.bad_log_op) / log(10.0); - if (0.0 == x - (double) (int) x) - debug(47, 1) ("WARNING: %d invalid swap log entries found\n", - rb->counts.bad_log_op); - rb->counts.invalid++; - continue; - } - if ((++rb->counts.scancount & 0xFFF) == 0) { - struct stat sb; - if (0 == fstat(fileno(rb->log), &sb)) - storeRebuildProgress(SD->index, - (int) sb.st_size / ss, rb->n_read); - } - if (!commonUfsDirValidFileno(SD, s.swap_filen, 0)) { - rb->counts.invalid++; - continue; - } - if (EBIT_TEST(s.flags, KEY_PRIVATE)) { - rb->counts.badflags++; - continue; - } - e = storeGet(s.key); - used = commonUfsDirMapBitTest(SD, s.swap_filen); - /* If this URL already exists in the cache, does the swap log - * appear to have a newer entry? Compare 'lastref' from the - * swap log to e->lastref. */ - disk_entry_newer = e ? (s.lastref > e->lastref ? 1 : 0) : 0; - if (used && !disk_entry_newer) { - /* log entry is old, ignore it */ - rb->counts.clashcount++; - continue; - } else if (used && e && e->swap_filen == s.swap_filen && e->swap_dirn == SD->index) { - /* swapfile taken, same URL, newer, update meta */ - if (e->store_status == STORE_OK) { - e->lastref = s.timestamp; - e->timestamp = s.timestamp; - e->expires = s.expires; - e->lastmod = s.lastmod; - e->flags = s.flags; - e->refcount += s.refcount; - commonUfsDirUnrefObj(SD, e); - } else { - debug_trap("commonUfsDirRebuildFromSwapLog: bad condition"); - debug(47, 1) ("\tSee %s:%d\n", __FILE__, __LINE__); - } - continue; - } else if (used) { - /* swapfile in use, not by this URL, log entry is newer */ - /* This is sorta bad: the log entry should NOT be newer at this - * point. If the log is dirty, the filesize check should have - * caught this. If the log is clean, there should never be a - * newer entry. */ - debug(47, 1) ("WARNING: newer swaplog entry for dirno %d, fileno %08X\n", - SD->index, s.swap_filen); - /* I'm tempted to remove the swapfile here just to be safe, - * but there is a bad race condition in the NOVM version if - * the swapfile has recently been opened for writing, but - * not yet opened for reading. Because we can't map - * swapfiles back to StoreEntrys, we don't know the state - * of the entry using that file. */ - /* We'll assume the existing entry is valid, probably because - * were in a slow rebuild and the the swap file number got taken - * and the validation procedure hasn't run. */ - assert(rb->flags.need_to_validate); - rb->counts.clashcount++; - continue; - } else if (e && !disk_entry_newer) { - /* key already exists, current entry is newer */ - /* keep old, ignore new */ - rb->counts.dupcount++; - continue; - } else if (e) { - /* key already exists, this swapfile not being used */ - /* junk old, load new */ - storeExpireNow(e); - storeReleaseRequest(e); - if (e->swap_filen > -1) { - commonUfsDirReplRemove(e); - /* Make sure we don't actually unlink the file */ - commonUfsDirMapBitReset(SD, e->swap_filen); - e->swap_filen = -1; - e->swap_dirn = -1; - } - storeRelease(e); - rb->counts.dupcount++; - } else { - /* URL doesnt exist, swapfile not in use */ - /* load new */ - (void) 0; - } - /* update store_swap_size */ - rb->counts.objcount++; - e = commonUfsDirAddDiskRestore(SD, s.key, - s.swap_filen, - s.swap_file_sz, - s.expires, - s.timestamp, - s.lastref, - s.lastmod, - s.refcount, - s.flags, - (int) rb->flags.clean); - storeDirSwapLog(e, SWAP_LOG_ADD); - } - eventAdd("storeRebuild", commonUfsDirRebuildFromSwapLog, rb, 0.0, 1); -} - -int -commonUfsDirGetNextFile(RebuildState * rb, sfileno * filn_p, int *size) -{ - SwapDir *SD = rb->sd; - squidufsinfo_t *ioinfo = (squidufsinfo_t *) SD->fsdata; - int fd = -1; - int used = 0; - int dirs_opened = 0; - debug(47, 3) ("commonUfsDirGetNextFile: flag=%d, %d: /%02X/%02X\n", - rb->flags.init, - rb->sd->index, - rb->curlvl1, - rb->curlvl2); - if (rb->done) - return -2; - while (fd < 0 && rb->done == 0) { - fd = -1; - if (0 == rb->flags.init) { /* initialize, open first file */ - rb->done = 0; - rb->curlvl1 = 0; - rb->curlvl2 = 0; - rb->in_dir = 0; - rb->flags.init = 1; - assert(Config.cacheSwap.n_configured > 0); - } - if (0 == rb->in_dir) { /* we need to read in a new directory */ - snprintf(rb->fullpath, SQUID_MAXPATHLEN, "%s/%02X/%02X", - rb->sd->path, - rb->curlvl1, rb->curlvl2); - if (dirs_opened) - return -1; - rb->td = opendir(rb->fullpath); - dirs_opened++; - if (rb->td == NULL) { - debug(47, 1) ("commonUfsDirGetNextFile: opendir: %s: %s\n", - rb->fullpath, xstrerror()); - } else { - rb->entry = readdir(rb->td); /* skip . and .. */ - rb->entry = readdir(rb->td); - if (rb->entry == NULL && errno == ENOENT) - debug(47, 1) ("commonUfsDirGetNextFile: directory does not exist!.\n"); - debug(47, 3) ("commonUfsDirGetNextFile: Directory %s\n", rb->fullpath); - } - } - if (rb->td != NULL && (rb->entry = readdir(rb->td)) != NULL) { - rb->in_dir++; - if (sscanf(rb->entry->d_name, "%x", &rb->fn) != 1) { - debug(47, 3) ("commonUfsDirGetNextFile: invalid %s\n", - rb->entry->d_name); - continue; - } - if (!commonUfsFilenoBelongsHere(rb->fn, rb->sd->index, rb->curlvl1, rb->curlvl2)) { - debug(47, 3) ("commonUfsDirGetNextFile: %08X does not belong in %d/%d/%d\n", - rb->fn, rb->sd->index, rb->curlvl1, rb->curlvl2); - continue; - } - used = commonUfsDirMapBitTest(SD, rb->fn); - if (used) { - debug(47, 3) ("commonUfsDirGetNextFile: Locked, continuing with next.\n"); - continue; - } - snprintf(rb->fullfilename, SQUID_MAXPATHLEN, "%s/%s", - rb->fullpath, rb->entry->d_name); - debug(47, 3) ("commonUfsDirGetNextFile: Opening %s\n", rb->fullfilename); - fd = file_open(rb->fullfilename, O_RDONLY | O_BINARY); - if (fd < 0) - debug(47, 1) ("commonUfsDirGetNextFile: %s: %s\n", rb->fullfilename, xstrerror()); - else - store_open_disk_fd++; - continue; - } - if (rb->td != NULL) - closedir(rb->td); - rb->td = NULL; - rb->in_dir = 0; - if (++rb->curlvl2 < ioinfo->l2) - continue; - rb->curlvl2 = 0; - if (++rb->curlvl1 < ioinfo->l1) - continue; - rb->curlvl1 = 0; - rb->done = 1; - } - *filn_p = rb->fn; - return fd; -} - -/* Add a new object to the cache with empty memory copy and pointer to disk - * use to rebuild store from disk. */ -StoreEntry * -commonUfsDirAddDiskRestore(SwapDir * SD, const cache_key * key, - sfileno file_number, - size_t swap_file_sz, - time_t expires, - time_t timestamp, - time_t lastref, - time_t lastmod, - u_int32_t refcount, - u_int16_t flags, - int clean) -{ - StoreEntry *e = NULL; - debug(47, 5) ("commonUfsAddDiskRestore: %s, fileno=%08X\n", storeKeyText(key), file_number); - /* if you call this you'd better be sure file_number is not - * already in use! */ - e = new_StoreEntry(STORE_ENTRY_WITHOUT_MEMOBJ, NULL, NULL); - e->store_status = STORE_OK; - storeSetMemStatus(e, NOT_IN_MEMORY); - e->swap_status = SWAPOUT_DONE; - e->swap_filen = file_number; - e->swap_dirn = SD->index; - e->swap_file_sz = swap_file_sz; - e->lock_count = 0; - e->lastref = lastref; - e->timestamp = timestamp; - e->expires = expires; - e->lastmod = lastmod; - e->refcount = refcount; - e->flags = flags; - EBIT_SET(e->flags, ENTRY_CACHABLE); - EBIT_CLR(e->flags, RELEASE_REQUEST); - EBIT_CLR(e->flags, KEY_PRIVATE); - e->ping_status = PING_NONE; - EBIT_CLR(e->flags, ENTRY_VALIDATED); - commonUfsDirMapBitSet(SD, e->swap_filen); - storeHashInsert(e, key); /* do it after we clear KEY_PRIVATE */ - commonUfsDirReplAdd(SD, e); - return e; -} - -CBDATA_TYPE(RebuildState); - -void -commonUfsDirRebuild(SwapDir * sd) -{ - RebuildState *rb; - int clean = 0; - int zero = 0; - FILE *fp; - EVH *func = NULL; - CBDATA_INIT_TYPE(RebuildState); - rb = cbdataAlloc(RebuildState); - rb->sd = sd; - rb->speed = opt_foreground_rebuild ? 1 << 30 : 50; - /* - * If the swap.state file exists in the cache_dir, then - * we'll use commonUfsDirRebuildFromSwapLog(), otherwise we'll - * use commonUfsDirRebuildFromDirectory() to open up each file - * and suck in the meta data. - */ - fp = commonUfsDirOpenTmpSwapLog(sd, &clean, &zero); - if (fp == NULL || zero) { - if (fp != NULL) - fclose(fp); - func = commonUfsDirRebuildFromDirectory; - } else { - func = commonUfsDirRebuildFromSwapLog; - rb->log = fp; - rb->flags.clean = (unsigned int) clean; - } - if (!clean) - rb->flags.need_to_validate = 1; - debug(47, 1) ("Rebuilding storage in %s (%s)\n", - sd->path, clean ? "CLEAN" : "DIRTY"); - store_dirs_rebuilding++; - eventAdd("storeRebuild", func, rb, 0.0, 1); -} - -void -commonUfsDirCloseTmpSwapLog(SwapDir * sd) -{ - squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata; - char *swaplog_path = xstrdup(commonUfsDirSwapLogFile(sd, NULL)); - char *new_path = xstrdup(commonUfsDirSwapLogFile(sd, ".new")); - int fd; - file_close(ioinfo->swaplog_fd); -#if defined (_SQUID_OS2_) || defined (_SQUID_CYGWIN_) || defined(_SQUID_MSWIN_) - if (unlink(swaplog_path) < 0) { - debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror()); - fatal("commonUfsDirCloseTmpSwapLog: unlink failed"); - } -#endif - if (xrename(new_path, swaplog_path) < 0) { - fatal("commonUfsDirCloseTmpSwapLog: rename failed"); - } - fd = file_open(swaplog_path, O_WRONLY | O_CREAT | O_BINARY); - if (fd < 0) { - debug(50, 1) ("%s: %s\n", swaplog_path, xstrerror()); - fatal("commonUfsDirCloseTmpSwapLog: Failed to open swap log."); - } - safe_free(swaplog_path); - safe_free(new_path); - ioinfo->swaplog_fd = fd; - debug(47, 3) ("Cache Dir #%d log opened on FD %d\n", sd->index, fd); -} - -FILE * -commonUfsDirOpenTmpSwapLog(SwapDir * sd, int *clean_flag, int *zero_flag) -{ - squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata; - char *swaplog_path = xstrdup(commonUfsDirSwapLogFile(sd, NULL)); - char *clean_path = xstrdup(commonUfsDirSwapLogFile(sd, ".last-clean")); - char *new_path = xstrdup(commonUfsDirSwapLogFile(sd, ".new")); - struct stat log_sb; - struct stat clean_sb; - FILE *fp; - int fd; - if (stat(swaplog_path, &log_sb) < 0) { - debug(47, 1) ("Cache Dir #%d: No log file\n", sd->index); - safe_free(swaplog_path); - safe_free(clean_path); - safe_free(new_path); - return NULL; - } - *zero_flag = log_sb.st_size == 0 ? 1 : 0; - /* close the existing write-only FD */ - if (ioinfo->swaplog_fd >= 0) - file_close(ioinfo->swaplog_fd); - /* open a write-only FD for the new log */ - fd = file_open(new_path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY); - if (fd < 0) { - debug(50, 1) ("%s: %s\n", new_path, xstrerror()); - fatal("storeDirOpenTmpSwapLog: Failed to open swap log."); - } - ioinfo->swaplog_fd = fd; - /* open a read-only stream of the old log */ - fp = fopen(swaplog_path, "rb"); - if (fp == NULL) { - debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror()); - fatal("Failed to open swap log for reading"); - } - memset(&clean_sb, '\0', sizeof(struct stat)); - if (stat(clean_path, &clean_sb) < 0) - *clean_flag = 0; - else if (clean_sb.st_mtime < log_sb.st_mtime) - *clean_flag = 0; - else - *clean_flag = 1; - safeunlink(clean_path, 1); - safe_free(swaplog_path); - safe_free(clean_path); - safe_free(new_path); - return fp; -} - -struct _clean_state { - char *cur; - char *new; - char *cln; - char *outbuf; - off_t outbuf_offset; - int fd; - RemovalPolicyWalker *walker; -}; - -#define CLEAN_BUF_SZ 16384 - -/* - * Begin the process to write clean cache state. For AUFS this means - * opening some log files and allocating write buffers. Return 0 if - * we succeed, and assign the 'func' and 'data' return pointers. - */ -int -commonUfsDirWriteCleanStart(SwapDir * sd) -{ - struct _clean_state *state = xcalloc(1, sizeof(*state)); -#if HAVE_FCHMOD - struct stat sb; -#endif - sd->log.clean.write = NULL; - sd->log.clean.state = NULL; - state->new = xstrdup(commonUfsDirSwapLogFile(sd, ".clean")); - state->fd = file_open(state->new, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY); - if (state->fd < 0) { - xfree(state->new); - xfree(state); - return -1; - } - state->cur = xstrdup(commonUfsDirSwapLogFile(sd, NULL)); - state->cln = xstrdup(commonUfsDirSwapLogFile(sd, ".last-clean")); - state->outbuf = xcalloc(CLEAN_BUF_SZ, 1); - state->outbuf_offset = 0; - state->walker = sd->repl->WalkInit(sd->repl); - unlink(state->cln); - debug(47, 3) ("storeDirWriteCleanLogs: opened %s, FD %d\n", - state->new, state->fd); -#if HAVE_FCHMOD - if (stat(state->cur, &sb) == 0) - fchmod(state->fd, sb.st_mode); -#endif - sd->log.clean.write = commonUfsDirWriteCleanEntry; - sd->log.clean.state = state; - return 0; -} - -/* - * Get the next entry that is a candidate for clean log writing - */ -const StoreEntry * -commonUfsDirCleanLogNextEntry(SwapDir * sd) -{ - const StoreEntry *entry = NULL; - struct _clean_state *state = sd->log.clean.state; - if (state->walker) - entry = state->walker->Next(state->walker); - return entry; -} - -/* - * "write" an entry to the clean log file. - */ -void -commonUfsDirWriteCleanEntry(SwapDir * sd, const StoreEntry * e) -{ - storeSwapLogData s; - static size_t ss = sizeof(storeSwapLogData); - struct _clean_state *state = sd->log.clean.state; - memset(&s, '\0', ss); - s.op = (char) SWAP_LOG_ADD; - s.swap_filen = e->swap_filen; - s.timestamp = e->timestamp; - s.lastref = e->lastref; - s.expires = e->expires; - s.lastmod = e->lastmod; - s.swap_file_sz = e->swap_file_sz; - s.refcount = e->refcount; - s.flags = e->flags; - xmemcpy(&s.key, e->hash.key, MD5_DIGEST_CHARS); - xmemcpy(state->outbuf + state->outbuf_offset, &s, ss); - state->outbuf_offset += ss; - /* buffered write */ - if (state->outbuf_offset + ss > CLEAN_BUF_SZ) { - if (FD_WRITE_METHOD(state->fd, state->outbuf, state->outbuf_offset) < 0) { - debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %s\n", - state->new, xstrerror()); - debug(50, 0) ("storeDirWriteCleanLogs: Current swap logfile not replaced.\n"); - file_close(state->fd); - state->fd = -1; - unlink(state->new); - safe_free(state); - sd->log.clean.state = NULL; - sd->log.clean.write = NULL; - return; - } - state->outbuf_offset = 0; - } -} - -void -commonUfsDirWriteCleanDone(SwapDir * sd) -{ - int fd; - struct _clean_state *state = sd->log.clean.state; - if (NULL == state) - return; - if (state->fd < 0) - return; - state->walker->Done(state->walker); - if (FD_WRITE_METHOD(state->fd, state->outbuf, state->outbuf_offset) < 0) { - debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %s\n", - state->new, xstrerror()); - debug(50, 0) ("storeDirWriteCleanLogs: Current swap logfile " - "not replaced.\n"); - file_close(state->fd); - state->fd = -1; - unlink(state->new); - } - safe_free(state->outbuf); - /* - * You can't rename open files on Microsoft "operating systems" - * so we have to close before renaming. - */ - commonUfsDirCloseSwapLog(sd); - /* save the fd value for a later test */ - fd = state->fd; - /* rename */ - if (state->fd >= 0) { -#if defined(_SQUID_OS2_) || defined (_SQUID_CYGWIN_) || defined(_SQUID_MSWIN_) - file_close(state->fd); - state->fd = -1; - if (unlink(state->cur) < 0) - debug(50, 0) ("storeDirWriteCleanLogs: unlinkd failed: %s, %s\n", - xstrerror(), state->cur); -#endif - xrename(state->new, state->cur); - } - /* touch a timestamp file if we're not still validating */ - if (store_dirs_rebuilding) - (void) 0; - else if (fd < 0) - (void) 0; - else - file_close(file_open(state->cln, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY)); - /* close */ - safe_free(state->cur); - safe_free(state->new); - safe_free(state->cln); - if (state->fd >= 0) - file_close(state->fd); - state->fd = -1; - safe_free(state); - sd->log.clean.state = NULL; - sd->log.clean.write = NULL; -} - -void -storeSwapLogDataFree(void *s) -{ - memFree(s, MEM_SWAP_LOG_DATA); -} - -void -commonUfsDirSwapLog(const SwapDir * sd, const StoreEntry * e, int op) -{ - squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata; - storeSwapLogData *s = memAllocate(MEM_SWAP_LOG_DATA); - s->op = (char) op; - s->swap_filen = e->swap_filen; - s->timestamp = e->timestamp; - s->lastref = e->lastref; - s->expires = e->expires; - s->lastmod = e->lastmod; - s->swap_file_sz = e->swap_file_sz; - s->refcount = e->refcount; - s->flags = e->flags; - xmemcpy(s->key, e->hash.key, MD5_DIGEST_CHARS); - file_write(ioinfo->swaplog_fd, - -1, - s, - sizeof(storeSwapLogData), - NULL, - NULL, - (FREE *) storeSwapLogDataFree); -} - -void -commonUfsDirNewfs(SwapDir * sd) -{ - debug(47, 3) ("Creating swap space in %s\n", sd->path); - commonUfsDirCreateDirectory(sd->path, 0); - commonUfsDirCreateSwapSubDirs(sd); -} - -static int -rev_int_sort(const void *A, const void *B) -{ - const int *i1 = A; - const int *i2 = B; - return *i2 - *i1; -} - -int -commonUfsDirClean(int swap_index) -{ - DIR *dp = NULL; - struct dirent *de = NULL; - LOCAL_ARRAY(char, p1, MAXPATHLEN + 1); - LOCAL_ARRAY(char, p2, MAXPATHLEN + 1); -#if USE_TRUNCATE - struct stat sb; -#endif - int files[20]; - int swapfileno; - int fn; /* same as swapfileno, but with dirn bits set */ - int n = 0; - int k = 0; - int N0, N1, N2; - int D0, D1, D2; - SwapDir *SD; - squidufsinfo_t *ioinfo; - N0 = n_dirs; - D0 = dir_index[swap_index % N0]; - SD = &Config.cacheSwap.swapDirs[D0]; - ioinfo = (squidufsinfo_t *) SD->fsdata; - N1 = ioinfo->l1; - D1 = (swap_index / N0) % N1; - N2 = ioinfo->l2; - D2 = ((swap_index / N0) / N1) % N2; - snprintf(p1, SQUID_MAXPATHLEN, "%s/%02X/%02X", - Config.cacheSwap.swapDirs[D0].path, D1, D2); - debug(36, 3) ("storeDirClean: Cleaning directory %s\n", p1); - dp = opendir(p1); - if (dp == NULL) { - if (errno == ENOENT) { - debug(36, 0) ("storeDirClean: WARNING: Creating %s\n", p1); -#ifdef _SQUID_MSWIN_ - if (mkdir(p1) == 0) -#else - if (mkdir(p1, 0777) == 0) -#endif - return 0; - } - debug(50, 0) ("storeDirClean: %s: %s\n", p1, xstrerror()); - safeunlink(p1, 1); - return 0; - } - while ((de = readdir(dp)) != NULL && k < 20) { - if (sscanf(de->d_name, "%X", &swapfileno) != 1) - continue; - fn = swapfileno; /* XXX should remove this cruft ! */ - if (commonUfsDirValidFileno(SD, fn, 1)) - if (commonUfsDirMapBitTest(SD, fn)) - if (commonUfsFilenoBelongsHere(fn, D0, D1, D2)) - continue; -#if USE_TRUNCATE - if (!stat(de->d_name, &sb)) - if (sb.st_size == 0) - continue; -#endif - files[k++] = swapfileno; - } - closedir(dp); - if (k == 0) - return 0; - qsort(files, k, sizeof(int), rev_int_sort); - if (k > 10) - k = 10; - for (n = 0; n < k; n++) { - debug(36, 3) ("storeDirClean: Cleaning file %08X\n", files[n]); - snprintf(p2, MAXPATHLEN + 1, "%s/%08X", p1, files[n]); -#if USE_TRUNCATE - truncate(p2, 0); -#else - safeunlink(p2, 0); -#endif - statCounter.swap.files_cleaned++; - } - debug(36, 3) ("Cleaned %d unused files from %s\n", k, p1); - return k; -} - -void -commonUfsDirCleanEvent(void *unused) -{ - static int swap_index = 0; - int i; - int j = 0; - int n = 0; - /* - * Assert that there are AUFS cache_dirs configured, otherwise - * we should never be called. - */ - assert(n_dirs); - if (NULL == dir_index) { - SwapDir *sd; - squidufsinfo_t *ioinfo; - /* - * Initialize the little array that translates AUFS cache_dir - * number into the Config.cacheSwap.swapDirs array index. - */ - dir_index = xcalloc(n_dirs, sizeof(*dir_index)); - for (i = 0, n = 0; i < Config.cacheSwap.n_configured; i++) { - sd = &Config.cacheSwap.swapDirs[i]; - if (!commonUfsDirIs(sd)) - continue; - dir_index[n++] = i; - ioinfo = (squidufsinfo_t *) sd->fsdata; - j += (ioinfo->l1 * ioinfo->l2); - } - assert(n == n_dirs); - /* - * Start the commonUfsDirClean() swap_index with a random - * value. j equals the total number of AUFS level 2 - * swap directories - */ - swap_index = (int) (squid_random() % j); - } - if (0 == store_dirs_rebuilding) { - n = commonUfsDirClean(swap_index); - swap_index++; - } - eventAdd("storeDirClean", commonUfsDirCleanEvent, NULL, - 15.0 * exp(-0.25 * n), 1); -} - -int -commonUfsDirIs(SwapDir * sd) -{ - if (strncmp(sd->type, "aufs", 4) == 0) - return 1; - if (strncmp(sd->type, "diskd", 5) == 0) - return 1; - if (strncmp(sd->type, "ufs", 3) == 0) - return 1; - return 0; -} - -/* - * Does swapfile number 'fn' belong in cachedir #F0, - * level1 dir #F1, level2 dir #F2? - */ -int -commonUfsFilenoBelongsHere(int fn, int F0, int F1, int F2) -{ - int D1, D2; - int L1, L2; - int filn = fn; - squidufsinfo_t *ioinfo; - assert(F0 < Config.cacheSwap.n_configured); - ioinfo = (squidufsinfo_t *) Config.cacheSwap.swapDirs[F0].fsdata; - L1 = ioinfo->l1; - L2 = ioinfo->l2; - D1 = ((filn / L2) / L2) % L1; - if (F1 != D1) - return 0; - D2 = (filn / L2) % L2; - if (F2 != D2) - return 0; - return 1; -} - -int -commonUfsDirValidFileno(SwapDir * SD, sfileno filn, int flag) -{ - squidufsinfo_t *ioinfo = (squidufsinfo_t *) SD->fsdata; - if (filn < 0) - return 0; - /* - * If flag is set it means out-of-range file number should - * be considered invalid. - */ - if (flag) - if (filn > ioinfo->map->max_n_files) - return 0; - return 1; -} - -void -commonUfsDirMaintain(SwapDir * SD) -{ - StoreEntry *e = NULL; - int removed = 0; - int max_scan; - int max_remove; - double f; - RemovalPurgeWalker *walker; - /* We can't delete objects while rebuilding swap */ - if (store_dirs_rebuilding) { - return; - } else { - f = (double) (SD->cur_size - SD->low_size) / (SD->max_size - SD->low_size); - f = f < 0.0 ? 0.0 : f > 1.0 ? 1.0 : f; - max_scan = (int) (f * 400.0 + 100.0); - max_remove = (int) (f * 70.0 + 10.0); - /* - * This is kinda cheap, but so we need this priority hack? - */ - } - debug(47, 3) ("storeMaintainSwapSpace: f=%f, max_scan=%d, max_remove=%d\n", - f, max_scan, max_remove); - walker = SD->repl->PurgeInit(SD->repl, max_scan); - while (1) { - if (SD->cur_size < SD->low_size) - break; - if (removed >= max_remove) - break; - e = walker->Next(walker); - if (!e) - break; /* no more objects */ - removed++; - storeRelease(e); - } - walker->Done(walker); - debug(47, (removed ? 2 : 3)) ("commonUfsDirMaintain: %s removed %d/%d f=%.03f max_scan=%d\n", - SD->path, removed, max_remove, f, max_scan); -} - -#if 0 -/* - * commonUfsDirCheckObj - * - * This routine is called by storeDirSelectSwapDir to see if the given - * object is able to be stored on this filesystem. AUFS filesystems will - * happily store anything as long as the LRU time isn't too small. - */ -int -commonUfsDirCheckObj(SwapDir * SD, const StoreEntry * e) -{ - int loadav; - int ql; - -#if OLD_UNUSED_CODE - if (commonUfsDirExpiredReferenceAge(SD) < 300) { - debug(47, 3) ("commonUfsDirCheckObj: NO: LRU Age = %d\n", - commonUfsDirExpiredReferenceAge(SD)); - /* store_check_cachable_hist.no.lru_age_too_low++; */ - return -1; - } -#endif - ql = aioQueueSize(); - if (ql == 0) - loadav = 0; - loadav = ql * 1000 / MAGIC1; - debug(47, 9) ("commonUfsDirCheckObj: load=%d\n", loadav); - return loadav; -} -#endif -/* - * commonUfsDirRefObj - * - * This routine is called whenever an object is referenced, so we can - * maintain replacement information within the storage fs. - */ -void -commonUfsDirRefObj(SwapDir * SD, StoreEntry * e) -{ - debug(47, 3) ("commonUfsDirRefObj: referencing %p %d/%d\n", e, e->swap_dirn, - e->swap_filen); - if (SD->repl->Referenced) - SD->repl->Referenced(SD->repl, e, &e->repl); -} - -/* - * commonUfsDirUnrefObj - * This routine is called whenever the last reference to an object is - * removed, to maintain replacement information within the storage fs. - */ -void -commonUfsDirUnrefObj(SwapDir * SD, StoreEntry * e) -{ - debug(47, 3) ("commonUfsDirUnrefObj: referencing %p %d/%d\n", e, e->swap_dirn, - e->swap_filen); - if (SD->repl->Dereferenced) - SD->repl->Dereferenced(SD->repl, e, &e->repl); -} - -/* - * commonUfsDirUnlinkFile - * - * This routine unlinks a file and pulls it out of the bitmap. - * It used to be in commonUfsUnlink(), however an interface change - * forced this bit of code here. Eeek. - */ -void -commonUfsDirUnlinkFile(SwapDir * SD, sfileno f) -{ - squidufsinfo_t *ioinfo = SD->fsdata; - debug(79, 3) ("commonUfsDirUnlinkFile: unlinking fileno %08X\n", f); - /* commonUfsDirMapBitReset(SD, f); */ - assert(ioinfo->io.storeDirUnlinkFile); - ioinfo->io.storeDirUnlinkFile(commonUfsDirFullPath(SD, f, NULL)); -} - - -/* - * Add and remove the given StoreEntry from the replacement policy in - * use. - */ - -void -commonUfsDirReplAdd(SwapDir * SD, StoreEntry * e) -{ - debug(47, 4) ("commonUfsDirReplAdd: added node %p to dir %d\n", e, - SD->index); - SD->repl->Add(SD->repl, e, &e->repl); -} - - -void -commonUfsDirReplRemove(StoreEntry * e) -{ - SwapDir *SD; - if (e->swap_dirn < 0) - return; - SD = INDEXSD(e->swap_dirn); - debug(47, 4) ("commonUfsDirReplRemove: remove node %p from dir %d\n", e, - SD->index); - SD->repl->Remove(SD->repl, e, &e->repl); -} - - - -/* ========== LOCAL FUNCTIONS ABOVE, GLOBAL FUNCTIONS BELOW ========== */ - -void -commonUfsDirStats(SwapDir * SD, StoreEntry * sentry) -{ - squidufsinfo_t *ioinfo = SD->fsdata; - int totl_kb = 0; - int free_kb = 0; - int totl_in = 0; - int free_in = 0; - int x; - storeAppendPrintf(sentry, "First level subdirectories: %d\n", ioinfo->l1); - storeAppendPrintf(sentry, "Second level subdirectories: %d\n", ioinfo->l2); - storeAppendPrintf(sentry, "Maximum Size: %d KB\n", SD->max_size); - storeAppendPrintf(sentry, "Current Size: %d KB\n", SD->cur_size); - storeAppendPrintf(sentry, "Percent Used: %0.2f%%\n", - 100.0 * SD->cur_size / SD->max_size); - storeAppendPrintf(sentry, "Filemap bits in use: %d of %d (%d%%)\n", - ioinfo->map->n_files_in_map, ioinfo->map->max_n_files, - percent(ioinfo->map->n_files_in_map, ioinfo->map->max_n_files)); - x = storeDirGetUFSStats(SD->path, &totl_kb, &free_kb, &totl_in, &free_in); - if (0 == x) { - storeAppendPrintf(sentry, "Filesystem Space in use: %d/%d KB (%d%%)\n", - totl_kb - free_kb, - totl_kb, - percent(totl_kb - free_kb, totl_kb)); - storeAppendPrintf(sentry, "Filesystem Inodes in use: %d/%d (%d%%)\n", - totl_in - free_in, - totl_in, - percent(totl_in - free_in, totl_in)); - } - storeAppendPrintf(sentry, "Flags:"); - if (SD->flags.selected) - storeAppendPrintf(sentry, " SELECTED"); - if (SD->flags.read_only) - storeAppendPrintf(sentry, " READ-ONLY"); - storeAppendPrintf(sentry, "\n"); -} - -#if 0 -static struct cache_dir_option options[] = -{ -#if NOT_YET_DONE - {"L1", commonUfsDirParseL1, commonUfsDirDumpL1}, - {"L2", commonUfsDirParseL2, commonUfsDirDumpL2}, -#endif - {NULL, NULL} -}; - -/* - * commonUfsDirReconfigure - * - * This routine is called when the given swapdir needs reconfiguring - */ -static void -commonUfsDirReconfigure(SwapDir * sd, int index, char *path) -{ - int i; - int size; - int l1; - int l2; - - i = GetInteger(); - size = i << 10; /* Mbytes to kbytes */ - if (size <= 0) - fatal("commonUfsDirReconfigure: invalid size value"); - i = GetInteger(); - l1 = i; - if (l1 <= 0) - fatal("commonUfsDirReconfigure: invalid level 1 directories value"); - i = GetInteger(); - l2 = i; - if (l2 <= 0) - fatal("commonUfsDirReconfigure: invalid level 2 directories value"); - - /* just reconfigure it */ - if (size == sd->max_size) - debug(3, 1) ("Cache dir '%s' size remains unchanged at %d KB\n", - path, size); - else - debug(3, 1) ("Cache dir '%s' size changed to %d KB\n", - path, size); - sd->max_size = size; - - parse_cachedir_options(sd, options, 0); - - return; -} - -#endif - -void -commonUfsDirDump(StoreEntry * entry, SwapDir * s) -{ - squidufsinfo_t *ioinfo = (squidufsinfo_t *) s->fsdata; - storeAppendPrintf(entry, " %d %d %d", - s->max_size >> 10, - ioinfo->l1, - ioinfo->l2); -} - -/* - * Only "free" the filesystem specific stuff here - */ -void -commonUfsDirFree(SwapDir * s) -{ - squidufsinfo_t *ioinfo = (squidufsinfo_t *) s->fsdata; - if (ioinfo->swaplog_fd > -1) { - file_close(ioinfo->swaplog_fd); - ioinfo->swaplog_fd = -1; - } - filemapFreeMemory(ioinfo->map); - xfree(ioinfo); - s->fsdata = NULL; /* Will aid debugging... */ -} - - -char * -commonUfsDirFullPath(SwapDir * SD, sfileno filn, char *fullpath) -{ - LOCAL_ARRAY(char, fullfilename, SQUID_MAXPATHLEN); - squidufsinfo_t *ioinfo = (squidufsinfo_t *) SD->fsdata; - int L1 = ioinfo->l1; - int L2 = ioinfo->l2; - if (!fullpath) - fullpath = fullfilename; - fullpath[0] = '\0'; - snprintf(fullpath, SQUID_MAXPATHLEN, "%s/%02X/%02X/%08X", - SD->path, - ((filn / L2) / L2) % L1, - (filn / L2) % L2, - filn); - return fullpath; -} - -/* - * commonUfsCleanupDoubleCheck - * - * This is called by storeCleanup() if -S was given on the command line. - */ -int -commonUfsCleanupDoubleCheck(SwapDir * sd, StoreEntry * e) -{ - struct stat sb; - if (stat(commonUfsDirFullPath(sd, e->swap_filen, NULL), &sb) < 0) { - debug(47, 0) ("commonUfsCleanupDoubleCheck: MISSING SWAP FILE\n"); - debug(47, 0) ("commonUfsCleanupDoubleCheck: FILENO %08X\n", e->swap_filen); - debug(47, 0) ("commonUfsCleanupDoubleCheck: PATH %s\n", - commonUfsDirFullPath(sd, e->swap_filen, NULL)); - storeEntryDump(e, 0); - return -1; - } - if (e->swap_file_sz != sb.st_size) { - debug(47, 0) ("commonUfsCleanupDoubleCheck: SIZE MISMATCH\n"); - debug(47, 0) ("commonUfsCleanupDoubleCheck: FILENO %08X\n", e->swap_filen); - debug(47, 0) ("commonUfsCleanupDoubleCheck: PATH %s\n", - commonUfsDirFullPath(sd, e->swap_filen, NULL)); - debug(47, 0) ("commonUfsCleanupDoubleCheck: ENTRY SIZE: %ld, FILE SIZE: %ld\n", - (long int) e->swap_file_sz, (long int) sb.st_size); - storeEntryDump(e, 0); - return -1; - } - return 0; -} - -#if 0 -/* - * commonUfsDirParse * - * Called when a *new* fs is being setup. - */ -static void -commonUfsDirParse(SwapDir * sd, int index, char *path) -{ - int i; - int size; - int l1; - int l2; - squidufsinfo_t *ioinfo; - - i = GetInteger(); - size = i << 10; /* Mbytes to kbytes */ - if (size <= 0) - fatal("commonUfsDirParse: invalid size value"); - i = GetInteger(); - l1 = i; - if (l1 <= 0) - fatal("commonUfsDirParse: invalid level 1 directories value"); - i = GetInteger(); - l2 = i; - if (l2 <= 0) - fatal("commonUfsDirParse: invalid level 2 directories value"); - - ioinfo = xmalloc(sizeof(squidufsinfo_t)); - if (ioinfo == NULL) - fatal("commonUfsDirParse: couldn't xmalloc() squidufsinfo_t!\n"); - - sd->index = index; - sd->path = xstrdup(path); - sd->max_size = size; - sd->fsdata = ioinfo; - ioinfo->l1 = l1; - ioinfo->l2 = l2; - ioinfo->swaplog_fd = -1; - ioinfo->map = NULL; /* Debugging purposes */ - ioinfo->suggest = 0; - sd->init = commonUfsDirInit; - sd->newfs = commonUfsDirNewfs; - sd->dump = commonUfsDirDump; - sd->freefs = commonUfsDirFree; - sd->dblcheck = commonUfsCleanupDoubleCheck; - sd->statfs = commonUfsDirStats; - sd->maintainfs = commonUfsDirMaintain; - sd->checkobj = commonUfsDirCheckObj; - sd->refobj = commonUfsDirRefObj; - sd->unrefobj = commonUfsDirUnrefObj; - sd->callback = aioCheckCallbacks; - sd->sync = aioSync; - sd->obj.create = commonUfsCreate; - sd->obj.open = commonUfsOpen; - sd->obj.close = commonUfsClose; - sd->obj.read = commonUfsRead; - sd->obj.write = commonUfsWrite; - sd->obj.unlink = commonUfsUnlink; - sd->log.open = commonUfsDirOpenSwapLog; - sd->log.close = commonUfsDirCloseSwapLog; - sd->log.write = commonUfsDirSwapLog; - sd->log.clean.start = commonUfsDirWriteCleanStart; - sd->log.clean.nextentry = commonUfsDirCleanLogNextEntry; - sd->log.clean.done = commonUfsDirWriteCleanDone; - - parse_cachedir_options(sd, options, 0); - - /* Initialise replacement policy stuff */ - sd->repl = createRemovalPolicy(Config.replPolicy); -} - -/* - * Initial setup / end destruction - */ -static void -commonUfsDirDone(void) -{ - aioDone(); - memPoolDestroy(&squidaio_state_pool); - memPoolDestroy(&aufs_qread_pool); - memPoolDestroy(&aufs_qwrite_pool); - asyncufs_initialised = 0; -} - -void -storeFsSetup_aufs(storefs_entry_t * storefs) -{ - assert(!asyncufs_initialised); - storefs->parsefunc = commonUfsDirParse; - storefs->reconfigurefunc = commonUfsDirReconfigure; - storefs->donefunc = commonUfsDirDone; - squidaio_state_pool = memPoolCreate("AUFS IO State data", sizeof(squidaiostate_t)); - aufs_qread_pool = memPoolCreate("AUFS Queued read data", - sizeof(queued_read)); - aufs_qwrite_pool = memPoolCreate("AUFS Queued write data", - sizeof(queued_write)); - - asyncufs_initialised = 1; - aioInit(); -} -#endif --- /dev/null Wed Feb 14 01:07:22 2007 +++ squid/src/ufscommon.cc Wed Feb 14 01:07:42 2007 @@ -0,0 +1,1632 @@ +/* + * $Id: ufscommon.cc,v 1.1.2.1 2002/10/12 12:21:42 rbcollins Exp $ + * + * DEBUG: section 47 Store Directory Routines + * AUTHOR: Duane Wessels + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "ufscommon.h" +#include "Store.h" + +typedef struct _RebuildState RebuildState; +struct _RebuildState { + SwapDir *sd; + int n_read; + FILE *log; + int speed; + int curlvl1; + int curlvl2; + struct { + unsigned int need_to_validate:1; + unsigned int clean:1; + unsigned int init:1; + } flags; + int done; + int in_dir; + int fn; + struct dirent *entry; + DIR *td; + char fullpath[SQUID_MAXPATHLEN]; + char fullfilename[SQUID_MAXPATHLEN]; + struct _store_rebuild_data counts; +}; + +static int n_dirs = 0; +static int *dir_index = NULL; +#if 0 +MemPool *squidaio_state_pool = NULL; +MemPool *aufs_qread_pool = NULL; +MemPool *aufs_qwrite_pool = NULL; +static int asyncufs_initialised = 0; +#endif +static int commonUfsFilenoBelongsHere(int fn, int F0, int F1, int F2); +static char *commonUfsDirSwapSubDir(SwapDir *, int subdirn); +static int commonUfsDirCreateDirectory(const char *path, int); +static int commonUfsDirVerifyCacheDirs(SwapDir * sd); +static int commonUfsDirVerifyDirectory(const char *path); +static void commonUfsDirCreateSwapSubDirs(SwapDir *); +static int commonUfsDirMapBitTest(SwapDir * SD, sfileno filn); +static char *commonUfsDirSwapLogFile(SwapDir *, const char *); +static EVH commonUfsDirRebuildFromDirectory; +static EVH commonUfsDirRebuildFromSwapLog; +static int commonUfsDirGetNextFile(RebuildState *, sfileno *, int *size); +static StoreEntry *commonUfsDirAddDiskRestore(SwapDir * SD, const cache_key * key, + sfileno file_number, + size_t swap_file_sz, + time_t expires, + time_t timestamp, + time_t lastref, + time_t lastmod, + u_int32_t refcount, + u_int16_t flags, + int clean); +static void commonUfsDirRebuild(SwapDir * sd); +static void commonUfsDirCloseTmpSwapLog(SwapDir * sd); +static FILE *commonUfsDirOpenTmpSwapLog(SwapDir *, int *, int *); +#if 0 +static STLOGOPEN commonUfsDirOpenSwapLog; +static STINIT commonUfsDirInit; +static STFREE commonUfsDirFree; +static STLOGCLEANSTART commonUfsDirWriteCleanStart; +static STLOGCLEANNEXTENTRY commonUfsDirCleanLogNextEntry; +#endif +static STLOGCLEANWRITE commonUfsDirWriteCleanEntry; +#if 0 +static STLOGCLEANDONE commonUfsDirWriteCleanDone; +static STLOGCLOSE commonUfsDirCloseSwapLog; +static STLOGWRITE commonUfsDirSwapLog; +static STNEWFS commonUfsDirNewfs; +static STCHECKOBJ commonUfsDirCheckObj; +#endif +static QS rev_int_sort; +static void commonUfsDirMapBitSet(SwapDir * SD, sfileno filn); +static EVH commonUfsDirCleanEvent; +static int commonUfsDirClean(int swap_index); +static int commonUfsDirIs(SwapDir * sd); +#if 0 +static int commonUfsCleanupDoubleCheck(SwapDir *, StoreEntry *); +#endif +static void commonUfsDirInitBitmap(SwapDir *); +static int commonUfsDirValidFileno(SwapDir * SD, sfileno filn, int flag); +static int commonUfsDirMapBitTest(SwapDir * SD, sfileno filn); +void commonUfsDirMapBitReset(SwapDir * SD, sfileno filn); + +#if 0 + +/* The MAIN externally visible function */ +STSETUP storeFsSetup_aufs; + +/* + * These functions were ripped straight out of the heart of store_dir.c. + * They assume that the given filenum is on a asyncufs partiton, which may or + * may not be true.. + * XXX this evilness should be tidied up at a later date! + */ + +#endif +int +commonUfsDirMapBitTest(SwapDir * SD, sfileno filn) +{ + squidufsinfo_t *ioinfo; + ioinfo = (squidufsinfo_t *) SD->fsdata; + return file_map_bit_test(ioinfo->map, filn); +} + +void +commonUfsDirMapBitSet(SwapDir * SD, sfileno filn) +{ + squidufsinfo_t *ioinfo; + ioinfo = (squidufsinfo_t *) SD->fsdata; + file_map_bit_set(ioinfo->map, filn); +} + +void +commonUfsDirMapBitReset(SwapDir * SD, sfileno filn) +{ + squidufsinfo_t *ioinfo; + ioinfo = (squidufsinfo_t *) SD->fsdata; + /* + * We have to test the bit before calling file_map_bit_reset. + * file_map_bit_reset doesn't do bounds checking. It assumes + * filn is a valid file number, but it might not be because + * the map is dynamic in size. Also clearing an already clear + * bit puts the map counter of-of-whack. + */ + if (file_map_bit_test(ioinfo->map, filn)) + file_map_bit_reset(ioinfo->map, filn); +} + +int +commonUfsDirMapBitAllocate(SwapDir * SD) +{ + squidufsinfo_t *ioinfo = (squidufsinfo_t *) SD->fsdata; + int fn; + fn = file_map_allocate(ioinfo->map, ioinfo->suggest); + file_map_bit_set(ioinfo->map, fn); + ioinfo->suggest = fn + 1; + return fn; +} + +/* + * Initialise the asyncufs bitmap + * + * If there already is a bitmap, and the numobjects is larger than currently + * configured, we allocate a new bitmap and 'grow' the old one into it. + */ +void +commonUfsDirInitBitmap(SwapDir * sd) +{ + squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata; + + if (ioinfo->map == NULL) { + /* First time */ + ioinfo->map = file_map_create(); + } else if (ioinfo->map->max_n_files) { + /* it grew, need to expand */ + /* XXX We don't need it anymore .. */ + } + /* else it shrunk, and we leave the old one in place */ +} + +char * +commonUfsDirSwapSubDir(SwapDir * sd, int subdirn) +{ + squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata; + + LOCAL_ARRAY(char, fullfilename, SQUID_MAXPATHLEN); + assert(0 <= subdirn && subdirn < ioinfo->l1); + snprintf(fullfilename, SQUID_MAXPATHLEN, "%s/%02X", sd->path, subdirn); + return fullfilename; +} + +int +commonUfsDirCreateDirectory(const char *path, int should_exist) +{ + int created = 0; + struct stat st; + getCurrentTime(); + if (0 == stat(path, &st)) { + if (S_ISDIR(st.st_mode)) { + debug(47, should_exist ? 3 : 1) ("%s exists\n", path); + } else { + fatalf("Swap directory %s is not a directory.", path); + } +#ifdef _SQUID_MSWIN_ + } else if (0 == mkdir(path)) { +#else + } else if (0 == mkdir(path, 0755)) { +#endif + debug(47, should_exist ? 1 : 3) ("%s created\n", path); + created = 1; + } else { + fatalf("Failed to make swap directory %s: %s", + path, xstrerror()); + } + return created; +} + +int +commonUfsDirVerifyDirectory(const char *path) +{ + struct stat sb; + if (stat(path, &sb) < 0) { + debug(47, 0) ("%s: %s\n", path, xstrerror()); + return -1; + } + if (S_ISDIR(sb.st_mode) == 0) { + debug(47, 0) ("%s is not a directory\n", path); + return -1; + } + return 0; +} + +/* + * This function is called by commonUfsDirInit(). If this returns < 0, + * then Squid exits, complains about swap directories not + * existing, and instructs the admin to run 'squid -z' + */ +int +commonUfsDirVerifyCacheDirs(SwapDir * sd) +{ + squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata; + int j; + const char *path = sd->path; + + if (commonUfsDirVerifyDirectory(path) < 0) + return -1; + for (j = 0; j < ioinfo->l1; j++) { + path = commonUfsDirSwapSubDir(sd, j); + if (commonUfsDirVerifyDirectory(path) < 0) + return -1; + } + return 0; +} + +void +commonUfsDirCreateSwapSubDirs(SwapDir * sd) +{ + squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata; + int i, k; + int should_exist; + LOCAL_ARRAY(char, name, MAXPATHLEN); + for (i = 0; i < ioinfo->l1; i++) { + snprintf(name, MAXPATHLEN, "%s/%02X", sd->path, i); + if (commonUfsDirCreateDirectory(name, 0)) + should_exist = 0; + else + should_exist = 1; + debug(47, 1) ("Making directories in %s\n", name); + for (k = 0; k < ioinfo->l2; k++) { + snprintf(name, MAXPATHLEN, "%s/%02X/%02X", sd->path, i, k); + commonUfsDirCreateDirectory(name, should_exist); + } + } +} + +char * +commonUfsDirSwapLogFile(SwapDir * sd, const char *ext) +{ + LOCAL_ARRAY(char, path, SQUID_MAXPATHLEN); + LOCAL_ARRAY(char, pathtmp, SQUID_MAXPATHLEN); + LOCAL_ARRAY(char, digit, 32); + char *pathtmp2; + if (Config.Log.swap) { + xstrncpy(pathtmp, sd->path, SQUID_MAXPATHLEN - 64); + pathtmp2 = pathtmp; + while ((pathtmp2 = strchr(pathtmp2, '/')) != NULL) + *pathtmp2 = '.'; + while (strlen(pathtmp) && pathtmp[strlen(pathtmp) - 1] == '.') + pathtmp[strlen(pathtmp) - 1] = '\0'; + for (pathtmp2 = pathtmp; *pathtmp2 == '.'; pathtmp2++); + snprintf(path, SQUID_MAXPATHLEN - 64, Config.Log.swap, pathtmp2); + if (strncmp(path, Config.Log.swap, SQUID_MAXPATHLEN - 64) == 0) { + strcat(path, "."); + snprintf(digit, 32, "%02d", sd->index); + strncat(path, digit, 3); + } + } else { + xstrncpy(path, sd->path, SQUID_MAXPATHLEN - 64); + strcat(path, "/swap.state"); + } + if (ext) + strncat(path, ext, 16); + return path; +} + +void +commonUfsDirOpenSwapLog(SwapDir * sd) +{ + squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata; + char *path; + int fd; + path = commonUfsDirSwapLogFile(sd, NULL); + fd = file_open(path, O_WRONLY | O_CREAT | O_BINARY); + if (fd < 0) { + debug(50, 1) ("%s: %s\n", path, xstrerror()); + fatal("commonUfsDirOpenSwapLog: Failed to open swap log."); + } + debug(50, 3) ("Cache Dir #%d log opened on FD %d\n", sd->index, fd); + ioinfo->swaplog_fd = fd; + if (0 == n_dirs) + assert(NULL == dir_index); + ++n_dirs; + assert(n_dirs <= Config.cacheSwap.n_configured); +} + +void +commonUfsDirCloseSwapLog(SwapDir * sd) +{ + squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata; + if (ioinfo->swaplog_fd < 0) /* not open */ + return; + file_close(ioinfo->swaplog_fd); + debug(47, 3) ("Cache Dir #%d log closed on FD %d\n", + sd->index, ioinfo->swaplog_fd); + ioinfo->swaplog_fd = -1; + n_dirs--; + assert(n_dirs >= 0); + if (0 == n_dirs) + safe_free(dir_index); +} + +void +commonUfsDirInit(SwapDir * sd) +{ + static int started_clean_event = 0; + static const char *errmsg = + "\tFailed to verify one of the swap directories, Check cache.log\n" + "\tfor details. Run 'squid -z' to create swap directories\n" + "\tif needed, or if running Squid for the first time."; + commonUfsDirInitBitmap(sd); + if (commonUfsDirVerifyCacheDirs(sd) < 0) + fatal(errmsg); + commonUfsDirOpenSwapLog(sd); + commonUfsDirRebuild(sd); + if (!started_clean_event) { + eventAdd("storeDirClean", commonUfsDirCleanEvent, NULL, 15.0, 1); + started_clean_event = 1; + } + (void) storeDirGetBlkSize(sd->path, &sd->fs.blksize); +} + +void +commonUfsDirRebuildFromDirectory(void *data) +{ + RebuildState *rb = (RebuildState *)data; + SwapDir *SD = rb->sd; + LOCAL_ARRAY(char, hdr_buf, SM_PAGE_SIZE); + StoreEntry *e = NULL; + StoreEntry tmpe; + cache_key key[MD5_DIGEST_CHARS]; + sfileno filn = 0; + int count; + int size; + struct stat sb; + int swap_hdr_len; + int fd = -1; + tlv *tlv_list; + tlv *t; + assert(rb != NULL); + debug(47, 3) ("commonUfsDirRebuildFromDirectory: DIR #%d\n", rb->sd->index); + for (count = 0; count < rb->speed; count++) { + assert(fd == -1); + fd = commonUfsDirGetNextFile(rb, &filn, &size); + if (fd == -2) { + debug(47, 1) ("Done scanning %s swaplog (%d entries)\n", + rb->sd->path, rb->n_read); + store_dirs_rebuilding--; + commonUfsDirCloseTmpSwapLog(rb->sd); + storeRebuildComplete(&rb->counts); + cbdataFree(rb); + return; + } else if (fd < 0) { + continue; + } + assert(fd > -1); + /* lets get file stats here */ + if (fstat(fd, &sb) < 0) { + debug(47, 1) ("commonUfsDirRebuildFromDirectory: fstat(FD %d): %s\n", + fd, xstrerror()); + file_close(fd); + store_open_disk_fd--; + fd = -1; + continue; + } + if ((++rb->counts.scancount & 0xFFFF) == 0) + debug(47, 3) (" %s %7d files opened so far.\n", + rb->sd->path, rb->counts.scancount); + debug(47, 9) ("file_in: fd=%d %08X\n", fd, filn); + statCounter.syscalls.disk.reads++; + if (FD_READ_METHOD(fd, hdr_buf, SM_PAGE_SIZE) < 0) { + debug(47, 1) ("commonUfsDirRebuildFromDirectory: read(FD %d): %s\n", + fd, xstrerror()); + file_close(fd); + store_open_disk_fd--; + fd = -1; + continue; + } + file_close(fd); + store_open_disk_fd--; + fd = -1; + swap_hdr_len = 0; +#if USE_TRUNCATE + if (sb.st_size == 0) + continue; +#endif + tlv_list = storeSwapMetaUnpack(hdr_buf, &swap_hdr_len); + if (tlv_list == NULL) { + debug(47, 1) ("commonUfsDirRebuildFromDirectory: failed to get meta data\n"); + /* XXX shouldn't this be a call to commonUfsUnlink ? */ + commonUfsDirUnlinkFile(SD, filn); + continue; + } + debug(47, 3) ("commonUfsDirRebuildFromDirectory: successful swap meta unpacking\n"); + memset(key, '\0', MD5_DIGEST_CHARS); + memset(&tmpe, '\0', sizeof(StoreEntry)); + for (t = tlv_list; t; t = t->next) { + switch (t->type) { + case STORE_META_KEY: + assert(t->length == MD5_DIGEST_CHARS); + xmemcpy(key, t->value, MD5_DIGEST_CHARS); + break; + case STORE_META_STD: + assert(t->length == STORE_HDR_METASIZE); + xmemcpy(&tmpe.timestamp, t->value, STORE_HDR_METASIZE); + break; + default: + break; + } + } + storeSwapTLVFree(tlv_list); + tlv_list = NULL; + if (storeKeyNull(key)) { + debug(47, 1) ("commonUfsDirRebuildFromDirectory: NULL key\n"); + commonUfsDirUnlinkFile(SD, filn); + continue; + } + tmpe.hash.key = key; + /* check sizes */ + if (tmpe.swap_file_sz == 0) { + tmpe.swap_file_sz = (size_t) sb.st_size; + } else if (tmpe.swap_file_sz == (size_t)(sb.st_size - swap_hdr_len)) { + tmpe.swap_file_sz = (size_t) sb.st_size; + } else if (tmpe.swap_file_sz != (size_t)sb.st_size) { + debug(47, 1) ("commonUfsDirRebuildFromDirectory: SIZE MISMATCH %ld!=%ld\n", + (long int) tmpe.swap_file_sz, (long int) sb.st_size); + commonUfsDirUnlinkFile(SD, filn); + continue; + } + if (EBIT_TEST(tmpe.flags, KEY_PRIVATE)) { + commonUfsDirUnlinkFile(SD, filn); + rb->counts.badflags++; + continue; + } + e = storeGet(key); + if (e && e->lastref >= tmpe.lastref) { + /* key already exists, current entry is newer */ + /* keep old, ignore new */ + rb->counts.dupcount++; + continue; + } else if (NULL != e) { + /* URL already exists, this swapfile not being used */ + /* junk old, load new */ + storeRelease(e); /* release old entry */ + rb->counts.dupcount++; + } + rb->counts.objcount++; + storeEntryDump(&tmpe, 5); + e = commonUfsDirAddDiskRestore(SD, key, + filn, + tmpe.swap_file_sz, + tmpe.expires, + tmpe.timestamp, + tmpe.lastref, + tmpe.lastmod, + tmpe.refcount, /* refcount */ + tmpe.flags, /* flags */ + (int) rb->flags.clean); + storeDirSwapLog(e, SWAP_LOG_ADD); + } + eventAdd("storeRebuild", commonUfsDirRebuildFromDirectory, rb, 0.0, 1); +} + +void +commonUfsDirRebuildFromSwapLog(void *data) +{ + RebuildState *rb = (RebuildState *)data; + SwapDir *SD = rb->sd; + StoreEntry *e = NULL; + storeSwapLogData s; + size_t ss = sizeof(storeSwapLogData); + int count; + int used; /* is swapfile already in use? */ + int disk_entry_newer; /* is the log entry newer than current entry? */ + double x; + assert(rb != NULL); + /* load a number of objects per invocation */ + for (count = 0; count < rb->speed; count++) { + if (fread(&s, ss, 1, rb->log) != 1) { + debug(47, 1) ("Done reading %s swaplog (%d entries)\n", + rb->sd->path, rb->n_read); + fclose(rb->log); + rb->log = NULL; + store_dirs_rebuilding--; + commonUfsDirCloseTmpSwapLog(rb->sd); + storeRebuildComplete(&rb->counts); + cbdataFree(rb); + return; + } + rb->n_read++; + if (s.op <= SWAP_LOG_NOP) + continue; + if (s.op >= SWAP_LOG_MAX) + continue; + /* + * BC: during 2.4 development, we changed the way swap file + * numbers are assigned and stored. The high 16 bits used + * to encode the SD index number. There used to be a call + * to storeDirProperFileno here that re-assigned the index + * bits. Now, for backwards compatibility, we just need + * to mask it off. + */ + s.swap_filen &= 0x00FFFFFF; + debug(47, 3) ("commonUfsDirRebuildFromSwapLog: %s %s %08X\n", + swap_log_op_str[(int) s.op], + storeKeyText(s.key), + s.swap_filen); + if (s.op == SWAP_LOG_ADD) { + (void) 0; + } else if (s.op == SWAP_LOG_DEL) { + if ((e = storeGet(s.key)) != NULL) { + /* + * Make sure we don't unlink the file, it might be + * in use by a subsequent entry. Also note that + * we don't have to subtract from store_swap_size + * because adding to store_swap_size happens in + * the cleanup procedure. + */ + storeExpireNow(e); + storeReleaseRequest(e); + if (e->swap_filen > -1) { + commonUfsDirReplRemove(e); + commonUfsDirMapBitReset(SD, e->swap_filen); + e->swap_filen = -1; + e->swap_dirn = -1; + } + storeRelease(e); + rb->counts.objcount--; + rb->counts.cancelcount++; + } + continue; + } else { + x = log(++rb->counts.bad_log_op) / log(10.0); + if (0.0 == x - (double) (int) x) + debug(47, 1) ("WARNING: %d invalid swap log entries found\n", + rb->counts.bad_log_op); + rb->counts.invalid++; + continue; + } + if ((++rb->counts.scancount & 0xFFF) == 0) { + struct stat sb; + if (0 == fstat(fileno(rb->log), &sb)) + storeRebuildProgress(SD->index, + (int) sb.st_size / ss, rb->n_read); + } + if (!commonUfsDirValidFileno(SD, s.swap_filen, 0)) { + rb->counts.invalid++; + continue; + } + if (EBIT_TEST(s.flags, KEY_PRIVATE)) { + rb->counts.badflags++; + continue; + } + e = storeGet(s.key); + used = commonUfsDirMapBitTest(SD, s.swap_filen); + /* If this URL already exists in the cache, does the swap log + * appear to have a newer entry? Compare 'lastref' from the + * swap log to e->lastref. */ + disk_entry_newer = e ? (s.lastref > e->lastref ? 1 : 0) : 0; + if (used && !disk_entry_newer) { + /* log entry is old, ignore it */ + rb->counts.clashcount++; + continue; + } else if (used && e && e->swap_filen == s.swap_filen && e->swap_dirn == SD->index) { + /* swapfile taken, same URL, newer, update meta */ + if (e->store_status == STORE_OK) { + e->lastref = s.timestamp; + e->timestamp = s.timestamp; + e->expires = s.expires; + e->lastmod = s.lastmod; + e->flags = s.flags; + e->refcount += s.refcount; + commonUfsDirUnrefObj(SD, e); + } else { + debug_trap("commonUfsDirRebuildFromSwapLog: bad condition"); + debug(47, 1) ("\tSee %s:%d\n", __FILE__, __LINE__); + } + continue; + } else if (used) { + /* swapfile in use, not by this URL, log entry is newer */ + /* This is sorta bad: the log entry should NOT be newer at this + * point. If the log is dirty, the filesize check should have + * caught this. If the log is clean, there should never be a + * newer entry. */ + debug(47, 1) ("WARNING: newer swaplog entry for dirno %d, fileno %08X\n", + SD->index, s.swap_filen); + /* I'm tempted to remove the swapfile here just to be safe, + * but there is a bad race condition in the NOVM version if + * the swapfile has recently been opened for writing, but + * not yet opened for reading. Because we can't map + * swapfiles back to StoreEntrys, we don't know the state + * of the entry using that file. */ + /* We'll assume the existing entry is valid, probably because + * were in a slow rebuild and the the swap file number got taken + * and the validation procedure hasn't run. */ + assert(rb->flags.need_to_validate); + rb->counts.clashcount++; + continue; + } else if (e && !disk_entry_newer) { + /* key already exists, current entry is newer */ + /* keep old, ignore new */ + rb->counts.dupcount++; + continue; + } else if (e) { + /* key already exists, this swapfile not being used */ + /* junk old, load new */ + storeExpireNow(e); + storeReleaseRequest(e); + if (e->swap_filen > -1) { + commonUfsDirReplRemove(e); + /* Make sure we don't actually unlink the file */ + commonUfsDirMapBitReset(SD, e->swap_filen); + e->swap_filen = -1; + e->swap_dirn = -1; + } + storeRelease(e); + rb->counts.dupcount++; + } else { + /* URL doesnt exist, swapfile not in use */ + /* load new */ + (void) 0; + } + /* update store_swap_size */ + rb->counts.objcount++; + e = commonUfsDirAddDiskRestore(SD, s.key, + s.swap_filen, + s.swap_file_sz, + s.expires, + s.timestamp, + s.lastref, + s.lastmod, + s.refcount, + s.flags, + (int) rb->flags.clean); + storeDirSwapLog(e, SWAP_LOG_ADD); + } + eventAdd("storeRebuild", commonUfsDirRebuildFromSwapLog, rb, 0.0, 1); +} + +int +commonUfsDirGetNextFile(RebuildState * rb, sfileno * filn_p, int *size) +{ + SwapDir *SD = rb->sd; + squidufsinfo_t *ioinfo = (squidufsinfo_t *) SD->fsdata; + int fd = -1; + int used = 0; + int dirs_opened = 0; + debug(47, 3) ("commonUfsDirGetNextFile: flag=%d, %d: /%02X/%02X\n", + rb->flags.init, + rb->sd->index, + rb->curlvl1, + rb->curlvl2); + if (rb->done) + return -2; + while (fd < 0 && rb->done == 0) { + fd = -1; + if (0 == rb->flags.init) { /* initialize, open first file */ + rb->done = 0; + rb->curlvl1 = 0; + rb->curlvl2 = 0; + rb->in_dir = 0; + rb->flags.init = 1; + assert(Config.cacheSwap.n_configured > 0); + } + if (0 == rb->in_dir) { /* we need to read in a new directory */ + snprintf(rb->fullpath, SQUID_MAXPATHLEN, "%s/%02X/%02X", + rb->sd->path, + rb->curlvl1, rb->curlvl2); + if (dirs_opened) + return -1; + rb->td = opendir(rb->fullpath); + dirs_opened++; + if (rb->td == NULL) { + debug(47, 1) ("commonUfsDirGetNextFile: opendir: %s: %s\n", + rb->fullpath, xstrerror()); + } else { + rb->entry = readdir(rb->td); /* skip . and .. */ + rb->entry = readdir(rb->td); + if (rb->entry == NULL && errno == ENOENT) + debug(47, 1) ("commonUfsDirGetNextFile: directory does not exist!.\n"); + debug(47, 3) ("commonUfsDirGetNextFile: Directory %s\n", rb->fullpath); + } + } + if (rb->td != NULL && (rb->entry = readdir(rb->td)) != NULL) { + rb->in_dir++; + if (sscanf(rb->entry->d_name, "%x", &rb->fn) != 1) { + debug(47, 3) ("commonUfsDirGetNextFile: invalid %s\n", + rb->entry->d_name); + continue; + } + if (!commonUfsFilenoBelongsHere(rb->fn, rb->sd->index, rb->curlvl1, rb->curlvl2)) { + debug(47, 3) ("commonUfsDirGetNextFile: %08X does not belong in %d/%d/%d\n", + rb->fn, rb->sd->index, rb->curlvl1, rb->curlvl2); + continue; + } + used = commonUfsDirMapBitTest(SD, rb->fn); + if (used) { + debug(47, 3) ("commonUfsDirGetNextFile: Locked, continuing with next.\n"); + continue; + } + snprintf(rb->fullfilename, SQUID_MAXPATHLEN, "%s/%s", + rb->fullpath, rb->entry->d_name); + debug(47, 3) ("commonUfsDirGetNextFile: Opening %s\n", rb->fullfilename); + fd = file_open(rb->fullfilename, O_RDONLY | O_BINARY); + if (fd < 0) + debug(47, 1) ("commonUfsDirGetNextFile: %s: %s\n", rb->fullfilename, xstrerror()); + else + store_open_disk_fd++; + continue; + } + if (rb->td != NULL) + closedir(rb->td); + rb->td = NULL; + rb->in_dir = 0; + if (++rb->curlvl2 < ioinfo->l2) + continue; + rb->curlvl2 = 0; + if (++rb->curlvl1 < ioinfo->l1) + continue; + rb->curlvl1 = 0; + rb->done = 1; + } + *filn_p = rb->fn; + return fd; +} + +/* Add a new object to the cache with empty memory copy and pointer to disk + * use to rebuild store from disk. */ +StoreEntry * +commonUfsDirAddDiskRestore(SwapDir * SD, const cache_key * key, + sfileno file_number, + size_t swap_file_sz, + time_t expires, + time_t timestamp, + time_t lastref, + time_t lastmod, + u_int32_t refcount, + u_int16_t flags, + int clean) +{ + StoreEntry *e = NULL; + debug(47, 5) ("commonUfsAddDiskRestore: %s, fileno=%08X\n", storeKeyText(key), file_number); + /* if you call this you'd better be sure file_number is not + * already in use! */ + e = new_StoreEntry(STORE_ENTRY_WITHOUT_MEMOBJ, NULL, NULL); + e->store_status = STORE_OK; + storeSetMemStatus(e, NOT_IN_MEMORY); + e->swap_status = SWAPOUT_DONE; + e->swap_filen = file_number; + e->swap_dirn = SD->index; + e->swap_file_sz = swap_file_sz; + e->lock_count = 0; + e->lastref = lastref; + e->timestamp = timestamp; + e->expires = expires; + e->lastmod = lastmod; + e->refcount = refcount; + e->flags = flags; + EBIT_SET(e->flags, ENTRY_CACHABLE); + EBIT_CLR(e->flags, RELEASE_REQUEST); + EBIT_CLR(e->flags, KEY_PRIVATE); + e->ping_status = PING_NONE; + EBIT_CLR(e->flags, ENTRY_VALIDATED); + commonUfsDirMapBitSet(SD, e->swap_filen); + storeHashInsert(e, key); /* do it after we clear KEY_PRIVATE */ + commonUfsDirReplAdd(SD, e); + return e; +} + +CBDATA_TYPE(RebuildState); + +void +commonUfsDirRebuild(SwapDir * sd) +{ + RebuildState *rb; + int clean = 0; + int zero = 0; + FILE *fp; + EVH *func = NULL; + CBDATA_INIT_TYPE(RebuildState); + rb = cbdataAlloc(RebuildState); + rb->sd = sd; + rb->speed = opt_foreground_rebuild ? 1 << 30 : 50; + /* + * If the swap.state file exists in the cache_dir, then + * we'll use commonUfsDirRebuildFromSwapLog(), otherwise we'll + * use commonUfsDirRebuildFromDirectory() to open up each file + * and suck in the meta data. + */ + fp = commonUfsDirOpenTmpSwapLog(sd, &clean, &zero); + if (fp == NULL || zero) { + if (fp != NULL) + fclose(fp); + func = commonUfsDirRebuildFromDirectory; + } else { + func = commonUfsDirRebuildFromSwapLog; + rb->log = fp; + rb->flags.clean = (unsigned int) clean; + } + if (!clean) + rb->flags.need_to_validate = 1; + debug(47, 1) ("Rebuilding storage in %s (%s)\n", + sd->path, clean ? "CLEAN" : "DIRTY"); + store_dirs_rebuilding++; + eventAdd("storeRebuild", func, rb, 0.0, 1); +} + +void +commonUfsDirCloseTmpSwapLog(SwapDir * sd) +{ + squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata; + char *swaplog_path = xstrdup(commonUfsDirSwapLogFile(sd, NULL)); + char *new_path = xstrdup(commonUfsDirSwapLogFile(sd, ".new")); + int fd; + file_close(ioinfo->swaplog_fd); +#if defined (_SQUID_OS2_) || defined (_SQUID_CYGWIN_) || defined(_SQUID_MSWIN_) + if (unlink(swaplog_path) < 0) { + debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror()); + fatal("commonUfsDirCloseTmpSwapLog: unlink failed"); + } +#endif + if (xrename(new_path, swaplog_path) < 0) { + fatal("commonUfsDirCloseTmpSwapLog: rename failed"); + } + fd = file_open(swaplog_path, O_WRONLY | O_CREAT | O_BINARY); + if (fd < 0) { + debug(50, 1) ("%s: %s\n", swaplog_path, xstrerror()); + fatal("commonUfsDirCloseTmpSwapLog: Failed to open swap log."); + } + safe_free(swaplog_path); + safe_free(new_path); + ioinfo->swaplog_fd = fd; + debug(47, 3) ("Cache Dir #%d log opened on FD %d\n", sd->index, fd); +} + +FILE * +commonUfsDirOpenTmpSwapLog(SwapDir * sd, int *clean_flag, int *zero_flag) +{ + squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata; + char *swaplog_path = xstrdup(commonUfsDirSwapLogFile(sd, NULL)); + char *clean_path = xstrdup(commonUfsDirSwapLogFile(sd, ".last-clean")); + char *new_path = xstrdup(commonUfsDirSwapLogFile(sd, ".new")); + struct stat log_sb; + struct stat clean_sb; + FILE *fp; + int fd; + if (stat(swaplog_path, &log_sb) < 0) { + debug(47, 1) ("Cache Dir #%d: No log file\n", sd->index); + safe_free(swaplog_path); + safe_free(clean_path); + safe_free(new_path); + return NULL; + } + *zero_flag = log_sb.st_size == 0 ? 1 : 0; + /* close the existing write-only FD */ + if (ioinfo->swaplog_fd >= 0) + file_close(ioinfo->swaplog_fd); + /* open a write-only FD for the new log */ + fd = file_open(new_path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY); + if (fd < 0) { + debug(50, 1) ("%s: %s\n", new_path, xstrerror()); + fatal("storeDirOpenTmpSwapLog: Failed to open swap log."); + } + ioinfo->swaplog_fd = fd; + /* open a read-only stream of the old log */ + fp = fopen(swaplog_path, "rb"); + if (fp == NULL) { + debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror()); + fatal("Failed to open swap log for reading"); + } + memset(&clean_sb, '\0', sizeof(struct stat)); + if (stat(clean_path, &clean_sb) < 0) + *clean_flag = 0; + else if (clean_sb.st_mtime < log_sb.st_mtime) + *clean_flag = 0; + else + *clean_flag = 1; + safeunlink(clean_path, 1); + safe_free(swaplog_path); + safe_free(clean_path); + safe_free(new_path); + return fp; +} + +struct _clean_state { + char *cur; + char *newLog; + char *cln; + char *outbuf; + off_t outbuf_offset; + int fd; + RemovalPolicyWalker *walker; +}; + +#define CLEAN_BUF_SZ 16384 + +/* + * Begin the process to write clean cache state. For AUFS this means + * opening some log files and allocating write buffers. Return 0 if + * we succeed, and assign the 'func' and 'data' return pointers. + */ +int +commonUfsDirWriteCleanStart(SwapDir * sd) +{ + struct _clean_state *state = (struct _clean_state *)xcalloc(1, sizeof(*state)); +#if HAVE_FCHMOD + struct stat sb; +#endif + sd->log.clean.write = NULL; + sd->log.clean.state = NULL; + state->newLog = xstrdup(commonUfsDirSwapLogFile(sd, ".clean")); + state->fd = file_open(state->newLog, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY); + if (state->fd < 0) { + xfree(state->newLog); + xfree(state); + return -1; + } + state->cur = xstrdup(commonUfsDirSwapLogFile(sd, NULL)); + state->cln = xstrdup(commonUfsDirSwapLogFile(sd, ".last-clean")); + state->outbuf = (char *)xcalloc(CLEAN_BUF_SZ, 1); + state->outbuf_offset = 0; + state->walker = sd->repl->WalkInit(sd->repl); + unlink(state->cln); + debug(47, 3) ("storeDirWriteCleanLogs: opened %s, FD %d\n", + state->newLog, state->fd); +#if HAVE_FCHMOD + if (stat(state->cur, &sb) == 0) + fchmod(state->fd, sb.st_mode); +#endif + sd->log.clean.write = commonUfsDirWriteCleanEntry; + sd->log.clean.state = state; + return 0; +} + +/* + * Get the next entry that is a candidate for clean log writing + */ +const StoreEntry * +commonUfsDirCleanLogNextEntry(SwapDir * sd) +{ + const StoreEntry *entry = NULL; + struct _clean_state *state = (struct _clean_state *)sd->log.clean.state; + if (state->walker) + entry = state->walker->Next(state->walker); + return entry; +} + +/* + * "write" an entry to the clean log file. + */ +void +commonUfsDirWriteCleanEntry(SwapDir * sd, const StoreEntry * e) +{ + storeSwapLogData s; + static size_t ss = sizeof(storeSwapLogData); + struct _clean_state *state = (struct _clean_state *)sd->log.clean.state; + memset(&s, '\0', ss); + s.op = (char) SWAP_LOG_ADD; + s.swap_filen = e->swap_filen; + s.timestamp = e->timestamp; + s.lastref = e->lastref; + s.expires = e->expires; + s.lastmod = e->lastmod; + s.swap_file_sz = e->swap_file_sz; + s.refcount = e->refcount; + s.flags = e->flags; + xmemcpy(&s.key, e->hash.key, MD5_DIGEST_CHARS); + xmemcpy(state->outbuf + state->outbuf_offset, &s, ss); + state->outbuf_offset += ss; + /* buffered write */ + if (state->outbuf_offset + ss > CLEAN_BUF_SZ) { + if (FD_WRITE_METHOD(state->fd, state->outbuf, state->outbuf_offset) < 0) { + debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %s\n", + state->newLog, xstrerror()); + debug(50, 0) ("storeDirWriteCleanLogs: Current swap logfile not replaced.\n"); + file_close(state->fd); + state->fd = -1; + unlink(state->newLog); + safe_free(state); + sd->log.clean.state = NULL; + sd->log.clean.write = NULL; + return; + } + state->outbuf_offset = 0; + } +} + +void +commonUfsDirWriteCleanDone(SwapDir * sd) +{ + int fd; + struct _clean_state *state = (struct _clean_state *)sd->log.clean.state; + if (NULL == state) + return; + if (state->fd < 0) + return; + state->walker->Done(state->walker); + if (FD_WRITE_METHOD(state->fd, state->outbuf, state->outbuf_offset) < 0) { + debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %s\n", + state->newLog, xstrerror()); + debug(50, 0) ("storeDirWriteCleanLogs: Current swap logfile " + "not replaced.\n"); + file_close(state->fd); + state->fd = -1; + unlink(state->newLog); + } + safe_free(state->outbuf); + /* + * You can't rename open files on Microsoft "operating systems" + * so we have to close before renaming. + */ + commonUfsDirCloseSwapLog(sd); + /* save the fd value for a later test */ + fd = state->fd; + /* rename */ + if (state->fd >= 0) { +#if defined(_SQUID_OS2_) || defined (_SQUID_CYGWIN_) || defined(_SQUID_MSWIN_) + file_close(state->fd); + state->fd = -1; + if (unlink(state->cur) < 0) + debug(50, 0) ("storeDirWriteCleanLogs: unlinkd failed: %s, %s\n", + xstrerror(), state->cur); +#endif + xrename(state->newLog, state->cur); + } + /* touch a timestamp file if we're not still validating */ + if (store_dirs_rebuilding) + (void) 0; + else if (fd < 0) + (void) 0; + else + file_close(file_open(state->cln, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY)); + /* close */ + safe_free(state->cur); + safe_free(state->newLog); + safe_free(state->cln); + if (state->fd >= 0) + file_close(state->fd); + state->fd = -1; + safe_free(state); + sd->log.clean.state = NULL; + sd->log.clean.write = NULL; +} + +void +storeSwapLogDataFree(void *s) +{ + memFree(s, MEM_SWAP_LOG_DATA); +} + +void +commonUfsDirSwapLog(const SwapDir * sd, const StoreEntry * e, int op) +{ + squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata; + storeSwapLogData *s = (storeSwapLogData *)memAllocate(MEM_SWAP_LOG_DATA); + s->op = (char) op; + s->swap_filen = e->swap_filen; + s->timestamp = e->timestamp; + s->lastref = e->lastref; + s->expires = e->expires; + s->lastmod = e->lastmod; + s->swap_file_sz = e->swap_file_sz; + s->refcount = e->refcount; + s->flags = e->flags; + xmemcpy(s->key, e->hash.key, MD5_DIGEST_CHARS); + file_write(ioinfo->swaplog_fd, + -1, + s, + sizeof(storeSwapLogData), + NULL, + NULL, + (FREE *) storeSwapLogDataFree); +} + +void +commonUfsDirNewfs(SwapDir * sd) +{ + debug(47, 3) ("Creating swap space in %s\n", sd->path); + commonUfsDirCreateDirectory(sd->path, 0); + commonUfsDirCreateSwapSubDirs(sd); +} + +static int +rev_int_sort(const void *A, const void *B) +{ + const int *i1 = (const int *)A; + const int *i2 = (const int *)B; + return *i2 - *i1; +} + +int +commonUfsDirClean(int swap_index) +{ + DIR *dp = NULL; + struct dirent *de = NULL; + LOCAL_ARRAY(char, p1, MAXPATHLEN + 1); + LOCAL_ARRAY(char, p2, MAXPATHLEN + 1); +#if USE_TRUNCATE + struct stat sb; +#endif + int files[20]; + int swapfileno; + int fn; /* same as swapfileno, but with dirn bits set */ + int n = 0; + int k = 0; + int N0, N1, N2; + int D0, D1, D2; + SwapDir *SD; + squidufsinfo_t *ioinfo; + N0 = n_dirs; + D0 = dir_index[swap_index % N0]; + SD = &Config.cacheSwap.swapDirs[D0]; + ioinfo = (squidufsinfo_t *) SD->fsdata; + N1 = ioinfo->l1; + D1 = (swap_index / N0) % N1; + N2 = ioinfo->l2; + D2 = ((swap_index / N0) / N1) % N2; + snprintf(p1, SQUID_MAXPATHLEN, "%s/%02X/%02X", + Config.cacheSwap.swapDirs[D0].path, D1, D2); + debug(36, 3) ("storeDirClean: Cleaning directory %s\n", p1); + dp = opendir(p1); + if (dp == NULL) { + if (errno == ENOENT) { + debug(36, 0) ("storeDirClean: WARNING: Creating %s\n", p1); +#ifdef _SQUID_MSWIN_ + if (mkdir(p1) == 0) +#else + if (mkdir(p1, 0777) == 0) +#endif + return 0; + } + debug(50, 0) ("storeDirClean: %s: %s\n", p1, xstrerror()); + safeunlink(p1, 1); + return 0; + } + while ((de = readdir(dp)) != NULL && k < 20) { + if (sscanf(de->d_name, "%X", &swapfileno) != 1) + continue; + fn = swapfileno; /* XXX should remove this cruft ! */ + if (commonUfsDirValidFileno(SD, fn, 1)) + if (commonUfsDirMapBitTest(SD, fn)) + if (commonUfsFilenoBelongsHere(fn, D0, D1, D2)) + continue; +#if USE_TRUNCATE + if (!stat(de->d_name, &sb)) + if (sb.st_size == 0) + continue; +#endif + files[k++] = swapfileno; + } + closedir(dp); + if (k == 0) + return 0; + qsort(files, k, sizeof(int), rev_int_sort); + if (k > 10) + k = 10; + for (n = 0; n < k; n++) { + debug(36, 3) ("storeDirClean: Cleaning file %08X\n", files[n]); + snprintf(p2, MAXPATHLEN + 1, "%s/%08X", p1, files[n]); +#if USE_TRUNCATE + truncate(p2, 0); +#else + safeunlink(p2, 0); +#endif + statCounter.swap.files_cleaned++; + } + debug(36, 3) ("Cleaned %d unused files from %s\n", k, p1); + return k; +} + +void +commonUfsDirCleanEvent(void *unused) +{ + static int swap_index = 0; + int i; + int j = 0; + int n = 0; + /* + * Assert that there are AUFS cache_dirs configured, otherwise + * we should never be called. + */ + assert(n_dirs); + if (NULL == dir_index) { + SwapDir *sd; + squidufsinfo_t *ioinfo; + /* + * Initialize the little array that translates AUFS cache_dir + * number into the Config.cacheSwap.swapDirs array index. + */ + dir_index = (int *)xcalloc(n_dirs, sizeof(*dir_index)); + for (i = 0, n = 0; i < Config.cacheSwap.n_configured; i++) { + sd = &Config.cacheSwap.swapDirs[i]; + if (!commonUfsDirIs(sd)) + continue; + dir_index[n++] = i; + ioinfo = (squidufsinfo_t *) sd->fsdata; + j += (ioinfo->l1 * ioinfo->l2); + } + assert(n == n_dirs); + /* + * Start the commonUfsDirClean() swap_index with a random + * value. j equals the total number of AUFS level 2 + * swap directories + */ + swap_index = (int) (squid_random() % j); + } + if (0 == store_dirs_rebuilding) { + n = commonUfsDirClean(swap_index); + swap_index++; + } + eventAdd("storeDirClean", commonUfsDirCleanEvent, NULL, + 15.0 * exp(-0.25 * n), 1); +} + +int +commonUfsDirIs(SwapDir * sd) +{ + if (strncmp(sd->type, "aufs", 4) == 0) + return 1; + if (strncmp(sd->type, "diskd", 5) == 0) + return 1; + if (strncmp(sd->type, "ufs", 3) == 0) + return 1; + return 0; +} + +/* + * Does swapfile number 'fn' belong in cachedir #F0, + * level1 dir #F1, level2 dir #F2? + */ +int +commonUfsFilenoBelongsHere(int fn, int F0, int F1, int F2) +{ + int D1, D2; + int L1, L2; + int filn = fn; + squidufsinfo_t *ioinfo; + assert(F0 < Config.cacheSwap.n_configured); + ioinfo = (squidufsinfo_t *) Config.cacheSwap.swapDirs[F0].fsdata; + L1 = ioinfo->l1; + L2 = ioinfo->l2; + D1 = ((filn / L2) / L2) % L1; + if (F1 != D1) + return 0; + D2 = (filn / L2) % L2; + if (F2 != D2) + return 0; + return 1; +} + +int +commonUfsDirValidFileno(SwapDir * SD, sfileno filn, int flag) +{ + squidufsinfo_t *ioinfo = (squidufsinfo_t *) SD->fsdata; + if (filn < 0) + return 0; + /* + * If flag is set it means out-of-range file number should + * be considered invalid. + */ + if (flag) + if (filn > ioinfo->map->max_n_files) + return 0; + return 1; +} + +void +commonUfsDirMaintain(SwapDir * SD) +{ + StoreEntry *e = NULL; + int removed = 0; + int max_scan; + int max_remove; + double f; + RemovalPurgeWalker *walker; + /* We can't delete objects while rebuilding swap */ + if (store_dirs_rebuilding) { + return; + } else { + f = (double) (SD->cur_size - SD->low_size) / (SD->max_size - SD->low_size); + f = f < 0.0 ? 0.0 : f > 1.0 ? 1.0 : f; + max_scan = (int) (f * 400.0 + 100.0); + max_remove = (int) (f * 70.0 + 10.0); + /* + * This is kinda cheap, but so we need this priority hack? + */ + } + debug(47, 3) ("storeMaintainSwapSpace: f=%f, max_scan=%d, max_remove=%d\n", + f, max_scan, max_remove); + walker = SD->repl->PurgeInit(SD->repl, max_scan); + while (1) { + if (SD->cur_size < SD->low_size) + break; + if (removed >= max_remove) + break; + e = walker->Next(walker); + if (!e) + break; /* no more objects */ + removed++; + storeRelease(e); + } + walker->Done(walker); + debug(47, (removed ? 2 : 3)) ("commonUfsDirMaintain: %s removed %d/%d f=%.03f max_scan=%d\n", + SD->path, removed, max_remove, f, max_scan); +} + +#if 0 +/* + * commonUfsDirCheckObj + * + * This routine is called by storeDirSelectSwapDir to see if the given + * object is able to be stored on this filesystem. AUFS filesystems will + * happily store anything as long as the LRU time isn't too small. + */ +int +commonUfsDirCheckObj(SwapDir * SD, const StoreEntry * e) +{ + int loadav; + int ql; + +#if OLD_UNUSED_CODE + if (commonUfsDirExpiredReferenceAge(SD) < 300) { + debug(47, 3) ("commonUfsDirCheckObj: NO: LRU Age = %d\n", + commonUfsDirExpiredReferenceAge(SD)); + /* store_check_cachable_hist.no.lru_age_too_low++; */ + return -1; + } +#endif + ql = aioQueueSize(); + if (ql == 0) + loadav = 0; + loadav = ql * 1000 / MAGIC1; + debug(47, 9) ("commonUfsDirCheckObj: load=%d\n", loadav); + return loadav; +} +#endif +/* + * commonUfsDirRefObj + * + * This routine is called whenever an object is referenced, so we can + * maintain replacement information within the storage fs. + */ +void +commonUfsDirRefObj(SwapDir * SD, StoreEntry * e) +{ + debug(47, 3) ("commonUfsDirRefObj: referencing %p %d/%d\n", e, e->swap_dirn, + e->swap_filen); + if (SD->repl->Referenced) + SD->repl->Referenced(SD->repl, e, &e->repl); +} + +/* + * commonUfsDirUnrefObj + * This routine is called whenever the last reference to an object is + * removed, to maintain replacement information within the storage fs. + */ +void +commonUfsDirUnrefObj(SwapDir * SD, StoreEntry * e) +{ + debug(47, 3) ("commonUfsDirUnrefObj: referencing %p %d/%d\n", e, e->swap_dirn, + e->swap_filen); + if (SD->repl->Dereferenced) + SD->repl->Dereferenced(SD->repl, e, &e->repl); +} + +/* + * commonUfsDirUnlinkFile + * + * This routine unlinks a file and pulls it out of the bitmap. + * It used to be in commonUfsUnlink(), however an interface change + * forced this bit of code here. Eeek. + */ +void +commonUfsDirUnlinkFile(SwapDir * SD, sfileno f) +{ + squidufsinfo_t *ioinfo = (squidufsinfo_t *)SD->fsdata; + debug(79, 3) ("commonUfsDirUnlinkFile: unlinking fileno %08X\n", f); + /* commonUfsDirMapBitReset(SD, f); */ + assert(ioinfo->io.storeDirUnlinkFile); + ioinfo->io.storeDirUnlinkFile(commonUfsDirFullPath(SD, f, NULL)); +} + + +/* + * Add and remove the given StoreEntry from the replacement policy in + * use. + */ + +void +commonUfsDirReplAdd(SwapDir * SD, StoreEntry * e) +{ + debug(47, 4) ("commonUfsDirReplAdd: added node %p to dir %d\n", e, + SD->index); + SD->repl->Add(SD->repl, e, &e->repl); +} + + +void +commonUfsDirReplRemove(StoreEntry * e) +{ + SwapDir *SD; + if (e->swap_dirn < 0) + return; + SD = INDEXSD(e->swap_dirn); + debug(47, 4) ("commonUfsDirReplRemove: remove node %p from dir %d\n", e, + SD->index); + SD->repl->Remove(SD->repl, e, &e->repl); +} + + + +/* ========== LOCAL FUNCTIONS ABOVE, GLOBAL FUNCTIONS BELOW ========== */ + +void +commonUfsDirStats(SwapDir * SD, StoreEntry * sentry) +{ + squidufsinfo_t *ioinfo = (squidufsinfo_t *)SD->fsdata; + int totl_kb = 0; + int free_kb = 0; + int totl_in = 0; + int free_in = 0; + int x; + storeAppendPrintf(sentry, "First level subdirectories: %d\n", ioinfo->l1); + storeAppendPrintf(sentry, "Second level subdirectories: %d\n", ioinfo->l2); + storeAppendPrintf(sentry, "Maximum Size: %d KB\n", SD->max_size); + storeAppendPrintf(sentry, "Current Size: %d KB\n", SD->cur_size); + storeAppendPrintf(sentry, "Percent Used: %0.2f%%\n", + 100.0 * SD->cur_size / SD->max_size); + storeAppendPrintf(sentry, "Filemap bits in use: %d of %d (%d%%)\n", + ioinfo->map->n_files_in_map, ioinfo->map->max_n_files, + percent(ioinfo->map->n_files_in_map, ioinfo->map->max_n_files)); + x = storeDirGetUFSStats(SD->path, &totl_kb, &free_kb, &totl_in, &free_in); + if (0 == x) { + storeAppendPrintf(sentry, "Filesystem Space in use: %d/%d KB (%d%%)\n", + totl_kb - free_kb, + totl_kb, + percent(totl_kb - free_kb, totl_kb)); + storeAppendPrintf(sentry, "Filesystem Inodes in use: %d/%d (%d%%)\n", + totl_in - free_in, + totl_in, + percent(totl_in - free_in, totl_in)); + } + storeAppendPrintf(sentry, "Flags:"); + if (SD->flags.selected) + storeAppendPrintf(sentry, " SELECTED"); + if (SD->flags.read_only) + storeAppendPrintf(sentry, " READ-ONLY"); + storeAppendPrintf(sentry, "\n"); +} + +#if 0 +static struct cache_dir_option options[] = +{ +#if NOT_YET_DONE + {"L1", commonUfsDirParseL1, commonUfsDirDumpL1}, + {"L2", commonUfsDirParseL2, commonUfsDirDumpL2}, +#endif + {NULL, NULL} +}; + +/* + * commonUfsDirReconfigure + * + * This routine is called when the given swapdir needs reconfiguring + */ +static void +commonUfsDirReconfigure(SwapDir * sd, int index, char *path) +{ + int i; + int size; + int l1; + int l2; + + i = GetInteger(); + size = i << 10; /* Mbytes to kbytes */ + if (size <= 0) + fatal("commonUfsDirReconfigure: invalid size value"); + i = GetInteger(); + l1 = i; + if (l1 <= 0) + fatal("commonUfsDirReconfigure: invalid level 1 directories value"); + i = GetInteger(); + l2 = i; + if (l2 <= 0) + fatal("commonUfsDirReconfigure: invalid level 2 directories value"); + + /* just reconfigure it */ + if (size == sd->max_size) + debug(3, 1) ("Cache dir '%s' size remains unchanged at %d KB\n", + path, size); + else + debug(3, 1) ("Cache dir '%s' size changed to %d KB\n", + path, size); + sd->max_size = size; + + parse_cachedir_options(sd, options, 0); + + return; +} + +#endif + +void +commonUfsDirDump(StoreEntry * entry, SwapDir * s) +{ + squidufsinfo_t *ioinfo = (squidufsinfo_t *) s->fsdata; + storeAppendPrintf(entry, " %d %d %d", + s->max_size >> 10, + ioinfo->l1, + ioinfo->l2); +} + +/* + * Only "free" the filesystem specific stuff here + */ +void +commonUfsDirFree(SwapDir * s) +{ + squidufsinfo_t *ioinfo = (squidufsinfo_t *) s->fsdata; + if (ioinfo->swaplog_fd > -1) { + file_close(ioinfo->swaplog_fd); + ioinfo->swaplog_fd = -1; + } + filemapFreeMemory(ioinfo->map); + xfree(ioinfo); + s->fsdata = NULL; /* Will aid debugging... */ +} + + +char * +commonUfsDirFullPath(SwapDir * SD, sfileno filn, char *fullpath) +{ + LOCAL_ARRAY(char, fullfilename, SQUID_MAXPATHLEN); + squidufsinfo_t *ioinfo = (squidufsinfo_t *) SD->fsdata; + int L1 = ioinfo->l1; + int L2 = ioinfo->l2; + if (!fullpath) + fullpath = fullfilename; + fullpath[0] = '\0'; + snprintf(fullpath, SQUID_MAXPATHLEN, "%s/%02X/%02X/%08X", + SD->path, + ((filn / L2) / L2) % L1, + (filn / L2) % L2, + filn); + return fullpath; +} + +/* + * commonUfsCleanupDoubleCheck + * + * This is called by storeCleanup() if -S was given on the command line. + */ +int +commonUfsCleanupDoubleCheck(SwapDir * sd, StoreEntry * e) +{ + struct stat sb; + if (stat(commonUfsDirFullPath(sd, e->swap_filen, NULL), &sb) < 0) { + debug(47, 0) ("commonUfsCleanupDoubleCheck: MISSING SWAP FILE\n"); + debug(47, 0) ("commonUfsCleanupDoubleCheck: FILENO %08X\n", e->swap_filen); + debug(47, 0) ("commonUfsCleanupDoubleCheck: PATH %s\n", + commonUfsDirFullPath(sd, e->swap_filen, NULL)); + storeEntryDump(e, 0); + return -1; + } + if ((off_t)e->swap_file_sz != sb.st_size) { + debug(47, 0) ("commonUfsCleanupDoubleCheck: SIZE MISMATCH\n"); + debug(47, 0) ("commonUfsCleanupDoubleCheck: FILENO %08X\n", e->swap_filen); + debug(47, 0) ("commonUfsCleanupDoubleCheck: PATH %s\n", + commonUfsDirFullPath(sd, e->swap_filen, NULL)); + debug(47, 0) ("commonUfsCleanupDoubleCheck: ENTRY SIZE: %ld, FILE SIZE: %ld\n", + (long int) e->swap_file_sz, (long int) sb.st_size); + storeEntryDump(e, 0); + return -1; + } + return 0; +} Index: squid/src/fs/Makefile.am =================================================================== RCS file: /cvsroot/squid-sf//squid/src/fs/Makefile.am,v retrieving revision 1.3.18.2 retrieving revision 1.3.18.3 diff -u -r1.3.18.2 -r1.3.18.3 --- squid/src/fs/Makefile.am 4 Oct 2002 21:22:10 -0000 1.3.18.2 +++ squid/src/fs/Makefile.am 12 Oct 2002 12:21:42 -0000 1.3.18.3 @@ -13,14 +13,14 @@ EXTRA_LIBRARIES = libaufs.a libcoss.a libdiskd.a libnull.a libufs.a noinst_LIBRARIES = @STORE_LIBS@ -libaufs_a_SOURCES = aufs/aiops.c aufs/async_io.c aufs/store_asyncufs.h \ - aufs/store_dir_aufs.c aufs/store_io_aufs.c -libcoss_a_SOURCES = coss/store_coss.h coss/store_io_coss.c coss/store_dir_coss.c \ - coss/async_io.c coss/async_io.h -libdiskd_a_SOURCES = diskd/diskd.c diskd/store_dir_diskd.c diskd/store_diskd.h \ - diskd/store_io_diskd.c -libnull_a_SOURCES = null/store_null.c -libufs_a_SOURCES = ufs/store_dir_ufs.c ufs/store_io_ufs.c ufs/store_ufs.h +libaufs_a_SOURCES = aufs/aiops.cc aufs/async_io.cc aufs/store_asyncufs.h \ + aufs/store_dir_aufs.cc aufs/store_io_aufs.cc +libcoss_a_SOURCES = coss/store_coss.h coss/store_io_coss.cc coss/store_dir_coss.cc \ + coss/async_io.cc coss/async_io.h +libdiskd_a_SOURCES = diskd/diskd.cc diskd/store_dir_diskd.cc diskd/store_diskd.h \ + diskd/store_io_diskd.cc +libnull_a_SOURCES = null/store_null.cc +libufs_a_SOURCES = ufs/store_dir_ufs.cc ufs/store_io_ufs.cc ufs/store_ufs.h EXTRA_DIST = \ coss/coss-notes.txt --- squid/src/fs/aufs/aiops.c Wed Feb 14 01:07:42 2007 +++ /dev/null Wed Feb 14 01:07:22 2007 @@ -1,900 +0,0 @@ -/* - * $Id$ - * - * DEBUG: section 43 AIOPS - * AUTHOR: Stewart Forster - * - * SQUID Web Proxy Cache http://www.squid-cache.org/ - * ---------------------------------------------------------- - * - * Squid is the result of efforts by numerous individuals from - * the Internet community; see the CONTRIBUTORS file for full - * details. Many organizations have provided support for Squid's - * development; see the SPONSORS file for full details. Squid is - * Copyrighted (C) 2001 by the Regents of the University of - * California; see the COPYRIGHT file for full details. Squid - * incorporates software developed and/or copyrighted by other - * sources; see the CREDITS file for full details. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. - * - */ - -#include "squid.h" -#include "store_asyncufs.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#if HAVE_SCHED_H -#include -#endif - -#define RIDICULOUS_LENGTH 4096 - -enum _squidaio_thread_status { - _THREAD_STARTING = 0, - _THREAD_WAITING, - _THREAD_BUSY, - _THREAD_FAILED, - _THREAD_DONE -}; -typedef enum _squidaio_thread_status squidaio_thread_status; - -typedef struct squidaio_request_t { - struct squidaio_request_t *next; - squidaio_request_type request_type; - int cancelled; - char *path; - int oflag; - mode_t mode; - int fd; - char *bufferp; - char *tmpbufp; - int buflen; - off_t offset; - int whence; - int ret; - int err; - struct stat *tmpstatp; - struct stat *statp; - squidaio_result_t *resultp; -} squidaio_request_t; - -typedef struct squidaio_request_queue_t { - pthread_mutex_t mutex; - pthread_cond_t cond; - squidaio_request_t *volatile head; - squidaio_request_t *volatile *volatile tailp; - unsigned long requests; - unsigned long blocked; /* main failed to lock the queue */ -} squidaio_request_queue_t; - -typedef struct squidaio_thread_t squidaio_thread_t; -struct squidaio_thread_t { - squidaio_thread_t *next; - pthread_t thread; - squidaio_thread_status status; - struct squidaio_request_t *current_req; - unsigned long requests; -}; - -static void squidaio_init(void); -static void squidaio_queue_request(squidaio_request_t *); -static void squidaio_cleanup_request(squidaio_request_t *); -static void *squidaio_thread_loop(void *); -static void squidaio_do_open(squidaio_request_t *); -static void squidaio_do_read(squidaio_request_t *); -static void squidaio_do_write(squidaio_request_t *); -static void squidaio_do_close(squidaio_request_t *); -static void squidaio_do_stat(squidaio_request_t *); -static void squidaio_do_unlink(squidaio_request_t *); -static void squidaio_do_truncate(squidaio_request_t *); -#if AIO_OPENDIR -static void *squidaio_do_opendir(squidaio_request_t *); -#endif -static void squidaio_debug(squidaio_request_t *); -static void squidaio_poll_queues(void); - -static squidaio_thread_t *threads = NULL; -static int squidaio_initialised = 0; - - -#define AIO_LARGE_BUFS 16384 -#define AIO_MEDIUM_BUFS AIO_LARGE_BUFS >> 1 -#define AIO_SMALL_BUFS AIO_LARGE_BUFS >> 2 -#define AIO_TINY_BUFS AIO_LARGE_BUFS >> 3 -#define AIO_MICRO_BUFS 128 - -static MemPool *squidaio_large_bufs = NULL; /* 16K */ -static MemPool *squidaio_medium_bufs = NULL; /* 8K */ -static MemPool *squidaio_small_bufs = NULL; /* 4K */ -static MemPool *squidaio_tiny_bufs = NULL; /* 2K */ -static MemPool *squidaio_micro_bufs = NULL; /* 128K */ - -static int request_queue_len = 0; -static MemPool *squidaio_request_pool = NULL; -static MemPool *squidaio_thread_pool = NULL; -static squidaio_request_queue_t request_queue; -static struct { - squidaio_request_t *head, **tailp; -} request_queue2 = { - - NULL, &request_queue2.head -}; -static squidaio_request_queue_t done_queue; -static struct { - squidaio_request_t *head, **tailp; -} done_requests = { - - NULL, &done_requests.head -}; -static pthread_attr_t globattr; -#if HAVE_SCHED_H -static struct sched_param globsched; -#endif -static pthread_t main_thread; - -static MemPool * -squidaio_get_pool(int size) -{ - MemPool *p; - if (size <= AIO_LARGE_BUFS) { - if (size <= AIO_MICRO_BUFS) - p = squidaio_micro_bufs; - else if (size <= AIO_TINY_BUFS) - p = squidaio_tiny_bufs; - else if (size <= AIO_SMALL_BUFS) - p = squidaio_small_bufs; - else if (size <= AIO_MEDIUM_BUFS) - p = squidaio_medium_bufs; - else - p = squidaio_large_bufs; - } else - p = NULL; - return p; -} - -static void * -squidaio_xmalloc(int size) -{ - void *p; - MemPool *pool; - - if ((pool = squidaio_get_pool(size)) != NULL) { - p = memPoolAlloc(pool); - } else - p = xmalloc(size); - - return p; -} - -static char * -squidaio_xstrdup(const char *str) -{ - char *p; - int len = strlen(str) + 1; - - p = squidaio_xmalloc(len); - strncpy(p, str, len); - - return p; -} - -static void -squidaio_xfree(void *p, int size) -{ - MemPool *pool; - - if ((pool = squidaio_get_pool(size)) != NULL) { - memPoolFree(pool, p); - } else - xfree(p); -} - -static void -squidaio_xstrfree(char *str) -{ - MemPool *pool; - int len = strlen(str) + 1; - - if ((pool = squidaio_get_pool(len)) != NULL) { - memPoolFree(pool, str); - } else - xfree(str); -} - -static void -squidaio_init(void) -{ - int i; - squidaio_thread_t *threadp; - - if (squidaio_initialised) - return; - - pthread_attr_init(&globattr); -#if HAVE_PTHREAD_ATTR_SETSCOPE - pthread_attr_setscope(&globattr, PTHREAD_SCOPE_SYSTEM); -#endif -#if HAVE_SCHED_H - globsched.sched_priority = 1; -#endif - main_thread = pthread_self(); -#if HAVE_SCHED_H && HAVE_PTHREAD_SETSCHEDPARAM - pthread_setschedparam(main_thread, SCHED_OTHER, &globsched); -#endif -#if HAVE_SCHED_H - globsched.sched_priority = 2; -#endif -#if HAVE_SCHED_H && HAVE_PTHREAD_ATTR_SETSCHEDPARAM - pthread_attr_setschedparam(&globattr, &globsched); -#endif - - /* Initialize request queue */ - if (pthread_mutex_init(&(request_queue.mutex), NULL)) - fatal("Failed to create mutex"); - if (pthread_cond_init(&(request_queue.cond), NULL)) - fatal("Failed to create condition variable"); - request_queue.head = NULL; - request_queue.tailp = &request_queue.head; - request_queue.requests = 0; - request_queue.blocked = 0; - - /* Initialize done queue */ - if (pthread_mutex_init(&(done_queue.mutex), NULL)) - fatal("Failed to create mutex"); - if (pthread_cond_init(&(done_queue.cond), NULL)) - fatal("Failed to create condition variable"); - done_queue.head = NULL; - done_queue.tailp = &done_queue.head; - done_queue.requests = 0; - done_queue.blocked = 0; - - /* Create threads and get them to sit in their wait loop */ - squidaio_thread_pool = memPoolCreate("aio_thread", sizeof(squidaio_thread_t)); - assert (NUMTHREADS); - for (i = 0; i < NUMTHREADS; i++) { - threadp = memPoolAlloc(squidaio_thread_pool); - threadp->status = _THREAD_STARTING; - threadp->current_req = NULL; - threadp->requests = 0; - threadp->next = threads; - threads = threadp; - if (pthread_create(&threadp->thread, &globattr, squidaio_thread_loop, threadp)) { - fprintf(stderr, "Thread creation failed\n"); - threadp->status = _THREAD_FAILED; - continue; - } - } - - /* Create request pool */ - squidaio_request_pool = memPoolCreate("aio_request", sizeof(squidaio_request_t)); - squidaio_large_bufs = memPoolCreate("squidaio_large_bufs", AIO_LARGE_BUFS); - squidaio_medium_bufs = memPoolCreate("squidaio_medium_bufs", AIO_MEDIUM_BUFS); - squidaio_small_bufs = memPoolCreate("squidaio_small_bufs", AIO_SMALL_BUFS); - squidaio_tiny_bufs = memPoolCreate("squidaio_tiny_bufs", AIO_TINY_BUFS); - squidaio_micro_bufs = memPoolCreate("squidaio_micro_bufs", AIO_MICRO_BUFS); - - squidaio_initialised = 1; -} - - -static void * -squidaio_thread_loop(void *ptr) -{ - squidaio_thread_t *threadp = ptr; - squidaio_request_t *request; - sigset_t new; - - /* - * Make sure to ignore signals which may possibly get sent to - * the parent squid thread. Causes havoc with mutex's and - * condition waits otherwise - */ - - sigemptyset(&new); - sigaddset(&new, SIGPIPE); - sigaddset(&new, SIGCHLD); -#ifdef _SQUID_LINUX_THREADS_ - sigaddset(&new, SIGQUIT); - sigaddset(&new, SIGTRAP); -#else - sigaddset(&new, SIGUSR1); - sigaddset(&new, SIGUSR2); -#endif - sigaddset(&new, SIGHUP); - sigaddset(&new, SIGTERM); - sigaddset(&new, SIGINT); - sigaddset(&new, SIGALRM); - pthread_sigmask(SIG_BLOCK, &new, NULL); - - while (1) { - threadp->current_req = request = NULL; - request = NULL; - /* Get a request to process */ - threadp->status = _THREAD_WAITING; - pthread_mutex_lock(&request_queue.mutex); - while (!request_queue.head) { - pthread_cond_wait(&request_queue.cond, &request_queue.mutex); - } - request = request_queue.head; - if (request) - request_queue.head = request->next; - if (!request_queue.head) - request_queue.tailp = &request_queue.head; - pthread_mutex_unlock(&request_queue.mutex); - /* process the request */ - threadp->status = _THREAD_BUSY; - request->next = NULL; - threadp->current_req = request; - errno = 0; - if (!request->cancelled) { - switch (request->request_type) { - case _AIO_OP_OPEN: - squidaio_do_open(request); - break; - case _AIO_OP_READ: - squidaio_do_read(request); - break; - case _AIO_OP_WRITE: - squidaio_do_write(request); - break; - case _AIO_OP_CLOSE: - squidaio_do_close(request); - break; - case _AIO_OP_UNLINK: - squidaio_do_unlink(request); - break; - case _AIO_OP_TRUNCATE: - squidaio_do_truncate(request); - break; -#if AIO_OPENDIR /* Opendir not implemented yet */ - case _AIO_OP_OPENDIR: - squidaio_do_opendir(request); - break; -#endif - case _AIO_OP_STAT: - squidaio_do_stat(request); - break; - default: - request->ret = -1; - request->err = EINVAL; - break; - } - } else { /* cancelled */ - request->ret = -1; - request->err = EINTR; - } - threadp->status = _THREAD_DONE; - /* put the request in the done queue */ - pthread_mutex_lock(&done_queue.mutex); - *done_queue.tailp = request; - done_queue.tailp = &request->next; - pthread_mutex_unlock(&done_queue.mutex); - threadp->requests++; - } /* while forever */ - return NULL; -} /* squidaio_thread_loop */ - -static void -squidaio_queue_request(squidaio_request_t * request) -{ - static int high_start = 0; - debug(43, 9) ("squidaio_queue_request: %p type=%d result=%p\n", - request, request->request_type, request->resultp); - /* Mark it as not executed (failing result, no error) */ - request->ret = -1; - request->err = 0; - /* Internal housekeeping */ - request_queue_len += 1; - request->resultp->_data = request; - /* Play some tricks with the request_queue2 queue */ - request->next = NULL; - if (!request_queue2.head) { - if (pthread_mutex_trylock(&request_queue.mutex) == 0) { - /* Normal path */ - *request_queue.tailp = request; - request_queue.tailp = &request->next; - pthread_cond_signal(&request_queue.cond); - pthread_mutex_unlock(&request_queue.mutex); - } else { - /* Oops, the request queue is blocked, use request_queue2 */ - *request_queue2.tailp = request; - request_queue2.tailp = &request->next; - } - } else { - /* Secondary path. We have blocked requests to deal with */ - /* add the request to the chain */ - *request_queue2.tailp = request; - if (pthread_mutex_trylock(&request_queue.mutex) == 0) { - /* Ok, the queue is no longer blocked */ - *request_queue.tailp = request_queue2.head; - request_queue.tailp = &request->next; - pthread_cond_signal(&request_queue.cond); - pthread_mutex_unlock(&request_queue.mutex); - request_queue2.head = NULL; - request_queue2.tailp = &request_queue2.head; - } else { - /* still blocked, bump the blocked request chain */ - request_queue2.tailp = &request->next; - } - } - if (request_queue2.head) { - static int filter = 0; - static int filter_limit = 8; - if (++filter >= filter_limit) { - filter_limit += filter; - filter = 0; - debug(43, 1) ("squidaio_queue_request: WARNING - Queue congestion\n"); - } - } - /* Warn if out of threads */ - if (request_queue_len > MAGIC1) { - static int last_warn = 0; - static int queue_high, queue_low; - if (high_start == 0) { - high_start = squid_curtime; - queue_high = request_queue_len; - queue_low = request_queue_len; - } - if (request_queue_len > queue_high) - queue_high = request_queue_len; - if (request_queue_len < queue_low) - queue_low = request_queue_len; - if (squid_curtime >= (last_warn + 15) && - squid_curtime >= (high_start + 5)) { - debug(43, 1) ("squidaio_queue_request: WARNING - Disk I/O overloading\n"); - if (squid_curtime >= (high_start + 15)) - debug(43, 1) ("squidaio_queue_request: Queue Length: current=%d, high=%d, low=%d, duration=%ld\n", - request_queue_len, queue_high, queue_low, (long int) (squid_curtime - high_start)); - last_warn = squid_curtime; - } - } else { - high_start = 0; - } - /* Warn if seriously overloaded */ - if (request_queue_len > RIDICULOUS_LENGTH) { - debug(43, 0) ("squidaio_queue_request: Async request queue growing uncontrollably!\n"); - debug(43, 0) ("squidaio_queue_request: Syncing pending I/O operations.. (blocking)\n"); - squidaio_sync(); - debug(43, 0) ("squidaio_queue_request: Synced\n"); - } -} /* squidaio_queue_request */ - -static void -squidaio_cleanup_request(squidaio_request_t * requestp) -{ - squidaio_result_t *resultp = requestp->resultp; - int cancelled = requestp->cancelled; - - /* Free allocated structures and copy data back to user space if the */ - /* request hasn't been cancelled */ - switch (requestp->request_type) { - case _AIO_OP_STAT: - if (!cancelled && requestp->ret == 0) - xmemcpy(requestp->statp, requestp->tmpstatp, sizeof(struct stat)); - squidaio_xfree(requestp->tmpstatp, sizeof(struct stat)); - squidaio_xstrfree(requestp->path); - break; - case _AIO_OP_OPEN: - if (cancelled && requestp->ret >= 0) - /* The open() was cancelled but completed */ - close(requestp->ret); - squidaio_xstrfree(requestp->path); - break; - case _AIO_OP_CLOSE: - if (cancelled && requestp->ret < 0) - /* The close() was cancelled and never got executed */ - close(requestp->fd); - break; - case _AIO_OP_UNLINK: - case _AIO_OP_TRUNCATE: - case _AIO_OP_OPENDIR: - squidaio_xstrfree(requestp->path); - break; - case _AIO_OP_READ: - if (!cancelled && requestp->ret > 0) - xmemcpy(requestp->bufferp, requestp->tmpbufp, requestp->ret); - squidaio_xfree(requestp->tmpbufp, requestp->buflen); - break; - case _AIO_OP_WRITE: - squidaio_xfree(requestp->tmpbufp, requestp->buflen); - break; - default: - break; - } - if (resultp != NULL && !cancelled) { - resultp->aio_return = requestp->ret; - resultp->aio_errno = requestp->err; - } - memPoolFree(squidaio_request_pool, requestp); -} /* squidaio_cleanup_request */ - - -int -squidaio_cancel(squidaio_result_t * resultp) -{ - squidaio_request_t *request = resultp->_data; - - if (request && request->resultp == resultp) { - debug(43, 9) ("squidaio_cancel: %p type=%d result=%p\n", - request, request->request_type, request->resultp); - request->cancelled = 1; - request->resultp = NULL; - resultp->_data = NULL; - resultp->result_type = _AIO_OP_NONE; - return 0; - } - return 1; -} /* squidaio_cancel */ - - -int -squidaio_open(const char *path, int oflag, mode_t mode, squidaio_result_t * resultp) -{ - squidaio_request_t *requestp; - - if (!squidaio_initialised) - squidaio_init(); - requestp = memPoolAlloc(squidaio_request_pool); - requestp->path = (char *) squidaio_xstrdup(path); - requestp->oflag = oflag; - requestp->mode = mode; - requestp->resultp = resultp; - requestp->request_type = _AIO_OP_OPEN; - requestp->cancelled = 0; - resultp->result_type = _AIO_OP_OPEN; - - squidaio_queue_request(requestp); - return 0; -} - - -static void -squidaio_do_open(squidaio_request_t * requestp) -{ - requestp->ret = open(requestp->path, requestp->oflag, requestp->mode); - requestp->err = errno; -} - - -int -squidaio_read(int fd, char *bufp, int bufs, off_t offset, int whence, squidaio_result_t * resultp) -{ - squidaio_request_t *requestp; - - if (!squidaio_initialised) - squidaio_init(); - requestp = memPoolAlloc(squidaio_request_pool); - requestp->fd = fd; - requestp->bufferp = bufp; - requestp->tmpbufp = (char *) squidaio_xmalloc(bufs); - requestp->buflen = bufs; - requestp->offset = offset; - requestp->whence = whence; - requestp->resultp = resultp; - requestp->request_type = _AIO_OP_READ; - requestp->cancelled = 0; - resultp->result_type = _AIO_OP_READ; - - squidaio_queue_request(requestp); - return 0; -} - - -static void -squidaio_do_read(squidaio_request_t * requestp) -{ - lseek(requestp->fd, requestp->offset, requestp->whence); - requestp->ret = read(requestp->fd, requestp->tmpbufp, requestp->buflen); - requestp->err = errno; -} - - -int -squidaio_write(int fd, char *bufp, int bufs, off_t offset, int whence, squidaio_result_t * resultp) -{ - squidaio_request_t *requestp; - - if (!squidaio_initialised) - squidaio_init(); - requestp = memPoolAlloc(squidaio_request_pool); - requestp->fd = fd; - requestp->tmpbufp = (char *) squidaio_xmalloc(bufs); - xmemcpy(requestp->tmpbufp, bufp, bufs); - requestp->buflen = bufs; - requestp->offset = offset; - requestp->whence = whence; - requestp->resultp = resultp; - requestp->request_type = _AIO_OP_WRITE; - requestp->cancelled = 0; - resultp->result_type = _AIO_OP_WRITE; - - squidaio_queue_request(requestp); - return 0; -} - - -static void -squidaio_do_write(squidaio_request_t * requestp) -{ - requestp->ret = write(requestp->fd, requestp->tmpbufp, requestp->buflen); - requestp->err = errno; -} - - -int -squidaio_close(int fd, squidaio_result_t * resultp) -{ - squidaio_request_t *requestp; - - if (!squidaio_initialised) - squidaio_init(); - requestp = memPoolAlloc(squidaio_request_pool); - requestp->fd = fd; - requestp->resultp = resultp; - requestp->request_type = _AIO_OP_CLOSE; - requestp->cancelled = 0; - resultp->result_type = _AIO_OP_CLOSE; - - squidaio_queue_request(requestp); - return 0; -} - - -static void -squidaio_do_close(squidaio_request_t * requestp) -{ - requestp->ret = close(requestp->fd); - requestp->err = errno; -} - - -int -squidaio_stat(const char *path, struct stat *sb, squidaio_result_t * resultp) -{ - squidaio_request_t *requestp; - - if (!squidaio_initialised) - squidaio_init(); - requestp = memPoolAlloc(squidaio_request_pool); - requestp->path = (char *) squidaio_xstrdup(path); - requestp->statp = sb; - requestp->tmpstatp = (struct stat *) squidaio_xmalloc(sizeof(struct stat)); - requestp->resultp = resultp; - requestp->request_type = _AIO_OP_STAT; - requestp->cancelled = 0; - resultp->result_type = _AIO_OP_STAT; - - squidaio_queue_request(requestp); - return 0; -} - - -static void -squidaio_do_stat(squidaio_request_t * requestp) -{ - requestp->ret = stat(requestp->path, requestp->tmpstatp); - requestp->err = errno; -} - - -int -squidaio_unlink(const char *path, squidaio_result_t * resultp) -{ - squidaio_request_t *requestp; - - if (!squidaio_initialised) - squidaio_init(); - requestp = memPoolAlloc(squidaio_request_pool); - requestp->path = squidaio_xstrdup(path); - requestp->resultp = resultp; - requestp->request_type = _AIO_OP_UNLINK; - requestp->cancelled = 0; - resultp->result_type = _AIO_OP_UNLINK; - - squidaio_queue_request(requestp); - return 0; -} - - -static void -squidaio_do_unlink(squidaio_request_t * requestp) -{ - requestp->ret = unlink(requestp->path); - requestp->err = errno; -} - -int -squidaio_truncate(const char *path, off_t length, squidaio_result_t * resultp) -{ - squidaio_request_t *requestp; - - if (!squidaio_initialised) - squidaio_init(); - requestp = memPoolAlloc(squidaio_request_pool); - requestp->path = (char *) squidaio_xstrdup(path); - requestp->offset = length; - requestp->resultp = resultp; - requestp->request_type = _AIO_OP_TRUNCATE; - requestp->cancelled = 0; - resultp->result_type = _AIO_OP_TRUNCATE; - - squidaio_queue_request(requestp); - return 0; -} - - -static void -squidaio_do_truncate(squidaio_request_t * requestp) -{ - requestp->ret = truncate(requestp->path, requestp->offset); - requestp->err = errno; -} - - -#if AIO_OPENDIR -/* XXX squidaio_opendir NOT implemented yet.. */ - -int -squidaio_opendir(const char *path, squidaio_result_t * resultp) -{ - squidaio_request_t *requestp; - int len; - - if (!squidaio_initialised) - squidaio_init(); - requestp = memPoolAlloc(squidaio_request_pool); - resultp->result_type = _AIO_OP_OPENDIR; - return -1; -} - -static void -squidaio_do_opendir(squidaio_request_t * requestp) -{ - /* NOT IMPLEMENTED */ -} - -#endif - -static void -squidaio_poll_queues(void) -{ - /* kick "overflow" request queue */ - if (request_queue2.head && - pthread_mutex_trylock(&request_queue.mutex) == 0) { - *request_queue.tailp = request_queue2.head; - request_queue.tailp = request_queue2.tailp; - pthread_cond_signal(&request_queue.cond); - pthread_mutex_unlock(&request_queue.mutex); - request_queue2.head = NULL; - request_queue2.tailp = &request_queue2.head; - } - /* poll done queue */ - if (done_queue.head && pthread_mutex_trylock(&done_queue.mutex) == 0) { - struct squidaio_request_t *requests = done_queue.head; - done_queue.head = NULL; - done_queue.tailp = &done_queue.head; - pthread_mutex_unlock(&done_queue.mutex); - *done_requests.tailp = requests; - request_queue_len -= 1; - while (requests->next) { - requests = requests->next; - request_queue_len -= 1; - } - done_requests.tailp = &requests->next; - } -#if HAVE_SCHED_H - /* Give up the CPU to allow the threads to do their work */ - /* - * For Andres thoughts about yield(), see - * http://www.squid-cache.org/mail-archive/squid-dev/200012/0001.html - */ - if (done_queue.head || request_queue.head) -#ifndef _SQUID_SOLARIS_ - sched_yield(); -#else - yield(); -#endif -#endif -} - -squidaio_result_t * -squidaio_poll_done(void) -{ - squidaio_request_t *request; - squidaio_result_t *resultp; - int cancelled; - int polled = 0; - - AIO_REPOLL: - request = done_requests.head; - if (request == NULL && !polled) { - squidaio_poll_queues(); - polled = 1; - request = done_requests.head; - } - if (!request) { - return NULL; - } - debug(43, 9) ("squidaio_poll_done: %p type=%d result=%p\n", - request, request->request_type, request->resultp); - done_requests.head = request->next; - if (!done_requests.head) - done_requests.tailp = &done_requests.head; - resultp = request->resultp; - cancelled = request->cancelled; - squidaio_debug(request); - debug(43, 5) ("DONE: %d -> %d\n", request->ret, request->err); - squidaio_cleanup_request(request); - if (cancelled) - goto AIO_REPOLL; - return resultp; -} /* squidaio_poll_done */ - -int -squidaio_operations_pending(void) -{ - return request_queue_len + (done_requests.head ? 1 : 0); -} - -int -squidaio_sync(void) -{ - /* XXX This might take a while if the queue is large.. */ - do { - squidaio_poll_queues(); - } while (request_queue_len > 0); - return squidaio_operations_pending(); -} - -int -squidaio_get_queue_len(void) -{ - return request_queue_len; -} - -static void -squidaio_debug(squidaio_request_t * request) -{ - switch (request->request_type) { - case _AIO_OP_OPEN: - debug(43, 5) ("OPEN of %s to FD %d\n", request->path, request->ret); - break; - case _AIO_OP_READ: - debug(43, 5) ("READ on fd: %d\n", request->fd); - break; - case _AIO_OP_WRITE: - debug(43, 5) ("WRITE on fd: %d\n", request->fd); - break; - case _AIO_OP_CLOSE: - debug(43, 5) ("CLOSE of fd: %d\n", request->fd); - break; - case _AIO_OP_UNLINK: - debug(43, 5) ("UNLINK of %s\n", request->path); - break; - case _AIO_OP_TRUNCATE: - debug(43, 5) ("UNLINK of %s\n", request->path); - break; - default: - break; - } -} --- /dev/null Wed Feb 14 01:07:22 2007 +++ squid/src/fs/aufs/aiops.cc Wed Feb 14 01:07:42 2007 @@ -0,0 +1,900 @@ +/* + * $Id: aiops.cc,v 1.1.2.1 2002/10/12 12:21:42 rbcollins Exp $ + * + * DEBUG: section 43 AIOPS + * AUTHOR: Stewart Forster + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" +#include "store_asyncufs.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#if HAVE_SCHED_H +#include +#endif + +#define RIDICULOUS_LENGTH 4096 + +enum _squidaio_thread_status { + _THREAD_STARTING = 0, + _THREAD_WAITING, + _THREAD_BUSY, + _THREAD_FAILED, + _THREAD_DONE +}; +typedef enum _squidaio_thread_status squidaio_thread_status; + +typedef struct squidaio_request_t { + struct squidaio_request_t *next; + squidaio_request_type request_type; + int cancelled; + char *path; + int oflag; + mode_t mode; + int fd; + char *bufferp; + char *tmpbufp; + int buflen; + off_t offset; + int whence; + int ret; + int err; + struct stat *tmpstatp; + struct stat *statp; + squidaio_result_t *resultp; +} squidaio_request_t; + +typedef struct squidaio_request_queue_t { + pthread_mutex_t mutex; + pthread_cond_t cond; + squidaio_request_t *volatile head; + squidaio_request_t *volatile *volatile tailp; + unsigned long requests; + unsigned long blocked; /* main failed to lock the queue */ +} squidaio_request_queue_t; + +typedef struct squidaio_thread_t squidaio_thread_t; +struct squidaio_thread_t { + squidaio_thread_t *next; + pthread_t thread; + squidaio_thread_status status; + struct squidaio_request_t *current_req; + unsigned long requests; +}; + +static void squidaio_init(void); +static void squidaio_queue_request(squidaio_request_t *); +static void squidaio_cleanup_request(squidaio_request_t *); +static void *squidaio_thread_loop(void *); +static void squidaio_do_open(squidaio_request_t *); +static void squidaio_do_read(squidaio_request_t *); +static void squidaio_do_write(squidaio_request_t *); +static void squidaio_do_close(squidaio_request_t *); +static void squidaio_do_stat(squidaio_request_t *); +static void squidaio_do_unlink(squidaio_request_t *); +static void squidaio_do_truncate(squidaio_request_t *); +#if AIO_OPENDIR +static void *squidaio_do_opendir(squidaio_request_t *); +#endif +static void squidaio_debug(squidaio_request_t *); +static void squidaio_poll_queues(void); + +static squidaio_thread_t *threads = NULL; +static int squidaio_initialised = 0; + + +#define AIO_LARGE_BUFS 16384 +#define AIO_MEDIUM_BUFS AIO_LARGE_BUFS >> 1 +#define AIO_SMALL_BUFS AIO_LARGE_BUFS >> 2 +#define AIO_TINY_BUFS AIO_LARGE_BUFS >> 3 +#define AIO_MICRO_BUFS 128 + +static MemPool *squidaio_large_bufs = NULL; /* 16K */ +static MemPool *squidaio_medium_bufs = NULL; /* 8K */ +static MemPool *squidaio_small_bufs = NULL; /* 4K */ +static MemPool *squidaio_tiny_bufs = NULL; /* 2K */ +static MemPool *squidaio_micro_bufs = NULL; /* 128K */ + +static int request_queue_len = 0; +static MemPool *squidaio_request_pool = NULL; +static MemPool *squidaio_thread_pool = NULL; +static squidaio_request_queue_t request_queue; +static struct { + squidaio_request_t *head, **tailp; +} request_queue2 = { + + NULL, &request_queue2.head +}; +static squidaio_request_queue_t done_queue; +static struct { + squidaio_request_t *head, **tailp; +} done_requests = { + + NULL, &done_requests.head +}; +static pthread_attr_t globattr; +#if HAVE_SCHED_H +static struct sched_param globsched; +#endif +static pthread_t main_thread; + +static MemPool * +squidaio_get_pool(int size) +{ + MemPool *p; + if (size <= AIO_LARGE_BUFS) { + if (size <= AIO_MICRO_BUFS) + p = squidaio_micro_bufs; + else if (size <= AIO_TINY_BUFS) + p = squidaio_tiny_bufs; + else if (size <= AIO_SMALL_BUFS) + p = squidaio_small_bufs; + else if (size <= AIO_MEDIUM_BUFS) + p = squidaio_medium_bufs; + else + p = squidaio_large_bufs; + } else + p = NULL; + return p; +} + +static void * +squidaio_xmalloc(int size) +{ + void *p; + MemPool *pool; + + if ((pool = squidaio_get_pool(size)) != NULL) { + p = memPoolAlloc(pool); + } else + p = xmalloc(size); + + return p; +} + +static char * +squidaio_xstrdup(const char *str) +{ + char *p; + int len = strlen(str) + 1; + + p = (char *)squidaio_xmalloc(len); + strncpy(p, str, len); + + return p; +} + +static void +squidaio_xfree(void *p, int size) +{ + MemPool *pool; + + if ((pool = squidaio_get_pool(size)) != NULL) { + memPoolFree(pool, p); + } else + xfree(p); +} + +static void +squidaio_xstrfree(char *str) +{ + MemPool *pool; + int len = strlen(str) + 1; + + if ((pool = squidaio_get_pool(len)) != NULL) { + memPoolFree(pool, str); + } else + xfree(str); +} + +static void +squidaio_init(void) +{ + int i; + squidaio_thread_t *threadp; + + if (squidaio_initialised) + return; + + pthread_attr_init(&globattr); +#if HAVE_PTHREAD_ATTR_SETSCOPE + pthread_attr_setscope(&globattr, PTHREAD_SCOPE_SYSTEM); +#endif +#if HAVE_SCHED_H + globsched.sched_priority = 1; +#endif + main_thread = pthread_self(); +#if HAVE_SCHED_H && HAVE_PTHREAD_SETSCHEDPARAM + pthread_setschedparam(main_thread, SCHED_OTHER, &globsched); +#endif +#if HAVE_SCHED_H + globsched.sched_priority = 2; +#endif +#if HAVE_SCHED_H && HAVE_PTHREAD_ATTR_SETSCHEDPARAM + pthread_attr_setschedparam(&globattr, &globsched); +#endif + + /* Initialize request queue */ + if (pthread_mutex_init(&(request_queue.mutex), NULL)) + fatal("Failed to create mutex"); + if (pthread_cond_init(&(request_queue.cond), NULL)) + fatal("Failed to create condition variable"); + request_queue.head = NULL; + request_queue.tailp = &request_queue.head; + request_queue.requests = 0; + request_queue.blocked = 0; + + /* Initialize done queue */ + if (pthread_mutex_init(&(done_queue.mutex), NULL)) + fatal("Failed to create mutex"); + if (pthread_cond_init(&(done_queue.cond), NULL)) + fatal("Failed to create condition variable"); + done_queue.head = NULL; + done_queue.tailp = &done_queue.head; + done_queue.requests = 0; + done_queue.blocked = 0; + + /* Create threads and get them to sit in their wait loop */ + squidaio_thread_pool = memPoolCreate("aio_thread", sizeof(squidaio_thread_t)); + assert (NUMTHREADS); + for (i = 0; i < NUMTHREADS; i++) { + threadp = (squidaio_thread_t *)memPoolAlloc(squidaio_thread_pool); + threadp->status = _THREAD_STARTING; + threadp->current_req = NULL; + threadp->requests = 0; + threadp->next = threads; + threads = threadp; + if (pthread_create(&threadp->thread, &globattr, squidaio_thread_loop, threadp)) { + fprintf(stderr, "Thread creation failed\n"); + threadp->status = _THREAD_FAILED; + continue; + } + } + + /* Create request pool */ + squidaio_request_pool = memPoolCreate("aio_request", sizeof(squidaio_request_t)); + squidaio_large_bufs = memPoolCreate("squidaio_large_bufs", AIO_LARGE_BUFS); + squidaio_medium_bufs = memPoolCreate("squidaio_medium_bufs", AIO_MEDIUM_BUFS); + squidaio_small_bufs = memPoolCreate("squidaio_small_bufs", AIO_SMALL_BUFS); + squidaio_tiny_bufs = memPoolCreate("squidaio_tiny_bufs", AIO_TINY_BUFS); + squidaio_micro_bufs = memPoolCreate("squidaio_micro_bufs", AIO_MICRO_BUFS); + + squidaio_initialised = 1; +} + + +static void * +squidaio_thread_loop(void *ptr) +{ + squidaio_thread_t *threadp = (squidaio_thread_t *)ptr; + squidaio_request_t *request; + sigset_t newSig; + + /* + * Make sure to ignore signals which may possibly get sent to + * the parent squid thread. Causes havoc with mutex's and + * condition waits otherwise + */ + + sigemptyset(&newSig); + sigaddset(&newSig, SIGPIPE); + sigaddset(&newSig, SIGCHLD); +#ifdef _SQUID_LINUX_THREADS_ + sigaddset(&newSig, SIGQUIT); + sigaddset(&newSig, SIGTRAP); +#else + sigaddset(&newSig, SIGUSR1); + sigaddset(&newSig, SIGUSR2); +#endif + sigaddset(&newSig, SIGHUP); + sigaddset(&newSig, SIGTERM); + sigaddset(&newSig, SIGINT); + sigaddset(&newSig, SIGALRM); + pthread_sigmask(SIG_BLOCK, &newSig, NULL); + + while (1) { + threadp->current_req = request = NULL; + request = NULL; + /* Get a request to process */ + threadp->status = _THREAD_WAITING; + pthread_mutex_lock(&request_queue.mutex); + while (!request_queue.head) { + pthread_cond_wait(&request_queue.cond, &request_queue.mutex); + } + request = request_queue.head; + if (request) + request_queue.head = request->next; + if (!request_queue.head) + request_queue.tailp = &request_queue.head; + pthread_mutex_unlock(&request_queue.mutex); + /* process the request */ + threadp->status = _THREAD_BUSY; + request->next = NULL; + threadp->current_req = request; + errno = 0; + if (!request->cancelled) { + switch (request->request_type) { + case _AIO_OP_OPEN: + squidaio_do_open(request); + break; + case _AIO_OP_READ: + squidaio_do_read(request); + break; + case _AIO_OP_WRITE: + squidaio_do_write(request); + break; + case _AIO_OP_CLOSE: + squidaio_do_close(request); + break; + case _AIO_OP_UNLINK: + squidaio_do_unlink(request); + break; + case _AIO_OP_TRUNCATE: + squidaio_do_truncate(request); + break; +#if AIO_OPENDIR /* Opendir not implemented yet */ + case _AIO_OP_OPENDIR: + squidaio_do_opendir(request); + break; +#endif + case _AIO_OP_STAT: + squidaio_do_stat(request); + break; + default: + request->ret = -1; + request->err = EINVAL; + break; + } + } else { /* cancelled */ + request->ret = -1; + request->err = EINTR; + } + threadp->status = _THREAD_DONE; + /* put the request in the done queue */ + pthread_mutex_lock(&done_queue.mutex); + *done_queue.tailp = request; + done_queue.tailp = &request->next; + pthread_mutex_unlock(&done_queue.mutex); + threadp->requests++; + } /* while forever */ + return NULL; +} /* squidaio_thread_loop */ + +static void +squidaio_queue_request(squidaio_request_t * request) +{ + static int high_start = 0; + debug(43, 9) ("squidaio_queue_request: %p type=%d result=%p\n", + request, request->request_type, request->resultp); + /* Mark it as not executed (failing result, no error) */ + request->ret = -1; + request->err = 0; + /* Internal housekeeping */ + request_queue_len += 1; + request->resultp->_data = request; + /* Play some tricks with the request_queue2 queue */ + request->next = NULL; + if (!request_queue2.head) { + if (pthread_mutex_trylock(&request_queue.mutex) == 0) { + /* Normal path */ + *request_queue.tailp = request; + request_queue.tailp = &request->next; + pthread_cond_signal(&request_queue.cond); + pthread_mutex_unlock(&request_queue.mutex); + } else { + /* Oops, the request queue is blocked, use request_queue2 */ + *request_queue2.tailp = request; + request_queue2.tailp = &request->next; + } + } else { + /* Secondary path. We have blocked requests to deal with */ + /* add the request to the chain */ + *request_queue2.tailp = request; + if (pthread_mutex_trylock(&request_queue.mutex) == 0) { + /* Ok, the queue is no longer blocked */ + *request_queue.tailp = request_queue2.head; + request_queue.tailp = &request->next; + pthread_cond_signal(&request_queue.cond); + pthread_mutex_unlock(&request_queue.mutex); + request_queue2.head = NULL; + request_queue2.tailp = &request_queue2.head; + } else { + /* still blocked, bump the blocked request chain */ + request_queue2.tailp = &request->next; + } + } + if (request_queue2.head) { + static int filter = 0; + static int filter_limit = 8; + if (++filter >= filter_limit) { + filter_limit += filter; + filter = 0; + debug(43, 1) ("squidaio_queue_request: WARNING - Queue congestion\n"); + } + } + /* Warn if out of threads */ + if (request_queue_len > MAGIC1) { + static int last_warn = 0; + static int queue_high, queue_low; + if (high_start == 0) { + high_start = squid_curtime; + queue_high = request_queue_len; + queue_low = request_queue_len; + } + if (request_queue_len > queue_high) + queue_high = request_queue_len; + if (request_queue_len < queue_low) + queue_low = request_queue_len; + if (squid_curtime >= (last_warn + 15) && + squid_curtime >= (high_start + 5)) { + debug(43, 1) ("squidaio_queue_request: WARNING - Disk I/O overloading\n"); + if (squid_curtime >= (high_start + 15)) + debug(43, 1) ("squidaio_queue_request: Queue Length: current=%d, high=%d, low=%d, duration=%ld\n", + request_queue_len, queue_high, queue_low, (long int) (squid_curtime - high_start)); + last_warn = squid_curtime; + } + } else { + high_start = 0; + } + /* Warn if seriously overloaded */ + if (request_queue_len > RIDICULOUS_LENGTH) { + debug(43, 0) ("squidaio_queue_request: Async request queue growing uncontrollably!\n"); + debug(43, 0) ("squidaio_queue_request: Syncing pending I/O operations.. (blocking)\n"); + squidaio_sync(); + debug(43, 0) ("squidaio_queue_request: Synced\n"); + } +} /* squidaio_queue_request */ + +static void +squidaio_cleanup_request(squidaio_request_t * requestp) +{ + squidaio_result_t *resultp = requestp->resultp; + int cancelled = requestp->cancelled; + + /* Free allocated structures and copy data back to user space if the */ + /* request hasn't been cancelled */ + switch (requestp->request_type) { + case _AIO_OP_STAT: + if (!cancelled && requestp->ret == 0) + xmemcpy(requestp->statp, requestp->tmpstatp, sizeof(struct stat)); + squidaio_xfree(requestp->tmpstatp, sizeof(struct stat)); + squidaio_xstrfree(requestp->path); + break; + case _AIO_OP_OPEN: + if (cancelled && requestp->ret >= 0) + /* The open() was cancelled but completed */ + close(requestp->ret); + squidaio_xstrfree(requestp->path); + break; + case _AIO_OP_CLOSE: + if (cancelled && requestp->ret < 0) + /* The close() was cancelled and never got executed */ + close(requestp->fd); + break; + case _AIO_OP_UNLINK: + case _AIO_OP_TRUNCATE: + case _AIO_OP_OPENDIR: + squidaio_xstrfree(requestp->path); + break; + case _AIO_OP_READ: + if (!cancelled && requestp->ret > 0) + xmemcpy(requestp->bufferp, requestp->tmpbufp, requestp->ret); + squidaio_xfree(requestp->tmpbufp, requestp->buflen); + break; + case _AIO_OP_WRITE: + squidaio_xfree(requestp->tmpbufp, requestp->buflen); + break; + default: + break; + } + if (resultp != NULL && !cancelled) { + resultp->aio_return = requestp->ret; + resultp->aio_errno = requestp->err; + } + memPoolFree(squidaio_request_pool, requestp); +} /* squidaio_cleanup_request */ + + +int +squidaio_cancel(squidaio_result_t * resultp) +{ + squidaio_request_t *request = (squidaio_request_t *)resultp->_data; + + if (request && request->resultp == resultp) { + debug(43, 9) ("squidaio_cancel: %p type=%d result=%p\n", + request, request->request_type, request->resultp); + request->cancelled = 1; + request->resultp = NULL; + resultp->_data = NULL; + resultp->result_type = _AIO_OP_NONE; + return 0; + } + return 1; +} /* squidaio_cancel */ + + +int +squidaio_open(const char *path, int oflag, mode_t mode, squidaio_result_t * resultp) +{ + squidaio_request_t *requestp; + + if (!squidaio_initialised) + squidaio_init(); + requestp = (squidaio_request_t *)memPoolAlloc(squidaio_request_pool); + requestp->path = (char *) squidaio_xstrdup(path); + requestp->oflag = oflag; + requestp->mode = mode; + requestp->resultp = resultp; + requestp->request_type = _AIO_OP_OPEN; + requestp->cancelled = 0; + resultp->result_type = _AIO_OP_OPEN; + + squidaio_queue_request(requestp); + return 0; +} + + +static void +squidaio_do_open(squidaio_request_t * requestp) +{ + requestp->ret = open(requestp->path, requestp->oflag, requestp->mode); + requestp->err = errno; +} + + +int +squidaio_read(int fd, char *bufp, int bufs, off_t offset, int whence, squidaio_result_t * resultp) +{ + squidaio_request_t *requestp; + + if (!squidaio_initialised) + squidaio_init(); + requestp = (squidaio_request_t *)memPoolAlloc(squidaio_request_pool); + requestp->fd = fd; + requestp->bufferp = bufp; + requestp->tmpbufp = (char *) squidaio_xmalloc(bufs); + requestp->buflen = bufs; + requestp->offset = offset; + requestp->whence = whence; + requestp->resultp = resultp; + requestp->request_type = _AIO_OP_READ; + requestp->cancelled = 0; + resultp->result_type = _AIO_OP_READ; + + squidaio_queue_request(requestp); + return 0; +} + + +static void +squidaio_do_read(squidaio_request_t * requestp) +{ + lseek(requestp->fd, requestp->offset, requestp->whence); + requestp->ret = read(requestp->fd, requestp->tmpbufp, requestp->buflen); + requestp->err = errno; +} + + +int +squidaio_write(int fd, char *bufp, int bufs, off_t offset, int whence, squidaio_result_t * resultp) +{ + squidaio_request_t *requestp; + + if (!squidaio_initialised) + squidaio_init(); + requestp = (squidaio_request_t *)memPoolAlloc(squidaio_request_pool); + requestp->fd = fd; + requestp->tmpbufp = (char *) squidaio_xmalloc(bufs); + xmemcpy(requestp->tmpbufp, bufp, bufs); + requestp->buflen = bufs; + requestp->offset = offset; + requestp->whence = whence; + requestp->resultp = resultp; + requestp->request_type = _AIO_OP_WRITE; + requestp->cancelled = 0; + resultp->result_type = _AIO_OP_WRITE; + + squidaio_queue_request(requestp); + return 0; +} + + +static void +squidaio_do_write(squidaio_request_t * requestp) +{ + requestp->ret = write(requestp->fd, requestp->tmpbufp, requestp->buflen); + requestp->err = errno; +} + + +int +squidaio_close(int fd, squidaio_result_t * resultp) +{ + squidaio_request_t *requestp; + + if (!squidaio_initialised) + squidaio_init(); + requestp = (squidaio_request_t *)memPoolAlloc(squidaio_request_pool); + requestp->fd = fd; + requestp->resultp = resultp; + requestp->request_type = _AIO_OP_CLOSE; + requestp->cancelled = 0; + resultp->result_type = _AIO_OP_CLOSE; + + squidaio_queue_request(requestp); + return 0; +} + + +static void +squidaio_do_close(squidaio_request_t * requestp) +{ + requestp->ret = close(requestp->fd); + requestp->err = errno; +} + + +int +squidaio_stat(const char *path, struct stat *sb, squidaio_result_t * resultp) +{ + squidaio_request_t *requestp; + + if (!squidaio_initialised) + squidaio_init(); + requestp = (squidaio_request_t *)memPoolAlloc(squidaio_request_pool); + requestp->path = (char *) squidaio_xstrdup(path); + requestp->statp = sb; + requestp->tmpstatp = (struct stat *) squidaio_xmalloc(sizeof(struct stat)); + requestp->resultp = resultp; + requestp->request_type = _AIO_OP_STAT; + requestp->cancelled = 0; + resultp->result_type = _AIO_OP_STAT; + + squidaio_queue_request(requestp); + return 0; +} + + +static void +squidaio_do_stat(squidaio_request_t * requestp) +{ + requestp->ret = stat(requestp->path, requestp->tmpstatp); + requestp->err = errno; +} + + +int +squidaio_unlink(const char *path, squidaio_result_t * resultp) +{ + squidaio_request_t *requestp; + + if (!squidaio_initialised) + squidaio_init(); + requestp = (squidaio_request_t *)memPoolAlloc(squidaio_request_pool); + requestp->path = squidaio_xstrdup(path); + requestp->resultp = resultp; + requestp->request_type = _AIO_OP_UNLINK; + requestp->cancelled = 0; + resultp->result_type = _AIO_OP_UNLINK; + + squidaio_queue_request(requestp); + return 0; +} + + +static void +squidaio_do_unlink(squidaio_request_t * requestp) +{ + requestp->ret = unlink(requestp->path); + requestp->err = errno; +} + +int +squidaio_truncate(const char *path, off_t length, squidaio_result_t * resultp) +{ + squidaio_request_t *requestp; + + if (!squidaio_initialised) + squidaio_init(); + requestp = (squidaio_request_t *)memPoolAlloc(squidaio_request_pool); + requestp->path = (char *) squidaio_xstrdup(path); + requestp->offset = length; + requestp->resultp = resultp; + requestp->request_type = _AIO_OP_TRUNCATE; + requestp->cancelled = 0; + resultp->result_type = _AIO_OP_TRUNCATE; + + squidaio_queue_request(requestp); + return 0; +} + + +static void +squidaio_do_truncate(squidaio_request_t * requestp) +{ + requestp->ret = truncate(requestp->path, requestp->offset); + requestp->err = errno; +} + + +#if AIO_OPENDIR +/* XXX squidaio_opendir NOT implemented yet.. */ + +int +squidaio_opendir(const char *path, squidaio_result_t * resultp) +{ + squidaio_request_t *requestp; + int len; + + if (!squidaio_initialised) + squidaio_init(); + requestp = memPoolAlloc(squidaio_request_pool); + resultp->result_type = _AIO_OP_OPENDIR; + return -1; +} + +static void +squidaio_do_opendir(squidaio_request_t * requestp) +{ + /* NOT IMPLEMENTED */ +} + +#endif + +static void +squidaio_poll_queues(void) +{ + /* kick "overflow" request queue */ + if (request_queue2.head && + pthread_mutex_trylock(&request_queue.mutex) == 0) { + *request_queue.tailp = request_queue2.head; + request_queue.tailp = request_queue2.tailp; + pthread_cond_signal(&request_queue.cond); + pthread_mutex_unlock(&request_queue.mutex); + request_queue2.head = NULL; + request_queue2.tailp = &request_queue2.head; + } + /* poll done queue */ + if (done_queue.head && pthread_mutex_trylock(&done_queue.mutex) == 0) { + struct squidaio_request_t *requests = done_queue.head; + done_queue.head = NULL; + done_queue.tailp = &done_queue.head; + pthread_mutex_unlock(&done_queue.mutex); + *done_requests.tailp = requests; + request_queue_len -= 1; + while (requests->next) { + requests = requests->next; + request_queue_len -= 1; + } + done_requests.tailp = &requests->next; + } +#if HAVE_SCHED_H + /* Give up the CPU to allow the threads to do their work */ + /* + * For Andres thoughts about yield(), see + * http://www.squid-cache.org/mail-archive/squid-dev/200012/0001.html + */ + if (done_queue.head || request_queue.head) +#ifndef _SQUID_SOLARIS_ + sched_yield(); +#else + yield(); +#endif +#endif +} + +squidaio_result_t * +squidaio_poll_done(void) +{ + squidaio_request_t *request; + squidaio_result_t *resultp; + int cancelled; + int polled = 0; + + AIO_REPOLL: + request = done_requests.head; + if (request == NULL && !polled) { + squidaio_poll_queues(); + polled = 1; + request = done_requests.head; + } + if (!request) { + return NULL; + } + debug(43, 9) ("squidaio_poll_done: %p type=%d result=%p\n", + request, request->request_type, request->resultp); + done_requests.head = request->next; + if (!done_requests.head) + done_requests.tailp = &done_requests.head; + resultp = request->resultp; + cancelled = request->cancelled; + squidaio_debug(request); + debug(43, 5) ("DONE: %d -> %d\n", request->ret, request->err); + squidaio_cleanup_request(request); + if (cancelled) + goto AIO_REPOLL; + return resultp; +} /* squidaio_poll_done */ + +int +squidaio_operations_pending(void) +{ + return request_queue_len + (done_requests.head ? 1 : 0); +} + +int +squidaio_sync(void) +{ + /* XXX This might take a while if the queue is large.. */ + do { + squidaio_poll_queues(); + } while (request_queue_len > 0); + return squidaio_operations_pending(); +} + +int +squidaio_get_queue_len(void) +{ + return request_queue_len; +} + +static void +squidaio_debug(squidaio_request_t * request) +{ + switch (request->request_type) { + case _AIO_OP_OPEN: + debug(43, 5) ("OPEN of %s to FD %d\n", request->path, request->ret); + break; + case _AIO_OP_READ: + debug(43, 5) ("READ on fd: %d\n", request->fd); + break; + case _AIO_OP_WRITE: + debug(43, 5) ("WRITE on fd: %d\n", request->fd); + break; + case _AIO_OP_CLOSE: + debug(43, 5) ("CLOSE of fd: %d\n", request->fd); + break; + case _AIO_OP_UNLINK: + debug(43, 5) ("UNLINK of %s\n", request->path); + break; + case _AIO_OP_TRUNCATE: + debug(43, 5) ("UNLINK of %s\n", request->path); + break; + default: + break; + } +} --- squid/src/fs/aufs/async_io.c Wed Feb 14 01:07:42 2007 +++ /dev/null Wed Feb 14 01:07:22 2007 @@ -1,380 +0,0 @@ - -/* - * $Id$ - * - * DEBUG: section 32 Asynchronous Disk I/O - * AUTHOR: Pete Bentley - * AUTHOR: Stewart Forster - * - * SQUID Web Proxy Cache http://www.squid-cache.org/ - * ---------------------------------------------------------- - * - * Squid is the result of efforts by numerous individuals from - * the Internet community; see the CONTRIBUTORS file for full - * details. Many organizations have provided support for Squid's - * development; see the SPONSORS file for full details. Squid is - * Copyrighted (C) 2001 by the Regents of the University of - * California; see the COPYRIGHT file for full details. Squid - * incorporates software developed and/or copyrighted by other - * sources; see the CREDITS file for full details. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. - * - */ - -#include "squid.h" -#include "store_asyncufs.h" -#include "Store.h" - -#define _AIO_OPEN 0 -#define _AIO_READ 1 -#define _AIO_WRITE 2 -#define _AIO_CLOSE 3 -#define _AIO_UNLINK 4 -#define _AIO_TRUNCATE 4 -#define _AIO_OPENDIR 5 -#define _AIO_STAT 6 - -typedef struct squidaio_ctrl_t { - struct squidaio_ctrl_t *next; - int fd; - int operation; - AIOCB *done_handler; - void *done_handler_data; - squidaio_result_t result; - char *bufp; - FREE *free_func; - dlink_node node; -} squidaio_ctrl_t; - -static struct { - int open_start; - int open_finish; - int close_start; - int close_finish; - int cancel; - int write_start; - int write_finish; - int read_start; - int read_finish; - int stat_start; - int stat_finish; - int unlink_start; - int unlink_finish; - int check_callback; -} squidaio_counts; - -typedef struct squidaio_unlinkq_t { - char *path; - struct squidaio_unlinkq_t *next; -} squidaio_unlinkq_t; - -static dlink_list used_list; -static int initialised = 0; -static OBJH aioStats; -static MemPool *squidaio_ctrl_pool; -static void aioFDWasClosed(int fd); - -static void -aioFDWasClosed(int fd) -{ - if (fd_table[fd].flags.closing) - fd_close(fd); -} - -void -aioInit(void) -{ - if (initialised) - return; - squidaio_ctrl_pool = memPoolCreate("aio_ctrl", sizeof(squidaio_ctrl_t)); - cachemgrRegister("squidaio_counts", "Async IO Function Counters", - aioStats, 0, 1); - initialised = 1; - comm_quick_poll_required(); -} - -void -aioDone(void) -{ - memPoolDestroy(&squidaio_ctrl_pool); - initialised = 0; -} - -void -aioOpen(const char *path, int oflag, mode_t mode, AIOCB * callback, void *callback_data) -{ - squidaio_ctrl_t *ctrlp; - - assert(initialised); - squidaio_counts.open_start++; - ctrlp = memPoolAlloc(squidaio_ctrl_pool); - ctrlp->fd = -2; - ctrlp->done_handler = callback; - ctrlp->done_handler_data = cbdataReference(callback_data); - ctrlp->operation = _AIO_OPEN; - ctrlp->result.data = ctrlp; - squidaio_open(path, oflag, mode, &ctrlp->result); - dlinkAdd(ctrlp, &ctrlp->node, &used_list); - return; -} - -void -aioClose(int fd) -{ - squidaio_ctrl_t *ctrlp; - - assert(initialised); - squidaio_counts.close_start++; - aioCancel(fd); - ctrlp = memPoolAlloc(squidaio_ctrl_pool); - ctrlp->fd = fd; - ctrlp->done_handler = NULL; - ctrlp->done_handler_data = NULL; - ctrlp->operation = _AIO_CLOSE; - ctrlp->result.data = ctrlp; - squidaio_close(fd, &ctrlp->result); - dlinkAdd(ctrlp, &ctrlp->node, &used_list); - return; -} - -void -aioCancel(int fd) -{ - squidaio_ctrl_t *curr; - dlink_node *m, *next; - - assert(initialised); - squidaio_counts.cancel++; - for (m = used_list.head; m; m = next) { - next = m->next; - curr = m->data; - if (curr->fd != fd) - continue; - - squidaio_cancel(&curr->result); - - if (curr->done_handler) { - AIOCB *callback = curr->done_handler; - void *cbdata; - curr->done_handler = NULL; - debug(32, 2) ("this be aioCancel\n"); - if (cbdataReferenceValidDone(curr->done_handler_data, &cbdata)) - callback(fd, cbdata, -2, -2); - } - dlinkDelete(m, &used_list); - memPoolFree(squidaio_ctrl_pool, curr); - } -} - - -void -aioWrite(int fd, int offset, char *bufp, int len, AIOCB * callback, void *callback_data, FREE * free_func) -{ - squidaio_ctrl_t *ctrlp; - int seekmode; - - assert(initialised); - squidaio_counts.write_start++; - ctrlp = memPoolAlloc(squidaio_ctrl_pool); - ctrlp->fd = fd; - ctrlp->done_handler = callback; - ctrlp->done_handler_data = cbdataReference(callback_data); - ctrlp->operation = _AIO_WRITE; - ctrlp->bufp = bufp; - ctrlp->free_func = free_func; - if (offset >= 0) - seekmode = SEEK_SET; - else { - seekmode = SEEK_END; - offset = 0; - } - ctrlp->result.data = ctrlp; - squidaio_write(fd, bufp, len, offset, seekmode, &ctrlp->result); - dlinkAdd(ctrlp, &ctrlp->node, &used_list); -} /* aioWrite */ - - -void -aioRead(int fd, int offset, char *bufp, int len, AIOCB * callback, void *callback_data) -{ - squidaio_ctrl_t *ctrlp; - int seekmode; - - assert(initialised); - squidaio_counts.read_start++; - ctrlp = memPoolAlloc(squidaio_ctrl_pool); - ctrlp->fd = fd; - ctrlp->done_handler = callback; - ctrlp->done_handler_data = cbdataReference(callback_data); - ctrlp->operation = _AIO_READ; - if (offset >= 0) - seekmode = SEEK_SET; - else { - seekmode = SEEK_CUR; - offset = 0; - } - ctrlp->result.data = ctrlp; - squidaio_read(fd, bufp, len, offset, seekmode, &ctrlp->result); - dlinkAdd(ctrlp, &ctrlp->node, &used_list); - return; -} /* aioRead */ - -void -aioStat(char *path, struct stat *sb, AIOCB * callback, void *callback_data) -{ - squidaio_ctrl_t *ctrlp; - - assert(initialised); - squidaio_counts.stat_start++; - ctrlp = memPoolAlloc(squidaio_ctrl_pool); - ctrlp->fd = -2; - ctrlp->done_handler = callback; - ctrlp->done_handler_data = cbdataReference(callback_data); - ctrlp->operation = _AIO_STAT; - ctrlp->result.data = ctrlp; - squidaio_stat(path, sb, &ctrlp->result); - dlinkAdd(ctrlp, &ctrlp->node, &used_list); - return; -} /* aioStat */ - -void -aioUnlink(const char *path, AIOCB * callback, void *callback_data) -{ - squidaio_ctrl_t *ctrlp; - assert(initialised); - squidaio_counts.unlink_start++; - ctrlp = memPoolAlloc(squidaio_ctrl_pool); - ctrlp->fd = -2; - ctrlp->done_handler = callback; - ctrlp->done_handler_data = cbdataReference(callback_data); - ctrlp->operation = _AIO_UNLINK; - ctrlp->result.data = ctrlp; - squidaio_unlink(path, &ctrlp->result); - dlinkAdd(ctrlp, &ctrlp->node, &used_list); -} /* aioUnlink */ - -void -aioTruncate(const char *path, off_t length, AIOCB * callback, void *callback_data) -{ - squidaio_ctrl_t *ctrlp; - assert(initialised); - squidaio_counts.unlink_start++; - ctrlp = memPoolAlloc(squidaio_ctrl_pool); - ctrlp->fd = -2; - ctrlp->done_handler = callback; - ctrlp->done_handler_data = cbdataReference(callback_data); - ctrlp->operation = _AIO_TRUNCATE; - ctrlp->result.data = ctrlp; - squidaio_truncate(path, length, &ctrlp->result); - dlinkAdd(ctrlp, &ctrlp->node, &used_list); -} /* aioTruncate */ - - -int -aioCheckCallbacks(SwapDir * SD) -{ - squidaio_result_t *resultp; - squidaio_ctrl_t *ctrlp; - int retval = 0; - - assert(initialised); - squidaio_counts.check_callback++; - for (;;) { - if ((resultp = squidaio_poll_done()) == NULL) - break; - ctrlp = (squidaio_ctrl_t *) resultp->data; - switch (resultp->result_type){ - case _AIO_OP_NONE: - case _AIO_OP_TRUNCATE: - case _AIO_OP_OPENDIR: - break; - case _AIO_OP_OPEN: - ++squidaio_counts.open_finish; - break; - case _AIO_OP_READ: - ++squidaio_counts.read_finish; - break; - case _AIO_OP_WRITE: - ++squidaio_counts.write_finish; - break; - case _AIO_OP_CLOSE: - ++squidaio_counts.close_finish; - break; - case _AIO_OP_UNLINK: - ++squidaio_counts.unlink_finish; - break; - case _AIO_OP_STAT: - ++squidaio_counts.stat_finish; - break; - } - if (ctrlp == NULL) - continue; /* XXX Should not happen */ - dlinkDelete(&ctrlp->node, &used_list); - if (ctrlp->done_handler) { - AIOCB *callback = ctrlp->done_handler; - void *cbdata; - ctrlp->done_handler = NULL; - if (cbdataReferenceValidDone(ctrlp->done_handler_data, &cbdata)) { - retval = 1; /* Return that we've actually done some work */ - callback(ctrlp->fd, cbdata, - ctrlp->result.aio_return, ctrlp->result.aio_errno); - } - } - /* free data if requested to aioWrite() */ - if (ctrlp->free_func) - ctrlp->free_func(ctrlp->bufp); - if (ctrlp->operation == _AIO_CLOSE) - aioFDWasClosed(ctrlp->fd); - memPoolFree(squidaio_ctrl_pool, ctrlp); - } - return retval; -} - -void -aioStats(StoreEntry * sentry) -{ - storeAppendPrintf(sentry, "ASYNC IO Counters:\n"); - storeAppendPrintf(sentry, "Operation\t# Requests\tNumber serviced\n"); - storeAppendPrintf(sentry, "open\t%d\t%d\n", squidaio_counts.open_start,squidaio_counts.open_finish); - storeAppendPrintf(sentry, "close\t%d\t%d\n", squidaio_counts.close_start,squidaio_counts.close_finish); - storeAppendPrintf(sentry, "cancel\t%d\t-\n", squidaio_counts.cancel); - storeAppendPrintf(sentry, "write\t%d\t%d\n", squidaio_counts.write_start,squidaio_counts.write_finish); - storeAppendPrintf(sentry, "read\t%d\t%d\n", squidaio_counts.read_start,squidaio_counts.read_finish); - storeAppendPrintf(sentry, "stat\t%d\t%d\n", squidaio_counts.stat_start,squidaio_counts.stat_finish); - storeAppendPrintf(sentry, "unlink\t%d\t%d\n", squidaio_counts.unlink_start,squidaio_counts.unlink_finish); - storeAppendPrintf(sentry, "check_callback\t%d\t-\n", squidaio_counts.check_callback); - storeAppendPrintf(sentry, "queue\t%d\t-\n", squidaio_get_queue_len()); -} - -/* Flush all pending I/O */ -void -aioSync(SwapDir * SD) -{ - if (!initialised) - return; /* nothing to do then */ - /* Flush all pending operations */ - debug(32, 1) ("aioSync: flushing pending I/O operations\n"); - do { - aioCheckCallbacks(SD); - } while (squidaio_sync()); - debug(32, 1) ("aioSync: done\n"); -} - -int -aioQueueSize(void) -{ - return memPoolInUseCount(squidaio_ctrl_pool); -} --- /dev/null Wed Feb 14 01:07:22 2007 +++ squid/src/fs/aufs/async_io.cc Wed Feb 14 01:07:42 2007 @@ -0,0 +1,380 @@ + +/* + * $Id: async_io.cc,v 1.1.2.1 2002/10/12 12:21:42 rbcollins Exp $ + * + * DEBUG: section 32 Asynchronous Disk I/O + * AUTHOR: Pete Bentley + * AUTHOR: Stewart Forster + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" +#include "store_asyncufs.h" +#include "Store.h" + +#define _AIO_OPEN 0 +#define _AIO_READ 1 +#define _AIO_WRITE 2 +#define _AIO_CLOSE 3 +#define _AIO_UNLINK 4 +#define _AIO_TRUNCATE 4 +#define _AIO_OPENDIR 5 +#define _AIO_STAT 6 + +typedef struct squidaio_ctrl_t { + struct squidaio_ctrl_t *next; + int fd; + int operation; + AIOCB *done_handler; + void *done_handler_data; + squidaio_result_t result; + char *bufp; + FREE *free_func; + dlink_node node; +} squidaio_ctrl_t; + +static struct { + int open_start; + int open_finish; + int close_start; + int close_finish; + int cancel; + int write_start; + int write_finish; + int read_start; + int read_finish; + int stat_start; + int stat_finish; + int unlink_start; + int unlink_finish; + int check_callback; +} squidaio_counts; + +typedef struct squidaio_unlinkq_t { + char *path; + struct squidaio_unlinkq_t *next; +} squidaio_unlinkq_t; + +static dlink_list used_list; +static int initialised = 0; +static OBJH aioStats; +static MemPool *squidaio_ctrl_pool; +static void aioFDWasClosed(int fd); + +static void +aioFDWasClosed(int fd) +{ + if (fd_table[fd].flags.closing) + fd_close(fd); +} + +void +aioInit(void) +{ + if (initialised) + return; + squidaio_ctrl_pool = memPoolCreate("aio_ctrl", sizeof(squidaio_ctrl_t)); + cachemgrRegister("squidaio_counts", "Async IO Function Counters", + aioStats, 0, 1); + initialised = 1; + comm_quick_poll_required(); +} + +void +aioDone(void) +{ + memPoolDestroy(&squidaio_ctrl_pool); + initialised = 0; +} + +void +aioOpen(const char *path, int oflag, mode_t mode, AIOCB * callback, void *callback_data) +{ + squidaio_ctrl_t *ctrlp; + + assert(initialised); + squidaio_counts.open_start++; + ctrlp = (squidaio_ctrl_t *)memPoolAlloc(squidaio_ctrl_pool); + ctrlp->fd = -2; + ctrlp->done_handler = callback; + ctrlp->done_handler_data = cbdataReference(callback_data); + ctrlp->operation = _AIO_OPEN; + ctrlp->result.data = ctrlp; + squidaio_open(path, oflag, mode, &ctrlp->result); + dlinkAdd(ctrlp, &ctrlp->node, &used_list); + return; +} + +void +aioClose(int fd) +{ + squidaio_ctrl_t *ctrlp; + + assert(initialised); + squidaio_counts.close_start++; + aioCancel(fd); + ctrlp = (squidaio_ctrl_t *)memPoolAlloc(squidaio_ctrl_pool); + ctrlp->fd = fd; + ctrlp->done_handler = NULL; + ctrlp->done_handler_data = NULL; + ctrlp->operation = _AIO_CLOSE; + ctrlp->result.data = ctrlp; + squidaio_close(fd, &ctrlp->result); + dlinkAdd(ctrlp, &ctrlp->node, &used_list); + return; +} + +void +aioCancel(int fd) +{ + squidaio_ctrl_t *curr; + dlink_node *m, *next; + + assert(initialised); + squidaio_counts.cancel++; + for (m = used_list.head; m; m = next) { + next = m->next; + curr = (squidaio_ctrl_t *)m->data; + if (curr->fd != fd) + continue; + + squidaio_cancel(&curr->result); + + if (curr->done_handler) { + AIOCB *callback = curr->done_handler; + void *cbdata; + curr->done_handler = NULL; + debug(32, 2) ("this be aioCancel\n"); + if (cbdataReferenceValidDone(curr->done_handler_data, &cbdata)) + callback(fd, cbdata, -2, -2); + } + dlinkDelete(m, &used_list); + memPoolFree(squidaio_ctrl_pool, curr); + } +} + + +void +aioWrite(int fd, int offset, char *bufp, int len, AIOCB * callback, void *callback_data, FREE * free_func) +{ + squidaio_ctrl_t *ctrlp; + int seekmode; + + assert(initialised); + squidaio_counts.write_start++; + ctrlp = (squidaio_ctrl_t *)memPoolAlloc(squidaio_ctrl_pool); + ctrlp->fd = fd; + ctrlp->done_handler = callback; + ctrlp->done_handler_data = cbdataReference(callback_data); + ctrlp->operation = _AIO_WRITE; + ctrlp->bufp = bufp; + ctrlp->free_func = free_func; + if (offset >= 0) + seekmode = SEEK_SET; + else { + seekmode = SEEK_END; + offset = 0; + } + ctrlp->result.data = ctrlp; + squidaio_write(fd, bufp, len, offset, seekmode, &ctrlp->result); + dlinkAdd(ctrlp, &ctrlp->node, &used_list); +} /* aioWrite */ + + +void +aioRead(int fd, int offset, char *bufp, int len, AIOCB * callback, void *callback_data) +{ + squidaio_ctrl_t *ctrlp; + int seekmode; + + assert(initialised); + squidaio_counts.read_start++; + ctrlp = (squidaio_ctrl_t *)memPoolAlloc(squidaio_ctrl_pool); + ctrlp->fd = fd; + ctrlp->done_handler = callback; + ctrlp->done_handler_data = cbdataReference(callback_data); + ctrlp->operation = _AIO_READ; + if (offset >= 0) + seekmode = SEEK_SET; + else { + seekmode = SEEK_CUR; + offset = 0; + } + ctrlp->result.data = ctrlp; + squidaio_read(fd, bufp, len, offset, seekmode, &ctrlp->result); + dlinkAdd(ctrlp, &ctrlp->node, &used_list); + return; +} /* aioRead */ + +void +aioStat(char *path, struct stat *sb, AIOCB * callback, void *callback_data) +{ + squidaio_ctrl_t *ctrlp; + + assert(initialised); + squidaio_counts.stat_start++; + ctrlp = (squidaio_ctrl_t *)memPoolAlloc(squidaio_ctrl_pool); + ctrlp->fd = -2; + ctrlp->done_handler = callback; + ctrlp->done_handler_data = cbdataReference(callback_data); + ctrlp->operation = _AIO_STAT; + ctrlp->result.data = ctrlp; + squidaio_stat(path, sb, &ctrlp->result); + dlinkAdd(ctrlp, &ctrlp->node, &used_list); + return; +} /* aioStat */ + +void +aioUnlink(const char *path, AIOCB * callback, void *callback_data) +{ + squidaio_ctrl_t *ctrlp; + assert(initialised); + squidaio_counts.unlink_start++; + ctrlp = (squidaio_ctrl_t *)memPoolAlloc(squidaio_ctrl_pool); + ctrlp->fd = -2; + ctrlp->done_handler = callback; + ctrlp->done_handler_data = cbdataReference(callback_data); + ctrlp->operation = _AIO_UNLINK; + ctrlp->result.data = ctrlp; + squidaio_unlink(path, &ctrlp->result); + dlinkAdd(ctrlp, &ctrlp->node, &used_list); +} /* aioUnlink */ + +void +aioTruncate(const char *path, off_t length, AIOCB * callback, void *callback_data) +{ + squidaio_ctrl_t *ctrlp; + assert(initialised); + squidaio_counts.unlink_start++; + ctrlp = (squidaio_ctrl_t *)memPoolAlloc(squidaio_ctrl_pool); + ctrlp->fd = -2; + ctrlp->done_handler = callback; + ctrlp->done_handler_data = cbdataReference(callback_data); + ctrlp->operation = _AIO_TRUNCATE; + ctrlp->result.data = ctrlp; + squidaio_truncate(path, length, &ctrlp->result); + dlinkAdd(ctrlp, &ctrlp->node, &used_list); +} /* aioTruncate */ + + +int +aioCheckCallbacks(SwapDir * SD) +{ + squidaio_result_t *resultp; + squidaio_ctrl_t *ctrlp; + int retval = 0; + + assert(initialised); + squidaio_counts.check_callback++; + for (;;) { + if ((resultp = squidaio_poll_done()) == NULL) + break; + ctrlp = (squidaio_ctrl_t *) resultp->data; + switch (resultp->result_type){ + case _AIO_OP_NONE: + case _AIO_OP_TRUNCATE: + case _AIO_OP_OPENDIR: + break; + case _AIO_OP_OPEN: + ++squidaio_counts.open_finish; + break; + case _AIO_OP_READ: + ++squidaio_counts.read_finish; + break; + case _AIO_OP_WRITE: + ++squidaio_counts.write_finish; + break; + case _AIO_OP_CLOSE: + ++squidaio_counts.close_finish; + break; + case _AIO_OP_UNLINK: + ++squidaio_counts.unlink_finish; + break; + case _AIO_OP_STAT: + ++squidaio_counts.stat_finish; + break; + } + if (ctrlp == NULL) + continue; /* XXX Should not happen */ + dlinkDelete(&ctrlp->node, &used_list); + if (ctrlp->done_handler) { + AIOCB *callback = ctrlp->done_handler; + void *cbdata; + ctrlp->done_handler = NULL; + if (cbdataReferenceValidDone(ctrlp->done_handler_data, &cbdata)) { + retval = 1; /* Return that we've actually done some work */ + callback(ctrlp->fd, cbdata, + ctrlp->result.aio_return, ctrlp->result.aio_errno); + } + } + /* free data if requested to aioWrite() */ + if (ctrlp->free_func) + ctrlp->free_func(ctrlp->bufp); + if (ctrlp->operation == _AIO_CLOSE) + aioFDWasClosed(ctrlp->fd); + memPoolFree(squidaio_ctrl_pool, ctrlp); + } + return retval; +} + +void +aioStats(StoreEntry * sentry) +{ + storeAppendPrintf(sentry, "ASYNC IO Counters:\n"); + storeAppendPrintf(sentry, "Operation\t# Requests\tNumber serviced\n"); + storeAppendPrintf(sentry, "open\t%d\t%d\n", squidaio_counts.open_start,squidaio_counts.open_finish); + storeAppendPrintf(sentry, "close\t%d\t%d\n", squidaio_counts.close_start,squidaio_counts.close_finish); + storeAppendPrintf(sentry, "cancel\t%d\t-\n", squidaio_counts.cancel); + storeAppendPrintf(sentry, "write\t%d\t%d\n", squidaio_counts.write_start,squidaio_counts.write_finish); + storeAppendPrintf(sentry, "read\t%d\t%d\n", squidaio_counts.read_start,squidaio_counts.read_finish); + storeAppendPrintf(sentry, "stat\t%d\t%d\n", squidaio_counts.stat_start,squidaio_counts.stat_finish); + storeAppendPrintf(sentry, "unlink\t%d\t%d\n", squidaio_counts.unlink_start,squidaio_counts.unlink_finish); + storeAppendPrintf(sentry, "check_callback\t%d\t-\n", squidaio_counts.check_callback); + storeAppendPrintf(sentry, "queue\t%d\t-\n", squidaio_get_queue_len()); +} + +/* Flush all pending I/O */ +void +aioSync(SwapDir * SD) +{ + if (!initialised) + return; /* nothing to do then */ + /* Flush all pending operations */ + debug(32, 1) ("aioSync: flushing pending I/O operations\n"); + do { + aioCheckCallbacks(SD); + } while (squidaio_sync()); + debug(32, 1) ("aioSync: done\n"); +} + +int +aioQueueSize(void) +{ + return memPoolInUseCount(squidaio_ctrl_pool); +} --- squid/src/fs/aufs/store_dir_aufs.c Wed Feb 14 01:07:42 2007 +++ /dev/null Wed Feb 14 01:07:22 2007 @@ -1,251 +0,0 @@ - -/* - * $Id$ - * - * DEBUG: section 47 Store Directory Routines - * AUTHOR: Duane Wessels - * - * SQUID Web Proxy Cache http://www.squid-cache.org/ - * ---------------------------------------------------------- - * - * Squid is the result of efforts by numerous individuals from - * the Internet community; see the CONTRIBUTORS file for full - * details. Many organizations have provided support for Squid's - * development; see the SPONSORS file for full details. Squid is - * Copyrighted (C) 2001 by the Regents of the University of - * California; see the COPYRIGHT file for full details. Squid - * incorporates software developed and/or copyrighted by other - * sources; see the CREDITS file for full details. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. - * - */ - -#include "squid.h" -#include "Store.h" - -#include "store_asyncufs.h" -#include "ufscommon.h" - -MemPool *squidaio_state_pool = NULL; -MemPool *aufs_qread_pool = NULL; -MemPool *aufs_qwrite_pool = NULL; -static int asyncufs_initialised = 0; - -static STDUMP storeAufsDirDump; -static STCHECKOBJ storeAufsDirCheckObj; -static void storeAufsDirIOUnlinkFile(char *path); - - -/* The MAIN externally visible function */ -STSETUP storeFsSetup_aufs; - -/* - * storeAufsDirCheckObj - * - * This routine is called by storeDirSelectSwapDir to see if the given - * object is able to be stored on this filesystem. AUFS filesystems will - * happily store anything as long as the LRU time isn't too small. - */ -int -storeAufsDirCheckObj(SwapDir * SD, const StoreEntry * e) -{ - int loadav; - int ql; - -#if OLD_UNUSED_CODE - if (storeAufsDirExpiredReferenceAge(SD) < 300) { - debug(47, 3) ("storeAufsDirCheckObj: NO: LRU Age = %d\n", - storeAufsDirExpiredReferenceAge(SD)); - /* store_check_cachable_hist.no.lru_age_too_low++; */ - return -1; - } -#endif - ql = aioQueueSize(); - if (ql == 0) - loadav = 0; - loadav = ql * 1000 / MAGIC1; - debug(47, 9) ("storeAufsDirCheckObj: load=%d\n", loadav); - return loadav; -} - -void -storeAufsDirIOUnlinkFile(char *path) -{ -#if USE_TRUNCATE_NOT_UNLINK - aioTruncate(path, NULL, NULL); -#else - aioUnlink(path, NULL, NULL); -#endif -} - -/* ========== LOCAL FUNCTIONS ABOVE, GLOBAL FUNCTIONS BELOW ========== */ - -static struct cache_dir_option options[] = -{ -#if NOT_YET_DONE - {"L1", storeAufsDirParseL1, storeAufsDirDumpL1}, - {"L2", storeAufsDirParseL2, storeAufsDirDumpL2}, -#endif - {NULL, NULL} -}; - -/* - * storeAufsDirReconfigure - * - * This routine is called when the given swapdir needs reconfiguring - */ -static void -storeAufsDirReconfigure(SwapDir * sd, int index, char *path) -{ - int i; - int size; - int l1; - int l2; - - i = GetInteger(); - size = i << 10; /* Mbytes to kbytes */ - if (size <= 0) - fatal("storeAufsDirReconfigure: invalid size value"); - i = GetInteger(); - l1 = i; - if (l1 <= 0) - fatal("storeAufsDirReconfigure: invalid level 1 directories value"); - i = GetInteger(); - l2 = i; - if (l2 <= 0) - fatal("storeAufsDirReconfigure: invalid level 2 directories value"); - - /* just reconfigure it */ - if (size == sd->max_size) - debug(3, 1) ("Cache dir '%s' size remains unchanged at %d KB\n", - path, size); - else - debug(3, 1) ("Cache dir '%s' size changed to %d KB\n", - path, size); - sd->max_size = size; - - parse_cachedir_options(sd, options, 0); - - return; -} - -void -storeAufsDirDump(StoreEntry * entry, SwapDir * s) -{ - commonUfsDirDump (entry, s); - dump_cachedir_options(entry, options, s); -} - -/* - * storeAufsDirParse * - * Called when a *new* fs is being setup. - */ -static void -storeAufsDirParse(SwapDir * sd, int index, char *path) -{ - int i; - int size; - int l1; - int l2; - squidufsinfo_t *aioinfo; - - i = GetInteger(); - size = i << 10; /* Mbytes to kbytes */ - if (size <= 0) - fatal("storeAufsDirParse: invalid size value"); - i = GetInteger(); - l1 = i; - if (l1 <= 0) - fatal("storeAufsDirParse: invalid level 1 directories value"); - i = GetInteger(); - l2 = i; - if (l2 <= 0) - fatal("storeAufsDirParse: invalid level 2 directories value"); - - aioinfo = xmalloc(sizeof(squidufsinfo_t)); - if (aioinfo == NULL) - fatal("storeAufsDirParse: couldn't xmalloc() squidufsinfo_t!\n"); - - sd->index = index; - sd->path = xstrdup(path); - sd->max_size = size; - sd->fsdata = aioinfo; - aioinfo->l1 = l1; - aioinfo->l2 = l2; - aioinfo->swaplog_fd = -1; - aioinfo->map = NULL; /* Debugging purposes */ - aioinfo->suggest = 0; - aioinfo->io.storeDirUnlinkFile = storeAufsDirIOUnlinkFile; - sd->init = commonUfsDirInit; - sd->newfs = commonUfsDirNewfs; - sd->dump = storeAufsDirDump; - sd->freefs = commonUfsDirFree; - sd->dblcheck = commonUfsCleanupDoubleCheck; - sd->statfs = commonUfsDirStats; - sd->maintainfs = commonUfsDirMaintain; - sd->checkobj = storeAufsDirCheckObj; - sd->refobj = commonUfsDirRefObj; - sd->unrefobj = commonUfsDirUnrefObj; - sd->callback = aioCheckCallbacks; - sd->sync = aioSync; - sd->obj.create = storeAufsCreate; - sd->obj.open = storeAufsOpen; - sd->obj.close = storeAufsClose; - sd->obj.read = storeAufsRead; - sd->obj.write = storeAufsWrite; - sd->obj.unlink = storeAufsUnlink; - sd->log.open = commonUfsDirOpenSwapLog; - sd->log.close = commonUfsDirCloseSwapLog; - sd->log.write = commonUfsDirSwapLog; - sd->log.clean.start = commonUfsDirWriteCleanStart; - sd->log.clean.nextentry = commonUfsDirCleanLogNextEntry; - sd->log.clean.done = commonUfsDirWriteCleanDone; - - parse_cachedir_options(sd, options, 0); - - /* Initialise replacement policy stuff */ - sd->repl = createRemovalPolicy(Config.replPolicy); -} - -/* - * Initial setup / end destruction - */ -static void -storeAufsDirDone(void) -{ - aioDone(); - memPoolDestroy(&squidaio_state_pool); - memPoolDestroy(&aufs_qread_pool); - memPoolDestroy(&aufs_qwrite_pool); - asyncufs_initialised = 0; -} - -void -storeFsSetup_aufs(storefs_entry_t * storefs) -{ - assert(!asyncufs_initialised); - storefs->parsefunc = storeAufsDirParse; - storefs->reconfigurefunc = storeAufsDirReconfigure; - storefs->donefunc = storeAufsDirDone; - squidaio_state_pool = memPoolCreate("AUFS IO State data", sizeof(squidaiostate_t)); - aufs_qread_pool = memPoolCreate("AUFS Queued read data", - sizeof(queued_read)); - aufs_qwrite_pool = memPoolCreate("AUFS Queued write data", - sizeof(queued_write)); - - asyncufs_initialised = 1; - aioInit(); -} --- /dev/null Wed Feb 14 01:07:22 2007 +++ squid/src/fs/aufs/store_dir_aufs.cc Wed Feb 14 01:07:42 2007 @@ -0,0 +1,251 @@ + +/* + * $Id: store_dir_aufs.cc,v 1.1.2.1 2002/10/12 12:21:43 rbcollins Exp $ + * + * DEBUG: section 47 Store Directory Routines + * AUTHOR: Duane Wessels + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" +#include "Store.h" + +#include "store_asyncufs.h" +#include "ufscommon.h" + +MemPool *squidaio_state_pool = NULL; +MemPool *aufs_qread_pool = NULL; +MemPool *aufs_qwrite_pool = NULL; +static int asyncufs_initialised = 0; + +static STDUMP storeAufsDirDump; +static STCHECKOBJ storeAufsDirCheckObj; +static void storeAufsDirIOUnlinkFile(char *path); + + +/* The MAIN externally visible function */ +STSETUP storeFsSetup_aufs; + +/* + * storeAufsDirCheckObj + * + * This routine is called by storeDirSelectSwapDir to see if the given + * object is able to be stored on this filesystem. AUFS filesystems will + * happily store anything as long as the LRU time isn't too small. + */ +int +storeAufsDirCheckObj(SwapDir * SD, const StoreEntry * e) +{ + int loadav; + int ql; + +#if OLD_UNUSED_CODE + if (storeAufsDirExpiredReferenceAge(SD) < 300) { + debug(47, 3) ("storeAufsDirCheckObj: NO: LRU Age = %d\n", + storeAufsDirExpiredReferenceAge(SD)); + /* store_check_cachable_hist.no.lru_age_too_low++; */ + return -1; + } +#endif + ql = aioQueueSize(); + if (ql == 0) + loadav = 0; + loadav = ql * 1000 / MAGIC1; + debug(47, 9) ("storeAufsDirCheckObj: load=%d\n", loadav); + return loadav; +} + +void +storeAufsDirIOUnlinkFile(char *path) +{ +#if USE_TRUNCATE_NOT_UNLINK + aioTruncate(path, NULL, NULL); +#else + aioUnlink(path, NULL, NULL); +#endif +} + +/* ========== LOCAL FUNCTIONS ABOVE, GLOBAL FUNCTIONS BELOW ========== */ + +static struct cache_dir_option options[] = +{ +#if NOT_YET_DONE + {"L1", storeAufsDirParseL1, storeAufsDirDumpL1}, + {"L2", storeAufsDirParseL2, storeAufsDirDumpL2}, +#endif + {NULL, NULL} +}; + +/* + * storeAufsDirReconfigure + * + * This routine is called when the given swapdir needs reconfiguring + */ +static void +storeAufsDirReconfigure(SwapDir * sd, int index, char *path) +{ + int i; + int size; + int l1; + int l2; + + i = GetInteger(); + size = i << 10; /* Mbytes to kbytes */ + if (size <= 0) + fatal("storeAufsDirReconfigure: invalid size value"); + i = GetInteger(); + l1 = i; + if (l1 <= 0) + fatal("storeAufsDirReconfigure: invalid level 1 directories value"); + i = GetInteger(); + l2 = i; + if (l2 <= 0) + fatal("storeAufsDirReconfigure: invalid level 2 directories value"); + + /* just reconfigure it */ + if (size == sd->max_size) + debug(3, 1) ("Cache dir '%s' size remains unchanged at %d KB\n", + path, size); + else + debug(3, 1) ("Cache dir '%s' size changed to %d KB\n", + path, size); + sd->max_size = size; + + parse_cachedir_options(sd, options, 0); + + return; +} + +void +storeAufsDirDump(StoreEntry * entry, SwapDir * s) +{ + commonUfsDirDump (entry, s); + dump_cachedir_options(entry, options, s); +} + +/* + * storeAufsDirParse * + * Called when a *new* fs is being setup. + */ +static void +storeAufsDirParse(SwapDir * sd, int index, char *path) +{ + int i; + int size; + int l1; + int l2; + squidufsinfo_t *aioinfo; + + i = GetInteger(); + size = i << 10; /* Mbytes to kbytes */ + if (size <= 0) + fatal("storeAufsDirParse: invalid size value"); + i = GetInteger(); + l1 = i; + if (l1 <= 0) + fatal("storeAufsDirParse: invalid level 1 directories value"); + i = GetInteger(); + l2 = i; + if (l2 <= 0) + fatal("storeAufsDirParse: invalid level 2 directories value"); + + aioinfo = (squidufsinfo_t *)xmalloc(sizeof(squidufsinfo_t)); + if (aioinfo == NULL) + fatal("storeAufsDirParse: couldn't xmalloc() squidufsinfo_t!\n"); + + sd->index = index; + sd->path = xstrdup(path); + sd->max_size = size; + sd->fsdata = aioinfo; + aioinfo->l1 = l1; + aioinfo->l2 = l2; + aioinfo->swaplog_fd = -1; + aioinfo->map = NULL; /* Debugging purposes */ + aioinfo->suggest = 0; + aioinfo->io.storeDirUnlinkFile = storeAufsDirIOUnlinkFile; + sd->init = commonUfsDirInit; + sd->newfs = commonUfsDirNewfs; + sd->dump = storeAufsDirDump; + sd->freefs = commonUfsDirFree; + sd->dblcheck = commonUfsCleanupDoubleCheck; + sd->statfs = commonUfsDirStats; + sd->maintainfs = commonUfsDirMaintain; + sd->checkobj = storeAufsDirCheckObj; + sd->refobj = commonUfsDirRefObj; + sd->unrefobj = commonUfsDirUnrefObj; + sd->callback = aioCheckCallbacks; + sd->sync = aioSync; + sd->obj.create = storeAufsCreate; + sd->obj.open = storeAufsOpen; + sd->obj.close = storeAufsClose; + sd->obj.read = storeAufsRead; + sd->obj.write = storeAufsWrite; + sd->obj.unlink = storeAufsUnlink; + sd->log.open = commonUfsDirOpenSwapLog; + sd->log.close = commonUfsDirCloseSwapLog; + sd->log.write = commonUfsDirSwapLog; + sd->log.clean.start = commonUfsDirWriteCleanStart; + sd->log.clean.nextentry = commonUfsDirCleanLogNextEntry; + sd->log.clean.done = commonUfsDirWriteCleanDone; + + parse_cachedir_options(sd, options, 0); + + /* Initialise replacement policy stuff */ + sd->repl = createRemovalPolicy(Config.replPolicy); +} + +/* + * Initial setup / end destruction + */ +static void +storeAufsDirDone(void) +{ + aioDone(); + memPoolDestroy(&squidaio_state_pool); + memPoolDestroy(&aufs_qread_pool); + memPoolDestroy(&aufs_qwrite_pool); + asyncufs_initialised = 0; +} + +void +storeFsSetup_aufs(storefs_entry_t * storefs) +{ + assert(!asyncufs_initialised); + storefs->parsefunc = storeAufsDirParse; + storefs->reconfigurefunc = storeAufsDirReconfigure; + storefs->donefunc = storeAufsDirDone; + squidaio_state_pool = memPoolCreate("AUFS IO State data", sizeof(squidaiostate_t)); + aufs_qread_pool = memPoolCreate("AUFS Queued read data", + sizeof(queued_read)); + aufs_qwrite_pool = memPoolCreate("AUFS Queued write data", + sizeof(queued_write)); + + asyncufs_initialised = 1; + aioInit(); +} --- squid/src/fs/aufs/store_io_aufs.c Wed Feb 14 01:07:42 2007 +++ /dev/null Wed Feb 14 01:07:22 2007 @@ -1,444 +0,0 @@ - -/* - * DEBUG 79 - */ - -#include "squid.h" -#include "store_asyncufs.h" -#include "Store.h" -#include "ufscommon.h" - -#if ASYNC_READ -static AIOCB storeAufsReadDone; -#else -static DRCB storeAufsReadDone; -#endif -#if ASYNC_WRITE -static AIOCB storeAufsWriteDone; -#else -static DWCB storeAufsWriteDone; -#endif -static void storeAufsIOCallback(storeIOState * sio, int errflag); -static AIOCB storeAufsOpenDone; -static int storeAufsSomethingPending(storeIOState *); -static int storeAufsKickWriteQueue(storeIOState * sio); -static CBDUNL storeAufsIOFreeEntry; - -CBDATA_TYPE(storeIOState); - -/* === PUBLIC =========================================================== */ - -/* open for reading */ -storeIOState * -storeAufsOpen(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, - STIOCB * callback, void *callback_data) -{ - sfileno f = e->swap_filen; - char *path = commonUfsDirFullPath(SD, f, NULL); - storeIOState *sio; -#if !ASYNC_OPEN - int fd; -#endif - debug(79, 3) ("storeAufsOpen: fileno %08X\n", f); - /* - * we should detect some 'too many files open' condition and return - * NULL here. - */ -#ifdef MAGIC2 - if (aioQueueSize() > MAGIC2) - return NULL; -#endif -#if !ASYNC_OPEN - fd = file_open(path, O_RDONLY | O_BINARY); - if (fd < 0) { - debug(79, 3) ("storeAufsOpen: got failure (%d)\n", errno); - return NULL; - } -#endif - CBDATA_INIT_TYPE_FREECB(storeIOState, storeAufsIOFreeEntry); - sio = cbdataAlloc(storeIOState); - sio->fsstate = memPoolAlloc(squidaio_state_pool); - ((squidaiostate_t *) (sio->fsstate))->fd = -1; - ((squidaiostate_t *) (sio->fsstate))->flags.opening = 1; - sio->swap_filen = f; - sio->swap_dirn = SD->index; - sio->mode = O_RDONLY | O_BINARY; - sio->callback = callback; - sio->callback_data = cbdataReference(callback_data); - sio->e = e; - Opening_FD++; -#if ASYNC_OPEN - aioOpen(path, O_RDONLY | O_BINARY, 0644, storeAufsOpenDone, sio); -#else - storeAufsOpenDone(fd, sio, fd, 0); -#endif - return sio; -} - -/* open for creating */ -storeIOState * -storeAufsCreate(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, STIOCB * callback, void *callback_data) -{ - char *path; - storeIOState *sio; - sfileno filn; - sdirno dirn; -#if !ASYNC_CREATE - int fd; -#endif - - /* Allocate a number */ - dirn = SD->index; - filn = commonUfsDirMapBitAllocate(SD); - path = commonUfsDirFullPath(SD, filn, NULL); - - debug(79, 3) ("storeAufsCreate: fileno %08X\n", filn); - /* - * we should detect some 'too many files open' condition and return - * NULL here. - */ -#ifdef MAGIC2 - if (aioQueueSize() > MAGIC2) - return NULL; -#endif -#if !ASYNC_CREATE - fd = file_open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY); - if (fd < 0) { - debug(79, 3) ("storeAufsCreate: got failure (%d)\n", errno); - return NULL; - } -#endif - CBDATA_INIT_TYPE_FREECB(storeIOState, storeAufsIOFreeEntry); - sio = cbdataAlloc(storeIOState); - sio->fsstate = memPoolAlloc(squidaio_state_pool); - ((squidaiostate_t *) (sio->fsstate))->fd = -1; - ((squidaiostate_t *) (sio->fsstate))->flags.opening = 1; - sio->swap_filen = filn; - sio->swap_dirn = dirn; - sio->mode = O_WRONLY | O_BINARY; - sio->callback = callback; - sio->callback_data = cbdataReference(callback_data); - sio->e = (StoreEntry *) e; - Opening_FD++; -#if ASYNC_CREATE - aioOpen(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644, storeAufsOpenDone, sio); -#else - storeAufsOpenDone(fd, sio, fd, 0); -#endif - - /* now insert into the replacement policy */ - commonUfsDirReplAdd(SD, e); - return sio; - -} - - - -/* Close */ -void -storeAufsClose(SwapDir * SD, storeIOState * sio) -{ - squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; - debug(79, 3) ("storeAufsClose: dirno %d, fileno %08X, FD %d\n", - sio->swap_dirn, sio->swap_filen, aiostate->fd); - if (storeAufsSomethingPending(sio)) { - aiostate->flags.close_request = 1; - return; - } - storeAufsIOCallback(sio, DISK_OK); -} - - -/* Read */ -void -storeAufsRead(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data) -{ - squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; - assert(sio->read.callback == NULL); - assert(sio->read.callback_data == NULL); - assert(!aiostate->flags.reading); - if (aiostate->fd < 0) { - struct _queued_read *q; - debug(79, 3) ("storeAufsRead: queueing read because FD < 0\n"); - assert(aiostate->flags.opening); - assert(aiostate->pending_reads == NULL); - q = memPoolAlloc(aufs_qread_pool); - q->buf = buf; - q->size = size; - q->offset = offset; - q->callback = callback; - q->callback_data = callback_data; - linklistPush(&(aiostate->pending_reads), q); - return; - } - sio->read.callback = callback; - sio->read.callback_data = cbdataReference(callback_data); - aiostate->read_buf = buf; - debug(79, 3) ("storeAufsRead: dirno %d, fileno %08X, FD %d\n", - sio->swap_dirn, sio->swap_filen, aiostate->fd); - sio->offset = offset; - aiostate->flags.reading = 1; -#if ASYNC_READ - aioRead(aiostate->fd, offset, buf, size, storeAufsReadDone, sio); -#else - file_read(aiostate->fd, buf, size, offset, storeAufsReadDone, sio); -#endif -} - - -/* Write */ -void -storeAufsWrite(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, FREE * free_func) -{ - squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; - debug(79, 3) ("storeAufsWrite: dirno %d, fileno %08X, FD %d\n", - sio->swap_dirn, sio->swap_filen, aiostate->fd); - if (aiostate->fd < 0) { - /* disk file not opened yet */ - struct _queued_write *q; - assert(aiostate->flags.opening); - q = memPoolAlloc(aufs_qwrite_pool); - q->buf = buf; - q->size = size; - q->offset = offset; - q->free_func = free_func; - linklistPush(&(aiostate->pending_writes), q); - return; - } -#if ASYNC_WRITE - if (aiostate->flags.writing) { - struct _queued_write *q; - debug(79, 3) ("storeAufsWrite: queuing write\n"); - q = memPoolAlloc(aufs_qwrite_pool); - q->buf = buf; - q->size = size; - q->offset = offset; - q->free_func = free_func; - linklistPush(&(aiostate->pending_writes), q); - return; - } - aiostate->flags.writing = 1; - aioWrite(aiostate->fd, offset, buf, size, storeAufsWriteDone, sio, - free_func); -#else - file_write(aiostate->fd, offset, buf, size, storeAufsWriteDone, sio, - free_func); -#endif -} - -/* Unlink */ -void -storeAufsUnlink(SwapDir * SD, StoreEntry * e) -{ - debug(79, 3) ("storeAufsUnlink: dirno %d, fileno %08X\n", SD->index, e->swap_filen); - commonUfsDirReplRemove(e); - commonUfsDirMapBitReset(SD, e->swap_filen); - commonUfsDirUnlinkFile(SD, e->swap_filen); -} - -/* === STATIC =========================================================== */ - -static int -storeAufsKickWriteQueue(storeIOState * sio) -{ - squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; - struct _queued_write *q = linklistShift(&aiostate->pending_writes); - if (NULL == q) - return 0; - debug(79, 3) ("storeAufsKickWriteQueue: writing queued chunk of %ld bytes\n", - (long int) q->size); - storeAufsWrite(INDEXSD(sio->swap_dirn), sio, q->buf, q->size, q->offset, q->free_func); - memPoolFree(aufs_qwrite_pool, q); - return 1; -} - -static int -storeAufsKickReadQueue(storeIOState * sio) -{ - squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; - struct _queued_read *q = linklistShift(&(aiostate->pending_reads)); - if (NULL == q) - return 0; - debug(79, 3) ("storeAufsKickReadQueue: reading queued request of %ld bytes\n", - (long int) q->size); - storeAufsRead(INDEXSD(sio->swap_dirn), sio, q->buf, q->size, q->offset, q->callback, q->callback_data); - memPoolFree(aufs_qread_pool, q); - return 1; -} - -static void -storeAufsOpenDone(int unused, void *my_data, int fd, int errflag) -{ - storeIOState *sio = my_data; - squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; - debug(79, 3) ("storeAufsOpenDone: FD %d, errflag %d\n", fd, errflag); - Opening_FD--; - aiostate->flags.opening = 0; - if (errflag || fd < 0) { - errno = errflag; - debug(79, 0) ("storeAufsOpenDone: %s\n", xstrerror()); - debug(79, 1) ("\t%s\n", commonUfsDirFullPath(INDEXSD(sio->swap_dirn), sio->swap_filen, NULL)); - storeAufsIOCallback(sio, DISK_ERROR); - return; - } - store_open_disk_fd++; - aiostate->fd = fd; - commSetCloseOnExec(fd); - fd_open(fd, FD_FILE, commonUfsDirFullPath(INDEXSD(sio->swap_dirn), sio->swap_filen, NULL)); - if (FILE_MODE(sio->mode) == O_WRONLY) { - if (storeAufsKickWriteQueue(sio)) - return; - } else if (FILE_MODE(sio->mode) == O_RDONLY) { - if (storeAufsKickReadQueue(sio)) - return; - } - if (aiostate->flags.close_request) - storeAufsIOCallback(sio, errflag); - debug(79, 3) ("storeAufsOpenDone: exiting\n"); -} - -#if ASYNC_READ -static void -storeAufsReadDone(int fd, void *my_data, int len, int errflag) -#else -static void -storeAufsReadDone(int fd, const char *buf, int len, int errflag, void *my_data) -#endif -{ - storeIOState *sio = my_data; - squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; - STRCB *callback = sio->read.callback; - void *cbdata; - ssize_t rlen; - debug(79, 3) ("storeAufsReadDone: dirno %d, fileno %08X, FD %d, len %d\n", - sio->swap_dirn, sio->swap_filen, fd, len); - aiostate->flags.inreaddone = 1; - aiostate->flags.reading = 0; - if (errflag) { - debug(79, 3) ("storeAufsReadDone: got failure (%d)\n", errflag); - rlen = -1; - } else { - rlen = (ssize_t) len; - sio->offset += len; - } -#if ASYNC_READ - /* translate errflag from errno to Squid disk error */ - errno = errflag; - if (errflag) - errflag = DISK_ERROR; - else - errflag = DISK_OK; -#else - if (errflag == DISK_EOF) - errflag = DISK_OK; /* EOF is signalled by len == 0, not errors... */ -#endif - assert(callback); - sio->read.callback = NULL; - if (cbdataReferenceValidDone(sio->read.callback_data, &cbdata)) - callback(cbdata, aiostate->read_buf, rlen); - aiostate->flags.inreaddone = 0; - if (aiostate->flags.close_request) - storeAufsIOCallback(sio, errflag); -} - -#if ASYNC_WRITE -static void -storeAufsWriteDone(int fd, void *my_data, int len, int errflag) -#else -static void -storeAufsWriteDone(int fd, int errflag, size_t len, void *my_data) -#endif -{ - static int loop_detect = 0; - storeIOState *sio = my_data; - squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; - debug(79, 3) ("storeAufsWriteDone: dirno %d, fileno %08X, FD %d, len %ld, err=%d\n", - sio->swap_dirn, sio->swap_filen, fd, (long int) len, errflag); -#if ASYNC_WRITE - /* Translate from errno to Squid disk error */ - errno = errflag; - if (errflag) - errflag = errno == ENOSPC ? DISK_NO_SPACE_LEFT : DISK_ERROR; - else - errflag = DISK_OK; -#endif - assert(++loop_detect < 10); - aiostate->flags.writing = 0; - if (errflag) { - debug(79, 0) ("storeAufsWriteDone: got failure (%d)\n", errflag); - storeAufsIOCallback(sio, errflag); - loop_detect--; - return; - } - sio->offset += len; -#if ASYNC_WRITE - if (!storeAufsKickWriteQueue(sio)) - 0; - else if (aiostate->flags.close_request) - storeAufsIOCallback(sio, errflag); -#else - if (!aiostate->flags.write_kicking) { - aiostate->flags.write_kicking = 1; - while (storeAufsKickWriteQueue(sio)) - (void) 0; - aiostate->flags.write_kicking = 0; - if (aiostate->flags.close_request) - storeAufsIOCallback(sio, errflag); - } -#endif - loop_detect--; -} - -static void -storeAufsIOCallback(storeIOState * sio, int errflag) -{ - STIOCB *callback = sio->callback; - squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; - int fd = aiostate->fd; - debug(79, 3) ("storeAufsIOCallback: errflag=%d\n", errflag); - debug(79, 3) ("%s:%d\n", __FILE__, __LINE__); - if (callback) { - void *cbdata; - sio->callback = NULL; - if (cbdataReferenceValidDone(sio->callback_data, &cbdata)) - callback(cbdata, errflag, sio); - } - debug(79, 3) ("%s:%d\n", __FILE__, __LINE__); - aiostate->fd = -1; - cbdataFree(sio); - if (fd < 0) - return; - debug(79, 3) ("%s:%d\n", __FILE__, __LINE__); - aioClose(fd); - fd_close(fd); - store_open_disk_fd--; - debug(79, 3) ("%s:%d\n", __FILE__, __LINE__); -} - - -static int -storeAufsSomethingPending(storeIOState * sio) -{ - squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; - if (aiostate->flags.reading) - return 1; - if (aiostate->flags.writing) - return 1; - if (aiostate->flags.opening) - return 1; - if (aiostate->flags.inreaddone) - return 1; - return 0; -} - - -/* - * Clean up references from the SIO before it gets released. - * The actuall SIO is managed by cbdata so we do not need - * to bother with that. - */ -static void -storeAufsIOFreeEntry(void *sio) -{ - memPoolFree(squidaio_state_pool, ((storeIOState *) sio)->fsstate); -} --- /dev/null Wed Feb 14 01:07:22 2007 +++ squid/src/fs/aufs/store_io_aufs.cc Wed Feb 14 01:07:42 2007 @@ -0,0 +1,444 @@ + +/* + * DEBUG 79 + */ + +#include "squid.h" +#include "store_asyncufs.h" +#include "Store.h" +#include "ufscommon.h" + +#if ASYNC_READ +static AIOCB storeAufsReadDone; +#else +static DRCB storeAufsReadDone; +#endif +#if ASYNC_WRITE +static AIOCB storeAufsWriteDone; +#else +static DWCB storeAufsWriteDone; +#endif +static void storeAufsIOCallback(storeIOState * sio, int errflag); +static AIOCB storeAufsOpenDone; +static int storeAufsSomethingPending(storeIOState *); +static int storeAufsKickWriteQueue(storeIOState * sio); +static CBDUNL storeAufsIOFreeEntry; + +CBDATA_TYPE(storeIOState); + +/* === PUBLIC =========================================================== */ + +/* open for reading */ +storeIOState * +storeAufsOpen(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, + STIOCB * callback, void *callback_data) +{ + sfileno f = e->swap_filen; + char *path = commonUfsDirFullPath(SD, f, NULL); + storeIOState *sio; +#if !ASYNC_OPEN + int fd; +#endif + debug(79, 3) ("storeAufsOpen: fileno %08X\n", f); + /* + * we should detect some 'too many files open' condition and return + * NULL here. + */ +#ifdef MAGIC2 + if (aioQueueSize() > MAGIC2) + return NULL; +#endif +#if !ASYNC_OPEN + fd = file_open(path, O_RDONLY | O_BINARY); + if (fd < 0) { + debug(79, 3) ("storeAufsOpen: got failure (%d)\n", errno); + return NULL; + } +#endif + CBDATA_INIT_TYPE_FREECB(storeIOState, storeAufsIOFreeEntry); + sio = cbdataAlloc(storeIOState); + sio->fsstate = memPoolAlloc(squidaio_state_pool); + ((squidaiostate_t *) (sio->fsstate))->fd = -1; + ((squidaiostate_t *) (sio->fsstate))->flags.opening = 1; + sio->swap_filen = f; + sio->swap_dirn = SD->index; + sio->mode = O_RDONLY | O_BINARY; + sio->callback = callback; + sio->callback_data = cbdataReference(callback_data); + sio->e = e; + Opening_FD++; +#if ASYNC_OPEN + aioOpen(path, O_RDONLY | O_BINARY, 0644, storeAufsOpenDone, sio); +#else + storeAufsOpenDone(fd, sio, fd, 0); +#endif + return sio; +} + +/* open for creating */ +storeIOState * +storeAufsCreate(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, STIOCB * callback, void *callback_data) +{ + char *path; + storeIOState *sio; + sfileno filn; + sdirno dirn; +#if !ASYNC_CREATE + int fd; +#endif + + /* Allocate a number */ + dirn = SD->index; + filn = commonUfsDirMapBitAllocate(SD); + path = commonUfsDirFullPath(SD, filn, NULL); + + debug(79, 3) ("storeAufsCreate: fileno %08X\n", filn); + /* + * we should detect some 'too many files open' condition and return + * NULL here. + */ +#ifdef MAGIC2 + if (aioQueueSize() > MAGIC2) + return NULL; +#endif +#if !ASYNC_CREATE + fd = file_open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY); + if (fd < 0) { + debug(79, 3) ("storeAufsCreate: got failure (%d)\n", errno); + return NULL; + } +#endif + CBDATA_INIT_TYPE_FREECB(storeIOState, storeAufsIOFreeEntry); + sio = cbdataAlloc(storeIOState); + sio->fsstate = memPoolAlloc(squidaio_state_pool); + ((squidaiostate_t *) (sio->fsstate))->fd = -1; + ((squidaiostate_t *) (sio->fsstate))->flags.opening = 1; + sio->swap_filen = filn; + sio->swap_dirn = dirn; + sio->mode = O_WRONLY | O_BINARY; + sio->callback = callback; + sio->callback_data = cbdataReference(callback_data); + sio->e = (StoreEntry *) e; + Opening_FD++; +#if ASYNC_CREATE + aioOpen(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644, storeAufsOpenDone, sio); +#else + storeAufsOpenDone(fd, sio, fd, 0); +#endif + + /* now insert into the replacement policy */ + commonUfsDirReplAdd(SD, e); + return sio; + +} + + + +/* Close */ +void +storeAufsClose(SwapDir * SD, storeIOState * sio) +{ + squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; + debug(79, 3) ("storeAufsClose: dirno %d, fileno %08X, FD %d\n", + sio->swap_dirn, sio->swap_filen, aiostate->fd); + if (storeAufsSomethingPending(sio)) { + aiostate->flags.close_request = 1; + return; + } + storeAufsIOCallback(sio, DISK_OK); +} + + +/* Read */ +void +storeAufsRead(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data) +{ + squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; + assert(sio->read.callback == NULL); + assert(sio->read.callback_data == NULL); + assert(!aiostate->flags.reading); + if (aiostate->fd < 0) { + struct _queued_read *q; + debug(79, 3) ("storeAufsRead: queueing read because FD < 0\n"); + assert(aiostate->flags.opening); + assert(aiostate->pending_reads == NULL); + q = (struct _queued_read *)memPoolAlloc(aufs_qread_pool); + q->buf = buf; + q->size = size; + q->offset = offset; + q->callback = callback; + q->callback_data = callback_data; + linklistPush(&(aiostate->pending_reads), q); + return; + } + sio->read.callback = callback; + sio->read.callback_data = cbdataReference(callback_data); + aiostate->read_buf = buf; + debug(79, 3) ("storeAufsRead: dirno %d, fileno %08X, FD %d\n", + sio->swap_dirn, sio->swap_filen, aiostate->fd); + sio->offset = offset; + aiostate->flags.reading = 1; +#if ASYNC_READ + aioRead(aiostate->fd, offset, buf, size, storeAufsReadDone, sio); +#else + file_read(aiostate->fd, buf, size, offset, storeAufsReadDone, sio); +#endif +} + + +/* Write */ +void +storeAufsWrite(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, FREE * free_func) +{ + squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; + debug(79, 3) ("storeAufsWrite: dirno %d, fileno %08X, FD %d\n", + sio->swap_dirn, sio->swap_filen, aiostate->fd); + if (aiostate->fd < 0) { + /* disk file not opened yet */ + struct _queued_write *q; + assert(aiostate->flags.opening); + q = (struct _queued_write *)memPoolAlloc(aufs_qwrite_pool); + q->buf = buf; + q->size = size; + q->offset = offset; + q->free_func = free_func; + linklistPush(&(aiostate->pending_writes), q); + return; + } +#if ASYNC_WRITE + if (aiostate->flags.writing) { + struct _queued_write *q; + debug(79, 3) ("storeAufsWrite: queuing write\n"); + q = (struct _queued_write *)memPoolAlloc(aufs_qwrite_pool); + q->buf = buf; + q->size = size; + q->offset = offset; + q->free_func = free_func; + linklistPush(&(aiostate->pending_writes), q); + return; + } + aiostate->flags.writing = 1; + aioWrite(aiostate->fd, offset, buf, size, storeAufsWriteDone, sio, + free_func); +#else + file_write(aiostate->fd, offset, buf, size, storeAufsWriteDone, sio, + free_func); +#endif +} + +/* Unlink */ +void +storeAufsUnlink(SwapDir * SD, StoreEntry * e) +{ + debug(79, 3) ("storeAufsUnlink: dirno %d, fileno %08X\n", SD->index, e->swap_filen); + commonUfsDirReplRemove(e); + commonUfsDirMapBitReset(SD, e->swap_filen); + commonUfsDirUnlinkFile(SD, e->swap_filen); +} + +/* === STATIC =========================================================== */ + +static int +storeAufsKickWriteQueue(storeIOState * sio) +{ + squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; + struct _queued_write *q = (struct _queued_write *)linklistShift(&aiostate->pending_writes); + if (NULL == q) + return 0; + debug(79, 3) ("storeAufsKickWriteQueue: writing queued chunk of %ld bytes\n", + (long int) q->size); + storeAufsWrite(INDEXSD(sio->swap_dirn), sio, q->buf, q->size, q->offset, q->free_func); + memPoolFree(aufs_qwrite_pool, q); + return 1; +} + +static int +storeAufsKickReadQueue(storeIOState * sio) +{ + squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; + struct _queued_read *q = (struct _queued_read *)linklistShift(&(aiostate->pending_reads)); + if (NULL == q) + return 0; + debug(79, 3) ("storeAufsKickReadQueue: reading queued request of %ld bytes\n", + (long int) q->size); + storeAufsRead(INDEXSD(sio->swap_dirn), sio, q->buf, q->size, q->offset, q->callback, q->callback_data); + memPoolFree(aufs_qread_pool, q); + return 1; +} + +static void +storeAufsOpenDone(int unused, void *my_data, int fd, int errflag) +{ + storeIOState *sio = (storeIOState *)my_data; + squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; + debug(79, 3) ("storeAufsOpenDone: FD %d, errflag %d\n", fd, errflag); + Opening_FD--; + aiostate->flags.opening = 0; + if (errflag || fd < 0) { + errno = errflag; + debug(79, 0) ("storeAufsOpenDone: %s\n", xstrerror()); + debug(79, 1) ("\t%s\n", commonUfsDirFullPath(INDEXSD(sio->swap_dirn), sio->swap_filen, NULL)); + storeAufsIOCallback(sio, DISK_ERROR); + return; + } + store_open_disk_fd++; + aiostate->fd = fd; + commSetCloseOnExec(fd); + fd_open(fd, FD_FILE, commonUfsDirFullPath(INDEXSD(sio->swap_dirn), sio->swap_filen, NULL)); + if (FILE_MODE(sio->mode) == O_WRONLY) { + if (storeAufsKickWriteQueue(sio)) + return; + } else if (FILE_MODE(sio->mode) == O_RDONLY) { + if (storeAufsKickReadQueue(sio)) + return; + } + if (aiostate->flags.close_request) + storeAufsIOCallback(sio, errflag); + debug(79, 3) ("storeAufsOpenDone: exiting\n"); +} + +#if ASYNC_READ +static void +storeAufsReadDone(int fd, void *my_data, int len, int errflag) +#else +static void +storeAufsReadDone(int fd, const char *buf, int len, int errflag, void *my_data) +#endif +{ + storeIOState *sio = (storeIOState *)my_data; + squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; + STRCB *callback = sio->read.callback; + void *cbdata; + ssize_t rlen; + debug(79, 3) ("storeAufsReadDone: dirno %d, fileno %08X, FD %d, len %d\n", + sio->swap_dirn, sio->swap_filen, fd, len); + aiostate->flags.inreaddone = 1; + aiostate->flags.reading = 0; + if (errflag) { + debug(79, 3) ("storeAufsReadDone: got failure (%d)\n", errflag); + rlen = -1; + } else { + rlen = (ssize_t) len; + sio->offset += len; + } +#if ASYNC_READ + /* translate errflag from errno to Squid disk error */ + errno = errflag; + if (errflag) + errflag = DISK_ERROR; + else + errflag = DISK_OK; +#else + if (errflag == DISK_EOF) + errflag = DISK_OK; /* EOF is signalled by len == 0, not errors... */ +#endif + assert(callback); + sio->read.callback = NULL; + if (cbdataReferenceValidDone(sio->read.callback_data, &cbdata)) + callback(cbdata, aiostate->read_buf, rlen); + aiostate->flags.inreaddone = 0; + if (aiostate->flags.close_request) + storeAufsIOCallback(sio, errflag); +} + +#if ASYNC_WRITE +static void +storeAufsWriteDone(int fd, void *my_data, int len, int errflag) +#else +static void +storeAufsWriteDone(int fd, int errflag, size_t len, void *my_data) +#endif +{ + static int loop_detect = 0; + storeIOState *sio = (storeIOState *)my_data; + squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; + debug(79, 3) ("storeAufsWriteDone: dirno %d, fileno %08X, FD %d, len %ld, err=%d\n", + sio->swap_dirn, sio->swap_filen, fd, (long int) len, errflag); +#if ASYNC_WRITE + /* Translate from errno to Squid disk error */ + errno = errflag; + if (errflag) + errflag = errno == ENOSPC ? DISK_NO_SPACE_LEFT : DISK_ERROR; + else + errflag = DISK_OK; +#endif + assert(++loop_detect < 10); + aiostate->flags.writing = 0; + if (errflag) { + debug(79, 0) ("storeAufsWriteDone: got failure (%d)\n", errflag); + storeAufsIOCallback(sio, errflag); + loop_detect--; + return; + } + sio->offset += len; +#if ASYNC_WRITE + if (!storeAufsKickWriteQueue(sio)) + 0; + else if (aiostate->flags.close_request) + storeAufsIOCallback(sio, errflag); +#else + if (!aiostate->flags.write_kicking) { + aiostate->flags.write_kicking = 1; + while (storeAufsKickWriteQueue(sio)) + (void) 0; + aiostate->flags.write_kicking = 0; + if (aiostate->flags.close_request) + storeAufsIOCallback(sio, errflag); + } +#endif + loop_detect--; +} + +static void +storeAufsIOCallback(storeIOState * sio, int errflag) +{ + STIOCB *callback = sio->callback; + squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; + int fd = aiostate->fd; + debug(79, 3) ("storeAufsIOCallback: errflag=%d\n", errflag); + debug(79, 3) ("%s:%d\n", __FILE__, __LINE__); + if (callback) { + void *cbdata; + sio->callback = NULL; + if (cbdataReferenceValidDone(sio->callback_data, &cbdata)) + callback(cbdata, errflag, sio); + } + debug(79, 3) ("%s:%d\n", __FILE__, __LINE__); + aiostate->fd = -1; + cbdataFree(sio); + if (fd < 0) + return; + debug(79, 3) ("%s:%d\n", __FILE__, __LINE__); + aioClose(fd); + fd_close(fd); + store_open_disk_fd--; + debug(79, 3) ("%s:%d\n", __FILE__, __LINE__); +} + + +static int +storeAufsSomethingPending(storeIOState * sio) +{ + squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate; + if (aiostate->flags.reading) + return 1; + if (aiostate->flags.writing) + return 1; + if (aiostate->flags.opening) + return 1; + if (aiostate->flags.inreaddone) + return 1; + return 0; +} + + +/* + * Clean up references from the SIO before it gets released. + * The actuall SIO is managed by cbdata so we do not need + * to bother with that. + */ +static void +storeAufsIOFreeEntry(void *sio) +{ + memPoolFree(squidaio_state_pool, ((storeIOState *) sio)->fsstate); +} --- squid/src/fs/coss/async_io.c Wed Feb 14 01:07:42 2007 +++ /dev/null Wed Feb 14 01:07:22 2007 @@ -1,247 +0,0 @@ -/* - * async_io.c - some quick async IO routines for COSS - * - * Adrian Chadd - * - * These routines are simple plugin replacements for the file_* routines - * in disk.c . They back-end into the POSIX AIO routines to provide - * a nice and simple async IO framework for COSS. - * - * AIO is suitable for COSS - the only sync operations that the standard - * supports are read/write, and since COSS works on a single file - * per storedir it should work just fine. - * - * $Id$ - */ - -#include "squid.h" -#include -#include - -#include "async_io.h" - -/* - * For the time being, we kinda don't need to have our own - * open/close. Just read/write (with the queueing), and callback - * with the dequeueing) - */ - - -/* Internal routines */ - -/* - * find a free aio slot. - * Return the index, or -1 if we can't find one. - */ -static int -a_file_findslot(async_queue_t * q) -{ - int i; - - /* Later we should use something a little more .. efficient :) */ - for (i = 0; i < MAX_ASYNCOP; i++) { - if (q->aq_queue[i].aq_e_state == AQ_ENTRY_FREE) - /* Found! */ - return i; - } - /* found nothing */ - return -1; -} - - - - -/* Exported routines */ - -void -a_file_read(async_queue_t * q, int fd, void *buf, int req_len, off_t offset, - DRCB * callback, void *data) -{ - int slot; - async_queue_entry_t *qe; - - assert(q->aq_state == AQ_STATE_SETUP); - -#if 0 - file_read(fd, buf, req_len, offset, callback, data); -#endif - /* Find a free slot */ - slot = a_file_findslot(q); - if (slot < 0) { - /* No free slot? Callback error, and return */ - fatal("Aiee! out of aiocb slots!\n"); - } - /* Mark slot as ours */ - qe = &q->aq_queue[slot]; - qe->aq_e_state = AQ_ENTRY_USED; - qe->aq_e_callback.read = callback; - qe->aq_e_callback_data = cbdataReference(data); - qe->aq_e_type = AQ_ENTRY_READ; - qe->aq_e_free = NULL; - qe->aq_e_buf = buf; - qe->aq_e_fd = fd; - - qe->aq_e_aiocb.aio_fildes = fd; - qe->aq_e_aiocb.aio_nbytes = req_len; - qe->aq_e_aiocb.aio_offset = offset; - qe->aq_e_aiocb.aio_buf = buf; - - /* Account */ - q->aq_numpending++; - - /* Initiate aio */ - if (aio_read(&qe->aq_e_aiocb) < 0) { - fatalf("Aiee! aio_read() returned error (%d)!\n", errno); - } -} - - -void -a_file_write(async_queue_t * q, int fd, off_t offset, void *buf, int len, - DWCB * callback, void *data, FREE * freefunc) -{ - int slot; - async_queue_entry_t *qe; - - assert(q->aq_state == AQ_STATE_SETUP); - -#if 0 - file_write(fd, offset, buf, len, callback, data, freefunc); -#endif - /* Find a free slot */ - slot = a_file_findslot(q); - if (slot < 0) { - /* No free slot? Callback error, and return */ - fatal("Aiee! out of aiocb slots!\n"); - } - /* Mark slot as ours */ - qe = &q->aq_queue[slot]; - qe->aq_e_state = AQ_ENTRY_USED; - qe->aq_e_callback.write = callback; - qe->aq_e_callback_data = cbdataReference(data); - qe->aq_e_type = AQ_ENTRY_WRITE; - qe->aq_e_free = freefunc; - qe->aq_e_buf = buf; - qe->aq_e_fd = fd; - - qe->aq_e_aiocb.aio_fildes = fd; - qe->aq_e_aiocb.aio_nbytes = len; - qe->aq_e_aiocb.aio_offset = offset; - qe->aq_e_aiocb.aio_buf = buf; - - /* Account */ - q->aq_numpending++; - - /* Initiate aio */ - if (aio_write(&qe->aq_e_aiocb) < 0) { - fatalf("Aiee! aio_read() returned error (%d)!\n", errno); - assert(1 == 0); - } -} - - -/* - * Note: we grab the state and free the state before calling the callback - * because this allows us to cut down the amount of time it'll take - * to find a free slot (since if we call the callback first, we're going - * to probably be allocated the slot _after_ this one..) - * - * I'll make it much more optimal later. - */ -int -a_file_callback(async_queue_t * q) -{ - int i; - int completed = 0; - int retval, reterr; - DRCB *rc; - DWCB *wc; - FREE *freefunc; - void *cbdata; - int callback_valid; - void *buf; - int fd; - async_queue_entry_t *aqe; - async_queue_entry_type_t type; - - assert(q->aq_state == AQ_STATE_SETUP); - - /* Loop through all slots */ - for (i = 0; i < MAX_ASYNCOP; i++) { - if (q->aq_queue[i].aq_e_state == AQ_ENTRY_USED) { - aqe = &q->aq_queue[i]; - /* Active, get status */ - reterr = aio_error(&aqe->aq_e_aiocb); - if (reterr < 0) { - fatal("aio_error returned an error!\n"); - } - if (reterr != EINPROGRESS) { - /* Get the return code */ - retval = aio_return(&aqe->aq_e_aiocb); - - /* Get the callback parameters */ - freefunc = aqe->aq_e_free; - rc = aqe->aq_e_callback.read; - wc = aqe->aq_e_callback.write; - buf = aqe->aq_e_buf; - fd = aqe->aq_e_fd; - type = aqe->aq_e_type; - callback_valid = cbdataReferenceValidDone(aqe->aq_e_callback_data, &cbdata); - - /* Free slot */ - bzero(aqe, sizeof(async_queue_entry_t)); - aqe->aq_e_state = AQ_ENTRY_FREE; - q->aq_numpending--; - - /* Callback */ - if (callback_valid) { - if (type == AQ_ENTRY_READ) - rc(fd, buf, retval, reterr, cbdata); - if (type == AQ_ENTRY_WRITE) - wc(fd, reterr, retval, cbdata); - } - if (type == AQ_ENTRY_WRITE && freefunc) - freefunc(buf); - } - } - } - return completed; -} - - -void -a_file_setupqueue(async_queue_t * q) -{ - /* Make sure the queue isn't setup */ - assert(q->aq_state == AQ_STATE_NONE); - - /* Loop through, blanking the queue entries */ - - /* Done */ - q->aq_state = AQ_STATE_SETUP; -} - - -void -a_file_syncqueue(async_queue_t * q) -{ - assert(q->aq_state == AQ_STATE_SETUP); - - /* - * Keep calling callback to complete ops until the queue is empty - * We can't quit when callback returns 0 - some calls may not - * return any completed pending events, but they're still pending! - */ - while (q->aq_numpending) - a_file_callback(q); -} - - -void -a_file_closequeue(async_queue_t * q) -{ - assert(q->aq_state == AQ_STATE_SETUP); - - a_file_syncqueue(q); - q->aq_state = AQ_STATE_NONE; -} --- /dev/null Wed Feb 14 01:07:22 2007 +++ squid/src/fs/coss/async_io.cc Wed Feb 14 01:07:42 2007 @@ -0,0 +1,247 @@ +/* + * async_io.c - some quick async IO routines for COSS + * + * Adrian Chadd + * + * These routines are simple plugin replacements for the file_* routines + * in disk.c . They back-end into the POSIX AIO routines to provide + * a nice and simple async IO framework for COSS. + * + * AIO is suitable for COSS - the only sync operations that the standard + * supports are read/write, and since COSS works on a single file + * per storedir it should work just fine. + * + * $Id: async_io.cc,v 1.1.2.1 2002/10/12 12:21:43 rbcollins Exp $ + */ + +#include "squid.h" +#include +#include + +#include "async_io.h" + +/* + * For the time being, we kinda don't need to have our own + * open/close. Just read/write (with the queueing), and callback + * with the dequeueing) + */ + + +/* Internal routines */ + +/* + * find a free aio slot. + * Return the index, or -1 if we can't find one. + */ +static int +a_file_findslot(async_queue_t * q) +{ + int i; + + /* Later we should use something a little more .. efficient :) */ + for (i = 0; i < MAX_ASYNCOP; i++) { + if (q->aq_queue[i].aq_e_state == AQ_ENTRY_FREE) + /* Found! */ + return i; + } + /* found nothing */ + return -1; +} + + + + +/* Exported routines */ + +void +a_file_read(async_queue_t * q, int fd, void *buf, int req_len, off_t offset, + DRCB * callback, void *data) +{ + int slot; + async_queue_entry_t *qe; + + assert(q->aq_state == AQ_STATE_SETUP); + +#if 0 + file_read(fd, buf, req_len, offset, callback, data); +#endif + /* Find a free slot */ + slot = a_file_findslot(q); + if (slot < 0) { + /* No free slot? Callback error, and return */ + fatal("Aiee! out of aiocb slots!\n"); + } + /* Mark slot as ours */ + qe = &q->aq_queue[slot]; + qe->aq_e_state = AQ_ENTRY_USED; + qe->aq_e_callback.read = callback; + qe->aq_e_callback_data = cbdataReference(data); + qe->aq_e_type = AQ_ENTRY_READ; + qe->aq_e_free = NULL; + qe->aq_e_buf = buf; + qe->aq_e_fd = fd; + + qe->aq_e_aiocb.aio_fildes = fd; + qe->aq_e_aiocb.aio_nbytes = req_len; + qe->aq_e_aiocb.aio_offset = offset; + qe->aq_e_aiocb.aio_buf = buf; + + /* Account */ + q->aq_numpending++; + + /* Initiate aio */ + if (aio_read(&qe->aq_e_aiocb) < 0) { + fatalf("Aiee! aio_read() returned error (%d)!\n", errno); + } +} + + +void +a_file_write(async_queue_t * q, int fd, off_t offset, void *buf, int len, + DWCB * callback, void *data, FREE * freefunc) +{ + int slot; + async_queue_entry_t *qe; + + assert(q->aq_state == AQ_STATE_SETUP); + +#if 0 + file_write(fd, offset, buf, len, callback, data, freefunc); +#endif + /* Find a free slot */ + slot = a_file_findslot(q); + if (slot < 0) { + /* No free slot? Callback error, and return */ + fatal("Aiee! out of aiocb slots!\n"); + } + /* Mark slot as ours */ + qe = &q->aq_queue[slot]; + qe->aq_e_state = AQ_ENTRY_USED; + qe->aq_e_callback.write = callback; + qe->aq_e_callback_data = cbdataReference(data); + qe->aq_e_type = AQ_ENTRY_WRITE; + qe->aq_e_free = freefunc; + qe->aq_e_buf = buf; + qe->aq_e_fd = fd; + + qe->aq_e_aiocb.aio_fildes = fd; + qe->aq_e_aiocb.aio_nbytes = len; + qe->aq_e_aiocb.aio_offset = offset; + qe->aq_e_aiocb.aio_buf = buf; + + /* Account */ + q->aq_numpending++; + + /* Initiate aio */ + if (aio_write(&qe->aq_e_aiocb) < 0) { + fatalf("Aiee! aio_read() returned error (%d)!\n", errno); + assert(1 == 0); + } +} + + +/* + * Note: we grab the state and free the state before calling the callback + * because this allows us to cut down the amount of time it'll take + * to find a free slot (since if we call the callback first, we're going + * to probably be allocated the slot _after_ this one..) + * + * I'll make it much more optimal later. + */ +int +a_file_callback(async_queue_t * q) +{ + int i; + int completed = 0; + int retval, reterr; + DRCB *rc; + DWCB *wc; + FREE *freefunc; + void *cbdata; + int callback_valid; + void *buf; + int fd; + async_queue_entry_t *aqe; + async_queue_entry_type_t type; + + assert(q->aq_state == AQ_STATE_SETUP); + + /* Loop through all slots */ + for (i = 0; i < MAX_ASYNCOP; i++) { + if (q->aq_queue[i].aq_e_state == AQ_ENTRY_USED) { + aqe = &q->aq_queue[i]; + /* Active, get status */ + reterr = aio_error(&aqe->aq_e_aiocb); + if (reterr < 0) { + fatal("aio_error returned an error!\n"); + } + if (reterr != EINPROGRESS) { + /* Get the return code */ + retval = aio_return(&aqe->aq_e_aiocb); + + /* Get the callback parameters */ + freefunc = aqe->aq_e_free; + rc = aqe->aq_e_callback.read; + wc = aqe->aq_e_callback.write; + buf = aqe->aq_e_buf; + fd = aqe->aq_e_fd; + type = aqe->aq_e_type; + callback_valid = cbdataReferenceValidDone(aqe->aq_e_callback_data, &cbdata); + + /* Free slot */ + bzero(aqe, sizeof(async_queue_entry_t)); + aqe->aq_e_state = AQ_ENTRY_FREE; + q->aq_numpending--; + + /* Callback */ + if (callback_valid) { + if (type == AQ_ENTRY_READ) + rc(fd, (char *)buf, retval, reterr, cbdata); + if (type == AQ_ENTRY_WRITE) + wc(fd, reterr, retval, cbdata); + } + if (type == AQ_ENTRY_WRITE && freefunc) + freefunc(buf); + } + } + } + return completed; +} + + +void +a_file_setupqueue(async_queue_t * q) +{ + /* Make sure the queue isn't setup */ + assert(q->aq_state == AQ_STATE_NONE); + + /* Loop through, blanking the queue entries */ + + /* Done */ + q->aq_state = AQ_STATE_SETUP; +} + + +void +a_file_syncqueue(async_queue_t * q) +{ + assert(q->aq_state == AQ_STATE_SETUP); + + /* + * Keep calling callback to complete ops until the queue is empty + * We can't quit when callback returns 0 - some calls may not + * return any completed pending events, but they're still pending! + */ + while (q->aq_numpending) + a_file_callback(q); +} + + +void +a_file_closequeue(async_queue_t * q) +{ + assert(q->aq_state == AQ_STATE_SETUP); + + a_file_syncqueue(q); + q->aq_state = AQ_STATE_NONE; +} --- squid/src/fs/coss/store_dir_coss.c Wed Feb 14 01:07:42 2007 +++ /dev/null Wed Feb 14 01:07:22 2007 @@ -1,904 +0,0 @@ - -/* - * $Id$ - * - * DEBUG: section 47 Store COSS Directory Routines - * AUTHOR: Eric Stern - * - * SQUID Web Proxy Cache http://www.squid-cache.org/ - * ---------------------------------------------------------- - * - * Squid is the result of efforts by numerous individuals from - * the Internet community; see the CONTRIBUTORS file for full - * details. Many organizations have provided support for Squid's - * development; see the SPONSORS file for full details. Squid is - * Copyrighted (C) 2001 by the Regents of the University of - * California; see the COPYRIGHT file for full details. Squid - * incorporates software developed and/or copyrighted by other - * sources; see the CREDITS file for full details. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. - * - */ - -#include "squid.h" -#include "Store.h" -#include - -#include "async_io.h" -#include "store_coss.h" - -#define STORE_META_BUFSZ 4096 - -int n_coss_dirs = 0; -/* static int last_coss_pick_index = -1; */ -int coss_initialised = 0; -MemPool *coss_state_pool = NULL; -MemPool *coss_index_pool = NULL; - -typedef struct _RebuildState RebuildState; -struct _RebuildState { - SwapDir *sd; - int n_read; - FILE *log; - int speed; - struct { - unsigned int clean:1; - } flags; - struct _store_rebuild_data counts; -}; - -static char *storeCossDirSwapLogFile(SwapDir *, const char *); -static EVH storeCossRebuildFromSwapLog; -static StoreEntry *storeCossAddDiskRestore(SwapDir * SD, const cache_key * key, - int file_number, - size_t swap_file_sz, - time_t expires, - time_t timestamp, - time_t lastref, - time_t lastmod, - u_int32_t refcount, - u_int16_t flags, - int clean); -static void storeCossDirRebuild(SwapDir * sd); -static void storeCossDirCloseTmpSwapLog(SwapDir * sd); -static FILE *storeCossDirOpenTmpSwapLog(SwapDir *, int *, int *); -static STLOGOPEN storeCossDirOpenSwapLog; -static STINIT storeCossDirInit; -static STLOGCLEANSTART storeCossDirWriteCleanStart; -static STLOGCLEANNEXTENTRY storeCossDirCleanLogNextEntry; -static STLOGCLEANWRITE storeCossDirWriteCleanEntry; -static STLOGCLEANDONE storeCossDirWriteCleanDone; -static STLOGCLOSE storeCossDirCloseSwapLog; -static STLOGWRITE storeCossDirSwapLog; -static STNEWFS storeCossDirNewfs; -static STCHECKOBJ storeCossDirCheckObj; -static STFREE storeCossDirShutdown; -static STFSPARSE storeCossDirParse; -static STFSRECONFIGURE storeCossDirReconfigure; -static STDUMP storeCossDirDump; -static STCALLBACK storeCossDirCallback; - -/* The "only" externally visible function */ -STSETUP storeFsSetup_coss; - -static char * -storeCossDirSwapLogFile(SwapDir * sd, const char *ext) -{ - LOCAL_ARRAY(char, path, SQUID_MAXPATHLEN); - LOCAL_ARRAY(char, pathtmp, SQUID_MAXPATHLEN); - LOCAL_ARRAY(char, digit, 32); - char *pathtmp2; - if (Config.Log.swap) { - xstrncpy(pathtmp, sd->path, SQUID_MAXPATHLEN - 64); - pathtmp2 = pathtmp; - while ((pathtmp2 = strchr(pathtmp2, '/')) != NULL) - *pathtmp2 = '.'; - while (strlen(pathtmp) && pathtmp[strlen(pathtmp) - 1] == '.') - pathtmp[strlen(pathtmp) - 1] = '\0'; - for (pathtmp2 = pathtmp; *pathtmp2 == '.'; pathtmp2++); - snprintf(path, SQUID_MAXPATHLEN - 64, Config.Log.swap, pathtmp2); - if (strncmp(path, Config.Log.swap, SQUID_MAXPATHLEN - 64) == 0) { - strcat(path, "."); - snprintf(digit, 32, "%02d", sd->index); - strncat(path, digit, 3); - } - } else { - xstrncpy(path, sd->path, SQUID_MAXPATHLEN - 64); - strcat(path, "/swap.state"); - } - if (ext) - strncat(path, ext, 16); - return path; -} - -static void -storeCossDirOpenSwapLog(SwapDir * sd) -{ - CossInfo *cs = (CossInfo *) sd->fsdata; - char *path; - int fd; - path = storeCossDirSwapLogFile(sd, NULL); - fd = file_open(path, O_WRONLY | O_CREAT | O_BINARY); - if (fd < 0) { - debug(47, 1) ("%s: %s\n", path, xstrerror()); - fatal("storeCossDirOpenSwapLog: Failed to open swap log."); - } - debug(47, 3) ("Cache COSS Dir #%d log opened on FD %d\n", sd->index, fd); - cs->swaplog_fd = fd; -} - -static void -storeCossDirCloseSwapLog(SwapDir * sd) -{ - CossInfo *cs = (CossInfo *) sd->fsdata; - if (cs->swaplog_fd < 0) /* not open */ - return; - file_close(cs->swaplog_fd); - debug(47, 3) ("Cache COSS Dir #%d log closed on FD %d\n", - sd->index, cs->swaplog_fd); - cs->swaplog_fd = -1; -} - -static void -storeCossDirInit(SwapDir * sd) -{ - CossInfo *cs = (CossInfo *) sd->fsdata; - a_file_setupqueue(&cs->aq); - storeCossDirOpenSwapLog(sd); - storeCossDirRebuild(sd); - cs->fd = file_open(sd->path, O_RDWR | O_CREAT); - if (cs->fd < 0) { - debug(47, 1) ("%s: %s\n", sd->path, xstrerror()); - fatal("storeCossDirInit: Failed to open a COSS directory."); - } - n_coss_dirs++; - (void) storeDirGetBlkSize(sd->path, &sd->fs.blksize); -} - -void -storeCossRemove(SwapDir * sd, StoreEntry * e) -{ - CossInfo *cs = (CossInfo *) sd->fsdata; - CossIndexNode *coss_node = e->repl.data; - e->repl.data = NULL; - dlinkDelete(&coss_node->node, &cs->index); - memPoolFree(coss_index_pool, coss_node); - cs->count -= 1; -} - -void -storeCossAdd(SwapDir * sd, StoreEntry * e) -{ - CossInfo *cs = (CossInfo *) sd->fsdata; - CossIndexNode *coss_node = memPoolAlloc(coss_index_pool); - assert(!e->repl.data); - e->repl.data = coss_node; - dlinkAdd(e, &coss_node->node, &cs->index); - cs->count += 1; -} - -static void -storeCossRebuildComplete(void *data) -{ - RebuildState *rb = data; - SwapDir *sd = rb->sd; - storeCossStartMembuf(sd); - store_dirs_rebuilding--; - storeCossDirCloseTmpSwapLog(rb->sd); - storeRebuildComplete(&rb->counts); - cbdataFree(rb); -} - -static void -storeCossRebuildFromSwapLog(void *data) -{ - RebuildState *rb = data; - StoreEntry *e = NULL; - storeSwapLogData s; - size_t ss = sizeof(storeSwapLogData); - int count; - double x; - assert(rb != NULL); - /* load a number of objects per invocation */ - for (count = 0; count < rb->speed; count++) { - if (fread(&s, ss, 1, rb->log) != 1) { - debug(47, 1) ("Done reading %s swaplog (%d entries)\n", - rb->sd->path, rb->n_read); - fclose(rb->log); - rb->log = NULL; - storeCossRebuildComplete(rb); - return; - } - rb->n_read++; - if (s.op <= SWAP_LOG_NOP) - continue; - if (s.op >= SWAP_LOG_MAX) - continue; - debug(47, 3) ("storeCossRebuildFromSwapLog: %s %s %08X\n", - swap_log_op_str[(int) s.op], - storeKeyText(s.key), - s.swap_filen); - if (s.op == SWAP_LOG_ADD) { - (void) 0; - } else if (s.op == SWAP_LOG_DEL) { - if ((e = storeGet(s.key)) != NULL) { - /* - * Make sure we don't unlink the file, it might be - * in use by a subsequent entry. Also note that - * we don't have to subtract from store_swap_size - * because adding to store_swap_size happens in - * the cleanup procedure. - */ - storeExpireNow(e); - storeReleaseRequest(e); - if (e->swap_filen > -1) { - e->swap_filen = -1; - } - storeRelease(e); - /* Fake an unlink here, this is a bad hack :( */ - storeCossRemove(rb->sd, e); - rb->counts.objcount--; - rb->counts.cancelcount++; - } - continue; - } else { - x = log(++rb->counts.bad_log_op) / log(10.0); - if (0.0 == x - (double) (int) x) - debug(47, 1) ("WARNING: %d invalid swap log entries found\n", - rb->counts.bad_log_op); - rb->counts.invalid++; - continue; - } - if ((++rb->counts.scancount & 0xFFF) == 0) { - struct stat sb; - if (0 == fstat(fileno(rb->log), &sb)) - storeRebuildProgress(rb->sd->index, - (int) sb.st_size / ss, rb->n_read); - } - if (EBIT_TEST(s.flags, KEY_PRIVATE)) { - rb->counts.badflags++; - continue; - } - e = storeGet(s.key); - if (e) { - /* key already exists, current entry is newer */ - /* keep old, ignore new */ - rb->counts.dupcount++; - continue; - } - /* update store_swap_size */ - rb->counts.objcount++; - e = storeCossAddDiskRestore(rb->sd, s.key, - s.swap_filen, - s.swap_file_sz, - s.expires, - s.timestamp, - s.lastref, - s.lastmod, - s.refcount, - s.flags, - (int) rb->flags.clean); - storeDirSwapLog(e, SWAP_LOG_ADD); - } - eventAdd("storeCossRebuild", storeCossRebuildFromSwapLog, rb, 0.0, 1); -} - -/* Add a new object to the cache with empty memory copy and pointer to disk - * use to rebuild store from disk. */ -static StoreEntry * -storeCossAddDiskRestore(SwapDir * SD, const cache_key * key, - int file_number, - size_t swap_file_sz, - time_t expires, - time_t timestamp, - time_t lastref, - time_t lastmod, - u_int32_t refcount, - u_int16_t flags, - int clean) -{ - StoreEntry *e = NULL; - debug(47, 5) ("storeCossAddDiskRestore: %s, fileno=%08X\n", storeKeyText(key), file_number); - /* if you call this you'd better be sure file_number is not - * already in use! */ - e = new_StoreEntry(STORE_ENTRY_WITHOUT_MEMOBJ, NULL, NULL); - e->store_status = STORE_OK; - e->swap_dirn = SD->index; - storeSetMemStatus(e, NOT_IN_MEMORY); - e->swap_status = SWAPOUT_DONE; - e->swap_filen = file_number; - e->swap_file_sz = swap_file_sz; - e->lock_count = 0; - e->lastref = lastref; - e->timestamp = timestamp; - e->expires = expires; - e->lastmod = lastmod; - e->refcount = refcount; - e->flags = flags; - EBIT_SET(e->flags, ENTRY_CACHABLE); - EBIT_CLR(e->flags, RELEASE_REQUEST); - EBIT_CLR(e->flags, KEY_PRIVATE); - e->ping_status = PING_NONE; - EBIT_CLR(e->flags, ENTRY_VALIDATED); - storeHashInsert(e, key); /* do it after we clear KEY_PRIVATE */ - storeCossAdd(SD, e); - e->swap_filen = storeCossAllocate(SD, e, COSS_ALLOC_NOTIFY); - return e; -} - -CBDATA_TYPE(RebuildState); -static void -storeCossDirRebuild(SwapDir * sd) -{ - RebuildState *rb; - int clean = 0; - int zero = 0; - FILE *fp; - EVH *func = NULL; - CBDATA_INIT_TYPE(RebuildState); - rb = cbdataAlloc(RebuildState); - rb->sd = sd; - rb->speed = opt_foreground_rebuild ? 1 << 30 : 50; - func = storeCossRebuildFromSwapLog; - rb->flags.clean = (unsigned int) clean; - /* - * If the swap.state file exists in the cache_dir, then - * we'll use storeCossRebuildFromSwapLog(). - */ - fp = storeCossDirOpenTmpSwapLog(sd, &clean, &zero); - debug(47, 1) ("Rebuilding COSS storage in %s (%s)\n", - sd->path, clean ? "CLEAN" : "DIRTY"); - rb->log = fp; - store_dirs_rebuilding++; - if (!clean || fp == NULL) { - /* COSS cannot yet rebuild from a dirty state. If the log - * is dirty then the COSS contents is thrown away. - * Why? I guess it is because some contents will be lost, - * and COSS cannot verify this.. - */ - if (fp != NULL) - fclose(fp); - /* - * XXX Make sure we don't trigger an assertion if this is the first - * storedir, since if we are, this call will cause storeRebuildComplete - * to prematurely complete the rebuild process, and then some other - * storedir will try to rebuild and eventually die. - */ - eventAdd("storeCossRebuildComplete", storeCossRebuildComplete, rb, 0.0, 0); - return; - } - eventAdd("storeCossRebuild", func, rb, 0.0, 1); -} - -static void -storeCossDirCloseTmpSwapLog(SwapDir * sd) -{ - CossInfo *cs = (CossInfo *) sd->fsdata; - char *swaplog_path = xstrdup(storeCossDirSwapLogFile(sd, NULL)); - char *new_path = xstrdup(storeCossDirSwapLogFile(sd, ".new")); - int fd; - file_close(cs->swaplog_fd); -#if defined (_SQUID_OS2_) || defined (_SQUID_CYGWIN_) - if (unlink(swaplog_path) < 0) { - debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror()); - fatal("storeCossDirCloseTmpSwapLog: unlink failed"); - } -#endif - if (xrename(new_path, swaplog_path) < 0) { - fatal("storeCossDirCloseTmpSwapLog: rename failed"); - } - fd = file_open(swaplog_path, O_WRONLY | O_CREAT | O_BINARY); - if (fd < 0) { - debug(50, 1) ("%s: %s\n", swaplog_path, xstrerror()); - fatal("storeCossDirCloseTmpSwapLog: Failed to open swap log."); - } - safe_free(swaplog_path); - safe_free(new_path); - cs->swaplog_fd = fd; - debug(47, 3) ("Cache COSS Dir #%d log opened on FD %d\n", sd->index, fd); -} - -static FILE * -storeCossDirOpenTmpSwapLog(SwapDir * sd, int *clean_flag, int *zero_flag) -{ - CossInfo *cs = (CossInfo *) sd->fsdata; - char *swaplog_path = xstrdup(storeCossDirSwapLogFile(sd, NULL)); - char *clean_path = xstrdup(storeCossDirSwapLogFile(sd, ".last-clean")); - char *new_path = xstrdup(storeCossDirSwapLogFile(sd, ".new")); - struct stat log_sb; - struct stat clean_sb; - FILE *fp; - int fd; - if (stat(swaplog_path, &log_sb) < 0) { - debug(50, 1) ("Cache COSS Dir #%d: No log file\n", sd->index); - safe_free(swaplog_path); - safe_free(clean_path); - safe_free(new_path); - return NULL; - } - *zero_flag = log_sb.st_size == 0 ? 1 : 0; - /* close the existing write-only FD */ - if (cs->swaplog_fd >= 0) - file_close(cs->swaplog_fd); - /* open a write-only FD for the new log */ - fd = file_open(new_path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY); - if (fd < 0) { - debug(50, 1) ("%s: %s\n", new_path, xstrerror()); - fatal("storeDirOpenTmpSwapLog: Failed to open swap log."); - } - cs->swaplog_fd = fd; - /* open a read-only stream of the old log */ - fp = fopen(swaplog_path, "rb"); - if (fp == NULL) { - debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror()); - fatal("Failed to open swap log for reading"); - } - memset(&clean_sb, '\0', sizeof(struct stat)); - if (stat(clean_path, &clean_sb) < 0) - *clean_flag = 0; - else if (clean_sb.st_mtime < log_sb.st_mtime) - *clean_flag = 0; - else - *clean_flag = 1; - safeunlink(clean_path, 1); - safe_free(swaplog_path); - safe_free(clean_path); - safe_free(new_path); - return fp; -} - -struct _clean_state { - char *cur; - char *new; - char *cln; - char *outbuf; - off_t outbuf_offset; - int fd; - dlink_node *current; -}; - -#define CLEAN_BUF_SZ 16384 -/* - * Begin the process to write clean cache state. For COSS this means - * opening some log files and allocating write buffers. Return 0 if - * we succeed, and assign the 'func' and 'data' return pointers. - */ -static int -storeCossDirWriteCleanStart(SwapDir * sd) -{ - CossInfo *cs = (CossInfo *) sd->fsdata; - struct _clean_state *state = xcalloc(1, sizeof(*state)); -#if HAVE_FCHMOD - struct stat sb; -#endif - state->new = xstrdup(storeCossDirSwapLogFile(sd, ".clean")); - state->fd = file_open(state->new, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY); - if (state->fd < 0) { - xfree(state->new); - xfree(state); - return -1; - } - sd->log.clean.write = NULL; - sd->log.clean.state = NULL; - state->cur = xstrdup(storeCossDirSwapLogFile(sd, NULL)); - state->cln = xstrdup(storeCossDirSwapLogFile(sd, ".last-clean")); - state->outbuf = xcalloc(CLEAN_BUF_SZ, 1); - state->outbuf_offset = 0; - unlink(state->cln); - state->current = cs->index.tail; - debug(50, 3) ("storeCOssDirWriteCleanLogs: opened %s, FD %d\n", - state->new, state->fd); -#if HAVE_FCHMOD - if (stat(state->cur, &sb) == 0) - fchmod(state->fd, sb.st_mode); -#endif - sd->log.clean.write = storeCossDirWriteCleanEntry; - sd->log.clean.state = state; - - return 0; -} - -static const StoreEntry * -storeCossDirCleanLogNextEntry(SwapDir * sd) -{ - struct _clean_state *state = sd->log.clean.state; - const StoreEntry *entry; - if (!state) - return NULL; - if (!state->current) - return NULL; - entry = (const StoreEntry *) state->current->data; - state->current = state->current->prev; - return entry; -} - -/* - * "write" an entry to the clean log file. - */ -static void -storeCossDirWriteCleanEntry(SwapDir * sd, const StoreEntry * e) -{ - storeSwapLogData s; - static size_t ss = sizeof(storeSwapLogData); - struct _clean_state *state = sd->log.clean.state; - memset(&s, '\0', ss); - s.op = (char) SWAP_LOG_ADD; - s.swap_filen = e->swap_filen; - s.timestamp = e->timestamp; - s.lastref = e->lastref; - s.expires = e->expires; - s.lastmod = e->lastmod; - s.swap_file_sz = e->swap_file_sz; - s.refcount = e->refcount; - s.flags = e->flags; - xmemcpy(&s.key, e->hash.key, MD5_DIGEST_CHARS); - xmemcpy(state->outbuf + state->outbuf_offset, &s, ss); - state->outbuf_offset += ss; - /* buffered write */ - if (state->outbuf_offset + ss > CLEAN_BUF_SZ) { - if (FD_WRITE_METHOD(state->fd, state->outbuf, state->outbuf_offset) < 0) { - debug(50, 0) ("storeCossDirWriteCleanLogs: %s: write: %s\n", - state->new, xstrerror()); - debug(50, 0) ("storeCossDirWriteCleanLogs: Current swap logfile not replaced.\n"); - file_close(state->fd); - state->fd = -1; - unlink(state->new); - safe_free(state); - sd->log.clean.state = NULL; - sd->log.clean.write = NULL; - return; - } - state->outbuf_offset = 0; - } -} - -static void -storeCossDirWriteCleanDone(SwapDir * sd) -{ - int fd; - struct _clean_state *state = sd->log.clean.state; - if (NULL == state) - return; - if (state->fd < 0) - return; - if (FD_WRITE_METHOD(state->fd, state->outbuf, state->outbuf_offset) < 0) { - debug(50, 0) ("storeCossDirWriteCleanLogs: %s: write: %s\n", - state->new, xstrerror()); - debug(50, 0) ("storeCossDirWriteCleanLogs: Current swap logfile " - "not replaced.\n"); - file_close(state->fd); - state->fd = -1; - unlink(state->new); - } - safe_free(state->outbuf); - /* - * You can't rename open files on Microsoft "operating systems" - * so we have to close before renaming. - */ - storeCossDirCloseSwapLog(sd); - /* save the fd value for a later test */ - fd = state->fd; - /* rename */ - if (state->fd >= 0) { -#if defined(_SQUID_OS2_) || defined (_SQUID_CYGWIN_) - file_close(state->fd); - state->fd = -1; - if (unlink(state->cur) < 0) - debug(50, 0) ("storeCossDirWriteCleanLogs: unlinkd failed: %s, %s\n", - xstrerror(), state->cur); -#endif - xrename(state->new, state->cur); - } - /* touch a timestamp file if we're not still validating */ - if (store_dirs_rebuilding) - (void) 0; - else if (fd < 0) - (void) 0; - else - file_close(file_open(state->cln, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY)); - /* close */ - safe_free(state->cur); - safe_free(state->new); - safe_free(state->cln); - if (state->fd >= 0) - file_close(state->fd); - state->fd = -1; - safe_free(state); - sd->log.clean.state = NULL; - sd->log.clean.write = NULL; -} - -static void -storeSwapLogDataFree(void *s) -{ - memFree(s, MEM_SWAP_LOG_DATA); -} - -static void -storeCossDirSwapLog(const SwapDir * sd, const StoreEntry * e, int op) -{ - CossInfo *cs = (CossInfo *) sd->fsdata; - storeSwapLogData *s = memAllocate(MEM_SWAP_LOG_DATA); - s->op = (char) op; - s->swap_filen = e->swap_filen; - s->timestamp = e->timestamp; - s->lastref = e->lastref; - s->expires = e->expires; - s->lastmod = e->lastmod; - s->swap_file_sz = e->swap_file_sz; - s->refcount = e->refcount; - s->flags = e->flags; - xmemcpy(s->key, e->hash.key, MD5_DIGEST_CHARS); - file_write(cs->swaplog_fd, - -1, - s, - sizeof(storeSwapLogData), - NULL, - NULL, - (FREE *) storeSwapLogDataFree); -} - -static void -storeCossDirNewfs(SwapDir * sd) -{ - debug(47, 3) ("Creating swap space in %s\n", sd->path); -} - -/* we are shutting down, flush all membufs to disk */ -static void -storeCossDirShutdown(SwapDir * SD) -{ - CossInfo *cs = (CossInfo *) SD->fsdata; - - storeCossSync(SD); /* This'll call a_file_syncqueue() */ - a_file_closequeue(&cs->aq); - file_close(cs->fd); - cs->fd = -1; - - if (cs->swaplog_fd > -1) { - file_close(cs->swaplog_fd); - cs->swaplog_fd = -1; - } - n_coss_dirs--; -} - -/* - * storeCossDirCheckObj - * - * This routine is called by storeDirSelectSwapDir to see if the given - * object is able to be stored on this filesystem. COSS filesystems will - * not store everything. We don't check for maxobjsize here since its - * done by the upper layers. - */ -int -storeCossDirCheckObj(SwapDir * SD, const StoreEntry * e) -{ - CossInfo *cs = (CossInfo *) SD->fsdata; - int loadav; - - /* Check if the object is a special object, we can't cache these */ - if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) - return -1; - - /* Otherwise, we're ok */ - /* Return load, cs->aq.aq_numpending out of MAX_ASYNCOP */ - loadav = cs->aq.aq_numpending * 1000 / MAX_ASYNCOP; - return loadav; -} - - -/* - * storeCossDirCallback - do the IO completions - */ -static int -storeCossDirCallback(SwapDir * SD) -{ - CossInfo *cs = (CossInfo *) SD->fsdata; - - return a_file_callback(&cs->aq); -} - -/* ========== LOCAL FUNCTIONS ABOVE, GLOBAL FUNCTIONS BELOW ========== */ - -static void -storeCossDirStats(SwapDir * SD, StoreEntry * sentry) -{ - CossInfo *cs = (CossInfo *) SD->fsdata; - - storeAppendPrintf(sentry, "\n"); - storeAppendPrintf(sentry, "Maximum Size: %d KB\n", SD->max_size); - storeAppendPrintf(sentry, "Current Size: %d KB\n", SD->cur_size); - storeAppendPrintf(sentry, "Percent Used: %0.2f%%\n", - 100.0 * SD->cur_size / SD->max_size); - storeAppendPrintf(sentry, "Number of object collisions: %d\n", (int) cs->numcollisions); -#if 0 - /* is this applicable? I Hope not .. */ - storeAppendPrintf(sentry, "Filemap bits in use: %d of %d (%d%%)\n", - SD->map->n_files_in_map, SD->map->max_n_files, - percent(SD->map->n_files_in_map, SD->map->max_n_files)); -#endif - storeAppendPrintf(sentry, "Pending operations: %d out of %d\n", cs->aq.aq_numpending, MAX_ASYNCOP); - storeAppendPrintf(sentry, "Flags:"); - if (SD->flags.selected) - storeAppendPrintf(sentry, " SELECTED"); - if (SD->flags.read_only) - storeAppendPrintf(sentry, " READ-ONLY"); - storeAppendPrintf(sentry, "\n"); -} - -static void -storeCossDirParse(SwapDir * sd, int index, char *path) -{ - unsigned int i; - unsigned int size; - CossInfo *cs; - - i = GetInteger(); - size = i << 10; /* Mbytes to Kbytes */ - if (size <= 0) - fatal("storeCossDirParse: invalid size value"); - - cs = xmalloc(sizeof(CossInfo)); - if (cs == NULL) - fatal("storeCossDirParse: couldn't xmalloc() CossInfo!\n"); - - sd->index = index; - sd->path = xstrdup(path); - sd->max_size = size; - sd->fsdata = cs; - - cs->fd = -1; - cs->swaplog_fd = -1; - - sd->init = storeCossDirInit; - sd->newfs = storeCossDirNewfs; - sd->dump = storeCossDirDump; - sd->freefs = storeCossDirShutdown; - sd->dblcheck = NULL; - sd->statfs = storeCossDirStats; - sd->maintainfs = NULL; - sd->checkobj = storeCossDirCheckObj; - sd->refobj = NULL; /* LRU is done in storeCossRead */ - sd->unrefobj = NULL; - sd->callback = storeCossDirCallback; - sd->sync = storeCossSync; - - sd->obj.create = storeCossCreate; - sd->obj.open = storeCossOpen; - sd->obj.close = storeCossClose; - sd->obj.read = storeCossRead; - sd->obj.write = storeCossWrite; - sd->obj.unlink = storeCossUnlink; - - sd->log.open = storeCossDirOpenSwapLog; - sd->log.close = storeCossDirCloseSwapLog; - sd->log.write = storeCossDirSwapLog; - sd->log.clean.start = storeCossDirWriteCleanStart; - sd->log.clean.write = storeCossDirWriteCleanEntry; - sd->log.clean.nextentry = storeCossDirCleanLogNextEntry; - sd->log.clean.done = storeCossDirWriteCleanDone; - - cs->current_offset = 0; - cs->fd = -1; - cs->swaplog_fd = -1; - cs->numcollisions = 0; - cs->membufs.head = cs->membufs.tail = NULL; /* set when the rebuild completes */ - cs->current_membuf = NULL; - cs->index.head = NULL; - cs->index.tail = NULL; - - parse_cachedir_options(sd, NULL, 0); - /* Enforce maxobjsize being set to something */ - if (sd->max_objsize == -1) - fatal("COSS requires max-size to be set to something other than -1!\n"); -} - - -static void -storeCossDirReconfigure(SwapDir * sd, int index, char *path) -{ - unsigned int i; - unsigned int size; - - i = GetInteger(); - size = i << 10; /* Mbytes to Kbytes */ - if (size <= 0) - fatal("storeCossDirParse: invalid size value"); - - if (size == sd->max_size) - debug(3, 1) ("Cache COSS dir '%s' size remains unchanged at %d KB\n", path, size); - else { - debug(3, 1) ("Cache COSS dir '%s' size changed to %d KB\n", path, size); - sd->max_size = size; - } - parse_cachedir_options(sd, NULL, 1); - /* Enforce maxobjsize being set to something */ - if (sd->max_objsize == -1) - fatal("COSS requires max-size to be set to something other than -1!\n"); -} - -void -storeCossDirDump(StoreEntry * entry, SwapDir * s) -{ - storeAppendPrintf(entry, " %d", - s->max_size >> 20); - dump_cachedir_options(entry, NULL, s); -} - -#if OLD_UNUSED_CODE -SwapDir * -storeCossDirPick(void) -{ - int i, choosenext = 0; - SwapDir *SD; - - if (n_coss_dirs == 0) - return NULL; - for (i = 0; i < Config.cacheSwap.n_configured; i++) { - SD = &Config.cacheSwap.swapDirs[i]; - if (SD->type == SWAPDIR_COSS) { - if ((last_coss_pick_index == -1) || (n_coss_dirs == 1)) { - last_coss_pick_index = i; - return SD; - } else if (choosenext) { - last_coss_pick_index = i; - return SD; - } else if (last_coss_pick_index == i) { - choosenext = 1; - } - } - } - for (i = 0; i < Config.cacheSwap.n_configured; i++) { - SD = &Config.cacheSwap.swapDirs[i]; - if (SD->type == SWAPDIR_COSS) { - if ((last_coss_pick_index == -1) || (n_coss_dirs == 1)) { - last_coss_pick_index = i; - return SD; - } else if (choosenext) { - last_coss_pick_index = i; - return SD; - } else if (last_coss_pick_index == i) { - choosenext = 1; - } - } - } - return NULL; -} -#endif - -/* - * initial setup/done code - */ -static void -storeCossDirDone(void) -{ - memPoolDestroy(&coss_state_pool); -/* memPoolDestroy(&coss_index_pool); XXX Should be here? */ - coss_initialised = 0; -} - -void -storeFsSetup_coss(storefs_entry_t * storefs) -{ - assert(!coss_initialised); - - storefs->parsefunc = storeCossDirParse; - storefs->reconfigurefunc = storeCossDirReconfigure; - storefs->donefunc = storeCossDirDone; - coss_state_pool = memPoolCreate("COSS IO State data", sizeof(CossState)); - coss_index_pool = memPoolCreate("COSS index data", sizeof(CossIndexNode)); - coss_initialised = 1; -} --- /dev/null Wed Feb 14 01:07:22 2007 +++ squid/src/fs/coss/store_dir_coss.cc Wed Feb 14 01:07:42 2007 @@ -0,0 +1,904 @@ + +/* + * $Id: store_dir_coss.cc,v 1.1.2.1 2002/10/12 12:21:43 rbcollins Exp $ + * + * DEBUG: section 47 Store COSS Directory Routines + * AUTHOR: Eric Stern + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" +#include "Store.h" +#include + +#include "async_io.h" +#include "store_coss.h" + +#define STORE_META_BUFSZ 4096 + +int n_coss_dirs = 0; +/* static int last_coss_pick_index = -1; */ +int coss_initialised = 0; +MemPool *coss_state_pool = NULL; +MemPool *coss_index_pool = NULL; + +typedef struct _RebuildState RebuildState; +struct _RebuildState { + SwapDir *sd; + int n_read; + FILE *log; + int speed; + struct { + unsigned int clean:1; + } flags; + struct _store_rebuild_data counts; +}; + +static char *storeCossDirSwapLogFile(SwapDir *, const char *); +static EVH storeCossRebuildFromSwapLog; +static StoreEntry *storeCossAddDiskRestore(SwapDir * SD, const cache_key * key, + int file_number, + size_t swap_file_sz, + time_t expires, + time_t timestamp, + time_t lastref, + time_t lastmod, + u_int32_t refcount, + u_int16_t flags, + int clean); +static void storeCossDirRebuild(SwapDir * sd); +static void storeCossDirCloseTmpSwapLog(SwapDir * sd); +static FILE *storeCossDirOpenTmpSwapLog(SwapDir *, int *, int *); +static STLOGOPEN storeCossDirOpenSwapLog; +static STINIT storeCossDirInit; +static STLOGCLEANSTART storeCossDirWriteCleanStart; +static STLOGCLEANNEXTENTRY storeCossDirCleanLogNextEntry; +static STLOGCLEANWRITE storeCossDirWriteCleanEntry; +static STLOGCLEANDONE storeCossDirWriteCleanDone; +static STLOGCLOSE storeCossDirCloseSwapLog; +static STLOGWRITE storeCossDirSwapLog; +static STNEWFS storeCossDirNewfs; +static STCHECKOBJ storeCossDirCheckObj; +static STFREE storeCossDirShutdown; +static STFSPARSE storeCossDirParse; +static STFSRECONFIGURE storeCossDirReconfigure; +static STDUMP storeCossDirDump; +static STCALLBACK storeCossDirCallback; + +/* The "only" externally visible function */ +STSETUP storeFsSetup_coss; + +static char * +storeCossDirSwapLogFile(SwapDir * sd, const char *ext) +{ + LOCAL_ARRAY(char, path, SQUID_MAXPATHLEN); + LOCAL_ARRAY(char, pathtmp, SQUID_MAXPATHLEN); + LOCAL_ARRAY(char, digit, 32); + char *pathtmp2; + if (Config.Log.swap) { + xstrncpy(pathtmp, sd->path, SQUID_MAXPATHLEN - 64); + pathtmp2 = pathtmp; + while ((pathtmp2 = strchr(pathtmp2, '/')) != NULL) + *pathtmp2 = '.'; + while (strlen(pathtmp) && pathtmp[strlen(pathtmp) - 1] == '.') + pathtmp[strlen(pathtmp) - 1] = '\0'; + for (pathtmp2 = pathtmp; *pathtmp2 == '.'; pathtmp2++); + snprintf(path, SQUID_MAXPATHLEN - 64, Config.Log.swap, pathtmp2); + if (strncmp(path, Config.Log.swap, SQUID_MAXPATHLEN - 64) == 0) { + strcat(path, "."); + snprintf(digit, 32, "%02d", sd->index); + strncat(path, digit, 3); + } + } else { + xstrncpy(path, sd->path, SQUID_MAXPATHLEN - 64); + strcat(path, "/swap.state"); + } + if (ext) + strncat(path, ext, 16); + return path; +} + +static void +storeCossDirOpenSwapLog(SwapDir * sd) +{ + CossInfo *cs = (CossInfo *) sd->fsdata; + char *path; + int fd; + path = storeCossDirSwapLogFile(sd, NULL); + fd = file_open(path, O_WRONLY | O_CREAT | O_BINARY); + if (fd < 0) { + debug(47, 1) ("%s: %s\n", path, xstrerror()); + fatal("storeCossDirOpenSwapLog: Failed to open swap log."); + } + debug(47, 3) ("Cache COSS Dir #%d log opened on FD %d\n", sd->index, fd); + cs->swaplog_fd = fd; +} + +static void +storeCossDirCloseSwapLog(SwapDir * sd) +{ + CossInfo *cs = (CossInfo *) sd->fsdata; + if (cs->swaplog_fd < 0) /* not open */ + return; + file_close(cs->swaplog_fd); + debug(47, 3) ("Cache COSS Dir #%d log closed on FD %d\n", + sd->index, cs->swaplog_fd); + cs->swaplog_fd = -1; +} + +static void +storeCossDirInit(SwapDir * sd) +{ + CossInfo *cs = (CossInfo *) sd->fsdata; + a_file_setupqueue(&cs->aq); + storeCossDirOpenSwapLog(sd); + storeCossDirRebuild(sd); + cs->fd = file_open(sd->path, O_RDWR | O_CREAT); + if (cs->fd < 0) { + debug(47, 1) ("%s: %s\n", sd->path, xstrerror()); + fatal("storeCossDirInit: Failed to open a COSS directory."); + } + n_coss_dirs++; + (void) storeDirGetBlkSize(sd->path, &sd->fs.blksize); +} + +void +storeCossRemove(SwapDir * sd, StoreEntry * e) +{ + CossInfo *cs = (CossInfo *) sd->fsdata; + CossIndexNode *coss_node = (CossIndexNode *)e->repl.data; + e->repl.data = NULL; + dlinkDelete(&coss_node->node, &cs->index); + memPoolFree(coss_index_pool, coss_node); + cs->count -= 1; +} + +void +storeCossAdd(SwapDir * sd, StoreEntry * e) +{ + CossInfo *cs = (CossInfo *) sd->fsdata; + CossIndexNode *coss_node = (CossIndexNode *)memPoolAlloc(coss_index_pool); + assert(!e->repl.data); + e->repl.data = coss_node; + dlinkAdd(e, &coss_node->node, &cs->index); + cs->count += 1; +} + +static void +storeCossRebuildComplete(void *data) +{ + RebuildState *rb = (RebuildState *)data; + SwapDir *sd = rb->sd; + storeCossStartMembuf(sd); + store_dirs_rebuilding--; + storeCossDirCloseTmpSwapLog(rb->sd); + storeRebuildComplete(&rb->counts); + cbdataFree(rb); +} + +static void +storeCossRebuildFromSwapLog(void *data) +{ + RebuildState *rb = (RebuildState *)data; + StoreEntry *e = NULL; + storeSwapLogData s; + size_t ss = sizeof(storeSwapLogData); + int count; + double x; + assert(rb != NULL); + /* load a number of objects per invocation */ + for (count = 0; count < rb->speed; count++) { + if (fread(&s, ss, 1, rb->log) != 1) { + debug(47, 1) ("Done reading %s swaplog (%d entries)\n", + rb->sd->path, rb->n_read); + fclose(rb->log); + rb->log = NULL; + storeCossRebuildComplete(rb); + return; + } + rb->n_read++; + if (s.op <= SWAP_LOG_NOP) + continue; + if (s.op >= SWAP_LOG_MAX) + continue; + debug(47, 3) ("storeCossRebuildFromSwapLog: %s %s %08X\n", + swap_log_op_str[(int) s.op], + storeKeyText(s.key), + s.swap_filen); + if (s.op == SWAP_LOG_ADD) { + (void) 0; + } else if (s.op == SWAP_LOG_DEL) { + if ((e = storeGet(s.key)) != NULL) { + /* + * Make sure we don't unlink the file, it might be + * in use by a subsequent entry. Also note that + * we don't have to subtract from store_swap_size + * because adding to store_swap_size happens in + * the cleanup procedure. + */ + storeExpireNow(e); + storeReleaseRequest(e); + if (e->swap_filen > -1) { + e->swap_filen = -1; + } + storeRelease(e); + /* Fake an unlink here, this is a bad hack :( */ + storeCossRemove(rb->sd, e); + rb->counts.objcount--; + rb->counts.cancelcount++; + } + continue; + } else { + x = log(++rb->counts.bad_log_op) / log(10.0); + if (0.0 == x - (double) (int) x) + debug(47, 1) ("WARNING: %d invalid swap log entries found\n", + rb->counts.bad_log_op); + rb->counts.invalid++; + continue; + } + if ((++rb->counts.scancount & 0xFFF) == 0) { + struct stat sb; + if (0 == fstat(fileno(rb->log), &sb)) + storeRebuildProgress(rb->sd->index, + (int) sb.st_size / ss, rb->n_read); + } + if (EBIT_TEST(s.flags, KEY_PRIVATE)) { + rb->counts.badflags++; + continue; + } + e = storeGet(s.key); + if (e) { + /* key already exists, current entry is newer */ + /* keep old, ignore new */ + rb->counts.dupcount++; + continue; + } + /* update store_swap_size */ + rb->counts.objcount++; + e = storeCossAddDiskRestore(rb->sd, s.key, + s.swap_filen, + s.swap_file_sz, + s.expires, + s.timestamp, + s.lastref, + s.lastmod, + s.refcount, + s.flags, + (int) rb->flags.clean); + storeDirSwapLog(e, SWAP_LOG_ADD); + } + eventAdd("storeCossRebuild", storeCossRebuildFromSwapLog, rb, 0.0, 1); +} + +/* Add a new object to the cache with empty memory copy and pointer to disk + * use to rebuild store from disk. */ +static StoreEntry * +storeCossAddDiskRestore(SwapDir * SD, const cache_key * key, + int file_number, + size_t swap_file_sz, + time_t expires, + time_t timestamp, + time_t lastref, + time_t lastmod, + u_int32_t refcount, + u_int16_t flags, + int clean) +{ + StoreEntry *e = NULL; + debug(47, 5) ("storeCossAddDiskRestore: %s, fileno=%08X\n", storeKeyText(key), file_number); + /* if you call this you'd better be sure file_number is not + * already in use! */ + e = new_StoreEntry(STORE_ENTRY_WITHOUT_MEMOBJ, NULL, NULL); + e->store_status = STORE_OK; + e->swap_dirn = SD->index; + storeSetMemStatus(e, NOT_IN_MEMORY); + e->swap_status = SWAPOUT_DONE; + e->swap_filen = file_number; + e->swap_file_sz = swap_file_sz; + e->lock_count = 0; + e->lastref = lastref; + e->timestamp = timestamp; + e->expires = expires; + e->lastmod = lastmod; + e->refcount = refcount; + e->flags = flags; + EBIT_SET(e->flags, ENTRY_CACHABLE); + EBIT_CLR(e->flags, RELEASE_REQUEST); + EBIT_CLR(e->flags, KEY_PRIVATE); + e->ping_status = PING_NONE; + EBIT_CLR(e->flags, ENTRY_VALIDATED); + storeHashInsert(e, key); /* do it after we clear KEY_PRIVATE */ + storeCossAdd(SD, e); + e->swap_filen = storeCossAllocate(SD, e, COSS_ALLOC_NOTIFY); + return e; +} + +CBDATA_TYPE(RebuildState); +static void +storeCossDirRebuild(SwapDir * sd) +{ + RebuildState *rb; + int clean = 0; + int zero = 0; + FILE *fp; + EVH *func = NULL; + CBDATA_INIT_TYPE(RebuildState); + rb = cbdataAlloc(RebuildState); + rb->sd = sd; + rb->speed = opt_foreground_rebuild ? 1 << 30 : 50; + func = storeCossRebuildFromSwapLog; + rb->flags.clean = (unsigned int) clean; + /* + * If the swap.state file exists in the cache_dir, then + * we'll use storeCossRebuildFromSwapLog(). + */ + fp = storeCossDirOpenTmpSwapLog(sd, &clean, &zero); + debug(47, 1) ("Rebuilding COSS storage in %s (%s)\n", + sd->path, clean ? "CLEAN" : "DIRTY"); + rb->log = fp; + store_dirs_rebuilding++; + if (!clean || fp == NULL) { + /* COSS cannot yet rebuild from a dirty state. If the log + * is dirty then the COSS contents is thrown away. + * Why? I guess it is because some contents will be lost, + * and COSS cannot verify this.. + */ + if (fp != NULL) + fclose(fp); + /* + * XXX Make sure we don't trigger an assertion if this is the first + * storedir, since if we are, this call will cause storeRebuildComplete + * to prematurely complete the rebuild process, and then some other + * storedir will try to rebuild and eventually die. + */ + eventAdd("storeCossRebuildComplete", storeCossRebuildComplete, rb, 0.0, 0); + return; + } + eventAdd("storeCossRebuild", func, rb, 0.0, 1); +} + +static void +storeCossDirCloseTmpSwapLog(SwapDir * sd) +{ + CossInfo *cs = (CossInfo *) sd->fsdata; + char *swaplog_path = xstrdup(storeCossDirSwapLogFile(sd, NULL)); + char *new_path = xstrdup(storeCossDirSwapLogFile(sd, ".new")); + int fd; + file_close(cs->swaplog_fd); +#if defined (_SQUID_OS2_) || defined (_SQUID_CYGWIN_) + if (unlink(swaplog_path) < 0) { + debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror()); + fatal("storeCossDirCloseTmpSwapLog: unlink failed"); + } +#endif + if (xrename(new_path, swaplog_path) < 0) { + fatal("storeCossDirCloseTmpSwapLog: rename failed"); + } + fd = file_open(swaplog_path, O_WRONLY | O_CREAT | O_BINARY); + if (fd < 0) { + debug(50, 1) ("%s: %s\n", swaplog_path, xstrerror()); + fatal("storeCossDirCloseTmpSwapLog: Failed to open swap log."); + } + safe_free(swaplog_path); + safe_free(new_path); + cs->swaplog_fd = fd; + debug(47, 3) ("Cache COSS Dir #%d log opened on FD %d\n", sd->index, fd); +} + +static FILE * +storeCossDirOpenTmpSwapLog(SwapDir * sd, int *clean_flag, int *zero_flag) +{ + CossInfo *cs = (CossInfo *) sd->fsdata; + char *swaplog_path = xstrdup(storeCossDirSwapLogFile(sd, NULL)); + char *clean_path = xstrdup(storeCossDirSwapLogFile(sd, ".last-clean")); + char *new_path = xstrdup(storeCossDirSwapLogFile(sd, ".new")); + struct stat log_sb; + struct stat clean_sb; + FILE *fp; + int fd; + if (stat(swaplog_path, &log_sb) < 0) { + debug(50, 1) ("Cache COSS Dir #%d: No log file\n", sd->index); + safe_free(swaplog_path); + safe_free(clean_path); + safe_free(new_path); + return NULL; + } + *zero_flag = log_sb.st_size == 0 ? 1 : 0; + /* close the existing write-only FD */ + if (cs->swaplog_fd >= 0) + file_close(cs->swaplog_fd); + /* open a write-only FD for the new log */ + fd = file_open(new_path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY); + if (fd < 0) { + debug(50, 1) ("%s: %s\n", new_path, xstrerror()); + fatal("storeDirOpenTmpSwapLog: Failed to open swap log."); + } + cs->swaplog_fd = fd; + /* open a read-only stream of the old log */ + fp = fopen(swaplog_path, "rb"); + if (fp == NULL) { + debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror()); + fatal("Failed to open swap log for reading"); + } + memset(&clean_sb, '\0', sizeof(struct stat)); + if (stat(clean_path, &clean_sb) < 0) + *clean_flag = 0; + else if (clean_sb.st_mtime < log_sb.st_mtime) + *clean_flag = 0; + else + *clean_flag = 1; + safeunlink(clean_path, 1); + safe_free(swaplog_path); + safe_free(clean_path); + safe_free(new_path); + return fp; +} + +struct _clean_state { + char *cur; + char *newLog; + char *cln; + char *outbuf; + off_t outbuf_offset; + int fd; + dlink_node *current; +}; + +#define CLEAN_BUF_SZ 16384 +/* + * Begin the process to write clean cache state. For COSS this means + * opening some log files and allocating write buffers. Return 0 if + * we succeed, and assign the 'func' and 'data' return pointers. + */ +static int +storeCossDirWriteCleanStart(SwapDir * sd) +{ + CossInfo *cs = (CossInfo *) sd->fsdata; + struct _clean_state *state = (struct _clean_state *)xcalloc(1, sizeof(*state)); +#if HAVE_FCHMOD + struct stat sb; +#endif + state->newLog = xstrdup(storeCossDirSwapLogFile(sd, ".clean")); + state->fd = file_open(state->newLog, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY); + if (state->fd < 0) { + xfree(state->newLog); + xfree(state); + return -1; + } + sd->log.clean.write = NULL; + sd->log.clean.state = NULL; + state->cur = xstrdup(storeCossDirSwapLogFile(sd, NULL)); + state->cln = xstrdup(storeCossDirSwapLogFile(sd, ".last-clean")); + state->outbuf = (char *)xcalloc(CLEAN_BUF_SZ, 1); + state->outbuf_offset = 0; + unlink(state->cln); + state->current = cs->index.tail; + debug(50, 3) ("storeCOssDirWriteCleanLogs: opened %s, FD %d\n", + state->newLog, state->fd); +#if HAVE_FCHMOD + if (stat(state->cur, &sb) == 0) + fchmod(state->fd, sb.st_mode); +#endif + sd->log.clean.write = storeCossDirWriteCleanEntry; + sd->log.clean.state = state; + + return 0; +} + +static const StoreEntry * +storeCossDirCleanLogNextEntry(SwapDir * sd) +{ + struct _clean_state *state = (struct _clean_state *)sd->log.clean.state; + const StoreEntry *entry; + if (!state) + return NULL; + if (!state->current) + return NULL; + entry = (const StoreEntry *) state->current->data; + state->current = state->current->prev; + return entry; +} + +/* + * "write" an entry to the clean log file. + */ +static void +storeCossDirWriteCleanEntry(SwapDir * sd, const StoreEntry * e) +{ + storeSwapLogData s; + static size_t ss = sizeof(storeSwapLogData); + struct _clean_state *state = (struct _clean_state *)sd->log.clean.state; + memset(&s, '\0', ss); + s.op = (char) SWAP_LOG_ADD; + s.swap_filen = e->swap_filen; + s.timestamp = e->timestamp; + s.lastref = e->lastref; + s.expires = e->expires; + s.lastmod = e->lastmod; + s.swap_file_sz = e->swap_file_sz; + s.refcount = e->refcount; + s.flags = e->flags; + xmemcpy(&s.key, e->hash.key, MD5_DIGEST_CHARS); + xmemcpy(state->outbuf + state->outbuf_offset, &s, ss); + state->outbuf_offset += ss; + /* buffered write */ + if (state->outbuf_offset + ss > CLEAN_BUF_SZ) { + if (FD_WRITE_METHOD(state->fd, state->outbuf, state->outbuf_offset) < 0) { + debug(50, 0) ("storeCossDirWriteCleanLogs: %s: write: %s\n", + state->newLog, xstrerror()); + debug(50, 0) ("storeCossDirWriteCleanLogs: Current swap logfile not replaced.\n"); + file_close(state->fd); + state->fd = -1; + unlink(state->newLog); + safe_free(state); + sd->log.clean.state = NULL; + sd->log.clean.write = NULL; + return; + } + state->outbuf_offset = 0; + } +} + +static void +storeCossDirWriteCleanDone(SwapDir * sd) +{ + int fd; + struct _clean_state *state = (struct _clean_state *)sd->log.clean.state; + if (NULL == state) + return; + if (state->fd < 0) + return; + if (FD_WRITE_METHOD(state->fd, state->outbuf, state->outbuf_offset) < 0) { + debug(50, 0) ("storeCossDirWriteCleanLogs: %s: write: %s\n", + state->newLog, xstrerror()); + debug(50, 0) ("storeCossDirWriteCleanLogs: Current swap logfile " + "not replaced.\n"); + file_close(state->fd); + state->fd = -1; + unlink(state->newLog); + } + safe_free(state->outbuf); + /* + * You can't rename open files on Microsoft "operating systems" + * so we have to close before renaming. + */ + storeCossDirCloseSwapLog(sd); + /* save the fd value for a later test */ + fd = state->fd; + /* rename */ + if (state->fd >= 0) { +#if defined(_SQUID_OS2_) || defined (_SQUID_CYGWIN_) + file_close(state->fd); + state->fd = -1; + if (unlink(state->cur) < 0) + debug(50, 0) ("storeCossDirWriteCleanLogs: unlinkd failed: %s, %s\n", + xstrerror(), state->cur); +#endif + xrename(state->newLog, state->cur); + } + /* touch a timestamp file if we're not still validating */ + if (store_dirs_rebuilding) + (void) 0; + else if (fd < 0) + (void) 0; + else + file_close(file_open(state->cln, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY)); + /* close */ + safe_free(state->cur); + safe_free(state->newLog); + safe_free(state->cln); + if (state->fd >= 0) + file_close(state->fd); + state->fd = -1; + safe_free(state); + sd->log.clean.state = NULL; + sd->log.clean.write = NULL; +} + +static void +storeSwapLogDataFree(void *s) +{ + memFree(s, MEM_SWAP_LOG_DATA); +} + +static void +storeCossDirSwapLog(const SwapDir * sd, const StoreEntry * e, int op) +{ + CossInfo *cs = (CossInfo *) sd->fsdata; + storeSwapLogData *s = (storeSwapLogData *)memAllocate(MEM_SWAP_LOG_DATA); + s->op = (char) op; + s->swap_filen = e->swap_filen; + s->timestamp = e->timestamp; + s->lastref = e->lastref; + s->expires = e->expires; + s->lastmod = e->lastmod; + s->swap_file_sz = e->swap_file_sz; + s->refcount = e->refcount; + s->flags = e->flags; + xmemcpy(s->key, e->hash.key, MD5_DIGEST_CHARS); + file_write(cs->swaplog_fd, + -1, + s, + sizeof(storeSwapLogData), + NULL, + NULL, + (FREE *) storeSwapLogDataFree); +} + +static void +storeCossDirNewfs(SwapDir * sd) +{ + debug(47, 3) ("Creating swap space in %s\n", sd->path); +} + +/* we are shutting down, flush all membufs to disk */ +static void +storeCossDirShutdown(SwapDir * SD) +{ + CossInfo *cs = (CossInfo *) SD->fsdata; + + storeCossSync(SD); /* This'll call a_file_syncqueue() */ + a_file_closequeue(&cs->aq); + file_close(cs->fd); + cs->fd = -1; + + if (cs->swaplog_fd > -1) { + file_close(cs->swaplog_fd); + cs->swaplog_fd = -1; + } + n_coss_dirs--; +} + +/* + * storeCossDirCheckObj + * + * This routine is called by storeDirSelectSwapDir to see if the given + * object is able to be stored on this filesystem. COSS filesystems will + * not store everything. We don't check for maxobjsize here since its + * done by the upper layers. + */ +int +storeCossDirCheckObj(SwapDir * SD, const StoreEntry * e) +{ + CossInfo *cs = (CossInfo *) SD->fsdata; + int loadav; + + /* Check if the object is a special object, we can't cache these */ + if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) + return -1; + + /* Otherwise, we're ok */ + /* Return load, cs->aq.aq_numpending out of MAX_ASYNCOP */ + loadav = cs->aq.aq_numpending * 1000 / MAX_ASYNCOP; + return loadav; +} + + +/* + * storeCossDirCallback - do the IO completions + */ +static int +storeCossDirCallback(SwapDir * SD) +{ + CossInfo *cs = (CossInfo *) SD->fsdata; + + return a_file_callback(&cs->aq); +} + +/* ========== LOCAL FUNCTIONS ABOVE, GLOBAL FUNCTIONS BELOW ========== */ + +static void +storeCossDirStats(SwapDir * SD, StoreEntry * sentry) +{ + CossInfo *cs = (CossInfo *) SD->fsdata; + + storeAppendPrintf(sentry, "\n"); + storeAppendPrintf(sentry, "Maximum Size: %d KB\n", SD->max_size); + storeAppendPrintf(sentry, "Current Size: %d KB\n", SD->cur_size); + storeAppendPrintf(sentry, "Percent Used: %0.2f%%\n", + 100.0 * SD->cur_size / SD->max_size); + storeAppendPrintf(sentry, "Number of object collisions: %d\n", (int) cs->numcollisions); +#if 0 + /* is this applicable? I Hope not .. */ + storeAppendPrintf(sentry, "Filemap bits in use: %d of %d (%d%%)\n", + SD->map->n_files_in_map, SD->map->max_n_files, + percent(SD->map->n_files_in_map, SD->map->max_n_files)); +#endif + storeAppendPrintf(sentry, "Pending operations: %d out of %d\n", cs->aq.aq_numpending, MAX_ASYNCOP); + storeAppendPrintf(sentry, "Flags:"); + if (SD->flags.selected) + storeAppendPrintf(sentry, " SELECTED"); + if (SD->flags.read_only) + storeAppendPrintf(sentry, " READ-ONLY"); + storeAppendPrintf(sentry, "\n"); +} + +static void +storeCossDirParse(SwapDir * sd, int index, char *path) +{ + unsigned int i; + unsigned int size; + CossInfo *cs; + + i = GetInteger(); + size = i << 10; /* Mbytes to Kbytes */ + if (size <= 0) + fatal("storeCossDirParse: invalid size value"); + + cs = (CossInfo *)xmalloc(sizeof(CossInfo)); + if (cs == NULL) + fatal("storeCossDirParse: couldn't xmalloc() CossInfo!\n"); + + sd->index = index; + sd->path = xstrdup(path); + sd->max_size = size; + sd->fsdata = cs; + + cs->fd = -1; + cs->swaplog_fd = -1; + + sd->init = storeCossDirInit; + sd->newfs = storeCossDirNewfs; + sd->dump = storeCossDirDump; + sd->freefs = storeCossDirShutdown; + sd->dblcheck = NULL; + sd->statfs = storeCossDirStats; + sd->maintainfs = NULL; + sd->checkobj = storeCossDirCheckObj; + sd->refobj = NULL; /* LRU is done in storeCossRead */ + sd->unrefobj = NULL; + sd->callback = storeCossDirCallback; + sd->sync = storeCossSync; + + sd->obj.create = storeCossCreate; + sd->obj.open = storeCossOpen; + sd->obj.close = storeCossClose; + sd->obj.read = storeCossRead; + sd->obj.write = storeCossWrite; + sd->obj.unlink = storeCossUnlink; + + sd->log.open = storeCossDirOpenSwapLog; + sd->log.close = storeCossDirCloseSwapLog; + sd->log.write = storeCossDirSwapLog; + sd->log.clean.start = storeCossDirWriteCleanStart; + sd->log.clean.write = storeCossDirWriteCleanEntry; + sd->log.clean.nextentry = storeCossDirCleanLogNextEntry; + sd->log.clean.done = storeCossDirWriteCleanDone; + + cs->current_offset = 0; + cs->fd = -1; + cs->swaplog_fd = -1; + cs->numcollisions = 0; + cs->membufs.head = cs->membufs.tail = NULL; /* set when the rebuild completes */ + cs->current_membuf = NULL; + cs->index.head = NULL; + cs->index.tail = NULL; + + parse_cachedir_options(sd, NULL, 0); + /* Enforce maxobjsize being set to something */ + if (sd->max_objsize == -1) + fatal("COSS requires max-size to be set to something other than -1!\n"); +} + + +static void +storeCossDirReconfigure(SwapDir * sd, int index, char *path) +{ + unsigned int i; + unsigned int size; + + i = GetInteger(); + size = i << 10; /* Mbytes to Kbytes */ + if (size <= 0) + fatal("storeCossDirParse: invalid size value"); + + if (size == (size_t)sd->max_size) + debug(3, 1) ("Cache COSS dir '%s' size remains unchanged at %d KB\n", path, size); + else { + debug(3, 1) ("Cache COSS dir '%s' size changed to %d KB\n", path, size); + sd->max_size = size; + } + parse_cachedir_options(sd, NULL, 1); + /* Enforce maxobjsize being set to something */ + if (sd->max_objsize == -1) + fatal("COSS requires max-size to be set to something other than -1!\n"); +} + +void +storeCossDirDump(StoreEntry * entry, SwapDir * s) +{ + storeAppendPrintf(entry, " %d", + s->max_size >> 20); + dump_cachedir_options(entry, NULL, s); +} + +#if OLD_UNUSED_CODE +SwapDir * +storeCossDirPick(void) +{ + int i, choosenext = 0; + SwapDir *SD; + + if (n_coss_dirs == 0) + return NULL; + for (i = 0; i < Config.cacheSwap.n_configured; i++) { + SD = &Config.cacheSwap.swapDirs[i]; + if (SD->type == SWAPDIR_COSS) { + if ((last_coss_pick_index == -1) || (n_coss_dirs == 1)) { + last_coss_pick_index = i; + return SD; + } else if (choosenext) { + last_coss_pick_index = i; + return SD; + } else if (last_coss_pick_index == i) { + choosenext = 1; + } + } + } + for (i = 0; i < Config.cacheSwap.n_configured; i++) { + SD = &Config.cacheSwap.swapDirs[i]; + if (SD->type == SWAPDIR_COSS) { + if ((last_coss_pick_index == -1) || (n_coss_dirs == 1)) { + last_coss_pick_index = i; + return SD; + } else if (choosenext) { + last_coss_pick_index = i; + return SD; + } else if (last_coss_pick_index == i) { + choosenext = 1; + } + } + } + return NULL; +} +#endif + +/* + * initial setup/done code + */ +static void +storeCossDirDone(void) +{ + memPoolDestroy(&coss_state_pool); +/* memPoolDestroy(&coss_index_pool); XXX Should be here? */ + coss_initialised = 0; +} + +void +storeFsSetup_coss(storefs_entry_t * storefs) +{ + assert(!coss_initialised); + + storefs->parsefunc = storeCossDirParse; + storefs->reconfigurefunc = storeCossDirReconfigure; + storefs->donefunc = storeCossDirDone; + coss_state_pool = memPoolCreate("COSS IO State data", sizeof(CossState)); + coss_index_pool = memPoolCreate("COSS index data", sizeof(CossIndexNode)); + coss_initialised = 1; +} --- squid/src/fs/coss/store_io_coss.c Wed Feb 14 01:07:42 2007 +++ /dev/null Wed Feb 14 01:07:22 2007 @@ -1,568 +0,0 @@ - -/* - * $Id$ - * - * DEBUG: section 79 Storage Manager COSS Interface - * AUTHOR: Eric Stern - * - * SQUID Web Proxy Cache http://www.squid-cache.org/ - * ---------------------------------------------------------- - * - * Squid is the result of efforts by numerous individuals from - * the Internet community; see the CONTRIBUTORS file for full - * details. Many organizations have provided support for Squid's - * development; see the SPONSORS file for full details. Squid is - * Copyrighted (C) 2001 by the Regents of the University of - * California; see the COPYRIGHT file for full details. Squid - * incorporates software developed and/or copyrighted by other - * sources; see the CREDITS file for full details. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. - * - */ - -#include "squid.h" -#include "Store.h" -#include -#include "async_io.h" -#include "store_coss.h" - -static DWCB storeCossWriteMemBufDone; -static DRCB storeCossReadDone; -static void storeCossIOCallback(storeIOState * sio, int errflag); -static char *storeCossMemPointerFromDiskOffset(SwapDir * SD, size_t offset, CossMemBuf ** mb); -static void storeCossMemBufLock(SwapDir * SD, storeIOState * e); -static void storeCossMemBufUnlock(SwapDir * SD, storeIOState * e); -static void storeCossWriteMemBuf(SwapDir * SD, CossMemBuf * t); -static void storeCossWriteMemBufDone(int fd, int errflag, size_t len, void *my_data); -static CossMemBuf *storeCossCreateMemBuf(SwapDir * SD, size_t start, - sfileno curfn, int *collision); -static CBDUNL storeCossIOFreeEntry; - -CBDATA_TYPE(storeIOState); -CBDATA_TYPE(CossMemBuf); - -/* === PUBLIC =========================================================== */ - -/* - * This routine sucks. I want to rewrite it when possible, and I also think - * that we should check after creatmembuf() to see if the object has a - * RELEASE_REQUEST set on it (thanks Eric!) rather than this way which seems - * to work.. - * -- Adrian - */ -off_t -storeCossAllocate(SwapDir * SD, const StoreEntry * e, int which) -{ - CossInfo *cs = (CossInfo *) SD->fsdata; - CossMemBuf *newmb; - off_t retofs; - size_t allocsize; - int coll = 0; - sfileno checkf; - - /* Make sure we chcek collisions if reallocating */ - if (which == COSS_ALLOC_REALLOC) - checkf = e->swap_filen; - else - checkf = -1; - - retofs = e->swap_filen; /* Just for defaults, or while rebuilding */ - - if (e->swap_file_sz > 0) - allocsize = e->swap_file_sz; - else - allocsize = objectLen(e) + e->mem_obj->swap_hdr_sz; - - /* Since we're not supporting NOTIFY anymore, lets fail */ - assert(which != COSS_ALLOC_NOTIFY); - - /* Check if we have overflowed the disk .. */ - if ((cs->current_offset + allocsize) > (SD->max_size << 10)) { - /* - * tried to allocate past the end of the disk, so wrap - * back to the beginning - */ - cs->current_membuf->flags.full = 1; - cs->current_membuf->diskend = cs->current_offset - 1; - cs->current_offset = 0; /* wrap back to beginning */ - debug(79, 2) ("storeCossAllocate: wrap to 0\n"); - - newmb = storeCossCreateMemBuf(SD, 0, checkf, &coll); - cs->current_membuf = newmb; - - /* Check if we have overflowed the MemBuf */ - } else if ((cs->current_offset + allocsize) > cs->current_membuf->diskend) { - /* - * Skip the blank space at the end of the stripe. start over. - */ - cs->current_membuf->flags.full = 1; - cs->current_offset = cs->current_membuf->diskend + 1; - debug(79, 2) ("storeCossAllocate: New offset - %ld\n", - (long int) cs->current_offset); - newmb = storeCossCreateMemBuf(SD, cs->current_offset, checkf, &coll); - cs->current_membuf = newmb; - } - /* If we didn't get a collision, then update the current offset and return it */ - if (coll == 0) { - retofs = cs->current_offset; - cs->current_offset = retofs + allocsize; - return retofs; - } else { - debug(79, 3) ("storeCossAllocate: Collision\n"); - return -1; - } -} - -void -storeCossUnlink(SwapDir * SD, StoreEntry * e) -{ - debug(79, 3) ("storeCossUnlink: offset %d\n", e->swap_filen); - storeCossRemove(SD, e); -} - - -storeIOState * -storeCossCreate(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, STIOCB * callback, void *callback_data) -{ - CossState *cstate; - storeIOState *sio; - - CBDATA_INIT_TYPE_FREECB(storeIOState, storeCossIOFreeEntry); - sio = cbdataAlloc(storeIOState); - cstate = memPoolAlloc(coss_state_pool); - sio->fsstate = cstate; - sio->offset = 0; - sio->mode = O_WRONLY | O_BINARY; - - /* - * If we get handed an object with a size of -1, - * the squid code is broken - */ - assert(e->mem_obj->object_sz != -1); - - /* - * this one is kinda strange - Eric called storeCossAllocate(), then - * storeCossOpen(O_RDONLY) .. weird. Anyway, I'm allocating this now. - */ - sio->st_size = objectLen(e) + e->mem_obj->swap_hdr_sz; - sio->swap_dirn = SD->index; - sio->swap_filen = storeCossAllocate(SD, e, COSS_ALLOC_ALLOCATE); - debug(79, 3) ("storeCossCreate: offset %d, size %ld, end %ld\n", sio->swap_filen, (long int) sio->st_size, (long int) (sio->swap_filen + sio->st_size)); - - sio->callback = callback; - sio->file_callback = file_callback; - sio->callback_data = cbdataReference(callback_data); - sio->e = (StoreEntry *) e; - - cstate->flags.writing = 0; - cstate->flags.reading = 0; - cstate->readbuffer = NULL; - cstate->reqdiskoffset = -1; - - /* Now add it into the index list */ - storeCossAdd(SD, e); - - storeCossMemBufLock(SD, sio); - return sio; -} - -storeIOState * -storeCossOpen(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, - STIOCB * callback, void *callback_data) -{ - storeIOState *sio; - char *p; - CossState *cstate; - sfileno f = e->swap_filen; - CossInfo *cs = (CossInfo *) SD->fsdata; - - debug(79, 3) ("storeCossOpen: offset %d\n", f); - - CBDATA_INIT_TYPE_FREECB(storeIOState, storeCossIOFreeEntry); - sio = cbdataAlloc(storeIOState); - cstate = memPoolAlloc(coss_state_pool); - - sio->fsstate = cstate; - sio->swap_filen = f; - sio->swap_dirn = SD->index; - sio->offset = 0; - sio->mode = O_RDONLY | O_BINARY; - sio->callback = callback; - sio->file_callback = file_callback; - sio->callback_data = cbdataReference(callback_data); - sio->st_size = e->swap_file_sz; - sio->e = e; - - cstate->flags.writing = 0; - cstate->flags.reading = 0; - cstate->readbuffer = NULL; - cstate->reqdiskoffset = -1; - p = storeCossMemPointerFromDiskOffset(SD, f, NULL); - /* make local copy so we don't have to lock membuf */ - if (p) { - cstate->readbuffer = xmalloc(sio->st_size); - xmemcpy(cstate->readbuffer, p, sio->st_size); - } else { - /* Do the allocation */ - /* this is the first time we've been called on a new sio - * read the whole object into memory, then return the - * requested amount - */ - /* - * This bit of code actually does the LRU disk thing - we realloc - * a place for the object here, and the file_read() reads the object - * into the cossmembuf for later writing .. - */ - cstate->reqdiskoffset = sio->swap_filen; - sio->swap_filen = -1; - sio->swap_filen = storeCossAllocate(SD, e, COSS_ALLOC_REALLOC); - if (sio->swap_filen == -1) { - /* We have to clean up neatly .. */ - cbdataFree(sio); - cs->numcollisions++; - debug(79, 2) ("storeCossOpen: Reallocation of %d/%d failed\n", e->swap_dirn, e->swap_filen); - /* XXX XXX XXX Will squid call storeUnlink for this object? */ - return NULL; - } - /* Notify the upper levels that we've changed file number */ - sio->file_callback(sio->callback_data, 0, sio); - - /* - * lock the buffer so it doesn't get swapped out on us - * this will get unlocked in storeCossReadDone - */ - storeCossMemBufLock(SD, sio); - - /* - * Do the index magic to keep the disk and memory LRUs identical - */ - storeCossRemove(SD, e); - storeCossAdd(SD, e); - - /* - * Since we've reallocated a spot for this object, we need to - * write it to the cossmembuf *and* return it in the read .. - */ - cstate->readbuffer = NULL; - } - return sio; -} - -void -storeCossClose(SwapDir * SD, storeIOState * sio) -{ - debug(79, 3) ("storeCossClose: offset %d\n", sio->swap_filen); - if (FILE_MODE(sio->mode) == O_WRONLY) - storeCossMemBufUnlock(SD, sio); - storeCossIOCallback(sio, 0); -} - -void -storeCossRead(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data) -{ - char *p; - CossState *cstate = (CossState *) sio->fsstate; - CossInfo *cs = (CossInfo *) SD->fsdata; - - assert(sio->read.callback == NULL); - assert(sio->read.callback_data == NULL); - sio->read.callback = callback; - sio->read.callback_data = cbdataReference(callback_data); - debug(79, 3) ("storeCossRead: offset %ld\n", (long int) offset); - sio->offset = offset; - cstate->flags.reading = 1; - if ((offset + size) > sio->st_size) - size = sio->st_size - offset; - cstate->requestlen = size; - cstate->requestbuf = buf; - cstate->requestoffset = offset; - if (cstate->readbuffer == NULL) { - p = storeCossMemPointerFromDiskOffset(SD, sio->swap_filen, NULL); - /* Remember we need to translate the block offset to a disk offset! */ - a_file_read(&cs->aq, cs->fd, - p, - sio->st_size, - cstate->reqdiskoffset, - storeCossReadDone, - sio); - cstate->reqdiskoffset = 0; /* XXX */ - } else { - storeCossReadDone(cs->fd, - cstate->readbuffer, - sio->st_size, - 0, - sio); - } -} - -void -storeCossWrite(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, FREE * free_func) -{ - char *dest; - CossMemBuf *membuf; - off_t diskoffset; - - /* - * If we get handed an object with a size of -1, - * the squid code is broken - */ - assert(sio->e->mem_obj->object_sz != -1); - - debug(79, 3) ("storeCossWrite: offset %ld, len %lu\n", (long int) sio->offset, (unsigned long int) size); - diskoffset = sio->swap_filen + sio->offset; - dest = storeCossMemPointerFromDiskOffset(SD, diskoffset, &membuf); - assert(dest != NULL); - xmemcpy(dest, buf, size); - sio->offset += size; - if (free_func) - (free_func) (buf); -} - - -/* === STATIC =========================================================== */ - -static void -storeCossReadDone(int fd, const char *buf, int len, int errflag, void *my_data) -{ - storeIOState *sio = my_data; - char *p; - STRCB *callback = sio->read.callback; - void *cbdata; - SwapDir *SD = INDEXSD(sio->swap_dirn); - CossState *cstate = (CossState *) sio->fsstate; - size_t rlen; - - debug(79, 3) ("storeCossReadDone: fileno %d, FD %d, len %d\n", - sio->swap_filen, fd, len); - cstate->flags.reading = 0; - if (errflag) { - debug(79, 3) ("storeCossReadDone: got failure (%d)\n", errflag); - rlen = -1; - } else { - if (cstate->readbuffer == NULL) { - cstate->readbuffer = xmalloc(sio->st_size); - p = storeCossMemPointerFromDiskOffset(SD, sio->swap_filen, NULL); - xmemcpy(cstate->readbuffer, p, sio->st_size); - storeCossMemBufUnlock(SD, sio); - } - sio->offset += len; - xmemcpy(cstate->requestbuf, &cstate->readbuffer[cstate->requestoffset], - cstate->requestlen); - rlen = (size_t) cstate->requestlen; - } - assert(callback); - sio->read.callback = NULL; - if (cbdataReferenceValidDone(sio->read.callback_data, &cbdata)) - callback(cbdata, cstate->requestbuf, rlen); -} - -static void -storeCossIOCallback(storeIOState * sio, int errflag) -{ - CossState *cstate = (CossState *) sio->fsstate; - STIOCB *callback = sio->callback; - void *cbdata; - debug(79, 3) ("storeCossIOCallback: errflag=%d\n", errflag); - xfree(cstate->readbuffer); - sio->callback = NULL; - if (cbdataReferenceValidDone(sio->callback_data, &cbdata)) - callback(cbdata, errflag, sio); - cbdataFree(sio); -} - -static char * -storeCossMemPointerFromDiskOffset(SwapDir * SD, size_t offset, CossMemBuf ** mb) -{ - CossMemBuf *t; - dlink_node *m; - CossInfo *cs = (CossInfo *) SD->fsdata; - - for (m = cs->membufs.head; m; m = m->next) { - t = m->data; - if ((offset >= t->diskstart) && (offset <= t->diskend)) { - if (mb) - *mb = t; - return &t->buffer[offset - t->diskstart]; - } - } - - if (mb) - *mb = NULL; - return NULL; -} - -static void -storeCossMemBufLock(SwapDir * SD, storeIOState * e) -{ - CossMemBuf *t; - dlink_node *m; - CossInfo *cs = (CossInfo *) SD->fsdata; - - for (m = cs->membufs.head; m; m = m->next) { - t = m->data; - if ((e->swap_filen >= t->diskstart) && (e->swap_filen <= t->diskend)) { - debug(79, 3) ("storeCossMemBufLock: locking %p, lockcount %d\n", t, t->lockcount); - t->lockcount++; - return; - } - } - debug(79, 3) ("storeCossMemBufLock: FAILED to lock %p\n", e); -} - -static void -storeCossMemBufUnlock(SwapDir * SD, storeIOState * e) -{ - CossMemBuf *t; - dlink_node *m, *n; - CossInfo *cs = (CossInfo *) SD->fsdata; - - for (m = cs->membufs.head; m; m = n) { - /* - * Note that storeCossWriteMemBuf() might call storeCossWriteMemBufDone - * immediately (if the write finishes immediately, of course!) which - * will make m = m->next kinda unworkable. So, get the next pointer. - */ - n = m->next; - t = m->data; - if ((e->swap_filen >= t->diskstart) && (e->swap_filen <= t->diskend)) { - t->lockcount--; - debug(79, 3) ("storeCossMemBufUnlock: unlocking %p, lockcount %d\n", t, t->lockcount); - } - if (t->flags.full && !t->flags.writing && !t->lockcount) - storeCossWriteMemBuf(SD, t); - } -} - -void -storeCossSync(SwapDir * SD) -{ - CossInfo *cs = (CossInfo *) SD->fsdata; - CossMemBuf *t; - dlink_node *m; - int end; - - /* First, flush pending IO ops */ - a_file_syncqueue(&cs->aq); - - /* Then, flush any in-memory partial membufs */ - if (!cs->membufs.head) - return; - for (m = cs->membufs.head; m; m = m->next) { - t = m->data; - if (t->flags.writing) - sleep(5); /* XXX EEEWWW! */ - lseek(cs->fd, t->diskstart, SEEK_SET); - end = (t == cs->current_membuf) ? cs->current_offset : t->diskend; - FD_WRITE_METHOD(cs->fd, t->buffer, end - t->diskstart); - } -} - -static void -storeCossWriteMemBuf(SwapDir * SD, CossMemBuf * t) -{ - CossInfo *cs = (CossInfo *) SD->fsdata; - debug(79, 3) ("storeCossWriteMemBuf: offset %ld, len %ld\n", - (long int) t->diskstart, (long int) (t->diskend - t->diskstart)); - t->flags.writing = 1; - /* Remember that diskstart/diskend are block offsets! */ - a_file_write(&cs->aq, cs->fd, t->diskstart, &t->buffer, - t->diskend - t->diskstart, storeCossWriteMemBufDone, t, NULL); -} - - -static void -storeCossWriteMemBufDone(int fd, int errflag, size_t len, void *my_data) -{ - CossMemBuf *t = my_data; - CossInfo *cs = (CossInfo *) t->SD->fsdata; - - debug(79, 3) ("storeCossWriteMemBufDone: buf %p, len %ld\n", t, (long int) len); - if (errflag) - debug(79, 0) ("storeCossMemBufWriteDone: got failure (%d)\n", errflag); - - dlinkDelete(&t->node, &cs->membufs); - cbdataFree(t); -} - -static CossMemBuf * -storeCossCreateMemBuf(SwapDir * SD, size_t start, - sfileno curfn, int *collision) -{ - CossMemBuf *newmb, *t; - StoreEntry *e; - dlink_node *m, *prev; - int numreleased = 0; - CossInfo *cs = (CossInfo *) SD->fsdata; - - CBDATA_INIT_TYPE_FREECB(CossMemBuf, NULL); - newmb = cbdataAlloc(CossMemBuf); - newmb->diskstart = start; - debug(79, 3) ("storeCossCreateMemBuf: creating new membuf at %ld\n", (long int) newmb->diskstart); - debug(79, 3) ("storeCossCreateMemBuf: at %p\n", newmb); - newmb->diskend = newmb->diskstart + COSS_MEMBUF_SZ - 1; - newmb->flags.full = 0; - newmb->flags.writing = 0; - newmb->lockcount = 0; - newmb->SD = SD; - /* XXX This should be reversed, with the new buffer last in the chain */ - dlinkAdd(newmb, &newmb->node, &cs->membufs); - - /* Print out the list of membufs */ - for (m = cs->membufs.head; m; m = m->next) { - t = m->data; - debug(79, 3) ("storeCossCreateMemBuf: membuflist %ld lockcount %d\n", (long int) t->diskstart, t->lockcount); - } - - /* - * Kill objects from the tail to make space for a new chunk - */ - for (m = cs->index.tail; m; m = prev) { - prev = m->prev; - e = m->data; - if (curfn == e->swap_filen) - *collision = 1; /* Mark an object alloc collision */ - if ((e->swap_filen >= newmb->diskstart) && - (e->swap_filen <= newmb->diskend)) { - storeRelease(e); - numreleased++; - } else - break; - } - if (numreleased > 0) - debug(79, 3) ("storeCossCreateMemBuf: this allocation released %d storeEntries\n", numreleased); - return newmb; -} - -/* - * Creates the initial membuf after rebuild - */ -void -storeCossStartMembuf(SwapDir * sd) -{ - CossInfo *cs = (CossInfo *) sd->fsdata; - CossMemBuf *newmb = storeCossCreateMemBuf(sd, cs->current_offset, -1, NULL); - assert(!cs->current_membuf); - cs->current_membuf = newmb; -} - -/* - * Clean up any references from the SIO before it get's released. - */ -static void -storeCossIOFreeEntry(void *sio) -{ - memPoolFree(coss_state_pool, ((storeIOState *) sio)->fsstate); -} --- /dev/null Wed Feb 14 01:07:22 2007 +++ squid/src/fs/coss/store_io_coss.cc Wed Feb 14 01:07:42 2007 @@ -0,0 +1,568 @@ + +/* + * $Id: store_io_coss.cc,v 1.1.2.1 2002/10/12 12:21:43 rbcollins Exp $ + * + * DEBUG: section 79 Storage Manager COSS Interface + * AUTHOR: Eric Stern + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" +#include "Store.h" +#include +#include "async_io.h" +#include "store_coss.h" + +static DWCB storeCossWriteMemBufDone; +static DRCB storeCossReadDone; +static void storeCossIOCallback(storeIOState * sio, int errflag); +static char *storeCossMemPointerFromDiskOffset(SwapDir * SD, size_t offset, CossMemBuf ** mb); +static void storeCossMemBufLock(SwapDir * SD, storeIOState * e); +static void storeCossMemBufUnlock(SwapDir * SD, storeIOState * e); +static void storeCossWriteMemBuf(SwapDir * SD, CossMemBuf * t); +static void storeCossWriteMemBufDone(int fd, int errflag, size_t len, void *my_data); +static CossMemBuf *storeCossCreateMemBuf(SwapDir * SD, size_t start, + sfileno curfn, int *collision); +static CBDUNL storeCossIOFreeEntry; + +CBDATA_TYPE(storeIOState); +CBDATA_TYPE(CossMemBuf); + +/* === PUBLIC =========================================================== */ + +/* + * This routine sucks. I want to rewrite it when possible, and I also think + * that we should check after creatmembuf() to see if the object has a + * RELEASE_REQUEST set on it (thanks Eric!) rather than this way which seems + * to work.. + * -- Adrian + */ +off_t +storeCossAllocate(SwapDir * SD, const StoreEntry * e, int which) +{ + CossInfo *cs = (CossInfo *) SD->fsdata; + CossMemBuf *newmb; + off_t retofs; + size_t allocsize; + int coll = 0; + sfileno checkf; + + /* Make sure we chcek collisions if reallocating */ + if (which == COSS_ALLOC_REALLOC) + checkf = e->swap_filen; + else + checkf = -1; + + retofs = e->swap_filen; /* Just for defaults, or while rebuilding */ + + if (e->swap_file_sz > 0) + allocsize = e->swap_file_sz; + else + allocsize = objectLen(e) + e->mem_obj->swap_hdr_sz; + + /* Since we're not supporting NOTIFY anymore, lets fail */ + assert(which != COSS_ALLOC_NOTIFY); + + /* Check if we have overflowed the disk .. */ + if ((cs->current_offset + allocsize) > (size_t)(SD->max_size << 10)) { + /* + * tried to allocate past the end of the disk, so wrap + * back to the beginning + */ + cs->current_membuf->flags.full = 1; + cs->current_membuf->diskend = cs->current_offset - 1; + cs->current_offset = 0; /* wrap back to beginning */ + debug(79, 2) ("storeCossAllocate: wrap to 0\n"); + + newmb = storeCossCreateMemBuf(SD, 0, checkf, &coll); + cs->current_membuf = newmb; + + /* Check if we have overflowed the MemBuf */ + } else if ((cs->current_offset + allocsize) > cs->current_membuf->diskend) { + /* + * Skip the blank space at the end of the stripe. start over. + */ + cs->current_membuf->flags.full = 1; + cs->current_offset = cs->current_membuf->diskend + 1; + debug(79, 2) ("storeCossAllocate: New offset - %ld\n", + (long int) cs->current_offset); + newmb = storeCossCreateMemBuf(SD, cs->current_offset, checkf, &coll); + cs->current_membuf = newmb; + } + /* If we didn't get a collision, then update the current offset and return it */ + if (coll == 0) { + retofs = cs->current_offset; + cs->current_offset = retofs + allocsize; + return retofs; + } else { + debug(79, 3) ("storeCossAllocate: Collision\n"); + return -1; + } +} + +void +storeCossUnlink(SwapDir * SD, StoreEntry * e) +{ + debug(79, 3) ("storeCossUnlink: offset %d\n", e->swap_filen); + storeCossRemove(SD, e); +} + + +storeIOState * +storeCossCreate(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, STIOCB * callback, void *callback_data) +{ + CossState *cstate; + storeIOState *sio; + + CBDATA_INIT_TYPE_FREECB(storeIOState, storeCossIOFreeEntry); + sio = cbdataAlloc(storeIOState); + cstate = (CossState *)memPoolAlloc(coss_state_pool); + sio->fsstate = cstate; + sio->offset = 0; + sio->mode = O_WRONLY | O_BINARY; + + /* + * If we get handed an object with a size of -1, + * the squid code is broken + */ + assert(e->mem_obj->object_sz != -1); + + /* + * this one is kinda strange - Eric called storeCossAllocate(), then + * storeCossOpen(O_RDONLY) .. weird. Anyway, I'm allocating this now. + */ + sio->st_size = objectLen(e) + e->mem_obj->swap_hdr_sz; + sio->swap_dirn = SD->index; + sio->swap_filen = storeCossAllocate(SD, e, COSS_ALLOC_ALLOCATE); + debug(79, 3) ("storeCossCreate: offset %d, size %ld, end %ld\n", sio->swap_filen, (long int) sio->st_size, (long int) (sio->swap_filen + sio->st_size)); + + sio->callback = callback; + sio->file_callback = file_callback; + sio->callback_data = cbdataReference(callback_data); + sio->e = (StoreEntry *) e; + + cstate->flags.writing = 0; + cstate->flags.reading = 0; + cstate->readbuffer = NULL; + cstate->reqdiskoffset = -1; + + /* Now add it into the index list */ + storeCossAdd(SD, e); + + storeCossMemBufLock(SD, sio); + return sio; +} + +storeIOState * +storeCossOpen(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, + STIOCB * callback, void *callback_data) +{ + storeIOState *sio; + char *p; + CossState *cstate; + sfileno f = e->swap_filen; + CossInfo *cs = (CossInfo *) SD->fsdata; + + debug(79, 3) ("storeCossOpen: offset %d\n", f); + + CBDATA_INIT_TYPE_FREECB(storeIOState, storeCossIOFreeEntry); + sio = cbdataAlloc(storeIOState); + cstate = (CossState *)memPoolAlloc(coss_state_pool); + + sio->fsstate = cstate; + sio->swap_filen = f; + sio->swap_dirn = SD->index; + sio->offset = 0; + sio->mode = O_RDONLY | O_BINARY; + sio->callback = callback; + sio->file_callback = file_callback; + sio->callback_data = cbdataReference(callback_data); + sio->st_size = e->swap_file_sz; + sio->e = e; + + cstate->flags.writing = 0; + cstate->flags.reading = 0; + cstate->readbuffer = NULL; + cstate->reqdiskoffset = -1; + p = storeCossMemPointerFromDiskOffset(SD, f, NULL); + /* make local copy so we don't have to lock membuf */ + if (p) { + cstate->readbuffer = (char *)xmalloc(sio->st_size); + xmemcpy(cstate->readbuffer, p, sio->st_size); + } else { + /* Do the allocation */ + /* this is the first time we've been called on a new sio + * read the whole object into memory, then return the + * requested amount + */ + /* + * This bit of code actually does the LRU disk thing - we realloc + * a place for the object here, and the file_read() reads the object + * into the cossmembuf for later writing .. + */ + cstate->reqdiskoffset = sio->swap_filen; + sio->swap_filen = -1; + sio->swap_filen = storeCossAllocate(SD, e, COSS_ALLOC_REALLOC); + if (sio->swap_filen == -1) { + /* We have to clean up neatly .. */ + cbdataFree(sio); + cs->numcollisions++; + debug(79, 2) ("storeCossOpen: Reallocation of %d/%d failed\n", e->swap_dirn, e->swap_filen); + /* XXX XXX XXX Will squid call storeUnlink for this object? */ + return NULL; + } + /* Notify the upper levels that we've changed file number */ + sio->file_callback(sio->callback_data, 0, sio); + + /* + * lock the buffer so it doesn't get swapped out on us + * this will get unlocked in storeCossReadDone + */ + storeCossMemBufLock(SD, sio); + + /* + * Do the index magic to keep the disk and memory LRUs identical + */ + storeCossRemove(SD, e); + storeCossAdd(SD, e); + + /* + * Since we've reallocated a spot for this object, we need to + * write it to the cossmembuf *and* return it in the read .. + */ + cstate->readbuffer = NULL; + } + return sio; +} + +void +storeCossClose(SwapDir * SD, storeIOState * sio) +{ + debug(79, 3) ("storeCossClose: offset %d\n", sio->swap_filen); + if (FILE_MODE(sio->mode) == O_WRONLY) + storeCossMemBufUnlock(SD, sio); + storeCossIOCallback(sio, 0); +} + +void +storeCossRead(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data) +{ + char *p; + CossState *cstate = (CossState *) sio->fsstate; + CossInfo *cs = (CossInfo *) SD->fsdata; + + assert(sio->read.callback == NULL); + assert(sio->read.callback_data == NULL); + sio->read.callback = callback; + sio->read.callback_data = cbdataReference(callback_data); + debug(79, 3) ("storeCossRead: offset %ld\n", (long int) offset); + sio->offset = offset; + cstate->flags.reading = 1; + if ((offset + size) > sio->st_size) + size = sio->st_size - offset; + cstate->requestlen = size; + cstate->requestbuf = buf; + cstate->requestoffset = offset; + if (cstate->readbuffer == NULL) { + p = storeCossMemPointerFromDiskOffset(SD, sio->swap_filen, NULL); + /* Remember we need to translate the block offset to a disk offset! */ + a_file_read(&cs->aq, cs->fd, + p, + sio->st_size, + cstate->reqdiskoffset, + storeCossReadDone, + sio); + cstate->reqdiskoffset = 0; /* XXX */ + } else { + storeCossReadDone(cs->fd, + cstate->readbuffer, + sio->st_size, + 0, + sio); + } +} + +void +storeCossWrite(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, FREE * free_func) +{ + char *dest; + CossMemBuf *membuf; + off_t diskoffset; + + /* + * If we get handed an object with a size of -1, + * the squid code is broken + */ + assert(sio->e->mem_obj->object_sz != -1); + + debug(79, 3) ("storeCossWrite: offset %ld, len %lu\n", (long int) sio->offset, (unsigned long int) size); + diskoffset = sio->swap_filen + sio->offset; + dest = storeCossMemPointerFromDiskOffset(SD, diskoffset, &membuf); + assert(dest != NULL); + xmemcpy(dest, buf, size); + sio->offset += size; + if (free_func) + (free_func) (buf); +} + + +/* === STATIC =========================================================== */ + +static void +storeCossReadDone(int fd, const char *buf, int len, int errflag, void *my_data) +{ + storeIOState *sio = (storeIOState *)my_data; + char *p; + STRCB *callback = sio->read.callback; + void *cbdata; + SwapDir *SD = INDEXSD(sio->swap_dirn); + CossState *cstate = (CossState *) sio->fsstate; + ssize_t rlen; + + debug(79, 3) ("storeCossReadDone: fileno %d, FD %d, len %d\n", + sio->swap_filen, fd, len); + cstate->flags.reading = 0; + if (errflag) { + debug(79, 3) ("storeCossReadDone: got failure (%d)\n", errflag); + rlen = -1; + } else { + if (cstate->readbuffer == NULL) { + cstate->readbuffer = (char *)xmalloc(sio->st_size); + p = storeCossMemPointerFromDiskOffset(SD, sio->swap_filen, NULL); + xmemcpy(cstate->readbuffer, p, sio->st_size); + storeCossMemBufUnlock(SD, sio); + } + sio->offset += len; + xmemcpy(cstate->requestbuf, &cstate->readbuffer[cstate->requestoffset], + cstate->requestlen); + rlen = (size_t) cstate->requestlen; + } + assert(callback); + sio->read.callback = NULL; + if (cbdataReferenceValidDone(sio->read.callback_data, &cbdata)) + callback(cbdata, cstate->requestbuf, rlen); +} + +static void +storeCossIOCallback(storeIOState * sio, int errflag) +{ + CossState *cstate = (CossState *) sio->fsstate; + STIOCB *callback = sio->callback; + void *cbdata; + debug(79, 3) ("storeCossIOCallback: errflag=%d\n", errflag); + xfree(cstate->readbuffer); + sio->callback = NULL; + if (cbdataReferenceValidDone(sio->callback_data, &cbdata)) + callback(cbdata, errflag, sio); + cbdataFree(sio); +} + +static char * +storeCossMemPointerFromDiskOffset(SwapDir * SD, size_t offset, CossMemBuf ** mb) +{ + CossMemBuf *t; + dlink_node *m; + CossInfo *cs = (CossInfo *) SD->fsdata; + + for (m = cs->membufs.head; m; m = m->next) { + t = (CossMemBuf *)m->data; + if ((offset >= t->diskstart) && (offset <= t->diskend)) { + if (mb) + *mb = t; + return &t->buffer[offset - t->diskstart]; + } + } + + if (mb) + *mb = NULL; + return NULL; +} + +static void +storeCossMemBufLock(SwapDir * SD, storeIOState * e) +{ + CossMemBuf *t; + dlink_node *m; + CossInfo *cs = (CossInfo *) SD->fsdata; + + for (m = cs->membufs.head; m; m = m->next) { + t = (CossMemBuf *)m->data; + if (((size_t)e->swap_filen >= t->diskstart) && ((size_t)e->swap_filen <= t->diskend)) { + debug(79, 3) ("storeCossMemBufLock: locking %p, lockcount %d\n", t, t->lockcount); + t->lockcount++; + return; + } + } + debug(79, 3) ("storeCossMemBufLock: FAILED to lock %p\n", e); +} + +static void +storeCossMemBufUnlock(SwapDir * SD, storeIOState * e) +{ + CossMemBuf *t; + dlink_node *m, *n; + CossInfo *cs = (CossInfo *) SD->fsdata; + + for (m = cs->membufs.head; m; m = n) { + /* + * Note that storeCossWriteMemBuf() might call storeCossWriteMemBufDone + * immediately (if the write finishes immediately, of course!) which + * will make m = m->next kinda unworkable. So, get the next pointer. + */ + n = m->next; + t = (CossMemBuf *)m->data; + if (((size_t)e->swap_filen >= t->diskstart) && ((size_t)e->swap_filen <= t->diskend)) { + t->lockcount--; + debug(79, 3) ("storeCossMemBufUnlock: unlocking %p, lockcount %d\n", t, t->lockcount); + } + if (t->flags.full && !t->flags.writing && !t->lockcount) + storeCossWriteMemBuf(SD, t); + } +} + +void +storeCossSync(SwapDir * SD) +{ + CossInfo *cs = (CossInfo *) SD->fsdata; + CossMemBuf *t; + dlink_node *m; + int end; + + /* First, flush pending IO ops */ + a_file_syncqueue(&cs->aq); + + /* Then, flush any in-memory partial membufs */ + if (!cs->membufs.head) + return; + for (m = cs->membufs.head; m; m = m->next) { + t = (CossMemBuf *)m->data; + if (t->flags.writing) + sleep(5); /* XXX EEEWWW! */ + lseek(cs->fd, t->diskstart, SEEK_SET); + end = (t == cs->current_membuf) ? cs->current_offset : t->diskend; + FD_WRITE_METHOD(cs->fd, t->buffer, end - t->diskstart); + } +} + +static void +storeCossWriteMemBuf(SwapDir * SD, CossMemBuf * t) +{ + CossInfo *cs = (CossInfo *) SD->fsdata; + debug(79, 3) ("storeCossWriteMemBuf: offset %ld, len %ld\n", + (long int) t->diskstart, (long int) (t->diskend - t->diskstart)); + t->flags.writing = 1; + /* Remember that diskstart/diskend are block offsets! */ + a_file_write(&cs->aq, cs->fd, t->diskstart, &t->buffer, + t->diskend - t->diskstart, storeCossWriteMemBufDone, t, NULL); +} + + +static void +storeCossWriteMemBufDone(int fd, int errflag, size_t len, void *my_data) +{ + CossMemBuf *t = (CossMemBuf *)my_data; + CossInfo *cs = (CossInfo *) t->SD->fsdata; + + debug(79, 3) ("storeCossWriteMemBufDone: buf %p, len %ld\n", t, (long int) len); + if (errflag) + debug(79, 0) ("storeCossMemBufWriteDone: got failure (%d)\n", errflag); + + dlinkDelete(&t->node, &cs->membufs); + cbdataFree(t); +} + +static CossMemBuf * +storeCossCreateMemBuf(SwapDir * SD, size_t start, + sfileno curfn, int *collision) +{ + CossMemBuf *newmb, *t; + StoreEntry *e; + dlink_node *m, *prev; + int numreleased = 0; + CossInfo *cs = (CossInfo *) SD->fsdata; + + CBDATA_INIT_TYPE_FREECB(CossMemBuf, NULL); + newmb = cbdataAlloc(CossMemBuf); + newmb->diskstart = start; + debug(79, 3) ("storeCossCreateMemBuf: creating new membuf at %ld\n", (long int) newmb->diskstart); + debug(79, 3) ("storeCossCreateMemBuf: at %p\n", newmb); + newmb->diskend = newmb->diskstart + COSS_MEMBUF_SZ - 1; + newmb->flags.full = 0; + newmb->flags.writing = 0; + newmb->lockcount = 0; + newmb->SD = SD; + /* XXX This should be reversed, with the new buffer last in the chain */ + dlinkAdd(newmb, &newmb->node, &cs->membufs); + + /* Print out the list of membufs */ + for (m = cs->membufs.head; m; m = m->next) { + t = (CossMemBuf *)m->data; + debug(79, 3) ("storeCossCreateMemBuf: membuflist %ld lockcount %d\n", (long int) t->diskstart, t->lockcount); + } + + /* + * Kill objects from the tail to make space for a new chunk + */ + for (m = cs->index.tail; m; m = prev) { + prev = m->prev; + e = (StoreEntry *)m->data; + if (curfn == e->swap_filen) + *collision = 1; /* Mark an object alloc collision */ + if (((size_t)e->swap_filen >= newmb->diskstart) && + ((size_t)e->swap_filen <= newmb->diskend)) { + storeRelease(e); + numreleased++; + } else + break; + } + if (numreleased > 0) + debug(79, 3) ("storeCossCreateMemBuf: this allocation released %d storeEntries\n", numreleased); + return newmb; +} + +/* + * Creates the initial membuf after rebuild + */ +void +storeCossStartMembuf(SwapDir * sd) +{ + CossInfo *cs = (CossInfo *) sd->fsdata; + CossMemBuf *newmb = storeCossCreateMemBuf(sd, cs->current_offset, -1, NULL); + assert(!cs->current_membuf); + cs->current_membuf = newmb; +} + +/* + * Clean up any references from the SIO before it get's released. + */ +static void +storeCossIOFreeEntry(void *sio) +{ + memPoolFree(coss_state_pool, ((storeIOState *) sio)->fsstate); +} Index: squid/src/fs/diskd/Makefile.am =================================================================== RCS file: /cvsroot/squid-sf//squid/src/fs/diskd/Attic/Makefile.am,v retrieving revision 1.2 retrieving revision 1.2.72.1 diff -u -r1.2 -r1.2.72.1 --- squid/src/fs/diskd/Makefile.am 1 Sep 2001 11:46:51 -0000 1.2 +++ squid/src/fs/diskd/Makefile.am 12 Oct 2002 12:21:43 -0000 1.2.72.1 @@ -5,6 +5,7 @@ # libexec_PROGRAMS = diskd +diskd_SOURCES = diskd.cc LDADD = $(top_builddir)/lib/libmiscutil.a @XTRA_LIBS@ INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \ --- squid/src/fs/diskd/diskd.c Wed Feb 14 01:07:42 2007 +++ /dev/null Wed Feb 14 01:07:22 2007 @@ -1,358 +0,0 @@ -/* - * $Id$ - * - * DEBUG: section -- External DISKD process implementation. - * AUTHOR: Harvest Derived - * - * SQUID Web Proxy Cache http://www.squid-cache.org/ - * ---------------------------------------------------------- - * - * Squid is the result of efforts by numerous individuals from - * the Internet community; see the CONTRIBUTORS file for full - * details. Many organizations have provided support for Squid's - * development; see the SPONSORS file for full details. Squid is - * Copyrighted (C) 2001 by the Regents of the University of - * California; see the COPYRIGHT file for full details. Squid - * incorporates software developed and/or copyrighted by other - * sources; see the CREDITS file for full details. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. - * - */ - -#include "config.h" -#include "squid.h" - -#include -#include -#include - -#include "store_diskd.h" - -#undef assert -#include - - -#define DEBUG(LEVEL) if (LEVEL <= DebugLevel) - -typedef struct _file_state file_state; - -struct _file_state { - void *key; - file_state *next; - int id; - int fd; - off_t offset; -}; - -static hash_table *hash = NULL; -static pid_t mypid; -static char *shmbuf; -static int DebugLevel = 0; - -static int -do_open(diomsg * r, int len, const char *buf) -{ - int fd; - file_state *fs; - /* - * note r->offset holds open() flags - */ - fd = open(buf, r->offset, 0600); - if (fd < 0) { - DEBUG(1) { - fprintf(stderr, "%d %s: ", (int) mypid, buf); - perror("open"); - } - return -errno; - } - fs = xcalloc(1, sizeof(*fs)); - fs->id = r->id; - fs->key = &fs->id; /* gack */ - fs->fd = fd; - hash_join(hash, (hash_link *) fs); - DEBUG(2) - fprintf(stderr, "%d OPEN id %d, FD %d, fs %p\n", - (int) mypid, - fs->id, - fs->fd, - fs); - return fd; -} - -static int -do_close(diomsg * r, int len) -{ - int fd; - file_state *fs; - fs = (file_state *) hash_lookup(hash, &r->id); - if (NULL == fs) { - errno = EBADF; - DEBUG(1) { - fprintf(stderr, "%d CLOSE id %d: ", (int) mypid, r->id); - perror("do_close"); - } - return -errno; - } - fd = fs->fd; - hash_remove_link(hash, (hash_link *) fs); - DEBUG(2) - fprintf(stderr, "%d CLOSE id %d, FD %d, fs %p\n", - (int) mypid, - r->id, - fs->fd, - fs); - xfree(fs); - return close(fd); -} - -static int -do_read(diomsg * r, int len, char *buf) -{ - int x; - int readlen = r->size; - file_state *fs; - fs = (file_state *) hash_lookup(hash, &r->id); - if (NULL == fs) { - errno = EBADF; - DEBUG(1) { - fprintf(stderr, "%d READ id %d: ", (int) mypid, r->id); - perror("do_read"); - } - return -errno; - } - if (r->offset > -1 && r->offset != fs->offset) { - DEBUG(2) - fprintf(stderr, "seeking to %d\n", r->offset); - if (lseek(fs->fd, r->offset, SEEK_SET) < 0) { - DEBUG(1) { - fprintf(stderr, "%d FD %d, offset %d: ", (int) mypid, fs->fd, r->offset); - perror("lseek"); - } - } - } - x = read(fs->fd, buf, readlen); - DEBUG(2) - fprintf(stderr, "%d READ %d,%d,%d ret %d\n", (int) mypid, - fs->fd, readlen, r->offset, x); - if (x < 0) { - DEBUG(1) { - fprintf(stderr, "%d FD %d: ", (int) mypid, fs->fd); - perror("read"); - } - return -errno; - } - fs->offset = r->offset + x; - return x; -} - -static int -do_write(diomsg * r, int len, const char *buf) -{ - int wrtlen = r->size; - int x; - file_state *fs; - fs = (file_state *) hash_lookup(hash, &r->id); - if (NULL == fs) { - errno = EBADF; - DEBUG(1) { - fprintf(stderr, "%d WRITE id %d: ", (int) mypid, r->id); - perror("do_write"); - } - return -errno; - } - if (r->offset > -1 && r->offset != fs->offset) { - if (lseek(fs->fd, r->offset, SEEK_SET) < 0) { - DEBUG(1) { - fprintf(stderr, "%d FD %d, offset %d: ", (int) mypid, fs->fd, r->offset); - perror("lseek"); - } - } - } - DEBUG(2) - fprintf(stderr, "%d WRITE %d,%d,%d\n", (int) mypid, - fs->fd, wrtlen, r->offset); - x = write(fs->fd, buf, wrtlen); - if (x < 0) { - DEBUG(1) { - fprintf(stderr, "%d FD %d: ", (int) mypid, fs->fd); - perror("write"); - } - return -errno; - } - fs->offset = r->offset + x; - return x; -} - -static int -do_unlink(diomsg * r, int len, const char *buf) -{ -#if USE_TRUNCATE - if (truncate(buf, 0) < 0) -#else - if (unlink(buf) < 0) -#endif - { - DEBUG(1) { - fprintf(stderr, "%d UNLNK id %d %s: ", (int) mypid, r->id, buf); - perror("truncate"); - } - return -errno; - } - DEBUG(2) - fprintf(stderr, "%d UNLNK %s\n", (int) mypid, buf); - return 0; -} - -static void -msg_handle(diomsg * r, int rl, diomsg * s) -{ - char *buf = NULL; - s->mtype = r->mtype; - s->callback_data = r->callback_data; - s->shm_offset = r->shm_offset; - s->id = r->id; - if (s->shm_offset > -1) - buf = shmbuf + s->shm_offset; - switch (r->mtype) { - case _MQD_OPEN: - s->status = do_open(r, rl, buf); - break; - case _MQD_CLOSE: - s->status = do_close(r, rl); - break; - case _MQD_READ: - s->status = do_read(r, rl, buf); - break; - case _MQD_WRITE: - s->status = do_write(r, rl, buf); - break; - case _MQD_UNLINK: - s->status = do_unlink(r, rl, buf); - break; - default: - assert(0); - break; - } -} - -static int -fsCmp(const void *a, const void *b) -{ - const int *A = a; - const int *B = b; - return *A != *B; -} - -static unsigned int -fsHash(const void *key, unsigned int n) -{ - /* note, n must be a power of 2! */ - const int *k = key; - return (*k & (--n)); -} - -static void -alarm_handler(int sig) -{ - (void) 0; -} - -int -main(int argc, char *argv[]) -{ - int key; - int rmsgid; - int smsgid; - int shmid; - diomsg rmsg; - diomsg smsg; - int rlen; - char rbuf[512]; - struct sigaction sa; - setbuf(stdout, NULL); - setbuf(stderr, NULL); - mypid = getpid(); - assert(4 == argc); - key = atoi(argv[1]); - rmsgid = msgget(key, 0600); - if (rmsgid < 0) { - perror("msgget"); - return 1; - } - key = atoi(argv[2]); - smsgid = msgget(key, 0600); - if (smsgid < 0) { - perror("msgget"); - return 1; - } - key = atoi(argv[3]); - shmid = shmget(key, 0, 0600); - if (shmid < 0) { - perror("shmget"); - return 1; - } - shmbuf = shmat(shmid, NULL, 0); - if (shmbuf == (void *) -1) { - perror("shmat"); - return 1; - } - hash = hash_create(fsCmp, 1 << 4, fsHash); - assert(hash); - fcntl(0, F_SETFL, SQUID_NONBLOCK); - memset(&sa, '\0', sizeof(sa)); - sa.sa_handler = alarm_handler; - sa.sa_flags = SA_RESTART; - sigaction(SIGALRM, &sa, NULL); - for (;;) { - alarm(1); - memset(&rmsg, '\0', sizeof(rmsg)); - rlen = msgrcv(rmsgid, &rmsg, msg_snd_rcv_sz, 0, 0); - if (rlen < 0) { - if (EINTR == errno) { - if (read(0, rbuf, 512) <= 0) { - if (EWOULDBLOCK == errno) - (void) 0; - else if (EAGAIN == errno) - (void) 0; - else - break; - } - } - if (EAGAIN == errno) { - continue; - } - perror("msgrcv"); - break; - } - alarm(0); - msg_handle(&rmsg, rlen, &smsg); - if (msgsnd(smsgid, &smsg, msg_snd_rcv_sz, 0) < 0) { - perror("msgsnd"); - break; - } - } - DEBUG(2) - fprintf(stderr, "%d diskd exiting\n", (int) mypid); - if (msgctl(rmsgid, IPC_RMID, 0) < 0) - perror("msgctl IPC_RMID"); - if (msgctl(smsgid, IPC_RMID, 0) < 0) - perror("msgctl IPC_RMID"); - if (shmdt(shmbuf) < 0) - perror("shmdt"); - if (shmctl(shmid, IPC_RMID, 0) < 0) - perror("shmctl IPC_RMID"); - return 0; -} --- /dev/null Wed Feb 14 01:07:22 2007 +++ squid/src/fs/diskd/diskd.cc Wed Feb 14 01:07:42 2007 @@ -0,0 +1,358 @@ +/* + * $Id: diskd.cc,v 1.1.2.1 2002/10/12 12:21:43 rbcollins Exp $ + * + * DEBUG: section -- External DISKD process implementation. + * AUTHOR: Harvest Derived + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "config.h" +#include "squid.h" + +#include +#include +#include + +#include "store_diskd.h" + +#undef assert +#include + + +#define DEBUG(LEVEL) if (LEVEL <= DebugLevel) + +typedef struct _file_state file_state; + +struct _file_state { + void *key; + file_state *next; + int id; + int fd; + off_t offset; +}; + +static hash_table *hash = NULL; +static pid_t mypid; +static char *shmbuf; +static int DebugLevel = 0; + +static int +do_open(diomsg * r, int len, const char *buf) +{ + int fd; + file_state *fs; + /* + * note r->offset holds open() flags + */ + fd = open(buf, r->offset, 0600); + if (fd < 0) { + DEBUG(1) { + fprintf(stderr, "%d %s: ", (int) mypid, buf); + perror("open"); + } + return -errno; + } + fs = (file_state *)xcalloc(1, sizeof(*fs)); + fs->id = r->id; + fs->key = &fs->id; /* gack */ + fs->fd = fd; + hash_join(hash, (hash_link *) fs); + DEBUG(2) + fprintf(stderr, "%d OPEN id %d, FD %d, fs %p\n", + (int) mypid, + fs->id, + fs->fd, + fs); + return fd; +} + +static int +do_close(diomsg * r, int len) +{ + int fd; + file_state *fs; + fs = (file_state *) hash_lookup(hash, &r->id); + if (NULL == fs) { + errno = EBADF; + DEBUG(1) { + fprintf(stderr, "%d CLOSE id %d: ", (int) mypid, r->id); + perror("do_close"); + } + return -errno; + } + fd = fs->fd; + hash_remove_link(hash, (hash_link *) fs); + DEBUG(2) + fprintf(stderr, "%d CLOSE id %d, FD %d, fs %p\n", + (int) mypid, + r->id, + fs->fd, + fs); + xfree(fs); + return close(fd); +} + +static int +do_read(diomsg * r, int len, char *buf) +{ + int x; + int readlen = r->size; + file_state *fs; + fs = (file_state *) hash_lookup(hash, &r->id); + if (NULL == fs) { + errno = EBADF; + DEBUG(1) { + fprintf(stderr, "%d READ id %d: ", (int) mypid, r->id); + perror("do_read"); + } + return -errno; + } + if (r->offset > -1 && r->offset != fs->offset) { + DEBUG(2) + fprintf(stderr, "seeking to %d\n", r->offset); + if (lseek(fs->fd, r->offset, SEEK_SET) < 0) { + DEBUG(1) { + fprintf(stderr, "%d FD %d, offset %d: ", (int) mypid, fs->fd, r->offset); + perror("lseek"); + } + } + } + x = read(fs->fd, buf, readlen); + DEBUG(2) + fprintf(stderr, "%d READ %d,%d,%d ret %d\n", (int) mypid, + fs->fd, readlen, r->offset, x); + if (x < 0) { + DEBUG(1) { + fprintf(stderr, "%d FD %d: ", (int) mypid, fs->fd); + perror("read"); + } + return -errno; + } + fs->offset = r->offset + x; + return x; +} + +static int +do_write(diomsg * r, int len, const char *buf) +{ + int wrtlen = r->size; + int x; + file_state *fs; + fs = (file_state *) hash_lookup(hash, &r->id); + if (NULL == fs) { + errno = EBADF; + DEBUG(1) { + fprintf(stderr, "%d WRITE id %d: ", (int) mypid, r->id); + perror("do_write"); + } + return -errno; + } + if (r->offset > -1 && r->offset != fs->offset) { + if (lseek(fs->fd, r->offset, SEEK_SET) < 0) { + DEBUG(1) { + fprintf(stderr, "%d FD %d, offset %d: ", (int) mypid, fs->fd, r->offset); + perror("lseek"); + } + } + } + DEBUG(2) + fprintf(stderr, "%d WRITE %d,%d,%d\n", (int) mypid, + fs->fd, wrtlen, r->offset); + x = write(fs->fd, buf, wrtlen); + if (x < 0) { + DEBUG(1) { + fprintf(stderr, "%d FD %d: ", (int) mypid, fs->fd); + perror("write"); + } + return -errno; + } + fs->offset = r->offset + x; + return x; +} + +static int +do_unlink(diomsg * r, int len, const char *buf) +{ +#if USE_TRUNCATE + if (truncate(buf, 0) < 0) +#else + if (unlink(buf) < 0) +#endif + { + DEBUG(1) { + fprintf(stderr, "%d UNLNK id %d %s: ", (int) mypid, r->id, buf); + perror("truncate"); + } + return -errno; + } + DEBUG(2) + fprintf(stderr, "%d UNLNK %s\n", (int) mypid, buf); + return 0; +} + +static void +msg_handle(diomsg * r, int rl, diomsg * s) +{ + char *buf = NULL; + s->mtype = r->mtype; + s->callback_data = r->callback_data; + s->shm_offset = r->shm_offset; + s->id = r->id; + if (s->shm_offset > -1) + buf = shmbuf + s->shm_offset; + switch (r->mtype) { + case _MQD_OPEN: + s->status = do_open(r, rl, buf); + break; + case _MQD_CLOSE: + s->status = do_close(r, rl); + break; + case _MQD_READ: + s->status = do_read(r, rl, buf); + break; + case _MQD_WRITE: + s->status = do_write(r, rl, buf); + break; + case _MQD_UNLINK: + s->status = do_unlink(r, rl, buf); + break; + default: + assert(0); + break; + } +} + +static int +fsCmp(const void *a, const void *b) +{ + const int *A = (const int *)a; + const int *B = (const int *)b; + return *A != *B; +} + +static unsigned int +fsHash(const void *key, unsigned int n) +{ + /* note, n must be a power of 2! */ + const int *k = (const int *)key; + return (*k & (--n)); +} + +static void +alarm_handler(int sig) +{ + (void) 0; +} + +int +main(int argc, char *argv[]) +{ + int key; + int rmsgid; + int smsgid; + int shmid; + diomsg rmsg; + diomsg smsg; + int rlen; + char rbuf[512]; + struct sigaction sa; + setbuf(stdout, NULL); + setbuf(stderr, NULL); + mypid = getpid(); + assert(4 == argc); + key = atoi(argv[1]); + rmsgid = msgget(key, 0600); + if (rmsgid < 0) { + perror("msgget"); + return 1; + } + key = atoi(argv[2]); + smsgid = msgget(key, 0600); + if (smsgid < 0) { + perror("msgget"); + return 1; + } + key = atoi(argv[3]); + shmid = shmget(key, 0, 0600); + if (shmid < 0) { + perror("shmget"); + return 1; + } + shmbuf = (char *)shmat(shmid, NULL, 0); + if (shmbuf == (void *) -1) { + perror("shmat"); + return 1; + } + hash = hash_create(fsCmp, 1 << 4, fsHash); + assert(hash); + fcntl(0, F_SETFL, SQUID_NONBLOCK); + memset(&sa, '\0', sizeof(sa)); + sa.sa_handler = alarm_handler; + sa.sa_flags = SA_RESTART; + sigaction(SIGALRM, &sa, NULL); + for (;;) { + alarm(1); + memset(&rmsg, '\0', sizeof(rmsg)); + rlen = msgrcv(rmsgid, &rmsg, msg_snd_rcv_sz, 0, 0); + if (rlen < 0) { + if (EINTR == errno) { + if (read(0, rbuf, 512) <= 0) { + if (EWOULDBLOCK == errno) + (void) 0; + else if (EAGAIN == errno) + (void) 0; + else + break; + } + } + if (EAGAIN == errno) { + continue; + } + perror("msgrcv"); + break; + } + alarm(0); + msg_handle(&rmsg, rlen, &smsg); + if (msgsnd(smsgid, &smsg, msg_snd_rcv_sz, 0) < 0) { + perror("msgsnd"); + break; + } + } + DEBUG(2) + fprintf(stderr, "%d diskd exiting\n", (int) mypid); + if (msgctl(rmsgid, IPC_RMID, 0) < 0) + perror("msgctl IPC_RMID"); + if (msgctl(smsgid, IPC_RMID, 0) < 0) + perror("msgctl IPC_RMID"); + if (shmdt(shmbuf) < 0) + perror("shmdt"); + if (shmctl(shmid, IPC_RMID, 0) < 0) + perror("shmctl IPC_RMID"); + return 0; +} --- squid/src/fs/diskd/store_dir_diskd.c Wed Feb 14 01:07:42 2007 +++ /dev/null Wed Feb 14 01:07:22 2007 @@ -1,516 +0,0 @@ - -/* - * $Id$ - * - * DEBUG: section 47 Store Directory Routines - * AUTHOR: Duane Wessels - * - * SQUID Web Proxy Cache http://www.squid-cache.org/ - * ---------------------------------------------------------- - * - * Squid is the result of efforts by numerous individuals from - * the Internet community; see the CONTRIBUTORS file for full - * details. Many organizations have provided support for Squid's - * development; see the SPONSORS file for full details. Squid is - * Copyrighted (C) 2001 by the Regents of the University of - * California; see the COPYRIGHT file for full details. Squid - * incorporates software developed and/or copyrighted by other - * sources; see the CREDITS file for full details. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. - * - */ - -#include "squid.h" -#include "Store.h" - -#include -#include -#include - -#include "store_diskd.h" - -#include "ufscommon.h" - -diskd_stats_t diskd_stats; - -MemPool *diskd_state_pool = NULL; -static int diskd_initialised = 0; - -static STINIT storeDiskdDirInit; -static STDUMP storeDiskdDirDump; -static STCHECKOBJ storeDiskdDirCheckObj; -static void storeDiskdDirStats(SwapDir *, StoreEntry *); -static void storeDiskdStats(StoreEntry * sentry); -static void storeDiskdDirSync(SwapDir *); -static void storeDiskdDirIOUnlinkFile(char *path); - -/* The only externally visible interface */ -STSETUP storeFsSetup_diskd; - -static void -storeDiskdDirInit(SwapDir * sd) -{ - int x; - int i; - int rfd; - int ikey; - const char *args[5]; - char skey1[32]; - char skey2[32]; - char skey3[32]; - diskdinfo_t *diskdinfo = sd->fsdata; - - ikey = (getpid() << 10) + (sd->index << 2); - ikey &= 0x7fffffff; - diskdinfo->smsgid = msgget((key_t) ikey, 0700 | IPC_CREAT); - if (diskdinfo->smsgid < 0) { - debug(50, 0) ("storeDiskdInit: msgget: %s\n", xstrerror()); - fatal("msgget failed"); - } - diskdinfo->rmsgid = msgget((key_t) (ikey + 1), 0700 | IPC_CREAT); - if (diskdinfo->rmsgid < 0) { - debug(50, 0) ("storeDiskdInit: msgget: %s\n", xstrerror()); - fatal("msgget failed"); - } - diskdinfo->shm.nbufs = diskdinfo->magic2 * 1.3; - diskdinfo->shm.id = shmget((key_t) (ikey + 2), - diskdinfo->shm.nbufs * SHMBUF_BLKSZ, 0600 | IPC_CREAT); - if (diskdinfo->shm.id < 0) { - debug(50, 0) ("storeDiskdInit: shmget: %s\n", xstrerror()); - fatal("shmget failed"); - } - diskdinfo->shm.buf = shmat(diskdinfo->shm.id, NULL, 0); - if (diskdinfo->shm.buf == (void *) -1) { - debug(50, 0) ("storeDiskdInit: shmat: %s\n", xstrerror()); - fatal("shmat failed"); - } - diskdinfo->shm.inuse_map = xcalloc((diskdinfo->shm.nbufs + 7) / 8, 1); - diskd_stats.shmbuf_count += diskdinfo->shm.nbufs; - for (i = 0; i < diskdinfo->shm.nbufs; i++) { - CBIT_SET(diskdinfo->shm.inuse_map, i); - storeDiskdShmPut(sd, i * SHMBUF_BLKSZ); - } - snprintf(skey1, 32, "%d", ikey); - snprintf(skey2, 32, "%d", ikey + 1); - snprintf(skey3, 32, "%d", ikey + 2); - args[0] = "diskd"; - args[1] = skey1; - args[2] = skey2; - args[3] = skey3; - args[4] = NULL; - x = ipcCreate(IPC_STREAM, - Config.Program.diskd, - args, - "diskd", - &rfd, - &diskdinfo->wfd); - if (x < 0) - fatalf("execl: %s", Config.Program.diskd); - if (rfd != diskdinfo->wfd) - comm_close(rfd); - fd_note(diskdinfo->wfd, "squid -> diskd"); - commSetTimeout(diskdinfo->wfd, -1, NULL, NULL); - commSetNonBlocking(diskdinfo->wfd); - - commonUfsDirInit (sd); - - comm_quick_poll_required(); -} - - -static void -storeDiskdStats(StoreEntry * sentry) -{ - storeAppendPrintf(sentry, "sent_count: %d\n", diskd_stats.sent_count); - storeAppendPrintf(sentry, "recv_count: %d\n", diskd_stats.recv_count); - storeAppendPrintf(sentry, "max_away: %d\n", diskd_stats.max_away); - storeAppendPrintf(sentry, "max_shmuse: %d\n", diskd_stats.max_shmuse); - storeAppendPrintf(sentry, "open_fail_queue_len: %d\n", diskd_stats.open_fail_queue_len); - storeAppendPrintf(sentry, "block_queue_len: %d\n", diskd_stats.block_queue_len); - diskd_stats.max_away = diskd_stats.max_shmuse = 0; - storeAppendPrintf(sentry, "\n OPS SUCCESS FAIL\n"); - storeAppendPrintf(sentry, "%7s %7d %7d %7d\n", - "open", diskd_stats.open.ops, diskd_stats.open.success, diskd_stats.open.fail); - storeAppendPrintf(sentry, "%7s %7d %7d %7d\n", - "create", diskd_stats.create.ops, diskd_stats.create.success, diskd_stats.create.fail); - storeAppendPrintf(sentry, "%7s %7d %7d %7d\n", - "close", diskd_stats.close.ops, diskd_stats.close.success, diskd_stats.close.fail); - storeAppendPrintf(sentry, "%7s %7d %7d %7d\n", - "unlink", diskd_stats.unlink.ops, diskd_stats.unlink.success, diskd_stats.unlink.fail); - storeAppendPrintf(sentry, "%7s %7d %7d %7d\n", - "read", diskd_stats.read.ops, diskd_stats.read.success, diskd_stats.read.fail); - storeAppendPrintf(sentry, "%7s %7d %7d %7d\n", - "write", diskd_stats.write.ops, diskd_stats.write.success, diskd_stats.write.fail); -} - -/* - * storeDiskdDirSync - * - * Sync any pending data. We just sit around and read the queue - * until the data has finished writing. - */ -static void -storeDiskdDirSync(SwapDir * SD) -{ - static time_t lastmsg = 0; - diskdinfo_t *diskdinfo = SD->fsdata; - while (diskdinfo->away > 0) { - if (squid_curtime > lastmsg) { - debug(47, 1) ("storeDiskdDirSync: %d messages away\n", - diskdinfo->away); - lastmsg = squid_curtime; - } - storeDiskdDirCallback(SD); - } -} - - -/* - * storeDiskdDirCallback - * - * Handle callbacks. If we have more than magic2 requests away, we block - * until the queue is below magic2. Otherwise, we simply return when we - * don't get a message. - */ -int -storeDiskdDirCallback(SwapDir * SD) -{ - diomsg M; - int x; - diskdinfo_t *diskdinfo = SD->fsdata; - int retval = 0; - - if (diskdinfo->away >= diskdinfo->magic2) { - diskd_stats.block_queue_len++; - retval = 1; /* We might not have anything to do, but our queue - * is full.. */ - } - if (diskd_stats.sent_count - diskd_stats.recv_count > - diskd_stats.max_away) { - diskd_stats.max_away = diskd_stats.sent_count - diskd_stats.recv_count; - } - while (1) { - memset(&M, '\0', sizeof(M)); - x = msgrcv(diskdinfo->rmsgid, &M, msg_snd_rcv_sz, 0, IPC_NOWAIT); - if (x < 0) - break; - else if (x != msg_snd_rcv_sz) { - debug(47, 1) ("storeDiskdDirCallback: msgget returns %d\n", - x); - break; - } - diskd_stats.recv_count++; - diskdinfo->away--; - storeDiskdHandle(&M); - retval = 1; /* Return that we've actually done some work */ - if (M.shm_offset > -1) - storeDiskdShmPut(SD, (off_t) M.shm_offset); - } - return retval; -} - -/* - * storeDiskdDirCheckObj - * - * This routine is called by storeDirSelectSwapDir to see if the given - * object is able to be stored on this filesystem. DISKD filesystems will - * happily store anything as long as the LRU time isn't too small. - */ -int -storeDiskdDirCheckObj(SwapDir * SD, const StoreEntry * e) -{ - diskdinfo_t *diskdinfo = SD->fsdata; - /* Check the queue length */ - if (diskdinfo->away >= diskdinfo->magic1) - return -1; - /* Calculate the storedir load relative to magic2 on a scale of 0 .. 1000 */ - /* the parse function guarantees magic2 is positivie */ - return diskdinfo->away * 1000 / diskdinfo->magic2; -} - -void -storeDiskdDirIOUnlinkFile(char *path) -{ -#if USE_UNLINKD - unlinkdUnlink(path); -#elif USE_TRUNCATE - truncate(path, 0); -#else - unlink(path); -#endif - -} - -/* - * SHM manipulation routines - */ - -void * -storeDiskdShmGet(SwapDir * sd, off_t * shm_offset) -{ - char *buf = NULL; - diskdinfo_t *diskdinfo = sd->fsdata; - int i; - for (i = 0; i < diskdinfo->shm.nbufs; i++) { - if (CBIT_TEST(diskdinfo->shm.inuse_map, i)) - continue; - CBIT_SET(diskdinfo->shm.inuse_map, i); - *shm_offset = i * SHMBUF_BLKSZ; - buf = diskdinfo->shm.buf + (*shm_offset); - break; - } - assert(buf); - assert(buf >= diskdinfo->shm.buf); - assert(buf < diskdinfo->shm.buf + (diskdinfo->shm.nbufs * SHMBUF_BLKSZ)); - diskd_stats.shmbuf_count++; - if (diskd_stats.max_shmuse < diskd_stats.shmbuf_count) - diskd_stats.max_shmuse = diskd_stats.shmbuf_count; - return buf; -} - -void -storeDiskdShmPut(SwapDir * sd, off_t offset) -{ - int i; - diskdinfo_t *diskdinfo = sd->fsdata; - assert(offset >= 0); - assert(offset < diskdinfo->shm.nbufs * SHMBUF_BLKSZ); - i = offset / SHMBUF_BLKSZ; - assert(i < diskdinfo->shm.nbufs); - assert(CBIT_TEST(diskdinfo->shm.inuse_map, i)); - CBIT_CLR(diskdinfo->shm.inuse_map, i); - diskd_stats.shmbuf_count--; -} - - - - -/* ========== LOCAL FUNCTIONS ABOVE, GLOBAL FUNCTIONS BELOW ========== */ - -void -storeDiskdDirStats(SwapDir * SD, StoreEntry * sentry) -{ - diskdinfo_t *diskdinfo = SD->fsdata; - commonUfsDirStats (SD, sentry); - storeAppendPrintf(sentry, "Pending operations: %d\n", diskdinfo->away); -} - -static void -storeDiskdDirParseQ1(SwapDir * sd, const char *name, const char *value, int reconfiguring) -{ - diskdinfo_t *diskdinfo = sd->fsdata; - int old_magic1 = diskdinfo->magic1; - diskdinfo->magic1 = atoi(value); - if (!reconfiguring) - return; - if (old_magic1 < diskdinfo->magic1) { - /* - * This is because shm.nbufs is computed at startup, when - * we call shmget(). We can't increase the Q1/Q2 parameters - * beyond their initial values because then we might have - * more "Q2 messages" than shared memory chunks, and this - * will cause an assertion in storeDiskdShmGet(). - */ - debug(3, 1) ("WARNING: cannot increase cache_dir '%s' Q1 value while Squid is running.\n", sd->path); - diskdinfo->magic1 = old_magic1; - return; - } - if (old_magic1 != diskdinfo->magic1) - debug(3, 1) ("cache_dir '%s' new Q1 value '%d'\n", - sd->path, diskdinfo->magic1); -} - -static void -storeDiskdDirDumpQ1(StoreEntry * e, const char *option, SwapDir * sd) -{ - diskdinfo_t *diskdinfo = sd->fsdata; - storeAppendPrintf(e, " Q1=%d", diskdinfo->magic1); -} - -static void -storeDiskdDirParseQ2(SwapDir * sd, const char *name, const char *value, int reconfiguring) -{ - diskdinfo_t *diskdinfo = sd->fsdata; - int old_magic2 = diskdinfo->magic2; - diskdinfo->magic2 = atoi(value); - if (!reconfiguring) - return; - if (old_magic2 < diskdinfo->magic2) { - /* See comments in Q1 function above */ - debug(3, 1) ("WARNING: cannot increase cache_dir '%s' Q2 value while Squid is running.\n", sd->path); - diskdinfo->magic2 = old_magic2; - return; - } - if (old_magic2 != diskdinfo->magic2) - debug(3, 1) ("cache_dir '%s' new Q2 value '%d'\n", - sd->path, diskdinfo->magic2); -} - -static void -storeDiskdDirDumpQ2(StoreEntry * e, const char *option, SwapDir * sd) -{ - diskdinfo_t *diskdinfo = sd->fsdata; - storeAppendPrintf(e, " Q2=%d", diskdinfo->magic2); -} - -struct cache_dir_option options[] = -{ -#if NOT_YET - {"L1", storeDiskdDirParseL1, storeDiskdDirDumpL1}, - {"L2", storeDiskdDirParseL2, storeDiskdDirDumpL2}, -#endif - {"Q1", storeDiskdDirParseQ1, storeDiskdDirDumpQ1}, - {"Q2", storeDiskdDirParseQ2, storeDiskdDirDumpQ2}, - {NULL, NULL} -}; - -/* - * storeDiskdDirReconfigure - * - * This routine is called when the given swapdir needs reconfiguring - */ -static void -storeDiskdDirReconfigure(SwapDir * sd, int index, char *path) -{ - int i; - int size; - int l1; - int l2; - - i = GetInteger(); - size = i << 10; /* Mbytes to kbytes */ - if (size <= 0) - fatal("storeDiskdDirReconfigure: invalid size value"); - i = GetInteger(); - l1 = i; - if (l1 <= 0) - fatal("storeDiskdDirReconfigure: invalid level 1 directories value"); - i = GetInteger(); - l2 = i; - if (l2 <= 0) - fatal("storeDiskdDirReconfigure: invalid level 2 directories value"); - - /* just reconfigure it */ - if (size == sd->max_size) - debug(3, 1) ("Cache dir '%s' size remains unchanged at %d KB\n", - path, size); - else - debug(3, 1) ("Cache dir '%s' size changed to %d KB\n", - path, size); - sd->max_size = size; - parse_cachedir_options(sd, options, 1); -} - -void -storeDiskdDirDump(StoreEntry * entry, SwapDir * s) -{ - commonUfsDirDump (entry, s); - dump_cachedir_options(entry, options, s); -} - -/* - * storeDiskdDirParse - * - * Called when a *new* fs is being setup. - */ -static void -storeDiskdDirParse(SwapDir * sd, int index, char *path) -{ - int i; - int size; - int l1; - int l2; - diskdinfo_t *diskdinfo; - - i = GetInteger(); - size = i << 10; /* Mbytes to kbytes */ - if (size <= 0) - fatal("storeDiskdDirParse: invalid size value"); - i = GetInteger(); - l1 = i; - if (l1 <= 0) - fatal("storeDiskdDirParse: invalid level 1 directories value"); - i = GetInteger(); - l2 = i; - if (l2 <= 0) - fatal("storeDiskdDirParse: invalid level 2 directories value"); - - sd->fsdata = diskdinfo = xcalloc(1, sizeof(*diskdinfo)); - sd->index = index; - sd->path = xstrdup(path); - sd->max_size = size; - diskdinfo->commondata.l1 = l1; - diskdinfo->commondata.l2 = l2; - diskdinfo->commondata.swaplog_fd = -1; - diskdinfo->commondata.map = NULL; /* Debugging purposes */ - diskdinfo->commondata.suggest = 0; - diskdinfo->commondata.io.storeDirUnlinkFile = storeDiskdDirIOUnlinkFile; - diskdinfo->magic1 = 64; - diskdinfo->magic2 = 72; - sd->init = storeDiskdDirInit; - sd->newfs = commonUfsDirNewfs; - sd->dump = storeDiskdDirDump; - sd->freefs = commonUfsDirFree; - sd->dblcheck = commonUfsCleanupDoubleCheck; - sd->statfs = storeDiskdDirStats; - sd->maintainfs = commonUfsDirMaintain; - sd->checkobj = storeDiskdDirCheckObj; - sd->refobj = commonUfsDirRefObj; - sd->unrefobj = commonUfsDirUnrefObj; - sd->callback = storeDiskdDirCallback; - sd->sync = storeDiskdDirSync; - sd->obj.create = storeDiskdCreate; - sd->obj.open = storeDiskdOpen; - sd->obj.close = storeDiskdClose; - sd->obj.read = storeDiskdRead; - sd->obj.write = storeDiskdWrite; - sd->obj.unlink = storeDiskdUnlink; - sd->log.open = commonUfsDirOpenSwapLog; - sd->log.close = commonUfsDirCloseSwapLog; - sd->log.write = commonUfsDirSwapLog; - sd->log.clean.start = commonUfsDirWriteCleanStart; - sd->log.clean.nextentry = commonUfsDirCleanLogNextEntry; - sd->log.clean.done = commonUfsDirWriteCleanDone; - - parse_cachedir_options(sd, options, 0); - - /* Initialise replacement policy stuff */ - sd->repl = createRemovalPolicy(Config.replPolicy); -} - -/* - * Initial setup / end destruction - */ -static void -storeDiskdDirDone(void) -{ - memPoolDestroy(&diskd_state_pool); - diskd_initialised = 0; -} - -void -storeFsSetup_diskd(storefs_entry_t * storefs) -{ - assert(!diskd_initialised); - storefs->parsefunc = storeDiskdDirParse; - storefs->reconfigurefunc = storeDiskdDirReconfigure; - storefs->donefunc = storeDiskdDirDone; - diskd_state_pool = memPoolCreate("DISKD IO State data", sizeof(diskdstate_t)); - memset(&diskd_stats, '\0', sizeof(diskd_stats)); - cachemgrRegister("diskd", "DISKD Stats", storeDiskdStats, 0, 1); - debug(47, 1) ("diskd started\n"); - diskd_initialised = 1; -} --- /dev/null Wed Feb 14 01:07:22 2007 +++ squid/src/fs/diskd/store_dir_diskd.cc Wed Feb 14 01:07:42 2007 @@ -0,0 +1,516 @@ + +/* + * $Id: store_dir_diskd.cc,v 1.1.2.1 2002/10/12 12:21:43 rbcollins Exp $ + * + * DEBUG: section 47 Store Directory Routines + * AUTHOR: Duane Wessels + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" +#include "Store.h" + +#include +#include +#include + +#include "store_diskd.h" + +#include "ufscommon.h" + +diskd_stats_t diskd_stats; + +MemPool *diskd_state_pool = NULL; +static int diskd_initialised = 0; + +static STINIT storeDiskdDirInit; +static STDUMP storeDiskdDirDump; +static STCHECKOBJ storeDiskdDirCheckObj; +static void storeDiskdDirStats(SwapDir *, StoreEntry *); +static void storeDiskdStats(StoreEntry * sentry); +static void storeDiskdDirSync(SwapDir *); +static void storeDiskdDirIOUnlinkFile(char *path); + +/* The only externally visible interface */ +STSETUP storeFsSetup_diskd; + +static void +storeDiskdDirInit(SwapDir * sd) +{ + int x; + int i; + int rfd; + int ikey; + const char *args[5]; + char skey1[32]; + char skey2[32]; + char skey3[32]; + diskdinfo_t *diskdinfo = (diskdinfo_t *)sd->fsdata; + + ikey = (getpid() << 10) + (sd->index << 2); + ikey &= 0x7fffffff; + diskdinfo->smsgid = msgget((key_t) ikey, 0700 | IPC_CREAT); + if (diskdinfo->smsgid < 0) { + debug(50, 0) ("storeDiskdInit: msgget: %s\n", xstrerror()); + fatal("msgget failed"); + } + diskdinfo->rmsgid = msgget((key_t) (ikey + 1), 0700 | IPC_CREAT); + if (diskdinfo->rmsgid < 0) { + debug(50, 0) ("storeDiskdInit: msgget: %s\n", xstrerror()); + fatal("msgget failed"); + } + diskdinfo->shm.nbufs = (int)(diskdinfo->magic2 * 1.3); + diskdinfo->shm.id = shmget((key_t) (ikey + 2), + diskdinfo->shm.nbufs * SHMBUF_BLKSZ, 0600 | IPC_CREAT); + if (diskdinfo->shm.id < 0) { + debug(50, 0) ("storeDiskdInit: shmget: %s\n", xstrerror()); + fatal("shmget failed"); + } + diskdinfo->shm.buf = (char *)shmat(diskdinfo->shm.id, NULL, 0); + if (diskdinfo->shm.buf == (void *) -1) { + debug(50, 0) ("storeDiskdInit: shmat: %s\n", xstrerror()); + fatal("shmat failed"); + } + diskdinfo->shm.inuse_map = (char *)xcalloc((diskdinfo->shm.nbufs + 7) / 8, 1); + diskd_stats.shmbuf_count += diskdinfo->shm.nbufs; + for (i = 0; i < diskdinfo->shm.nbufs; i++) { + CBIT_SET(diskdinfo->shm.inuse_map, i); + storeDiskdShmPut(sd, i * SHMBUF_BLKSZ); + } + snprintf(skey1, 32, "%d", ikey); + snprintf(skey2, 32, "%d", ikey + 1); + snprintf(skey3, 32, "%d", ikey + 2); + args[0] = "diskd"; + args[1] = skey1; + args[2] = skey2; + args[3] = skey3; + args[4] = NULL; + x = ipcCreate(IPC_STREAM, + Config.Program.diskd, + args, + "diskd", + &rfd, + &diskdinfo->wfd); + if (x < 0) + fatalf("execl: %s", Config.Program.diskd); + if (rfd != diskdinfo->wfd) + comm_close(rfd); + fd_note(diskdinfo->wfd, "squid -> diskd"); + commSetTimeout(diskdinfo->wfd, -1, NULL, NULL); + commSetNonBlocking(diskdinfo->wfd); + + commonUfsDirInit (sd); + + comm_quick_poll_required(); +} + + +static void +storeDiskdStats(StoreEntry * sentry) +{ + storeAppendPrintf(sentry, "sent_count: %d\n", diskd_stats.sent_count); + storeAppendPrintf(sentry, "recv_count: %d\n", diskd_stats.recv_count); + storeAppendPrintf(sentry, "max_away: %d\n", diskd_stats.max_away); + storeAppendPrintf(sentry, "max_shmuse: %d\n", diskd_stats.max_shmuse); + storeAppendPrintf(sentry, "open_fail_queue_len: %d\n", diskd_stats.open_fail_queue_len); + storeAppendPrintf(sentry, "block_queue_len: %d\n", diskd_stats.block_queue_len); + diskd_stats.max_away = diskd_stats.max_shmuse = 0; + storeAppendPrintf(sentry, "\n OPS SUCCESS FAIL\n"); + storeAppendPrintf(sentry, "%7s %7d %7d %7d\n", + "open", diskd_stats.open.ops, diskd_stats.open.success, diskd_stats.open.fail); + storeAppendPrintf(sentry, "%7s %7d %7d %7d\n", + "create", diskd_stats.create.ops, diskd_stats.create.success, diskd_stats.create.fail); + storeAppendPrintf(sentry, "%7s %7d %7d %7d\n", + "close", diskd_stats.close.ops, diskd_stats.close.success, diskd_stats.close.fail); + storeAppendPrintf(sentry, "%7s %7d %7d %7d\n", + "unlink", diskd_stats.unlink.ops, diskd_stats.unlink.success, diskd_stats.unlink.fail); + storeAppendPrintf(sentry, "%7s %7d %7d %7d\n", + "read", diskd_stats.read.ops, diskd_stats.read.success, diskd_stats.read.fail); + storeAppendPrintf(sentry, "%7s %7d %7d %7d\n", + "write", diskd_stats.write.ops, diskd_stats.write.success, diskd_stats.write.fail); +} + +/* + * storeDiskdDirSync + * + * Sync any pending data. We just sit around and read the queue + * until the data has finished writing. + */ +static void +storeDiskdDirSync(SwapDir * SD) +{ + static time_t lastmsg = 0; + diskdinfo_t *diskdinfo = (diskdinfo_t *)SD->fsdata; + while (diskdinfo->away > 0) { + if (squid_curtime > lastmsg) { + debug(47, 1) ("storeDiskdDirSync: %d messages away\n", + diskdinfo->away); + lastmsg = squid_curtime; + } + storeDiskdDirCallback(SD); + } +} + + +/* + * storeDiskdDirCallback + * + * Handle callbacks. If we have more than magic2 requests away, we block + * until the queue is below magic2. Otherwise, we simply return when we + * don't get a message. + */ +int +storeDiskdDirCallback(SwapDir * SD) +{ + diomsg M; + int x; + diskdinfo_t *diskdinfo = (diskdinfo_t *)SD->fsdata; + int retval = 0; + + if (diskdinfo->away >= diskdinfo->magic2) { + diskd_stats.block_queue_len++; + retval = 1; /* We might not have anything to do, but our queue + * is full.. */ + } + if (diskd_stats.sent_count - diskd_stats.recv_count > + diskd_stats.max_away) { + diskd_stats.max_away = diskd_stats.sent_count - diskd_stats.recv_count; + } + while (1) { + memset(&M, '\0', sizeof(M)); + x = msgrcv(diskdinfo->rmsgid, &M, msg_snd_rcv_sz, 0, IPC_NOWAIT); + if (x < 0) + break; + else if (x != msg_snd_rcv_sz) { + debug(47, 1) ("storeDiskdDirCallback: msgget returns %d\n", + x); + break; + } + diskd_stats.recv_count++; + diskdinfo->away--; + storeDiskdHandle(&M); + retval = 1; /* Return that we've actually done some work */ + if (M.shm_offset > -1) + storeDiskdShmPut(SD, (off_t) M.shm_offset); + } + return retval; +} + +/* + * storeDiskdDirCheckObj + * + * This routine is called by storeDirSelectSwapDir to see if the given + * object is able to be stored on this filesystem. DISKD filesystems will + * happily store anything as long as the LRU time isn't too small. + */ +int +storeDiskdDirCheckObj(SwapDir * SD, const StoreEntry * e) +{ + diskdinfo_t *diskdinfo = (diskdinfo_t *)SD->fsdata; + /* Check the queue length */ + if (diskdinfo->away >= diskdinfo->magic1) + return -1; + /* Calculate the storedir load relative to magic2 on a scale of 0 .. 1000 */ + /* the parse function guarantees magic2 is positivie */ + return diskdinfo->away * 1000 / diskdinfo->magic2; +} + +void +storeDiskdDirIOUnlinkFile(char *path) +{ +#if USE_UNLINKD + unlinkdUnlink(path); +#elif USE_TRUNCATE + truncate(path, 0); +#else + unlink(path); +#endif + +} + +/* + * SHM manipulation routines + */ + +void * +storeDiskdShmGet(SwapDir * sd, off_t * shm_offset) +{ + char *buf = NULL; + diskdinfo_t *diskdinfo = (diskdinfo_t *)sd->fsdata; + int i; + for (i = 0; i < diskdinfo->shm.nbufs; i++) { + if (CBIT_TEST(diskdinfo->shm.inuse_map, i)) + continue; + CBIT_SET(diskdinfo->shm.inuse_map, i); + *shm_offset = i * SHMBUF_BLKSZ; + buf = diskdinfo->shm.buf + (*shm_offset); + break; + } + assert(buf); + assert(buf >= diskdinfo->shm.buf); + assert(buf < diskdinfo->shm.buf + (diskdinfo->shm.nbufs * SHMBUF_BLKSZ)); + diskd_stats.shmbuf_count++; + if (diskd_stats.max_shmuse < diskd_stats.shmbuf_count) + diskd_stats.max_shmuse = diskd_stats.shmbuf_count; + return buf; +} + +void +storeDiskdShmPut(SwapDir * sd, off_t offset) +{ + int i; + diskdinfo_t *diskdinfo = (diskdinfo_t *)sd->fsdata; + assert(offset >= 0); + assert(offset < diskdinfo->shm.nbufs * SHMBUF_BLKSZ); + i = offset / SHMBUF_BLKSZ; + assert(i < diskdinfo->shm.nbufs); + assert(CBIT_TEST(diskdinfo->shm.inuse_map, i)); + CBIT_CLR(diskdinfo->shm.inuse_map, i); + diskd_stats.shmbuf_count--; +} + + + + +/* ========== LOCAL FUNCTIONS ABOVE, GLOBAL FUNCTIONS BELOW ========== */ + +void +storeDiskdDirStats(SwapDir * SD, StoreEntry * sentry) +{ + diskdinfo_t *diskdinfo = (diskdinfo_t *)SD->fsdata; + commonUfsDirStats (SD, sentry); + storeAppendPrintf(sentry, "Pending operations: %d\n", diskdinfo->away); +} + +static void +storeDiskdDirParseQ1(SwapDir * sd, const char *name, const char *value, int reconfiguring) +{ + diskdinfo_t *diskdinfo = (diskdinfo_t *)sd->fsdata; + int old_magic1 = diskdinfo->magic1; + diskdinfo->magic1 = atoi(value); + if (!reconfiguring) + return; + if (old_magic1 < diskdinfo->magic1) { + /* + * This is because shm.nbufs is computed at startup, when + * we call shmget(). We can't increase the Q1/Q2 parameters + * beyond their initial values because then we might have + * more "Q2 messages" than shared memory chunks, and this + * will cause an assertion in storeDiskdShmGet(). + */ + debug(3, 1) ("WARNING: cannot increase cache_dir '%s' Q1 value while Squid is running.\n", sd->path); + diskdinfo->magic1 = old_magic1; + return; + } + if (old_magic1 != diskdinfo->magic1) + debug(3, 1) ("cache_dir '%s' new Q1 value '%d'\n", + sd->path, diskdinfo->magic1); +} + +static void +storeDiskdDirDumpQ1(StoreEntry * e, const char *option, SwapDir * sd) +{ + diskdinfo_t *diskdinfo = (diskdinfo_t *)sd->fsdata; + storeAppendPrintf(e, " Q1=%d", diskdinfo->magic1); +} + +static void +storeDiskdDirParseQ2(SwapDir * sd, const char *name, const char *value, int reconfiguring) +{ + diskdinfo_t *diskdinfo = (diskdinfo_t *)sd->fsdata; + int old_magic2 = diskdinfo->magic2; + diskdinfo->magic2 = atoi(value); + if (!reconfiguring) + return; + if (old_magic2 < diskdinfo->magic2) { + /* See comments in Q1 function above */ + debug(3, 1) ("WARNING: cannot increase cache_dir '%s' Q2 value while Squid is running.\n", sd->path); + diskdinfo->magic2 = old_magic2; + return; + } + if (old_magic2 != diskdinfo->magic2) + debug(3, 1) ("cache_dir '%s' new Q2 value '%d'\n", + sd->path, diskdinfo->magic2); +} + +static void +storeDiskdDirDumpQ2(StoreEntry * e, const char *option, SwapDir * sd) +{ + diskdinfo_t *diskdinfo = (diskdinfo_t *)sd->fsdata; + storeAppendPrintf(e, " Q2=%d", diskdinfo->magic2); +} + +struct cache_dir_option options[] = +{ +#if NOT_YET + {"L1", storeDiskdDirParseL1, storeDiskdDirDumpL1}, + {"L2", storeDiskdDirParseL2, storeDiskdDirDumpL2}, +#endif + {"Q1", storeDiskdDirParseQ1, storeDiskdDirDumpQ1}, + {"Q2", storeDiskdDirParseQ2, storeDiskdDirDumpQ2}, + {NULL, NULL} +}; + +/* + * storeDiskdDirReconfigure + * + * This routine is called when the given swapdir needs reconfiguring + */ +static void +storeDiskdDirReconfigure(SwapDir * sd, int index, char *path) +{ + int i; + int size; + int l1; + int l2; + + i = GetInteger(); + size = i << 10; /* Mbytes to kbytes */ + if (size <= 0) + fatal("storeDiskdDirReconfigure: invalid size value"); + i = GetInteger(); + l1 = i; + if (l1 <= 0) + fatal("storeDiskdDirReconfigure: invalid level 1 directories value"); + i = GetInteger(); + l2 = i; + if (l2 <= 0) + fatal("storeDiskdDirReconfigure: invalid level 2 directories value"); + + /* just reconfigure it */ + if (size == sd->max_size) + debug(3, 1) ("Cache dir '%s' size remains unchanged at %d KB\n", + path, size); + else + debug(3, 1) ("Cache dir '%s' size changed to %d KB\n", + path, size); + sd->max_size = size; + parse_cachedir_options(sd, options, 1); +} + +void +storeDiskdDirDump(StoreEntry * entry, SwapDir * s) +{ + commonUfsDirDump (entry, s); + dump_cachedir_options(entry, options, s); +} + +/* + * storeDiskdDirParse + * + * Called when a *new* fs is being setup. + */ +static void +storeDiskdDirParse(SwapDir * sd, int index, char *path) +{ + int i; + int size; + int l1; + int l2; + diskdinfo_t *diskdinfo; + + i = GetInteger(); + size = i << 10; /* Mbytes to kbytes */ + if (size <= 0) + fatal("storeDiskdDirParse: invalid size value"); + i = GetInteger(); + l1 = i; + if (l1 <= 0) + fatal("storeDiskdDirParse: invalid level 1 directories value"); + i = GetInteger(); + l2 = i; + if (l2 <= 0) + fatal("storeDiskdDirParse: invalid level 2 directories value"); + + sd->fsdata = diskdinfo = (diskdinfo_t *)xcalloc(1, sizeof(*diskdinfo)); + sd->index = index; + sd->path = xstrdup(path); + sd->max_size = size; + diskdinfo->commondata.l1 = l1; + diskdinfo->commondata.l2 = l2; + diskdinfo->commondata.swaplog_fd = -1; + diskdinfo->commondata.map = NULL; /* Debugging purposes */ + diskdinfo->commondata.suggest = 0; + diskdinfo->commondata.io.storeDirUnlinkFile = storeDiskdDirIOUnlinkFile; + diskdinfo->magic1 = 64; + diskdinfo->magic2 = 72; + sd->init = storeDiskdDirInit; + sd->newfs = commonUfsDirNewfs; + sd->dump = storeDiskdDirDump; + sd->freefs = commonUfsDirFree; + sd->dblcheck = commonUfsCleanupDoubleCheck; + sd->statfs = storeDiskdDirStats; + sd->maintainfs = commonUfsDirMaintain; + sd->checkobj = storeDiskdDirCheckObj; + sd->refobj = commonUfsDirRefObj; + sd->unrefobj = commonUfsDirUnrefObj; + sd->callback = storeDiskdDirCallback; + sd->sync = storeDiskdDirSync; + sd->obj.create = storeDiskdCreate; + sd->obj.open = storeDiskdOpen; + sd->obj.close = storeDiskdClose; + sd->obj.read = storeDiskdRead; + sd->obj.write = storeDiskdWrite; + sd->obj.unlink = storeDiskdUnlink; + sd->log.open = commonUfsDirOpenSwapLog; + sd->log.close = commonUfsDirCloseSwapLog; + sd->log.write = commonUfsDirSwapLog; + sd->log.clean.start = commonUfsDirWriteCleanStart; + sd->log.clean.nextentry = commonUfsDirCleanLogNextEntry; + sd->log.clean.done = commonUfsDirWriteCleanDone; + + parse_cachedir_options(sd, options, 0); + + /* Initialise replacement policy stuff */ + sd->repl = createRemovalPolicy(Config.replPolicy); +} + +/* + * Initial setup / end destruction + */ +static void +storeDiskdDirDone(void) +{ + memPoolDestroy(&diskd_state_pool); + diskd_initialised = 0; +} + +void +storeFsSetup_diskd(storefs_entry_t * storefs) +{ + assert(!diskd_initialised); + storefs->parsefunc = storeDiskdDirParse; + storefs->reconfigurefunc = storeDiskdDirReconfigure; + storefs->donefunc = storeDiskdDirDone; + diskd_state_pool = memPoolCreate("DISKD IO State data", sizeof(diskdstate_t)); + memset(&diskd_stats, '\0', sizeof(diskd_stats)); + cachemgrRegister("diskd", "DISKD Stats", storeDiskdStats, 0, 1); + debug(47, 1) ("diskd started\n"); + diskd_initialised = 1; +} --- squid/src/fs/diskd/store_io_diskd.c Wed Feb 14 01:07:42 2007 +++ /dev/null Wed Feb 14 01:07:22 2007 @@ -1,520 +0,0 @@ - -/* - * $Id$ - * - * DEBUG: section 79 Squid-side DISKD I/O functions. - * AUTHOR: Duane Wessels - * - * SQUID Web Proxy Cache http://www.squid-cache.org/ - * ---------------------------------------------------------- - * - * Squid is the result of efforts by numerous individuals from - * the Internet community; see the CONTRIBUTORS file for full - * details. Many organizations have provided support for Squid's - * development; see the SPONSORS file for full details. Squid is - * Copyrighted (C) 2001 by the Regents of the University of - * California; see the COPYRIGHT file for full details. Squid - * incorporates software developed and/or copyrighted by other - * sources; see the CREDITS file for full details. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. - * - */ - -#include "config.h" -#include "squid.h" -#include "Store.h" - -#include -#include -#include - -#include "store_diskd.h" - -static int storeDiskdSend(int, SwapDir *, int, storeIOState *, int, int, off_t); -static void storeDiskdIOCallback(storeIOState * sio, int errflag); -static CBDUNL storeDiskdIOFreeEntry; - -CBDATA_TYPE(storeIOState); - -/* === PUBLIC =========================================================== */ - -storeIOState * -storeDiskdOpen(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, - STIOCB * callback, void *callback_data) -{ - sfileno f = e->swap_filen; - int x; - storeIOState *sio; - char *buf; - diskdstate_t *diskdstate; - off_t shm_offset; - diskdinfo_t *diskdinfo = SD->fsdata; - debug(79, 3) ("storeDiskdOpen: fileno %08X\n", f); - /* - * Fail on open() if there are too many requests queued. - */ - if (diskdinfo->away > diskdinfo->magic1) { - debug(79, 3) ("storeDiskdOpen: FAILING, too many requests away\n"); - diskd_stats.open_fail_queue_len++; - return NULL; - } - CBDATA_INIT_TYPE_FREECB(storeIOState, storeDiskdIOFreeEntry); - sio = cbdataAlloc(storeIOState); - sio->fsstate = diskdstate = memPoolAlloc(diskd_state_pool); - - sio->swap_filen = f; - sio->swap_dirn = SD->index; - sio->mode = O_RDONLY | O_BINARY; - sio->callback = callback; - sio->callback_data = cbdataReference(callback_data); - sio->e = e; - - diskdstate->flags.writing = 0; - diskdstate->flags.reading = 0; - diskdstate->flags.close_request = 0; - diskdstate->id = diskd_stats.sio_id++; - - buf = storeDiskdShmGet(SD, &shm_offset); - xstrncpy(buf, commonUfsDirFullPath(SD, f, NULL), SHMBUF_BLKSZ); - x = storeDiskdSend(_MQD_OPEN, - SD, - diskdstate->id, - sio, - strlen(buf) + 1, - O_RDONLY, - shm_offset); - if (x < 0) { - debug(79, 1) ("storeDiskdSend OPEN: %s\n", xstrerror()); - storeDiskdShmPut(SD, shm_offset); - cbdataReferenceDone(sio->callback_data); - cbdataFree(sio); - return NULL; - } - diskd_stats.open.ops++; - return sio; -} - -storeIOState * -storeDiskdCreate(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, - STIOCB * callback, void *callback_data) -{ - sfileno f; - int x; - storeIOState *sio; - char *buf; - off_t shm_offset; - diskdinfo_t *diskdinfo = SD->fsdata; - diskdstate_t *diskdstate; - /* - * Fail on open() if there are too many requests queued. - */ - if (diskdinfo->away > diskdinfo->magic1) { - diskd_stats.open_fail_queue_len++; - return NULL; - } - /* Allocate a number */ - f = commonUfsDirMapBitAllocate(SD); - debug(79, 3) ("storeDiskdCreate: fileno %08X\n", f); - - CBDATA_INIT_TYPE_FREECB(storeIOState, storeDiskdIOFreeEntry); - sio = cbdataAlloc(storeIOState); - sio->fsstate = diskdstate = memPoolAlloc(diskd_state_pool); - - sio->swap_filen = f; - sio->swap_dirn = SD->index; - sio->mode = O_WRONLY | O_CREAT | O_TRUNC; - sio->callback = callback; - sio->callback_data = cbdataReference(callback_data); - sio->e = e; - - diskdstate->flags.writing = 0; - diskdstate->flags.reading = 0; - diskdstate->flags.close_request = 0; - diskdstate->id = diskd_stats.sio_id++; - - buf = storeDiskdShmGet(SD, &shm_offset); - xstrncpy(buf, commonUfsDirFullPath(SD, f, NULL), SHMBUF_BLKSZ); - x = storeDiskdSend(_MQD_OPEN, - SD, - diskdstate->id, - sio, - strlen(buf) + 1, - sio->mode, - shm_offset); - if (x < 0) { - debug(79, 1) ("storeDiskdSend OPEN: %s\n", xstrerror()); - storeDiskdShmPut(SD, shm_offset); - cbdataReferenceDone(sio->callback_data); - cbdataFree(sio); - return NULL; - } - commonUfsDirReplAdd(SD, e); - diskd_stats.create.ops++; - return sio; -} - - -void -storeDiskdClose(SwapDir * SD, storeIOState * sio) -{ - int x; - diskdstate_t *diskdstate = sio->fsstate; - debug(79, 3) ("storeDiskdClose: dirno %d, fileno %08X\n", SD->index, - sio->swap_filen); - x = storeDiskdSend(_MQD_CLOSE, - SD, - diskdstate->id, - sio, - 0, - 0, - -1); - if (x < 0) { - debug(79, 1) ("storeDiskdSend CLOSE: %s\n", xstrerror()); - storeDiskdIOCallback(sio, DISK_ERROR); - } - diskdstate->flags.close_request = 1; - diskd_stats.close.ops++; -} - -void -storeDiskdRead(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data) -{ - int x; - off_t shm_offset; - char *rbuf; - diskdstate_t *diskdstate = sio->fsstate; - debug(79, 3) ("storeDiskdRead: dirno %d, fileno %08X\n", sio->swap_dirn, sio->swap_filen); - assert(!diskdstate->flags.close_request); - if (!cbdataReferenceValid(sio)) - return; - if (diskdstate->flags.reading) { - debug(79, 1) ("storeDiskdRead: already reading!\n"); - return; - } - assert(sio->read.callback == NULL); - assert(sio->read.callback_data == NULL); - sio->read.callback = callback; - sio->read.callback_data = cbdataReference(callback_data); - diskdstate->read_buf = buf; /* the one passed from above */ - sio->offset = offset; - diskdstate->flags.reading = 1; - rbuf = storeDiskdShmGet(SD, &shm_offset); - assert(rbuf); - x = storeDiskdSend(_MQD_READ, - SD, - diskdstate->id, - sio, - (int) size, - (int) offset, - shm_offset); - if (x < 0) { - debug(79, 1) ("storeDiskdSend READ: %s\n", xstrerror()); - storeDiskdShmPut(SD, shm_offset); - storeDiskdIOCallback(sio, DISK_ERROR); - } - diskd_stats.read.ops++; -} - -void -storeDiskdWrite(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, FREE * free_func) -{ - int x; - char *sbuf; - off_t shm_offset; - diskdstate_t *diskdstate = sio->fsstate; - debug(79, 3) ("storeDiskdWrite: dirno %d, fileno %08X\n", SD->index, sio->swap_filen); - assert(!diskdstate->flags.close_request); - if (!cbdataReferenceValid(sio)) { - free_func(buf); - return; - } - diskdstate->flags.writing = 1; - sbuf = storeDiskdShmGet(SD, &shm_offset); - xmemcpy(sbuf, buf, size); - if (free_func) - free_func(buf); - x = storeDiskdSend(_MQD_WRITE, - SD, - diskdstate->id, - sio, - (int) size, - (int) offset, - shm_offset); - if (x < 0) { - debug(79, 1) ("storeDiskdSend WRITE: %s\n", xstrerror()); - storeDiskdShmPut(SD, shm_offset); - storeDiskdIOCallback(sio, DISK_ERROR); - } - diskd_stats.write.ops++; -} - -void -storeDiskdUnlink(SwapDir * SD, StoreEntry * e) -{ - int x; - off_t shm_offset; - char *buf; - diskdinfo_t *diskdinfo = SD->fsdata; - - debug(79, 3) ("storeDiskdUnlink: dirno %d, fileno %08X\n", SD->index, - e->swap_filen); - commonUfsDirReplRemove(e); - commonUfsDirMapBitReset(SD, e->swap_filen); - if (diskdinfo->away >= diskdinfo->magic1) { - /* Damn, we need to issue a sync unlink here :( */ - debug(79, 2) ("storeDiskUnlink: Out of queue space, sync unlink\n"); - commonUfsDirUnlinkFile(SD, e->swap_filen); - return; - } - /* We can attempt a diskd unlink */ - buf = storeDiskdShmGet(SD, &shm_offset); - xstrncpy(buf, commonUfsDirFullPath(SD, e->swap_filen, NULL), SHMBUF_BLKSZ); - x = storeDiskdSend(_MQD_UNLINK, - SD, - e->swap_filen, - NULL, - 0, - 0, - shm_offset); - if (x < 0) { - debug(79, 1) ("storeDiskdSend UNLINK: %s\n", xstrerror()); - unlink(buf); /* XXX EWW! */ - storeDiskdShmPut(SD, shm_offset); - } - diskd_stats.unlink.ops++; -} - - -/* === STATIC =========================================================== */ - -static void -storeDiskdOpenDone(diomsg * M) -{ - storeIOState *sio = M->callback_data; - statCounter.syscalls.disk.opens++; - debug(79, 3) ("storeDiskdOpenDone: dirno %d, fileno %08x status %d\n", - sio->swap_dirn, sio->swap_filen, M->status); - if (M->status < 0) { - FILE_MODE(sio->mode) == O_RDONLY ? diskd_stats.open.fail++ : diskd_stats.create.fail++; - storeDiskdIOCallback(sio, DISK_ERROR); - } else { - FILE_MODE(sio->mode) == O_RDONLY ? diskd_stats.open.success++ : diskd_stats.create.success++; - } -} - -static void -storeDiskdCloseDone(diomsg * M) -{ - storeIOState *sio = M->callback_data; - statCounter.syscalls.disk.closes++; - debug(79, 3) ("storeDiskdCloseDone: dirno %d, fileno %08x status %d\n", - sio->swap_dirn, sio->swap_filen, M->status); - if (M->status < 0) { - diskd_stats.close.fail++; - storeDiskdIOCallback(sio, DISK_ERROR); - return; - } - diskd_stats.close.success++; - storeDiskdIOCallback(sio, DISK_OK); -} - -static void -storeDiskdReadDone(diomsg * M) -{ - storeIOState *sio = M->callback_data; - STRCB *callback = sio->read.callback; - void *cbdata; - SwapDir *sd = INDEXSD(sio->swap_dirn); - diskdstate_t *diskdstate = sio->fsstate; - diskdinfo_t *diskdinfo = sd->fsdata; - char *their_buf = diskdstate->read_buf; - char *sbuf; - size_t len; - statCounter.syscalls.disk.reads++; - diskdstate->flags.reading = 0; - debug(79, 3) ("storeDiskdReadDone: dirno %d, fileno %08x status %d\n", - sio->swap_dirn, sio->swap_filen, M->status); - if (M->status < 0) { - diskd_stats.read.fail++; - storeDiskdIOCallback(sio, DISK_ERROR); - return; - } - diskd_stats.read.success++; - sbuf = diskdinfo->shm.buf + M->shm_offset; - len = M->status; - sio->offset += len; - assert(callback); - sio->read.callback = NULL; - if (cbdataReferenceValidDone(sio->read.callback_data, &cbdata)) { - assert(!diskdstate->flags.close_request); - /* - * Only copy the data if the callback is still valid, - * if it isn't valid then the request should have been - * aborted. - * -- adrian - */ - xmemcpy(their_buf, sbuf, len); /* yucky copy */ - callback(cbdata, their_buf, len); - } -} - -static void -storeDiskdWriteDone(diomsg * M) -{ - storeIOState *sio = M->callback_data; - diskdstate_t *diskdstate = sio->fsstate; - statCounter.syscalls.disk.writes++; - diskdstate->flags.writing = 0; - debug(79, 3) ("storeDiskdWriteDone: dirno %d, fileno %08x status %d\n", - sio->swap_dirn, sio->swap_filen, M->status); - if (M->status < 0) { - diskd_stats.write.fail++; - storeDiskdIOCallback(sio, DISK_ERROR); - return; - } - diskd_stats.write.success++; - sio->offset += M->status; -} - -static void -storeDiskdUnlinkDone(diomsg * M) -{ - debug(79, 3) ("storeDiskdUnlinkDone: fileno %08x status %d\n", - M->id, M->status); - statCounter.syscalls.disk.unlinks++; - if (M->status < 0) - diskd_stats.unlink.fail++; - else - diskd_stats.unlink.success++; -} - -void -storeDiskdHandle(diomsg * M) -{ - if (cbdataReferenceValid(M->callback_data)) { - switch (M->mtype) { - case _MQD_OPEN: - storeDiskdOpenDone(M); - break; - case _MQD_CLOSE: - storeDiskdCloseDone(M); - break; - case _MQD_READ: - storeDiskdReadDone(M); - break; - case _MQD_WRITE: - storeDiskdWriteDone(M); - break; - case _MQD_UNLINK: - storeDiskdUnlinkDone(M); - break; - default: - assert(0); - break; - } - } else { - debug(79, 3) ("storeDiskdHandle: Invalid callback_data %p\n", - M->callback_data); - /* - * The read operation has its own callback. If we don't - * call storeDiskdReadDone(), then we must make sure the - * callback_data gets unlocked! - */ - if (_MQD_READ == M->mtype) { - /* XXX This cannot be the correct approach. This - * is most likely the wrong place for this. It should - * be done before the sio becomes invalid, not here. - */ - storeIOState *sio = M->callback_data; - cbdataReferenceDone(sio->read.callback_data); - } - } - cbdataReferenceDone(M->callback_data); -} - -static void -storeDiskdIOCallback(storeIOState * sio, int errflag) -{ - void *cbdata; - STIOCB *callback = sio->callback; - debug(79, 3) ("storeUfsIOCallback: errflag=%d\n", errflag); - sio->callback = NULL; - if (cbdataReferenceValidDone(sio->callback_data, &cbdata)) - callback(cbdata, errflag, sio); - cbdataFree(sio); -} - -static int -storeDiskdSend(int mtype, SwapDir * sd, int id, storeIOState * sio, int size, int offset, off_t shm_offset) -{ - int x; - diomsg M; - static int send_errors = 0; - static int last_seq_no = 0; - static int seq_no = 0; - diskdinfo_t *diskdinfo = sd->fsdata; - M.mtype = mtype; - M.callback_data = cbdataReference(sio); - M.size = size; - M.offset = offset; - M.status = -1; - M.shm_offset = (int) shm_offset; - M.id = id; - M.seq_no = ++seq_no; - if (M.seq_no < last_seq_no) - debug(79, 1) ("WARNING: sequencing out of order\n"); - x = msgsnd(diskdinfo->smsgid, &M, msg_snd_rcv_sz, IPC_NOWAIT); - last_seq_no = M.seq_no; - if (0 == x) { - diskd_stats.sent_count++; - diskdinfo->away++; - } else { - debug(79, 1) ("storeDiskdSend: msgsnd: %s\n", xstrerror()); - cbdataReferenceDone(M.callback_data); - assert(++send_errors < 100); - } - /* - * We have to drain the queue here if necessary. If we don't, - * then we can have a lot of messages in the queue (probably - * up to 2*magic1) and we can run out of shared memory buffers. - */ - /* - * Note that we call storeDirCallback (for all SDs), rather - * than storeDiskdDirCallback for just this SD, so that while - * we're "blocking" on this SD we can also handle callbacks - * from other SDs that might be ready. - */ - while (diskdinfo->away > diskdinfo->magic2) { - struct timeval delay = - {0, 1}; - select(0, NULL, NULL, NULL, &delay); - storeDirCallback(); - if (delay.tv_usec < 1000000) - delay.tv_usec <<= 1; - } - return x; -} - - -/* - * We can't pass memFree() as a free function here, because we need to free - * the fsstate variable .. - */ -static void -storeDiskdIOFreeEntry(void *sio) -{ - memPoolFree(diskd_state_pool, ((storeIOState *) sio)->fsstate); -} --- /dev/null Wed Feb 14 01:07:22 2007 +++ squid/src/fs/diskd/store_io_diskd.cc Wed Feb 14 01:07:42 2007 @@ -0,0 +1,520 @@ + +/* + * $Id: store_io_diskd.cc,v 1.1.2.1 2002/10/12 12:21:43 rbcollins Exp $ + * + * DEBUG: section 79 Squid-side DISKD I/O functions. + * AUTHOR: Duane Wessels + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "config.h" +#include "squid.h" +#include "Store.h" + +#include +#include +#include + +#include "store_diskd.h" + +static int storeDiskdSend(int, SwapDir *, int, storeIOState *, int, int, off_t); +static void storeDiskdIOCallback(storeIOState * sio, int errflag); +static CBDUNL storeDiskdIOFreeEntry; + +CBDATA_TYPE(storeIOState); + +/* === PUBLIC =========================================================== */ + +storeIOState * +storeDiskdOpen(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, + STIOCB * callback, void *callback_data) +{ + sfileno f = e->swap_filen; + int x; + storeIOState *sio; + char *buf; + diskdstate_t *diskdstate; + off_t shm_offset; + diskdinfo_t *diskdinfo = (diskdinfo_t *)SD->fsdata; + debug(79, 3) ("storeDiskdOpen: fileno %08X\n", f); + /* + * Fail on open() if there are too many requests queued. + */ + if (diskdinfo->away > diskdinfo->magic1) { + debug(79, 3) ("storeDiskdOpen: FAILING, too many requests away\n"); + diskd_stats.open_fail_queue_len++; + return NULL; + } + CBDATA_INIT_TYPE_FREECB(storeIOState, storeDiskdIOFreeEntry); + sio = cbdataAlloc(storeIOState); + sio->fsstate = diskdstate = (diskdstate_t *)memPoolAlloc(diskd_state_pool); + + sio->swap_filen = f; + sio->swap_dirn = SD->index; + sio->mode = O_RDONLY | O_BINARY; + sio->callback = callback; + sio->callback_data = cbdataReference(callback_data); + sio->e = e; + + diskdstate->flags.writing = 0; + diskdstate->flags.reading = 0; + diskdstate->flags.close_request = 0; + diskdstate->id = diskd_stats.sio_id++; + + buf = (char *)storeDiskdShmGet(SD, &shm_offset); + xstrncpy(buf, commonUfsDirFullPath(SD, f, NULL), SHMBUF_BLKSZ); + x = storeDiskdSend(_MQD_OPEN, + SD, + diskdstate->id, + sio, + strlen(buf) + 1, + O_RDONLY, + shm_offset); + if (x < 0) { + debug(79, 1) ("storeDiskdSend OPEN: %s\n", xstrerror()); + storeDiskdShmPut(SD, shm_offset); + cbdataReferenceDone(sio->callback_data); + cbdataFree(sio); + return NULL; + } + diskd_stats.open.ops++; + return sio; +} + +storeIOState * +storeDiskdCreate(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, + STIOCB * callback, void *callback_data) +{ + sfileno f; + int x; + storeIOState *sio; + char *buf; + off_t shm_offset; + diskdinfo_t *diskdinfo = (diskdinfo_t *)SD->fsdata; + diskdstate_t *diskdstate; + /* + * Fail on open() if there are too many requests queued. + */ + if (diskdinfo->away > diskdinfo->magic1) { + diskd_stats.open_fail_queue_len++; + return NULL; + } + /* Allocate a number */ + f = commonUfsDirMapBitAllocate(SD); + debug(79, 3) ("storeDiskdCreate: fileno %08X\n", f); + + CBDATA_INIT_TYPE_FREECB(storeIOState, storeDiskdIOFreeEntry); + sio = cbdataAlloc(storeIOState); + sio->fsstate = diskdstate = (diskdstate_t *)memPoolAlloc(diskd_state_pool); + + sio->swap_filen = f; + sio->swap_dirn = SD->index; + sio->mode = O_WRONLY | O_CREAT | O_TRUNC; + sio->callback = callback; + sio->callback_data = cbdataReference(callback_data); + sio->e = e; + + diskdstate->flags.writing = 0; + diskdstate->flags.reading = 0; + diskdstate->flags.close_request = 0; + diskdstate->id = diskd_stats.sio_id++; + + buf = (char *)storeDiskdShmGet(SD, &shm_offset); + xstrncpy(buf, commonUfsDirFullPath(SD, f, NULL), SHMBUF_BLKSZ); + x = storeDiskdSend(_MQD_OPEN, + SD, + diskdstate->id, + sio, + strlen(buf) + 1, + sio->mode, + shm_offset); + if (x < 0) { + debug(79, 1) ("storeDiskdSend OPEN: %s\n", xstrerror()); + storeDiskdShmPut(SD, shm_offset); + cbdataReferenceDone(sio->callback_data); + cbdataFree(sio); + return NULL; + } + commonUfsDirReplAdd(SD, e); + diskd_stats.create.ops++; + return sio; +} + + +void +storeDiskdClose(SwapDir * SD, storeIOState * sio) +{ + int x; + diskdstate_t *diskdstate = (diskdstate_t *)sio->fsstate; + debug(79, 3) ("storeDiskdClose: dirno %d, fileno %08X\n", SD->index, + sio->swap_filen); + x = storeDiskdSend(_MQD_CLOSE, + SD, + diskdstate->id, + sio, + 0, + 0, + -1); + if (x < 0) { + debug(79, 1) ("storeDiskdSend CLOSE: %s\n", xstrerror()); + storeDiskdIOCallback(sio, DISK_ERROR); + } + diskdstate->flags.close_request = 1; + diskd_stats.close.ops++; +} + +void +storeDiskdRead(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data) +{ + int x; + off_t shm_offset; + char *rbuf; + diskdstate_t *diskdstate = (diskdstate_t *)sio->fsstate; + debug(79, 3) ("storeDiskdRead: dirno %d, fileno %08X\n", sio->swap_dirn, sio->swap_filen); + assert(!diskdstate->flags.close_request); + if (!cbdataReferenceValid(sio)) + return; + if (diskdstate->flags.reading) { + debug(79, 1) ("storeDiskdRead: already reading!\n"); + return; + } + assert(sio->read.callback == NULL); + assert(sio->read.callback_data == NULL); + sio->read.callback = callback; + sio->read.callback_data = cbdataReference(callback_data); + diskdstate->read_buf = buf; /* the one passed from above */ + sio->offset = offset; + diskdstate->flags.reading = 1; + rbuf = (char *)storeDiskdShmGet(SD, &shm_offset); + assert(rbuf); + x = storeDiskdSend(_MQD_READ, + SD, + diskdstate->id, + sio, + (int) size, + (int) offset, + shm_offset); + if (x < 0) { + debug(79, 1) ("storeDiskdSend READ: %s\n", xstrerror()); + storeDiskdShmPut(SD, shm_offset); + storeDiskdIOCallback(sio, DISK_ERROR); + } + diskd_stats.read.ops++; +} + +void +storeDiskdWrite(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, FREE * free_func) +{ + int x; + char *sbuf; + off_t shm_offset; + diskdstate_t *diskdstate = (diskdstate_t *)sio->fsstate; + debug(79, 3) ("storeDiskdWrite: dirno %d, fileno %08X\n", SD->index, sio->swap_filen); + assert(!diskdstate->flags.close_request); + if (!cbdataReferenceValid(sio)) { + free_func(buf); + return; + } + diskdstate->flags.writing = 1; + sbuf = (char *)storeDiskdShmGet(SD, &shm_offset); + xmemcpy(sbuf, buf, size); + if (free_func) + free_func(buf); + x = storeDiskdSend(_MQD_WRITE, + SD, + diskdstate->id, + sio, + (int) size, + (int) offset, + shm_offset); + if (x < 0) { + debug(79, 1) ("storeDiskdSend WRITE: %s\n", xstrerror()); + storeDiskdShmPut(SD, shm_offset); + storeDiskdIOCallback(sio, DISK_ERROR); + } + diskd_stats.write.ops++; +} + +void +storeDiskdUnlink(SwapDir * SD, StoreEntry * e) +{ + int x; + off_t shm_offset; + char *buf; + diskdinfo_t *diskdinfo = (diskdinfo_t *)SD->fsdata; + + debug(79, 3) ("storeDiskdUnlink: dirno %d, fileno %08X\n", SD->index, + e->swap_filen); + commonUfsDirReplRemove(e); + commonUfsDirMapBitReset(SD, e->swap_filen); + if (diskdinfo->away >= diskdinfo->magic1) { + /* Damn, we need to issue a sync unlink here :( */ + debug(79, 2) ("storeDiskUnlink: Out of queue space, sync unlink\n"); + commonUfsDirUnlinkFile(SD, e->swap_filen); + return; + } + /* We can attempt a diskd unlink */ + buf = (char *)storeDiskdShmGet(SD, &shm_offset); + xstrncpy(buf, commonUfsDirFullPath(SD, e->swap_filen, NULL), SHMBUF_BLKSZ); + x = storeDiskdSend(_MQD_UNLINK, + SD, + e->swap_filen, + NULL, + 0, + 0, + shm_offset); + if (x < 0) { + debug(79, 1) ("storeDiskdSend UNLINK: %s\n", xstrerror()); + unlink(buf); /* XXX EWW! */ + storeDiskdShmPut(SD, shm_offset); + } + diskd_stats.unlink.ops++; +} + + +/* === STATIC =========================================================== */ + +static void +storeDiskdOpenDone(diomsg * M) +{ + storeIOState *sio = (storeIOState *)M->callback_data; + statCounter.syscalls.disk.opens++; + debug(79, 3) ("storeDiskdOpenDone: dirno %d, fileno %08x status %d\n", + sio->swap_dirn, sio->swap_filen, M->status); + if (M->status < 0) { + FILE_MODE(sio->mode) == O_RDONLY ? diskd_stats.open.fail++ : diskd_stats.create.fail++; + storeDiskdIOCallback(sio, DISK_ERROR); + } else { + FILE_MODE(sio->mode) == O_RDONLY ? diskd_stats.open.success++ : diskd_stats.create.success++; + } +} + +static void +storeDiskdCloseDone(diomsg * M) +{ + storeIOState *sio = (storeIOState *)M->callback_data; + statCounter.syscalls.disk.closes++; + debug(79, 3) ("storeDiskdCloseDone: dirno %d, fileno %08x status %d\n", + sio->swap_dirn, sio->swap_filen, M->status); + if (M->status < 0) { + diskd_stats.close.fail++; + storeDiskdIOCallback(sio, DISK_ERROR); + return; + } + diskd_stats.close.success++; + storeDiskdIOCallback(sio, DISK_OK); +} + +static void +storeDiskdReadDone(diomsg * M) +{ + storeIOState *sio = (storeIOState *)M->callback_data; + STRCB *callback = sio->read.callback; + void *cbdata; + SwapDir *sd = INDEXSD(sio->swap_dirn); + diskdstate_t *diskdstate = (diskdstate_t *)sio->fsstate; + diskdinfo_t *diskdinfo = (diskdinfo_t *)sd->fsdata; + char *their_buf = diskdstate->read_buf; + char *sbuf; + size_t len; + statCounter.syscalls.disk.reads++; + diskdstate->flags.reading = 0; + debug(79, 3) ("storeDiskdReadDone: dirno %d, fileno %08x status %d\n", + sio->swap_dirn, sio->swap_filen, M->status); + if (M->status < 0) { + diskd_stats.read.fail++; + storeDiskdIOCallback(sio, DISK_ERROR); + return; + } + diskd_stats.read.success++; + sbuf = diskdinfo->shm.buf + M->shm_offset; + len = M->status; + sio->offset += len; + assert(callback); + sio->read.callback = NULL; + if (cbdataReferenceValidDone(sio->read.callback_data, &cbdata)) { + assert(!diskdstate->flags.close_request); + /* + * Only copy the data if the callback is still valid, + * if it isn't valid then the request should have been + * aborted. + * -- adrian + */ + xmemcpy(their_buf, sbuf, len); /* yucky copy */ + callback(cbdata, their_buf, len); + } +} + +static void +storeDiskdWriteDone(diomsg * M) +{ + storeIOState *sio = (storeIOState *)M->callback_data; + diskdstate_t *diskdstate = (diskdstate_t *)sio->fsstate; + statCounter.syscalls.disk.writes++; + diskdstate->flags.writing = 0; + debug(79, 3) ("storeDiskdWriteDone: dirno %d, fileno %08x status %d\n", + sio->swap_dirn, sio->swap_filen, M->status); + if (M->status < 0) { + diskd_stats.write.fail++; + storeDiskdIOCallback(sio, DISK_ERROR); + return; + } + diskd_stats.write.success++; + sio->offset += M->status; +} + +static void +storeDiskdUnlinkDone(diomsg * M) +{ + debug(79, 3) ("storeDiskdUnlinkDone: fileno %08x status %d\n", + M->id, M->status); + statCounter.syscalls.disk.unlinks++; + if (M->status < 0) + diskd_stats.unlink.fail++; + else + diskd_stats.unlink.success++; +} + +void +storeDiskdHandle(diomsg * M) +{ + if (cbdataReferenceValid(M->callback_data)) { + switch (M->mtype) { + case _MQD_OPEN: + storeDiskdOpenDone(M); + break; + case _MQD_CLOSE: + storeDiskdCloseDone(M); + break; + case _MQD_READ: + storeDiskdReadDone(M); + break; + case _MQD_WRITE: + storeDiskdWriteDone(M); + break; + case _MQD_UNLINK: + storeDiskdUnlinkDone(M); + break; + default: + assert(0); + break; + } + } else { + debug(79, 3) ("storeDiskdHandle: Invalid callback_data %p\n", + M->callback_data); + /* + * The read operation has its own callback. If we don't + * call storeDiskdReadDone(), then we must make sure the + * callback_data gets unlocked! + */ + if (_MQD_READ == M->mtype) { + /* XXX This cannot be the correct approach. This + * is most likely the wrong place for this. It should + * be done before the sio becomes invalid, not here. + */ + storeIOState *sio = (storeIOState *)M->callback_data; + cbdataReferenceDone(sio->read.callback_data); + } + } + cbdataReferenceDone(M->callback_data); +} + +static void +storeDiskdIOCallback(storeIOState * sio, int errflag) +{ + void *cbdata; + STIOCB *callback = sio->callback; + debug(79, 3) ("storeUfsIOCallback: errflag=%d\n", errflag); + sio->callback = NULL; + if (cbdataReferenceValidDone(sio->callback_data, &cbdata)) + callback(cbdata, errflag, sio); + cbdataFree(sio); +} + +static int +storeDiskdSend(int mtype, SwapDir * sd, int id, storeIOState * sio, int size, int offset, off_t shm_offset) +{ + int x; + diomsg M; + static int send_errors = 0; + static int last_seq_no = 0; + static int seq_no = 0; + diskdinfo_t *diskdinfo = (diskdinfo_t *)sd->fsdata; + M.mtype = mtype; + M.callback_data = cbdataReference(sio); + M.size = size; + M.offset = offset; + M.status = -1; + M.shm_offset = (int) shm_offset; + M.id = id; + M.seq_no = ++seq_no; + if (M.seq_no < last_seq_no) + debug(79, 1) ("WARNING: sequencing out of order\n"); + x = msgsnd(diskdinfo->smsgid, &M, msg_snd_rcv_sz, IPC_NOWAIT); + last_seq_no = M.seq_no; + if (0 == x) { + diskd_stats.sent_count++; + diskdinfo->away++; + } else { + debug(79, 1) ("storeDiskdSend: msgsnd: %s\n", xstrerror()); + cbdataReferenceDone(M.callback_data); + assert(++send_errors < 100); + } + /* + * We have to drain the queue here if necessary. If we don't, + * then we can have a lot of messages in the queue (probably + * up to 2*magic1) and we can run out of shared memory buffers. + */ + /* + * Note that we call storeDirCallback (for all SDs), rather + * than storeDiskdDirCallback for just this SD, so that while + * we're "blocking" on this SD we can also handle callbacks + * from other SDs that might be ready. + */ + while (diskdinfo->away > diskdinfo->magic2) { + struct timeval delay = + {0, 1}; + select(0, NULL, NULL, NULL, &delay); + storeDirCallback(); + if (delay.tv_usec < 1000000) + delay.tv_usec <<= 1; + } + return x; +} + + +/* + * We can't pass memFree() as a free function here, because we need to free + * the fsstate variable .. + */ +static void +storeDiskdIOFreeEntry(void *sio) +{ + memPoolFree(diskd_state_pool, ((storeIOState *) sio)->fsstate); +} --- squid/src/fs/null/store_null.c Wed Feb 14 01:07:42 2007 +++ /dev/null Wed Feb 14 01:07:22 2007 @@ -1,131 +0,0 @@ - -/* - * $Id$ - * - * DEBUG: section 47 Store Directory Routines - * AUTHOR: Duane Wessels - * - * SQUID Web Proxy Cache http://www.squid-cache.org/ - * ---------------------------------------------------------- - * - * Squid is the result of efforts by numerous individuals from - * the Internet community; see the CONTRIBUTORS file for full - * details. Many organizations have provided support for Squid's - * development; see the SPONSORS file for full details. Squid is - * Copyrighted (C) 2001 by the Regents of the University of - * California; see the COPYRIGHT file for full details. Squid - * incorporates software developed and/or copyrighted by other - * sources; see the CREDITS file for full details. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. - * - */ - -#include "squid.h" -#if HAVE_STATVFS -#if HAVE_SYS_STATVFS_H -#include -#endif -#endif - -static int null_initialised = 0; -static void storeNullDirInit(SwapDir * sd); -static void storeNullDirStats(SwapDir * SD, StoreEntry * sentry); -static STCHECKOBJ storeNullDirCheckObj; -static STFSRECONFIGURE storeNullDirReconfigure; -static STLOGCLEANSTART storeNullDirWriteCleanStart; -static STLOGCLEANDONE storeNullDirWriteCleanDone; -static EVH storeNullDirRebuildComplete; - -/* The only externally visible interface */ -STSETUP storeFsSetup_null; - -static void -storeNullDirReconfigure(SwapDir * sd, int index, char *path) -{ - (void) 0; -} - -static void -storeNullDirDone(void) -{ - null_initialised = 0; -} - -static void -storeNullDirStats(SwapDir * SD, StoreEntry * sentry) -{ - (void) 0; -} - -static void -storeNullDirInit(SwapDir * sd) -{ - store_dirs_rebuilding++; - eventAdd("storeNullDirRebuildComplete", storeNullDirRebuildComplete, - NULL, 0.0, 1); -} - -static void -storeNullDirRebuildComplete(void *unused) -{ - struct _store_rebuild_data counts; - memset(&counts, '\0', sizeof(counts)); - store_dirs_rebuilding--; - storeRebuildComplete(&counts); -} - -static int -storeNullDirCheckObj(SwapDir * SD, const StoreEntry * e) -{ - return -1; -} - -static int -storeNullDirWriteCleanStart(SwapDir * unused) -{ - return 0; -} - -static void -storeNullDirWriteCleanDone(SwapDir * unused) -{ - (void) 0; -} - -static void -storeNullDirParse(SwapDir * sd, int index, char *path) -{ - sd->index = index; - sd->path = xstrdup(path); - sd->statfs = storeNullDirStats; - sd->init = storeNullDirInit; - sd->checkobj = storeNullDirCheckObj; - sd->log.clean.start = storeNullDirWriteCleanStart; - sd->log.clean.done = storeNullDirWriteCleanDone; - parse_cachedir_options(sd, NULL, 0); -} - -/* Setup and register the store module */ - -void -storeFsSetup_null(storefs_entry_t * storefs) -{ - assert(!null_initialised); - storefs->parsefunc = storeNullDirParse; - storefs->reconfigurefunc = storeNullDirReconfigure; - storefs->donefunc = storeNullDirDone; - null_initialised = 1; -} --- /dev/null Wed Feb 14 01:07:22 2007 +++ squid/src/fs/null/store_null.cc Wed Feb 14 01:07:42 2007 @@ -0,0 +1,131 @@ + +/* + * $Id: store_null.cc,v 1.1.2.1 2002/10/12 12:21:44 rbcollins Exp $ + * + * DEBUG: section 47 Store Directory Routines + * AUTHOR: Duane Wessels + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" +#if HAVE_STATVFS +#if HAVE_SYS_STATVFS_H +#include +#endif +#endif + +static int null_initialised = 0; +static void storeNullDirInit(SwapDir * sd); +static void storeNullDirStats(SwapDir * SD, StoreEntry * sentry); +static STCHECKOBJ storeNullDirCheckObj; +static STFSRECONFIGURE storeNullDirReconfigure; +static STLOGCLEANSTART storeNullDirWriteCleanStart; +static STLOGCLEANDONE storeNullDirWriteCleanDone; +static EVH storeNullDirRebuildComplete; + +/* The only externally visible interface */ +STSETUP storeFsSetup_null; + +static void +storeNullDirReconfigure(SwapDir * sd, int index, char *path) +{ + (void) 0; +} + +static void +storeNullDirDone(void) +{ + null_initialised = 0; +} + +static void +storeNullDirStats(SwapDir * SD, StoreEntry * sentry) +{ + (void) 0; +} + +static void +storeNullDirInit(SwapDir * sd) +{ + store_dirs_rebuilding++; + eventAdd("storeNullDirRebuildComplete", storeNullDirRebuildComplete, + NULL, 0.0, 1); +} + +static void +storeNullDirRebuildComplete(void *unused) +{ + struct _store_rebuild_data counts; + memset(&counts, '\0', sizeof(counts)); + store_dirs_rebuilding--; + storeRebuildComplete(&counts); +} + +static int +storeNullDirCheckObj(SwapDir * SD, const StoreEntry * e) +{ + return -1; +} + +static int +storeNullDirWriteCleanStart(SwapDir * unused) +{ + return 0; +} + +static void +storeNullDirWriteCleanDone(SwapDir * unused) +{ + (void) 0; +} + +static void +storeNullDirParse(SwapDir * sd, int index, char *path) +{ + sd->index = index; + sd->path = xstrdup(path); + sd->statfs = storeNullDirStats; + sd->init = storeNullDirInit; + sd->checkobj = storeNullDirCheckObj; + sd->log.clean.start = storeNullDirWriteCleanStart; + sd->log.clean.done = storeNullDirWriteCleanDone; + parse_cachedir_options(sd, NULL, 0); +} + +/* Setup and register the store module */ + +void +storeFsSetup_null(storefs_entry_t * storefs) +{ + assert(!null_initialised); + storefs->parsefunc = storeNullDirParse; + storefs->reconfigurefunc = storeNullDirReconfigure; + storefs->donefunc = storeNullDirDone; + null_initialised = 1; +} --- squid/src/fs/ufs/store_dir_ufs.c Wed Feb 14 01:07:42 2007 +++ /dev/null Wed Feb 14 01:07:22 2007 @@ -1,224 +0,0 @@ - -/* - * $Id$ - * - * DEBUG: section 47 Store Directory Routines - * AUTHOR: Duane Wessels - * - * SQUID Web Proxy Cache http://www.squid-cache.org/ - * ---------------------------------------------------------- - * - * Squid is the result of efforts by numerous individuals from - * the Internet community; see the CONTRIBUTORS file for full - * details. Many organizations have provided support for Squid's - * development; see the SPONSORS file for full details. Squid is - * Copyrighted (C) 2001 by the Regents of the University of - * California; see the COPYRIGHT file for full details. Squid - * incorporates software developed and/or copyrighted by other - * sources; see the CREDITS file for full details. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. - * - */ - -#include "squid.h" -#include "Store.h" - -#include "store_ufs.h" -#include "ufscommon.h" - -MemPool *ufs_state_pool = NULL; -static int ufs_initialised = 0; - -static STDUMP storeUfsDirDump; -static STCHECKOBJ storeUfsDirCheckObj; -static void storeUfsDirIOUnlinkFile(char *path); - -STSETUP storeFsSetup_ufs; - -/* - * storeUfsDirCheckObj - * - * This routine is called by storeDirSelectSwapDir to see if the given - * object is able to be stored on this filesystem. UFS filesystems will - * happily store anything as long as the LRU time isn't too small. - */ -int -storeUfsDirCheckObj(SwapDir * SD, const StoreEntry * e) -{ - /* Return 999 (99.9%) constant load */ - return 999; -} - -void -storeUfsDirIOUnlinkFile(char *path) -{ -#if USE_UNLINKD - unlinkdUnlink(path); -#elif USE_TRUNCATE - truncate(path, 0); -#else - unlink(path); -#endif -} - -/* ========== LOCAL FUNCTIONS ABOVE, GLOBAL FUNCTIONS BELOW ========== */ - -static struct cache_dir_option options[] = -{ -#if NOT_YET_DONE - {"L1", storeUfsDirParseL1, storeUfsDirDumpL1}, - {"L2", storeUfsDirParseL2, storeUfsDirDumpL2}, -#endif - {NULL, NULL} -}; - -/* - * storeUfsDirReconfigure - * - * This routine is called when the given swapdir needs reconfiguring - */ -static void -storeUfsDirReconfigure(SwapDir * sd, int index, char *path) -{ - int i; - int size; - int l1; - int l2; - - i = GetInteger(); - size = i << 10; /* Mbytes to kbytes */ - if (size <= 0) - fatal("storeUfsDirReconfigure: invalid size value"); - i = GetInteger(); - l1 = i; - if (l1 <= 0) - fatal("storeUfsDirReconfigure: invalid level 1 directories value"); - i = GetInteger(); - l2 = i; - if (l2 <= 0) - fatal("storeUfsDirReconfigure: invalid level 2 directories value"); - - /* just reconfigure it */ - if (size == sd->max_size) - debug(3, 1) ("Cache dir '%s' size remains unchanged at %d KB\n", - path, size); - else - debug(3, 1) ("Cache dir '%s' size changed to %d KB\n", - path, size); - sd->max_size = size; - - parse_cachedir_options(sd, options, 1); -} - -void -storeUfsDirDump(StoreEntry * entry, SwapDir * s) -{ - commonUfsDirDump (entry, s); - dump_cachedir_options(entry, options, s); -} - -/* - * storeUfsDirParse - * - * Called when a *new* fs is being setup. - */ -static void -storeUfsDirParse(SwapDir * sd, int index, char *path) -{ - int i; - int size; - int l1; - int l2; - squidufsinfo_t *ufsinfo; - - i = GetInteger(); - size = i << 10; /* Mbytes to kbytes */ - if (size <= 0) - fatal("storeUfsDirParse: invalid size value"); - i = GetInteger(); - l1 = i; - if (l1 <= 0) - fatal("storeUfsDirParse: invalid level 1 directories value"); - i = GetInteger(); - l2 = i; - if (l2 <= 0) - fatal("storeUfsDirParse: invalid level 2 directories value"); - - ufsinfo = xmalloc(sizeof(squidufsinfo_t)); - if (ufsinfo == NULL) - fatal("storeUfsDirParse: couldn't xmalloc() squidufsinfo_t!\n"); - - sd->index = index; - sd->path = xstrdup(path); - sd->max_size = size; - sd->fsdata = ufsinfo; - ufsinfo->l1 = l1; - ufsinfo->l2 = l2; - ufsinfo->swaplog_fd = -1; - ufsinfo->map = NULL; /* Debugging purposes */ - ufsinfo->suggest = 0; - ufsinfo->io.storeDirUnlinkFile = storeUfsDirIOUnlinkFile; - sd->init = commonUfsDirInit; - sd->newfs = commonUfsDirNewfs; - sd->dump = storeUfsDirDump; - sd->freefs = commonUfsDirFree; - sd->dblcheck = commonUfsCleanupDoubleCheck; - sd->statfs = commonUfsDirStats; - sd->maintainfs = commonUfsDirMaintain; - sd->checkobj = storeUfsDirCheckObj; - sd->refobj = commonUfsDirRefObj; - sd->unrefobj = commonUfsDirUnrefObj; - sd->callback = NULL; - sd->sync = NULL; - sd->obj.create = storeUfsCreate; - sd->obj.open = storeUfsOpen; - sd->obj.close = storeUfsClose; - sd->obj.read = storeUfsRead; - sd->obj.write = storeUfsWrite; - sd->obj.unlink = storeUfsUnlink; - sd->log.open = commonUfsDirOpenSwapLog; - sd->log.close = commonUfsDirCloseSwapLog; - sd->log.write = commonUfsDirSwapLog; - sd->log.clean.start = commonUfsDirWriteCleanStart; - sd->log.clean.nextentry = commonUfsDirCleanLogNextEntry; - sd->log.clean.done = commonUfsDirWriteCleanDone; - - parse_cachedir_options(sd, options, 1); - - /* Initialise replacement policy stuff */ - sd->repl = createRemovalPolicy(Config.replPolicy); -} - -/* - * Initial setup / end destruction - */ -static void -storeUfsDirDone(void) -{ - memPoolDestroy(&ufs_state_pool); - ufs_initialised = 0; -} - -void -storeFsSetup_ufs(storefs_entry_t * storefs) -{ - assert(!ufs_initialised); - storefs->parsefunc = storeUfsDirParse; - storefs->reconfigurefunc = storeUfsDirReconfigure; - storefs->donefunc = storeUfsDirDone; - ufs_state_pool = memPoolCreate("UFS IO State data", sizeof(ufsstate_t)); - ufs_initialised = 1; -} --- /dev/null Wed Feb 14 01:07:22 2007 +++ squid/src/fs/ufs/store_dir_ufs.cc Wed Feb 14 01:07:42 2007 @@ -0,0 +1,224 @@ + +/* + * $Id: store_dir_ufs.cc,v 1.1.2.1 2002/10/12 12:21:45 rbcollins Exp $ + * + * DEBUG: section 47 Store Directory Routines + * AUTHOR: Duane Wessels + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" +#include "Store.h" + +#include "store_ufs.h" +#include "ufscommon.h" + +MemPool *ufs_state_pool = NULL; +static int ufs_initialised = 0; + +static STDUMP storeUfsDirDump; +static STCHECKOBJ storeUfsDirCheckObj; +static void storeUfsDirIOUnlinkFile(char *path); + +STSETUP storeFsSetup_ufs; + +/* + * storeUfsDirCheckObj + * + * This routine is called by storeDirSelectSwapDir to see if the given + * object is able to be stored on this filesystem. UFS filesystems will + * happily store anything as long as the LRU time isn't too small. + */ +int +storeUfsDirCheckObj(SwapDir * SD, const StoreEntry * e) +{ + /* Return 999 (99.9%) constant load */ + return 999; +} + +void +storeUfsDirIOUnlinkFile(char *path) +{ +#if USE_UNLINKD + unlinkdUnlink(path); +#elif USE_TRUNCATE + truncate(path, 0); +#else + unlink(path); +#endif +} + +/* ========== LOCAL FUNCTIONS ABOVE, GLOBAL FUNCTIONS BELOW ========== */ + +static struct cache_dir_option options[] = +{ +#if NOT_YET_DONE + {"L1", storeUfsDirParseL1, storeUfsDirDumpL1}, + {"L2", storeUfsDirParseL2, storeUfsDirDumpL2}, +#endif + {NULL, NULL} +}; + +/* + * storeUfsDirReconfigure + * + * This routine is called when the given swapdir needs reconfiguring + */ +static void +storeUfsDirReconfigure(SwapDir * sd, int index, char *path) +{ + int i; + int size; + int l1; + int l2; + + i = GetInteger(); + size = i << 10; /* Mbytes to kbytes */ + if (size <= 0) + fatal("storeUfsDirReconfigure: invalid size value"); + i = GetInteger(); + l1 = i; + if (l1 <= 0) + fatal("storeUfsDirReconfigure: invalid level 1 directories value"); + i = GetInteger(); + l2 = i; + if (l2 <= 0) + fatal("storeUfsDirReconfigure: invalid level 2 directories value"); + + /* just reconfigure it */ + if (size == sd->max_size) + debug(3, 1) ("Cache dir '%s' size remains unchanged at %d KB\n", + path, size); + else + debug(3, 1) ("Cache dir '%s' size changed to %d KB\n", + path, size); + sd->max_size = size; + + parse_cachedir_options(sd, options, 1); +} + +void +storeUfsDirDump(StoreEntry * entry, SwapDir * s) +{ + commonUfsDirDump (entry, s); + dump_cachedir_options(entry, options, s); +} + +/* + * storeUfsDirParse + * + * Called when a *new* fs is being setup. + */ +static void +storeUfsDirParse(SwapDir * sd, int index, char *path) +{ + int i; + int size; + int l1; + int l2; + squidufsinfo_t *ufsinfo; + + i = GetInteger(); + size = i << 10; /* Mbytes to kbytes */ + if (size <= 0) + fatal("storeUfsDirParse: invalid size value"); + i = GetInteger(); + l1 = i; + if (l1 <= 0) + fatal("storeUfsDirParse: invalid level 1 directories value"); + i = GetInteger(); + l2 = i; + if (l2 <= 0) + fatal("storeUfsDirParse: invalid level 2 directories value"); + + ufsinfo = (squidufsinfo_t *)xmalloc(sizeof(squidufsinfo_t)); + if (ufsinfo == NULL) + fatal("storeUfsDirParse: couldn't xmalloc() squidufsinfo_t!\n"); + + sd->index = index; + sd->path = xstrdup(path); + sd->max_size = size; + sd->fsdata = ufsinfo; + ufsinfo->l1 = l1; + ufsinfo->l2 = l2; + ufsinfo->swaplog_fd = -1; + ufsinfo->map = NULL; /* Debugging purposes */ + ufsinfo->suggest = 0; + ufsinfo->io.storeDirUnlinkFile = storeUfsDirIOUnlinkFile; + sd->init = commonUfsDirInit; + sd->newfs = commonUfsDirNewfs; + sd->dump = storeUfsDirDump; + sd->freefs = commonUfsDirFree; + sd->dblcheck = commonUfsCleanupDoubleCheck; + sd->statfs = commonUfsDirStats; + sd->maintainfs = commonUfsDirMaintain; + sd->checkobj = storeUfsDirCheckObj; + sd->refobj = commonUfsDirRefObj; + sd->unrefobj = commonUfsDirUnrefObj; + sd->callback = NULL; + sd->sync = NULL; + sd->obj.create = storeUfsCreate; + sd->obj.open = storeUfsOpen; + sd->obj.close = storeUfsClose; + sd->obj.read = storeUfsRead; + sd->obj.write = storeUfsWrite; + sd->obj.unlink = storeUfsUnlink; + sd->log.open = commonUfsDirOpenSwapLog; + sd->log.close = commonUfsDirCloseSwapLog; + sd->log.write = commonUfsDirSwapLog; + sd->log.clean.start = commonUfsDirWriteCleanStart; + sd->log.clean.nextentry = commonUfsDirCleanLogNextEntry; + sd->log.clean.done = commonUfsDirWriteCleanDone; + + parse_cachedir_options(sd, options, 1); + + /* Initialise replacement policy stuff */ + sd->repl = createRemovalPolicy(Config.replPolicy); +} + +/* + * Initial setup / end destruction + */ +static void +storeUfsDirDone(void) +{ + memPoolDestroy(&ufs_state_pool); + ufs_initialised = 0; +} + +void +storeFsSetup_ufs(storefs_entry_t * storefs) +{ + assert(!ufs_initialised); + storefs->parsefunc = storeUfsDirParse; + storefs->reconfigurefunc = storeUfsDirReconfigure; + storefs->donefunc = storeUfsDirDone; + ufs_state_pool = memPoolCreate("UFS IO State data", sizeof(ufsstate_t)); + ufs_initialised = 1; +} --- squid/src/fs/ufs/store_io_ufs.c Wed Feb 14 01:07:42 2007 +++ /dev/null Wed Feb 14 01:07:22 2007 @@ -1,265 +0,0 @@ - -/* - * $Id$ - * - * DEBUG: section 79 Storage Manager UFS Interface - * AUTHOR: Duane Wessels - * - * SQUID Web Proxy Cache http://www.squid-cache.org/ - * ---------------------------------------------------------- - * - * Squid is the result of efforts by numerous individuals from - * the Internet community; see the CONTRIBUTORS file for full - * details. Many organizations have provided support for Squid's - * development; see the SPONSORS file for full details. Squid is - * Copyrighted (C) 2001 by the Regents of the University of - * California; see the COPYRIGHT file for full details. Squid - * incorporates software developed and/or copyrighted by other - * sources; see the CREDITS file for full details. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. - * - */ - -#include "squid.h" -#include "store_ufs.h" -#include "Store.h" -#include "ufscommon.h" - - -static DRCB storeUfsReadDone; -static DWCB storeUfsWriteDone; -static void storeUfsIOCallback(storeIOState * sio, int errflag); -static CBDUNL storeUfsIOFreeEntry; - -CBDATA_TYPE(storeIOState); - -/* === PUBLIC =========================================================== */ - -storeIOState * -storeUfsOpen(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, - STIOCB * callback, void *callback_data) -{ - sfileno f = e->swap_filen; - char *path = commonUfsDirFullPath(SD, f, NULL); - storeIOState *sio; - struct stat sb; - int fd; - debug(79, 3) ("storeUfsOpen: fileno %08X\n", f); - fd = file_open(path, O_RDONLY | O_BINARY); - if (fd < 0) { - debug(79, 3) ("storeUfsOpen: got failure (%d)\n", errno); - return NULL; - } - debug(79, 3) ("storeUfsOpen: opened FD %d\n", fd); - CBDATA_INIT_TYPE_FREECB(storeIOState, storeUfsIOFreeEntry); - sio = cbdataAlloc(storeIOState); - sio->fsstate = memPoolAlloc(ufs_state_pool); - - sio->swap_filen = f; - sio->swap_dirn = SD->index; - sio->mode = O_RDONLY | O_BINARY; - sio->callback = callback; - sio->callback_data = cbdataReference(callback_data); - sio->e = e; - ((ufsstate_t *) (sio->fsstate))->fd = fd; - ((ufsstate_t *) (sio->fsstate))->flags.writing = 0; - ((ufsstate_t *) (sio->fsstate))->flags.reading = 0; - ((ufsstate_t *) (sio->fsstate))->flags.close_request = 0; - if (fstat(fd, &sb) == 0) - sio->st_size = sb.st_size; - store_open_disk_fd++; - - /* We should update the heap/dlink position here ! */ - return sio; -} - -storeIOState * -storeUfsCreate(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, STIOCB * callback, void *callback_data) -{ - storeIOState *sio; - int fd; - int mode = (O_WRONLY | O_CREAT | O_TRUNC | O_BINARY); - char *path; - squidufsinfo_t *ufsinfo = (squidufsinfo_t *) SD->fsdata; - sfileno filn; - sdirno dirn; - - /* Allocate a number */ - dirn = SD->index; - filn = commonUfsDirMapBitAllocate(SD); - ufsinfo->suggest = filn + 1; - /* Shouldn't we handle a 'bitmap full' error here? */ - path = commonUfsDirFullPath(SD, filn, NULL); - - debug(79, 3) ("storeUfsCreate: fileno %08X\n", filn); - fd = file_open(path, mode); - if (fd < 0) { - debug(79, 3) ("storeUfsCreate: got failure (%d)\n", errno); - return NULL; - } - debug(79, 3) ("storeUfsCreate: opened FD %d\n", fd); - CBDATA_INIT_TYPE_FREECB(storeIOState, storeUfsIOFreeEntry); - sio = cbdataAlloc(storeIOState); - sio->fsstate = memPoolAlloc(ufs_state_pool); - - sio->swap_filen = filn; - sio->swap_dirn = dirn; - sio->mode = mode; - sio->callback = callback; - sio->callback_data = cbdataReference(callback_data); - sio->e = (StoreEntry *) e; - ((ufsstate_t *) (sio->fsstate))->fd = fd; - ((ufsstate_t *) (sio->fsstate))->flags.writing = 0; - ((ufsstate_t *) (sio->fsstate))->flags.reading = 0; - ((ufsstate_t *) (sio->fsstate))->flags.close_request = 0; - store_open_disk_fd++; - - /* now insert into the replacement policy */ - commonUfsDirReplAdd(SD, e); - return sio; -} - -void -storeUfsClose(SwapDir * SD, storeIOState * sio) -{ - ufsstate_t *ufsstate = (ufsstate_t *) sio->fsstate; - - debug(79, 3) ("storeUfsClose: dirno %d, fileno %08X, FD %d\n", - sio->swap_dirn, sio->swap_filen, ufsstate->fd); - if (ufsstate->flags.reading || ufsstate->flags.writing) { - ufsstate->flags.close_request = 1; - return; - } - storeUfsIOCallback(sio, 0); -} - -void -storeUfsRead(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data) -{ - ufsstate_t *ufsstate = (ufsstate_t *) sio->fsstate; - - assert(sio->read.callback == NULL); - assert(sio->read.callback_data == NULL); - sio->read.callback = callback; - sio->read.callback_data = cbdataReference(callback_data); - debug(79, 3) ("storeUfsRead: dirno %d, fileno %08X, FD %d\n", - sio->swap_dirn, sio->swap_filen, ufsstate->fd); - sio->offset = offset; - ufsstate->flags.reading = 1; - file_read(ufsstate->fd, - buf, - size, - offset, - storeUfsReadDone, - sio); -} - -void -storeUfsWrite(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, FREE * free_func) -{ - ufsstate_t *ufsstate = (ufsstate_t *) sio->fsstate; - debug(79, 3) ("storeUfsWrite: dirn %d, fileno %08X, FD %d\n", sio->swap_dirn, sio->swap_filen, ufsstate->fd); - ufsstate->flags.writing = 1; - file_write(ufsstate->fd, - offset, - buf, - size, - storeUfsWriteDone, - sio, - free_func); -} - -void -storeUfsUnlink(SwapDir * SD, StoreEntry * e) -{ - debug(79, 3) ("storeUfsUnlink: fileno %08X\n", e->swap_filen); - commonUfsDirReplRemove(e); - commonUfsDirMapBitReset(SD, e->swap_filen); - commonUfsDirUnlinkFile(SD, e->swap_filen); -} - -/* === STATIC =========================================================== */ - -static void -storeUfsReadDone(int fd, const char *buf, int len, int errflag, void *my_data) -{ - storeIOState *sio = my_data; - ufsstate_t *ufsstate = (ufsstate_t *) sio->fsstate; - STRCB *callback; - void *cbdata; - ssize_t rlen; - - debug(79, 3) ("storeUfsReadDone: dirno %d, fileno %08X, FD %d, len %d\n", - sio->swap_dirn, sio->swap_filen, fd, len); - ufsstate->flags.reading = 0; - if (errflag) { - debug(79, 3) ("storeUfsReadDone: got failure (%d)\n", errflag); - rlen = -1; - } else { - rlen = (ssize_t) len; - sio->offset += len; - } - assert(sio->read.callback); - assert(sio->read.callback_data); - callback = sio->read.callback; - sio->read.callback = NULL; - if (cbdataReferenceValidDone(sio->read.callback_data, &cbdata)) - callback(cbdata, buf, (size_t) rlen); -} - -static void -storeUfsWriteDone(int fd, int errflag, size_t len, void *my_data) -{ - storeIOState *sio = my_data; - ufsstate_t *ufsstate = (ufsstate_t *) sio->fsstate; - debug(79, 3) ("storeUfsWriteDone: dirno %d, fileno %08X, FD %d, len %ld\n", - sio->swap_dirn, sio->swap_filen, fd, (long int) len); - ufsstate->flags.writing = 0; - if (errflag) { - debug(79, 0) ("storeUfsWriteDone: got failure (%d)\n", errflag); - storeUfsIOCallback(sio, errflag); - return; - } - sio->offset += len; - if (ufsstate->flags.close_request) - storeUfsIOCallback(sio, errflag); -} - -static void -storeUfsIOCallback(storeIOState * sio, int errflag) -{ - ufsstate_t *ufsstate = (ufsstate_t *) sio->fsstate; - void *cbdata; - debug(79, 3) ("storeUfsIOCallback: errflag=%d\n", errflag); - if (ufsstate->fd > -1) { - file_close(ufsstate->fd); - store_open_disk_fd--; - } - if (cbdataReferenceValidDone(sio->callback_data, &cbdata)) - sio->callback(cbdata, errflag, sio); - sio->callback = NULL; - cbdataFree(sio); -} - - -/* - * Clean up any references from the SIO before it get's released. - */ -static void -storeUfsIOFreeEntry(void *sio) -{ - memPoolFree(ufs_state_pool, ((storeIOState *) sio)->fsstate); -} --- /dev/null Wed Feb 14 01:07:22 2007 +++ squid/src/fs/ufs/store_io_ufs.cc Wed Feb 14 01:07:42 2007 @@ -0,0 +1,265 @@ + +/* + * $Id: store_io_ufs.cc,v 1.1.2.1 2002/10/12 12:21:45 rbcollins Exp $ + * + * DEBUG: section 79 Storage Manager UFS Interface + * AUTHOR: Duane Wessels + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" +#include "store_ufs.h" +#include "Store.h" +#include "ufscommon.h" + + +static DRCB storeUfsReadDone; +static DWCB storeUfsWriteDone; +static void storeUfsIOCallback(storeIOState * sio, int errflag); +static CBDUNL storeUfsIOFreeEntry; + +CBDATA_TYPE(storeIOState); + +/* === PUBLIC =========================================================== */ + +storeIOState * +storeUfsOpen(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, + STIOCB * callback, void *callback_data) +{ + sfileno f = e->swap_filen; + char *path = commonUfsDirFullPath(SD, f, NULL); + storeIOState *sio; + struct stat sb; + int fd; + debug(79, 3) ("storeUfsOpen: fileno %08X\n", f); + fd = file_open(path, O_RDONLY | O_BINARY); + if (fd < 0) { + debug(79, 3) ("storeUfsOpen: got failure (%d)\n", errno); + return NULL; + } + debug(79, 3) ("storeUfsOpen: opened FD %d\n", fd); + CBDATA_INIT_TYPE_FREECB(storeIOState, storeUfsIOFreeEntry); + sio = cbdataAlloc(storeIOState); + sio->fsstate = memPoolAlloc(ufs_state_pool); + + sio->swap_filen = f; + sio->swap_dirn = SD->index; + sio->mode = O_RDONLY | O_BINARY; + sio->callback = callback; + sio->callback_data = cbdataReference(callback_data); + sio->e = e; + ((ufsstate_t *) (sio->fsstate))->fd = fd; + ((ufsstate_t *) (sio->fsstate))->flags.writing = 0; + ((ufsstate_t *) (sio->fsstate))->flags.reading = 0; + ((ufsstate_t *) (sio->fsstate))->flags.close_request = 0; + if (fstat(fd, &sb) == 0) + sio->st_size = sb.st_size; + store_open_disk_fd++; + + /* We should update the heap/dlink position here ! */ + return sio; +} + +storeIOState * +storeUfsCreate(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, STIOCB * callback, void *callback_data) +{ + storeIOState *sio; + int fd; + int mode = (O_WRONLY | O_CREAT | O_TRUNC | O_BINARY); + char *path; + squidufsinfo_t *ufsinfo = (squidufsinfo_t *) SD->fsdata; + sfileno filn; + sdirno dirn; + + /* Allocate a number */ + dirn = SD->index; + filn = commonUfsDirMapBitAllocate(SD); + ufsinfo->suggest = filn + 1; + /* Shouldn't we handle a 'bitmap full' error here? */ + path = commonUfsDirFullPath(SD, filn, NULL); + + debug(79, 3) ("storeUfsCreate: fileno %08X\n", filn); + fd = file_open(path, mode); + if (fd < 0) { + debug(79, 3) ("storeUfsCreate: got failure (%d)\n", errno); + return NULL; + } + debug(79, 3) ("storeUfsCreate: opened FD %d\n", fd); + CBDATA_INIT_TYPE_FREECB(storeIOState, storeUfsIOFreeEntry); + sio = cbdataAlloc(storeIOState); + sio->fsstate = memPoolAlloc(ufs_state_pool); + + sio->swap_filen = filn; + sio->swap_dirn = dirn; + sio->mode = mode; + sio->callback = callback; + sio->callback_data = cbdataReference(callback_data); + sio->e = (StoreEntry *) e; + ((ufsstate_t *) (sio->fsstate))->fd = fd; + ((ufsstate_t *) (sio->fsstate))->flags.writing = 0; + ((ufsstate_t *) (sio->fsstate))->flags.reading = 0; + ((ufsstate_t *) (sio->fsstate))->flags.close_request = 0; + store_open_disk_fd++; + + /* now insert into the replacement policy */ + commonUfsDirReplAdd(SD, e); + return sio; +} + +void +storeUfsClose(SwapDir * SD, storeIOState * sio) +{ + ufsstate_t *ufsstate = (ufsstate_t *) sio->fsstate; + + debug(79, 3) ("storeUfsClose: dirno %d, fileno %08X, FD %d\n", + sio->swap_dirn, sio->swap_filen, ufsstate->fd); + if (ufsstate->flags.reading || ufsstate->flags.writing) { + ufsstate->flags.close_request = 1; + return; + } + storeUfsIOCallback(sio, 0); +} + +void +storeUfsRead(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data) +{ + ufsstate_t *ufsstate = (ufsstate_t *) sio->fsstate; + + assert(sio->read.callback == NULL); + assert(sio->read.callback_data == NULL); + sio->read.callback = callback; + sio->read.callback_data = cbdataReference(callback_data); + debug(79, 3) ("storeUfsRead: dirno %d, fileno %08X, FD %d\n", + sio->swap_dirn, sio->swap_filen, ufsstate->fd); + sio->offset = offset; + ufsstate->flags.reading = 1; + file_read(ufsstate->fd, + buf, + size, + offset, + storeUfsReadDone, + sio); +} + +void +storeUfsWrite(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, FREE * free_func) +{ + ufsstate_t *ufsstate = (ufsstate_t *) sio->fsstate; + debug(79, 3) ("storeUfsWrite: dirn %d, fileno %08X, FD %d\n", sio->swap_dirn, sio->swap_filen, ufsstate->fd); + ufsstate->flags.writing = 1; + file_write(ufsstate->fd, + offset, + buf, + size, + storeUfsWriteDone, + sio, + free_func); +} + +void +storeUfsUnlink(SwapDir * SD, StoreEntry * e) +{ + debug(79, 3) ("storeUfsUnlink: fileno %08X\n", e->swap_filen); + commonUfsDirReplRemove(e); + commonUfsDirMapBitReset(SD, e->swap_filen); + commonUfsDirUnlinkFile(SD, e->swap_filen); +} + +/* === STATIC =========================================================== */ + +static void +storeUfsReadDone(int fd, const char *buf, int len, int errflag, void *my_data) +{ + storeIOState *sio = (storeIOState *)my_data; + ufsstate_t *ufsstate = (ufsstate_t *) sio->fsstate; + STRCB *callback; + void *cbdata; + ssize_t rlen; + + debug(79, 3) ("storeUfsReadDone: dirno %d, fileno %08X, FD %d, len %d\n", + sio->swap_dirn, sio->swap_filen, fd, len); + ufsstate->flags.reading = 0; + if (errflag) { + debug(79, 3) ("storeUfsReadDone: got failure (%d)\n", errflag); + rlen = -1; + } else { + rlen = (ssize_t) len; + sio->offset += len; + } + assert(sio->read.callback); + assert(sio->read.callback_data); + callback = sio->read.callback; + sio->read.callback = NULL; + if (cbdataReferenceValidDone(sio->read.callback_data, &cbdata)) + callback(cbdata, buf, (size_t) rlen); +} + +static void +storeUfsWriteDone(int fd, int errflag, size_t len, void *my_data) +{ + storeIOState *sio = (storeIOState *)my_data; + ufsstate_t *ufsstate = (ufsstate_t *) sio->fsstate; + debug(79, 3) ("storeUfsWriteDone: dirno %d, fileno %08X, FD %d, len %ld\n", + sio->swap_dirn, sio->swap_filen, fd, (long int) len); + ufsstate->flags.writing = 0; + if (errflag) { + debug(79, 0) ("storeUfsWriteDone: got failure (%d)\n", errflag); + storeUfsIOCallback(sio, errflag); + return; + } + sio->offset += len; + if (ufsstate->flags.close_request) + storeUfsIOCallback(sio, errflag); +} + +static void +storeUfsIOCallback(storeIOState * sio, int errflag) +{ + ufsstate_t *ufsstate = (ufsstate_t *) sio->fsstate; + void *cbdata; + debug(79, 3) ("storeUfsIOCallback: errflag=%d\n", errflag); + if (ufsstate->fd > -1) { + file_close(ufsstate->fd); + store_open_disk_fd--; + } + if (cbdataReferenceValidDone(sio->callback_data, &cbdata)) + sio->callback(cbdata, errflag, sio); + sio->callback = NULL; + cbdataFree(sio); +} + + +/* + * Clean up any references from the SIO before it get's released. + */ +static void +storeUfsIOFreeEntry(void *sio) +{ + memPoolFree(ufs_state_pool, ((storeIOState *) sio)->fsstate); +}