]> git.ipfire.org Git - thirdparty/squid.git/blame - src/store_swapout.cc
Fixed a small patch merge error
[thirdparty/squid.git] / src / store_swapout.cc
CommitLineData
9cef6668 1
2/*
50a49a6f 3 * $Id: store_swapout.cc,v 1.64 2000/04/18 06:06:17 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
efd900cb 15 * the Regents of the University of California. Please see the
16 * COPYRIGHT file for full details. Squid incorporates software
17 * developed and/or copyrighted by other sources. Please see the
18 * CREDITS file for full details.
9cef6668 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);
6ba94df3 53 storeSwapFileNumberSet(e, 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;
6ba94df3 61 storeSwapFileNumberSet(e, -1);
3fc29499 62 cbdataFree(c);
63 storeUnlockObject(e);
64 return;
65 }
2391a162 66 e->swap_status = SWAPOUT_WRITING;
3fc29499 67 cbdataLock(mem->swapout.sio);
2391a162 68 debug(20, 5) ("storeSwapOutStart: Begin SwapOut '%s' to fileno %08X\n",
69 storeUrl(e), e->swap_file_number);
70 tlv_list = storeSwapMetaBuild(e);
71 buf = storeSwapMetaPack(tlv_list, &swap_hdr_sz);
72 storeSwapTLVFree(tlv_list);
73 mem->swap_hdr_sz = (size_t) swap_hdr_sz;
50f4d6ae 74 storeWrite(mem->swapout.sio, buf, mem->swap_hdr_sz, 0, xfree);
f09f5b26 75}
76
77void
2391a162 78storeSwapOut(StoreEntry * e)
f09f5b26 79{
80 MemObject *mem = e->mem_obj;
81 off_t lowest_offset;
82 off_t new_mem_lo;
2391a162 83 off_t on_disk = 0;
f09f5b26 84 size_t swapout_size;
85 char *swap_buf;
86 ssize_t swap_buf_len;
77b32a34 87 if (mem == NULL)
88 return;
f09f5b26 89 /* should we swap something out to disk? */
2391a162 90 debug(20, 7) ("storeSwapOut: %s\n", storeUrl(e));
91 debug(20, 7) ("storeSwapOut: store_status = %s\n",
f09f5b26 92 storeStatusStr[e->store_status]);
b7fe0ab0 93 if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
d46a87a8 94 assert(EBIT_TEST(e->flags, RELEASE_REQUEST));
f09f5b26 95 storeSwapOutFileClose(e);
96 return;
97 }
2391a162 98 debug(20, 7) ("storeSwapOut: mem->inmem_lo = %d\n",
f09f5b26 99 (int) mem->inmem_lo);
2391a162 100 debug(20, 7) ("storeSwapOut: mem->inmem_hi = %d\n",
f09f5b26 101 (int) mem->inmem_hi);
2391a162 102 debug(20, 7) ("storeSwapOut: swapout.queue_offset = %d\n",
f09f5b26 103 (int) mem->swapout.queue_offset);
2391a162 104 if (mem->swapout.sio)
60df005c 105 debug(20, 7) ("storeSwapOut: storeOffset() = %d\n",
2391a162 106 (int) storeOffset(mem->swapout.sio));
f09f5b26 107 assert(mem->inmem_hi >= mem->swapout.queue_offset);
f09f5b26 108 lowest_offset = storeLowestMemReaderOffset(e);
2391a162 109 debug(20, 7) ("storeSwapOut: lowest_offset = %d\n",
f09f5b26 110 (int) lowest_offset);
50a49a6f 111 /*
112 * Careful. lowest_offset can be greater than inmem_hi, such
113 * as in the case of a range request.
114 */
115 if (mem->inmem_hi < lowest_offset)
116 new_mem_lo = lowest_offset;
117 else if (mem->inmem_hi - lowest_offset > DISK_PAGE_SIZE)
118 new_mem_lo = lowest_offset;
279447ff 119 else
50a49a6f 120 new_mem_lo = mem->inmem_lo;
c2725718 121 assert(new_mem_lo >= mem->inmem_lo);
eb824054 122 if (storeSwapOutAble(e)) {
1f38f50a 123 /*
124 * We should only free up to what we know has been written
125 * to disk, not what has been queued for writing. Otherwise
126 * there will be a chunk of the data which is not in memory
127 * and is not yet on disk.
128 */
1b72bda1 129 if ((on_disk = storeSwapOutObjectBytesOnDisk(mem)) < new_mem_lo)
c2725718 130 new_mem_lo = on_disk;
279447ff 131 } else if (new_mem_lo > 0) {
1f38f50a 132 /*
279447ff 133 * Its not swap-able, and we're about to delete a chunk,
134 * so we must make it PRIVATE. This is tricky/ugly because
135 * for the most part, we treat swapable == cachable here.
1f38f50a 136 */
eb824054 137 storeReleaseRequest(e);
1f38f50a 138 }
18fe65d0 139 stmemFreeDataUpto(&mem->data_hdr, new_mem_lo);
f09f5b26 140 mem->inmem_lo = new_mem_lo;
c2725718 141 if (e->swap_status == SWAPOUT_WRITING)
2391a162 142 assert(mem->inmem_lo <= on_disk);
c2725718 143 if (!storeSwapOutAble(e))
1b72bda1 144 return;
f09f5b26 145 swapout_size = (size_t) (mem->inmem_hi - mem->swapout.queue_offset);
2391a162 146 debug(20, 7) ("storeSwapOut: swapout_size = %d\n",
f09f5b26 147 (int) swapout_size);
1b72bda1 148 if (swapout_size == 0) {
614a44a6 149 if (e->store_status == STORE_OK)
1b72bda1 150 storeSwapOutFileClose(e);
614a44a6 151 return; /* Nevermore! */
1b72bda1 152 }
c47511fd 153 if (e->store_status == STORE_PENDING) {
154 /* wait for a full block to write */
614a44a6 155 if (swapout_size < DISK_PAGE_SIZE)
c47511fd 156 return;
157 /*
158 * Wait until we are below the disk FD limit, only if the
159 * next server-side read won't be deferred.
160 */
161 if (storeTooManyDiskFilesOpen() && !fwdCheckDeferRead(-1, e))
162 return;
163 }
2391a162 164 /* Ok, we have stuff to swap out. Is there a swapout.sio open? */
f09f5b26 165 if (e->swap_status == SWAPOUT_NONE) {
2391a162 166 assert(mem->swapout.sio == NULL);
c2725718 167 assert(mem->inmem_lo == 0);
f09f5b26 168 if (storeCheckCachable(e))
169 storeSwapOutStart(e);
2391a162 170 else
171 return;
614a44a6 172 /* ENTRY_CACHABLE will be cleared and we'll never get here again */
f09f5b26 173 }
3fc29499 174 if (NULL == mem->swapout.sio)
175 return;
614a44a6 176 do {
177 if (swapout_size > DISK_PAGE_SIZE)
178 swapout_size = DISK_PAGE_SIZE;
179 swap_buf = memAllocate(MEM_DISK_BUF);
180 swap_buf_len = stmemCopy(&mem->data_hdr,
181 mem->swapout.queue_offset,
182 swap_buf,
183 swapout_size);
184 if (swap_buf_len < 0) {
185 debug(20, 1) ("stmemCopy returned %d for '%s'\n", swap_buf_len, storeKeyText(e->key));
186 storeUnlink(e->swap_file_number);
6ba94df3 187 storeSwapFileNumberSet(e, -1);
614a44a6 188 e->swap_status = SWAPOUT_NONE;
189 memFree(swap_buf, MEM_DISK_BUF);
190 storeReleaseRequest(e);
191 storeSwapOutFileClose(e);
192 return;
193 }
194 debug(20, 3) ("storeSwapOut: swap_buf_len = %d\n", (int) swap_buf_len);
195 assert(swap_buf_len > 0);
196 debug(20, 3) ("storeSwapOut: swapping out %d bytes from %d\n",
197 swap_buf_len, (int) mem->swapout.queue_offset);
198 mem->swapout.queue_offset += swap_buf_len;
199 storeWrite(mem->swapout.sio, swap_buf, swap_buf_len, -1, memFreeDISK);
200 /* the storeWrite() call might generate an error */
201 if (e->swap_status != SWAPOUT_WRITING)
202 break;
203 swapout_size = (size_t) (mem->inmem_hi - mem->swapout.queue_offset);
1792fbdb 204 if (e->store_status == STORE_PENDING)
205 if (swapout_size < DISK_PAGE_SIZE)
206 break;
207 } while (swapout_size > 0);
3fc29499 208 if (NULL == mem->swapout.sio)
209 /* oops, we're not swapping out any more */
210 return;
1792fbdb 211 if (e->store_status == STORE_OK) {
212 /*
213 * If the state is STORE_OK, then all data must have been given
214 * to the filesystem at this point because storeSwapOut() is
215 * not going to be called again for this entry.
216 */
217 assert(mem->inmem_hi == mem->swapout.queue_offset);
218 storeSwapOutFileClose(e);
219 }
f09f5b26 220}
221
222void
223storeSwapOutFileClose(StoreEntry * e)
224{
225 MemObject *mem = e->mem_obj;
4215b049 226 assert(mem != NULL);
2ac76861 227 debug(20, 3) ("storeSwapOutFileClose: %s\n", storeKeyText(e->key));
5bd1abac 228 debug(20, 3) ("storeSwapOutFileClose: sio = %p\n", mem->swapout.sio);
2391a162 229 if (mem->swapout.sio == NULL)
25354045 230 return;
2391a162 231 storeClose(mem->swapout.sio);
f09f5b26 232}
233
234static void
2391a162 235storeSwapOutFileClosed(void *data, int errflag, storeIOState * sio)
f09f5b26 236{
2391a162 237 generic_cbdata *c = data;
238 StoreEntry *e = c->data;
25354045 239 MemObject *mem = e->mem_obj;
2391a162 240 assert(e->swap_status == SWAPOUT_WRITING);
241 cbdataFree(c);
242 if (errflag) {
6ba94df3 243 sfileno bad = e->swap_file_number;
2391a162 244 debug(20, 1) ("storeSwapOutFileClosed: swapfile %08X, errflag=%d\n\t%s\n",
6ba94df3 245 bad, errflag, xstrerror());
246 storeSwapFileNumberSet(e, -1);
b2f9d4cd 247 /*
6ba94df3 248 * yuck. re-set the filemap bit for some errors so that
b2f9d4cd 249 * we don't try re-using it over and over
250 */
6ba94df3 251 if (errno == EPERM)
252 storeDirMapBitSet(bad);
2391a162 253 if (errflag == DISK_NO_SPACE_LEFT) {
97de0ec7 254 storeDirDiskFull(bad);
2391a162 255 storeDirConfigure();
256 storeConfigure();
257 }
5bd1abac 258 storeReleaseRequest(e);
2391a162 259 e->swap_status = SWAPOUT_NONE;
2391a162 260 } else {
261 /* swapping complete */
262 debug(20, 3) ("storeSwapOutFileClosed: SwapOut complete: '%s' to %08X\n",
263 storeUrl(e), e->swap_file_number);
264 e->swap_file_sz = objectLen(e) + mem->swap_hdr_sz;
265 e->swap_status = SWAPOUT_DONE;
266 storeDirUpdateSwapSize(e->swap_file_number, e->swap_file_sz, 1);
267 if (storeCheckCachable(e)) {
268 storeLog(STORE_LOG_SWAPOUT, e);
269 storeDirSwapLog(e, SWAP_LOG_ADD);
270 }
f09f5b26 271 }
5bd1abac 272 debug(20, 3) ("storeSwapOutFileClosed: %s:%d\n", __FILE__, __LINE__);
273 mem->swapout.sio = NULL;
2391a162 274 cbdataUnlock(sio);
5bd1abac 275 storeUnlockObject(e);
f09f5b26 276}
61038223 277
bbcd7374 278/*
279 * How much of the object data is on the disk?
280 */
281static off_t
282storeSwapOutObjectBytesOnDisk(const MemObject * mem)
283{
284 /*
2391a162 285 * NOTE: storeOffset() represents the disk file size,
bbcd7374 286 * not the amount of object data on disk.
287 *
288 * If we don't have at least 'swap_hdr_sz' bytes
289 * then none of the object data is on disk.
290 *
291 * This should still be safe if swap_hdr_sz == 0,
292 * meaning we haven't even opened the swapout file
293 * yet.
294 */
2391a162 295 off_t nwritten;
60df005c 296 if (mem->swapout.sio == NULL)
bbcd7374 297 return 0;
2391a162 298 nwritten = storeOffset(mem->swapout.sio);
299 if (nwritten <= mem->swap_hdr_sz)
300 return 0;
301 return nwritten - mem->swap_hdr_sz;
bbcd7374 302}
c2725718 303
304/*
305 * Is this entry a candidate for writing to disk?
306 */
5f25e839 307int
c2725718 308storeSwapOutAble(const StoreEntry * e)
309{
5f25e839 310 store_client *sc;
2391a162 311 if (e->mem_obj->swapout.sio != NULL)
c2725718 312 return 1;
313 if (e->mem_obj->inmem_lo > 0)
314 return 0;
5f25e839 315 /*
316 * If there are DISK clients, we must write to disk
317 * even if its not cachable
318 */
135171fe 319 for (sc = e->mem_obj->clients; sc; sc = sc->next)
5f25e839 320 if (sc->type == STORE_DISK_CLIENT)
321 return 1;
1792fbdb 322 if (store_dirs_rebuilding)
323 if (!EBIT_TEST(e->flags, ENTRY_SPECIAL))
324 return 0;
d46a87a8 325 return EBIT_TEST(e->flags, ENTRY_CACHABLE);
c2725718 326}