You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Bill Stoddard <st...@raleigh.ibm.com> on 2000/02/04 20:48:03 UTC

[PATCH] mod_mmap_static hacking

I've hacked mod_mmap_static to cache file handles on Windows NT. Most of the
work should be applicable to any platform that supports the sendfile() API.

First off, I am NOT proposing we commit this. I'm just sharing some of my
hacking with the list for those who may be interested. As I get time, I plan
to polish this up to the point where I can commit it. It has lots of
problems, like caching file handles in the parent process (where they are
never used :-), replicating code from the core_translate hook, unstructured
tweaking of the internals of the BUFF structure, etc.

Apache 1.3 on Windows NT V4 SP5 will serve a 500 byte file at 400 requests
per second (no-keep-alive) on my 400Mhz PII. Apache 2.0 w/o caching (and
with TransmitFile) ups the number to around 490. Apache 2.0 with file handle
caching ups the number to around 730. The difference in performance between
Apache 1.3 and Apache 2.0 increases as the file size increases.

________________________________________________
Bill Stoddard stoddard@raleigh.ibm.com

Come to the first official Apache Software Foundation
Conference!  <http://ApacheCon.Com/>




Re: [PATCH] mod_mmap_static hacking (caching file handles on Windows NT)

Posted by David Reid <ab...@dial.pipex.com>.
It was suggested a while back that we split the directory structure a little
to have specific modules for platforms.  Maybe we should do it now and copy
all modules into both?  It shouldn't take long for a few volunteers to strip
out non-platform code.

david
----- Original Message -----
From: "Bill Stoddard" <st...@raleigh.ibm.com>
To: <ne...@apache.org>
Sent: Friday, February 04, 2000 7:58 PM
Subject: [PATCH] mod_mmap_static hacking (caching file handles on Windows
NT)


