dgaudet 97/08/18 00:19:39
Modified: htdocs/manual new_features_1_3.html
src CHANGES PORTING
src/core conf.h http_core.c http_protocol.c http_protocol.h
Log:
Added mmap() support for static files going through default_handler.
Revision Changes Path
1.18 +1 -1 apachen/htdocs/manual/new_features_1_3.html
Index: new_features_1_3.html
===================================================================
RCS file: /export/home/cvs/apachen/htdocs/manual/new_features_1_3.html,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -r1.17 -r1.18
--- new_features_1_3.html 1997/08/18 07:17:19 1.17
+++ new_features_1_3.html 1997/08/18 07:19:30 1.18
@@ -193,7 +193,7 @@
to issue multiple writes with a single system call. They also avoid
copying memory into buffers as much as possible. The result is
less CPU time spent on transferring large files.
- <li><i>XXX Incomplete:</i> Static requests are served using
+ <li>Static requests are served using
<code>mmap</code>, which means bytes are only copied from the
disk buffer to the network buffer directly by the kernel. The
program never copies bytes around, which reduces CPU time.
1.404 +7 -0 apachen/src/CHANGES
Index: CHANGES
===================================================================
RCS file: /export/home/cvs/apachen/src/CHANGES,v
retrieving revision 1.403
retrieving revision 1.404
diff -u -r1.403 -r1.404
--- CHANGES 1997/08/18 07:17:21 1.403
+++ CHANGES 1997/08/18 07:19:31 1.404
@@ -1,5 +1,12 @@
Changes with Apache 1.3a2
+ *) Various architectures now define USE_MMAP_FILES which causes
+ the server to use mmap() for static files. There are two
+ compile-time tunables MMAP_THRESHOLD (minimum number of bytes
+ required to use mmap(), default is 0), and MMAP_SEGMENT_SIZE (maximum
+ number of bytes written in one cycle from a single mmap()d object,
+ default 32768). [Dean Gaudet]
+
*) API: Added post_read_request API phase which is run right after reading
the request from a client, or right after an internal redirect. It is
useful for modules setting environment variables that depend only on
1.10 +5 -1 apachen/src/PORTING
Index: PORTING
===================================================================
RCS file: /export/home/cvs/apachen/src/PORTING,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- PORTING 1997/08/09 00:55:53 1.9
+++ PORTING 1997/08/18 07:19:32 1.10
@@ -171,7 +171,8 @@
HAVE_MMAP:
Define if the OS supports the BSD mmap() call. This is used by various
OSs to allow the scoreboard file to be held in shared mmapped-memory
- instead of a real file.
+ instead of a real file. Note that this is only used to determine
+ if mmap should be used for shared memory.
HAVE_SHMGET:
Define if the OS has the SysV-based shmget() family of shared-memory
@@ -213,6 +214,9 @@
USE_LONGJMP:
use the longjmp() call instead of siglongjmp()
(as well as setjmp() instead of sigsetjmp())
+
+ USE_MMAP_FILES:
+ Enable the use of mmap() for sending static files.
--
1.125 +12 -0 apachen/src/core/conf.h
Index: conf.h
===================================================================
RCS file: /export/home/cvs/apachen/src/core/conf.h,v
retrieving revision 1.124
retrieving revision 1.125
diff -u -r1.124 -r1.125
--- conf.h 1997/08/17 11:14:34 1.124
+++ conf.h 1997/08/18 07:19:34 1.125
@@ -85,6 +85,7 @@
char *mktemp(char *template);
#define JMP_BUF sigjmp_buf
#define HAVE_MMAP
+#define USE_MMAP_FILES
#include <sys/time.h>
#define NEED_STRERROR
typedef int rlim_t;
@@ -105,6 +106,7 @@
#define USE_PTHREAD_SERIALIZED_ACCEPT
#define NEED_UNION_SEMUN
#define HAVE_MMAP
+#define USE_MMAP_FILES
#define HAVE_CRYPT_H
int gethostname(char *name, int namelen);
@@ -118,6 +120,7 @@
/*#define USE_FCNTL_SERIALIZED_ACCEPT*/
#define USE_SYSVSEM_SERIALIZED_ACCEPT
#define HAVE_SHMGET
+#define USE_MMAP_FILES
#define HAVE_CRYPT_H
#define NO_LONG_DOUBLE
#define HAVE_BSTRING_H
@@ -158,6 +161,7 @@
#define JMP_BUF sigjmp_buf
#ifndef __ps2__
#define HAVE_MMAP
+#define USE_MMAP_FILES
#define DEFAULT_GROUP "nobody"
#endif
#define DEFAULT_USER "nobody"
@@ -183,6 +187,7 @@
#undef NO_SETSID
#define JMP_BUF sigjmp_buf
#define HAVE_MMAP
+#define USE_MMAP_FILES
#define HAVE_CRYPT_H
#define NO_LONG_DOUBLE
@@ -192,6 +197,7 @@
#undef NO_SETSID
#define JMP_BUF sigjmp_buf
#define HAVE_MMAP
+#define USE_MMAP_FILES
#define HAVE_CRYPT_H
#define NO_LONG_DOUBLE
typedef int rlim_t;
@@ -271,6 +277,7 @@
#define NET_SIZE_T size_t
#endif
#define HAVE_SHMGET
+#define USE_MMAP_FILES
#define HAVE_SYS_RESOURCE_H
typedef int rlim_t;
/* flock is faster ... but hasn't been tested on 1.x systems */
@@ -302,6 +309,7 @@
#define HAVE_SYS_SELECT_H
#define USE_FCNTL_SERIALIZED_ACCEPT
#define HAVE_MMAP
+#define USE_MMAP_FILES
#define HAVE_SYS_RESOURCE_H
#define SecureWare
@@ -366,6 +374,7 @@
#define JMP_BUF sigjmp_buf
#define HAVE_RESOURCE
#define HAVE_MMAP
+#define USE_MMAP_FILES
#define HAVE_SHMGET
#define HAVE_CRYPT_H
#define HAVE_SYS_SELECT_H
@@ -421,6 +430,7 @@
#undef NO_SETSID
#define JMP_BUF sigjmp_buf
#define HAVE_MMAP
+#define USE_MMAP_FILES
#define DEFAULT_USER "nobody"
#define DEFAULT_GROUP "nogroup"
#if defined(__bsdi__) || \
@@ -469,6 +479,7 @@
#define JMP_BUF sigjmp_buf
#define USE_FCNTL_SERIALIZED_ACCEPT
#define HAVE_MMAP
+#define USE_MMAP_FILES
#define HAVE_CRYPT_H
#elif defined(__EMX__)
@@ -510,6 +521,7 @@
#undef NO_SETSID
#undef NEED_STRDUP
#define HAVE_MMAP
+#define USE_MMAP_FILES
#define NO_TIMEZONE
#include <stdio.h>
1.112 +104 -13 apachen/src/core/http_core.c
Index: http_core.c
===================================================================
RCS file: /export/home/cvs/apachen/src/core/http_core.c,v
retrieving revision 1.111
retrieving revision 1.112
diff -u -r1.111 -r1.112
--- http_core.c 1997/08/17 20:21:36 1.111
+++ http_core.c 1997/08/18 07:19:34 1.112
@@ -64,6 +64,28 @@
#include "scoreboard.h"
#include "fnmatch.h"
+#ifdef USE_MMAP_FILES
+#include <unistd.h>
+#include <sys/mman.h>
+
+/* mmap support for static files based on ideas from John Heidemann's
+ * patch against 1.0.5. See
+ * <http://www.isi.edu/~johnh/SOFTWARE/APACHE/index.html>.
+ */
+
+/* Files have to be at least this big before they're mmap()d. This is to
+ * deal with systems where the expense of doing an mmap() and an munmap()
+ * outweighs the benefit for small files.
+ */
+#ifndef MMAP_THRESHOLD
+#ifdef SUNOS4
+#define MMAP_THRESHOLD (8*1024)
+#else
+#define MMAP_THRESHOLD 0
+#endif
+#endif
+#endif
+
/* Server core module... This module provides support for really basic
* server operations, including options and commands which control the
* operation of other modules. Consider this the bureaucracy module.
@@ -1500,6 +1522,20 @@
int do_nothing (request_rec *r) { return OK; }
+#ifdef USE_MMAP_FILES
+struct mmap {
+ void *mm;
+ size_t length;
+};
+
+static void mmap_cleanup (void *mmv)
+{
+ struct mmap *mmd = mmv;
+
+ munmap(mmd->mm, mmd->length);
+}
+#endif
+
/*
* Default handler for MIME types without other handlers. Only GET
* and OPTIONS at this point... anyone who wants to write a generic
@@ -1514,6 +1550,9 @@
(core_dir_config *)get_module_config(r->per_dir_config, &core_module);
int rangestatus, errstatus;
FILE *f;
+#ifdef USE_MMAP_FILES
+ caddr_t mm;
+#endif
/* This handler has no use for a request body (yet), but we still
* need to read and discard it if the client sent one.
@@ -1555,24 +1594,76 @@
|| (errstatus = set_content_length (r, r->finfo.st_size)))
return errstatus;
- if (d->content_md5 & 1) {
- table_set (r->headers_out, "Content-MD5", md5digest(r->pool, f));
+#ifdef USE_MMAP_FILES
+ block_alarms();
+ if (r->finfo.st_size >= MMAP_THRESHOLD) {
+ /* we need to protect ourselves in case we die while we've got the
+ * file mmapped */
+ mm = mmap (NULL, r->finfo.st_size, PROT_READ, MAP_PRIVATE,
+ fileno(f), 0);
+ } else {
+ mm = (caddr_t)-1;
}
- rangestatus = set_byterange(r);
- send_http_header (r);
-
- if (!r->header_only) {
- if (!rangestatus)
- send_fd (f, r);
- else {
- long offset, length;
- while (each_byterange(r, &offset, &length)) {
- fseek(f, offset, SEEK_SET);
- send_fd_length(f, r, length);
+ if (mm == (caddr_t)-1) {
+ unblock_alarms();
+
+ log_unixerr ("mmap_handler", r->filename, "mmap failed", r->server);
+#endif
+
+ if (d->content_md5 & 1) {
+ table_set (r->headers_out, "Content-MD5", md5digest(r->pool, f));
+ }
+
+ rangestatus = set_byterange(r);
+ send_http_header (r);
+
+ if (!r->header_only) {
+ if (!rangestatus)
+ send_fd (f, r);
+ else {
+ long offset, length;
+ while (each_byterange(r, &offset, &length)) {
+ fseek(f, offset, SEEK_SET);
+ send_fd_length(f, r, length);
+ }
+ }
+ }
+
+#ifdef USE_MMAP_FILES
+ } else {
+ struct mmap *mmd;
+
+ mmd = palloc (r->pool, sizeof (*mmd));
+ mmd->mm = mm;
+ mmd->length = r->finfo.st_size;
+ register_cleanup (r->pool, (void *)mmd, mmap_cleanup, mmap_cleanup);
+ unblock_alarms();
+
+ if (d->content_md5 & 1) {
+ MD5_CTX context;
+
+ MD5Init(&context);
+ MD5Update(&context, (void *)mm, r->finfo.st_size);
+ table_set (r->headers_out, "Content-MD5",
+ md5contextTo64(r->pool, &context));
+ }
+
+ rangestatus = set_byterange(r);
+ send_http_header (r);
+
+ if (!r->header_only) {
+ if (!rangestatus)
+ send_mmap (mm, r, 0, r->finfo.st_size);
+ else {
+ long offset, length;
+ while (each_byterange(r, &offset, &length)) {
+ send_mmap(mm, r, offset, length);
+ }
}
}
}
+#endif
pfclose(r->pool, f);
return OK;
1.155 +62 -0 apachen/src/core/http_protocol.c
Index: http_protocol.c
===================================================================
RCS file: /export/home/cvs/apachen/src/core/http_protocol.c,v
retrieving revision 1.154
retrieving revision 1.155
diff -u -r1.154 -r1.155
--- http_protocol.c 1997/08/18 07:17:26 1.154
+++ http_protocol.c 1997/08/18 07:19:36 1.155
@@ -1762,6 +1762,68 @@
return total_bytes_sent;
}
+
+
+/* The code writes MMAP_SEGMENT_SIZE bytes at a time. This is due to
Apache's
+ * timeout model, which is a timeout per-write rather than a time for the
+ * entire transaction to complete. Essentially this should be small enough
+ * so that in one Timeout period, your slowest clients should be reasonably
+ * able to receive this many bytes.
+ */
+#ifndef MMAP_SEGMENT_SIZE
+#define MMAP_SEGMENT_SIZE 32768
+#endif
+
+/* send data from an in-memory buffer */
+API_EXPORT(size_t) send_mmap(void * mm, request_rec *r, size_t offset,
+ size_t length)
+{
+ size_t total_bytes_sent = 0;
+ int n, w;
+
+ if (length == 0) return 0;
+
+ soft_timeout("send mmap", r);
+
+ length += offset;
+ while (!r->connection->aborted && offset < length) {
+ if (length - offset > MMAP_SEGMENT_SIZE) {
+ n = MMAP_SEGMENT_SIZE;
+ } else {
+ n = length - offset;
+ }
+
+ while (n && !r->connection->aborted) {
+ w = bwrite(r->connection->client, (char *)mm + offset, n);
+ if (w > 0) {
+ reset_timeout(r); /* reset timeout after successful write */
+ total_bytes_sent += w;
+ n -= w;
+ offset += w;
+ }
+ else if (w < 0) {
+ if (r->connection->aborted)
+ break;
+ else if (errno == EAGAIN)
+ continue;
+ else {
+ log_unixerr("send mmap lost connection to",
+ get_remote_host(r->connection,
+ r->per_dir_config, REMOTE_NAME),
+ NULL, r->server);
+ bsetflag(r->connection->client, B_EOUT, 1);
+ r->connection->aborted = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ kill_timeout(r);
+ SET_BYTES_SENT(r);
+ return total_bytes_sent;
+}
+
API_EXPORT(int) rputc (int c, request_rec *r)
{
if (r->connection->aborted) return EOF;
1.26 +3 -0 apachen/src/core/http_protocol.h
Index: http_protocol.h
===================================================================
RCS file: /export/home/cvs/apachen/src/core/http_protocol.h,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -r1.25 -r1.26
--- http_protocol.h 1997/07/24 04:23:59 1.25
+++ http_protocol.h 1997/08/18 07:19:36 1.26
@@ -113,6 +113,9 @@
API_EXPORT(long) send_fb(BUFF *f, request_rec *r);
API_EXPORT(long) send_fb_length(BUFF *f, request_rec *r, long length);
+
+API_EXPORT(size_t) send_mmap(void *mm, request_rec *r, size_t offset,
+ size_t length);
/* Hmmm... could macrofy these for now, and maybe forever, though the
* definitions of the macros would get a whole lot hairier.