Index: src/Makefile.am
===================================================================
RCS file: /server/cvs-server/squid/squid/src/Makefile.am,v
retrieving revision 1.51
diff -u -r1.51 Makefile.am
--- src/Makefile.am	11 Jun 2006 17:06:25 -0000	1.51
+++ src/Makefile.am	16 Jul 2006 13:41:40 -0000
@@ -44,6 +44,8 @@
 UNLINKD = 
 endif
 
+LOGFILE_DAEMON = logfile_daemon
+
 if ENABLE_PINGER
 PINGER = pinger
 else
@@ -84,6 +86,7 @@
 
 EXTRA_PROGRAMS = \
 	unlinkd \
+	logfile_daemon \
 	pinger \
 	dnsserver
 
@@ -96,6 +99,7 @@
 libexec_PROGRAMS = \
 	$(PINGER) \
 	$(DNSSERVER) \
+	$(LOGFILE_DAEMON) \
 	$(UNLINKD)
 
 cf_gen_SOURCES = cf_gen.c defines.h debug.c
@@ -257,6 +261,11 @@
 unlinkd-daemon.o: unlinkd.c
 	$(COMPILE) -DUNLINK_DAEMON -c $(srcdir)/unlinkd.c -o $@
 
+logfile_daemon_SOURCES = logfile_daemon.c
+logfile_daemon.o: logfile_daemon.c
+	$(COMPILE) -c $(srcdir)/logfile_daemon.c -o $@
+
+
 pinger_SOURCES = \
 	pinger.c \
 	debug.c
@@ -307,6 +316,7 @@
 DEFAULT_SWAP_DIR        = $(localstatedir)/cache
 DEFAULT_PINGER		= $(libexecdir)/`echo pinger | sed '$(transform);s/$$/$(EXEEXT)/'`
 DEFAULT_UNLINKD		= $(libexecdir)/`echo unlinkd | sed '$(transform);s/$$/$(EXEEXT)/'`
+DEFAULT_LOGFILE_DAEMON	= $(libexecdir)/`echo logfile_daemon | sed '$(transform);s/$$/$(EXEEXT)/'`
 DEFAULT_DISKD		= $(libexecdir)/`echo diskd_daemon | sed '$(transform);s/$$/$(EXEEXT)/'`
 DEFAULT_ICON_DIR	= $(datadir)/icons
 DEFAULT_ERROR_DIR	= $(datadir)/errors/@ERR_DEFAULT_LANGUAGE@
@@ -353,6 +363,7 @@
 	s%@DEFAULT_MIME_TABLE@%$(DEFAULT_MIME_TABLE)%g;\
 	s%@DEFAULT_DNSSERVER@%$(DEFAULT_DNSSERVER)%g;\
 	s%@DEFAULT_UNLINKD@%$(DEFAULT_UNLINKD)%g;\
+	s%@DEFAULT_LOGFILE_DAEMON@%$(DEFAULT_LOGFILE_DAEMON)%g;\
 	s%@DEFAULT_PINGER@%$(DEFAULT_PINGER)%g;\
 	s%@DEFAULT_DISKD@%$(DEFAULT_DISKD)%g;\
 	s%@DEFAULT_CACHE_LOG@%$(DEFAULT_CACHE_LOG)%g;\
Index: src/logfile.c
===================================================================
RCS file: /server/cvs-server/squid/squid/src/logfile.c,v
retrieving revision 1.16
diff -u -r1.16 logfile.c
--- src/logfile.c	5 Jun 2006 21:06:34 -0000	1.16
+++ src/logfile.c	16 Jul 2006 13:41:41 -0000
@@ -34,7 +34,7 @@
 
 #include "squid.h"
 
-static void logfileWriteWrapper(Logfile * lf, const void *buf, size_t len);
+#define	LOGFILE_BUFSZ	32768
 
 #if HAVE_SYSLOG
 
@@ -48,6 +48,7 @@
     int value;
 } syslog_symbol_t;
 