> It would help to include the patch :-) Here it is...
>
> Index: mod_mmap_static.c
> ===================================================================
> RCS file:
/home/cvs/apache-2.0/src/modules/experimental/mod_mmap_static.c,v
> retrieving revision 1.6
> diff -u -r1.6 mod_mmap_static.c
> --- mod_mmap_static.c 2000/01/04 19:00:56 1.6
> +++ mod_mmap_static.c 2000/02/04 19:34:03
> @@ -123,13 +123,18 @@
>  #include "apr_mmap.h"
>
>  module MODULE_VAR_EXPORT mmap_static_module;
> +static ap_context_t *context;
> +static int once_through = 0;
>
>  typedef struct {
> +#ifdef WIN32
> +    ap_file_t *file;
> +#else
>      ap_mmap_t *mm;
> +#endif
>      char *filename;
> -    struct stat finfo;
> +    ap_finfo_t finfo;
>  } a_file;
> -ap_context_t *context;
>
>  typedef struct {
>      ap_array_header_t *files;
> @@ -145,7 +150,36 @@
>      sconf->inode_sorted = NULL;
>      return sconf;
>  }
> +static void pre_config(ap_context_t *pconf, ap_context_t *plog,
> ap_context_t *ptemp)
> +{
> +    context = pconf;
> +}
> +static ap_status_t open_file(ap_file_t **file, char* filename, int flg1,
> int flg2,
> +                             ap_context_t *context)
> +{
> +    ap_status_t rv;
> +#ifndef WIN32
> +    rv = ap_open(file, filename, flg1, flg2, context);
> +#else
> +    HANDLE hFile;
> +    hFile = CreateFile(filename,          // pointer to name of the file
> +                       GENERIC_READ,      // access (read-write) mode
> +                       FILE_SHARE_READ,   // share mode
> +                       NULL,              // pointer to security
attributes
> +                       OPEN_EXISTING,    // how to create
> +                       FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN,
> // file attributes
> +                       NULL); // handle to file with attributes to copy
> +    if (hFile != INVALID_HANDLE_VALUE)
> +        rv = ap_put_os_file(file, &hFile, context);
> +    else {
> +        rv = GetLastError();
> +        *file = NULL;
> +    }
>
> +#endif
> +    return rv;
> +}
> +
>  ap_status_t cleanup_mmap(void *sconfv)
>  {
>      a_server_config *sconf = sconfv;
> @@ -155,9 +189,13 @@
>      n = sconf->files->nelts;
>      file = (a_file *)sconf->files->elts;
>      while(n) {
> -     ap_mmap_delete(file->mm);
> -     ++file;
> -     --n;
> +#ifdef WIN32
> +        ap_close(file->file);
> +#else
> +        ap_mmap_delete(file->mm);
> +#endif
> +        ++file;
> +        --n;
>      }
>      return APR_SUCCESS;
>  }
> @@ -168,23 +206,33 @@
>      a_file *new_file;
>      a_file tmp;
>      ap_file_t *fd = NULL;
> +#ifndef WIN32
>      caddr_t mm;
> -
> -    if (stat(filename, &tmp.finfo) == -1) {
> +#endif
> +    ap_status_t rc;
> +    /* canonicalize the file name */
> +    /* os_canonical... */
> +    if (ap_stat(&tmp.finfo, filename, NULL) != APR_SUCCESS) {
>   ap_log_error(APLOG_MARK, APLOG_WARNING, errno, cmd->server,
>       "mmap_static: unable to stat(%s), skipping", filename);
>   return NULL;
>      }
> -    if ((tmp.finfo.st_mode & S_IFMT) != S_IFREG) {
> +    if (tmp.finfo.filetype != APR_REG) {
>   ap_log_error(APLOG_MARK, APLOG_WARNING, errno, cmd->server,
>       "mmap_static: %s isn't a regular file, skipping", filename);
>   return NULL;
>      }
> -    if (ap_open(&fd, filename, APR_READ, APR_OS_DEFAULT, context) !=
> APR_SUCCESS) {
> - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, cmd->server,
> -     "mmap_static: unable to open(%s, O_RDONLY), skipping", filename);
> +    /* Note: open_file should call ap_open for Unix and CreateFile for
> Windows.
> +     * The Windows file needs to be opened for async I/O to allow
multiple
> threads
> +     * to serve it up at once.
> +     */
> +    rc = open_file(&fd, filename, APR_READ, APR_OS_DEFAULT, context);
> +    if (rc != APR_SUCCESS) {
> +        ap_log_error(APLOG_MARK, APLOG_WARNING, rc, cmd->server,
> +                     "mmap_static: unable to open(%s, O_RDONLY),
skipping",
> filename);
>   return NULL;
>      }
> +#ifndef WIN32
>      if (ap_mmap_create(&tmp.mm, fd, 0, tmp.finfo.st_size, context) !=
> APR_SUCCESS) {
>   int save_errno = errno;
>   ap_close(fd);
> @@ -194,6 +242,9 @@
>   return NULL;
>      }
>      ap_close(fd);
> +#else
> +    tmp.file = fd;
> +#endif
>      tmp.filename = ap_pstrdup(cmd->pool, filename);
>      sconf = ap_get_module_config(cmd->server->module_config,
> &mmap_static_module);
>      new_file = ap_push_array(sconf->files);
> @@ -205,6 +256,7 @@
>      return NULL;
>  }
>
> +#ifdef WIN32
>  static int file_compare(const void *av, const void *bv)
>  {
>      const a_file *a = av;
> @@ -212,7 +264,7 @@
>
>      return strcmp(a->filename, b->filename);
>  }
> -
> +#else
>  static int inode_compare(const void *av, const void *bv)
>  {
>      const a_file *a = *(a_file **)av;
> @@ -225,9 +277,9 @@
>      }
>      return c;
>  }
> -
> +#endif
>  static void mmap_post_config(ap_context_t *p, ap_context_t *plog,
> -          ap_context_t *ptemp, server_rec *s)
> +                             ap_context_t *ptemp, server_rec *s)
>  {
>      a_server_config *sconf;
>      ap_array_header_t *inodes;
> @@ -243,13 +295,14 @@
>      qsort(elts, nelts, sizeof(a_file), file_compare);
>
>      /* build an index by inode as well, speeds up the search in the
handler
> */
> +#ifndef WIN32
>      inodes = ap_make_array(p, nelts, sizeof(a_file *));
>      sconf->inode_sorted = inodes;
>      for (i = 0; i < nelts; ++i) {
>   *(a_file **)ap_push_array(inodes) = &elts[i];
>      }
>      qsort(inodes->elts, nelts, sizeof(a_file *), inode_compare);
> -
> +#endif
>      /* and make the virtualhosts share the same thing */
>      for (s = s->next; s; s = s->next) {
>   ap_set_module_config(s->module_config, &mmap_static_module, sconf);
> @@ -259,7 +312,47 @@
>  /* If it's one of ours, fill in r->finfo now to avoid extra stat()...
this
> is a
>   * bit of a kludge, because we really want to run after core_translate
> runs.
>   */
> -
> +int core_translate_copy(request_rec *r)
> +{
> +    void *sconf = r->server->module_config;
> +    core_server_config *conf = ap_get_module_config(sconf, &core_module);
> +
> +    if (r->proxyreq) {
> +        return HTTP_FORBIDDEN;
> +    }
> +    if ((r->uri[0] != '/') && strcmp(r->uri, "*")) {
> +        ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
> +                      "Invalid URI in request %s", r->the_request);
> +        return BAD_REQUEST;
> +    }
> +
> +    if (r->server->path
> +        && !strncmp(r->uri, r->server->path, r->server->pathlen)
> +        && (r->server->path[r->server->pathlen - 1] == '/'
> +            || r->uri[r->server->pathlen] == '/'
> +            || r->uri[r->server->pathlen] == '\0')) {
> +        r->filename = ap_pstrcat(r->pool, conf->ap_document_root,
> +                                 (r->uri + r->server->pathlen), NULL);
> +    }
> +    else {
> +        /*
> +         * Make sure that we do not mess up the translation by adding two
> +         * /'s in a row.  This happens under windows when the document
> +         * root ends with a /
> +         */
> +        if ((conf->ap_document_root[strlen(conf->ap_document_root)-1] ==
> '/')
> +            && (*(r->uri) == '/')) {
> +            r->filename = ap_pstrcat(r->pool, conf->ap_document_root,
> r->uri+1,
> +                                     NULL);
> +        }
> +        else {
> +            r->filename = ap_pstrcat(r->pool, conf->ap_document_root,
> r->uri,
> +                                     NULL);
> +        }
> +
> +        return OK;
> +    }
> +}
>  static int mmap_static_xlat(request_rec *r)
>  {
>      a_server_config *sconf;
> @@ -273,10 +366,12 @@
>      if (ap_is_empty_table(sconf->files))
>   return DECLINED;
>
> -/*    res = core_module.translate_handler(r);
> +/*  res = core_module.translate_handler(r);  */
> +    res = core_translate_copy(r);
>      if (res == DECLINED || !r->filename) {
>   return res;
> -    }*/
> +    }
> +
>      if (!r->filename)
>          return DECLINED;
>      tmp.filename = r->filename;
> @@ -299,23 +394,38 @@
>      a_file **pmatch;
>      a_file *match;
>      int rangestatus, errstatus;
> +#ifdef WIN32
> +    HANDLE hCurrentProcess;
> +#endif
>
>      /* we don't handle anything but GET */
>      if (r->method_number != M_GET) return DECLINED;
>
>      /* file doesn't exist, we won't be dealing with it */
> -    if (r->finfo.st_mode == 0) return DECLINED;
> +    if (r->finfo.protection == 0) return DECLINED;
>
>      sconf = ap_get_module_config(r->server->module_config,
> &mmap_static_module);
> +#ifdef WIN32
> +    tmp.filename = r->filename;
> +#else
>      tmp.finfo.st_dev = r->finfo.st_dev;
>      tmp.finfo.st_ino = r->finfo.st_ino;
> +#endif
>      ptmp = &tmp;
> +#ifdef WIN32
> +    match = (a_file *)bsearch(ptmp, sconf->files->elts,
> + sconf->files->nelts, sizeof(a_file), file_compare);
> +    if (match == NULL) {
> + return DECLINED;
> +    }
> +#else
>      pmatch = (a_file **)bsearch(&ptmp, sconf->inode_sorted->elts,
>   sconf->inode_sorted->nelts, sizeof(a_file *), inode_compare);
>      if (pmatch == NULL) {
>   return DECLINED;
>      }
>      match = *pmatch;
> +#endif
>
>      /* note that we would handle GET on this resource */
>      r->allowed |= (1 << M_GET);
> @@ -326,11 +436,11 @@
>      if ((errstatus = ap_discard_request_body(r)) != OK)
>          return errstatus;
>
> -    ap_update_mtime(r, match->finfo.st_mtime);
> +    ap_update_mtime(r, match->finfo.mtime);
>      ap_set_last_modified(r);
>      ap_set_etag(r);
>      if (((errstatus = ap_meets_conditions(r)) != OK)
> - || (errstatus = ap_set_content_length (r, match->finfo.st_size))) {
> + || (errstatus = ap_set_content_length (r, match->finfo.size))) {
>       return errstatus;
>      }
>
> @@ -338,16 +448,53 @@
>      ap_send_http_header(r);
>
>      if (!r->header_only) {
> +        long length = match->finfo.size;
> +        ap_off_t offset = 0;
> +#ifdef WIN32
> +//        ap_bflush(r->connection->client->);
> +        struct iovec iov;
> +        ap_hdtr_t hdtr;
> +        ap_hdtr_t *phdtr = &hdtr;
> +        /* frob the client buffer */
> +        iov.iov_base = r->connection->client->outbase;
> +        iov.iov_len =  r->connection->client->outcnt;
> +        r->connection->client->outcnt = 0;
> +
> +        /* initialize the ap_hdtr_t struct */
> +        phdtr->headers = &iov;
> +        phdtr->numheaders = 1;
> +        phdtr->trailers = NULL;
> +        phdtr->numtrailers = 0;
> +
> + if (!rangestatus) {
> +            iol_sendfile(r->connection->client->iol,
> +                         match->file,
> +                         phdtr,
> +                         &offset,
> +                         &length,
> +                         0);
> + }
> + else {
> +     while (ap_each_byterange(r, &offset, &length)) {
> +                iol_sendfile(r->connection->client->iol,
> +                             match->file,
> +                             phdtr,
> +                             &offset,
> +                             &length,
> +                             0);
> +                phdtr = NULL;
> +     }
> + }
> +#else
>   if (!rangestatus) {
>       ap_send_mmap (match->mm, r, 0, match->finfo.st_size);
>   }
>   else {
> -     long length;
> -     ap_off_t offset;
>       while (ap_each_byterange(r, &offset, &length)) {
>    ap_send_mmap(match->mm, r, offset, length);
>       }
>   }
> +#endif
>      }
>      return OK;
>  }
> @@ -362,8 +509,9 @@
>  static void register_hooks(void)
>  {
>      static const char* const aszPre[]={"http_core.c",NULL};
> +    ap_hook_pre_config(pre_config,NULL,NULL,HOOK_MIDDLE);
>      ap_hook_post_config(mmap_post_config, NULL, NULL, HOOK_MIDDLE);
> -    ap_hook_translate_name(mmap_static_xlat, aszPre, NULL, HOOK_LAST);
> +    ap_hook_translate_name(mmap_static_xlat, aszPre, NULL, HOOK_MIDDLE);
>  };
>
>  static const handler_rec mmap_static_handlers[] =
>
>
>


