cvs: pecl /apc apc_cache.c apc_cache.h apc_main.c
| From: | Rasmus Lerdorf | Date: | Wed, 08 Sep 2004 18:27:31 +0000 |
| Subject: | cvs: pecl /apc apc_cache.c apc_cache.h apc_main.c | ||
| Groups: | php.pecl.cvs | ||
| Request: | Send a blank email to pecl-cvs+get-1803@lists.php.net to get a copy of this message | ||
rasmus Wed Sep 8 14:27:31 2004 EDT
Modified files:
/pecl/apc apc_cache.c apc_cache.h apc_main.c
Log:
More APC robustness fixes aimed at handling running out of shared memory
more gracefully. This adds a previously missed out of memory check along
with apc_cache_expunge() which walks through and removes all cache entries
that haven't been accessed for TTL seconds. The idea here being that
there is no point removing something already in the cache that was
accessed recently in favour of the current cache attempt, but if there are
stale entries sitting around it is worth a bit of time getting rid of them.
http://cvs.php.net/diff.php/pecl/apc/apc_cache.c?r1=3.65&r2=3.66&ty=u Index: pecl/apc/apc_cache.c diff -u pecl/apc/apc_cache.c:3.65 pecl/apc/apc_cache.c:3.66 --- pecl/apc/apc_cache.c:3.65 Tue Sep 7 13:41:24 2004 +++ pecl/apc/apc_cache.c Wed Sep 8 14:27:30 2004 @@ -14,16 +14,12 @@ +----------------------------------------------------------------------+ */ -/* $Id: apc_cache.c,v 3.65 2004/09/07 17:41:24 rasmus Exp $ */ +/* $Id: apc_cache.c,v 3.66 2004/09/08 18:27:30 rasmus Exp $ */ #include "apc_cache.h" #include "apc_lock.h" #include "apc_sma.h" #include "SAPI.h" -#if HAVE_APACHE -#include "httpd.h" -#endif - /* TODO: rehash when load factor exceeds threshold */ @@ -254,13 +250,36 @@ } /* }}} */ +/* {{{ apc_cache_expunge */ +void apc_cache_expunge(apc_cache_t* cache, time_t t) +{ + int i; + slot_t *p; + + if(!cache || (cache && !cache->ttl)) return; + + LOCK(cache); + for (i = 0; i < cache->num_slots; i++) { + p = cache->slots[i]; + while(p) { + if(p->access_time < (t - cache->ttl)) { + remove_slot(cache, &p); + continue; + } + p = p->next; + } + } + UNLOCK(cache); +} +/* }}} */ + /* {{{ apc_cache_insert */ int apc_cache_insert(apc_cache_t* cache, apc_cache_key_t key, - apc_cache_entry_t* value) + apc_cache_entry_t* value, + time_t t) { slot_t** slot; - time_t t; if (!value) { return 0; @@ -271,14 +290,6 @@ slot = &cache->slots[hash(key) % cache->num_slots]; -#if HAVE_APACHE - /* Save a syscall here under Apache. This should actually be a SAPI call instead - * but we don't have that yet. Once that is introduced in PHP this can be cleaned up -Rasmus */ - t = ((request_rec *)SG(server_context))->request_time; -#else - t = time(0); -#endif - while (*slot) { if (key_equals((*slot)->key, key)) { if ((*slot)->key.mtime < key.mtime) { @@ -305,23 +316,14 @@ /* }}} */ /* {{{ apc_cache_find */ -apc_cache_entry_t* apc_cache_find(apc_cache_t* cache, apc_cache_key_t key) +apc_cache_entry_t* apc_cache_find(apc_cache_t* cache, apc_cache_key_t key, time_t t) { slot_t** slot; - time_t t; LOCK(cache); slot = &cache->slots[hash(key) % cache->num_slots]; - if(*slot) { -#if HAVE_APACHE - /* Save a syscall here under Apache. This should actually be a SAPI call instead - * but we don't have that yet. Once that is introduced this can be cleaned up -Rasmus */ - t = ((request_rec *)SG(server_context))->request_time; -#else - t = time(0); -#endif - } + while (*slot) { if (key_equals((*slot)->key, key)) { if ((*slot)->key.mtime < key.mtime) { http://cvs.php.net/diff.php/pecl/apc/apc_cache.h?r1=3.17&r2=3.18&ty=u Index: pecl/apc/apc_cache.h diff -u pecl/apc/apc_cache.h:3.17 pecl/apc/apc_cache.h:3.18 --- pecl/apc/apc_cache.h:3.17 Thu Aug 12 13:35:00 2004 +++ pecl/apc/apc_cache.h Wed Sep 8 14:27:30 2004 @@ -14,7 +14,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: apc_cache.h,v 3.17 2004/08/12 17:35:00 rasmus Exp $ */ +/* $Id: apc_cache.h,v 3.18 2004/09/08 18:27:30 rasmus Exp $ */ #ifndef APC_CACHE_H #define APC_CACHE_H @@ -96,7 +96,7 @@ * value is a cache entry returned by apc_cache_make_entry (see below). */ extern int apc_cache_insert(T cache, apc_cache_key_t key, - apc_cache_entry_t* value); + apc_cache_entry_t* value, time_t t); /* * apc_cache_find searches for a cache entry by filename, and returns a @@ -104,7 +104,7 @@ * * key is a value created by apc_cache_make_key. */ -extern apc_cache_entry_t* apc_cache_find(T cache, apc_cache_key_t key); +extern apc_cache_entry_t* apc_cache_find(T cache, apc_cache_key_t key, time_t t); /* * apc_cache_release decrements the reference count associated with a cache http://cvs.php.net/diff.php/pecl/apc/apc_main.c?r1=3.18&r2=3.19&ty=u Index: pecl/apc/apc_main.c diff -u pecl/apc/apc_main.c:3.18 pecl/apc/apc_main.c:3.19 --- pecl/apc/apc_main.c:3.18 Tue Sep 7 16:24:29 2004 +++ pecl/apc/apc_main.c Wed Sep 8 14:27:30 2004 @@ -14,7 +14,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: apc_main.c,v 3.18 2004/09/07 20:24:29 rasmus Exp $ */ +/* $Id: apc_main.c,v 3.19 2004/09/08 18:27:30 rasmus Exp $ */ #include "apc_php.h" #include "apc_main.h" @@ -25,6 +25,10 @@ #include "apc_sma.h" #include "apc_stack.h" #include "apc_zend.h" +#include "SAPI.h" +#if HAVE_APACHE +#include "httpd.h" +#endif /* {{{ module variables */ @@ -129,6 +133,7 @@ zend_op_array* alloc_op_array; apc_function_t* alloc_functions; apc_class_t* alloc_classes; + time_t t; /* check our regular expression filters first */ if (APCG(compiled_filters)) { @@ -140,13 +145,21 @@ return old_compile_file(h, type TSRMLS_CC); } +#if HAVE_APACHE + /* Save a syscall here under Apache. This should actually be a SAPI call instead + * but we don't have that yet. Once that is introduced in PHP this can be cleaned up -Rasmus */ + t = ((request_rec *)SG(server_context))->request_time; +#else + t = time(0); +#endif + /* try to create a cache key; if we fail, give up on caching */ if (!apc_cache_make_key(&key, h->filename, PG(include_path) TSRMLS_CC)) { return old_compile_file(h, type TSRMLS_CC); } /* search for the file in the cache */ - cache_entry = apc_cache_find(APCG(cache), key); + cache_entry = apc_cache_find(APCG(cache), key, t); if (cache_entry != NULL) { if (h->opened_path == NULL) { h->opened_path = estrdup(cache_entry->filename); @@ -168,30 +181,43 @@ HANDLE_BLOCK_INTERRUPTIONS(); if(!(alloc_op_array = apc_copy_op_array(NULL, op_array, apc_sma_malloc, apc_sma_free TSRMLS_CC))) { - apc_log(APC_WARNING, "(apc_copy_op_array) unable to cache '%s': insufficient " "shared memory available", h->opened_path); + apc_cache_expunge(APCG(cache),t); HANDLE_UNBLOCK_INTERRUPTIONS(); + apc_log(APC_WARNING, "(apc_copy_op_array) unable to cache '%s': insufficient " "shared memory available", h->opened_path); return op_array; } if(!(alloc_functions = apc_copy_new_functions(num_functions, apc_sma_malloc, apc_sma_free TSRMLS_CC))) { - apc_log(APC_WARNING, "(apc_copy_new_functions) unable to cache '%s': insufficient " "shared memory available", h->opened_path); apc_free_op_array(alloc_op_array, apc_sma_free); + apc_cache_expunge(APCG(cache),t); HANDLE_UNBLOCK_INTERRUPTIONS(); + apc_log(APC_WARNING, "(apc_copy_new_functions) unable to cache '%s': insufficient " "shared memory available", h->opened_path); return op_array; } if(!(alloc_classes = apc_copy_new_classes(op_array, num_classes, apc_sma_malloc, apc_sma_free TSRMLS_CC))) { + apc_free_op_array(alloc_op_array, apc_sma_free); + apc_free_functions(alloc_functions, apc_sma_free); + apc_cache_expunge(APCG(cache),t); + HANDLE_UNBLOCK_INTERRUPTIONS(); apc_log(APC_WARNING, "(apc_copy_new_classes) unable to cache '%s': insufficient " "shared memory available", h->opened_path); + return op_array; + } + + if(!(cache_entry = apc_cache_make_entry(h->opened_path, alloc_op_array, alloc_functions, alloc_classes))) { apc_free_op_array(alloc_op_array, apc_sma_free); apc_free_functions(alloc_functions, apc_sma_free); + apc_free_classes(alloc_classes, apc_sma_free); + apc_cache_expunge(APCG(cache),t); HANDLE_UNBLOCK_INTERRUPTIONS(); + apc_log(APC_WARNING, "(apc_cache_make_entry) unable to cache '%s': insufficient " "shared memory available", h->opened_path); return op_array; } HANDLE_UNBLOCK_INTERRUPTIONS(); - /* cache the compiler results */ - cache_entry = apc_cache_make_entry(h->opened_path, alloc_op_array, alloc_functions, alloc_classes); - if (!apc_cache_insert(APCG(cache), key, cache_entry)) { + if (!apc_cache_insert(APCG(cache), key, cache_entry, t)) { apc_cache_free_entry(cache_entry); + apc_cache_expunge(APCG(cache),t); + apc_log(APC_WARNING, "(apc_cache_insert) unable to cache '%s': insufficient " "shared memory available", h->opened_path); } return op_array;
http://cvs.php.net/diff.php/pecl/apc/apc_cache.c?r1=3.65&r2=3.66&ty=u Index: pecl/apc/apc_cache.c diff -u pecl/apc/apc_cache.c:3.65 pecl/apc/apc_cache.c:3.66 --- pecl/apc/apc_cache.c:3.65 Tue Sep 7 13:41:24 2004 +++ pecl/apc/apc_cache.c Wed Sep 8 14:27:30 2004 @@ -14,16 +14,12 @@ +----------------------------------------------------------------------+ */ -/* $Id: apc_cache.c,v 3.65 2004/09/07 17:41:24 rasmus Exp $ */ +/* $Id: apc_cache.c,v 3.66 2004/09/08 18:27:30 rasmus Exp $ */ #include "apc_cache.h" #include "apc_lock.h" #include "apc_sma.h" #include "SAPI.h" -#if HAVE_APACHE -#include "httpd.h" -#endif - /* TODO: rehash when load factor exceeds threshold */ @@ -254,13 +250,36 @@ } /* }}} */ +/* {{{ apc_cache_expunge */ +void apc_cache_expunge(apc_cache_t* cache, time_t t) +{ + int i; + slot_t *p; + + if(!cache || (cache && !cache->ttl)) return; + + LOCK(cache); + for (i = 0; i < cache->num_slots; i++) { + p = cache->slots[i]; + while(p) { + if(p->access_time < (t - cache->ttl)) { + remove_slot(cache, &p); + continue; + } + p = p->next; + } + } + UNLOCK(cache); +} +/* }}} */ + /* {{{ apc_cache_insert */ int apc_cache_insert(apc_cache_t* cache, apc_cache_key_t key, - apc_cache_entry_t* value) + apc_cache_entry_t* value, + time_t t) { slot_t** slot; - time_t t; if (!value) { return 0; @@ -271,14 +290,6 @@ slot = &cache->slots[hash(key) % cache->num_slots]; -#if HAVE_APACHE - /* Save a syscall here under Apache. This should actually be a SAPI call instead - * but we don't have that yet. Once that is introduced in PHP this can be cleaned up -Rasmus */ - t = ((request_rec *)SG(server_context))->request_time; -#else - t = time(0); -#endif - while (*slot) { if (key_equals((*slot)->key, key)) { if ((*slot)->key.mtime < key.mtime) { @@ -305,23 +316,14 @@ /* }}} */ /* {{{ apc_cache_find */ -apc_cache_entry_t* apc_cache_find(apc_cache_t* cache, apc_cache_key_t key) +apc_cache_entry_t* apc_cache_find(apc_cache_t* cache, apc_cache_key_t key, time_t t) { slot_t** slot; - time_t t; LOCK(cache); slot = &cache->slots[hash(key) % cache->num_slots]; - if(*slot) { -#if HAVE_APACHE - /* Save a syscall here under Apache. This should actually be a SAPI call instead - * but we don't have that yet. Once that is introduced this can be cleaned up -Rasmus */ - t = ((request_rec *)SG(server_context))->request_time; -#else - t = time(0); -#endif - } + while (*slot) { if (key_equals((*slot)->key, key)) { if ((*slot)->key.mtime < key.mtime) { http://cvs.php.net/diff.php/pecl/apc/apc_cache.h?r1=3.17&r2=3.18&ty=u Index: pecl/apc/apc_cache.h diff -u pecl/apc/apc_cache.h:3.17 pecl/apc/apc_cache.h:3.18 --- pecl/apc/apc_cache.h:3.17 Thu Aug 12 13:35:00 2004 +++ pecl/apc/apc_cache.h Wed Sep 8 14:27:30 2004 @@ -14,7 +14,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: apc_cache.h,v 3.17 2004/08/12 17:35:00 rasmus Exp $ */ +/* $Id: apc_cache.h,v 3.18 2004/09/08 18:27:30 rasmus Exp $ */ #ifndef APC_CACHE_H #define APC_CACHE_H @@ -96,7 +96,7 @@ * value is a cache entry returned by apc_cache_make_entry (see below). */ extern int apc_cache_insert(T cache, apc_cache_key_t key, - apc_cache_entry_t* value); + apc_cache_entry_t* value, time_t t); /* * apc_cache_find searches for a cache entry by filename, and returns a @@ -104,7 +104,7 @@ * * key is a value created by apc_cache_make_key. */ -extern apc_cache_entry_t* apc_cache_find(T cache, apc_cache_key_t key); +extern apc_cache_entry_t* apc_cache_find(T cache, apc_cache_key_t key, time_t t); /* * apc_cache_release decrements the reference count associated with a cache http://cvs.php.net/diff.php/pecl/apc/apc_main.c?r1=3.18&r2=3.19&ty=u Index: pecl/apc/apc_main.c diff -u pecl/apc/apc_main.c:3.18 pecl/apc/apc_main.c:3.19 --- pecl/apc/apc_main.c:3.18 Tue Sep 7 16:24:29 2004 +++ pecl/apc/apc_main.c Wed Sep 8 14:27:30 2004 @@ -14,7 +14,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: apc_main.c,v 3.18 2004/09/07 20:24:29 rasmus Exp $ */ +/* $Id: apc_main.c,v 3.19 2004/09/08 18:27:30 rasmus Exp $ */ #include "apc_php.h" #include "apc_main.h" @@ -25,6 +25,10 @@ #include "apc_sma.h" #include "apc_stack.h" #include "apc_zend.h" +#include "SAPI.h" +#if HAVE_APACHE +#include "httpd.h" +#endif /* {{{ module variables */ @@ -129,6 +133,7 @@ zend_op_array* alloc_op_array; apc_function_t* alloc_functions; apc_class_t* alloc_classes; + time_t t; /* check our regular expression filters first */ if (APCG(compiled_filters)) { @@ -140,13 +145,21 @@ return old_compile_file(h, type TSRMLS_CC); } +#if HAVE_APACHE + /* Save a syscall here under Apache. This should actually be a SAPI call instead + * but we don't have that yet. Once that is introduced in PHP this can be cleaned up -Rasmus */ + t = ((request_rec *)SG(server_context))->request_time; +#else + t = time(0); +#endif + /* try to create a cache key; if we fail, give up on caching */ if (!apc_cache_make_key(&key, h->filename, PG(include_path) TSRMLS_CC)) { return old_compile_file(h, type TSRMLS_CC); } /* search for the file in the cache */ - cache_entry = apc_cache_find(APCG(cache), key); + cache_entry = apc_cache_find(APCG(cache), key, t); if (cache_entry != NULL) { if (h->opened_path == NULL) { h->opened_path = estrdup(cache_entry->filename); @@ -168,30 +181,43 @@ HANDLE_BLOCK_INTERRUPTIONS(); if(!(alloc_op_array = apc_copy_op_array(NULL, op_array, apc_sma_malloc, apc_sma_free TSRMLS_CC))) { - apc_log(APC_WARNING, "(apc_copy_op_array) unable to cache '%s': insufficient " "shared memory available", h->opened_path); + apc_cache_expunge(APCG(cache),t); HANDLE_UNBLOCK_INTERRUPTIONS(); + apc_log(APC_WARNING, "(apc_copy_op_array) unable to cache '%s': insufficient " "shared memory available", h->opened_path); return op_array; } if(!(alloc_functions = apc_copy_new_functions(num_functions, apc_sma_malloc, apc_sma_free TSRMLS_CC))) { - apc_log(APC_WARNING, "(apc_copy_new_functions) unable to cache '%s': insufficient " "shared memory available", h->opened_path); apc_free_op_array(alloc_op_array, apc_sma_free); + apc_cache_expunge(APCG(cache),t); HANDLE_UNBLOCK_INTERRUPTIONS(); + apc_log(APC_WARNING, "(apc_copy_new_functions) unable to cache '%s': insufficient " "shared memory available", h->opened_path); return op_array; } if(!(alloc_classes = apc_copy_new_classes(op_array, num_classes, apc_sma_malloc, apc_sma_free TSRMLS_CC))) { + apc_free_op_array(alloc_op_array, apc_sma_free); + apc_free_functions(alloc_functions, apc_sma_free); + apc_cache_expunge(APCG(cache),t); + HANDLE_UNBLOCK_INTERRUPTIONS(); apc_log(APC_WARNING, "(apc_copy_new_classes) unable to cache '%s': insufficient " "shared memory available", h->opened_path); + return op_array; + } + + if(!(cache_entry = apc_cache_make_entry(h->opened_path, alloc_op_array, alloc_functions, alloc_classes))) { apc_free_op_array(alloc_op_array, apc_sma_free); apc_free_functions(alloc_functions, apc_sma_free); + apc_free_classes(alloc_classes, apc_sma_free); + apc_cache_expunge(APCG(cache),t); HANDLE_UNBLOCK_INTERRUPTIONS(); + apc_log(APC_WARNING, "(apc_cache_make_entry) unable to cache '%s': insufficient " "shared memory available", h->opened_path); return op_array; } HANDLE_UNBLOCK_INTERRUPTIONS(); - /* cache the compiler results */ - cache_entry = apc_cache_make_entry(h->opened_path, alloc_op_array, alloc_functions, alloc_classes); - if (!apc_cache_insert(APCG(cache), key, cache_entry)) { + if (!apc_cache_insert(APCG(cache), key, cache_entry, t)) { apc_cache_free_entry(cache_entry); + apc_cache_expunge(APCG(cache),t); + apc_log(APC_WARNING, "(apc_cache_insert) unable to cache '%s': insufficient " "shared memory available", h->opened_path); } return op_array;