Delivered-To: new-httpd-archive@hyperreal.org Received: (qmail 12661 invoked by uid 6000); 4 Feb 2000 22:24:02 -0000 Received: (qmail 12410 invoked from network); 4 Feb 2000 22:23:53 -0000 Received: from www.jetnet.co.uk (root@62.172.71.4) by taz.hyperreal.org with SMTP; 4 Feb 2000 22:23:53 -0000 Received: from godzilla (ppp63.dialin.co.uk [194.73.252.63]) by www.jetnet.co.uk (8.9.3/8.9.3) with SMTP id WAA28293 for ; Fri, 4 Feb 2000 22:20:36 GMT Message-ID: <007401bf6f5e$7b2bf2f0$0a1aa8c0@jetnet.co.uk> From: "David Reid" To: References: <00f501bf6f48$bfa91180$064b2509@raleigh.ibm.com> <010701bf6f4a$45304e80$064b2509@raleigh.ibm.com> Subject: Re: [PATCH] mod_mmap_static hacking (caching file handles on Windows NT) Date: Fri, 4 Feb 2000 22:23:35 -0000 MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit X-Priority: 3 X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook Express 5.00.2919.6600 X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2919.6600 Sender: new-httpd-owner@apache.org Precedence: bulk Reply-To: new-httpd@apache.org Status: O 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" To: 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[] = > > >