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

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: store_swapout.c,v 1.46 1999/01/29 17:36:37 wessels Exp $
  3.  *
  4.  * DEBUG: section 20    Storage Manager Swapout Functions
  5.  * AUTHOR: Duane Wessels
  6.  *
  7.  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
  8.  * ----------------------------------------------------------
  9.  *
  10.  *  Squid is the result of efforts by numerous individuals from the
  11.  *  Internet community.  Development is led by Duane Wessels of the
  12.  *  National Laboratory for Applied Network Research and funded by the
  13.  *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
  14.  *  Duane Wessels and the University of California San Diego.  Please
  15.  *  see the COPYRIGHT file for full details.  Squid incorporates
  16.  *  software developed and/or copyrighted by other sources.  Please see
  17.  *  the CREDITS file for full details.
  18.  *
  19.  *  This program is free software; you can redistribute it and/or modify
  20.  *  it under the terms of the GNU General Public License as published by
  21.  *  the Free Software Foundation; either version 2 of the License, or
  22.  *  (at your option) any later version.
  23.  *  
  24.  *  This program is distributed in the hope that it will be useful,
  25.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  26.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27.  *  GNU General Public License for more details.
  28.  *  
  29.  *  You should have received a copy of the GNU General Public License
  30.  *  along with this program; if not, write to the Free Software
  31.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  32.  *
  33.  */
  34. #include "squid.h"
  35. typedef struct swapout_ctrl_t {
  36.     char *swapfilename;
  37.     int oldswapstatus;
  38.     StoreEntry *e;
  39. } swapout_ctrl_t;
  40. static FOCB storeSwapOutFileOpened;
  41. static off_t storeSwapOutObjectBytesOnDisk(const MemObject *);
  42. static void storeSwapOutStart(StoreEntry * e);
  43. static DWCB storeSwapOutHandle;
  44. /* start swapping object to disk */
  45. static void
  46. storeSwapOutStart(StoreEntry * e)
  47. {
  48.     swapout_ctrl_t *ctrlp = xmalloc(sizeof(swapout_ctrl_t));
  49.     assert(e->mem_obj);
  50.     cbdataAdd(ctrlp, cbdataXfree, 0);
  51.     storeLockObject(e);
  52.     e->swap_file_number = storeDirMapAllocate();
  53.     ctrlp->swapfilename = xstrdup(storeSwapFullPath(e->swap_file_number, NULL));
  54.     ctrlp->e = e;
  55.     ctrlp->oldswapstatus = e->swap_status;
  56.     e->swap_status = SWAPOUT_OPENING;
  57.     e->mem_obj->swapout.ctrl = ctrlp;
  58.     store_open_disk_fd++;
  59.     file_open(ctrlp->swapfilename,
  60. O_WRONLY | O_CREAT | O_TRUNC,
  61. storeSwapOutFileOpened,
  62. ctrlp,
  63. e);
  64. }
  65. static void
  66. storeSwapOutHandle(int fdnotused, int flag, size_t len, void *data)
  67. {
  68.     swapout_ctrl_t *ctrlp = data;
  69.     StoreEntry *e = ctrlp->e;
  70.     MemObject *mem = e->mem_obj;
  71.     debug(20, 3) ("storeSwapOutHandle: '%s', len=%dn", storeKeyText(e->key), (int) len);
  72.     if (flag < 0) {
  73. debug(20, 1) ("storeSwapOutHandle: SwapOut failure (err code = %d).n",
  74.     flag);
  75. e->swap_status = SWAPOUT_NONE;
  76. if (e->swap_file_number > -1) {
  77.     storeUnlinkFileno(e->swap_file_number);
  78.     storeDirMapBitReset(e->swap_file_number);
  79.     if (flag == DISK_NO_SPACE_LEFT) {
  80. storeDirDiskFull(e->swap_file_number);
  81. storeDirConfigure();
  82. storeConfigure();
  83.     }
  84.     e->swap_file_number = -1;
  85. }
  86. storeReleaseRequest(e);
  87. storeSwapOutFileClose(e);
  88. return;
  89.     }
  90. #if USE_ASYNC_IO
  91.     if (mem == NULL) {
  92. debug(20, 1) ("storeSwapOutHandle: mem == NULL : Cancelling swapoutn");
  93. return;
  94.     }
  95. #else
  96.     assert(mem != NULL);
  97. #endif
  98.     assert(mem->swap_hdr_sz != 0);
  99.     mem->swapout.done_offset += len;
  100.     if (e->store_status == STORE_PENDING) {
  101. storeCheckSwapOut(e);
  102. return;
  103.     } else if (mem->swapout.done_offset < objectLen(e) + mem->swap_hdr_sz) {
  104. storeCheckSwapOut(e);
  105. return;
  106.     }
  107.     /* swapping complete */
  108.     debug(20, 5) ("storeSwapOutHandle: SwapOut complete: '%s' to %s.n",
  109. storeUrl(e), storeSwapFullPath(e->swap_file_number, NULL));
  110.     e->swap_file_sz = objectLen(e) + mem->swap_hdr_sz;
  111.     e->swap_status = SWAPOUT_DONE;
  112.     storeDirUpdateSwapSize(e->swap_file_number, e->swap_file_sz, 1);
  113.     if (storeCheckCachable(e)) {
  114. storeLog(STORE_LOG_SWAPOUT, e);
  115. storeDirSwapLog(e, SWAP_LOG_ADD);
  116.     }
  117.     /* Note, we don't otherwise call storeReleaseRequest() here because
  118.      * storeCheckCachable() does it for is if necessary */
  119.     storeSwapOutFileClose(e);
  120. }
  121. void
  122. storeCheckSwapOut(StoreEntry * e)
  123. {
  124.     MemObject *mem = e->mem_obj;
  125.     off_t lowest_offset;
  126.     off_t new_mem_lo;
  127.     off_t on_disk;
  128.     size_t swapout_size;
  129.     char *swap_buf;
  130.     ssize_t swap_buf_len;
  131.     int hdr_len = 0;
  132.     if (mem == NULL)
  133. return;
  134.     /* should we swap something out to disk? */
  135.     debug(20, 7) ("storeCheckSwapOut: %sn", storeUrl(e));
  136.     debug(20, 7) ("storeCheckSwapOut: store_status = %sn",
  137. storeStatusStr[e->store_status]);
  138.     if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
  139. assert(EBIT_TEST(e->flags, RELEASE_REQUEST));
  140. storeSwapOutFileClose(e);
  141. return;
  142.     }
  143.     debug(20, 7) ("storeCheckSwapOut: mem->inmem_lo = %dn",
  144. (int) mem->inmem_lo);
  145.     debug(20, 7) ("storeCheckSwapOut: mem->inmem_hi = %dn",
  146. (int) mem->inmem_hi);
  147.     debug(20, 7) ("storeCheckSwapOut: swapout.queue_offset = %dn",
  148. (int) mem->swapout.queue_offset);
  149.     debug(20, 7) ("storeCheckSwapOut: swapout.done_offset = %dn",
  150. (int) mem->swapout.done_offset);
  151. #if USE_ASYNC_IO
  152.     if (mem->inmem_hi < mem->swapout.queue_offset) {
  153. storeAbort(e);
  154. assert(EBIT_TEST(e->flags, RELEASE_REQUEST));
  155. storeSwapOutFileClose(e);
  156. return;
  157.     }
  158. #else
  159.     assert(mem->inmem_hi >= mem->swapout.queue_offset);
  160. #endif
  161.     lowest_offset = storeLowestMemReaderOffset(e);
  162.     debug(20, 7) ("storeCheckSwapOut: lowest_offset = %dn",
  163. (int) lowest_offset);
  164.     new_mem_lo = lowest_offset;
  165.     assert(new_mem_lo >= mem->inmem_lo);
  166.     /*
  167.      * We should only free up to what we know has been written to
  168.      * disk, not what has been queued for writing.  Otherwise there
  169.      * will be a chunk of the data which is not in memory and is
  170.      * not yet on disk.
  171.      */
  172.     if (storeSwapOutAble(e))
  173. if ((on_disk = storeSwapOutObjectBytesOnDisk(mem)) < new_mem_lo)
  174.     new_mem_lo = on_disk;
  175.     stmemFreeDataUpto(&mem->data_hdr, new_mem_lo);
  176.     mem->inmem_lo = new_mem_lo;
  177.     if (e->swap_status == SWAPOUT_WRITING)
  178. assert(mem->inmem_lo <= mem->swapout.done_offset);
  179.     if (!storeSwapOutAble(e))
  180. return;
  181.     swapout_size = (size_t) (mem->inmem_hi - mem->swapout.queue_offset);
  182.     debug(20, 7) ("storeCheckSwapOut: swapout_size = %dn",
  183. (int) swapout_size);
  184.     if (swapout_size == 0) {
  185. if (e->store_status == STORE_OK && !storeSwapOutWriteQueued(mem)) {
  186.     debug(20, 7) ("storeCheckSwapOut: nothing to write for STORE_OKn");
  187.     if (e->swap_file_number > -1) {
  188. storeUnlinkFileno(e->swap_file_number);
  189. storeDirMapBitReset(e->swap_file_number);
  190. e->swap_file_number = -1;
  191.     }
  192.     e->swap_status = SWAPOUT_NONE;
  193.     storeReleaseRequest(e);
  194.     storeSwapOutFileClose(e);
  195. }
  196. return;
  197.     }
  198.     if (e->store_status == STORE_PENDING) {
  199. /* wait for a full block to write */
  200. if (swapout_size < VM_WINDOW_SZ)
  201.     return;
  202. /*
  203.  * Wait until we are below the disk FD limit, only if the
  204.  * next server-side read won't be deferred.
  205.  */
  206. if (storeTooManyDiskFilesOpen() && !fwdCheckDeferRead(-1, e))
  207.     return;
  208.     }
  209.     /* Ok, we have stuff to swap out.  Is there a swapout.fd open? */
  210.     if (e->swap_status == SWAPOUT_NONE) {
  211. assert(mem->swapout.fd == -1);
  212. assert(mem->inmem_lo == 0);
  213. if (storeCheckCachable(e))
  214.     storeSwapOutStart(e);
  215. /* else ENTRY_CACHABLE will be cleared and we'll never get
  216.  * here again */
  217. return;
  218.     }
  219.     if (e->swap_status == SWAPOUT_OPENING)
  220. return;
  221.     assert(mem->swapout.fd > -1);
  222.     if (swapout_size > STORE_SWAP_BUF)
  223. swapout_size = STORE_SWAP_BUF;
  224.     swap_buf = memAllocate(MEM_DISK_BUF);
  225.     swap_buf_len = stmemCopy(&mem->data_hdr,
  226. mem->swapout.queue_offset,
  227. swap_buf,
  228. swapout_size);
  229.     if (swap_buf_len < 0) {
  230. debug(20, 1) ("stmemCopy returned %d for '%s'n", swap_buf_len, storeKeyText(e->key));
  231. storeUnlinkFileno(e->swap_file_number);
  232. storeDirMapBitReset(e->swap_file_number);
  233. e->swap_file_number = -1;
  234. e->swap_status = SWAPOUT_NONE;
  235. memFree(swap_buf, MEM_DISK_BUF);
  236. storeReleaseRequest(e);
  237. storeSwapOutFileClose(e);
  238. return;
  239.     }
  240.     debug(20, 3) ("storeCheckSwapOut: swap_buf_len = %dn", (int) swap_buf_len);
  241.     assert(swap_buf_len > 0);
  242.     debug(20, 3) ("storeCheckSwapOut: swapping out %d bytes from %dn",
  243. swap_buf_len, (int) mem->swapout.queue_offset);
  244.     mem->swapout.queue_offset += swap_buf_len - hdr_len;
  245.     file_write(mem->swapout.fd,
  246. -1,
  247. swap_buf,
  248. swap_buf_len,
  249. storeSwapOutHandle,
  250. mem->swapout.ctrl,
  251. memFreeDISK);
  252. }
  253. void
  254. storeSwapOutFileClose(StoreEntry * e)
  255. {
  256.     MemObject *mem = e->mem_obj;
  257.     swapout_ctrl_t *ctrlp;
  258.     assert(mem != NULL);
  259.     debug(20, 3) ("storeSwapOutFileClose: %sn", storeKeyText(e->key));
  260.     if (mem->swapout.fd < 0) {
  261. #if USE_ASYNC_IO
  262. aioCancel(-1, e); /* Make doubly certain pending ops are gone */
  263. #endif
  264. return;
  265.     }
  266.     ctrlp = mem->swapout.ctrl;
  267.     file_close(mem->swapout.fd);
  268.     store_open_disk_fd--;
  269.     mem->swapout.fd = -1;
  270.     xfree(ctrlp->swapfilename);
  271.     cbdataFree(ctrlp);
  272.     mem->swapout.ctrl = NULL;
  273.     storeUnlockObject(e);
  274. }
  275. static void
  276. storeSwapOutFileOpened(void *data, int fd, int errcode)
  277. {
  278.     swapout_ctrl_t *ctrlp = data;
  279.     StoreEntry *e = ctrlp->e;
  280.     MemObject *mem = e->mem_obj;
  281.     int swap_hdr_sz = 0;
  282.     tlv *tlv_list;
  283.     char *buf;
  284.     if (fd == -2 && errcode == -2) { /* Cancelled - Clean up */
  285. xfree(ctrlp->swapfilename);
  286. cbdataFree(ctrlp);
  287. mem->swapout.ctrl = NULL;
  288. store_open_disk_fd--;
  289. return;
  290.     }
  291.     assert(e->swap_status == SWAPOUT_OPENING);
  292.     if (fd < 0) {
  293. debug(20, 0) ("storeSwapOutFileOpened: Unable to open swapfile: %snt%sn",
  294.     ctrlp->swapfilename, xstrerror());
  295. /*
  296.  * yuck.  don't clear the filemap bit for some errors so that
  297.  * we don't try re-using it over and over
  298.  */
  299. if (errno != EPERM)
  300.     storeDirMapBitReset(e->swap_file_number);
  301. e->swap_file_number = -1;
  302. e->swap_status = ctrlp->oldswapstatus;
  303. xfree(ctrlp->swapfilename);
  304. cbdataFree(ctrlp);
  305. mem->swapout.ctrl = NULL;
  306. store_open_disk_fd--;
  307. return;
  308.     }
  309.     mem->swapout.fd = (short) fd;
  310.     e->swap_status = SWAPOUT_WRITING;
  311.     debug(20, 5) ("storeSwapOutFileOpened: Begin SwapOut '%s' to FD %d '%s'n",
  312. storeUrl(e), fd, ctrlp->swapfilename);
  313.     debug(20, 5) ("swap_file_number=%08Xn", e->swap_file_number);
  314.     tlv_list = storeSwapMetaBuild(e);
  315.     buf = storeSwapMetaPack(tlv_list, &swap_hdr_sz);
  316.     storeSwapTLVFree(tlv_list);
  317.     mem->swap_hdr_sz = (size_t) swap_hdr_sz;
  318.     file_write(mem->swapout.fd,
  319. -1,
  320. buf,
  321. mem->swap_hdr_sz,
  322. storeSwapOutHandle,
  323. ctrlp,
  324. xfree);
  325. }
  326. /*
  327.  * Return 1 if we have some data queued.  If there is no data queued,
  328.  * then 'done_offset' equals 'queued_offset' + 'swap_hdr_sz'
  329.  *
  330.  * done_offset represents data written to disk (including the swap meta
  331.  * header), but queued_offset is relative to the in-memory data, and
  332.  * does not include the meta header.
  333.  */
  334. int
  335. storeSwapOutWriteQueued(MemObject * mem)
  336. {
  337.     /*
  338.      * this function doesn't get called much, so I'm using
  339.      * local variables to improve readability.  pphhbbht.
  340.      */
  341.     off_t queued = mem->swapout.queue_offset;
  342.     off_t done = mem->swapout.done_offset;
  343.     size_t hdr = mem->swap_hdr_sz;
  344.     assert(queued + hdr >= done);
  345.     return (queued + hdr > done);
  346. }
  347. /*
  348.  * How much of the object data is on the disk?
  349.  */
  350. static off_t
  351. storeSwapOutObjectBytesOnDisk(const MemObject * mem)
  352. {
  353.     /*
  354.      * NOTE: done_offset represents the disk file size,
  355.      * not the amount of object data on disk.
  356.      * 
  357.      * If we don't have at least 'swap_hdr_sz' bytes
  358.      * then none of the object data is on disk.
  359.      *
  360.      * This should still be safe if swap_hdr_sz == 0,
  361.      * meaning we haven't even opened the swapout file
  362.      * yet.
  363.      */
  364.     if (mem->swapout.done_offset <= mem->swap_hdr_sz)
  365. return 0;
  366.     return mem->swapout.done_offset - mem->swap_hdr_sz;
  367. }
  368. /*
  369.  * Is this entry a candidate for writing to disk?
  370.  */
  371. int
  372. storeSwapOutAble(const StoreEntry * e)
  373. {
  374.     store_client *sc;
  375.     if (e->swap_status == SWAPOUT_OPENING)
  376. return 1;
  377.     if (e->mem_obj->swapout.fd > -1)
  378. return 1;
  379.     if (e->mem_obj->inmem_lo > 0)
  380. return 0;
  381.     /* swapout.fd == -1 && inmem_lo == 0 */
  382.     /*
  383.      * If there are DISK clients, we must write to disk
  384.      * even if its not cachable
  385.      */
  386.     for (sc = e->mem_obj->clients; sc; sc = sc->next)
  387. if (sc->type == STORE_DISK_CLIENT)
  388.     return 1;
  389.     return EBIT_TEST(e->flags, ENTRY_CACHABLE);
  390. }