? .apc_cache.c.swp ? .gdbinit ? local-cache.patch Index: apc_cache.c =================================================================== RCS file: /repository/pecl/apc/apc_cache.c,v retrieving revision 3.132 diff -u -r3.132 apc_cache.c --- apc_cache.c 24 Feb 2007 11:45:29 -0000 3.132 +++ apc_cache.c 27 Feb 2007 23:24:55 -0000 @@ -92,6 +92,25 @@ }; /* }}} */ +/* {{{ struct definition local_slot_t */ +typedef struct local_slot_t local_slot_t; +struct local_slot_t { + slot_t *original; /* the original slot in shm */ + int num_hits; /* number of hits */ + apc_cache_entry_t *value; /* shallow copy of slot->value */ +}; +/* }}} */ +/* {{{ struct definition apc_local_cache_t */ +struct apc_local_cache_t { + apc_cache_t* shmcache; /* the real cache in shm */ + local_slot_t* slots; /* process (local) cache of objects */ + int num_slots; /* number of slots in cache */ + int ttl; /* time to live */ + int num_hits; /* number of hits */ + int generation; /* every generation lives between expunges */ +}; +/* }}} */ + /* {{{ key_equals */ #define key_equals(a, b) (a.inode==b.inode && a.device==b.device) /* }}} */ @@ -548,11 +567,11 @@ } /* }}} */ -/* {{{ apc_cache_find */ -apc_cache_entry_t* apc_cache_find(apc_cache_t* cache, apc_cache_key_t key, time_t t) +/* {{{ apc_cache_find_slot */ +slot_t* apc_cache_find_slot(apc_cache_t* cache, apc_cache_key_t key, time_t t) { slot_t** slot; - volatile apc_cache_entry_t* value = NULL; + volatile slot_t* retval = NULL; LOCK(cache); if(key.type == APC_CACHE_KEY_FILE) slot = &cache->slots[hash(key) % cache->num_slots]; @@ -573,9 +592,9 @@ (*slot)->access_time = t; prevent_garbage_collection((*slot)->value); cache->header->num_hits++; - value = (*slot)->value; + retval = *slot; UNLOCK(cache); - return (apc_cache_entry_t*)value; + return (slot_t*)retval; } } else { /* APC_CACHE_KEY_FPFILE */ if(!memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) { @@ -585,9 +604,9 @@ (*slot)->access_time = t; prevent_garbage_collection((*slot)->value); cache->header->num_hits++; - value = (*slot)->value; + retval = *slot; UNLOCK(cache); - return (apc_cache_entry_t*)value; + return (slot_t*)retval; } } } @@ -599,6 +618,14 @@ } /* }}} */ +/* {{{ apc_cache_find */ +apc_cache_entry_t* apc_cache_find(apc_cache_t* cache, apc_cache_key_t key, time_t t) +{ + slot_t * slot = apc_cache_find_slot(cache, key, t); + return (slot) ? slot->value : NULL; +} +/* }}} */ + /* {{{ apc_cache_user_find */ apc_cache_entry_t* apc_cache_user_find(apc_cache_t* cache, char *strkey, int keylen, time_t t) { @@ -661,6 +688,8 @@ /* {{{ apc_cache_release */ void apc_cache_release(apc_cache_t* cache, apc_cache_entry_t* entry) { + if(entry->local) return; + LOCK(cache); entry->ref_count--; UNLOCK(cache); @@ -814,6 +843,8 @@ entry->type = APC_CACHE_ENTRY_FILE; entry->ref_count = 0; entry->mem_size = 0; + entry->autofiltered = 0; + entry->local = 0; return entry; } /* }}} */ @@ -954,6 +985,8 @@ entry->type = APC_CACHE_ENTRY_USER; entry->ref_count = 0; entry->mem_size = 0; + entry->autofiltered = 0; + entry->local = 0; return entry; } /* }}} */ @@ -1127,6 +1160,137 @@ /* }}} */ #endif +/* {{{ make_local_slot */ +static local_slot_t* make_local_slot(apc_local_cache_t* cache, slot_t* slot, local_slot_t* lslot) +{ + apc_cache_entry_t* value; + + value = apc_emalloc(sizeof(apc_cache_entry_t)); + memcpy(value, slot->value, sizeof(apc_cache_entry_t)); /* bitwise copy */ + value->local = 1; + + lslot->original = slot; + lslot->value = value; + lslot->num_hits++; + + return lslot; /* for what joy ? ... consistency */ +} +/* }}} */ + +/* {{{ free_local_slot */ +static void free_local_slot(apc_local_cache_t* cache, local_slot_t* lslot) +{ + if(!lslot->original) return; + + LOCK(cache->shmcache); + lslot->original->num_hits += lslot->num_hits; + UNLOCK(cache->shmcache); + + apc_cache_release(cache->shmcache, lslot->original->value); + apc_efree(lslot->value); +} +/* }}} */ + +/* {{{ apc_local_cache_create */ +apc_local_cache_t* apc_local_cache_create(apc_cache_t *shmcache, int num_slots, int ttl) +{ +#ifdef __APC_LOCAL_CACHE__ + apc_local_cache_t* cache = NULL; + + cache = (apc_local_cache_t*) apc_emalloc(sizeof(apc_local_cache_t)); + + cache->slots = (local_slot_t*) (apc_emalloc(sizeof(local_slot_t) * num_slots)); + memset(cache->slots, 0, sizeof(local_slot_t) * num_slots); + + cache->shmcache = shmcache; + cache->num_slots = num_slots; + cache->ttl = ttl; + cache->num_hits = 0; + cache->generation = shmcache->header->expunges; + + return cache; +#else + return NULL; +#endif +} +/* }}} */ + +/* {{{ apc_local_cache_destroy */ +void apc_local_cache_destroy(apc_local_cache_t* cache) +{ +#ifdef __APC_LOCAL_CACHE__ + int i; + for(i = 0; i < cache->num_slots; i++) { + /* too many lock/unlock calls in there ? */ + free_local_slot(cache, &cache->slots[i]); + } + + LOCK(cache->shmcache); + cache->shmcache->header->num_hits += cache->num_hits; + UNLOCK(cache->shmcache); + + apc_efree(cache->slots); + apc_efree(cache); +#endif +} +/* }}} */ + +/* {{{ local_cache_cleanup */ +static void local_cache_cleanup(apc_local_cache_t* cache, time_t t) { + int i; + for(i = 0; i < cache->num_slots; i++) { + slot_t * slot = cache->slots[i].original; + if((slot && slot->access_time < (t - cache->ttl)) || + cache->generation != cache->shmcache->header->expunges) { + free_local_slot(cache, &cache->slots[i]); + } + } +} +/* }}} */ + +/* {{{ apc_local_cache_find */ +apc_cache_entry_t* apc_local_cache_find(apc_local_cache_t* cache, apc_cache_key_t key, time_t t) +{ + slot_t* slot; + local_slot_t* lslot; + apc_cache_entry_t* entry; + + local_cache_cleanup(cache, t); + + if(key.type == APC_CACHE_KEY_FILE) lslot = &cache->slots[hash(key) % cache->num_slots]; + else lslot = &cache->slots[string_nhash_8(key.data.fpfile.fullpath, key.data.fpfile.fullpath_len) % cache->num_slots]; + + slot = lslot->original; + + if(slot && key.type == slot->key.type) { + if(key.type == APC_CACHE_KEY_FILE && + key_equals(slot->key.data.file, key.data.file)) { + if(slot->key.mtime != key.mtime) { + free_local_slot(cache, lslot); + goto not_found; + } + return lslot->value; + } else { + if(!memcmp(slot->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) { + return lslot->value; + } + } + } +not_found: + + slot = apc_cache_find_slot(cache->shmcache, key, t); + + if(!slot) return NULL; + + /* i.e maintain a sort of top list */ + if(lslot->original == NULL || (lslot->original->num_hits + lslot->num_hits) < slot->num_hits) { + free_local_slot(cache, lslot); + make_local_slot(cache, slot, lslot); + } + return (slot->value); +} +/* }}} */ + /* * Local variables: * tab-width: 4 Index: apc_cache.h =================================================================== RCS file: /repository/pecl/apc/apc_cache.h,v retrieving revision 3.43 diff -u -r3.43 apc_cache.h --- apc_cache.h 24 Feb 2007 11:45:29 -0000 3.43 +++ apc_cache.h 27 Feb 2007 23:25:00 -0000 @@ -94,6 +94,7 @@ apc_cache_entry_value_t data; unsigned char type; unsigned char autofiltered; + unsigned char local; int ref_count; size_t mem_size; }; @@ -286,6 +287,18 @@ extern zend_bool apc_cache_write_lock(apc_cache_t* cache); extern void apc_cache_write_unlock(apc_cache_t* cache); +/* + * Process local cache, which keeps a refcount hungry version of the slots + * for quick access without a lock - as long as the entry exists in local + * cache, the refcount of the shm version will be +1 more than required. + * It holds no data, only a shallow copy of apc_cache_entry. + */ +typedef struct apc_local_cache_t apc_local_cache_t; /* process-local cache */ + +extern apc_local_cache_t* apc_local_cache_create(apc_cache_t *shmcache, int num_slots, int ttl); +extern apc_cache_entry_t* apc_local_cache_find(apc_local_cache_t* cache, apc_cache_key_t key, time_t t); +extern void apc_local_cache_destroy(apc_local_cache_t* cache); + #undef T #endif Index: apc_globals.h =================================================================== RCS file: /repository/pecl/apc/apc_globals.h,v retrieving revision 3.57 diff -u -r3.57 apc_globals.h --- apc_globals.h 24 Feb 2007 23:06:09 -0000 3.57 +++ apc_globals.h 27 Feb 2007 23:25:01 -0000 @@ -79,6 +79,7 @@ #ifdef ZEND_ENGINE_2 int reserved_offset; /* offset for apc info in op_array->reserved[] */ #endif + apc_local_cache_t* fastcache;/* unlocked local cache */ ZEND_END_MODULE_GLOBALS(apc) /* (the following declaration is defined in php_apc.c) */ Index: apc_main.c =================================================================== RCS file: /repository/pecl/apc/apc_main.c,v retrieving revision 3.92 diff -u -r3.92 apc_main.c --- apc_main.c 6 Feb 2007 22:05:16 -0000 3.92 +++ apc_main.c 27 Feb 2007 23:25:10 -0000 @@ -329,9 +329,14 @@ if (!apc_cache_make_file_key(&key, h->filename, PG(include_path), t TSRMLS_CC)) { return old_compile_file(h, type TSRMLS_CC); } - + +#ifdef __APC_LOCAL_CACHE__ + /* search for the file in the local cache */ + cache_entry = apc_local_cache_find(APCG(fastcache), key, t); +#else /* search for the file in the cache */ cache_entry = apc_cache_find(apc_cache, key, t); +#endif if (cache_entry != NULL && !cache_entry->autofiltered) { int dummy = 1; if (h->opened_path == NULL) { @@ -470,7 +475,6 @@ } APCG(mem_size_ptr) = NULL; cache_entry->mem_size = mem_size; - cache_entry->autofiltered = 0; if ((ret = apc_cache_insert(apc_cache, key, cache_entry, t)) != 1) { apc_cache_free_entry(cache_entry); @@ -503,6 +507,7 @@ #endif apc_cache = apc_cache_create(APCG(num_files_hint), APCG(gc_ttl), APCG(ttl)); apc_user_cache = apc_cache_create(APCG(user_entries_hint), APCG(gc_ttl), APCG(user_ttl)); + apc_compiled_filters = apc_regex_compile_array(APCG(filters)); /* override compilation */ @@ -562,6 +567,27 @@ /* }}} */ +/* {{{ process init and shutdown */ +int apc_process_init(int module_number TSRMLS_DC) +{ + int minttl = APCG(gc_ttl) > APCG(ttl) ? APCG(ttl) : APCG(gc_ttl); + int size = (((APCG(num_files_hint)) / 32) | 32); /* min 32 */ + if(APCG(initialized)) { + APCG(fastcache) = apc_local_cache_create(apc_cache, size, minttl); + } + return 0; +} + +int apc_process_shutdown(TSRMLS_D) +{ + if(APCG(initialized) && APCG(fastcache)) { + apc_local_cache_destroy(APCG(fastcache)); + APCG(fastcache) = NULL; + } + return 0; +} +/* }}} */ + /* {{{ request init and shutdown */ int apc_request_init(TSRMLS_D) Index: apc_main.h =================================================================== RCS file: /repository/pecl/apc/apc_main.h,v retrieving revision 3.8 diff -u -r3.8 apc_main.h --- apc_main.h 12 Mar 2006 00:31:45 -0000 3.8 +++ apc_main.h 27 Feb 2007 23:25:11 -0000 @@ -40,6 +40,8 @@ extern int apc_module_init(int module_number TSRMLS_DC); extern int apc_module_shutdown(TSRMLS_D); +extern int apc_process_init(int module_number TSRMLS_DC); +extern int apc_process_shutdown(TSRMLS_D); extern int apc_request_init(TSRMLS_D); extern int apc_request_shutdown(TSRMLS_D); Index: php_apc.c =================================================================== RCS file: /repository/pecl/apc/php_apc.c,v retrieving revision 3.136 diff -u -r3.136 php_apc.c --- php_apc.c 27 Feb 2007 19:51:30 -0000 3.136 +++ php_apc.c 27 Feb 2007 23:25:44 -0000 @@ -217,15 +217,20 @@ APCG(enabled) = 0; } - if (APCG(enabled) && !APCG(initialized)) { - apc_module_init(module_number TSRMLS_CC); - apc_zend_init(TSRMLS_C); + if (APCG(enabled)) { + if(APCG(initialized)) { + apc_process_init(module_number TSRMLS_CC); + } else { + apc_module_init(module_number TSRMLS_CC); + apc_zend_init(TSRMLS_C); + apc_process_init(module_number TSRMLS_CC); #ifdef MULTIPART_EVENT_FORMDATA - /* File upload progress tracking */ - if(APCG(rfc1867)) { - php_rfc1867_callback = apc_rfc1867_progress; - } + /* File upload progress tracking */ + if(APCG(rfc1867)) { + php_rfc1867_callback = apc_rfc1867_progress; + } #endif + } } return SUCCESS; @@ -236,6 +241,7 @@ static PHP_MSHUTDOWN_FUNCTION(apc) { if(APCG(enabled)) { + apc_process_shutdown(TSRMLS_C); apc_zend_shutdown(TSRMLS_C); apc_module_shutdown(TSRMLS_C); #ifndef ZTS