Changes with Apache 2.0.34-dev
+ *) Use apr_atomic operations in managing the mod_mem_cache
+ cache_objects for SMP scalability. (see USE_ATOMICS
+ preprocessor directive in mod_file_cache)
+ [Bill Stoddard]
+
+ *) Add filehandle caching to mod_mem_cache. (see CACHE_FD
+ preprocessor directive in mod_file_cache)
+ [Bill Stoddard]
+
+ *) Implement prototype mod_disk_cache for use with mod_cache.
+ [Bill Stoddard]
*) Add a missing manualdir entry in the Debian config.layout.
[Thom May <thom@planetarytramp.net>]
*/
#define CORE_PRIVATE
+/* CACHE_FD will eventually be exposed as a configuration directive */
#define CACHE_FD 0
#include "mod_cache.h"
#include "ap_mpm.h"
#include "apr_thread_mutex.h"
+/* USE_ATOMICS should be replaced with the appropriate APR feature macro */
+#define USE_ATOMICS
+#ifdef USE_ATOMICS
+#include "apr_atomic.h"
+#endif
+
#if !APR_HAS_THREADS
#error This module does not currently compile unless you have a thread-capable APR. Sorry!
#endif
{
cache_object_t *obj = (cache_object_t *) arg;
+#ifdef USE_ATOMICS
+ if (!apr_atomic_dec(&obj->refcount)) {
+ if (obj->cleanup) {
+ cleanup_cache_object(obj);
+ }
+ }
+#else
if (sconf->lock) {
apr_thread_mutex_lock(sconf->lock);
}
if (sconf->lock) {
apr_thread_mutex_unlock(sconf->lock);
}
+#endif
return APR_SUCCESS;
}
static apr_status_t cleanup_cache_mem(void *sconfv)
for (hi = apr_hash_first(NULL, co->cacheht); hi; hi=apr_hash_next(hi)) {
apr_hash_this(hi, NULL, NULL, (void **)&obj);
if (obj) {
+#ifdef USE_ATOMICS
+ apr_atomic_inc(&obj->refcount);
+ obj->cleanup = 1;
+ if (!apr_atomic_dec(&obj->refcount)) {
+#else
obj->cleanup = 1;
if (!obj->refcount) {
+#endif
cleanup_cache_object(obj);
}
}
{
cache_object_t *obj = h->cache_obj;
+ /* Remove the cache object from the cache */
if (sconf->lock) {
apr_thread_mutex_lock(sconf->lock);
}
apr_hash_set(sconf->cacheht, obj->key, strlen(obj->key), NULL);
sconf->object_cnt--;
sconf->cache_size -= mobj->m_len;
- obj->cleanup = 1;
- if (!obj->refcount) {
- cleanup_cache_object(obj);
- }
- h->cache_obj = NULL;
}
+ else {
+ /* If the object was removed from the cache prior to this function being
+ * called, then obj == NULL. Reinit obj with the object being cleaned up.
+ * Note: This code assumes that there is at most only one object in the
+ * cache per key.
+ */
+ obj = h->cache_obj;
+ }
+
+ /* Cleanup the cache object
+ * Set obj->cleanup to ensure decrement_refcount cleans up the obj if it
+ * is still being referenced by another thread
+ */
+ obj->cleanup = 1;
+#ifndef USE_ATOMICS
+ obj->refcount--;
+ if (!obj->refcount) {
+ cleanup_cache_object(obj);
+ }
+#endif
if (sconf->lock) {
apr_thread_mutex_unlock(sconf->lock);
}
-
+#ifdef USE_ATOMICS
+ if (!apr_atomic_dec(&obj->refcount)) {
+ cleanup_cache_object(obj);
+ }
+#endif
+ h->cache_obj = NULL;
return OK;
}
static apr_status_t serialize_table(cache_header_tbl_t **obj,
apr_hash_set(sconf->cacheht, key, APR_HASH_KEY_STRING, NULL);
sconf->object_cnt--;
sconf->cache_size -= mobj->m_len;
+ /* Set cleanup to ensure decrement_refcount cleans up the obj if it
+ * is still being referenced by another thread
+ */
obj->cleanup = 1;
+#ifdef USE_ATOMICS
+ /* Refcount increment MUST be made under protection of the lock */
+ obj->refcount++;
+#else
if (!obj->refcount) {
cleanup_cache_object(obj);
}
+#endif
}
if (sconf->lock) {
apr_thread_mutex_unlock(sconf->lock);
}
-
- if (!obj) {
- return DECLINED;
+#ifdef USE_ATOMICS
+ if (obj) {
+ if (!apr_atomic_dec(&obj->refcount)) {
+ cleanup_cache_object(obj);
+ }
}
-
+#endif
return OK;
}