[PATCH] mod_mmap_static hacking (caching file handles on Windows NT)

Posted by Bill Stoddard <st...@raleigh.ibm.com>.
It would help to include the patch :-) Here it is...

Index: mod_mmap_static.c
===================================================================
RCS file: /home/cvs/apache-2.0/src/modules/experimental/mod_mmap_static.c,v
retrieving revision 1.6
diff -u -r1.6 mod_mmap_static.c
--- mod_mmap_static.c 2000/01/04 19:00:56 1.6
+++ mod_mmap_static.c 2000/02/04 19:34:03
@@ -123,13 +123,18 @@
 #include "apr_mmap.h"

 module MODULE_VAR_EXPORT mmap_static_module;
+static ap_context_t *context;
+static int once_through = 0;

 typedef struct {
+#ifdef WIN32
+    ap_file_t *file;
+#else
     ap_mmap_t *mm;
+#endif
     char *filename;
-    struct stat finfo;
+    ap_finfo_t finfo;
 } a_file;
-ap_context_t *context;

 typedef struct {
     ap_array_header_t *files;
@@ -145,7 +150,36 @@
     sconf->inode_sorted = NULL;
     return sconf;
 }
+static void pre_config(ap_context_t *pconf, ap_context_t *plog,
ap_context_t *ptemp)
+{
+    context = pconf;
+}
+static ap_status_t open_file(ap_file_t **file, char* filename, int flg1,
int flg2,
+                             ap_context_t *context)
+{
+    ap_status_t rv;
+#ifndef WIN32
+    rv = ap_open(file, filename, flg1, flg2, context);
+#else
+    HANDLE hFile;
+    hFile = CreateFile(filename,          // pointer to name of the file
+                       GENERIC_READ,      // access (read-write) mode
+                       FILE_SHARE_READ,   // share mode
+                       NULL,              // pointer to security attributes
+                       OPEN_EXISTING,    // how to create
+                       FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN,
// file attributes
+                       NULL); // handle to file with attributes to copy
+    if (hFile != INVALID_HANDLE_VALUE)
+        rv = ap_put_os_file(file, &hFile, context);
+    else {
+        rv = GetLastError();
+        *file = NULL;
+    }

+#endif
+    return rv;
+}
+
 ap_status_t cleanup_mmap(void *sconfv)
 {
     a_server_config *sconf = sconfv;
@@ -155,9 +189,13 @@
     n = sconf->files->nelts;
     file = (a_file *)sconf->files->elts;
     while(n) {
-     ap_mmap_delete(file->mm);
-     ++file;
-     --n;
+#ifdef WIN32
+        ap_close(file->file);
+#else
+        ap_mmap_delete(file->mm);
+#endif
+        ++file;
+        --n;
     }
     return APR_SUCCESS;
 }
