]> git.ipfire.org Git - thirdparty/squid.git/blame - src/disk.cc
update
[thirdparty/squid.git] / src / disk.cc
CommitLineData
30a4f2a8 1/*
f2b30883 2 * $Id: disk.cc,v 1.93 1997/11/12 00:10:45 wessels Exp $
30a4f2a8 3 *
4 * DEBUG: section 6 Disk I/O Routines
5 * AUTHOR: Harvest Derived
6 *
42c04c16 7 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
30a4f2a8 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
13 * the National Science Foundation.
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 *
29 */
30
31/*
32 * Copyright (c) 1994, 1995. All rights reserved.
33 *
34 * The Harvest software was developed by the Internet Research Task
35 * Force Research Group on Resource Discovery (IRTF-RD):
36 *
37 * Mic Bowman of Transarc Corporation.
38 * Peter Danzig of the University of Southern California.
39 * Darren R. Hardy of the University of Colorado at Boulder.
40 * Udi Manber of the University of Arizona.
41 * Michael F. Schwartz of the University of Colorado at Boulder.
42 * Duane Wessels of the University of Colorado at Boulder.
43 *
44 * This copyright notice applies to software in the Harvest
45 * ``src/'' directory only. Users should consult the individual
46 * copyright notices in the ``components/'' subdirectories for
47 * copyright information about other software bundled with the
48 * Harvest source code distribution.
49 *
50 * TERMS OF USE
51 *
52 * The Harvest software may be used and re-distributed without
53 * charge, provided that the software origin and research team are
54 * cited in any use of the system. Most commonly this is
55 * accomplished by including a link to the Harvest Home Page
56 * (http://harvest.cs.colorado.edu/) from the query page of any
57 * Broker you deploy, as well as in the query result pages. These
58 * links are generated automatically by the standard Broker
59 * software distribution.
60 *
61 * The Harvest software is provided ``as is'', without express or
62 * implied warranty, and with no support nor obligation to assist
63 * in its use, correction, modification or enhancement. We assume
64 * no liability with respect to the infringement of copyrights,
65 * trade secrets, or any patents, and are not responsible for
66 * consequential damages. Proper use of the Harvest software is
67 * entirely the responsibility of the user.
68 *
69 * DERIVATIVE WORKS
70 *
71 * Users may make derivative works from the Harvest software, subject
72 * to the following constraints:
73 *
74 * - You must include the above copyright notice and these
75 * accompanying paragraphs in all forms of derivative works,
76 * and any documentation and other materials related to such
77 * distribution and use acknowledge that the software was
78 * developed at the above institutions.
79 *
80 * - You must notify IRTF-RD regarding your distribution of
81 * the derivative work.
82 *
83 * - You must clearly notify users that your are distributing
84 * a modified version and not the original Harvest software.
85 *
86 * - Any derivative product is also subject to these copyright
87 * and use restrictions.
88 *
89 * Note that the Harvest software is NOT in the public domain. We
90 * retain copyright, as specified above.
91 *
92 * HISTORY OF FREE SOFTWARE STATUS
93 *
94 * Originally we required sites to license the software in cases
95 * where they were going to build commercial products/services
96 * around Harvest. In June 1995 we changed this policy. We now
97 * allow people to use the core Harvest software (the code found in
98 * the Harvest ``src/'' directory) for free. We made this change
99 * in the interest of encouraging the widest possible deployment of
100 * the technology. The Harvest software is really a reference
101 * implementation of a set of protocols and formats, some of which
102 * we intend to standardize. We encourage commercial
103 * re-implementations of code complying to this set of standards.
104 */
ed43818f 105
44a47c6e 106#include "squid.h"
090089c4 107
108#define DISK_LINE_LEN 1024
090089c4 109
0a0bf5db 110typedef struct disk_ctrl_t {
111 int fd;
112 void *data;
113} disk_ctrl_t;
114
115
116typedef struct open_ctrl_t {
f17936ab 117 FOCB *callback;
0a0bf5db 118 void *callback_data;
119 char *path;
120} open_ctrl_t;
121
de866d20 122static AIOCB diskHandleWriteComplete;
123static AIOCB diskHandleReadComplete;
95d15928 124static PF diskHandleRead;
125static PF diskHandleWrite;
f5b8bbc4 126static void file_open_complete(void *, int, int);
24382924 127
090089c4 128/* initialize table */
b8d8561b 129int
0673c0ba 130disk_init(void)
090089c4 131{
090089c4 132 return 0;
133}
134
135/* Open a disk file. Return a file descriptor */
684c2720 136int
9e4ad609 137file_open(const char *path, int mode, FOCB * callback, void *callback_data)
090089c4 138{
090089c4 139 int fd;
0a0bf5db 140 open_ctrl_t *ctrlp;
141
142 ctrlp = xmalloc(sizeof(open_ctrl_t));
143 ctrlp->path = xstrdup(path);
144 ctrlp->callback = callback;
145 ctrlp->callback_data = callback_data;
090089c4 146
b59c7120 147 if (mode & O_WRONLY)
148 mode |= O_APPEND;
4f92c80c 149 mode |= SQUID_NONBLOCK;
b59c7120 150
090089c4 151 /* Open file */
0a0bf5db 152#if USE_ASYNC_IO
f17936ab 153 if (callback != NULL) {
9e4ad609 154 aioOpen(path, mode, 0644, file_open_complete, ctrlp);
155 return DISK_OK;
0a0bf5db 156 }
f17936ab 157#endif
0a0bf5db 158 fd = open(path, mode, 0644);
159 file_open_complete(ctrlp, fd, errno);
160 if (fd < 0)
161 return DISK_ERROR;
162 return fd;
0a0bf5db 163}
164
165
166static void
95d15928 167file_open_complete(void *data, int fd, int errcode)
0a0bf5db 168{
169 open_ctrl_t *ctrlp = (open_ctrl_t *) data;
0a0bf5db 170 if (fd < 0) {
171 errno = errcode;
a3d5953d 172 debug(50, 0) ("file_open: error opening file %s: %s\n", ctrlp->path,
0a0bf5db 173 xstrerror());
174 if (ctrlp->callback)
175 (ctrlp->callback) (ctrlp->callback_data, DISK_ERROR);
176 xfree(ctrlp->path);
177 xfree(ctrlp);
178 return;
090089c4 179 }
365e5b34 180 debug(6, 5) ("file_open: FD %d\n", fd);
3ca60c86 181 commSetCloseOnExec(fd);
5c5783a2 182 fd_open(fd, FD_FILE, ctrlp->path);
0a0bf5db 183 if (ctrlp->callback)
184 (ctrlp->callback) (ctrlp->callback_data, fd);
185 xfree(ctrlp->path);
186 xfree(ctrlp);
187}
188
090089c4 189/* close a disk file. */
95d15928 190void
b8d8561b 191file_close(int fd)
090089c4 192{
76f87348 193 fde *F = &fd_table[fd];
f88211e8 194 assert(fd >= 0);
76f87348 195 assert(F->open);
79a15e0a 196 if (EBIT_TEST(F->flags, FD_WRITE_DAEMON)) {
197 EBIT_SET(F->flags, FD_CLOSE_REQUEST);
95d15928 198 return;
fb247d78 199 }
79a15e0a 200 if (EBIT_TEST(F->flags, FD_WRITE_PENDING)) {
201 EBIT_SET(F->flags, FD_CLOSE_REQUEST);
95d15928 202 return;
203 }
5c5783a2 204 fd_close(fd);
365e5b34 205 debug(6, 5) ("file_close: FD %d\n", fd);
0a0bf5db 206#if USE_ASYNC_IO
95d15928 207 aioClose(fd);
0a0bf5db 208#else
95d15928 209 close(fd);
0a0bf5db 210#endif
090089c4 211}
212
090089c4 213
214/* write handler */
582b6456 215static void
79d39a72 216diskHandleWrite(int fd, void *notused)
090089c4 217{
4a86108c 218 int len = 0;
0a0bf5db 219 disk_ctrl_t *ctrlp;
220 dwrite_q *q = NULL;
221 dwrite_q *wq = NULL;
76f87348 222 fde *F = &fd_table[fd];
223 struct _fde_disk *fdd = &F->disk;
de866d20 224 if (!fdd->write_q)
582b6456 225 return;
0a0bf5db 226 /* We need to combine subsequent write requests after the first */
de866d20 227 if (fdd->write_q->next != NULL && fdd->write_q->next->next != NULL) {
228 len = 0;
229 for (q = fdd->write_q->next; q != NULL; q = q->next)
0a0bf5db 230 len += q->len - q->cur_offset;
231 wq = xcalloc(1, sizeof(dwrite_q));
232 wq->buf = xmalloc(len);
233 wq->len = 0;
234 wq->cur_offset = 0;
235 wq->next = NULL;
236 wq->free = xfree;
237 do {
de866d20 238 q = fdd->write_q->next;
0a0bf5db 239 len = q->len - q->cur_offset;
de866d20 240 xmemcpy(wq->buf + wq->len, q->buf + q->cur_offset, len);
0a0bf5db 241 wq->len += len;
de866d20 242 fdd->write_q->next = q->next;
0a0bf5db 243 if (q->free)
244 (q->free) (q->buf);
245 safe_free(q);
de866d20 246 } while (fdd->write_q->next != NULL);
247 fdd->write_q_tail = wq;
248 fdd->write_q->next = wq;
0a0bf5db 249 }
250 ctrlp = xcalloc(1, sizeof(disk_ctrl_t));
251 ctrlp->fd = fd;
8350fe9b 252 assert(fdd->write_q != NULL);
253 assert(fdd->write_q->len > fdd->write_q->cur_offset);
0a0bf5db 254#if USE_ASYNC_IO
255 aioWrite(fd,
de866d20 256 fdd->write_q->buf + fdd->write_q->cur_offset,
257 fdd->write_q->len - fdd->write_q->cur_offset,
0a0bf5db 258 diskHandleWriteComplete,
cd1fb0eb 259 ctrlp);
0a0bf5db 260#else
261 len = write(fd,
de866d20 262 fdd->write_q->buf + fdd->write_q->cur_offset,
263 fdd->write_q->len - fdd->write_q->cur_offset);
582b6456 264 diskHandleWriteComplete(ctrlp, len, errno);
0a0bf5db 265#endif
266}
267
de866d20 268static void
b69f7771 269diskHandleWriteComplete(void *data, int len, int errcode)
0a0bf5db 270{
271 disk_ctrl_t *ctrlp = data;
0a0bf5db 272 int fd = ctrlp->fd;
76f87348 273 fde *F = &fd_table[fd];
274 struct _fde_disk *fdd = &F->disk;
de866d20 275 dwrite_q *q = fdd->write_q;
276 int status = DISK_OK;
0a0bf5db 277 errno = errcode;
278 safe_free(data);
b69f7771 279 fd_bytes(fd, len, FD_WRITE);
de866d20 280 if (q == NULL) /* Someone aborted then write completed */
281 return;
0a0bf5db 282 if (len < 0) {
283 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
de866d20 284 (void) 0;
0a0bf5db 285 } else {
de866d20 286 status = errno == ENOSPC ? DISK_NO_SPACE_LEFT : DISK_ERROR;
a3d5953d 287 debug(50, 1) ("diskHandleWrite: FD %d: disk write error: %s\n",
0c77d853 288 fd, xstrerror());
de866d20 289 if (fdd->wrt_handle == NULL) {
290 /* FLUSH PENDING BUFFERS */
291 do {
292 fdd->write_q = q->next;
293 if (q->free)
294 (q->free) (q->buf);
295 safe_free(q);
296 } while ((q = fdd->write_q));
090089c4 297 }
0c77d853 298 }
de866d20 299 len = 0;
0a0bf5db 300 }
8350fe9b 301 if (q != NULL) {
302 /* q might become NULL from write failure above */
56878878 303 q->cur_offset += len;
304 assert(q->cur_offset <= q->len);
305 if (q->cur_offset == q->len) {
306 /* complete write */
307 fdd->write_q = q->next;
308 if (q->free)
309 (q->free) (q->buf);
310 safe_free(q);
311 }
090089c4 312 }
de866d20 313 if (fdd->write_q == NULL) {
314 /* no more data */
315 fdd->write_q_tail = NULL;
79a15e0a 316 EBIT_CLR(F->flags, FD_WRITE_PENDING);
317 EBIT_CLR(F->flags, FD_WRITE_DAEMON);
de866d20 318 } else {
0a0bf5db 319 /* another block is queued */
de866d20 320 commSetSelect(fd, COMM_SELECT_WRITE, diskHandleWrite, NULL, 0);
79a15e0a 321 EBIT_SET(F->flags, FD_WRITE_DAEMON);
4a86108c 322 }
de866d20 323 if (fdd->wrt_handle)
d89d1fb6 324 fdd->wrt_handle(fd, status, len, fdd->wrt_handle_data);
79a15e0a 325 if (EBIT_TEST(F->flags, FD_CLOSE_REQUEST))
b59c7120 326 file_close(fd);
090089c4 327}
328
329
090089c4 330/* write block to a file */
331/* write back queue. Only one writer at a time. */
332/* call a handle when writing is complete. */
b8d8561b 333int
3ebcfaa1 334file_write(int fd,
684c2720 335 char *ptr_to_buf,
336 int len,
d89d1fb6 337 DWCB handle,
684c2720 338 void *handle_data,
9e4ad609 339 FREE * free_func)
090089c4 340{
c6ac7aae 341 dwrite_q *wq = NULL;
48cc3fcf 342 fde *F = &fd_table[fd];
343 assert(fd >= 0);
344 assert(F->open);
090089c4 345 /* if we got here. Caller is eligible to write. */
30a4f2a8 346 wq = xcalloc(1, sizeof(dwrite_q));
090089c4 347 wq->buf = ptr_to_buf;
090089c4 348 wq->len = len;
349 wq->cur_offset = 0;
350 wq->next = NULL;
86ee2017 351 wq->free = free_func;
76f87348 352 F->disk.wrt_handle = handle;
353 F->disk.wrt_handle_data = handle_data;
090089c4 354 /* add to queue */
79a15e0a 355 EBIT_SET(F->flags, FD_WRITE_PENDING);
48cc3fcf 356 if (F->disk.write_q == NULL) {
090089c4 357 /* empty queue */
76f87348 358 F->disk.write_q = F->disk.write_q_tail = wq;
090089c4 359 } else {
76f87348 360 F->disk.write_q_tail->next = wq;
361 F->disk.write_q_tail = wq;
090089c4 362 }
79a15e0a 363 if (!EBIT_TEST(F->flags, FD_WRITE_DAEMON)) {
0a0bf5db 364#if USE_ASYNC_IO
95d15928 365 diskHandleWrite(fd, NULL);
0a0bf5db 366#else
95d15928 367 commSetSelect(fd, COMM_SELECT_WRITE, diskHandleWrite, NULL, 0);
0a0bf5db 368#endif
79a15e0a 369 EBIT_SET(F->flags, FD_WRITE_DAEMON);
429fdbec 370 }
090089c4 371 return DISK_OK;
372}
373
374
375
376/* Read from FD */
582b6456 377static void
378diskHandleRead(int fd, void *data)
090089c4 379{
582b6456 380 dread_ctrl *ctrl_dat = data;
711982d8 381 fde *F = &fd_table[fd];
606bd3b5 382#if !USE_ASYNC_IO
090089c4 383 int len;
606bd3b5 384#endif
385 disk_ctrl_t *ctrlp = xcalloc(1, sizeof(disk_ctrl_t));
0a0bf5db 386 ctrlp->fd = fd;
cd1fb0eb 387 ctrlp->data = ctrl_dat;
0a0bf5db 388#if USE_ASYNC_IO
389 aioRead(fd,
711982d8 390 ctrl_dat->buf,
391 ctrl_dat->req_len,
0a0bf5db 392 diskHandleReadComplete,
cd1fb0eb 393 ctrlp);
0a0bf5db 394#else
711982d8 395 if (F->disk.offset != ctrl_dat->offset) {
f2b30883 396 debug(6, 3) ("diskHandleRead: FD %d seeking to offset %d\n",
343c257b 397 fd, (int) ctrl_dat->offset);
711982d8 398 lseek(fd, ctrl_dat->offset, SEEK_SET); /* XXX ignore return? */
556c33d5 399 F->disk.offset = ctrl_dat->offset;
711982d8 400 }
401 len = read(fd, ctrl_dat->buf, ctrl_dat->req_len);
402 F->disk.offset += len;
582b6456 403 diskHandleReadComplete(ctrlp, len, errno);
090089c4 404#endif
0a0bf5db 405}
406
de866d20 407static void
4f92c80c 408diskHandleReadComplete(void *data, int len, int errcode)
0a0bf5db 409{
410 disk_ctrl_t *ctrlp = data;
411 dread_ctrl *ctrl_dat = ctrlp->data;
412 int fd = ctrlp->fd;
901a2a3c 413 int rc = DISK_OK;
0a0bf5db 414 errno = errcode;
415 xfree(data);
4f92c80c 416 fd_bytes(fd, len, FD_READ);
0a0bf5db 417 if (len < 0) {
418 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
901a2a3c 419 commSetSelect(fd, COMM_SELECT_READ, diskHandleRead, ctrl_dat, 0);
de866d20 420 return;
0a0bf5db 421 }
901a2a3c 422 debug(50, 1) ("diskHandleRead: FD %d: %s\n", fd, xstrerror());
423 len = 0;
424 rc = DISK_ERROR;
090089c4 425 } else if (len == 0) {
901a2a3c 426 rc = DISK_EOF;
090089c4 427 }
901a2a3c 428 if (cbdataValid(ctrl_dat->client_data))
5d86029a 429 ctrl_dat->handler(fd, ctrl_dat->buf, len, rc, ctrl_dat->client_data);
901a2a3c 430 cbdataUnlock(ctrl_dat->client_data);
6a54c60e 431 safe_free(ctrl_dat);
090089c4 432}
433
434
435/* start read operation */
436/* buffer must be allocated from the caller.
437 * It must have at least req_len space in there.
438 * call handler when a reading is complete. */
b8d8561b 439int
d89d1fb6 440file_read(int fd, char *buf, int req_len, int offset, DRCB * handler, void *client_data)
090089c4 441{
442 dread_ctrl *ctrl_dat;
711982d8 443 assert(fd >= 0);
30a4f2a8 444 ctrl_dat = xcalloc(1, sizeof(dread_ctrl));
090089c4 445 ctrl_dat->fd = fd;
446 ctrl_dat->offset = offset;
447 ctrl_dat->req_len = req_len;
448 ctrl_dat->buf = buf;
090089c4 449 ctrl_dat->end_of_file = 0;
450 ctrl_dat->handler = handler;
451 ctrl_dat->client_data = client_data;
901a2a3c 452 cbdataLock(client_data);
0a0bf5db 453#if USE_ASYNC_IO
454 diskHandleRead(fd, ctrl_dat);
455#else
b177367b 456 commSetSelect(fd,
234967c9 457 COMM_SELECT_READ,
cd1fb0eb 458 diskHandleRead,
459 ctrl_dat,
b177367b 460 0);
0a0bf5db 461#endif
090089c4 462 return DISK_OK;
463}
464
b8d8561b 465int
466diskWriteIsComplete(int fd)
b59c7120 467{
95d15928 468 return fd_table[fd].disk.write_q ? 0 : 1;
0a21bd84 469}