/*
- * $Id: async_io.cc,v 1.1 2000/05/03 17:15:46 adrian Exp $
+ * $Id: async_io.cc,v 1.22 2003/01/23 00:38:09 robertc Exp $
*
* DEBUG: section 32 Asynchronous Disk I/O
* AUTHOR: Pete Bentley <pete@demon.net>
* AUTHOR: Stewart Forster <slf@connect.com.au>
*
- * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
+ * SQUID Web Proxy Cache http://www.squid-cache.org/
* ----------------------------------------------------------
*
- * Squid is the result of efforts by numerous individuals from the
- * Internet community. Development is led by Duane Wessels of the
- * National Laboratory for Applied Network Research and funded by the
- * National Science Foundation. Squid is Copyrighted (C) 1998 by
- * Duane Wessels and the University of California San Diego. Please
- * see the COPYRIGHT file for full details. Squid incorporates
- * software developed and/or copyrighted by other sources. Please see
- * the CREDITS file for full details.
+ * Squid is the result of efforts by numerous individuals from
+ * the Internet community; see the CONTRIBUTORS file for full
+ * details. Many organizations have provided support for Squid's
+ * development; see the SPONSORS file for full details. Squid is
+ * Copyrighted (C) 2001 by the Regents of the University of
+ * California; see the COPYRIGHT file for full details. Squid
+ * incorporates software developed and/or copyrighted by other
+ * sources; see the CREDITS file for full details.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include "squid.h"
#include "store_asyncufs.h"
+#include "Store.h"
+#include "fde.h"
#define _AIO_OPEN 0
#define _AIO_READ 1
#define _AIO_WRITE 2
#define _AIO_CLOSE 3
#define _AIO_UNLINK 4
+#define _AIO_TRUNCATE 4
#define _AIO_OPENDIR 5
#define _AIO_STAT 6
-typedef struct aio_ctrl_t {
- struct aio_ctrl_t *next;
+typedef struct squidaio_ctrl_t {
+ struct squidaio_ctrl_t *next;
int fd;
int operation;
AIOCB *done_handler;
void *done_handler_data;
- aio_result_t result;
-} aio_ctrl_t;
-
-struct {
- int open;
- int close;
+ squidaio_result_t result;
+ int len;
+ char *bufp;
+ FREE *free_func;
+ dlink_node node;
+} squidaio_ctrl_t;
+
+static struct {
+ int open_start;
+ int open_finish;
+ int close_start;
+ int close_finish;
int cancel;
- int write;
- int read;
- int stat;
- int unlink;
+ int write_start;
+ int write_finish;
+ int read_start;
+ int read_finish;
+ int stat_start;
+ int stat_finish;
+ int unlink_start;
+ int unlink_finish;
int check_callback;
-} aio_counts;
+} squidaio_counts;
-typedef struct aio_unlinkq_t {
+typedef struct squidaio_unlinkq_t {
char *path;
- struct aio_unlinkq_t *next;
-} aio_unlinkq_t;
+ struct squidaio_unlinkq_t *next;
+} squidaio_unlinkq_t;
-static aio_ctrl_t *used_list = NULL;
+static dlink_list used_list;
static int initialised = 0;
static OBJH aioStats;
-static MemPool *aio_ctrl_pool;
+static MemPool *squidaio_ctrl_pool;
static void aioFDWasClosed(int fd);
-MemPool * aio_state_pool;
-
static void
aioFDWasClosed(int fd)
{
fd_close(fd);
}
+
void
aioInit(void)
{
if (initialised)
return;
- aio_ctrl_pool = memPoolCreate("aio_ctrl", sizeof(aio_ctrl_t));
- aio_state_pool = memPoolCreate("Async UFS IO State data", sizeof(aiostate_t));
- cachemgrRegister("aio_counts", "Async IO Function Counters",
+ squidaio_ctrl_pool = memPoolCreate("aio_ctrl", sizeof(squidaio_ctrl_t));
+ cachemgrRegister("squidaio_counts", "Async IO Function Counters",
aioStats, 0, 1);
initialised = 1;
- comm_quick_poll_required();
}
void
aioDone(void)
{
- memPoolDestroy(aio_ctrl_pool);
- memPoolDestroy(aio_state_pool);
+ memPoolDestroy(&squidaio_ctrl_pool);
initialised = 0;
}
void
aioOpen(const char *path, int oflag, mode_t mode, AIOCB * callback, void *callback_data)
{
- aio_ctrl_t *ctrlp;
- int ret;
+ squidaio_ctrl_t *ctrlp;
assert(initialised);
- aio_counts.open++;
- ctrlp = memPoolAlloc(aio_ctrl_pool);
+ squidaio_counts.open_start++;
+ ctrlp = (squidaio_ctrl_t *)memPoolAlloc(squidaio_ctrl_pool);
ctrlp->fd = -2;
ctrlp->done_handler = callback;
- ctrlp->done_handler_data = callback_data;
+ ctrlp->done_handler_data = cbdataReference(callback_data);
ctrlp->operation = _AIO_OPEN;
- cbdataLock(callback_data);
- if (aio_open(path, oflag, mode, &ctrlp->result) < 0) {
- ret = open(path, oflag, mode);
- if (callback)
- (callback) (ctrlp->fd, callback_data, ret, errno);
- cbdataUnlock(callback_data);
- memPoolFree(aio_ctrl_pool, ctrlp);
- return;
- }
- ctrlp->next = used_list;
- used_list = ctrlp;
+ ctrlp->result.data = ctrlp;
+ squidaio_open(path, oflag, mode, &ctrlp->result);
+ dlinkAdd(ctrlp, &ctrlp->node, &used_list);
return;
}
void
aioClose(int fd)
{
- aio_ctrl_t *ctrlp;
+ squidaio_ctrl_t *ctrlp;
assert(initialised);
- aio_counts.close++;
+ squidaio_counts.close_start++;
aioCancel(fd);
- ctrlp = memPoolAlloc(aio_ctrl_pool);
+ ctrlp = (squidaio_ctrl_t *)memPoolAlloc(squidaio_ctrl_pool);
ctrlp->fd = fd;
ctrlp->done_handler = NULL;
ctrlp->done_handler_data = NULL;
ctrlp->operation = _AIO_CLOSE;
- if (aio_close(fd, &ctrlp->result) < 0) {
- close(fd); /* Can't create thread - do a normal close */
- memPoolFree(aio_ctrl_pool, ctrlp);
- aioFDWasClosed(fd);
- return;
- }
- ctrlp->next = used_list;
- used_list = ctrlp;
+ ctrlp->result.data = ctrlp;
+ squidaio_close(fd, &ctrlp->result);
+ dlinkAdd(ctrlp, &ctrlp->node, &used_list);
return;
}
void
aioCancel(int fd)
{
- aio_ctrl_t *curr;
- aio_ctrl_t *prev;
- aio_ctrl_t *next;
- AIOCB *done_handler;
- void *their_data;
+ squidaio_ctrl_t *ctrlp;
+ dlink_node *m, *next;
assert(initialised);
- aio_counts.cancel++;
- prev = NULL;
- curr = used_list;
- for (curr = used_list;; curr = next) {
- while (curr != NULL) {
- if (curr->fd == fd)
- break;
- prev = curr;
- curr = curr->next;
- }
- if (curr == NULL)
- break;
+ squidaio_counts.cancel++;
+ for (m = used_list.head; m; m = next) {
+ next = m->next;
+ ctrlp = (squidaio_ctrl_t *)m->data;
+ if (ctrlp->fd != fd)
+ continue;
- aio_cancel(&curr->result);
+ squidaio_cancel(&ctrlp->result);
- if ((done_handler = curr->done_handler)) {
- their_data = curr->done_handler_data;
- curr->done_handler = NULL;
- curr->done_handler_data = NULL;
- debug(0, 0) ("this be aioCancel\n");
- if (cbdataValid(their_data))
- done_handler(fd, their_data, -2, -2);
- cbdataUnlock(their_data);
+ if (ctrlp->done_handler) {
+ AIOCB *callback = ctrlp->done_handler;
+ void *cbdata;
+ ctrlp->done_handler = NULL;
+ debug(32, 1) ("this be aioCancel. Danger ahead!\n");
+ if (cbdataReferenceValidDone(ctrlp->done_handler_data, &cbdata))
+ callback(fd, cbdata, NULL, -2, -2);
+ /* free data if requested to aioWrite() */
+ if (ctrlp->free_func)
+ ctrlp->free_func(ctrlp->bufp);
+ /* free temporary read buffer */
+ if (ctrlp->operation == _AIO_READ)
+ squidaio_xfree(ctrlp->bufp, ctrlp->len);
}
- next = curr->next;
- if (prev == NULL)
- used_list = next;
- else
- prev->next = next;
-
- memPoolFree(aio_ctrl_pool, curr);
+ dlinkDelete(m, &used_list);
+ memPoolFree(squidaio_ctrl_pool, ctrlp);
}
}
void
aioWrite(int fd, int offset, char *bufp, int len, AIOCB * callback, void *callback_data, FREE * free_func)
{
- aio_ctrl_t *ctrlp;
+ squidaio_ctrl_t *ctrlp;
int seekmode;
assert(initialised);
- aio_counts.write++;
- for (ctrlp = used_list; ctrlp != NULL; ctrlp = ctrlp->next)
- if (ctrlp->fd == fd)
- break;
- if (ctrlp != NULL) {
- debug(0, 0) ("aioWrite: EWOULDBLOCK\n");
- errno = EWOULDBLOCK;
- if (callback)
- (callback) (fd, callback_data, -1, errno);
- if (free_func)
- free_func(bufp);
- return;
- }
- ctrlp = memPoolAlloc(aio_ctrl_pool);
+ squidaio_counts.write_start++;
+ ctrlp = (squidaio_ctrl_t *)memPoolAlloc(squidaio_ctrl_pool);
ctrlp->fd = fd;
ctrlp->done_handler = callback;
- ctrlp->done_handler_data = callback_data;
+ ctrlp->done_handler_data = cbdataReference(callback_data);
ctrlp->operation = _AIO_WRITE;
+ ctrlp->bufp = bufp;
+ ctrlp->free_func = free_func;
if (offset >= 0)
seekmode = SEEK_SET;
else {
seekmode = SEEK_END;
offset = 0;
}
- cbdataLock(callback_data);
- if (aio_write(fd, bufp, len, offset, seekmode, &ctrlp->result) < 0) {
- if (errno == ENOMEM || errno == EAGAIN || errno == EINVAL)
- errno = EWOULDBLOCK;
- if (callback)
- (callback) (fd, callback_data, -1, errno);
- cbdataUnlock(callback_data);
- memPoolFree(aio_ctrl_pool, ctrlp);
- } else {
- ctrlp->next = used_list;
- used_list = ctrlp;
- }
- /*
- * aio_write copies the buffer so we can free it here
- */
- if (free_func)
- free_func(bufp);
+ ctrlp->result.data = ctrlp;
+ squidaio_write(fd, bufp, len, offset, seekmode, &ctrlp->result);
+ dlinkAdd(ctrlp, &ctrlp->node, &used_list);
} /* aioWrite */
void
-aioRead(int fd, int offset, char *bufp, int len, AIOCB * callback, void *callback_data)
+aioRead(int fd, int offset, int len, AIOCB * callback, void *callback_data)
{
- aio_ctrl_t *ctrlp;
+ squidaio_ctrl_t *ctrlp;
int seekmode;
assert(initialised);
- aio_counts.read++;
- for (ctrlp = used_list; ctrlp != NULL; ctrlp = ctrlp->next)
- if (ctrlp->fd == fd)
- break;
- if (ctrlp != NULL) {
- errno = EWOULDBLOCK;
- if (callback)
- (callback) (fd, callback_data, -1, errno);
- return;
- }
- ctrlp = memPoolAlloc(aio_ctrl_pool);
+ squidaio_counts.read_start++;
+ ctrlp = (squidaio_ctrl_t *)memPoolAlloc(squidaio_ctrl_pool);
ctrlp->fd = fd;
ctrlp->done_handler = callback;
- ctrlp->done_handler_data = callback_data;
+ ctrlp->done_handler_data = cbdataReference(callback_data);
ctrlp->operation = _AIO_READ;
+ ctrlp->len = len;
+ ctrlp->bufp = (char *)squidaio_xmalloc(len);
if (offset >= 0)
seekmode = SEEK_SET;
else {
seekmode = SEEK_CUR;
offset = 0;
}
- cbdataLock(callback_data);
- if (aio_read(fd, bufp, len, offset, seekmode, &ctrlp->result) < 0) {
- if (errno == ENOMEM || errno == EAGAIN || errno == EINVAL)
- errno = EWOULDBLOCK;
- if (callback)
- (callback) (fd, callback_data, -1, errno);
- cbdataUnlock(callback_data);
- memPoolFree(aio_ctrl_pool, ctrlp);
- return;
- }
- ctrlp->next = used_list;
- used_list = ctrlp;
+ ctrlp->result.data = ctrlp;
+ squidaio_read(fd, ctrlp->bufp, len, offset, seekmode, &ctrlp->result);
+ dlinkAdd(ctrlp, &ctrlp->node, &used_list);
return;
} /* aioRead */
void
aioStat(char *path, struct stat *sb, AIOCB * callback, void *callback_data)
{
- aio_ctrl_t *ctrlp;
+ squidaio_ctrl_t *ctrlp;
assert(initialised);
- aio_counts.stat++;
- ctrlp = memPoolAlloc(aio_ctrl_pool);
+ squidaio_counts.stat_start++;
+ ctrlp = (squidaio_ctrl_t *)memPoolAlloc(squidaio_ctrl_pool);
ctrlp->fd = -2;
ctrlp->done_handler = callback;
- ctrlp->done_handler_data = callback_data;
+ ctrlp->done_handler_data = cbdataReference(callback_data);
ctrlp->operation = _AIO_STAT;
- cbdataLock(callback_data);
- if (aio_stat(path, sb, &ctrlp->result) < 0) {
- if (errno == ENOMEM || errno == EAGAIN || errno == EINVAL)
- errno = EWOULDBLOCK;
- if (callback)
- (callback) (ctrlp->fd, callback_data, -1, errno);
- cbdataUnlock(callback_data);
- memPoolFree(aio_ctrl_pool, ctrlp);
- return;
- }
- ctrlp->next = used_list;
- used_list = ctrlp;
+ ctrlp->result.data = ctrlp;
+ squidaio_stat(path, sb, &ctrlp->result);
+ dlinkAdd(ctrlp, &ctrlp->node, &used_list);
return;
} /* aioStat */
void
-aioUnlink(const char *pathname, AIOCB * callback, void *callback_data)
+aioUnlink(const char *path, AIOCB * callback, void *callback_data)
{
- aio_ctrl_t *ctrlp;
- char *path;
+ squidaio_ctrl_t *ctrlp;
assert(initialised);
- aio_counts.unlink++;
- ctrlp = memPoolAlloc(aio_ctrl_pool);
+ squidaio_counts.unlink_start++;
+ ctrlp = (squidaio_ctrl_t *)memPoolAlloc(squidaio_ctrl_pool);
ctrlp->fd = -2;
ctrlp->done_handler = callback;
- ctrlp->done_handler_data = callback_data;
+ ctrlp->done_handler_data = cbdataReference(callback_data);
ctrlp->operation = _AIO_UNLINK;
- path = xstrdup(pathname);
- cbdataLock(callback_data);
- if (aio_unlink(path, &ctrlp->result) < 0) {
- int ret = unlink(path);
- (callback) (ctrlp->fd, callback_data, ret, errno);
- cbdataUnlock(callback_data);
- memPoolFree(aio_ctrl_pool, ctrlp);
- xfree(path);
- return;
- }
- ctrlp->next = used_list;
- used_list = ctrlp;
- xfree(path);
+ ctrlp->result.data = ctrlp;
+ squidaio_unlink(path, &ctrlp->result);
+ dlinkAdd(ctrlp, &ctrlp->node, &used_list);
} /* aioUnlink */
-
void
-aioCheckCallbacks(SwapDir *SD)
+aioTruncate(const char *path, off_t length, AIOCB * callback, void *callback_data)
{
- aio_result_t *resultp;
- aio_ctrl_t *ctrlp;
- aio_ctrl_t *prev;
- AIOCB *done_handler;
- void *their_data;
+ squidaio_ctrl_t *ctrlp;
+ assert(initialised);
+ squidaio_counts.unlink_start++;
+ ctrlp = (squidaio_ctrl_t *)memPoolAlloc(squidaio_ctrl_pool);
+ ctrlp->fd = -2;
+ ctrlp->done_handler = callback;
+ ctrlp->done_handler_data = cbdataReference(callback_data);
+ ctrlp->operation = _AIO_TRUNCATE;
+ ctrlp->result.data = ctrlp;
+ squidaio_truncate(path, length, &ctrlp->result);
+ dlinkAdd(ctrlp, &ctrlp->node, &used_list);
+} /* aioTruncate */
+
+
+int
+AUFSSwapDir::callback()
+{
+ squidaio_result_t *resultp;
+ squidaio_ctrl_t *ctrlp;
+ int retval = 0;
assert(initialised);
- aio_counts.check_callback++;
+ squidaio_counts.check_callback++;
for (;;) {
- if ((resultp = aio_poll_done()) == NULL)
+ if ((resultp = squidaio_poll_done()) == NULL)
+ break;
+ ctrlp = (squidaio_ctrl_t *) resultp->data;
+ switch (resultp->result_type) {
+ case _AIO_OP_NONE:
+ case _AIO_OP_TRUNCATE:
+ case _AIO_OP_OPENDIR:
+ break;
+ case _AIO_OP_OPEN:
+ ++squidaio_counts.open_finish;
+ break;
+ case _AIO_OP_READ:
+ ++squidaio_counts.read_finish;
+ break;
+ case _AIO_OP_WRITE:
+ ++squidaio_counts.write_finish;
break;
- prev = NULL;
- for (ctrlp = used_list; ctrlp != NULL; prev = ctrlp, ctrlp = ctrlp->next)
- if (&ctrlp->result == resultp)
- break;
+ case _AIO_OP_CLOSE:
+ ++squidaio_counts.close_finish;
+ break;
+ case _AIO_OP_UNLINK:
+ ++squidaio_counts.unlink_finish;
+ break;
+ case _AIO_OP_STAT:
+ ++squidaio_counts.stat_finish;
+ break;
+ }
if (ctrlp == NULL)
- continue;
- if (prev == NULL)
- used_list = ctrlp->next;
- else
- prev->next = ctrlp->next;
- if ((done_handler = ctrlp->done_handler)) {
- their_data = ctrlp->done_handler_data;
+ continue; /* XXX Should not happen */
+ dlinkDelete(&ctrlp->node, &used_list);
+ if (ctrlp->done_handler) {
+ AIOCB *callback = ctrlp->done_handler;
+ void *cbdata;
ctrlp->done_handler = NULL;
- ctrlp->done_handler_data = NULL;
- if (cbdataValid(their_data))
- done_handler(ctrlp->fd, their_data,
+ if (cbdataReferenceValidDone(ctrlp->done_handler_data, &cbdata)) {
+ retval = 1; /* Return that we've actually done some work */
+ callback(ctrlp->fd, cbdata, ctrlp->bufp,
ctrlp->result.aio_return, ctrlp->result.aio_errno);
- cbdataUnlock(their_data);
+ } else {
+ if (ctrlp->operation == _AIO_OPEN) {
+ /* The open operation was aborted.. */
+ int fd = ctrlp->result.aio_return;
+ if (fd >= 0)
+ aioClose(fd);
+ }
+ }
}
+ /* free data if requested to aioWrite() */
+ if (ctrlp->free_func)
+ ctrlp->free_func(ctrlp->bufp);
+ /* free temporary read buffer */
+ if (ctrlp->operation == _AIO_READ)
+ squidaio_xfree(ctrlp->bufp, ctrlp->len);
if (ctrlp->operation == _AIO_CLOSE)
aioFDWasClosed(ctrlp->fd);
- memPoolFree(aio_ctrl_pool, ctrlp);
+ memPoolFree(squidaio_ctrl_pool, ctrlp);
}
+ return retval;
}
void
aioStats(StoreEntry * sentry)
{
storeAppendPrintf(sentry, "ASYNC IO Counters:\n");
- storeAppendPrintf(sentry, "open\t%d\n", aio_counts.open);
- storeAppendPrintf(sentry, "close\t%d\n", aio_counts.close);
- storeAppendPrintf(sentry, "cancel\t%d\n", aio_counts.cancel);
- storeAppendPrintf(sentry, "write\t%d\n", aio_counts.write);
- storeAppendPrintf(sentry, "read\t%d\n", aio_counts.read);
- storeAppendPrintf(sentry, "stat\t%d\n", aio_counts.stat);
- storeAppendPrintf(sentry, "unlink\t%d\n", aio_counts.unlink);
- storeAppendPrintf(sentry, "check_callback\t%d\n", aio_counts.check_callback);
- storeAppendPrintf(sentry, "queue\t%d\n", aio_get_queue_len());
+ storeAppendPrintf(sentry, "Operation\t# Requests\tNumber serviced\n");
+ storeAppendPrintf(sentry, "open\t%d\t%d\n", squidaio_counts.open_start, squidaio_counts.open_finish);
+ storeAppendPrintf(sentry, "close\t%d\t%d\n", squidaio_counts.close_start, squidaio_counts.close_finish);
+ storeAppendPrintf(sentry, "cancel\t%d\t-\n", squidaio_counts.cancel);
+ storeAppendPrintf(sentry, "write\t%d\t%d\n", squidaio_counts.write_start, squidaio_counts.write_finish);
+ storeAppendPrintf(sentry, "read\t%d\t%d\n", squidaio_counts.read_start, squidaio_counts.read_finish);
+ storeAppendPrintf(sentry, "stat\t%d\t%d\n", squidaio_counts.stat_start, squidaio_counts.stat_finish);
+ storeAppendPrintf(sentry, "unlink\t%d\t%d\n", squidaio_counts.unlink_start, squidaio_counts.unlink_finish);
+ storeAppendPrintf(sentry, "check_callback\t%d\t-\n", squidaio_counts.check_callback);
+ storeAppendPrintf(sentry, "queue\t%d\t-\n", squidaio_get_queue_len());
}
/* Flush all pending I/O */
void
-aioSync(SwapDir *SD)
+AUFSSwapDir::sync()
{
if (!initialised)
return; /* nothing to do then */
/* Flush all pending operations */
debug(32, 1) ("aioSync: flushing pending I/O operations\n");
do {
- aioCheckCallbacks(SD);
- } while (aio_sync());
+ callback();
+ } while (squidaio_sync());
debug(32, 1) ("aioSync: done\n");
}
int
aioQueueSize(void)
{
- return memPoolInUseCount(aio_ctrl_pool);
+ return memPoolInUseCount(squidaio_ctrl_pool);
}