@@ -168,23 +206,33 @@
     a_file *new_file;
     a_file tmp;
     ap_file_t *fd = NULL;
+#ifndef WIN32
     caddr_t mm;
-
-    if (stat(filename, &tmp.finfo) == -1) {
+#endif
+    ap_status_t rc;
+    /* canonicalize the file name */
+    /* os_canonical... */
+    if (ap_stat(&tmp.finfo, filename, NULL) != APR_SUCCESS) {
  ap_log_error(APLOG_MARK, APLOG_WARNING, errno, cmd->server,
      "mmap_static: unable to stat(%s), skipping", filename);
  return NULL;
     }
-    if ((tmp.finfo.st_mode & S_IFMT) != S_IFREG) {
+    if (tmp.finfo.filetype != APR_REG) {
  ap_log_error(APLOG_MARK, APLOG_WARNING, errno, cmd->server,
      "mmap_static: %s isn't a regular file, skipping", filename);
  return NULL;
     }
-    if (ap_open(&fd, filename, APR_READ, APR_OS_DEFAULT, context) !=
APR_SUCCESS) {
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, cmd->server,
-     "mmap_static: unable to open(%s, O_RDONLY), skipping", filename);
+    /* Note: open_file should call ap_open for Unix and CreateFile for
Windows.
+     * The Windows file needs to be opened for async I/O to allow multiple
threads
+     * to serve it up at once.
+     */
+    rc = open_file(&fd, filename, APR_READ, APR_OS_DEFAULT, context);
+    if (rc != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_WARNING, rc, cmd->server,
+                     "mmap_static: unable to open(%s, O_RDONLY), skipping",
filename);
  return NULL;
     }
+#ifndef WIN32
     if (ap_mmap_create(&tmp.mm, fd, 0, tmp.finfo.st_size, context) !=
APR_SUCCESS) {
  int save_errno = errno;
  ap_close(fd);
@@ -194,6 +242,9 @@
  return NULL;
     }
     ap_close(fd);
+#else
+    tmp.file = fd;
+#endif
     tmp.filename = ap_pstrdup(cmd->pool, filename);
     sconf = ap_get_module_config(cmd->server->module_config,
&mmap_static_module);
     new_file = ap_push_array(sconf->files);
@@ -205,6 +256,7 @@
     return NULL;
 }

+#ifdef WIN32
 static int file_compare(const void *av, const void *bv)
 {
     const a_file *a = av;
@@ -212,7 +264,7 @@

     return strcmp(a->filename, b->filename);
 }
-
+#else
 static int inode_compare(const void *av, const void *bv)
 {
     const a_file *a = *(a_file **)av;
@@ -225,9 +277,9 @@
     }
     return c;
 }
-
+#endif
 static void mmap_post_config(ap_context_t *p, ap_context_t *plog,
-          ap_context_t *ptemp, server_rec *s)
+                             ap_context_t *ptemp, server_rec *s)
 {
     a_server_config *sconf;
     ap_array_header_t *inodes;
@@ -243,13 +295,14 @@
     qsort(elts, nelts, sizeof(a_file), file_compare);

     /* build an index by inode as well, speeds up the search in the handler
*/
+#ifndef WIN32
     inodes = ap_make_array(p, nelts, sizeof(a_file *));
     sconf->inode_sorted = inodes;
     for (i = 0; i < nelts; ++i) {
  *(a_file **)ap_push_array(inodes) = &elts[i];
     }
     qsort(inodes->elts, nelts, sizeof(a_file *), inode_compare);
-
+#endif
     /* and make the virtualhosts share the same thing */
     for (s = s->next; s; s = s->next) {
  ap_set_module_config(s->module_config, &mmap_static_module, sconf);
@@ -259,7 +312,47 @@
 /* If it's one of ours, fill in r->finfo now to avoid extra stat()... this
is a
  * bit of a kludge, because we really want to run after core_translate
runs.
  */
-
+int core_translate_copy(request_rec *r)
+{
+    void *sconf = r->server->module_config;
+    core_server_config *conf = ap_get_module_config(sconf, &core_module);
+
+    if (r->proxyreq) {
+        return HTTP_FORBIDDEN;
+    }
+    if ((r->uri[0] != '/') && strcmp(r->uri, "*")) {
+        ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
+                      "Invalid URI in request %s", r->the_request);
+        return BAD_REQUEST;
+    }
+
+    if (r->server->path
+        && !strncmp(r->uri, r->server->path, r->server->pathlen)
+        && (r->server->path[r->server->pathlen - 1] == '/'
+            || r->uri[r->server->pathlen] == '/'
+            || r->uri[r->server->pathlen] == '\0')) {
+        r->filename = ap_pstrcat(r->pool, conf->ap_document_root,
+                                 (r->uri + r->server->pathlen), NULL);
+    }
+    else {
+        /*
+         * Make sure that we do not mess up the translation by adding two
+         * /'s in a row.  This happens under windows when the document
+         * root ends with a /
+         */
+        if ((conf->ap_document_root[strlen(conf->ap_document_root)-1] ==
'/')
+            && (*(r->uri) == '/')) {
+            r->filename = ap_pstrcat(r->pool, conf->ap_document_root,
r->uri+1,
+                                     NULL);
+        }
+        else {
+            r->filename = ap_pstrcat(r->pool, conf->ap_document_root,
r->uri,
+                                     NULL);
+        }
+
+        return OK;
+    }
+}
 static int mmap_static_xlat(request_rec *r)
 {
     a_server_config *sconf;
@@ -273,10 +366,12 @@
     if (ap_is_empty_table(sconf->files))
  return DECLINED;

-/*    res = core_module.translate_handler(r);
+/*  res = core_module.translate_handler(r);  */
+    res = core_translate_copy(r);
     if (res == DECLINED || !r->filename) {
  return res;
-    }*/
+    }
+
     if (!r->filename)
         return DECLINED;
     tmp.filename = r->filename;
@@ -299,23 +394,38 @@
     a_file **pmatch;
     a_file *match;
     int rangestatus, errstatus;
+#ifdef WIN32
+    HANDLE hCurrentProcess;
+#endif

     /* we don't handle anything but GET */
     if (r->method_number != M_GET) return DECLINED;

     /* file doesn't exist, we won't be dealing with it */
-    if (r->finfo.st_mode == 0) return DECLINED;
+    if (r->finfo.protection == 0) return DECLINED;

     sconf = ap_get_module_config(r->server->module_config,
&mmap_static_module);
+#ifdef WIN32
+    tmp.filename = r->filename;
+#else
     tmp.finfo.st_dev = r->finfo.st_dev;
     tmp.finfo.st_ino = r->finfo.st_ino;
+#endif
     ptmp = &tmp;
+#ifdef WIN32
+    match = (a_file *)bsearch(ptmp, sconf->files->elts,
+ sconf->files->nelts, sizeof(a_file), file_compare);
+    if (match == NULL) {
+ return DECLINED;
+    }
+#else
     pmatch = (a_file **)bsearch(&ptmp, sconf->inode_sorted->elts,
  sconf->inode_sorted->nelts, sizeof(a_file *), inode_compare);
     if (pmatch == NULL) {
  return DECLINED;
     }
     match = *pmatch;
+#endif

     /* note that we would handle GET on this resource */
     r->allowed |= (1 << M_GET);
@@ -326,11 +436,11 @@
     if ((errstatus = ap_discard_request_body(r)) != OK)
         return errstatus;

-    ap_update_mtime(r, match->finfo.st_mtime);
+    ap_update_mtime(r, match->finfo.mtime);
     ap_set_last_modified(r);
     ap_set_etag(r);
     if (((errstatus = ap_meets_conditions(r)) != OK)
- || (errstatus = ap_set_content_length (r, match->finfo.st_size))) {
+ || (errstatus = ap_set_content_length (r, match->finfo.size))) {
      return errstatus;
     }

@@ -338,16 +448,53 @@
     ap_send_http_header(r);

     if (!r->header_only) {
+        long length = match->finfo.size;
+        ap_off_t offset = 0;
+#ifdef WIN32
+//        ap_bflush(r->connection->client->);
+        struct iovec iov;
+        ap_hdtr_t hdtr;
+        ap_hdtr_t *phdtr = &hdtr;
+        /* frob the client buffer */
+        iov.iov_base = r->connection->client->outbase;
+        iov.iov_len =  r->connection->client->outcnt;
+        r->connection->client->outcnt = 0;
+
+        /* initialize the ap_hdtr_t struct */
+        phdtr->headers = &iov;
+        phdtr->numheaders = 1;
+        phdtr->trailers = NULL;
+        phdtr->numtrailers = 0;
+
+ if (!rangestatus) {
+            iol_sendfile(r->connection->client->iol,
+                         match->file,
+                         phdtr,
+                         &offset,
+                         &length,
+                         0);
+ }
+ else {
+     while (ap_each_byterange(r, &offset, &length)) {
+                iol_sendfile(r->connection->client->iol,
+                             match->file,
+                             phdtr,
+                             &offset,
+                             &length,
+                             0);
+                phdtr = NULL;
+     }
+ }
+#else
  if (!rangestatus) {
      ap_send_mmap (match->mm, r, 0, match->finfo.st_size);
  }
  else {
-     long length;
-     ap_off_t offset;
      while (ap_each_byterange(r, &offset, &length)) {
   ap_send_mmap(match->mm, r, offset, length);
      }
  }
+#endif
     }
     return OK;
 }
@@ -362,8 +509,9 @@
 static void register_hooks(void)
 {
     static const char* const aszPre[]={"http_core.c",NULL};
+    ap_hook_pre_config(pre_config,NULL,NULL,HOOK_MIDDLE);
     ap_hook_post_config(mmap_post_config, NULL, NULL, HOOK_MIDDLE);
-    ap_hook_translate_name(mmap_static_xlat, aszPre, NULL, HOOK_LAST);
+    ap_hook_translate_name(mmap_static_xlat, aszPre, NULL, HOOK_MIDDLE);
 };

 static const handler_rec mmap_static_handlers[] =