]> git.ipfire.org Git - thirdparty/squid.git/blame - src/store_swapout.cc
merge changes from SQUID_2_3 branch
[thirdparty/squid.git] / src / store_swapout.cc
CommitLineData
9cef6668 1
2/*
7e3ce7b9 3 * $Id: store_swapout.cc,v 1.59 1999/12/30 17:36:59 wessels Exp $
9cef6668 4 *
5 * DEBUG: section 20 Storage Manager Swapout Functions
6 * AUTHOR: Duane Wessels
7 *
8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
13 * National Laboratory for Applied Network Research and funded by the
14 * National Science Foundation. Squid is Copyrighted (C) 1998 by
15 * Duane Wessels and the University of California San Diego. Please
16 * see the COPYRIGHT file for full details. Squid incorporates
17 * software developed and/or copyrighted by other sources. Please see
18 * the CREDITS file for full details.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
f09f5b26 36#include "squid.h"
37
bbcd7374 38static off_t storeSwapOutObjectBytesOnDisk(const MemObject *);
d54f0ab3 39static void storeSwapOutStart(StoreEntry * e);
2391a162 40static STIOCB storeSwapOutFileClosed;
f09f5b26 41
42/* start swapping object to disk */
d54f0ab3 43static void
f09f5b26 44storeSwapOutStart(StoreEntry * e)
45{
2391a162 46 generic_cbdata *c;
47 MemObject *mem = e->mem_obj;
48 int swap_hdr_sz = 0;
49 tlv *tlv_list;
50 char *buf;
51 assert(mem);
f09f5b26 52 storeLockObject(e);
25535cbe 53 e->swap_file_number = storeDirMapAllocate();
2391a162 54 c = xcalloc(1, sizeof(*c));
55 c->data = e;
56 cbdataAdd(c, cbdataXfree, 0);
57 mem->swapout.sio = storeOpen(e->swap_file_number,
58 O_WRONLY, storeSwapOutFileClosed, c);
3fc29499 59 if (NULL == mem->swapout.sio) {
60 e->swap_status = SWAPOUT_NONE;
61 storeDirMapBitReset(e->swap_file_number);
62 e->swap_file_number = -1;
63 cbdataFree(c);
64 storeUnlockObject(e);
65 return;
66 }
2391a162 67 e->swap_status = SWAPOUT_WRITING;
3fc29499 68 cbdataLock(mem->swapout.sio);
2391a162 69 debug(20, 5) ("storeSwapOutStart: Begin SwapOut '%s' to fileno %08X\n",
70 storeUrl(e), e->swap_file_number);
71 tlv_list = storeSwapMetaBuild(e);
72 buf = storeSwapMetaPack(tlv_list, &swap_hdr_sz);
73 storeSwapTLVFree(tlv_list);
74 mem->swap_hdr_sz = (size_t) swap_hdr_sz;
50f4d6ae 75 storeWrite(mem->swapout.sio, buf, mem->swap_hdr_sz, 0, xfree);
f09f5b26 76}
77
78void
2391a162 79storeSwapOut(StoreEntry * e)
f09f5b26 80{
81 MemObject *mem = e->mem_obj;
82 off_t lowest_offset;
83 off_t new_mem_lo;
2391a162 84 off_t on_disk = 0;
f09f5b26 85 size_t swapout_size;
86 char *swap_buf;
87 ssize_t swap_buf_len;
77b32a34 88 if (mem == NULL)
89 return;
f09f5b26 90 /* should we swap something out to disk? */
2391a162 91 debug(20, 7) ("storeSwapOut: %s\n", storeUrl(e));
92 debug(20, 7) ("storeSwapOut: store_status = %s\n",
f09f5b26 93 storeStatusStr[e->store_status]);
b7fe0ab0 94 if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
d46a87a8 95 assert(EBIT_TEST(e->flags, RELEASE_REQUEST));
f09f5b26 96 storeSwapOutFileClose(e);
97 return;
98 }
2391a162 99 debug(20, 7) ("storeSwapOut: mem->inmem_lo = %d\n",
f09f5b26 100 (int) mem->inmem_lo);
2391a162 101 debug(20, 7) ("storeSwapOut: mem->inmem_hi = %d\n",
f09f5b26 102 (int) mem->inmem_hi);
2391a162 103 debug(20, 7) ("storeSwapOut: swapout.queue_offset = %d\n",
f09f5b26 104 (int) mem->swapout.queue_offset);
2391a162 105 if (mem->swapout.sio)
60df005c 106 debug(20, 7) ("storeSwapOut: storeOffset() = %d\n",
2391a162 107 (int) storeOffset(mem->swapout.sio));
f09f5b26 108 assert(mem->inmem_hi >= mem->swapout.queue_offset);
f09f5b26 109 lowest_offset = storeLowestMemReaderOffset(e);
2391a162 110 debug(20, 7) ("storeSwapOut: lowest_offset = %d\n",
f09f5b26 111 (int) lowest_offset);
f09f5b26 112 new_mem_lo = lowest_offset;
c2725718 113 assert(new_mem_lo >= mem->inmem_lo);
eb824054 114 if (storeSwapOutAble(e)) {
1f38f50a 115 /*
116 * We should only free up to what we know has been written
117 * to disk, not what has been queued for writing. Otherwise
118 * there will be a chunk of the data which is not in memory
119 * and is not yet on disk.
120 */
1b72bda1 121 if ((on_disk = storeSwapOutObjectBytesOnDisk(mem)) < new_mem_lo)
c2725718 122 new_mem_lo = on_disk;
1f38f50a 123 } else {
124 /*
125 * Its not swap-able, so we must make it PRIVATE. Even if
126 * be only one MEM client and all others must read from
127 * disk.
128 */
eb824054 129 storeReleaseRequest(e);
1f38f50a 130 }
18fe65d0 131 stmemFreeDataUpto(&mem->data_hdr, new_mem_lo);
f09f5b26 132 mem->inmem_lo = new_mem_lo;
c2725718 133 if (e->swap_status == SWAPOUT_WRITING)
2391a162 134 assert(mem->inmem_lo <= on_disk);
c2725718 135 if (!storeSwapOutAble(e))
1b72bda1 136 return;
f09f5b26 137 swapout_size = (size_t) (mem->inmem_hi - mem->swapout.queue_offset);
2391a162 138 debug(20, 7) ("storeSwapOut: swapout_size = %d\n",
f09f5b26 139 (int) swapout_size);
1b72bda1 140 if (swapout_size == 0) {
614a44a6 141 if (e->store_status == STORE_OK)
1b72bda1 142 storeSwapOutFileClose(e);
614a44a6 143 return; /* Nevermore! */
1b72bda1 144 }
c47511fd 145 if (e->store_status == STORE_PENDING) {
146 /* wait for a full block to write */
614a44a6 147 if (swapout_size < DISK_PAGE_SIZE)
c47511fd 148 return;
149 /*
150 * Wait until we are below the disk FD limit, only if the
151 * next server-side read won't be deferred.
152 */
153 if (storeTooManyDiskFilesOpen() && !fwdCheckDeferRead(-1, e))
154 return;
155 }
2391a162 156 /* Ok, we have stuff to swap out. Is there a swapout.sio open? */
f09f5b26 157 if (e->swap_status == SWAPOUT_NONE) {
2391a162 158 assert(mem->swapout.sio == NULL);
c2725718 159 assert(mem->inmem_lo == 0);
f09f5b26 160 if (storeCheckCachable(e))
161 storeSwapOutStart(e);
2391a162 162 else
163 return;
614a44a6 164 /* ENTRY_CACHABLE will be cleared and we'll never get here again */
f09f5b26 165 }
3fc29499 166 if (NULL == mem->swapout.sio)
167 return;
614a44a6 168 do {
169 if (swapout_size > DISK_PAGE_SIZE)
170 swapout_size = DISK_PAGE_SIZE;
171 swap_buf = memAllocate(MEM_DISK_BUF);
172 swap_buf_len = stmemCopy(&mem->data_hdr,
173 mem->swapout.queue_offset,
174 swap_buf,
175 swapout_size);
176 if (swap_buf_len < 0) {
177 debug(20, 1) ("stmemCopy returned %d for '%s'\n", swap_buf_len, storeKeyText(e->key));
178 storeUnlink(e->swap_file_number);
179 storeDirMapBitReset(e->swap_file_number);
180 e->swap_file_number = -1;
181 e->swap_status = SWAPOUT_NONE;
182 memFree(swap_buf, MEM_DISK_BUF);
183 storeReleaseRequest(e);
184 storeSwapOutFileClose(e);
185 return;
186 }
187 debug(20, 3) ("storeSwapOut: swap_buf_len = %d\n", (int) swap_buf_len);
188 assert(swap_buf_len > 0);
189 debug(20, 3) ("storeSwapOut: swapping out %d bytes from %d\n",
190 swap_buf_len, (int) mem->swapout.queue_offset);
191 mem->swapout.queue_offset += swap_buf_len;
192 storeWrite(mem->swapout.sio, swap_buf, swap_buf_len, -1, memFreeDISK);
193 /* the storeWrite() call might generate an error */
194 if (e->swap_status != SWAPOUT_WRITING)
195 break;
196 swapout_size = (size_t) (mem->inmem_hi - mem->swapout.queue_offset);
1792fbdb 197 if (e->store_status == STORE_PENDING)
198 if (swapout_size < DISK_PAGE_SIZE)
199 break;
200 } while (swapout_size > 0);
3fc29499 201 if (NULL == mem->swapout.sio)
202 /* oops, we're not swapping out any more */
203 return;
1792fbdb 204 if (e->store_status == STORE_OK) {
205 /*
206 * If the state is STORE_OK, then all data must have been given
207 * to the filesystem at this point because storeSwapOut() is
208 * not going to be called again for this entry.
209 */
210 assert(mem->inmem_hi == mem->swapout.queue_offset);
211 storeSwapOutFileClose(e);
212 }
f09f5b26 213}
214
215void
216storeSwapOutFileClose(StoreEntry * e)
217{
218 MemObject *mem = e->mem_obj;
4215b049 219 assert(mem != NULL);
2ac76861 220 debug(20, 3) ("storeSwapOutFileClose: %s\n", storeKeyText(e->key));
5bd1abac 221 debug(20, 3) ("storeSwapOutFileClose: sio = %p\n", mem->swapout.sio);
2391a162 222 if (mem->swapout.sio == NULL)
25354045 223 return;
2391a162 224 storeClose(mem->swapout.sio);
f09f5b26 225}
226
227static void
2391a162 228storeSwapOutFileClosed(void *data, int errflag, storeIOState * sio)
f09f5b26 229{
2391a162 230 generic_cbdata *c = data;
231 StoreEntry *e = c->data;
25354045 232 MemObject *mem = e->mem_obj;
2391a162 233 assert(e->swap_status == SWAPOUT_WRITING);
234 cbdataFree(c);
235 if (errflag) {
236 debug(20, 1) ("storeSwapOutFileClosed: swapfile %08X, errflag=%d\n\t%s\n",
237 e->swap_file_number, errflag, xstrerror());
b2f9d4cd 238 /*
239 * yuck. don't clear the filemap bit for some errors so that
240 * we don't try re-using it over and over
241 */
242 if (errno != EPERM)
243 storeDirMapBitReset(e->swap_file_number);
2391a162 244 if (errflag == DISK_NO_SPACE_LEFT) {
245 storeDirDiskFull(e->swap_file_number);
246 storeDirConfigure();
247 storeConfigure();
248 }
5bd1abac 249 storeReleaseRequest(e);
f09f5b26 250 e->swap_file_number = -1;
2391a162 251 e->swap_status = SWAPOUT_NONE;
2391a162 252 } else {
253 /* swapping complete */
254 debug(20, 3) ("storeSwapOutFileClosed: SwapOut complete: '%s' to %08X\n",
255 storeUrl(e), e->swap_file_number);
256 e->swap_file_sz = objectLen(e) + mem->swap_hdr_sz;
257 e->swap_status = SWAPOUT_DONE;
258 storeDirUpdateSwapSize(e->swap_file_number, e->swap_file_sz, 1);
259 if (storeCheckCachable(e)) {
260 storeLog(STORE_LOG_SWAPOUT, e);
261 storeDirSwapLog(e, SWAP_LOG_ADD);
262 }
f09f5b26 263 }
5bd1abac 264 debug(20, 3) ("storeSwapOutFileClosed: %s:%d\n", __FILE__, __LINE__);
265 mem->swapout.sio = NULL;
2391a162 266 cbdataUnlock(sio);
5bd1abac 267 storeUnlockObject(e);
f09f5b26 268}
61038223 269
bbcd7374 270/*
271 * How much of the object data is on the disk?
272 */
273static off_t
274storeSwapOutObjectBytesOnDisk(const MemObject * mem)
275{
276 /*
2391a162 277 * NOTE: storeOffset() represents the disk file size,
bbcd7374 278 * not the amount of object data on disk.
279 *
280 * If we don't have at least 'swap_hdr_sz' bytes
281 * then none of the object data is on disk.
282 *
283 * This should still be safe if swap_hdr_sz == 0,
284 * meaning we haven't even opened the swapout file
285 * yet.
286 */
2391a162 287 off_t nwritten;
60df005c 288 if (mem->swapout.sio == NULL)
bbcd7374 289 return 0;
2391a162 290 nwritten = storeOffset(mem->swapout.sio);
291 if (nwritten <= mem->swap_hdr_sz)
292 return 0;
293 return nwritten - mem->swap_hdr_sz;
bbcd7374 294}
c2725718 295
296/*
297 * Is this entry a candidate for writing to disk?
298 */
5f25e839 299int
c2725718 300storeSwapOutAble(const StoreEntry * e)
301{
5f25e839 302 store_client *sc;
2391a162 303 if (e->mem_obj->swapout.sio != NULL)
c2725718 304 return 1;
305 if (e->mem_obj->inmem_lo > 0)
306 return 0;
5f25e839 307 /*
308 * If there are DISK clients, we must write to disk
309 * even if its not cachable
310 */
135171fe 311 for (sc = e->mem_obj->clients; sc; sc = sc->next)
5f25e839 312 if (sc->type == STORE_DISK_CLIENT)
313 return 1;
1792fbdb 314 if (store_dirs_rebuilding)
315 if (!EBIT_TEST(e->flags, ENTRY_SPECIAL))
316 return 0;
d46a87a8 317 return EBIT_TEST(e->flags, ENTRY_CACHABLE);
c2725718 318}