mod_mem_cache.c revision ecf435f0c6379df7ed83285d5597fc9aa39c6f6d
124N/A/* ==================================================================== 124N/A * The Apache Software License, Version 1.1 124N/A * Copyright (c) 2000-2002 The Apache Software Foundation. All rights 124N/A * Redistribution and use in source and binary forms, with or without 124N/A * modification, are permitted provided that the following conditions 124N/A * 1. Redistributions of source code must retain the above copyright 124N/A * notice, this list of conditions and the following disclaimer. 124N/A * 2. Redistributions in binary form must reproduce the above copyright 124N/A * notice, this list of conditions and the following disclaimer in 124N/A * the documentation and/or other materials provided with the 124N/A * 3. The end-user documentation included with the redistribution, 124N/A * if any, must include the following acknowledgment: 2317N/A * "This product includes software developed by the 124N/A * Alternately, this acknowledgment may appear in the software itself, 124N/A * if and wherever such third-party acknowledgments normally appear. 3472N/A * 4. The names "Apache" and "Apache Software Foundation" must 618N/A * not be used to endorse or promote products derived from this 124N/A * software without prior written permission. For written 124N/A * permission, please contact apache@apache.org. 3472N/A * 5. Products derived from this software may not be called "Apache", 618N/A * nor may "Apache" appear in their name, without prior written 1258N/A * permission of the Apache Software Foundation. 3472N/A * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 2899N/A * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 124N/A * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 124N/A * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 124N/A * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 124N/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2960N/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 2960N/A * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 2960N/A * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2960N/A * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 1776N/A * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 1776N/A * ==================================================================== 124N/A * This software consists of voluntary contributions made by many 3069N/A * individuals on behalf of the Apache Software Foundation. For more 3069N/A * information on the Apache Software Foundation, please see 124N/A * Portions of this software are based upon public domain software 124N/A * originally written at the National Center for Supercomputing Applications, 124N/A * University of Illinois, Urbana-Champaign. long priority;
/**< the priority of this entry */ long total_refs;
/**< total number of references this entry has had */ /* Fields set by config directives */ /* Forward declarations */ /** callback to get the key of a item */ * callback to free an entry * There is way too much magic in this code. Right now, this callback * is only called out of cache_insert() which is called under protection * of the sconf->lock, which means that we do not (and should not) * attempt to obtain the lock recursively. /* Cleanup the cache object. Object should be removed from the cache * now. Increment the refcount before setting cleanup to avoid a race * condition. A similar pattern is used in remove_url() * functions return a 'negative' score as lower is better in a priority Q * a 'proper' LRU function would just be * mobj->priority = mobj->total_refs; * We desperately need a more efficient way of allocating objects. We're * making way too many malloc calls to create a fully populated /* Cleanup the cache_object_t */ /* Cleanup the mem_cache_object_t */ /* If obj->complete is not set, the cache update failed and the * object needs to be removed from the cache then cleaned up. /* Remember, objects marked for cleanup are, by design, already * removed from the cache. remove_url() could have already * removed the object from the cache (and set obj->cleanup) /* Cleanup the cache object */ /* If the object is marked for cleanup and the refcount * has dropped to zero, cleanup the object /* Iterate over the cache and clean up each entry */ /* Free the object if the recount == 0 */ /* Cache is empty, free the cache table */ * TODO: enable directives to be overridden in various containers /* Number of objects in the cache */ /* Size of the cache in bytes */ /* In principle, we should be able to dispense with the cache_size checks * when caching open file descriptors. However, code in cache_insert() and * other places does not make the distinction whether a file's content or * descriptor is being cached. For now, just do all the same size checks * regardless of what we are caching. "cache_mem: URL %s failed the size check, " /* CACHE_TYPE_FILE is only valid for local content handled by the * default handler. Need a better way to check if the file is /* Allocate and initialize cache_object_t */ /* Safe cast: We tested < sconf->max_cache_object_size above */ /* Allocate and init mem_cache_object_t */ /* Finish initing the cache object */ /* Safe cast: We tested < sconf->max_cache_object_size above */ /* Place the cache_object_t into the hash table. * Note: Perhaps we should wait to put the object in the * hash table when the object is complete? I add the object here to * avoid multiple threads attempting to cache the same content only * to discover at the very end that only one of them will suceed. * Furthermore, adding the cache object to the table at the end could * open up a subtle but easy to exploit DoS hole: someone could request * a very large file with multiple requests. Better to detect this here * rather than after the cache object has been completely built and * XXX Need a way to insert into the cache w/o such coarse grained locking /* Safe cast: Must fit in cache_size or alloc would have failed */ /* This thread collided with another thread loading the same object * into the cache at the same time. Defer to the other thread which /* Populate the cache handle */ /* Look up entity keyed to 'url' */ /* cache is worried about overall counts, not 'open' ones */ /* If this is a subrequest, register the cleanup against * the main request. This will prevent the cache object * from being cleaned up from under the request after the * subrequest is destroyed. /* Initialize the cache_handle */ /* Remove the cache object from the cache under protection */ /* If the object is not already marked for cleanup, remove * it from the cache and mark it for cleanup. Remember, * an object marked for cleanup is by design not in the len +=
2;
/* Extra space for NULL string terminator for key and val */ /* Transfer the headers into a contiguous memory block */ for (i = 0; i < *
nelts; ++i) {
/* Define request processing hook handlers */ /* Order of the operations is important to avoid race conditions. * First, remove the object from the cache. Remember, all additions * deletions from the cache are protected by sconf->lock. * Increment the ref count on the object to indicate our thread * is accessing the object. Then set the cleanup flag on the * object. Remember, the cleanup flag is NEVER set on an * object in the hash table. If an object has the cleanup * flag set, it is guaranteed to NOT be in the hash table. /* Refcount increment in this case MUST be made under /* Content-Type: header may not be set if content is local since * CACHE_IN runs before header filters.... * The cache needs to keep track of the following information: * - Date, LastMod, Version, ReqTime, RespTime, ContentLength * - The original request headers (for Vary) * - The original response headers (for returning with a cached response) * - The body of the message /* Precompute how much storage we need to hold the headers */ /* Init the info struct */ /* 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 /* Open a new XTHREAD handle to the file */ /* Content not suitable for fd caching. Cache in-memory instead. */ /* Check to make sure the object will not exceed configured thresholds */ * FD cacheing is not enabled or the content was not * suitable for fd caching. /* Iterate accross the brigade and populate the cache storage */ /* Check for buffer overflow */ /* This should not fail, but if it does, we are in BIG trouble * cause we just stomped all over the heap. * Configuration and start-up /* Sanity check the cache configuration */ "MCacheMaxObjectSize must be greater than MCacheMinObjectSize");
"MCacheSize must be greater than MCacheMaxObjectSize");
return "MCacheSize argument must be an integer representing the max cache size in KBytes.";
return "MCacheMinObjectSize value must be an integer (bytes)";
return "MCacheMaxObjectSize value must be an integer (bytes)";
return "MCacheMaxObjectCount value must be an integer";
return "currently implemented algorithms are LRU and GDSF";
"The maximum amount of memory used by the cache in KBytes"),
"The maximum number of objects allowed to be placed in the cache"),
"The minimum size (in bytes) of an object to be placed in the cache"),
"The maximum size (in bytes) of an object to be placed in the cache"),
"The algorithm used to remove entries from the cache (default: GDSF)"),
/* cache_hook_init(cache_mem_init, NULL, NULL, APR_HOOK_MIDDLE); */ NULL,
/* create per-directory config structure */ NULL,
/* merge per-directory config structures */ NULL,
/* merge per-server config structures */