]> git.ipfire.org Git - thirdparty/squid.git/blame - src/disk.cc
stop caching if LRU age gets below 300 seconds
[thirdparty/squid.git] / src / disk.cc
CommitLineData
b224ea98 1
95e36d02 2
30a4f2a8 3/*
015b507a 4 * $Id: disk.cc,v 1.124 1998/08/13 18:26:41 wessels Exp $
30a4f2a8 5 *
6 * DEBUG: section 6 Disk I/O Routines
7 * AUTHOR: Harvest Derived
8 *
42c04c16 9 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
e25c139f 10 * ----------------------------------------------------------
30a4f2a8 11 *
12 * Squid is the result of efforts by numerous individuals from the
13 * Internet community. Development is led by Duane Wessels of the
e25c139f 14 * National Laboratory for Applied Network Research and funded by the
15 * National Science Foundation. Squid is Copyrighted (C) 1998 by
16 * Duane Wessels and the University of California San Diego. Please
17 * see the COPYRIGHT file for full details. Squid incorporates
18 * software developed and/or copyrighted by other sources. Please see
19 * the CREDITS file for full details.
30a4f2a8 20 *
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
cbdec147 33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 34 *
30a4f2a8 35 */
ed43818f 36
44a47c6e 37#include "squid.h"
090089c4 38
39#define DISK_LINE_LEN 1024
090089c4 40
0a0bf5db 41typedef struct disk_ctrl_t {
42 int fd;
43 void *data;
44} disk_ctrl_t;
45
46
47typedef struct open_ctrl_t {
f17936ab 48 FOCB *callback;
0a0bf5db 49 void *callback_data;
50 char *path;
51} open_ctrl_t;
52
de866d20 53static AIOCB diskHandleWriteComplete;
54static AIOCB diskHandleReadComplete;
95d15928 55static PF diskHandleRead;
56static PF diskHandleWrite;
f5b8bbc4 57static void file_open_complete(void *, int, int);
24382924 58
04cece06 59void
0673c0ba 60disk_init(void)
090089c4 61{
04cece06 62#if USE_ASYNC_IO
63 aioClose(dup(0));
64#endif
090089c4 65}
66
67/* Open a disk file. Return a file descriptor */
684c2720 68int
6cf028ab 69file_open(const char *path, int mode, FOCB * callback, void *callback_data, void *tag)
090089c4 70{
090089c4 71 int fd;
0a0bf5db 72 open_ctrl_t *ctrlp;
73
74 ctrlp = xmalloc(sizeof(open_ctrl_t));
75 ctrlp->path = xstrdup(path);
76 ctrlp->callback = callback;
77 ctrlp->callback_data = callback_data;
090089c4 78
b59c7120 79 if (mode & O_WRONLY)
80 mode |= O_APPEND;
4f92c80c 81 mode |= SQUID_NONBLOCK;
b59c7120 82
090089c4 83 /* Open file */
0a0bf5db 84#if USE_ASYNC_IO
f17936ab 85 if (callback != NULL) {
6cf028ab 86 aioOpen(path, mode, 0644, file_open_complete, ctrlp, tag);
9e4ad609 87 return DISK_OK;
0a0bf5db 88 }
f17936ab 89#endif
0a0bf5db 90 fd = open(path, mode, 0644);
91 file_open_complete(ctrlp, fd, errno);
92 if (fd < 0)
93 return DISK_ERROR;
94 return fd;
0a0bf5db 95}
96
97
98static void
95d15928 99file_open_complete(void *data, int fd, int errcode)
0a0bf5db 100{
101 open_ctrl_t *ctrlp = (open_ctrl_t *) data;
6cf028ab 102
0e473d70 103 if (fd == -2 && errcode == -2) { /* Cancelled - clean up */
6cf028ab 104 if (ctrlp->callback)
105 (ctrlp->callback) (ctrlp->callback_data, fd, errcode);
106 xfree(ctrlp->path);
107 xfree(ctrlp);
108 return;
109 }
0a0bf5db 110 if (fd < 0) {
111 errno = errcode;
af95908a 112 debug(50, 3) ("file_open: error opening file %s: %s\n", ctrlp->path,
0a0bf5db 113 xstrerror());
114 if (ctrlp->callback)
6cf028ab 115 (ctrlp->callback) (ctrlp->callback_data, DISK_ERROR, errcode);
0a0bf5db 116 xfree(ctrlp->path);
117 xfree(ctrlp);
118 return;
090089c4 119 }
365e5b34 120 debug(6, 5) ("file_open: FD %d\n", fd);
3ca60c86 121 commSetCloseOnExec(fd);
5c5783a2 122 fd_open(fd, FD_FILE, ctrlp->path);
0a0bf5db 123 if (ctrlp->callback)
6cf028ab 124 (ctrlp->callback) (ctrlp->callback_data, fd, errcode);
0a0bf5db 125 xfree(ctrlp->path);
126 xfree(ctrlp);
127}
128
090089c4 129/* close a disk file. */
95d15928 130void
b8d8561b 131file_close(int fd)
090089c4 132{
76f87348 133 fde *F = &fd_table[fd];
25354045 134#if USE_ASYNC_IO
0e473d70 135 if (fd < 0) {
6cf028ab 136 debug(6, 0) ("file_close: FD less than zero: %d\n", fd);
137 return;
138 }
25354045 139#else
140 assert(fd >= 0);
141#endif
76f87348 142 assert(F->open);
0cd30ba5 143 if (F->flags.write_daemon) {
144 F->flags.close_request = 1;
66979cec 145 debug(6, 2) ("file_close: FD %d, delaying close\n", fd);
95d15928 146 return;
fb247d78 147 }
0a0bf5db 148#if USE_ASYNC_IO
95d15928 149 aioClose(fd);
0a0bf5db 150#else
42f99d0d 151#if CALL_FSYNC_BEFORE_CLOSE
152 fsync(fd);
153#endif
95d15928 154 close(fd);
0a0bf5db 155#endif
0cd30ba5 156 debug(6, F->flags.close_request ? 2 : 5)
5ac0b6e7 157 ("file_close: FD %d, really closing\n", fd);
6cf028ab 158 fd_close(fd);
090089c4 159}
160
090089c4 161
162/* write handler */
582b6456 163static void
79d39a72 164diskHandleWrite(int fd, void *notused)
090089c4 165{
4a86108c 166 int len = 0;
0a0bf5db 167 disk_ctrl_t *ctrlp;
168 dwrite_q *q = NULL;
169 dwrite_q *wq = NULL;
76f87348 170 fde *F = &fd_table[fd];
171 struct _fde_disk *fdd = &F->disk;
de866d20 172 if (!fdd->write_q)
582b6456 173 return;
ba7b771e 174 debug(6, 3) ("diskHandleWrite: FD %d\n", fd);
0a0bf5db 175 /* We need to combine subsequent write requests after the first */
eb139d08 176 /* But only if we don't need to seek() in between them, ugh! */
20f92343 177 /* XXX This currently ignores any seeks (file_offset) */
de866d20 178 if (fdd->write_q->next != NULL && fdd->write_q->next->next != NULL) {
179 len = 0;
180 for (q = fdd->write_q->next; q != NULL; q = q->next)
d377699f 181 len += q->len - q->buf_offset;
0a0bf5db 182 wq = xcalloc(1, sizeof(dwrite_q));
183 wq->buf = xmalloc(len);
184 wq->len = 0;
d377699f 185 wq->buf_offset = 0;
0a0bf5db 186 wq->next = NULL;
ed7f0b6a 187 wq->free_func = xfree;
0a0bf5db 188 do {
de866d20 189 q = fdd->write_q->next;
d377699f 190 len = q->len - q->buf_offset;
191 xmemcpy(wq->buf + wq->len, q->buf + q->buf_offset, len);
0a0bf5db 192 wq->len += len;
de866d20 193 fdd->write_q->next = q->next;
ed7f0b6a 194 if (q->free_func)
195 (q->free_func) (q->buf);
0a0bf5db 196 safe_free(q);
de866d20 197 } while (fdd->write_q->next != NULL);
198 fdd->write_q_tail = wq;
199 fdd->write_q->next = wq;
0a0bf5db 200 }
201 ctrlp = xcalloc(1, sizeof(disk_ctrl_t));
202 ctrlp->fd = fd;
f0027316 203#if USE_ASYNC_IO
204 ctrlp->data = fdd->write_q;
205#endif
8350fe9b 206 assert(fdd->write_q != NULL);
d377699f 207 assert(fdd->write_q->len > fdd->write_q->buf_offset);
0a0bf5db 208#if USE_ASYNC_IO
209 aioWrite(fd,
5999b776 210 -1, /* seek offset, -1 == append */
d377699f 211 fdd->write_q->buf + fdd->write_q->buf_offset,
212 fdd->write_q->len - fdd->write_q->buf_offset,
0a0bf5db 213 diskHandleWriteComplete,
cd1fb0eb 214 ctrlp);
0a0bf5db 215#else
ba7b771e 216 debug(6, 3) ("diskHandleWrite: FD %d writing %d bytes\n",
5f6ac48b 217 fd, (int) (fdd->write_q->len - fdd->write_q->buf_offset));
0a0bf5db 218 len = write(fd,
d377699f 219 fdd->write_q->buf + fdd->write_q->buf_offset,
220 fdd->write_q->len - fdd->write_q->buf_offset);
582b6456 221 diskHandleWriteComplete(ctrlp, len, errno);
0a0bf5db 222#endif
223}
224
de866d20 225static void
b69f7771 226diskHandleWriteComplete(void *data, int len, int errcode)
0a0bf5db 227{
228 disk_ctrl_t *ctrlp = data;
0a0bf5db 229 int fd = ctrlp->fd;
76f87348 230 fde *F = &fd_table[fd];
231 struct _fde_disk *fdd = &F->disk;
de866d20 232 dwrite_q *q = fdd->write_q;
233 int status = DISK_OK;
ba7b771e 234 int do_callback;
68c21f71 235 int do_close;
0a0bf5db 236 errno = errcode;
ba7b771e 237 debug(6, 3) ("diskHandleWriteComplete: FD %d len = %d\n", fd, len);
f0027316 238#if USE_ASYNC_IO
239/*
240 * From: "Michael O'Reilly" <michael@metal.iinet.net.au>
241 * Date: 24 Feb 1998 15:12:06 +0800
242 *
243 * A small patch to improve the AIO sanity. the patch below makes sure
244 * the write request really does match the data passed back from the
245 * async IO call. note that I haven't actually rebooted with this
246 * patch yet, so 'provisional' is an understatement.
247 */
248 if (q && q != ctrlp->data) {
249 dwrite_q *p = ctrlp->data;
250 debug(50, 0) ("KARMA: q != data (%p, %p)\n", q, p);
251 debug(50, 0) ("KARMA: (%d, %d, %d FD %d)\n",
252 q->buf_offset, q->len, len, fd);
253 debug(50, 0) ("KARMA: desc %s, type %d, open %d, flags 0x%x\n",
254 F->desc, F->type, F->open, F->flags);
255 debug(50, 0) ("KARMA: (%d, %d)\n", p->buf_offset, p->len);
256 len = -1;
257 errcode = EFAULT;
258 }
259#endif
0a0bf5db 260 safe_free(data);
de866d20 261 if (q == NULL) /* Someone aborted then write completed */
262 return;
6cf028ab 263
0e473d70 264 if (len == -2 && errcode == -2) { /* Write cancelled - cleanup */
6cf028ab 265 do {
266 fdd->write_q = q->next;
ed7f0b6a 267 if (q->free_func)
268 (q->free_func) (q->buf);
6cf028ab 269 safe_free(q);
270 } while ((q = fdd->write_q));
271 return;
272 }
6cf028ab 273 fd_bytes(fd, len, FD_WRITE);
0a0bf5db 274 if (len < 0) {
b224ea98 275 if (!ignoreErrno(errno)) {
de866d20 276 status = errno == ENOSPC ? DISK_NO_SPACE_LEFT : DISK_ERROR;
a3d5953d 277 debug(50, 1) ("diskHandleWrite: FD %d: disk write error: %s\n",
0c77d853 278 fd, xstrerror());
25354045 279 /*
280 * If there is no write callback, then this file is
281 * most likely something important like a log file, or
282 * an interprocess pipe. Its not a swapfile. We feel
283 * that a write failure on a log file is rather important,
284 * and Squid doesn't otherwise deal with this condition.
285 * So to get the administrators attention, we exit with
286 * a fatal message.
287 */
288 if (fdd->wrt_handle == NULL)
289 fatal("Write failure -- check your disk space and cache.log");
290 /*
291 * If there is a write failure, then we notify the
292 * upper layer via the callback, at the end of this
293 * function. Meanwhile, flush all pending buffers
294 * here. Let the upper layer decide how to handle the
295 * failure. This will prevent experiencing multiple,
296 * repeated write failures for the same FD because of
297 * the queued data.
298 */
299 do {
300 fdd->write_q = q->next;
301 if (q->free_func)
302 (q->free_func) (q->buf);
303 safe_free(q);
304 } while ((q = fdd->write_q));
0c77d853 305 }
de866d20 306 len = 0;
0a0bf5db 307 }
8350fe9b 308 if (q != NULL) {
309 /* q might become NULL from write failure above */
d377699f 310 q->buf_offset += len;
6cf028ab 311 if (q->buf_offset > q->len)
312 debug(50, 1) ("diskHandleWriteComplete: q->buf_offset > q->len (%p,%d, %d, %d FD %d)\n",
5f6ac48b 313 q, (int) q->buf_offset, q->len, len, fd);
d377699f 314 assert(q->buf_offset <= q->len);
315 if (q->buf_offset == q->len) {
56878878 316 /* complete write */
317 fdd->write_q = q->next;
ed7f0b6a 318 if (q->free_func)
319 (q->free_func) (q->buf);
56878878 320 safe_free(q);
321 }
090089c4 322 }
de866d20 323 if (fdd->write_q == NULL) {
324 /* no more data */
325 fdd->write_q_tail = NULL;
0cd30ba5 326 F->flags.write_daemon = 0;
de866d20 327 } else {
0a0bf5db 328 /* another block is queued */
25354045 329 cbdataLock(fdd->wrt_handle_data);
de866d20 330 commSetSelect(fd, COMM_SELECT_WRITE, diskHandleWrite, NULL, 0);
0cd30ba5 331 F->flags.write_daemon = 1;
4a86108c 332 }
0cd30ba5 333 do_close = F->flags.close_request;
25354045 334 if (fdd->wrt_handle) {
ba7b771e 335 if (fdd->wrt_handle_data == NULL)
336 do_callback = 1;
337 else if (cbdataValid(fdd->wrt_handle_data))
338 do_callback = 1;
339 else
340 do_callback = 0;
25354045 341 if (fdd->wrt_handle_data != NULL)
342 cbdataUnlock(fdd->wrt_handle_data);
26720a7c 343 if (do_callback) {
ba7b771e 344 fdd->wrt_handle(fd, status, len, fdd->wrt_handle_data);
26720a7c 345 /*
346 * NOTE, this callback can close the FD, so we must
347 * not touch 'F', 'fdd', etc. after this.
348 */
349 return;
350 }
25354045 351 }
68c21f71 352 if (do_close)
b59c7120 353 file_close(fd);
090089c4 354}
355
356
090089c4 357/* write block to a file */
358/* write back queue. Only one writer at a time. */
359/* call a handle when writing is complete. */
e3ef2b09 360void
3ebcfaa1 361file_write(int fd,
d377699f 362 off_t file_offset,
5830cdb3 363 void *ptr_to_buf,
684c2720 364 int len,
d89d1fb6 365 DWCB handle,
684c2720 366 void *handle_data,
9e4ad609 367 FREE * free_func)
090089c4 368{
c6ac7aae 369 dwrite_q *wq = NULL;
48cc3fcf 370 fde *F = &fd_table[fd];
371 assert(fd >= 0);
372 assert(F->open);
090089c4 373 /* if we got here. Caller is eligible to write. */
30a4f2a8 374 wq = xcalloc(1, sizeof(dwrite_q));
d377699f 375 wq->file_offset = file_offset;
090089c4 376 wq->buf = ptr_to_buf;
090089c4 377 wq->len = len;
d377699f 378 wq->buf_offset = 0;
090089c4 379 wq->next = NULL;
ed7f0b6a 380 wq->free_func = free_func;
76f87348 381 F->disk.wrt_handle = handle;
382 F->disk.wrt_handle_data = handle_data;
090089c4 383 /* add to queue */
48cc3fcf 384 if (F->disk.write_q == NULL) {
090089c4 385 /* empty queue */
76f87348 386 F->disk.write_q = F->disk.write_q_tail = wq;
090089c4 387 } else {
76f87348 388 F->disk.write_q_tail->next = wq;
389 F->disk.write_q_tail = wq;
090089c4 390 }
0cd30ba5 391 if (!F->flags.write_daemon) {
25354045 392 cbdataLock(F->disk.wrt_handle_data);
0a0bf5db 393#if USE_ASYNC_IO
95d15928 394 diskHandleWrite(fd, NULL);
0a0bf5db 395#else
95d15928 396 commSetSelect(fd, COMM_SELECT_WRITE, diskHandleWrite, NULL, 0);
0a0bf5db 397#endif
0cd30ba5 398 F->flags.write_daemon = 1;
429fdbec 399 }
090089c4 400}
401
137ee196 402/* a wrapper around file_write to allow for MemBuf to be file_written in a snap */
403void
404file_write_mbuf(int fd, off_t off, MemBuf mb, DWCB * handler, void *handler_data)
405{
406 file_write(fd, off, mb.buf, mb.size, handler, handler_data, memBufFreeFunc(&mb));
407}
090089c4 408
409/* Read from FD */
582b6456 410static void
411diskHandleRead(int fd, void *data)
090089c4 412{
582b6456 413 dread_ctrl *ctrl_dat = data;
606bd3b5 414#if !USE_ASYNC_IO
edd2eb63 415 fde *F = &fd_table[fd];
090089c4 416 int len;
606bd3b5 417#endif
418 disk_ctrl_t *ctrlp = xcalloc(1, sizeof(disk_ctrl_t));
0a0bf5db 419 ctrlp->fd = fd;
cd1fb0eb 420 ctrlp->data = ctrl_dat;
0a0bf5db 421#if USE_ASYNC_IO
422 aioRead(fd,
20f92343 423 ctrl_dat->offset,
711982d8 424 ctrl_dat->buf,
425 ctrl_dat->req_len,
0a0bf5db 426 diskHandleReadComplete,
cd1fb0eb 427 ctrlp);
0a0bf5db 428#else
711982d8 429 if (F->disk.offset != ctrl_dat->offset) {
f2b30883 430 debug(6, 3) ("diskHandleRead: FD %d seeking to offset %d\n",
343c257b 431 fd, (int) ctrl_dat->offset);
711982d8 432 lseek(fd, ctrl_dat->offset, SEEK_SET); /* XXX ignore return? */
556c33d5 433 F->disk.offset = ctrl_dat->offset;
711982d8 434 }
435 len = read(fd, ctrl_dat->buf, ctrl_dat->req_len);
015b507a 436 if (len > 0)
437 F->disk.offset += len;
582b6456 438 diskHandleReadComplete(ctrlp, len, errno);
090089c4 439#endif
0a0bf5db 440}
441
de866d20 442static void
4f92c80c 443diskHandleReadComplete(void *data, int len, int errcode)
0a0bf5db 444{
445 disk_ctrl_t *ctrlp = data;
446 dread_ctrl *ctrl_dat = ctrlp->data;
447 int fd = ctrlp->fd;
901a2a3c 448 int rc = DISK_OK;
0a0bf5db 449 errno = errcode;
6cf028ab 450
0a0bf5db 451 xfree(data);
6cf028ab 452
0e473d70 453 if (len == -2 && errcode == -2) { /* Read cancelled - cleanup */
6cf028ab 454 cbdataUnlock(ctrl_dat->client_data);
0a5bc521 455 memFree(MEM_DREAD_CTRL, ctrl_dat);
6cf028ab 456 return;
457 }
4f92c80c 458 fd_bytes(fd, len, FD_READ);
0a0bf5db 459 if (len < 0) {
b224ea98 460 if (ignoreErrno(errno)) {
901a2a3c 461 commSetSelect(fd, COMM_SELECT_READ, diskHandleRead, ctrl_dat, 0);
de866d20 462 return;
0a0bf5db 463 }
901a2a3c 464 debug(50, 1) ("diskHandleRead: FD %d: %s\n", fd, xstrerror());
465 len = 0;
466 rc = DISK_ERROR;
090089c4 467 } else if (len == 0) {
901a2a3c 468 rc = DISK_EOF;
090089c4 469 }
901a2a3c 470 if (cbdataValid(ctrl_dat->client_data))
5d86029a 471 ctrl_dat->handler(fd, ctrl_dat->buf, len, rc, ctrl_dat->client_data);
901a2a3c 472 cbdataUnlock(ctrl_dat->client_data);
0a5bc521 473 memFree(MEM_DREAD_CTRL, ctrl_dat);
090089c4 474}
475
476
477/* start read operation */
478/* buffer must be allocated from the caller.
479 * It must have at least req_len space in there.
480 * call handler when a reading is complete. */
b8d8561b 481int
d377699f 482file_read(int fd, char *buf, int req_len, off_t offset, DRCB * handler, void *client_data)
090089c4 483{
484 dread_ctrl *ctrl_dat;
711982d8 485 assert(fd >= 0);
0a5bc521 486 ctrl_dat = memAllocate(MEM_DREAD_CTRL);
090089c4 487 ctrl_dat->fd = fd;
488 ctrl_dat->offset = offset;
489 ctrl_dat->req_len = req_len;
490 ctrl_dat->buf = buf;
090089c4 491 ctrl_dat->end_of_file = 0;
492 ctrl_dat->handler = handler;
493 ctrl_dat->client_data = client_data;
901a2a3c 494 cbdataLock(client_data);
0a0bf5db 495#if USE_ASYNC_IO
496 diskHandleRead(fd, ctrl_dat);
497#else
b177367b 498 commSetSelect(fd,
234967c9 499 COMM_SELECT_READ,
cd1fb0eb 500 diskHandleRead,
501 ctrl_dat,
b177367b 502 0);
0a0bf5db 503#endif
090089c4 504 return DISK_OK;
505}
506
b8d8561b 507int
508diskWriteIsComplete(int fd)
b59c7120 509{
95d15928 510 return fd_table[fd].disk.write_q ? 0 : 1;
0a21bd84 511}