📄 mod_mem_cache.c
字号:
int eos = 0; if (mobj->type == CACHE_TYPE_FILE) { apr_file_t *file = NULL; int fd = 0; int other = 0; /* We can cache an open file descriptor if: * - the brigade contains one and only one file_bucket && * - the brigade is complete && * - the file_bucket is the last data bucket in the brigade */ for (e = APR_BRIGADE_FIRST(b); e != APR_BRIGADE_SENTINEL(b); e = APR_BUCKET_NEXT(e)) { if (APR_BUCKET_IS_EOS(e)) { eos = 1; } else if (APR_BUCKET_IS_FILE(e)) { apr_bucket_file *a = e->data; fd++; file = a->fd; } else { other++; } } if (fd == 1 && !other && eos) { apr_file_t *tmpfile; const char *name; /* Open a new XTHREAD handle to the file */ apr_file_name_get(&name, file); mobj->flags = ((APR_SENDFILE_ENABLED & apr_file_flags_get(file)) | APR_READ | APR_BINARY | APR_XTHREAD | APR_FILE_NOCLEANUP); rv = apr_file_open(&tmpfile, name, mobj->flags, APR_OS_DEFAULT, r->pool); if (rv != APR_SUCCESS) { return rv; } apr_file_inherit_unset(tmpfile); apr_os_file_get(&(mobj->fd), tmpfile); /* Open for business */ ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, "mem_cache: Cached file: %s with key: %s", name, obj->key); obj->complete = 1; return APR_SUCCESS; } /* Content not suitable for fd caching. Cache in-memory instead. */ mobj->type = CACHE_TYPE_HEAP; } /* * FD cacheing is not enabled or the content was not * suitable for fd caching. */ if (mobj->m == NULL) { mobj->m = malloc(mobj->m_len); if (mobj->m == NULL) { return APR_ENOMEM; } obj->count = 0; } cur = (char*) mobj->m + obj->count; /* Iterate accross the brigade and populate the cache storage */ for (e = APR_BRIGADE_FIRST(b); e != APR_BRIGADE_SENTINEL(b); e = APR_BUCKET_NEXT(e)) { const char *s; apr_size_t len; if (APR_BUCKET_IS_EOS(e)) { if (mobj->m_len > obj->count) { /* Caching a streamed response. Reallocate a buffer of the * correct size and copy the streamed response into that * buffer */ char *buf = malloc(obj->count); if (!buf) { return APR_ENOMEM; } memcpy(buf, mobj->m, obj->count); free(mobj->m); mobj->m = buf; /* Now comes the crufty part... there is no way to tell the * cache that the size of the object has changed. We need * to remove the object, update the size and re-add the * object, all under protection of the lock. */ if (sconf->lock) { apr_thread_mutex_lock(sconf->lock); } /* Has the object been ejected from the cache? */ tobj = (cache_object_t *) cache_find(sconf->cache_cache, obj->key); if (tobj == obj) { /* Object is still in the cache, remove it, update the len field then * replace it under protection of sconf->lock. */ cache_remove(sconf->cache_cache, obj); /* For illustration, cache no longer has reference to the object * so decrement the refcount * apr_atomic_dec32(&obj->refcount); */ mobj->m_len = obj->count; cache_insert(sconf->cache_cache, obj); /* For illustration, cache now has reference to the object, so * increment the refcount * apr_atomic_inc32(&obj->refcount); */ } else if (tobj) { /* Different object with the same key found in the cache. Doing nothing * here will cause the object refcount to drop to 0 in decrement_refcount * and the object will be cleaned up. */ } else { /* Object has been ejected from the cache, add it back to the cache */ mobj->m_len = obj->count; cache_insert(sconf->cache_cache, obj); apr_atomic_inc32(&obj->refcount); } if (sconf->lock) { apr_thread_mutex_unlock(sconf->lock); } } /* Open for business */ ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, "mem_cache: Cached url: %s", obj->key); obj->complete = 1; break; } rv = apr_bucket_read(e, &s, &len, eblock); if (rv != APR_SUCCESS) { return rv; } if (len) { /* Check for buffer overflow */ if ((obj->count + len) > mobj->m_len) { return APR_ENOMEM; } else { memcpy(cur, s, len); cur+=len; obj->count+=len; } } /* This should not fail, but if it does, we are in BIG trouble * cause we just stomped all over the heap. */ AP_DEBUG_ASSERT(obj->count <= mobj->m_len); } return APR_SUCCESS;}/** * Configuration and start-up */static int mem_cache_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s){ int threaded_mpm; /* Sanity check the cache configuration */ if (sconf->min_cache_object_size >= sconf->max_cache_object_size) { ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, "MCacheMaxObjectSize must be greater than MCacheMinObjectSize"); return DONE; } if (sconf->max_cache_object_size >= sconf->max_cache_size) { ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, "MCacheSize must be greater than MCacheMaxObjectSize"); return DONE; } if (sconf->max_streaming_buffer_size > sconf->max_cache_object_size) { /* Issue a notice only if something other than the default config * is being used */ if (sconf->max_streaming_buffer_size != DEFAULT_MAX_STREAMING_BUFFER_SIZE && sconf->max_cache_object_size != DEFAULT_MAX_CACHE_OBJECT_SIZE) { ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, "MCacheMaxStreamingBuffer must be less than or equal to MCacheMaxObjectSize. " "Resetting MCacheMaxStreamingBuffer to MCacheMaxObjectSize."); } sconf->max_streaming_buffer_size = sconf->max_cache_object_size; } if (sconf->max_streaming_buffer_size < sconf->min_cache_object_size) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "MCacheMaxStreamingBuffer must be greater than or equal to MCacheMinObjectSize. " "Resetting MCacheMaxStreamingBuffer to MCacheMinObjectSize."); sconf->max_streaming_buffer_size = sconf->min_cache_object_size; } ap_mpm_query(AP_MPMQ_IS_THREADED, &threaded_mpm); if (threaded_mpm) { apr_thread_mutex_create(&sconf->lock, APR_THREAD_MUTEX_DEFAULT, p); } sconf->cache_cache = cache_init(sconf->max_object_cnt, sconf->max_cache_size, memcache_get_priority, sconf->cache_remove_algorithm, memcache_get_pos, memcache_set_pos, memcache_inc_frequency, memcache_cache_get_size, memcache_cache_get_key, memcache_cache_free); apr_pool_cleanup_register(p, sconf, cleanup_cache_mem, apr_pool_cleanup_null); if (sconf->cache_cache) return OK; return -1;}static const char*set_max_cache_size(cmd_parms *parms, void *in_struct_ptr, const char *arg){ apr_size_t val; if (sscanf(arg, "%" APR_SIZE_T_FMT, &val) != 1) { return "MCacheSize argument must be an integer representing the max cache size in KBytes."; } sconf->max_cache_size = val*1024; return NULL;}static const char*set_min_cache_object_size(cmd_parms *parms, void *in_struct_ptr, const char *arg){ apr_size_t val; if (sscanf(arg, "%" APR_SIZE_T_FMT, &val) != 1) { return "MCacheMinObjectSize value must be an integer (bytes)"; } sconf->min_cache_object_size = val; return NULL;}static const char*set_max_cache_object_size(cmd_parms *parms, void *in_struct_ptr, const char *arg){ apr_size_t val; if (sscanf(arg, "%" APR_SIZE_T_FMT, &val) != 1) { return "MCacheMaxObjectSize value must be an integer (bytes)"; } sconf->max_cache_object_size = val; return NULL;}static const char*set_max_object_count(cmd_parms *parms, void *in_struct_ptr, const char *arg){ apr_size_t val; if (sscanf(arg, "%" APR_SIZE_T_FMT, &val) != 1) { return "MCacheMaxObjectCount value must be an integer"; } sconf->max_object_cnt = val; return NULL;}static const char*set_cache_removal_algorithm(cmd_parms *parms, void *name, const char *arg){ if (strcasecmp("LRU", arg)) { sconf->cache_remove_algorithm = memcache_lru_algorithm; } else { if (strcasecmp("GDSF", arg)) { sconf->cache_remove_algorithm = memcache_gdsf_algorithm; } else { return "currently implemented algorithms are LRU and GDSF"; } } return NULL;}static const char *set_max_streaming_buffer(cmd_parms *parms, void *dummy, const char *arg){ char *err; if (apr_strtoff(&sconf->max_streaming_buffer_size, arg, &err, 10) || *err) { return "MCacheMaxStreamingBuffer value must be a number"; } return NULL;}static const command_rec cache_cmds[] ={ AP_INIT_TAKE1("MCacheSize", set_max_cache_size, NULL, RSRC_CONF, "The maximum amount of memory used by the cache in KBytes"), AP_INIT_TAKE1("MCacheMaxObjectCount", set_max_object_count, NULL, RSRC_CONF, "The maximum number of objects allowed to be placed in the cache"), AP_INIT_TAKE1("MCacheMinObjectSize", set_min_cache_object_size, NULL, RSRC_CONF, "The minimum size (in bytes) of an object to be placed in the cache"), AP_INIT_TAKE1("MCacheMaxObjectSize", set_max_cache_object_size, NULL, RSRC_CONF, "The maximum size (in bytes) of an object to be placed in the cache"), AP_INIT_TAKE1("MCacheRemovalAlgorithm", set_cache_removal_algorithm, NULL, RSRC_CONF, "The algorithm used to remove entries from the cache (default: GDSF)"), AP_INIT_TAKE1("MCacheMaxStreamingBuffer", set_max_streaming_buffer, NULL, RSRC_CONF, "Maximum number of bytes of content to buffer for a streamed response"), {NULL}};static const cache_provider cache_mem_provider ={ &remove_entity, &store_headers, &store_body, &recall_headers, &recall_body, &create_mem_entity, &open_entity, &remove_url,};static const cache_provider cache_fd_provider ={ &remove_entity, &store_headers, &store_body, &recall_headers, &recall_body, &create_fd_entity, &open_entity, &remove_url,};static void register_hooks(apr_pool_t *p){ ap_hook_post_config(mem_cache_post_config, NULL, NULL, APR_HOOK_MIDDLE); /* cache initializer */ /* cache_hook_init(cache_mem_init, NULL, NULL, APR_HOOK_MIDDLE); */ /* cache_hook_create_entity(create_entity, NULL, NULL, APR_HOOK_MIDDLE); cache_hook_open_entity(open_entity, NULL, NULL, APR_HOOK_MIDDLE); cache_hook_remove_url(remove_url, NULL, NULL, APR_HOOK_MIDDLE); */ ap_register_provider(p, CACHE_PROVIDER_GROUP, "mem", "0", &cache_mem_provider); ap_register_provider(p, CACHE_PROVIDER_GROUP, "fd", "0", &cache_fd_provider);}module AP_MODULE_DECLARE_DATA mem_cache_module ={ STANDARD20_MODULE_STUFF, NULL, /* create per-directory config structure */ NULL, /* merge per-directory config structures */ create_cache_config, /* create per-server config structure */ NULL, /* merge per-server config structures */ cache_cmds, /* command apr_table_t */ register_hooks};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -