⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mod_mem_cache.c

📁 Apache HTTP Server 是一个功能强大的灵活的与HTTP/1.1相兼容的web服务器.这里给出的是Apache HTTP服务器的源码。
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Copyright 2001-2005 The Apache Software Foundation or its licensors, as * applicable. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//* * Rules for managing obj->refcount: * refcount should be incremented when an object is placed in the cache. Insertion  *   of an object into the cache and the refcount increment should happen under  *   protection of the sconf->lock. * * refcount should be decremented when the object is removed from the cache. *   Object should be removed from the cache and the refcount decremented while *   under protection of the sconf->lock. *  * refcount should be incremented when an object is retrieved from the cache *   by a worker thread. The retrieval/find operation and refcount increment *   should occur under protection of the sconf->lock * * refcount can be atomically decremented w/o protection of the sconf->lock *   by worker threads. * * Any object whose refcount drops to 0 should be freed/cleaned up. A refcount  * of 0 means the object is not in the cache and no worker threads are accessing  * it. */#define CORE_PRIVATE#include "mod_cache.h"#include "cache_pqueue.h"#include "cache_cache.h"#include "ap_provider.h"#include "ap_mpm.h"#include "apr_thread_mutex.h"#if APR_HAVE_UNISTD_H#include <unistd.h>#endif#if !APR_HAS_THREADS#error This module does not currently compile unless you have a thread-capable APR. Sorry!#endifmodule AP_MODULE_DECLARE_DATA mem_cache_module;typedef enum {    CACHE_TYPE_FILE = 1,    CACHE_TYPE_HEAP,    CACHE_TYPE_MMAP} cache_type_e;typedef struct {    char* hdr;    char* val;} cache_header_tbl_t;typedef struct mem_cache_object {    cache_type_e type;    apr_ssize_t num_header_out;    apr_ssize_t num_err_header_out;    apr_ssize_t num_subprocess_env;    apr_ssize_t num_notes;    apr_ssize_t num_req_hdrs;    cache_header_tbl_t *header_out;    cache_header_tbl_t *err_header_out;    cache_header_tbl_t *subprocess_env;    cache_header_tbl_t *notes;    cache_header_tbl_t *req_hdrs; /* for Vary negotiation */    apr_size_t m_len;    void *m;    apr_os_file_t fd;    apr_int32_t flags;  /* File open flags */    long priority;      /**< the priority of this entry */    long total_refs;          /**< total number of references this entry has had */    apr_uint32_t pos;   /**< the position of this entry in the cache */} mem_cache_object_t;typedef struct {    apr_thread_mutex_t *lock;    cache_cache_t *cache_cache;    /* Fields set by config directives */    apr_size_t min_cache_object_size;   /* in bytes */    apr_size_t max_cache_object_size;   /* in bytes */    apr_size_t max_cache_size;          /* in bytes */    apr_size_t max_object_cnt;    cache_pqueue_set_priority cache_remove_algorithm;    /* maximum amount of data to buffer on a streamed response where     * we haven't yet seen EOS */    apr_off_t max_streaming_buffer_size;} mem_cache_conf;static mem_cache_conf *sconf;#define DEFAULT_MAX_CACHE_SIZE 100*1024#define DEFAULT_MIN_CACHE_OBJECT_SIZE 0#define DEFAULT_MAX_CACHE_OBJECT_SIZE 10000#define DEFAULT_MAX_OBJECT_CNT 1009#define DEFAULT_MAX_STREAMING_BUFFER_SIZE 100000#define CACHEFILE_LEN 20/* Forward declarations */static int remove_entity(cache_handle_t *h);static apr_status_t store_headers(cache_handle_t *h, request_rec *r, cache_info *i);static apr_status_t store_body(cache_handle_t *h, request_rec *r, apr_bucket_brigade *b);static apr_status_t recall_headers(cache_handle_t *h, request_rec *r);static apr_status_t recall_body(cache_handle_t *h, apr_pool_t *p, apr_bucket_brigade *bb);static void cleanup_cache_object(cache_object_t *obj);static long memcache_get_priority(void*a){    cache_object_t *obj = (cache_object_t *)a;    mem_cache_object_t *mobj = obj->vobj;    return  mobj->priority;}static void memcache_inc_frequency(void*a){    cache_object_t *obj = (cache_object_t *)a;    mem_cache_object_t *mobj = obj->vobj;    mobj->total_refs++;    mobj->priority = 0;}static void memcache_set_pos(void *a, apr_ssize_t pos){    cache_object_t *obj = (cache_object_t *)a;    mem_cache_object_t *mobj = obj->vobj;    apr_atomic_set(&mobj->pos, pos);}static apr_ssize_t memcache_get_pos(void *a){    cache_object_t *obj = (cache_object_t *)a;    mem_cache_object_t *mobj = obj->vobj;    return apr_atomic_read(&mobj->pos);}static apr_size_t memcache_cache_get_size(void*a){    cache_object_t *obj = (cache_object_t *)a;    mem_cache_object_t *mobj = obj->vobj;    return mobj->m_len;}/** callback to get the key of a item */static const char* memcache_cache_get_key(void*a){    cache_object_t *obj = (cache_object_t *)a;    return obj->key;}/**  * memcache_cache_free() * memcache_cache_free is a callback that is only invoked by a thread  * running in cache_insert(). cache_insert() runs under protection * of sconf->lock.  By the time this function has been entered, the cache_object * has been ejected from the cache. decrement the refcount and if the refcount drops * to 0, cleanup the cache object. */static void memcache_cache_free(void*a){    cache_object_t *obj = (cache_object_t *)a;    /* Decrement the refcount to account for the object being ejected     * from the cache. If the refcount is 0, free the object.     */    if (!apr_atomic_dec(&obj->refcount)) {        cleanup_cache_object(obj);    }}/* * functions return a 'negative' score since priority queues * dequeue the object with the highest value first */static long memcache_lru_algorithm(long queue_clock, void *a) {    cache_object_t *obj = (cache_object_t *)a;    mem_cache_object_t *mobj = obj->vobj;    if (mobj->priority == 0)        mobj->priority = queue_clock - mobj->total_refs;    /*	     * a 'proper' LRU function would just be     *  mobj->priority = mobj->total_refs;      */    return mobj->priority;}static long memcache_gdsf_algorithm(long queue_clock, void *a) {    cache_object_t *obj = (cache_object_t *)a;    mem_cache_object_t *mobj = obj->vobj;    if (mobj->priority == 0)        mobj->priority = queue_clock -                           (long)(mobj->total_refs*1000 / mobj->m_len);    return mobj->priority;}static void cleanup_cache_object(cache_object_t *obj){    mem_cache_object_t *mobj = obj->vobj;    /* TODO:     * We desperately need a more efficient way of allocating objects. We're     * making way too many malloc calls to create a fully populated      * cache object...     */    /* Cleanup the cache_object_t */    if (obj->key) {        free(obj->key);    }    if (obj->info.content_type) {        free(obj->info.content_type);    }    if (obj->info.etag) {        free(obj->info.etag);    }    if (obj->info.lastmods) {        free(obj->info.lastmods);    }    if (obj->info.filename) {        free(obj->info.filename);    }    free(obj);        /* Cleanup the mem_cache_object_t */    if (mobj) {        if (mobj->type == CACHE_TYPE_HEAP && mobj->m) {            free(mobj->m);        }        if (mobj->type == CACHE_TYPE_FILE && mobj->fd) {#ifdef WIN32            CloseHandle(mobj->fd);#else            close(mobj->fd);#endif        }        if (mobj->header_out) {            if (mobj->header_out[0].hdr)                 free(mobj->header_out[0].hdr);            free(mobj->header_out);        }        if (mobj->err_header_out) {            if (mobj->err_header_out[0].hdr)                 free(mobj->err_header_out[0].hdr);            free(mobj->err_header_out);        }        if (mobj->subprocess_env) {            if (mobj->subprocess_env[0].hdr)                 free(mobj->subprocess_env[0].hdr);            free(mobj->subprocess_env);        }        if (mobj->notes) {            if (mobj->notes[0].hdr)                 free(mobj->notes[0].hdr);            free(mobj->notes);        }        if (mobj->req_hdrs) {            if (mobj->req_hdrs[0].hdr)                free(mobj->req_hdrs[0].hdr);            free(mobj->req_hdrs);        }        free(mobj);    }}static apr_status_t decrement_refcount(void *arg) {    cache_object_t *obj = (cache_object_t *) arg;    /* If obj->complete is not set, the cache update failed and the     * object needs to be removed from the cache then cleaned up.     * The garbage collector may have ejected the object from the     * cache already, so make sure it is really still in the cache     * before attempting to remove it.     */    if (!obj->complete) {        cache_object_t *tobj = NULL;        if (sconf->lock) {            apr_thread_mutex_lock(sconf->lock);        }        tobj = cache_find(sconf->cache_cache, obj->key);        if (tobj == obj) {            cache_remove(sconf->cache_cache, obj);            apr_atomic_dec(&obj->refcount);        }        if (sconf->lock) {            apr_thread_mutex_unlock(sconf->lock);        }    }     /* If the refcount drops to 0, cleanup the cache object */    if (!apr_atomic_dec(&obj->refcount)) {        cleanup_cache_object(obj);    }    return APR_SUCCESS;}static apr_status_t cleanup_cache_mem(void *sconfv){    cache_object_t *obj;    mem_cache_conf *co = (mem_cache_conf*) sconfv;    if (!co) {        return APR_SUCCESS;    }    if (!co->cache_cache) {        return APR_SUCCESS;    }    if (sconf->lock) {        apr_thread_mutex_lock(sconf->lock);    }    obj = cache_pop(co->cache_cache);    while (obj) {                 /* Iterate over the cache and clean up each unreferenced entry */        if (!apr_atomic_dec(&obj->refcount)) {            cleanup_cache_object(obj);        }        obj = cache_pop(co->cache_cache);    }    /* Cache is empty, free the cache table */            cache_free(co->cache_cache);    if (sconf->lock) {        apr_thread_mutex_unlock(sconf->lock);    }    return APR_SUCCESS;}/* * TODO: enable directives to be overridden in various containers */static void *create_cache_config(apr_pool_t *p, server_rec *s){    sconf = apr_pcalloc(p, sizeof(mem_cache_conf));    sconf->min_cache_object_size = DEFAULT_MIN_CACHE_OBJECT_SIZE;    sconf->max_cache_object_size = DEFAULT_MAX_CACHE_OBJECT_SIZE;    /* Number of objects in the cache */    sconf->max_object_cnt = DEFAULT_MAX_OBJECT_CNT;    /* Size of the cache in bytes */    sconf->max_cache_size = DEFAULT_MAX_CACHE_SIZE;    sconf->cache_cache = NULL;    sconf->cache_remove_algorithm = memcache_gdsf_algorithm;    sconf->max_streaming_buffer_size = DEFAULT_MAX_STREAMING_BUFFER_SIZE;    return sconf;}static int create_entity(cache_handle_t *h, cache_type_e type_e,                         request_rec *r, const char *key, apr_off_t len) {    cache_object_t *obj, *tmp_obj;    mem_cache_object_t *mobj;    apr_size_t key_len;    if (len == -1) {        /* Caching a streaming response. Assume the response is         * less than or equal to max_streaming_buffer_size. We will         * correct all the cache size counters in store_body once         * we know exactly know how much we are caching.         */        len = sconf->max_streaming_buffer_size;    }    /* Note: cache_insert() will automatically garbage collect      * objects from the cache if the max_cache_size threshold is     * exceeded. This means mod_mem_cache does not need to implement     * max_cache_size checks.     */    if (len < sconf->min_cache_object_size ||         len > sconf->max_cache_object_size) {        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,                     "mem_cache: URL %s failed the size check and will not be cached.",                     key);        return DECLINED;    }    if (type_e == CACHE_TYPE_FILE) {        /* CACHE_TYPE_FILE is only valid for local content handled by the          * default handler. Need a better way to check if the file is         * local or not.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -