Commit a617c172 authored by Bill Stoddard's avatar Bill Stoddard
Browse files

Eat our own cooking. Cleanup code paths and use apr_hash functions. Good

for a small performance boost.


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@88586 13f79535-47bb-0310-9956-ffa450edef68
parent e2f2f1c1
Loading
Loading
Loading
Loading
+72 −125
Original line number Diff line number Diff line
@@ -109,6 +109,7 @@
#include "apr.h"
#include "apr_mmap.h"
#include "apr_strings.h"
#include "apr_hash.h"

#define APR_WANT_STRFUNC
#include "apr_want.h"
@@ -143,7 +144,7 @@ typedef struct {
} a_file;

typedef struct {
    apr_array_header_t *files;
    apr_hash_t *fileht;
} a_server_config;


@@ -151,176 +152,124 @@ static void *create_server_config(apr_pool_t *p, server_rec *s)
{
    a_server_config *sconf = apr_palloc(p, sizeof(*sconf));

    sconf->files = apr_array_make(p, 20, sizeof(a_file));
    sconf->fileht = apr_hash_make(p);
    return sconf;
}

static apr_status_t cleanup_file_cache(void *sconfv)
{
    a_server_config *sconf = sconfv;
    size_t n;
    a_file *file;
    apr_hash_index_t *hi;

    n = sconf->files->nelts;
    file = (a_file *)sconf->files->elts;
    while(n) {
    /* Iterate over the file hash table and clean up each entry */
    for (hi = apr_hash_first(sconf->fileht); hi; hi=apr_hash_next(hi)) {
        apr_hash_this(hi, NULL, NULL, &file);
#if APR_HAS_MMAP
        if (file->is_mmapped) { 
	    apr_mmap_delete(file->mm);
        } 
        else 
#endif 
#if APR_HAS_SENDFILE
        if (!file->is_mmapped) {
            apr_file_close(file->file); 
        }
#endif
	    ++file;
	    --n;
    }
    return APR_SUCCESS;
}

static const char *cachefile(cmd_parms *cmd, void *dummy, const char *filename)

static void cache_the_file(cmd_parms *cmd, const char *filename, int mmap)
{
    /* ToDo:
     * Disable the file cache on a Windows 9X box. APR_HAS_SENDFILE will be
     * defined in an Apache for Windows build, but apr_sendfile returns
     * APR_ENOTIMPL on Windows 9X because TransmitFile is not available.
     */

#if APR_HAS_SENDFILE
    a_server_config *sconf;
    a_file *new_file;
    a_file tmp;
    apr_file_t *fd = NULL;
    apr_status_t rc;
    const char *fspec;

    /* canonicalize the file name? */
    /* os_canonical... */
    /* XXX: uh... yea, or expect them to be -very- accurate typists */
    if ((rc = apr_stat(&tmp.finfo, filename, APR_FINFO_MIN, 
    fspec = ap_os_case_canonical_filename(cmd->pool, filename);
    if ((rc = apr_stat(&tmp.finfo, fspec, APR_FINFO_MIN, 
                       cmd->temp_pool)) != APR_SUCCESS) {
	ap_log_error(APLOG_MARK, APLOG_WARNING, rc, cmd->server,
	    "mod_file_cache: unable to stat(%s), skipping", filename);
	return NULL;
	    "mod_file_cache: unable to stat(%s), skipping", fspec);
	return;
    }
    if (tmp.finfo.filetype != APR_REG) {
	ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, cmd->server,
	    "mod_file_cache: %s isn't a regular file, skipping", filename);
	return NULL;
	    "mod_file_cache: %s isn't a regular file, skipping", fspec);
	return;
    }

    rc = apr_file_open(&fd, filename, APR_READ | APR_XTHREAD, APR_OS_DEFAULT, cmd->pool);
    rc = apr_file_open(&fd, fspec, APR_READ | APR_XTHREAD, APR_OS_DEFAULT, cmd->pool);
    if (rc != APR_SUCCESS) {
        ap_log_error(APLOG_MARK, APLOG_WARNING, rc, cmd->server,
                     "mod_file_cache: unable to open(%s, O_RDONLY), skipping", filename);
	return NULL;
    }
    tmp.file = fd;
    tmp.filename = apr_pstrdup(cmd->pool, filename);
    apr_rfc822_date(tmp.mtimestr, tmp.finfo.mtime);
    apr_snprintf(tmp.sizestr, sizeof tmp.sizestr, "%" APR_OFF_T_FMT, tmp.finfo.size);
    sconf = ap_get_module_config(cmd->server->module_config, &file_cache_module);
    new_file = apr_array_push(sconf->files);
    *new_file = tmp;
    if (sconf->files->nelts == 1) {
	/* first one, register the cleanup */
	apr_pool_cleanup_register(cmd->pool, sconf, cleanup_file_cache, apr_pool_cleanup_null);
                     "mod_file_cache: unable to open(%s, O_RDONLY), skipping", fspec);
	return;
    }

    new_file->is_mmapped = FALSE;
    /* WooHoo, we have a file to put in the cache */
    new_file = apr_pcalloc(cmd->pool, sizeof(a_file));
    new_file->finfo = tmp.finfo;

    return NULL;
#else
    /* Sendfile not supported on this platform */
    ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, cmd->server,
                 "mod_file_cache: unable to cache file: %s. Sendfile is not supported on this OS", filename);
    return NULL;
#endif
}

static const char *mmapfile(cmd_parms *cmd, void *dummy, const char *filename)
{
#if APR_HAS_MMAP
    a_server_config *sconf;
    a_file *new_file;
    a_file tmp;
    apr_file_t *fd = NULL;
    apr_status_t rc;
    const char *fspec;

    fspec = ap_os_case_canonical_filename(cmd->pool, filename);
    if ((rc = apr_stat(&tmp.finfo, fspec, APR_FINFO_MIN, 
                       cmd->temp_pool)) != APR_SUCCESS) {
	ap_log_error(APLOG_MARK, APLOG_WARNING, rc, cmd->server,
	    "mod_file_cache: unable to stat(%s), skipping", filename);
	return NULL;
    }
    if ((tmp.finfo.filetype) != APR_REG) {
	ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, cmd->server,
	    "mod_file_cache: %s isn't a regular file, skipping", filename);
	return NULL;
    }
    if ((rc = apr_file_open(&fd, fspec, APR_READ, APR_OS_DEFAULT, 
                       cmd->temp_pool)) != APR_SUCCESS) { 
	ap_log_error(APLOG_MARK, APLOG_WARNING, rc, cmd->server,
                     "mod_file_cache: unable to open %s, skipping", 
                     filename);
	return NULL;
    }
    if ((rc = apr_mmap_create(&tmp.mm, fd, 0, tmp.finfo.size, APR_MMAP_READ, cmd->pool)) != APR_SUCCESS) { 
    if (mmap) {
         /* MMAPFile directive. MMAP'ing the file */
        if ((rc = apr_mmap_create(&new_file->mm, fd, 0, new_file->finfo.size,
                                  APR_MMAP_READ, cmd->pool)) != APR_SUCCESS) { 
            apr_file_close(fd);
            ap_log_error(APLOG_MARK, APLOG_WARNING, rc, cmd->server,
                         "mod_file_cache: unable to mmap %s, skipping", filename);
	return NULL;
            return;
        }
        apr_file_close(fd);
    tmp.filename = fspec;
    apr_rfc822_date(tmp.mtimestr, tmp.finfo.mtime);
    apr_snprintf(tmp.sizestr, sizeof tmp.sizestr, "%" APR_OFF_T_FMT, tmp.finfo.size);
        new_file->is_mmapped = TRUE;
    }
    else {
        /* CacheFile directive. Caching the file handle */
        new_file->is_mmapped = FALSE;
        new_file->file = fd;
    }

    new_file->filename = fspec;
    apr_rfc822_date(new_file->mtimestr, new_file->finfo.mtime);
    apr_snprintf(new_file->sizestr, sizeof new_file->sizestr, "%" APR_OFF_T_FMT, new_file->finfo.size);

    sconf = ap_get_module_config(cmd->server->module_config, &file_cache_module);
    new_file = apr_array_push(sconf->files);
    *new_file = tmp;
    if (sconf->files->nelts == 1) {
    apr_hash_set(sconf->fileht, new_file->filename, strlen(new_file->filename), new_file);

    if (apr_hash_count(sconf->fileht) == 1) {
	/* first one, register the cleanup */
	apr_pool_cleanup_register(cmd->pool, sconf, cleanup_file_cache, apr_pool_cleanup_null);
    }
}

    new_file->is_mmapped = TRUE;

    return NULL;
static const char *cachefilehandle(cmd_parms *cmd, void *dummy, const char *filename)
{
#if APR_HAS_SENDFILE
    cache_the_file(cmd, filename, 0);
#else
    /* MMAP not supported on this platform*/
    return NULL;
    /* Sendfile not supported by this OS */
    ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, cmd->server,
                 "mod_file_cache: unable to cache file: %s. Sendfile is not supported on this OS", fspec);
#endif
    return NULL;
}


static int file_compare(const void *av, const void *bv)
static const char *cachefilemmap(cmd_parms *cmd, void *dummy, const char *filename) 
{
    const a_file *a = av;
    const a_file *b = bv;

    return strcmp(a->filename, b->filename);
#if APR_HAS_MMAP
    cache_the_file(cmd, filename, 1);
#else
    /* MMAP not supported by this OS */
    ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, cmd->server,
                 "mod_file_cache: unable to cache file: %s. MMAP is not supported by this OS", fspec);
#endif
    return NULL;
}

static void file_cache_post_config(apr_pool_t *p, apr_pool_t *plog,
                                   apr_pool_t *ptemp, server_rec *s)
{
    a_server_config *sconf;
    a_file *elts;
    int nelts;

    /* sort the elements of the main_server, by filename */
    sconf = ap_get_module_config(s->module_config, &file_cache_module);
    elts = (a_file *)sconf->files->elts;
    nelts = sconf->files->nelts;
    qsort(elts, nelts, sizeof(a_file), file_compare);

    /* and make the virtualhosts share the same thing */
    for (s = s->next; s; s = s->next) {
	ap_set_module_config(s->module_config, &file_cache_module, sconf);
    }
    /* Hummm, anything to do here? */
}

/* If it's one of ours, fill in r->finfo now to avoid extra stat()... this is a
@@ -336,22 +285,21 @@ static int file_cache_xlat(request_rec *r)
    sconf = ap_get_module_config(r->server->module_config, &file_cache_module);

    /* we only operate when at least one cachefile directive was used */
    if (apr_is_empty_table(sconf->files))
    if (!apr_hash_count(sconf->fileht)) {
	return DECLINED;
    }

    res = ap_core_translate(r);
    if (res != OK || !r->filename) {
	return res;
    }

    tmp.filename = r->filename;
    match = (a_file *)bsearch(&tmp, sconf->files->elts, sconf->files->nelts,
	sizeof(a_file), file_compare);

    /* search the cache */
    match = (a_file *) apr_hash_get(sconf->fileht, r->filename, APR_HASH_KEY_STRING);
    if (match == NULL)
        return DECLINED;

    /* pass bsearch results to handler */
    /* pass search results to handler */
    ap_set_module_config(r->request_config, &file_cache_module, match);

    /* shortcircuit the get_path_info() stat() calls and stuff */
@@ -359,7 +307,6 @@ static int file_cache_xlat(request_rec *r)
    return OK;
}


static int mmap_handler(request_rec *r, a_file *file)
{
#if APR_HAS_MMAP
@@ -481,9 +428,9 @@ static int file_cache_handler(request_rec *r)

static command_rec file_cache_cmds[] =
{
AP_INIT_ITERATE("cachefile", cachefile, NULL, RSRC_CONF,
AP_INIT_ITERATE("cachefile", cachefilehandle, NULL, RSRC_CONF,
     "A space separated list of files to add to the file handle cache at config time"),
AP_INIT_ITERATE("mmapfile", mmapfile, NULL, RSRC_CONF,
AP_INIT_ITERATE("mmapfile", cachefilemmap, NULL, RSRC_CONF,
     "A space separated list of files to mmap at config time"),
    {NULL}
};