+
 static int
 syslog_ntoa(const char *s)
 {
@@ -115,15 +116,156 @@
 #define PRIORITY_MASK (LOG_ERR | LOG_WARNING | LOG_NOTICE | LOG_INFO | LOG_DEBUG)
 #endif /* HAVE_SYSLOG */
 
+/* Internal code */
+static void
+logfileNewBuffer(Logfile *lf)
+{
+	logfile_buffer_t *b;
+
+	debug(50, 3) ("logfileNewBuffer: %s: new buffer\n", lf->path);
+
+	b = xcalloc(1, sizeof(logfile_buffer_t));
+	assert(b != NULL);
+	b->buf = xcalloc(1, LOGFILE_BUFSZ);
+	assert(b->buf != NULL);
+	b->size = LOGFILE_BUFSZ;
+	b->written_len = 0;
+	b->len = 0;
+	b->full = 0;
+	dlinkAddTail(b, &b->node, &lf->bufs);
+	lf->nbufs++;
+}
+
+static void
+logfileFreeBuffer(Logfile *lf, logfile_buffer_t *b)
+{
+	assert(b != NULL);
+	dlinkDelete(&b->node, &lf->bufs);
+	lf->nbufs --;
+	xfree(b->buf);
+	xfree(b);
+}
+
+static void
+logfileHandleWrite(int fd, void *data)
+{
+	Logfile *lf = (Logfile *) data;
+	int ret;
+	logfile_buffer_t *b;
+
+	/*
+	 * We'll try writing the first entry until its done - if we
+	 * get a partial write then we'll re-schedule until its completed.
+	 * Its naive but it'll do for now.
+	 */
+	b = lf->bufs.head->data;
+	assert (b != NULL);
+	lf->flush_pending = 0;
+
+	ret = FD_WRITE_METHOD(lf->wfd, b->buf + b->written_len, b->len - b->written_len);
+	debug(50, 3) ("logfileHandleWrite: %s: write returned %d\n", lf->path, ret);
+	if (ret < 0) {
+		if (ignoreErrno(errno)) {
+			/* something temporary */
+			goto reschedule;
+		}
+		debug(50, 1) ("logfileHandleWrite: %s: error writing (%s)\n", lf->path, xstrerror());
+		/* XXX should handle this better */
+		fatal("I don't handle this error well!");
+	}
+	if (ret == 0) {
+		/* error? */
+		debug(50, 1) ("logfileHandleWrite: %s: wrote 0 bytes?\n", lf->path);
+		/* XXX should handle this better */
+		fatal("I don't handle this error well!");
+	}
+
+	/* ret > 0, so something was written */
+	b->written_len += ret;
+	assert(b->written_len <= b->len);
+	if (b->written_len == b->len) {
+		/* written the whole buffer! */
+		logfileFreeBuffer(lf, b);
+		b = NULL;
+	}
+	/* Is there more to write? */
+	if (lf->bufs.head == NULL) {
+		goto finish;
+	}
+	/* there is, so schedule more */
+
+reschedule:
+	commSetSelect(lf->wfd, COMM_SELECT_WRITE, logfileHandleWrite, lf, 0);
+	lf->flush_pending = 1;
+finish:
+	return;
+}
+
+static void
+logfileQueueWrite(void *data)
+{
+	Logfile *lf = (Logfile *) data;
+	eventAdd("logfile_flush", logfileQueueWrite, lf, 1.0, 1);
+	if (lf->flush_pending || lf->bufs.head == NULL) {
+		return;
+	}
+	/* Ok, schedule a write-event */
+	commSetSelect(lf->wfd, COMM_SELECT_WRITE, logfileHandleWrite, lf, 0);
+	lf->flush_pending = 1;
+	debug(5, 2) ("logfileQueueWrite: %s: queue depth = %d\n", lf->path, lf->nbufs);
+}
+
+
+static void
+logfileAppend(Logfile *lf, char *buf, int len)
+{
+	logfile_buffer_t *b;
+	int s;
+
+	/* Is there a buffer? If not, create one */
+	if (lf->bufs.head == NULL) {
+		logfileNewBuffer(lf);
+	}
+	debug(50, 3) ("logfileAppend: %s: appending %d bytes\n", lf->path, len);
+	/* Copy what can be copied */
+	while (len > 0) {
+		b = lf->bufs.tail->data;
+		debug(50, 3) ("logfileAppend: current buffer has %d of %d bytes before append\n",  b->len, b->size);
+		s = XMIN(len, (b->size - b->len));
+		xmemcpy(b->buf + b->len, buf, s);
+		len = len - s;
+		buf = buf + s;
+		b->len = b->len + s;
+		assert(b->len <= LOGFILE_BUFSZ);
+		assert(len >= 0);
+		if (len > 0) {
+			logfileNewBuffer(lf);
+		}
+	}
+#if 0
+	if (lf->bufs.head != NULL) {
+		logfileQueueWrite(lf);
+	}
+#endif
+}
+
+
+/* External code */
+
+CBDATA_TYPE(Logfile);
 Logfile *
 logfileOpen(const char *path, size_t bufsz, int fatal_flag)
 {
-    Logfile *lf = xcalloc(1, sizeof(*lf));
+    Logfile *lf;
+    const char * args[3];
+    CBDATA_INIT_TYPE(Logfile);
+    lf = cbdataAlloc(Logfile);
     xstrncpy(lf->path, path, MAXPATHLEN);
 #if HAVE_SYSLOG
     if (strcmp(path, "syslog") == 0 || strncmp(path, "syslog:", 7) == 0) {
 	lf->flags.syslog = 1;
-	lf->fd = -1;
+	lf->rfd = -1;
+	lf->wfd = -1;
 	if (path[6] != '\0') {
 	    const char *priority = path + 7;
 	    char *facility = (char *) strchr(priority, '|');
@@ -138,29 +280,16 @@
     } else
 #endif
     {
-	int fd = file_open(path, O_WRONLY | O_CREAT | O_TEXT);
-	if (DISK_ERROR == fd) {
-	    if (ENOENT == errno && fatal_flag) {
-		fatalf("Cannot open '%s' because\n"
-		    "\tthe parent directory does not exist.\n"
-		    "\tPlease create the directory.\n", path);
-	    } else if (EACCES == errno && fatal_flag) {
-		fatalf("Cannot open '%s' for writing.\n"
-		    "\tThe parent directory must be writeable by the\n"
-		    "\tuser '%s', which is the cache_effective_user\n"
-		    "\tset in squid.conf.", path, Config.effectiveUser);
-	    } else {
-		debug(50, 1) ("logfileOpen: %s: %s\n", path, xstrerror());
-		safe_free(lf);
-		return NULL;
-	    }
-	}
-	lf->fd = fd;
-	if (bufsz > 0) {
-	    lf->buf = xmalloc(bufsz);
-	    lf->bufsz = bufsz;
-	}
+        args[0] = "logfile_daemon";
+        args[1] = path;
+        args[2] = NULL;
+        lf->lpid = ipcCreate(IPC_STREAM, "/home/adrian/work/squid/squid-2.6/src/logfile_daemon", args, "logfile_daemon", &lf->rfd, &lf->wfd);
+        if (lf->lpid < 0)
+	    fatal("Couldn't start logfile helper");
     }
+    lf->nbufs = 0;
+    eventAdd("logfile_flush", logfileQueueWrite, lf, 1.0, 1);
+
     if (fatal_flag)
 	lf->flags.fatal = 1;
     return lf;
@@ -170,50 +299,20 @@
 logfileClose(Logfile * lf)
 {
     logfileFlush(lf);
-    if (lf->fd >= 0)
-	file_close(lf->fd);
-    if (lf->buf)
-	xfree(lf->buf);
-    xfree(lf);
+    fd_close(lf->rfd);
+    fd_close(lf->wfd); /* Should kill the logfile process! */
+    eventDelete(logfileQueueWrite, lf);
+    cbdataFree(lf);
 }
 
 void
 logfileRotate(Logfile * lf)
 {
-#ifdef S_ISREG
-    struct stat sb;
-#endif
-    int i;
-    char from[MAXPATHLEN];
-    char to[MAXPATHLEN];
-    assert(lf->path);
-    if (lf->flags.syslog)
-	return;
-#ifdef S_ISREG
-    if (stat(lf->path, &sb) == 0)
-	if (S_ISREG(sb.st_mode) == 0)
-	    return;
-#endif
     debug(0, 1) ("logfileRotate: %s\n", lf->path);
-    /* Rotate numbers 0 through N up one */
-    for (i = Config.Log.rotateNumber; i > 1;) {
-	i--;
-	snprintf(from, MAXPATHLEN, "%s.%d", lf->path, i - 1);
-	snprintf(to, MAXPATHLEN, "%s.%d", lf->path, i);
-	xrename(from, to);
-    }
-    /* Rotate the current log to .0 */
-    logfileFlush(lf);
-    file_close(lf->fd);		/* always close */
-    if (Config.Log.rotateNumber > 0) {
-	snprintf(to, MAXPATHLEN, "%s.%d", lf->path, 0);
-	xrename(lf->path, to);
-    }
-    /* Reopen the log.  It may have been renamed "manually" */
-    lf->fd = file_open(lf->path, O_WRONLY | O_CREAT | O_TEXT);
-    if (DISK_ERROR == lf->fd && lf->flags.fatal) {
-	debug(50, 1) ("logfileRotate: %s: %s\n", lf->path, xstrerror());
-	fatalf("Cannot open %s: %s", lf->path, xstrerror());
+    if (lf->lpid > 0) {
+	if (kill(lf->lpid, SIGHUP) < 0) {
+	    debug(0, 1) ("logfileRotate: %s: couldn't contact logfile_daemon process: %s\n", lf->path, xstrerror());
+	}
     }
 }
 
@@ -226,22 +325,8 @@
 	return;
     }
 #endif
-    if (0 == lf->bufsz) {
-	/* buffering disabled */
-	logfileWriteWrapper(lf, buf, len);
-	return;
-    }
-    if (lf->offset > 0 && lf->offset + len > lf->bufsz)
-	logfileFlush(lf);
-    if (len > lf->bufsz) {
-	/* too big to fit in buffer */
-	logfileWriteWrapper(lf, buf, len);
-	return;
-    }
-    /* buffer it */
-    xmemcpy(lf->buf + lf->offset, buf, len);
-    lf->offset += len;
-    assert(lf->offset <= lf->bufsz);
+    /* Append this data to the end buffer; create a new one if needed */
+    logfileAppend(lf, buf, len);
 }
 
 void
@@ -277,25 +362,5 @@
 void
 logfileFlush(Logfile * lf)
 {
-    if (0 == lf->offset)
-	return;
-    logfileWriteWrapper(lf, lf->buf, (size_t) lf->offset);
-    lf->offset = 0;
-}
-
-/*
- * Aborts with fatal message if write() returns something other
- * than its length argument.
- */
-static void
-logfileWriteWrapper(Logfile * lf, const void *buf, size_t len)
-{
-    int s;
-    s = FD_WRITE_METHOD(lf->fd, buf, len);
-    fd_bytes(lf->fd, s, FD_WRITE);
-    if (s == len)
-	return;
-    if (!lf->flags.fatal)
-	return;
-    fatalf("logfileWrite: %s: %s\n", lf->path, xstrerror());
+    /* XXX unimplemented for now */
 }
Index: src/structs.h
===================================================================
RCS file: /server/cvs-server/squid/squid/src/structs.h,v
retrieving revision 1.491
diff -u -r1.491 structs.h
--- src/structs.h	5 Jul 2006 06:52:12 -0000	1.491
+++ src/structs.h	16 Jul 2006 13:41:53 -0000
@@ -553,6 +553,7 @@
 #if USE_UNLINKD
 	char *unlinkd;
 #endif
+	char *logfile_daemon;
 	char *diskd;
 #if USE_SSL
 	char *ssl_password;
@@ -2409,17 +2410,27 @@
     } shm;
 };
 
