httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dean Gaudet <dgau...@arctic.org>
Subject [PATCH] USE_MMAP_FILES
Date Sun, 17 Aug 1997 02:49:44 GMT
Here is mmap integrated into the core.  Pretty much everything that
defined HAVE_MMAP I also defined USE_MMAP_FILES.  I also added
USE_MMAP_FILES for Linux 2.x and IRIX.

Tested on Linux 2.0.30 and IRIX 5.3. 

Dean

Index: htdocs/manual/new_features_1_3.html
===================================================================
RCS file: /export/home/cvs/apachen/htdocs/manual/new_features_1_3.html,v
retrieving revision 1.14
diff -u -r1.14 new_features_1_3.html
--- new_features_1_3.html	1997/08/11 10:04:43	1.14
+++ new_features_1_3.html	1997/08/17 02:34:58
@@ -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.
Index: src/CHANGES
===================================================================
RCS file: /export/home/cvs/apachen/src/CHANGES,v
retrieving revision 1.398
diff -u -r1.398 CHANGES
--- CHANGES	1997/08/17 02:31:47	1.398
+++ CHANGES	1997/08/17 02:35:08
@@ -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]
+
   *) Configure changes: TestLib replaced by TestCompile, which has
      some additional capability (such as doing a sanity check of
      the compiler and flags selected); the version of Solaris is now
Index: src/PORTING
===================================================================
RCS file: /export/home/cvs/apachen/src/PORTING,v
retrieving revision 1.9
diff -u -r1.9 PORTING
--- PORTING	1997/08/09 00:55:53	1.9
+++ PORTING	1997/08/17 02:35:08
@@ -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.
 
 --
 
Index: src/core/conf.h
===================================================================
RCS file: /export/home/cvs/apachen/src/core/conf.h,v
retrieving revision 1.123
diff -u -r1.123 conf.h
--- conf.h	1997/08/15 18:12:09	1.123
+++ conf.h	1997/08/17 02:35:10
@@ -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;
@@ -102,6 +103,7 @@
 #define JMP_BUF sigjmp_buf
 #define USE_FCNTL_SERIALIZED_ACCEPT
 #define HAVE_MMAP
+#define USE_MMAP_FILES
 #define HAVE_CRYPT_H
 int gethostname(char *name, int namelen);
 
@@ -114,6 +116,7 @@
 #define JMP_BUF sigjmp_buf
 #define USE_FCNTL_SERIALIZED_ACCEPT
 #define HAVE_SHMGET
+#define USE_MMAP_FILES
 #define HAVE_CRYPT_H
 #define NO_LONG_DOUBLE
 #define HAVE_BSTRING_H
@@ -154,6 +157,7 @@
 #define JMP_BUF sigjmp_buf
 #ifndef __ps2__
 #define HAVE_MMAP
+#define USE_MMAP_FILES
 #define DEFAULT_GROUP "nobody"
 #endif
 #define DEFAULT_USER "nobody"
@@ -179,6 +183,7 @@
 #undef NO_SETSID
 #define JMP_BUF sigjmp_buf
 #define HAVE_MMAP
+#define USE_MMAP_FILES
 #define HAVE_CRYPT_H
 #define NO_LONG_DOUBLE
 
@@ -188,6 +193,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;
@@ -267,6 +273,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 */
@@ -298,6 +305,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
 
@@ -362,6 +370,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
@@ -417,6 +426,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__) || \
@@ -465,6 +475,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__)
@@ -506,6 +517,7 @@
 #undef NO_SETSID
 #undef NEED_STRDUP
 #define HAVE_MMAP
+#define USE_MMAP_FILES
 
 #define NO_TIMEZONE
 #include <stdio.h>
Index: src/core/http_core.c
===================================================================
RCS file: /export/home/cvs/apachen/src/core/http_core.c,v
retrieving revision 1.109
diff -u -r1.109 http_core.c
--- http_core.c	1997/08/06 20:21:24	1.109
+++ http_core.c	1997/08/17 02:35:15
@@ -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.
@@ -1484,6 +1506,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
@@ -1498,6 +1534,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.
@@ -1539,24 +1578,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;
Index: src/core/http_protocol.c
===================================================================
RCS file: /export/home/cvs/apachen/src/core/http_protocol.c,v
retrieving revision 1.152
diff -u -r1.152 http_protocol.c
--- http_protocol.c	1997/08/15 17:59:50	1.152
+++ http_protocol.c	1997/08/17 02:35:20
@@ -1754,6 +1754,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;
Index: src/core/http_protocol.h
===================================================================
RCS file: /export/home/cvs/apachen/src/core/http_protocol.h,v
retrieving revision 1.25
diff -u -r1.25 http_protocol.h
--- http_protocol.h	1997/07/24 04:23:59	1.25
+++ http_protocol.h	1997/08/17 02:35:21
@@ -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.



Mime
View raw message