+struct _logfile_buffer {
+    char *buf;
+    int size;
+    int len;
+    int written_len;
+    int full;
+    dlink_node node;
+};
+
 struct _Logfile {
-    int fd;
+    int rfd, wfd;
     char path[MAXPATHLEN];
-    char *buf;
-    size_t bufsz;
-    ssize_t offset;
+    dlink_list bufs;
+    int nbufs;
     struct {
 	unsigned int fatal;
 	unsigned int syslog;
     } flags;
     int syslog_priority;
+    int flush_pending;
+    pid_t lpid;
 };
 
 struct _logformat {
Index: src/typedefs.h
===================================================================
RCS file: /server/cvs-server/squid/squid/src/typedefs.h,v
retrieving revision 1.148
diff -u -r1.148 typedefs.h
--- src/typedefs.h	5 Jul 2006 06:52:12 -0000	1.148
+++ src/typedefs.h	16 Jul 2006 13:41:54 -0000
@@ -213,6 +213,7 @@
 typedef struct _storefs_entry storefs_entry_t;
 typedef struct _storerepl_entry storerepl_entry_t;
 typedef struct _diskd_queue diskd_queue;
+typedef struct _logfile_buffer logfile_buffer_t;
 typedef struct _Logfile Logfile;
 typedef struct _logformat_token logformat_token;
 typedef struct _logformat logformat;
Index: src/cf.data.pre
===================================================================
RCS file: /server/cvs-server/squid/squid/src/cf.data.pre,v
retrieving revision 1.357
diff -u -r1.357 cf.data.pre
--- src/cf.data.pre	9 Jul 2006 14:39:31 -0000	1.357
+++ src/cf.data.pre	16 Jul 2006 13:42:18 -0000
@@ -1632,6 +1632,14 @@
 	Specify the location of the executable for file deletion process.
 DOC_END
 
+NAME: logfile_daemon_program
+TYPE: string
+DEFAULT: @DEFAULT_LOGFILE_DAEMON@
+LOC: Config.Program.logfile_daemon
+DOC_START
+	Specify the location of the executable for writing to logfiles.
+DOC_END
+
 NAME: pinger_program
 TYPE: string
 DEFAULT: @DEFAULT_PINGER@

