[-]
[+]
|
Changed |
php5-APC.changes
|
|
[-]
[+]
|
Changed |
php5-APC.spec
^
|
|
[-]
[+]
|
Deleted |
APC-3.1.8.tar.bz2/APC-3.1.8/apc_cache.c
^
|
@@ -1,1380 +0,0 @@
-/*
- +----------------------------------------------------------------------+
- | APC |
- +----------------------------------------------------------------------+
- | Copyright (c) 2006-2011 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Authors: Daniel Cowgill <dcowgill@communityconnect.com> |
- | Rasmus Lerdorf <rasmus@php.net> |
- | Arun C. Murthy <arunc@yahoo-inc.com> |
- | Gopal Vijayaraghavan <gopalv@yahoo-inc.com> |
- +----------------------------------------------------------------------+
-
- This software was contributed to PHP by Community Connect Inc. in 2002
- and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
- Future revisions and derivatives of this source code must acknowledge
- Community Connect Inc. as the original contributor of this module by
- leaving this note intact in the source code.
-
- All other licensing and usage conditions are those of the PHP Group.
-
- */
-
-/* $Id: apc_cache.c 309488 2011-03-20 23:59:42Z pajoye $ */
-
-#include "apc_cache.h"
-#include "apc_zend.h"
-#include "apc_sma.h"
-#include "apc_globals.h"
-#include "SAPI.h"
-#include "TSRM.h"
-#include "ext/standard/md5.h"
-
-/* TODO: rehash when load factor exceeds threshold */
-
-#define CHECK(p) { if ((p) == NULL) return NULL; }
-
-/* {{{ key_equals */
-#define key_equals(a, b) (a.inode==b.inode && a.device==b.device)
-/* }}} */
-
-static void apc_cache_expunge(apc_cache_t* cache, size_t size TSRMLS_DC);
-
-/* {{{ hash */
-static unsigned long hash(apc_cache_key_t key)
-{
- return (unsigned long)(key.data.file.device + key.data.file.inode);
-}
-/* }}} */
-
-/* {{{ string_nhash_8 */
-#define string_nhash_8(s,len) (unsigned long)(zend_inline_hash_func((s), len))
-/* }}} */
-
-/* {{{ murmurhash */
-#if 0
-static inline unsigned long murmurhash(const char *skey, size_t keylen)
-{
- const long m = 0x7fd652ad;
- const long r = 16;
- unsigned int h = 0xdeadbeef;
-
- while(keylen >= 4)
- {
- h += *(unsigned int*)skey;
- h *= m;
- h ^= h >> r;
-
- skey += 4;
- keylen -= 4;
- }
-
- switch(keylen)
- {
- case 3:
- h += skey[2] << 16;
- case 2:
- h += skey[1] << 8;
- case 1:
- h += skey[0];
- h *= m;
- h ^= h >> r;
- };
-
- h *= m;
- h ^= h >> 10;
- h *= m;
- h ^= h >> 17;
-
- return h;
-}
-#endif
-/* }}} */
-
-
-/* {{{ make_prime */
-static int const primes[] = {
- 257, /* 256 */
- 521, /* 512 */
- 1031, /* 1024 */
- 2053, /* 2048 */
- 3079, /* 3072 */
- 4099, /* 4096 */
- 5147, /* 5120 */
- 6151, /* 6144 */
- 7177, /* 7168 */
- 8209, /* 8192 */
- 9221, /* 9216 */
-10243, /* 10240 */
-11273, /* 11264 */
-12289, /* 12288 */
-13313, /* 13312 */
-14341, /* 14336 */
-15361, /* 15360 */
-16411, /* 16384 */
-17417, /* 17408 */
-18433, /* 18432 */
-19457, /* 19456 */
-0 /* sentinel */
-};
-
-static int make_prime(int n)
-{
- int *k = (int*)primes;
- while(*k) {
- if((*k) > n) return *k;
- k++;
- }
- return *(k-1);
-}
-/* }}} */
-
-/* {{{ make_slot */
-slot_t* make_slot(apc_cache_key_t *key, apc_cache_entry_t* value, slot_t* next, time_t t TSRMLS_DC)
-{
- slot_t* p = apc_pool_alloc(value->pool, sizeof(slot_t));
-
- if (!p) return NULL;
-
- if(key->type == APC_CACHE_KEY_USER) {
- char *identifier = (char*) apc_pmemcpy(key->data.user.identifier, key->data.user.identifier_len, value->pool TSRMLS_CC);
- if (!identifier) {
- return NULL;
- }
- key->data.user.identifier = identifier;
- } else if(key->type == APC_CACHE_KEY_FPFILE) {
- char *fullpath = (char*) apc_pstrdup(key->data.fpfile.fullpath, value->pool TSRMLS_CC);
- if (!fullpath) {
- return NULL;
- }
- key->data.fpfile.fullpath = fullpath;
- }
- p->key = key[0];
- p->value = value;
- p->next = next;
- p->num_hits = 0;
- p->creation_time = t;
- p->access_time = t;
- p->deletion_time = 0;
- return p;
-}
-/* }}} */
-
-/* {{{ free_slot */
-static void free_slot(slot_t* slot TSRMLS_DC)
-{
- apc_pool_destroy(slot->value->pool TSRMLS_CC);
-}
-/* }}} */
-
-/* {{{ remove_slot */
-static void remove_slot(apc_cache_t* cache, slot_t** slot TSRMLS_DC)
-{
- slot_t* dead = *slot;
- *slot = (*slot)->next;
-
- cache->header->mem_size -= dead->value->mem_size;
- CACHE_FAST_DEC(cache, cache->header->num_entries);
- if (dead->value->ref_count <= 0) {
- free_slot(dead TSRMLS_CC);
- }
- else {
- dead->next = cache->header->deleted_list;
- dead->deletion_time = time(0);
- cache->header->deleted_list = dead;
- }
-}
-/* }}} */
-
-/* {{{ process_pending_removals */
-static void process_pending_removals(apc_cache_t* cache TSRMLS_DC)
-{
- slot_t** slot;
- time_t now;
-
- /* This function scans the list of removed cache entries and deletes any
- * entry whose reference count is zero (indicating that it is no longer
- * being executed) or that has been on the pending list for more than
- * cache->gc_ttl seconds (we issue a warning in the latter case).
- */
-
- if (!cache->header->deleted_list)
- return;
-
- slot = &cache->header->deleted_list;
- now = time(0);
-
- while (*slot != NULL) {
- int gc_sec = cache->gc_ttl ? (now - (*slot)->deletion_time) : 0;
-
- if ((*slot)->value->ref_count <= 0 || gc_sec > cache->gc_ttl) {
- slot_t* dead = *slot;
-
- if (dead->value->ref_count > 0) {
- switch(dead->value->type) {
- case APC_CACHE_ENTRY_FILE:
- apc_debug("GC cache entry '%s' (dev=%d ino=%d) was on gc-list for %d seconds" TSRMLS_CC,
- dead->value->data.file.filename, dead->key.data.file.device, dead->key.data.file.inode, gc_sec);
- break;
- case APC_CACHE_ENTRY_USER:
- apc_debug("GC cache entry '%s' was on gc-list for %d seconds" TSRMLS_CC, dead->value->data.user.info, gc_sec);
- break;
- }
- }
- *slot = dead->next;
- free_slot(dead TSRMLS_CC);
- }
- else {
- slot = &(*slot)->next;
- }
- }
-}
-/* }}} */
-
-/* {{{ prevent_garbage_collection */
-static void prevent_garbage_collection(apc_cache_entry_t* entry)
-{
- /* set reference counts on zend objects to an arbitrarily high value to
- * prevent garbage collection after execution */
-
- enum { BIG_VALUE = 1000 };
-
- if(entry->data.file.op_array) {
- entry->data.file.op_array->refcount[0] = BIG_VALUE;
- }
- if (entry->data.file.functions) {
- int i;
- apc_function_t* fns = entry->data.file.functions;
- for (i=0; fns[i].function != NULL; i++) {
- *(fns[i].function->op_array.refcount) = BIG_VALUE;
- }
- }
- if (entry->data.file.classes) {
- int i;
- apc_class_t* classes = entry->data.file.classes;
- for (i=0; classes[i].class_entry != NULL; i++) {
- classes[i].class_entry->refcount = BIG_VALUE;
- }
- }
-}
-/* }}} */
-
-/* {{{ apc_cache_create */
-apc_cache_t* apc_cache_create(int size_hint, int gc_ttl, int ttl TSRMLS_DC)
-{
- apc_cache_t* cache;
- int cache_size;
- int num_slots;
-
- num_slots = make_prime(size_hint > 0 ? size_hint : 2000);
-
- cache = (apc_cache_t*) apc_emalloc(sizeof(apc_cache_t) TSRMLS_CC);
- cache_size = sizeof(cache_header_t) + num_slots*sizeof(slot_t*);
-
- cache->shmaddr = apc_sma_malloc(cache_size TSRMLS_CC);
- if(!cache->shmaddr) {
- apc_error("Unable to allocate shared memory for cache structures. (Perhaps your shared memory size isn't large enough?). " TSRMLS_CC);
- return NULL;
- }
- memset(cache->shmaddr, 0, cache_size);
-
- cache->header = (cache_header_t*) cache->shmaddr;
- cache->header->num_hits = 0;
- cache->header->num_misses = 0;
- cache->header->deleted_list = NULL;
- cache->header->start_time = time(NULL);
- cache->header->expunges = 0;
- cache->header->busy = 0;
-
- cache->slots = (slot_t**) (((char*) cache->shmaddr) + sizeof(cache_header_t));
- cache->num_slots = num_slots;
- cache->gc_ttl = gc_ttl;
- cache->ttl = ttl;
- CREATE_LOCK(cache->header->lock);
-#if NONBLOCKING_LOCK_AVAILABLE
- CREATE_LOCK(cache->header->wrlock);
-#endif
- memset(cache->slots, 0, sizeof(slot_t*)*num_slots);
- cache->expunge_cb = apc_cache_expunge;
- cache->has_lock = 0;
-
- return cache;
-}
-/* }}} */
-
-/* {{{ apc_cache_destroy */
-void apc_cache_destroy(apc_cache_t* cache TSRMLS_DC)
-{
- DESTROY_LOCK(cache->header->lock);
-#ifdef NONBLOCKING_LOCK_AVAILABLE
- DESTROY_LOCK(cache->header->wrlock);
-#endif
- apc_efree(cache TSRMLS_CC);
-}
-/* }}} */
-
-/* {{{ apc_cache_clear */
-void apc_cache_clear(apc_cache_t* cache TSRMLS_DC)
-{
- int i;
-
- if(!cache) return;
-
- CACHE_LOCK(cache);
- cache->header->busy = 1;
- cache->header->num_hits = 0;
- cache->header->num_misses = 0;
- cache->header->start_time = time(NULL);
- cache->header->expunges = 0;
-
- for (i = 0; i < cache->num_slots; i++) {
- slot_t* p = cache->slots[i];
- while (p) {
- remove_slot(cache, &p TSRMLS_CC);
- }
- cache->slots[i] = NULL;
- }
-
- memset(&cache->header->lastkey, 0, sizeof(apc_keyid_t));
-
- cache->header->busy = 0;
- CACHE_UNLOCK(cache);
-}
-/* }}} */
-
-/* {{{ apc_cache_expunge */
-static void apc_cache_expunge(apc_cache_t* cache, size_t size TSRMLS_DC)
-{
- int i;
- time_t t;
-
- t = apc_time();
-
- if(!cache) return;
-
- if(!cache->ttl) {
- /*
- * If cache->ttl is not set, we wipe out the entire cache when
- * we run out of space.
- */
- CACHE_SAFE_LOCK(cache);
- process_pending_removals(cache TSRMLS_CC);
- if (apc_sma_get_avail_mem() > (size_t)(APCG(shm_size)/2)) {
- /* probably a queued up expunge, we don't need to do this */
- CACHE_SAFE_UNLOCK(cache);
- return;
- }
- cache->header->busy = 1;
- CACHE_FAST_INC(cache, cache->header->expunges);
-clear_all:
- for (i = 0; i < cache->num_slots; i++) {
- slot_t* p = cache->slots[i];
- while (p) {
- remove_slot(cache, &p TSRMLS_CC);
- }
- cache->slots[i] = NULL;
- }
- memset(&cache->header->lastkey, 0, sizeof(apc_keyid_t));
- cache->header->busy = 0;
- CACHE_SAFE_UNLOCK(cache);
- } else {
- slot_t **p;
- /*
- * If the ttl for the cache is set we walk through and delete stale
- * entries. For the user cache that is slightly confusing since
- * we have the individual entry ttl's we can look at, but that would be
- * too much work. So if you want the user cache expunged, set a high
- * default apc.user_ttl and still provide a specific ttl for each entry
- * on insert
- */
-
- CACHE_SAFE_LOCK(cache);
- process_pending_removals(cache TSRMLS_CC);
- if (apc_sma_get_avail_mem() > (size_t)(APCG(shm_size)/2)) {
- /* probably a queued up expunge, we don't need to do this */
- CACHE_SAFE_UNLOCK(cache);
- return;
- }
- cache->header->busy = 1;
- CACHE_FAST_INC(cache, cache->header->expunges);
- for (i = 0; i < cache->num_slots; i++) {
- p = &cache->slots[i];
- while(*p) {
- /*
- * For the user cache we look at the individual entry ttl values
- * and if not set fall back to the default ttl for the user cache
- */
- if((*p)->value->type == APC_CACHE_ENTRY_USER) {
- if((*p)->value->data.user.ttl) {
- if((time_t) ((*p)->creation_time + (*p)->value->data.user.ttl) < t) {
- remove_slot(cache, p TSRMLS_CC);
- continue;
- }
- } else if(cache->ttl) {
- if((*p)->creation_time + cache->ttl < t) {
- remove_slot(cache, p TSRMLS_CC);
- continue;
- }
- }
- } else if((*p)->access_time < (t - cache->ttl)) {
- remove_slot(cache, p TSRMLS_CC);
- continue;
- }
- p = &(*p)->next;
- }
- }
-
- if (!apc_sma_get_avail_size(size)) {
- /* TODO: re-do this to remove goto across locked sections */
- goto clear_all;
- }
- memset(&cache->header->lastkey, 0, sizeof(apc_keyid_t));
- cache->header->busy = 0;
- CACHE_SAFE_UNLOCK(cache);
- }
-}
-/* }}} */
-
-/* {{{ apc_cache_insert */
-static inline int _apc_cache_insert(apc_cache_t* cache,
- apc_cache_key_t key,
- apc_cache_entry_t* value,
- apc_context_t* ctxt,
- time_t t
- TSRMLS_DC)
-{
- slot_t** slot;
-
- if (!value) {
- return 0;
- }
-
- apc_debug("Inserting [%s]\n" TSRMLS_CC, value->data.file.filename);
-
- process_pending_removals(cache TSRMLS_CC);
-
- slot = &cache->slots[key.h % cache->num_slots];
-
- while(*slot) {
- if(key.type == (*slot)->key.type) {
- if(key.type == APC_CACHE_KEY_FILE) {
- if(key_equals((*slot)->key.data.file, key.data.file)) {
- /* If existing slot for the same device+inode is different, remove it and insert the new version */
- if (ctxt->force_update || (*slot)->key.mtime != key.mtime) {
- remove_slot(cache, slot TSRMLS_CC);
- break;
- }
- return 0;
- } else if(cache->ttl && (*slot)->access_time < (t - cache->ttl)) {
- remove_slot(cache, slot TSRMLS_CC);
- continue;
- }
- } else { /* APC_CACHE_KEY_FPFILE */
- if((key.h == (*slot)->key.h) &&
- !memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) {
- /* Hrm.. it's already here, remove it and insert new one */
- remove_slot(cache, slot TSRMLS_CC);
- break;
- } else if(cache->ttl && (*slot)->access_time < (t - cache->ttl)) {
- remove_slot(cache, slot TSRMLS_CC);
- continue;
- }
- }
- }
- slot = &(*slot)->next;
- }
-
- if ((*slot = make_slot(&key, value, *slot, t TSRMLS_CC)) == NULL) {
- return -1;
- }
-
- value->mem_size = ctxt->pool->size;
- cache->header->mem_size += ctxt->pool->size;
- CACHE_FAST_INC(cache, cache->header->num_entries);
- CACHE_FAST_INC(cache, cache->header->num_inserts);
-
- return 1;
-}
-/* }}} */
-
-/* {{{ apc_cache_insert */
-int apc_cache_insert(apc_cache_t* cache, apc_cache_key_t key, apc_cache_entry_t* value, apc_context_t *ctxt, time_t t TSRMLS_DC)
-{
- int rval;
- CACHE_LOCK(cache);
- rval = _apc_cache_insert(cache, key, value, ctxt, t TSRMLS_CC);
- CACHE_UNLOCK(cache);
- return rval;
-}
-/* }}} */
-
-/* {{{ apc_cache_insert */
-int *apc_cache_insert_mult(apc_cache_t* cache, apc_cache_key_t* keys, apc_cache_entry_t** values, apc_context_t *ctxt, time_t t, int num_entries TSRMLS_DC)
-{
- int *rval;
- int i;
-
- rval = emalloc(sizeof(int) * num_entries);
- CACHE_LOCK(cache);
- for (i=0; i < num_entries; i++) {
- if (values[i]) {
- ctxt->pool = values[i]->pool;
- rval[i] = _apc_cache_insert(cache, keys[i], values[i], ctxt, t TSRMLS_CC);
- }
- }
- CACHE_UNLOCK(cache);
- return rval;
-}
-/* }}} */
-
-
-/* {{{ apc_cache_user_insert */
-int apc_cache_user_insert(apc_cache_t* cache, apc_cache_key_t key, apc_cache_entry_t* value, apc_context_t* ctxt, time_t t, int exclusive TSRMLS_DC)
-{
- slot_t** slot;
- unsigned int keylen = key.data.user.identifier_len;
- apc_keyid_t *lastkey = &cache->header->lastkey;
-
- if (!value) {
- return 0;
- }
-
- if(apc_cache_busy(cache)) {
- /* cache cleanup in progress, do not wait */
- return 0;
- }
-
- if(apc_cache_is_last_key(cache, &key, t TSRMLS_CC)) {
- /* potential cache slam */
- return 0;
- }
-
- CACHE_LOCK(cache);
-
- memset(lastkey, 0, sizeof(apc_keyid_t));
-
- lastkey->h = key.h;
- lastkey->keylen = keylen;
- lastkey->mtime = t;
-#ifdef ZTS
- lastkey->tid = tsrm_thread_id();
-#else
- lastkey->pid = getpid();
-#endif
-
- /* we do not reset lastkey after the insert. Whether it is inserted
- * or not, another insert in the same second is always a bad idea.
- */
-
- process_pending_removals(cache TSRMLS_CC);
-
- slot = &cache->slots[key.h % cache->num_slots];
-
- while (*slot) {
- if (((*slot)->key.h == key.h) &&
- (!memcmp((*slot)->key.data.user.identifier, key.data.user.identifier, keylen))) {
- /*
- * At this point we have found the user cache entry. If we are doing
- * an exclusive insert (apc_add) we are going to bail right away if
- * the user entry already exists and it has no ttl, or
- * there is a ttl and the entry has not timed out yet.
- */
- if(exclusive && ( !(*slot)->value->data.user.ttl ||
- ( (*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) >= t )
- ) ) {
- goto fail;
- }
- remove_slot(cache, slot TSRMLS_CC);
- break;
- } else
- /*
- * This is a bit nasty. The idea here is to do runtime cleanup of the linked list of
- * slot entries so we don't always have to skip past a bunch of stale entries. We check
- * for staleness here and get rid of them by first checking to see if the cache has a global
- * access ttl on it and removing entries that haven't been accessed for ttl seconds and secondly
- * we see if the entry has a hard ttl on it and remove it if it has been around longer than its ttl
- */
- if((cache->ttl && (*slot)->access_time < (t - cache->ttl)) ||
- ((*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t)) {
- remove_slot(cache, slot TSRMLS_CC);
- continue;
- }
- slot = &(*slot)->next;
- }
-
- if ((*slot = make_slot(&key, value, *slot, t TSRMLS_CC)) == NULL) {
- goto fail;
- }
-
- value->mem_size = ctxt->pool->size;
- cache->header->mem_size += ctxt->pool->size;
-
- CACHE_FAST_INC(cache, cache->header->num_entries);
- CACHE_FAST_INC(cache, cache->header->num_inserts);
-
- CACHE_UNLOCK(cache);
-
- return 1;
-
-fail:
- CACHE_UNLOCK(cache);
-
- return 0;
-}
-/* }}} */
-
-/* {{{ apc_cache_find_slot */
-slot_t* apc_cache_find_slot(apc_cache_t* cache, apc_cache_key_t key, time_t t TSRMLS_DC)
-{
- slot_t** slot;
- volatile slot_t* retval = NULL;
-
- CACHE_RDLOCK(cache);
- if(key.type == APC_CACHE_KEY_FILE) slot = &cache->slots[hash(key) % cache->num_slots];
- else slot = &cache->slots[key.h % cache->num_slots];
-
- while (*slot) {
- if(key.type == (*slot)->key.type) {
- if(key.type == APC_CACHE_KEY_FILE) {
- if(key_equals((*slot)->key.data.file, key.data.file)) {
- if((*slot)->key.mtime != key.mtime) {
- #if (USE_READ_LOCKS == 0)
- /* this is merely a memory-friendly optimization, if we do have a write-lock
- * might as well move this to the deleted_list right-away. Otherwise an insert
- * of the same key wil do it (or an expunge, *eventually*).
- */
- remove_slot(cache, slot TSRMLS_CC);
- #endif
- CACHE_SAFE_INC(cache, cache->header->num_misses);
- CACHE_RDUNLOCK(cache);
- return NULL;
- }
- CACHE_SAFE_INC(cache, (*slot)->num_hits);
- CACHE_SAFE_INC(cache, (*slot)->value->ref_count);
- (*slot)->access_time = t;
- prevent_garbage_collection((*slot)->value);
- CACHE_FAST_INC(cache, cache->header->num_hits);
- retval = *slot;
- CACHE_RDUNLOCK(cache);
- return (slot_t*)retval;
- }
- } else { /* APC_CACHE_KEY_FPFILE */
- if(((*slot)->key.h == key.h) &&
- !memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) {
- /* TTL Check ? */
- CACHE_SAFE_INC(cache, (*slot)->num_hits);
- CACHE_SAFE_INC(cache, (*slot)->value->ref_count);
- (*slot)->access_time = t;
- prevent_garbage_collection((*slot)->value);
- CACHE_FAST_INC(cache, cache->header->num_hits);
- retval = *slot;
- CACHE_RDUNLOCK(cache);
- return (slot_t*)retval;
- }
- }
- }
- slot = &(*slot)->next;
- }
- CACHE_FAST_INC(cache, cache->header->num_misses);
- CACHE_RDUNLOCK(cache);
- return NULL;
-}
-/* }}} */
-
-/* {{{ apc_cache_find */
-apc_cache_entry_t* apc_cache_find(apc_cache_t* cache, apc_cache_key_t key, time_t t TSRMLS_DC)
-{
- slot_t * slot = apc_cache_find_slot(cache, key, t TSRMLS_CC);
- apc_debug("apc_cache_find [%i]\n" TSRMLS_CC, key.h);
- 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 TSRMLS_DC)
-{
- slot_t** slot;
- volatile apc_cache_entry_t* value = NULL;
- unsigned long h;
-
- if(apc_cache_busy(cache))
- {
- /* cache cleanup in progress */
- return NULL;
- }
-
- CACHE_RDLOCK(cache);
-
- h = string_nhash_8(strkey, keylen);
-
- slot = &cache->slots[h % cache->num_slots];
-
- while (*slot) {
- if ((h == (*slot)->key.h) &&
- !memcmp((*slot)->key.data.user.identifier, strkey, keylen)) {
- /* Check to make sure this entry isn't expired by a hard TTL */
- if((*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t) {
- #if (USE_READ_LOCKS == 0)
- /* this is merely a memory-friendly optimization, if we do have a write-lock
- * might as well move this to the deleted_list right-away. Otherwise an insert
- * of the same key wil do it (or an expunge, *eventually*).
- */
- remove_slot(cache, slot TSRMLS_CC);
- #endif
- CACHE_FAST_INC(cache, cache->header->num_misses);
- CACHE_RDUNLOCK(cache);
- return NULL;
- }
- /* Otherwise we are fine, increase counters and return the cache entry */
- CACHE_SAFE_INC(cache, (*slot)->num_hits);
- CACHE_SAFE_INC(cache, (*slot)->value->ref_count);
- (*slot)->access_time = t;
-
- CACHE_FAST_INC(cache, cache->header->num_hits);
- value = (*slot)->value;
- CACHE_RDUNLOCK(cache);
- return (apc_cache_entry_t*)value;
- }
- slot = &(*slot)->next;
- }
-
- CACHE_FAST_INC(cache, cache->header->num_misses);
- CACHE_RDUNLOCK(cache);
- return NULL;
-}
-/* }}} */
-
-/* {{{ apc_cache_user_exists */
-apc_cache_entry_t* apc_cache_user_exists(apc_cache_t* cache, char *strkey, int keylen, time_t t TSRMLS_DC)
-{
- slot_t** slot;
- volatile apc_cache_entry_t* value = NULL;
- unsigned long h;
-
- if(apc_cache_busy(cache))
- {
- /* cache cleanup in progress */
- return NULL;
- }
-
- CACHE_RDLOCK(cache);
-
- h = string_nhash_8(strkey, keylen);
-
- slot = &cache->slots[h % cache->num_slots];
-
- while (*slot) {
- if ((h == (*slot)->key.h) &&
- !memcmp((*slot)->key.data.user.identifier, strkey, keylen)) {
- /* Check to make sure this entry isn't expired by a hard TTL */
- if((*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t) {
- CACHE_UNLOCK(cache);
- return NULL;
- }
- /* Return the cache entry ptr */
- value = (*slot)->value;
- CACHE_RDUNLOCK(cache);
- return (apc_cache_entry_t*)value;
- }
- slot = &(*slot)->next;
- }
- CACHE_RDUNLOCK(cache);
- return NULL;
-}
-/* }}} */
-
-/* {{{ apc_cache_user_update */
-int _apc_cache_user_update(apc_cache_t* cache, char *strkey, int keylen, apc_cache_updater_t updater, void* data TSRMLS_DC)
-{
- slot_t** slot;
- int retval;
- unsigned long h;
-
- if(apc_cache_busy(cache))
- {
- /* cache cleanup in progress */
- return 0;
- }
-
- CACHE_LOCK(cache);
-
- h = string_nhash_8(strkey, keylen);
- slot = &cache->slots[h % cache->num_slots];
-
- while (*slot) {
- if ((h == (*slot)->key.h) &&
- !memcmp((*slot)->key.data.user.identifier, strkey, keylen)) {
- switch(Z_TYPE_P((*slot)->value->data.user.val) & ~IS_CONSTANT_INDEX) {
- case IS_ARRAY:
- case IS_CONSTANT_ARRAY:
- case IS_OBJECT:
- {
- if(APCG(serializer)) {
- retval = 0;
- break;
- } else {
- /* fall through */
- }
- }
- /* fall through */
- default:
- {
- retval = updater(cache, (*slot)->value, data);
- (*slot)->key.mtime = apc_time();
- }
- break;
- }
- CACHE_UNLOCK(cache);
- return retval;
- }
- slot = &(*slot)->next;
- }
- CACHE_UNLOCK(cache);
- return 0;
-}
-/* }}} */
-
-/* {{{ apc_cache_user_delete */
-int apc_cache_user_delete(apc_cache_t* cache, char *strkey, int keylen TSRMLS_DC)
-{
- slot_t** slot;
- unsigned long h;
-
- CACHE_LOCK(cache);
-
- h = string_nhash_8(strkey, keylen);
-
- slot = &cache->slots[h % cache->num_slots];
-
- while (*slot) {
- if ((h == (*slot)->key.h) &&
- !memcmp((*slot)->key.data.user.identifier, strkey, keylen)) {
- remove_slot(cache, slot TSRMLS_CC);
- CACHE_UNLOCK(cache);
- return 1;
- }
- slot = &(*slot)->next;
- }
-
- CACHE_UNLOCK(cache);
- return 0;
-}
-/* }}} */
-
-/* {{{ apc_cache_delete */
-int apc_cache_delete(apc_cache_t* cache, char *filename, int filename_len TSRMLS_DC)
-{
- slot_t** slot;
- time_t t;
- apc_cache_key_t key;
-
- t = apc_time();
-
- /* try to create a cache key; if we fail, give up on caching */
- if (!apc_cache_make_file_key(&key, filename, PG(include_path), t TSRMLS_CC)) {
- apc_warning("Could not stat file %s, unable to delete from cache." TSRMLS_CC, filename);
- return -1;
- }
-
- CACHE_LOCK(cache);
-
- if(key.type == APC_CACHE_KEY_FILE) slot = &cache->slots[hash(key) % cache->num_slots];
- else slot = &cache->slots[key.h % cache->num_slots];
-
- while(*slot) {
- if(key.type == (*slot)->key.type) {
- if(key.type == APC_CACHE_KEY_FILE) {
- if(key_equals((*slot)->key.data.file, key.data.file)) {
- remove_slot(cache, slot TSRMLS_CC);
- CACHE_UNLOCK(cache);
- return 1;
- }
- } else { /* APC_CACHE_KEY_FPFILE */
- if(((*slot)->key.h == key.h) &&
- (!memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1))) {
- remove_slot(cache, slot TSRMLS_CC);
- CACHE_UNLOCK(cache);
- return 1;
- }
- }
- }
- slot = &(*slot)->next;
- }
-
- memset(&cache->header->lastkey, 0, sizeof(apc_keyid_t));
-
- CACHE_UNLOCK(cache);
- return 0;
-
-}
-/* }}} */
-
-/* {{{ apc_cache_release */
-void apc_cache_release(apc_cache_t* cache, apc_cache_entry_t* entry TSRMLS_DC)
-{
- CACHE_SAFE_DEC(cache, entry->ref_count);
-}
-/* }}} */
-
-/* {{{ apc_cache_make_file_key */
-int apc_cache_make_file_key(apc_cache_key_t* key,
- const char* filename,
- const char* include_path,
- time_t t
- TSRMLS_DC)
-{
- struct stat *tmp_buf=NULL;
- struct apc_fileinfo_t *fileinfo = NULL;
- int len;
-
- assert(key != NULL);
-
- if (!filename || !SG(request_info).path_translated) {
- apc_debug("No filename and no path_translated - bailing\n" TSRMLS_CC);
- goto cleanup;
- }
-
- len = strlen(filename);
- if(APCG(fpstat)==0) {
- if(IS_ABSOLUTE_PATH(filename,len)) {
- key->data.fpfile.fullpath = filename;
- key->data.fpfile.fullpath_len = len;
- key->h = string_nhash_8(key->data.fpfile.fullpath, key->data.fpfile.fullpath_len);
- key->mtime = t;
- key->type = APC_CACHE_KEY_FPFILE;
- goto success;
- } else if(APCG(canonicalize)) {
-
- fileinfo = apc_php_malloc(sizeof(apc_fileinfo_t) TSRMLS_CC);
-
- if (apc_search_paths(filename, include_path, fileinfo TSRMLS_CC) != 0) {
- apc_warning("apc failed to locate %s - bailing" TSRMLS_CC, filename);
- goto cleanup;
- }
-
- if(!VCWD_REALPATH(fileinfo->fullpath, APCG(canon_path))) {
- apc_warning("realpath failed to canonicalize %s - bailing" TSRMLS_CC, filename);
- goto cleanup;
- }
-
- key->data.fpfile.fullpath = APCG(canon_path);
- key->data.fpfile.fullpath_len = strlen(APCG(canon_path));
- key->h = string_nhash_8(key->data.fpfile.fullpath, key->data.fpfile.fullpath_len);
- key->mtime = t;
- key->type = APC_CACHE_KEY_FPFILE;
- goto success;
- }
- /* fall through to stat mode */
- }
-
- fileinfo = apc_php_malloc(sizeof(apc_fileinfo_t) TSRMLS_CC);
-
- assert(fileinfo != NULL);
-
- if(!strcmp(SG(request_info).path_translated, filename)) {
- tmp_buf = sapi_get_stat(TSRMLS_C); /* Apache has already done this stat() for us */
- }
-
- if(tmp_buf) {
- fileinfo->st_buf.sb = *tmp_buf;
- } else {
- if (apc_search_paths(filename, include_path, fileinfo TSRMLS_CC) != 0) {
- apc_debug("Stat failed %s - bailing (%s) (%d)\n" TSRMLS_CC, filename,SG(request_info).path_translated);
- goto cleanup;
- }
- }
-
- if(APCG(max_file_size) < fileinfo->st_buf.sb.st_size) {
- apc_debug("File is too big %s (%d - %ld) - bailing\n" TSRMLS_CC, filename,t,fileinfo->st_buf.sb.st_size);
- goto cleanup;
- }
-
- /*
- * This is a bit of a hack.
- *
- * Here I am checking to see if the file is at least 2 seconds old.
- * The idea is that if the file is currently being written to then its
- * mtime is going to match or at most be 1 second off of the current
- * request time and we want to avoid caching files that have not been
- * completely written. Of course, people should be using atomic
- * mechanisms to push files onto live web servers, but adding this
- * tiny safety is easier than educating the world. This is now
- * configurable, but the default is still 2 seconds.
- */
- if(APCG(file_update_protection) && (t - fileinfo->st_buf.sb.st_mtime < APCG(file_update_protection)) && !APCG(force_file_update)) {
- apc_debug("File is too new %s (%d - %d) - bailing\n" TSRMLS_CC,filename,t,fileinfo->st_buf.sb.st_mtime);
- goto cleanup;
- }
-
- key->data.file.device = fileinfo->st_buf.sb.st_dev;
- key->data.file.inode = fileinfo->st_buf.sb.st_ino;
- key->h = (unsigned long) key->data.file.device + (unsigned long) key->data.file.inode;
-
- /*
- * If working with content management systems that like to munge the mtime,
- * it might be appropriate to key off of the ctime to be immune to systems
- * that try to backdate a template. If the mtime is set to something older
- * than the previous mtime of a template we will obviously never see this
- * "older" template. At some point the Smarty templating system did this.
- * I generally disagree with using the ctime here because you lose the
- * ability to warm up new content by saving it to a temporary file, hitting
- * it once to cache it and then renaming it into its permanent location so
- * set the apc.stat_ctime=true to enable this check.
- */
- if(APCG(stat_ctime)) {
- key->mtime = (fileinfo->st_buf.sb.st_ctime > fileinfo->st_buf.sb.st_mtime) ? fileinfo->st_buf.sb.st_ctime : fileinfo->st_buf.sb.st_mtime;
- } else {
- key->mtime = fileinfo->st_buf.sb.st_mtime;
- }
- key->type = APC_CACHE_KEY_FILE;
-
-success:
-
- if(fileinfo != NULL) {
- apc_php_free(fileinfo TSRMLS_CC);
- }
-
- return 1;
-
-cleanup:
-
- if(fileinfo != NULL) {
- apc_php_free(fileinfo TSRMLS_CC);
- }
-
- return 0;
-}
-/* }}} */
-
-/* {{{ apc_cache_make_user_key */
-int apc_cache_make_user_key(apc_cache_key_t* key, char* identifier, int identifier_len, const time_t t)
-{
- assert(key != NULL);
-
- if (!identifier)
- return 0;
-
- key->data.user.identifier = identifier;
- key->data.user.identifier_len = identifier_len;
- key->h = string_nhash_8(key->data.user.identifier, key->data.user.identifier_len);
- key->mtime = t;
- key->type = APC_CACHE_KEY_USER;
- return 1;
-}
-/* }}} */
-
-/* {{{ apc_cache_make_file_entry */
-apc_cache_entry_t* apc_cache_make_file_entry(const char* filename,
- zend_op_array* op_array,
- apc_function_t* functions,
- apc_class_t* classes,
- apc_context_t* ctxt
- TSRMLS_DC)
-{
- apc_cache_entry_t* entry;
- apc_pool* pool = ctxt->pool;
-
- entry = (apc_cache_entry_t*) apc_pool_alloc(pool, sizeof(apc_cache_entry_t));
- if (!entry) return NULL;
-
- entry->data.file.filename = apc_pstrdup(filename, pool TSRMLS_CC);
- if(!entry->data.file.filename) {
- apc_debug("apc_cache_make_file_entry: entry->data.file.filename is NULL - bailing\n" TSRMLS_CC);
- return NULL;
- }
- apc_debug("apc_cache_make_file_entry: entry->data.file.filename is [%s]\n" TSRMLS_CC,entry->data.file.filename);
- entry->data.file.op_array = op_array;
- entry->data.file.functions = functions;
- entry->data.file.classes = classes;
-
- entry->data.file.halt_offset = apc_file_halt_offset(filename TSRMLS_CC);
-
- entry->type = APC_CACHE_ENTRY_FILE;
- entry->ref_count = 0;
- entry->mem_size = 0;
- entry->pool = pool;
- return entry;
-}
-/* }}} */
-
-/* {{{ apc_cache_store_zval */
-zval* apc_cache_store_zval(zval* dst, const zval* src, apc_context_t* ctxt TSRMLS_DC)
-{
- if (Z_TYPE_P(src) == IS_ARRAY) {
- /* Maintain a list of zvals we've copied to properly handle recursive structures */
- zend_hash_init(&APCG(copied_zvals), 0, NULL, NULL, 0);
- dst = apc_copy_zval(dst, src, ctxt TSRMLS_CC);
- zend_hash_destroy(&APCG(copied_zvals));
- APCG(copied_zvals).nTableSize=0;
- } else {
- dst = apc_copy_zval(dst, src, ctxt TSRMLS_CC);
- }
-
-
- return dst;
-}
-/* }}} */
-
-/* {{{ apc_cache_fetch_zval */
-zval* apc_cache_fetch_zval(zval* dst, const zval* src, apc_context_t* ctxt TSRMLS_DC)
-{
- if (Z_TYPE_P(src) == IS_ARRAY) {
- /* Maintain a list of zvals we've copied to properly handle recursive structures */
- zend_hash_init(&APCG(copied_zvals), 0, NULL, NULL, 0);
- dst = apc_copy_zval(dst, src, ctxt TSRMLS_CC);
- zend_hash_destroy(&APCG(copied_zvals));
- APCG(copied_zvals).nTableSize=0;
- } else {
- dst = apc_copy_zval(dst, src, ctxt TSRMLS_CC);
- }
-
-
- return dst;
-}
-/* }}} */
-
-/* {{{ apc_cache_make_user_entry */
-apc_cache_entry_t* apc_cache_make_user_entry(const char* info, int info_len, const zval* val, apc_context_t* ctxt, const unsigned int ttl TSRMLS_DC)
-{
- apc_cache_entry_t* entry;
- apc_pool* pool = ctxt->pool;
-
- entry = (apc_cache_entry_t*) apc_pool_alloc(pool, sizeof(apc_cache_entry_t));
- if (!entry) return NULL;
-
- entry->data.user.info = apc_pmemcpy(info, info_len, pool TSRMLS_CC);
- entry->data.user.info_len = info_len;
- if(!entry->data.user.info) {
- return NULL;
- }
- entry->data.user.val = apc_cache_store_zval(NULL, val, ctxt TSRMLS_CC);
- if(!entry->data.user.val) {
- return NULL;
- }
- INIT_PZVAL(entry->data.user.val);
- entry->data.user.ttl = ttl;
- entry->type = APC_CACHE_ENTRY_USER;
- entry->ref_count = 0;
- entry->mem_size = 0;
- entry->pool = pool;
- return entry;
-}
-/* }}} */
-
-/* {{{ */
-static zval* apc_cache_link_info(apc_cache_t *cache, slot_t* p TSRMLS_DC)
-{
- zval *link = NULL;
- char md5str[33];
-
- ALLOC_INIT_ZVAL(link);
-
- if(!link) {
- return NULL;
- }
-
- array_init(link);
-
- if(p->value->type == APC_CACHE_ENTRY_FILE) {
- add_assoc_string(link, "type", "file", 1);
- if(p->key.type == APC_CACHE_KEY_FILE) {
-
- #ifdef PHP_WIN32
- {
- char buf[20];
- sprintf(buf, "%I64d", p->key.data.file.device);
- add_assoc_string(link, "device", buf, 1);
-
- sprintf(buf, "%I64d", p->key.data.file.inode);
- add_assoc_string(link, "inode", buf, 1);
- }
- #else
- add_assoc_long(link, "device", p->key.data.file.device);
- add_assoc_long(link, "inode", p->key.data.file.inode);
- #endif
-
- add_assoc_string(link, "filename", p->value->data.file.filename, 1);
- } else { /* This is a no-stat fullpath file entry */
- add_assoc_long(link, "device", 0);
- add_assoc_long(link, "inode", 0);
- add_assoc_string(link, "filename", (char*)p->key.data.fpfile.fullpath, 1);
- }
- if (APCG(file_md5)) {
- make_digest(md5str, p->key.md5);
- add_assoc_string(link, "md5", md5str, 1);
- }
- } else if(p->value->type == APC_CACHE_ENTRY_USER) {
- add_assoc_stringl(link, "info", p->value->data.user.info, p->value->data.user.info_len-1, 1);
- add_assoc_long(link, "ttl", (long)p->value->data.user.ttl);
- add_assoc_string(link, "type", "user", 1);
- }
-
- add_assoc_double(link, "num_hits", (double)p->num_hits);
- add_assoc_long(link, "mtime", p->key.mtime);
- add_assoc_long(link, "creation_time", p->creation_time);
- add_assoc_long(link, "deletion_time", p->deletion_time);
- add_assoc_long(link, "access_time", p->access_time);
- add_assoc_long(link, "ref_count", p->value->ref_count);
- add_assoc_long(link, "mem_size", p->value->mem_size);
-
- return link;
-}
-/* }}} */
-
-/* {{{ apc_cache_info */
-zval* apc_cache_info(apc_cache_t* cache, zend_bool limited TSRMLS_DC)
-{
- zval *info = NULL;
- zval *list = NULL;
- zval *deleted_list = NULL;
- zval *slots = NULL;
- slot_t* p;
- int i, j;
-
- if(!cache) return NULL;
-
- CACHE_RDLOCK(cache);
-
- ALLOC_INIT_ZVAL(info);
-
- if(!info) {
- CACHE_RDUNLOCK(cache);
- return NULL;
- }
-
- array_init(info);
- add_assoc_long(info, "num_slots", cache->num_slots);
- add_assoc_long(info, "ttl", cache->ttl);
-
- add_assoc_double(info, "num_hits", (double)cache->header->num_hits);
- add_assoc_double(info, "num_misses", (double)cache->header->num_misses);
- add_assoc_double(info, "num_inserts", (double)cache->header->num_inserts);
- add_assoc_double(info, "expunges", (double)cache->header->expunges);
-
- add_assoc_long(info, "start_time", cache->header->start_time);
- add_assoc_double(info, "mem_size", (double)cache->header->mem_size);
- add_assoc_long(info, "num_entries", cache->header->num_entries);
-#ifdef MULTIPART_EVENT_FORMDATA
- add_assoc_long(info, "file_upload_progress", 1);
-#else
- add_assoc_long(info, "file_upload_progress", 0);
-#endif
-#if APC_MMAP
- add_assoc_stringl(info, "memory_type", "mmap", sizeof("mmap")-1, 1);
-#else
- add_assoc_stringl(info, "memory_type", "IPC shared", sizeof("IPC shared")-1, 1);
-#endif
- add_assoc_stringl(info, "locking_type", APC_LOCK_TYPE, sizeof(APC_LOCK_TYPE)-1, 1);
-
- if(!limited) {
- /* For each hashtable slot */
- ALLOC_INIT_ZVAL(list);
- array_init(list);
-
- ALLOC_INIT_ZVAL(slots);
- array_init(slots);
- for (i = 0; i < cache->num_slots; i++) {
- p = cache->slots[i];
- j = 0;
- for (; p != NULL; p = p->next) {
- zval *link = apc_cache_link_info(cache, p TSRMLS_CC);
- add_next_index_zval(list, link);
- j++;
- }
- add_next_index_long(slots, j);
- }
-
- /* For each slot pending deletion */
- ALLOC_INIT_ZVAL(deleted_list);
- array_init(deleted_list);
-
- for (p = cache->header->deleted_list; p != NULL; p = p->next) {
- zval *link = apc_cache_link_info(cache, p TSRMLS_CC);
- add_next_index_zval(deleted_list, link);
- }
-
- add_assoc_zval(info, "cache_list", list);
- add_assoc_zval(info, "deleted_list", deleted_list);
- add_assoc_zval(info, "slot_distribution", slots);
- }
-
- CACHE_RDUNLOCK(cache);
- return info;
-}
-/* }}} */
-
-/* {{{ apc_cache_unlock */
-void apc_cache_unlock(apc_cache_t* cache TSRMLS_DC)
-{
- CACHE_UNLOCK(cache);
-}
-/* }}} */
-
-/* {{{ apc_cache_busy */
-zend_bool apc_cache_busy(apc_cache_t* cache)
-{
- return cache->header->busy;
-}
-/* }}} */
-
-/* {{{ apc_cache_is_last_key */
-zend_bool apc_cache_is_last_key(apc_cache_t* cache, apc_cache_key_t* key, time_t t TSRMLS_DC)
-{
- apc_keyid_t *lastkey = &cache->header->lastkey;
- unsigned int keylen = key->data.user.identifier_len;
-#ifdef ZTS
- THREAD_T tid = tsrm_thread_id();
- #define FROM_DIFFERENT_THREAD(k) (memcmp(&((k)->tid), &tid, sizeof(THREAD_T))!=0)
-#else
- pid_t pid = getpid();
- #define FROM_DIFFERENT_THREAD(k) (pid != (k)->pid)
-#endif
-
-
- /* unlocked reads, but we're not shooting for 100% success with this */
- if(lastkey->h == key->h && keylen == lastkey->keylen) {
- if(lastkey->mtime == t && FROM_DIFFERENT_THREAD(lastkey)) {
- /* potential cache slam */
- if(APCG(slam_defense)) {
- apc_debug("Potential cache slam averted for key '%s'" TSRMLS_CC, key->data.user.identifier);
- return 1;
- }
- }
- }
-
- return 0;
-}
-/* }}} */
-
-#if NONBLOCKING_LOCK_AVAILABLE
-/* {{{ apc_cache_write_lock */
-zend_bool apc_cache_write_lock(apc_cache_t* cache TSRMLS_DC)
-{
- return apc_lck_nb_lock(cache->header->wrlock);
-}
-/* }}} */
-
-/* {{{ apc_cache_write_unlock */
-void apc_cache_write_unlock(apc_cache_t* cache TSRMLS_DC)
-{
- apc_lck_unlock(cache->header->wrlock);
-}
-/* }}} */
-#endif
-
-/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker
- * vim<600: expandtab sw=4 ts=4 sts=4
- */
|
[-]
[+]
|
Deleted |
APC-3.1.8.tar.bz2/APC-3.1.8/apc_main.c
^
|
@@ -1,1028 +0,0 @@
-/*
- +----------------------------------------------------------------------+
- | APC |
- +----------------------------------------------------------------------+
- | Copyright (c) 2006-2011 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Authors: Daniel Cowgill <dcowgill@communityconnect.com> |
- | Rasmus Lerdorf <rasmus@php.net> |
- | Arun C. Murthy <arunc@yahoo-inc.com> |
- | Gopal Vijayaraghavan <gopalv@yahoo-inc.com> |
- +----------------------------------------------------------------------+
-
- This software was contributed to PHP by Community Connect Inc. in 2002
- and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
- Future revisions and derivatives of this source code must acknowledge
- Community Connect Inc. as the original contributor of this module by
- leaving this note intact in the source code.
-
- All other licensing and usage conditions are those of the PHP Group.
-
- */
-
-/* $Id: apc_main.c 309002 2011-03-07 19:50:18Z pajoye $ */
-
-#include "apc_php.h"
-#include "apc_main.h"
-#include "apc.h"
-#include "apc_lock.h"
-#include "apc_cache.h"
-#include "apc_compile.h"
-#include "apc_globals.h"
-#include "apc_sma.h"
-#include "apc_stack.h"
-#include "apc_zend.h"
-#include "apc_pool.h"
-#include "apc_string.h"
-#include "SAPI.h"
-#include "php_scandir.h"
-#include "ext/standard/php_var.h"
-#include "ext/standard/md5.h"
-
-#define APC_MAX_SERIALIZERS 16
-
-/* {{{ module variables */
-
-/* pointer to the original Zend engine compile_file function */
-typedef zend_op_array* (zend_compile_t)(zend_file_handle*, int TSRMLS_DC);
-static zend_compile_t *old_compile_file;
-static apc_serializer_t apc_serializers[APC_MAX_SERIALIZERS] = {{0,}};
-
-/* }}} */
-
-/* {{{ get/set old_compile_file (to interact with other extensions that need the compile hook) */
-static zend_compile_t* set_compile_hook(zend_compile_t *ptr)
-{
- zend_compile_t *retval = old_compile_file;
-
- if (ptr != NULL) old_compile_file = ptr;
- return retval;
-}
-/* }}} */
-
-/* {{{ install_function */
-static int install_function(apc_function_t fn, apc_context_t* ctxt, int lazy TSRMLS_DC)
-{
- int status;
-
-#if APC_HAVE_LOOKUP_HOOKS
- if(lazy && fn.name[0] != '\0' && strncmp(fn.name, "__autoload", fn.name_len) != 0) {
- status = zend_hash_add(APCG(lazy_function_table),
- fn.name,
- fn.name_len+1,
- &fn,
- sizeof(apc_function_t),
- NULL);
-#else
- if(0) {
-#endif
- } else {
- zend_function *func = apc_copy_function_for_execution(fn.function, ctxt TSRMLS_CC);
- status = zend_hash_add(EG(function_table),
- fn.name,
- fn.name_len+1,
- func,
- sizeof(fn.function[0]),
- NULL);
- efree(func);
- }
-
- if (status == FAILURE) {
- /* apc_error("Cannot redeclare %s()" TSRMLS_CC, fn.name); */
- }
-
- return status;
-}
-/* }}} */
-
-/* {{{ apc_lookup_function_hook */
-int apc_lookup_function_hook(char *name, int len, ulong hash, zend_function **fe) {
- apc_function_t *fn;
- int status = FAILURE;
- apc_context_t ctxt = {0,};
- TSRMLS_FETCH();
-
- ctxt.pool = apc_pool_create(APC_UNPOOL, apc_php_malloc, apc_php_free, apc_sma_protect, apc_sma_unprotect TSRMLS_CC);
- ctxt.copy = APC_COPY_OUT_OPCODE;
-
- if(zend_hash_quick_find(APCG(lazy_function_table), name, len, hash, (void**)&fn) == SUCCESS) {
- *fe = apc_copy_function_for_execution(fn->function, &ctxt TSRMLS_CC);
- status = zend_hash_add(EG(function_table),
- fn->name,
- fn->name_len+1,
- *fe,
- sizeof(zend_function),
- NULL);
- }
-
- return status;
-}
-/* }}} */
-
-/* {{{ install_class */
-static int install_class(apc_class_t cl, apc_context_t* ctxt, int lazy TSRMLS_DC)
-{
- zend_class_entry* class_entry = cl.class_entry;
- zend_class_entry* parent = NULL;
- int status;
- zend_class_entry** allocated_ce = NULL;
-
- /* Special case for mangled names. Mangled names are unique to a file.
- * There is no way two classes with the same mangled name will occur,
- * unless a file is included twice. And if in case, a file is included
- * twice, all mangled name conflicts can be ignored and the class redeclaration
- * error may be deferred till runtime of the corresponding DECLARE_CLASS
- * calls.
- */
-
- if(cl.name_len != 0 && cl.name[0] == '\0') {
- if(zend_hash_exists(CG(class_table), cl.name, cl.name_len+1)) {
- return SUCCESS;
- }
- }
-
- if(lazy && cl.name_len != 0 && cl.name[0] != '\0') {
- status = zend_hash_add(APCG(lazy_class_table),
- cl.name,
- cl.name_len+1,
- &cl,
- sizeof(apc_class_t),
- NULL);
- if(status == FAILURE) {
- zend_error(E_ERROR, "Cannot redeclare class %s", cl.name);
- }
- return status;
- }
-
- /*
- * XXX: We need to free this somewhere...
- */
- allocated_ce = apc_php_malloc(sizeof(zend_class_entry*) TSRMLS_CC);
-
- if(!allocated_ce) {
- return FAILURE;
- }
-
- *allocated_ce =
- class_entry =
- apc_copy_class_entry_for_execution(cl.class_entry, ctxt TSRMLS_CC);
-
-
- /* restore parent class pointer for compile-time inheritance */
- if (cl.parent_name != NULL) {
- zend_class_entry** parent_ptr = NULL;
- /*
- * __autoload brings in the old issues with mixed inheritance.
- * When a statically inherited class triggers autoload, it runs
- * afoul of a potential require_once "parent.php" in the previous
- * line, which when executed provides the parent class, but right
- * now goes and hits __autoload which could fail.
- *
- * missing parent == re-compile.
- *
- * whether __autoload is enabled or not, because __autoload errors
- * cause php to die.
- *
- * Aside: Do NOT pass *strlen(cl.parent_name)+1* because
- * zend_lookup_class_ex does it internally anyway!
- */
- status = zend_lookup_class_ex(cl.parent_name,
- strlen(cl.parent_name),
-#ifdef ZEND_ENGINE_2_4
- NULL,
-#endif
- 0,
- &parent_ptr TSRMLS_CC);
- if (status == FAILURE) {
- if(APCG(report_autofilter)) {
- apc_warning("Dynamic inheritance detected for class %s" TSRMLS_CC, cl.name);
- }
- class_entry->parent = NULL;
- return status;
- }
- else {
- parent = *parent_ptr;
- class_entry->parent = parent;
- zend_do_inheritance(class_entry, parent TSRMLS_CC);
- }
-
-
- }
-
- status = zend_hash_add(EG(class_table),
- cl.name,
- cl.name_len+1,
- allocated_ce,
- sizeof(zend_class_entry*),
- NULL);
-
- if (status == FAILURE) {
- apc_error("Cannot redeclare class %s" TSRMLS_CC, cl.name);
- }
- return status;
-}
-/* }}} */
-
-/* {{{ apc_lookup_class_hook */
-int apc_lookup_class_hook(char *name, int len, ulong hash, zend_class_entry ***ce) {
-
- apc_class_t *cl;
- apc_context_t ctxt = {0,};
- TSRMLS_FETCH();
-
- if(zend_is_compiling(TSRMLS_C)) { return FAILURE; }
-
- if(zend_hash_quick_find(APCG(lazy_class_table), name, len, hash, (void**)&cl) == FAILURE) {
- return FAILURE;
- }
-
- ctxt.pool = apc_pool_create(APC_UNPOOL, apc_php_malloc, apc_php_free, apc_sma_protect, apc_sma_unprotect TSRMLS_CC);
- ctxt.copy = APC_COPY_OUT_OPCODE;
-
- if(install_class(*cl, &ctxt, 0 TSRMLS_CC) == FAILURE) {
- apc_warning("apc_lookup_class_hook: could not install %s" TSRMLS_CC, name);
- return FAILURE;
- }
-
- if(zend_hash_quick_find(EG(class_table), name, len, hash, (void**)ce) == FAILURE) {
- apc_warning("apc_lookup_class_hook: known error trying to fetch class %s" TSRMLS_CC, name);
- return FAILURE;
- }
-
- return SUCCESS;
-
-}
-/* }}} */
-
-/* {{{ uninstall_class */
-static int uninstall_class(apc_class_t cl TSRMLS_DC)
-{
- int status;
-
- status = zend_hash_del(EG(class_table),
- cl.name,
- cl.name_len+1);
- if (status == FAILURE) {
- apc_error("Cannot delete class %s" TSRMLS_CC, cl.name);
- }
- return status;
-}
-/* }}} */
-
-/* {{{ copy_function_name (taken from zend_builtin_functions.c to ensure future compatibility with APC) */
-static int copy_function_name(apc_function_t *pf TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
-{
- zval *internal_ar = va_arg(args, zval *),
- *user_ar = va_arg(args, zval *);
- zend_function *func = pf->function;
-
- if (hash_key->nKeyLength == 0 || hash_key->arKey[0] == 0) {
- return 0;
- }
-
- if (func->type == ZEND_INTERNAL_FUNCTION) {
- add_next_index_stringl(internal_ar, hash_key->arKey, hash_key->nKeyLength-1, 1);
- } else if (func->type == ZEND_USER_FUNCTION) {
- add_next_index_stringl(user_ar, hash_key->arKey, hash_key->nKeyLength-1, 1);
- }
-
- return 0;
-}
-
-/* {{{ copy_class_or_interface_name (taken from zend_builtin_functions.c to ensure future compatibility with APC) */
-static int copy_class_or_interface_name(apc_class_t *cl TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
-{
- zval *array = va_arg(args, zval *);
- zend_uint mask = va_arg(args, zend_uint);
- zend_uint comply = va_arg(args, zend_uint);
- zend_uint comply_mask = (comply)? mask:0;
- zend_class_entry *ce = cl->class_entry;
-
- if ((hash_key->nKeyLength==0 || hash_key->arKey[0]!=0)
- && (comply_mask == (ce->ce_flags & mask))) {
- add_next_index_stringl(array, ce->name, ce->name_length, 1);
- }
- return ZEND_HASH_APPLY_KEEP;
-}
-/* }}} */
-
-/* }}} */
-
-/* {{{ apc_defined_function_hook */
-int apc_defined_function_hook(zval *internal, zval *user) {
- TSRMLS_FETCH();
- zend_hash_apply_with_arguments(APCG(lazy_function_table)
-#ifdef ZEND_ENGINE_2_3
- TSRMLS_CC
-#endif
- ,(apply_func_args_t) copy_function_name, 2, internal, user);
- return 1;
-}
-/* }}} */
-
-/* {{{ apc_declared_class_hook */
-int apc_declared_class_hook(zval *classes, zend_uint mask, zend_uint comply) {
- TSRMLS_FETCH();
- zend_hash_apply_with_arguments(APCG(lazy_class_table)
-#ifdef ZEND_ENGINE_2_3
- TSRMLS_CC
-#endif
- , (apply_func_args_t) copy_class_or_interface_name, 3, classes, mask, comply);
- return 1;
-}
-/* }}} */
-
-/* {{{ cached_compile */
-static zend_op_array* cached_compile(zend_file_handle* h,
- int type,
- apc_context_t* ctxt TSRMLS_DC)
-{
- apc_cache_entry_t* cache_entry;
- int i, ii;
-
- cache_entry = (apc_cache_entry_t*) apc_stack_top(APCG(cache_stack));
- assert(cache_entry != NULL);
-
- if (cache_entry->data.file.classes) {
- int lazy_classes = APCG(lazy_classes);
- for (i = 0; cache_entry->data.file.classes[i].class_entry != NULL; i++) {
- if(install_class(cache_entry->data.file.classes[i], ctxt, lazy_classes TSRMLS_CC) == FAILURE) {
- goto default_compile;
- }
- }
- }
-
- if (cache_entry->data.file.functions) {
- int lazy_functions = APCG(lazy_functions);
- for (i = 0; cache_entry->data.file.functions[i].function != NULL; i++) {
- install_function(cache_entry->data.file.functions[i], ctxt, lazy_functions TSRMLS_CC);
- }
- }
-
- apc_do_halt_compiler_register(cache_entry->data.file.filename, cache_entry->data.file.halt_offset TSRMLS_CC);
-
-
- return apc_copy_op_array_for_execution(NULL, cache_entry->data.file.op_array, ctxt TSRMLS_CC);
-
-default_compile:
-
- if(cache_entry->data.file.classes) {
- for(ii = 0; ii < i ; ii++) {
- uninstall_class(cache_entry->data.file.classes[ii] TSRMLS_CC);
- }
- }
-
- apc_stack_pop(APCG(cache_stack)); /* pop out cache_entry */
-
- apc_cache_release(apc_cache, cache_entry TSRMLS_CC);
-
- /* cannot free up cache data yet, it maybe in use */
-
- return NULL;
-}
-/* }}} */
-
-/* {{{ apc_compile_cache_entry */
-zend_bool apc_compile_cache_entry(apc_cache_key_t key, zend_file_handle* h, int type, time_t t, zend_op_array** op_array, apc_cache_entry_t** cache_entry TSRMLS_DC) {
- int num_functions, num_classes;
- apc_function_t* alloc_functions;
- zend_op_array* alloc_op_array;
- apc_class_t* alloc_classes;
- char *path;
- apc_context_t ctxt;
-
- /* remember how many functions and classes existed before compilation */
- num_functions = zend_hash_num_elements(CG(function_table));
- num_classes = zend_hash_num_elements(CG(class_table));
-
- /* compile the file using the default compile function, *
- * we set *op_array here so we return opcodes during *
- * a failure. We should not return prior to this line. */
- *op_array = old_compile_file(h, type TSRMLS_CC);
- if (*op_array == NULL) {
- return FAILURE;
- }
-
- ctxt.pool = apc_pool_create(APC_MEDIUM_POOL, apc_sma_malloc, apc_sma_free,
- apc_sma_protect, apc_sma_unprotect TSRMLS_CC);
- if (!ctxt.pool) {
- apc_warning("Unable to allocate memory for pool." TSRMLS_CC);
- return FAILURE;
- }
- ctxt.copy = APC_COPY_IN_OPCODE;
-
- if(APCG(file_md5)) {
- int n;
- unsigned char buf[1024];
- PHP_MD5_CTX context;
- php_stream *stream;
- char *filename;
-
- if(h->opened_path) {
- filename = h->opened_path;
- } else {
- filename = h->filename;
- }
- stream = php_stream_open_wrapper(filename, "rb", REPORT_ERRORS | ENFORCE_SAFE_MODE, NULL);
- if(stream) {
- PHP_MD5Init(&context);
- while((n = php_stream_read(stream, (char*)buf, sizeof(buf))) > 0) {
- PHP_MD5Update(&context, buf, n);
- }
- PHP_MD5Final(key.md5, &context);
- php_stream_close(stream);
- if(n<0) {
- apc_warning("Error while reading '%s' for md5 generation." TSRMLS_CC, filename);
- }
- } else {
- apc_warning("Unable to open '%s' for md5 generation." TSRMLS_CC, filename);
- }
- }
-
- if(!(alloc_op_array = apc_copy_op_array(NULL, *op_array, &ctxt TSRMLS_CC))) {
- goto freepool;
- }
-
- if(!(alloc_functions = apc_copy_new_functions(num_functions, &ctxt TSRMLS_CC))) {
- goto freepool;
- }
- if(!(alloc_classes = apc_copy_new_classes(*op_array, num_classes, &ctxt TSRMLS_CC))) {
- goto freepool;
- }
-
- path = h->opened_path;
- if(!path && key.type == APC_CACHE_KEY_FPFILE) path = (char*)key.data.fpfile.fullpath;
- if(!path) path=h->filename;
-
- apc_debug("2. h->opened_path=[%s] h->filename=[%s]\n" TSRMLS_CC, h->opened_path?h->opened_path:"null",h->filename);
-
- if(!(*cache_entry = apc_cache_make_file_entry(path, alloc_op_array, alloc_functions, alloc_classes, &ctxt TSRMLS_CC))) {
- goto freepool;
- }
-
- return SUCCESS;
-
-freepool:
- apc_pool_destroy(ctxt.pool TSRMLS_CC);
- ctxt.pool = NULL;
-
- return FAILURE;
-
-}
-/* }}} */
-
-/* {{{ my_compile_file
- Overrides zend_compile_file */
-static zend_op_array* my_compile_file(zend_file_handle* h,
- int type TSRMLS_DC)
-{
- apc_cache_key_t key;
- apc_cache_entry_t* cache_entry;
- zend_op_array* op_array = NULL;
- time_t t;
- apc_context_t ctxt = {0,};
- int bailout=0;
- const char* filename = NULL;
-
- if (!APCG(enabled) || apc_cache_busy(apc_cache)) {
- return old_compile_file(h, type TSRMLS_CC);
- }
-
- if(h->opened_path) {
- filename = h->opened_path;
- } else {
- filename = h->filename;
- }
-
- /* check our regular expression filters */
- if (APCG(filters) && APCG(compiled_filters) && filename) {
- int ret = apc_regex_match_array(APCG(compiled_filters), filename);
-
- if(ret == APC_NEGATIVE_MATCH || (ret != APC_POSITIVE_MATCH && !APCG(cache_by_default))) {
- return old_compile_file(h, type TSRMLS_CC);
- }
- } else if(!APCG(cache_by_default)) {
- return old_compile_file(h, type TSRMLS_CC);
- }
- APCG(current_cache) = apc_cache;
-
-
- t = apc_time();
-
- apc_debug("1. h->opened_path=[%s] h->filename=[%s]\n" TSRMLS_CC, h->opened_path?h->opened_path:"null",h->filename);
-
- /* try to create a cache key; if we fail, give up on caching */
- if (!apc_cache_make_file_key(&key, h->filename, PG(include_path), t TSRMLS_CC)) {
- return old_compile_file(h, type TSRMLS_CC);
- }
-
- if(!APCG(force_file_update)) {
- /* search for the file in the cache */
- cache_entry = apc_cache_find(apc_cache, key, t TSRMLS_CC);
- ctxt.force_update = 0;
- } else {
- cache_entry = NULL;
- ctxt.force_update = 1;
- }
-
- if (cache_entry != NULL) {
- int dummy = 1;
-
- ctxt.pool = apc_pool_create(APC_UNPOOL, apc_php_malloc, apc_php_free,
- apc_sma_protect, apc_sma_unprotect TSRMLS_CC);
- if (!ctxt.pool) {
- apc_warning("Unable to allocate memory for pool." TSRMLS_CC);
- return old_compile_file(h, type TSRMLS_CC);
- }
- ctxt.copy = APC_COPY_OUT_OPCODE;
-
- zend_hash_add(&EG(included_files), cache_entry->data.file.filename,
- strlen(cache_entry->data.file.filename)+1,
- (void *)&dummy, sizeof(int), NULL);
-
- apc_stack_push(APCG(cache_stack), cache_entry TSRMLS_CC);
- op_array = cached_compile(h, type, &ctxt TSRMLS_CC);
-
- if(op_array) {
-#ifdef APC_FILEHITS
- /* If the file comes from the cache, add it to the global request file list */
- add_next_index_string(APCG(filehits), h->filename, 1);
-#endif
- /* this is an unpool, which has no cleanup - this only free's the pool header */
- apc_pool_destroy(ctxt.pool TSRMLS_CC);
-
- /* We might leak fds without this hack */
- if (h->type != ZEND_HANDLE_FILENAME) {
- zend_llist_add_element(&CG(open_files), h);
- }
-
- op_array->filename = filename;
- return op_array;
- }
- if(APCG(report_autofilter)) {
- apc_warning("Autofiltering %s" TSRMLS_CC,
- (h->opened_path ? h->opened_path : h->filename));
- apc_warning("Recompiling %s" TSRMLS_CC, cache_entry->data.file.filename);
- }
- /* TODO: check what happens with EG(included_files) */
- }
-
- /* Make sure the mtime reflects the files last known mtime, and we respect max_file_size in the case of fpstat==0 */
- if(key.type == APC_CACHE_KEY_FPFILE) {
- apc_fileinfo_t fileinfo;
- struct stat *tmp_buf = NULL;
- if(!strcmp(SG(request_info).path_translated, h->filename)) {
- tmp_buf = sapi_get_stat(TSRMLS_C); /* Apache has already done this stat() for us */
- }
- if(tmp_buf) {
- fileinfo.st_buf.sb = *tmp_buf;
- } else {
- if (apc_search_paths(h->filename, PG(include_path), &fileinfo TSRMLS_CC) != 0) {
- apc_debug("Stat failed %s - bailing (%s) (%d)\n" TSRMLS_CC,h->filename,SG(request_info).path_translated);
- return old_compile_file(h, type TSRMLS_CC);
- }
- }
- if (APCG(max_file_size) < fileinfo.st_buf.sb.st_size) {
- apc_debug("File is too big %s (%ld) - bailing\n" TSRMLS_CC, h->filename, fileinfo.st_buf.sb.st_size);
- return old_compile_file(h, type TSRMLS_CC);
- }
- key.mtime = fileinfo.st_buf.sb.st_mtime;
- }
-
- HANDLE_BLOCK_INTERRUPTIONS();
-
-#if NONBLOCKING_LOCK_AVAILABLE
- if(APCG(write_lock)) {
- if(!apc_cache_write_lock(apc_cache TSRMLS_CC)) {
- HANDLE_UNBLOCK_INTERRUPTIONS();
- return old_compile_file(h, type TSRMLS_CC);
- }
- }
-#endif
-
- zend_try {
- if (apc_compile_cache_entry(key, h, type, t, &op_array, &cache_entry TSRMLS_CC) == SUCCESS) {
- ctxt.pool = cache_entry->pool;
- ctxt.copy = APC_COPY_IN_OPCODE;
- if (apc_cache_insert(apc_cache, key, cache_entry, &ctxt, t TSRMLS_CC) != 1) {
- apc_pool_destroy(ctxt.pool TSRMLS_CC);
- ctxt.pool = NULL;
- }
- }
- } zend_catch {
- bailout=1; /* in the event of a bailout, ensure we don't create a dead-lock */
- } zend_end_try();
-
- APCG(current_cache) = NULL;
-
-#if NONBLOCKING_LOCK_AVAILABLE
- if(APCG(write_lock)) {
- apc_cache_write_unlock(apc_cache TSRMLS_CC);
- }
-#endif
- HANDLE_UNBLOCK_INTERRUPTIONS();
-
- if (bailout) zend_bailout();
-
- return op_array;
-}
-/* }}} */
-
-/* {{{ data preload */
-
-extern int _apc_store(char *strkey, int strkey_len, const zval *val, const unsigned int ttl, const int exclusive TSRMLS_DC);
-
-static zval* data_unserialize(const char *filename TSRMLS_DC)
-{
- zval* retval;
- long len = 0;
- struct stat sb;
- char *contents, *tmp;
- FILE *fp;
- php_unserialize_data_t var_hash;
-
- if(VCWD_STAT(filename, &sb) == -1) {
- return NULL;
- }
-
- fp = fopen(filename, "rb");
-
- len = sizeof(char)*sb.st_size;
-
- tmp = contents = malloc(len);
-
- if(!contents) {
- return NULL;
- }
-
- if(fread(contents, 1, len, fp) < 1) {
- free(contents);
- return NULL;
- }
-
- MAKE_STD_ZVAL(retval);
-
- PHP_VAR_UNSERIALIZE_INIT(var_hash);
-
- /* I wish I could use json */
- if(!php_var_unserialize(&retval, (const unsigned char**)&tmp, (const unsigned char*)(contents+len), &var_hash TSRMLS_CC)) {
- zval_ptr_dtor(&retval);
- return NULL;
- }
-
- PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
-
- free(contents);
- fclose(fp);
-
- return retval;
-}
-
-static int apc_load_data(const char *data_file TSRMLS_DC)
-{
- char *p;
- char key[MAXPATHLEN] = {0,};
- unsigned int key_len;
- zval *data;
-
- p = strrchr(data_file, DEFAULT_SLASH);
-
- if(p && p[1]) {
- strlcpy(key, p+1, sizeof(key));
- p = strrchr(key, '.');
-
- if(p) {
- p[0] = '\0';
- key_len = strlen(key);
-
- data = data_unserialize(data_file TSRMLS_CC);
- if(data) {
- _apc_store(key, key_len, data, 0, 1 TSRMLS_CC);
- }
- return 1;
- }
- }
-
- return 0;
-}
-
-static int apc_walk_dir(const char *path TSRMLS_DC)
-{
- char file[MAXPATHLEN]={0,};
- int ndir, i;
- char *p = NULL;
- struct dirent **namelist = NULL;
-
- if ((ndir = php_scandir(path, &namelist, 0, php_alphasort)) > 0)
- {
- for (i = 0; i < ndir; i++)
- {
- /* check for extension */
- if (!(p = strrchr(namelist[i]->d_name, '.'))
- || (p && strcmp(p, ".data")))
- {
- free(namelist[i]);
- continue;
- }
- snprintf(file, MAXPATHLEN, "%s%c%s",
- path, DEFAULT_SLASH, namelist[i]->d_name);
- if(!apc_load_data(file TSRMLS_CC))
- {
- /* print error */
- }
- free(namelist[i]);
- }
- free(namelist);
- }
-
- return 1;
-}
-
-void apc_data_preload(TSRMLS_D)
-{
- if(!APCG(preload_path)) return;
-
- apc_walk_dir(APCG(preload_path) TSRMLS_CC);
-}
-/* }}} */
-
-/* {{{ apc_serializer hooks */
-static int _apc_register_serializer(const char* name, apc_serialize_t serialize,
- apc_unserialize_t unserialize,
- void *config TSRMLS_DC)
-{
- int i;
- apc_serializer_t *serializer;
-
- for(i = 0; i < APC_MAX_SERIALIZERS; i++) {
- serializer = &apc_serializers[i];
- if(!serializer->name) {
- /* empty entry */
- serializer->name = name; /* assumed to be const */
- serializer->serialize = serialize;
- serializer->unserialize = unserialize;
- serializer->config = config;
- apc_serializers[i+1].name = NULL;
- return 1;
- }
- }
-
- return 0;
-}
-
-apc_serializer_t* apc_find_serializer(const char* name TSRMLS_DC)
-{
- int i;
- apc_serializer_t *serializer;
-
- for(i = 0; i < APC_MAX_SERIALIZERS; i++) {
- serializer = &apc_serializers[i];
- if(serializer->name && (strcmp(serializer->name, name) == 0)) {
- return serializer;
- }
- }
- return NULL;
-}
-
-apc_serializer_t* apc_get_serializers(TSRMLS_D)
-{
- return &(apc_serializers[0]);
-}
-/* }}} */
-
-/* {{{ module init and shutdown */
-
-int apc_module_init(int module_number TSRMLS_DC)
-{
- /* apc initialization */
-#if APC_MMAP
- apc_sma_init(APCG(shm_segments), APCG(shm_size), APCG(mmap_file_mask) TSRMLS_CC);
-#else
- apc_sma_init(APCG(shm_segments), APCG(shm_size), NULL TSRMLS_CC);
-#endif
- apc_cache = apc_cache_create(APCG(num_files_hint), APCG(gc_ttl), APCG(ttl) TSRMLS_CC);
- apc_user_cache = apc_cache_create(APCG(user_entries_hint), APCG(gc_ttl), APCG(user_ttl) TSRMLS_CC);
-
- /* override compilation */
- old_compile_file = zend_compile_file;
- zend_compile_file = my_compile_file;
- REGISTER_LONG_CONSTANT("\000apc_magic", (long)&set_compile_hook, CONST_PERSISTENT | CONST_CS);
- REGISTER_LONG_CONSTANT("\000apc_compile_file", (long)&my_compile_file, CONST_PERSISTENT | CONST_CS);
- REGISTER_LONG_CONSTANT(APC_SERIALIZER_CONSTANT, (long)&_apc_register_serializer, CONST_PERSISTENT | CONST_CS);
-
- /* test out the constant function pointer */
- apc_register_serializer("php", APC_SERIALIZER_NAME(php), APC_UNSERIALIZER_NAME(php), NULL TSRMLS_CC);
-
- assert(apc_serializers[0].name != NULL);
-
- apc_pool_init();
-
- apc_data_preload(TSRMLS_C);
-
-#if APC_HAVE_LOOKUP_HOOKS
- if(APCG(lazy_functions)) {
- zend_set_lookup_function_hook(apc_lookup_function_hook TSRMLS_CC);
- zend_set_defined_function_hook(apc_defined_function_hook TSRMLS_CC);
- }
- if(APCG(lazy_classes)) {
- zend_set_lookup_class_hook(apc_lookup_class_hook TSRMLS_CC);
- zend_set_declared_class_hook(apc_declared_class_hook TSRMLS_CC);
- }
-#else
- if(APCG(lazy_functions) || APCG(lazy_classes)) {
- apc_warning("Lazy function/class loading not available with this version of PHP, please disable APC lazy loading." TSRMLS_CC);
- APCG(lazy_functions) = APCG(lazy_classes) = 0;
- }
-#endif
-
-#ifdef ZEND_ENGINE_2_4
- apc_interned_strings_init(TSRMLS_C);
-#endif
-
- APCG(initialized) = 1;
- return 0;
-}
-
-int apc_module_shutdown(TSRMLS_D)
-{
- if (!APCG(initialized))
- return 0;
-
- /* restore compilation */
- zend_compile_file = old_compile_file;
-
- /*
- * In case we got interrupted by a SIGTERM or something else during execution
- * we may have cache entries left on the stack that we need to check to make
- * sure that any functions or classes these may have added to the global function
- * and class tables are removed before we blow away the memory that hold them.
- *
- * This is merely to remove memory leak warnings - as the process is terminated
- * immediately after shutdown. The following while loop can be removed without
- * affecting anything else.
- */
- while (apc_stack_size(APCG(cache_stack)) > 0) {
- int i;
- apc_cache_entry_t* cache_entry = (apc_cache_entry_t*) apc_stack_pop(APCG(cache_stack));
- if (cache_entry->data.file.functions) {
- for (i = 0; cache_entry->data.file.functions[i].function != NULL; i++) {
- zend_hash_del(EG(function_table),
- cache_entry->data.file.functions[i].name,
- cache_entry->data.file.functions[i].name_len+1);
- }
- }
- if (cache_entry->data.file.classes) {
- for (i = 0; cache_entry->data.file.classes[i].class_entry != NULL; i++) {
- zend_hash_del(EG(class_table),
- cache_entry->data.file.classes[i].name,
- cache_entry->data.file.classes[i].name_len+1);
- }
- }
- apc_cache_release(apc_cache, cache_entry TSRMLS_CC);
- }
-
- apc_cache_destroy(apc_cache TSRMLS_CC);
- apc_cache_destroy(apc_user_cache TSRMLS_CC);
- apc_sma_cleanup(TSRMLS_C);
-
-#ifdef ZEND_ENGINE_2_4
- apc_interned_strings_shutdown(TSRMLS_C);
-#endif
-
- APCG(initialized) = 0;
- return 0;
-}
-
-/* }}} */
-
-/* {{{ process init and shutdown */
-int apc_process_init(int module_number TSRMLS_DC)
-{
- return 0;
-}
-
-int apc_process_shutdown(TSRMLS_D)
-{
- return 0;
-}
-/* }}} */
-
-
-/* {{{ apc_deactivate */
-static void apc_deactivate(TSRMLS_D)
-{
- /* The execution stack was unwound, which prevented us from decrementing
- * the reference counts on active cache entries in `my_execute`.
- */
- while (apc_stack_size(APCG(cache_stack)) > 0) {
- int i;
- zend_class_entry* zce = NULL;
- void ** centry = (void*)(&zce);
- zend_class_entry** pzce = NULL;
-
- apc_cache_entry_t* cache_entry =
- (apc_cache_entry_t*) apc_stack_pop(APCG(cache_stack));
-
- if (cache_entry->data.file.classes) {
- for (i = 0; cache_entry->data.file.classes[i].class_entry != NULL; i++) {
- centry = (void**)&pzce; /* a triple indirection to get zend_class_entry*** */
- if(zend_hash_find(EG(class_table),
- cache_entry->data.file.classes[i].name,
- cache_entry->data.file.classes[i].name_len+1,
- (void**)centry) == FAILURE)
- {
- /* double inclusion of conditional classes ends up failing
- * this lookup the second time around.
- */
- continue;
- }
-
- zce = *pzce;
-
- zend_hash_del(EG(class_table),
- cache_entry->data.file.classes[i].name,
- cache_entry->data.file.classes[i].name_len+1);
-
- apc_free_class_entry_after_execution(zce TSRMLS_CC);
- }
- }
- apc_cache_release(apc_cache, cache_entry TSRMLS_CC);
- }
-}
-/* }}} */
-
-/* {{{ request init and shutdown */
-
-int apc_request_init(TSRMLS_D)
-{
- apc_stack_clear(APCG(cache_stack));
- if (!APCG(compiled_filters) && APCG(filters)) {
- /* compile regex filters here to avoid race condition between MINIT of PCRE and APC.
- * This should be moved to apc_cache_create() if this race condition between modules is resolved */
- APCG(compiled_filters) = apc_regex_compile_array(APCG(filters) TSRMLS_CC);
- }
-
- if (!APCG(serializer) && APCG(serializer_name)) {
- /* Avoid race conditions between MINIT of apc and serializer exts like igbinary */
- APCG(serializer) = apc_find_serializer(APCG(serializer_name) TSRMLS_CC);
- }
-
-#if APC_HAVE_LOOKUP_HOOKS
- if(APCG(lazy_functions)) {
- APCG(lazy_function_table) = emalloc(sizeof(HashTable));
- zend_hash_init(APCG(lazy_function_table), 0, NULL, NULL, 0);
- }
- if(APCG(lazy_classes)) {
- APCG(lazy_class_table) = emalloc(sizeof(HashTable));
- zend_hash_init(APCG(lazy_class_table), 0, NULL, NULL, 0);
- }
-#endif
-
-#ifdef APC_FILEHITS
- ALLOC_INIT_ZVAL(APCG(filehits));
- array_init(APCG(filehits));
-#endif
-
- return 0;
-}
-
-int apc_request_shutdown(TSRMLS_D)
-{
-#if APC_HAVE_LOOKUP_HOOKS
- if(APCG(lazy_class_table)) {
- zend_hash_destroy(APCG(lazy_class_table));
- efree(APCG(lazy_class_table));
- }
- if(APCG(lazy_function_table)) {
- zend_hash_destroy(APCG(lazy_function_table));
- efree(APCG(lazy_function_table));
- }
-#endif
-
- apc_deactivate(TSRMLS_C);
-
-#ifdef APC_FILEHITS
- zval_ptr_dtor(&APCG(filehits));
-#endif
- return 0;
-}
-
-/* }}} */
-
-
-/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker
- * vim<600: expandtab sw=4 ts=4 sts=4
- */
|
[-]
[+]
|
Deleted |
APC-3.1.8.tar.bz2/APC-3.1.8/php_apc.h
^
|
@@ -1,54 +0,0 @@
-/*
- +----------------------------------------------------------------------+
- | APC |
- +----------------------------------------------------------------------+
- | Copyright (c) 2006-2011 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Authors: Daniel Cowgill <dcowgill@communityconnect.com> |
- | George Schlossnagle <george@omniti.com> |
- | Rasmus Lerdorf <rasmus@php.net> |
- +----------------------------------------------------------------------+
-
- This software was contributed to PHP by Community Connect Inc. in 2002
- and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
- Future revisions and derivatives of this source code must acknowledge
- Community Connect Inc. as the original contributor of this module by
- leaving this note intact in the source code.
-
- All other licensing and usage conditions are those of the PHP Group.
-
- */
-
-/* $Id: php_apc.h 309979 2011-04-06 09:50:32Z pajoye $ */
-
-#ifndef PHP_APC_H
-#define PHP_APC_H
-
-#include "apc_php.h"
-#include "apc_globals.h"
-
-#define PHP_APC_VERSION "3.1.8"
-
-extern zend_module_entry apc_module_entry;
-#define apc_module_ptr &apc_module_entry
-
-#define phpext_apc_ptr apc_module_ptr
-
-#endif /* PHP_APC_H */
-
-/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker
- * vim<600: expandtab sw=4 ts=4 sts=4
- */
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/CHANGELOG
^
|
(renamed from APC-3.1.8/CHANGELOG)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/CHANGELOG
^
|
(renamed from APC-3.1.8/CHANGELOG)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/INSTALL
^
|
(renamed from APC-3.1.8/INSTALL)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/INSTALL
^
|
(renamed from APC-3.1.8/INSTALL)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/LICENSE
^
|
(renamed from APC-3.1.8/LICENSE)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/LICENSE
^
|
(renamed from APC-3.1.8/LICENSE)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/NOTICE
^
|
(renamed from APC-3.1.8/NOTICE)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/NOTICE
^
|
(renamed from APC-3.1.8/NOTICE)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/TECHNOTES.txt
^
|
(renamed from APC-3.1.8/TECHNOTES.txt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/TECHNOTES.txt
^
|
(renamed from APC-3.1.8/TECHNOTES.txt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/TODO
^
|
(renamed from APC-3.1.8/TODO)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/TODO
^
|
(renamed from APC-3.1.8/TODO)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc.c
^
|
(renamed from APC-3.1.8/apc.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc.c
^
|
(renamed from APC-3.1.8/apc.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc.h
^
|
(renamed from APC-3.1.8/apc.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc.h
^
|
(renamed from APC-3.1.8/apc.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc.php
^
|
(renamed from APC-3.1.8/apc.php)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc.php
^
|
(renamed from APC-3.1.8/apc.php)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_bin.c
^
|
(renamed from APC-3.1.8/apc_bin.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_bin.c
^
|
(renamed from APC-3.1.8/apc_bin.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_bin.h
^
|
(renamed from APC-3.1.8/apc_bin.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_bin.h
^
|
(renamed from APC-3.1.8/apc_bin.h)
|
[-]
[+]
|
Added |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_cache.c
^
|
@@ -0,0 +1,1381 @@
+/*
+ +----------------------------------------------------------------------+
+ | APC |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2006-2011 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Daniel Cowgill <dcowgill@communityconnect.com> |
+ | Rasmus Lerdorf <rasmus@php.net> |
+ | Arun C. Murthy <arunc@yahoo-inc.com> |
+ | Gopal Vijayaraghavan <gopalv@yahoo-inc.com> |
+ +----------------------------------------------------------------------+
+
+ This software was contributed to PHP by Community Connect Inc. in 2002
+ and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
+ Future revisions and derivatives of this source code must acknowledge
+ Community Connect Inc. as the original contributor of this module by
+ leaving this note intact in the source code.
+
+ All other licensing and usage conditions are those of the PHP Group.
+
+ */
+
+/* $Id: apc_cache.c 309488 2011-03-20 23:59:42Z pajoye $ */
+
+#include "apc_cache.h"
+#include "apc_zend.h"
+#include "apc_sma.h"
+#include "apc_globals.h"
+#include "SAPI.h"
+#include "TSRM.h"
+#include "ext/standard/md5.h"
+
+/* TODO: rehash when load factor exceeds threshold */
+
+#define CHECK(p) { if ((p) == NULL) return NULL; }
+
+/* {{{ key_equals */
+#define key_equals(a, b) (a.inode==b.inode && a.device==b.device)
+/* }}} */
+
+static void apc_cache_expunge(apc_cache_t* cache, size_t size TSRMLS_DC);
+
+/* {{{ hash */
+static unsigned long hash(apc_cache_key_t key)
+{
+ return (unsigned long)(key.data.file.device + key.data.file.inode);
+}
+/* }}} */
+
+/* {{{ string_nhash_8 */
+#define string_nhash_8(s,len) (unsigned long)(zend_inline_hash_func((s), len))
+/* }}} */
+
+/* {{{ murmurhash */
+#if 0
+static inline unsigned long murmurhash(const char *skey, size_t keylen)
+{
+ const long m = 0x7fd652ad;
+ const long r = 16;
+ unsigned int h = 0xdeadbeef;
+
+ while(keylen >= 4)
+ {
+ h += *(unsigned int*)skey;
+ h *= m;
+ h ^= h >> r;
+
+ skey += 4;
+ keylen -= 4;
+ }
+
+ switch(keylen)
+ {
+ case 3:
+ h += skey[2] << 16;
+ case 2:
+ h += skey[1] << 8;
+ case 1:
+ h += skey[0];
+ h *= m;
+ h ^= h >> r;
+ };
+
+ h *= m;
+ h ^= h >> 10;
+ h *= m;
+ h ^= h >> 17;
+
+ return h;
+}
+#endif
+/* }}} */
+
+
+/* {{{ make_prime */
+static int const primes[] = {
+ 257, /* 256 */
+ 521, /* 512 */
+ 1031, /* 1024 */
+ 2053, /* 2048 */
+ 3079, /* 3072 */
+ 4099, /* 4096 */
+ 5147, /* 5120 */
+ 6151, /* 6144 */
+ 7177, /* 7168 */
+ 8209, /* 8192 */
+ 9221, /* 9216 */
+10243, /* 10240 */
+11273, /* 11264 */
+12289, /* 12288 */
+13313, /* 13312 */
+14341, /* 14336 */
+15361, /* 15360 */
+16411, /* 16384 */
+17417, /* 17408 */
+18433, /* 18432 */
+19457, /* 19456 */
+0 /* sentinel */
+};
+
+static int make_prime(int n)
+{
+ int *k = (int*)primes;
+ while(*k) {
+ if((*k) > n) return *k;
+ k++;
+ }
+ return *(k-1);
+}
+/* }}} */
+
+/* {{{ make_slot */
+slot_t* make_slot(apc_cache_key_t *key, apc_cache_entry_t* value, slot_t* next, time_t t TSRMLS_DC)
+{
+ slot_t* p = apc_pool_alloc(value->pool, sizeof(slot_t));
+
+ if (!p) return NULL;
+
+ if(key->type == APC_CACHE_KEY_USER) {
+ char *identifier = (char*) apc_pmemcpy(key->data.user.identifier, key->data.user.identifier_len, value->pool TSRMLS_CC);
+ if (!identifier) {
+ return NULL;
+ }
+ key->data.user.identifier = identifier;
+ } else if(key->type == APC_CACHE_KEY_FPFILE) {
+ char *fullpath = (char*) apc_pstrdup(key->data.fpfile.fullpath, value->pool TSRMLS_CC);
+ if (!fullpath) {
+ return NULL;
+ }
+ key->data.fpfile.fullpath = fullpath;
+ }
+ p->key = key[0];
+ p->value = value;
+ p->next = next;
+ p->num_hits = 0;
+ p->creation_time = t;
+ p->access_time = t;
+ p->deletion_time = 0;
+ return p;
+}
+/* }}} */
+
+/* {{{ free_slot */
+static void free_slot(slot_t* slot TSRMLS_DC)
+{
+ apc_pool_destroy(slot->value->pool TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ remove_slot */
+static void remove_slot(apc_cache_t* cache, slot_t** slot TSRMLS_DC)
+{
+ slot_t* dead = *slot;
+ *slot = (*slot)->next;
+
+ cache->header->mem_size -= dead->value->mem_size;
+ CACHE_FAST_DEC(cache, cache->header->num_entries);
+ if (dead->value->ref_count <= 0) {
+ free_slot(dead TSRMLS_CC);
+ }
+ else {
+ dead->next = cache->header->deleted_list;
+ dead->deletion_time = time(0);
+ cache->header->deleted_list = dead;
+ }
+}
+/* }}} */
+
+/* {{{ process_pending_removals */
+static void process_pending_removals(apc_cache_t* cache TSRMLS_DC)
+{
+ slot_t** slot;
+ time_t now;
+
+ /* This function scans the list of removed cache entries and deletes any
+ * entry whose reference count is zero (indicating that it is no longer
+ * being executed) or that has been on the pending list for more than
+ * cache->gc_ttl seconds (we issue a warning in the latter case).
+ */
+
+ if (!cache->header->deleted_list)
+ return;
+
+ slot = &cache->header->deleted_list;
+ now = time(0);
+
+ while (*slot != NULL) {
+ int gc_sec = cache->gc_ttl ? (now - (*slot)->deletion_time) : 0;
+
+ if ((*slot)->value->ref_count <= 0 || gc_sec > cache->gc_ttl) {
+ slot_t* dead = *slot;
+
+ if (dead->value->ref_count > 0) {
+ switch(dead->value->type) {
+ case APC_CACHE_ENTRY_FILE:
+ apc_debug("GC cache entry '%s' (dev=%d ino=%d) was on gc-list for %d seconds" TSRMLS_CC,
+ dead->value->data.file.filename, dead->key.data.file.device, dead->key.data.file.inode, gc_sec);
+ break;
+ case APC_CACHE_ENTRY_USER:
+ apc_debug("GC cache entry '%s' was on gc-list for %d seconds" TSRMLS_CC, dead->value->data.user.info, gc_sec);
+ break;
+ }
+ }
+ *slot = dead->next;
+ free_slot(dead TSRMLS_CC);
+ }
+ else {
+ slot = &(*slot)->next;
+ }
+ }
+}
+/* }}} */
+
+/* {{{ prevent_garbage_collection */
+static void prevent_garbage_collection(apc_cache_entry_t* entry)
+{
+ /* set reference counts on zend objects to an arbitrarily high value to
+ * prevent garbage collection after execution */
+
+ enum { BIG_VALUE = 1000 };
+
+ if(entry->data.file.op_array) {
+ entry->data.file.op_array->refcount[0] = BIG_VALUE;
+ }
+ if (entry->data.file.functions) {
+ int i;
+ apc_function_t* fns = entry->data.file.functions;
+ for (i=0; fns[i].function != NULL; i++) {
+ *(fns[i].function->op_array.refcount) = BIG_VALUE;
+ }
+ }
+ if (entry->data.file.classes) {
+ int i;
+ apc_class_t* classes = entry->data.file.classes;
+ for (i=0; classes[i].class_entry != NULL; i++) {
+ classes[i].class_entry->refcount = BIG_VALUE;
+ }
+ }
+}
+/* }}} */
+
+/* {{{ apc_cache_create */
+apc_cache_t* apc_cache_create(int size_hint, int gc_ttl, int ttl TSRMLS_DC)
+{
+ apc_cache_t* cache;
+ int cache_size;
+ int num_slots;
+
+ num_slots = make_prime(size_hint > 0 ? size_hint : 2000);
+
+ cache = (apc_cache_t*) apc_emalloc(sizeof(apc_cache_t) TSRMLS_CC);
+ cache_size = sizeof(cache_header_t) + num_slots*sizeof(slot_t*);
+
+ cache->shmaddr = apc_sma_malloc(cache_size TSRMLS_CC);
+ if(!cache->shmaddr) {
+ apc_error("Unable to allocate shared memory for cache structures. (Perhaps your shared memory size isn't large enough?). " TSRMLS_CC);
+ return NULL;
+ }
+ memset(cache->shmaddr, 0, cache_size);
+
+ cache->header = (cache_header_t*) cache->shmaddr;
+ cache->header->num_hits = 0;
+ cache->header->num_misses = 0;
+ cache->header->deleted_list = NULL;
+ cache->header->start_time = time(NULL);
+ cache->header->expunges = 0;
+ cache->header->busy = 0;
+
+ cache->slots = (slot_t**) (((char*) cache->shmaddr) + sizeof(cache_header_t));
+ cache->num_slots = num_slots;
+ cache->gc_ttl = gc_ttl;
+ cache->ttl = ttl;
+ CREATE_LOCK(cache->header->lock);
+#if NONBLOCKING_LOCK_AVAILABLE
+ CREATE_LOCK(cache->header->wrlock);
+#endif
+ memset(cache->slots, 0, sizeof(slot_t*)*num_slots);
+ cache->expunge_cb = apc_cache_expunge;
+ cache->has_lock = 0;
+
+ return cache;
+}
+/* }}} */
+
+/* {{{ apc_cache_destroy */
+void apc_cache_destroy(apc_cache_t* cache TSRMLS_DC)
+{
+ DESTROY_LOCK(cache->header->lock);
+#ifdef NONBLOCKING_LOCK_AVAILABLE
+ DESTROY_LOCK(cache->header->wrlock);
+#endif
+ apc_efree(cache TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ apc_cache_clear */
+void apc_cache_clear(apc_cache_t* cache TSRMLS_DC)
+{
+ int i;
+
+ if(!cache) return;
+
+ CACHE_LOCK(cache);
+ cache->header->busy = 1;
+ cache->header->num_hits = 0;
+ cache->header->num_misses = 0;
+ cache->header->start_time = time(NULL);
+ cache->header->expunges = 0;
+
+ for (i = 0; i < cache->num_slots; i++) {
+ slot_t* p = cache->slots[i];
+ while (p) {
+ remove_slot(cache, &p TSRMLS_CC);
+ }
+ cache->slots[i] = NULL;
+ }
+
+ memset(&cache->header->lastkey, 0, sizeof(apc_keyid_t));
+
+ cache->header->busy = 0;
+ CACHE_UNLOCK(cache);
+}
+/* }}} */
+
+/* {{{ apc_cache_expunge */
+static void apc_cache_expunge(apc_cache_t* cache, size_t size TSRMLS_DC)
+{
+ int i;
+ time_t t;
+
+ t = apc_time();
+
+ if(!cache) return;
+
+ if(!cache->ttl) {
+ /*
+ * If cache->ttl is not set, we wipe out the entire cache when
+ * we run out of space.
+ */
+ CACHE_SAFE_LOCK(cache);
+ process_pending_removals(cache TSRMLS_CC);
+ if (apc_sma_get_avail_mem() > (size_t)(APCG(shm_size)/2)) {
+ /* probably a queued up expunge, we don't need to do this */
+ CACHE_SAFE_UNLOCK(cache);
+ return;
+ }
+ cache->header->busy = 1;
+ CACHE_FAST_INC(cache, cache->header->expunges);
+clear_all:
+ for (i = 0; i < cache->num_slots; i++) {
+ slot_t* p = cache->slots[i];
+ while (p) {
+ remove_slot(cache, &p TSRMLS_CC);
+ }
+ cache->slots[i] = NULL;
+ }
+ memset(&cache->header->lastkey, 0, sizeof(apc_keyid_t));
+ cache->header->busy = 0;
+ CACHE_SAFE_UNLOCK(cache);
+ } else {
+ slot_t **p;
+ /*
+ * If the ttl for the cache is set we walk through and delete stale
+ * entries. For the user cache that is slightly confusing since
+ * we have the individual entry ttl's we can look at, but that would be
+ * too much work. So if you want the user cache expunged, set a high
+ * default apc.user_ttl and still provide a specific ttl for each entry
+ * on insert
+ */
+
+ CACHE_SAFE_LOCK(cache);
+ process_pending_removals(cache TSRMLS_CC);
+ if (apc_sma_get_avail_mem() > (size_t)(APCG(shm_size)/2)) {
+ /* probably a queued up expunge, we don't need to do this */
+ CACHE_SAFE_UNLOCK(cache);
+ return;
+ }
+ cache->header->busy = 1;
+ CACHE_FAST_INC(cache, cache->header->expunges);
+ for (i = 0; i < cache->num_slots; i++) {
+ p = &cache->slots[i];
+ while(*p) {
+ /*
+ * For the user cache we look at the individual entry ttl values
+ * and if not set fall back to the default ttl for the user cache
+ */
+ if((*p)->value->type == APC_CACHE_ENTRY_USER) {
+ if((*p)->value->data.user.ttl) {
+ if((time_t) ((*p)->creation_time + (*p)->value->data.user.ttl) < t) {
+ remove_slot(cache, p TSRMLS_CC);
+ continue;
+ }
+ } else if(cache->ttl) {
+ if((*p)->creation_time + cache->ttl < t) {
+ remove_slot(cache, p TSRMLS_CC);
+ continue;
+ }
+ }
+ } else if((*p)->access_time < (t - cache->ttl)) {
+ remove_slot(cache, p TSRMLS_CC);
+ continue;
+ }
+ p = &(*p)->next;
+ }
+ }
+
+ if (!apc_sma_get_avail_size(size)) {
+ /* TODO: re-do this to remove goto across locked sections */
+ goto clear_all;
+ }
+ memset(&cache->header->lastkey, 0, sizeof(apc_keyid_t));
+ cache->header->busy = 0;
+ CACHE_SAFE_UNLOCK(cache);
+ }
+}
+/* }}} */
+
+/* {{{ apc_cache_insert */
+static inline int _apc_cache_insert(apc_cache_t* cache,
+ apc_cache_key_t key,
+ apc_cache_entry_t* value,
+ apc_context_t* ctxt,
+ time_t t
+ TSRMLS_DC)
+{
+ slot_t** slot;
+
+ if (!value) {
+ return 0;
+ }
+
+ apc_debug("Inserting [%s]\n" TSRMLS_CC, value->data.file.filename);
+
+ process_pending_removals(cache TSRMLS_CC);
+
+ slot = &cache->slots[key.h % cache->num_slots];
+
+ while(*slot) {
+ if(key.type == (*slot)->key.type) {
+ if(key.type == APC_CACHE_KEY_FILE) {
+ if(key_equals((*slot)->key.data.file, key.data.file)) {
+ /* If existing slot for the same device+inode is different, remove it and insert the new version */
+ if (ctxt->force_update || (*slot)->key.mtime != key.mtime) {
+ remove_slot(cache, slot TSRMLS_CC);
+ break;
+ }
+ return 0;
+ } else if(cache->ttl && (*slot)->access_time < (t - cache->ttl)) {
+ remove_slot(cache, slot TSRMLS_CC);
+ continue;
+ }
+ } else { /* APC_CACHE_KEY_FPFILE */
+ if((key.h == (*slot)->key.h) &&
+ !memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) {
+ /* Hrm.. it's already here, remove it and insert new one */
+ remove_slot(cache, slot TSRMLS_CC);
+ break;
+ } else if(cache->ttl && (*slot)->access_time < (t - cache->ttl)) {
+ remove_slot(cache, slot TSRMLS_CC);
+ continue;
+ }
+ }
+ }
+ slot = &(*slot)->next;
+ }
+
+ if ((*slot = make_slot(&key, value, *slot, t TSRMLS_CC)) == NULL) {
+ return -1;
+ }
+
+ value->mem_size = ctxt->pool->size;
+ cache->header->mem_size += ctxt->pool->size;
+ CACHE_FAST_INC(cache, cache->header->num_entries);
+ CACHE_FAST_INC(cache, cache->header->num_inserts);
+
+ return 1;
+}
+/* }}} */
+
+/* {{{ apc_cache_insert */
+int apc_cache_insert(apc_cache_t* cache, apc_cache_key_t key, apc_cache_entry_t* value, apc_context_t *ctxt, time_t t TSRMLS_DC)
+{
+ int rval;
+ CACHE_LOCK(cache);
+ rval = _apc_cache_insert(cache, key, value, ctxt, t TSRMLS_CC);
+ CACHE_UNLOCK(cache);
+ return rval;
+}
+/* }}} */
+
+/* {{{ apc_cache_insert */
+int *apc_cache_insert_mult(apc_cache_t* cache, apc_cache_key_t* keys, apc_cache_entry_t** values, apc_context_t *ctxt, time_t t, int num_entries TSRMLS_DC)
+{
+ int *rval;
+ int i;
+
+ rval = emalloc(sizeof(int) * num_entries);
+ CACHE_LOCK(cache);
+ for (i=0; i < num_entries; i++) {
+ if (values[i]) {
+ ctxt->pool = values[i]->pool;
+ rval[i] = _apc_cache_insert(cache, keys[i], values[i], ctxt, t TSRMLS_CC);
+ }
+ }
+ CACHE_UNLOCK(cache);
+ return rval;
+}
+/* }}} */
+
+
+/* {{{ apc_cache_user_insert */
+int apc_cache_user_insert(apc_cache_t* cache, apc_cache_key_t key, apc_cache_entry_t* value, apc_context_t* ctxt, time_t t, int exclusive TSRMLS_DC)
+{
+ slot_t** slot;
+ unsigned int keylen = key.data.user.identifier_len;
+ apc_keyid_t *lastkey = &cache->header->lastkey;
+
+ if (!value) {
+ return 0;
+ }
+
+ if(apc_cache_busy(cache)) {
+ /* cache cleanup in progress, do not wait */
+ return 0;
+ }
+
+ if(apc_cache_is_last_key(cache, &key, t TSRMLS_CC)) {
+ /* potential cache slam */
+ return 0;
+ }
+
+ CACHE_LOCK(cache);
+
+ memset(lastkey, 0, sizeof(apc_keyid_t));
+
+ lastkey->h = key.h;
+ lastkey->keylen = keylen;
+ lastkey->mtime = t;
+#ifdef ZTS
+ lastkey->tid = tsrm_thread_id();
+#else
+ lastkey->pid = getpid();
+#endif
+
+ /* we do not reset lastkey after the insert. Whether it is inserted
+ * or not, another insert in the same second is always a bad idea.
+ */
+
+ process_pending_removals(cache TSRMLS_CC);
+
+ slot = &cache->slots[key.h % cache->num_slots];
+
+ while (*slot) {
+ if (((*slot)->key.h == key.h) &&
+ (!memcmp((*slot)->key.data.user.identifier, key.data.user.identifier, keylen))) {
+ /*
+ * At this point we have found the user cache entry. If we are doing
+ * an exclusive insert (apc_add) we are going to bail right away if
+ * the user entry already exists and it has no ttl, or
+ * there is a ttl and the entry has not timed out yet.
+ */
+ if(exclusive && ( !(*slot)->value->data.user.ttl ||
+ ( (*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) >= t )
+ ) ) {
+ goto fail;
+ }
+ remove_slot(cache, slot TSRMLS_CC);
+ break;
+ } else
+ /*
+ * This is a bit nasty. The idea here is to do runtime cleanup of the linked list of
+ * slot entries so we don't always have to skip past a bunch of stale entries. We check
+ * for staleness here and get rid of them by first checking to see if the cache has a global
+ * access ttl on it and removing entries that haven't been accessed for ttl seconds and secondly
+ * we see if the entry has a hard ttl on it and remove it if it has been around longer than its ttl
+ */
+ if((cache->ttl && (*slot)->access_time < (t - cache->ttl)) ||
+ ((*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t)) {
+ remove_slot(cache, slot TSRMLS_CC);
+ continue;
+ }
+ slot = &(*slot)->next;
+ }
+
+ if ((*slot = make_slot(&key, value, *slot, t TSRMLS_CC)) == NULL) {
+ goto fail;
+ }
+
+ value->mem_size = ctxt->pool->size;
+ cache->header->mem_size += ctxt->pool->size;
+
+ CACHE_FAST_INC(cache, cache->header->num_entries);
+ CACHE_FAST_INC(cache, cache->header->num_inserts);
+
+ CACHE_UNLOCK(cache);
+
+ return 1;
+
+fail:
+ CACHE_UNLOCK(cache);
+
+ return 0;
+}
+/* }}} */
+
+/* {{{ apc_cache_find_slot */
+slot_t* apc_cache_find_slot(apc_cache_t* cache, apc_cache_key_t key, time_t t TSRMLS_DC)
+{
+ slot_t** slot;
+ volatile slot_t* retval = NULL;
+
+ CACHE_RDLOCK(cache);
+ if(key.type == APC_CACHE_KEY_FILE) slot = &cache->slots[hash(key) % cache->num_slots];
+ else slot = &cache->slots[key.h % cache->num_slots];
+
+ while (*slot) {
+ if(key.type == (*slot)->key.type) {
+ if(key.type == APC_CACHE_KEY_FILE) {
+ if(key_equals((*slot)->key.data.file, key.data.file)) {
+ if((*slot)->key.mtime != key.mtime) {
+ #if (USE_READ_LOCKS == 0)
+ /* this is merely a memory-friendly optimization, if we do have a write-lock
+ * might as well move this to the deleted_list right-away. Otherwise an insert
+ * of the same key wil do it (or an expunge, *eventually*).
+ */
+ remove_slot(cache, slot TSRMLS_CC);
+ #endif
+ CACHE_SAFE_INC(cache, cache->header->num_misses);
+ CACHE_RDUNLOCK(cache);
+ return NULL;
+ }
+ CACHE_SAFE_INC(cache, (*slot)->num_hits);
+ CACHE_SAFE_INC(cache, (*slot)->value->ref_count);
+ (*slot)->access_time = t;
+ prevent_garbage_collection((*slot)->value);
+ CACHE_FAST_INC(cache, cache->header->num_hits);
+ retval = *slot;
+ CACHE_RDUNLOCK(cache);
+ return (slot_t*)retval;
+ }
+ } else { /* APC_CACHE_KEY_FPFILE */
+ if(((*slot)->key.h == key.h) &&
+ !memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) {
+ /* TTL Check ? */
+ CACHE_SAFE_INC(cache, (*slot)->num_hits);
+ CACHE_SAFE_INC(cache, (*slot)->value->ref_count);
+ (*slot)->access_time = t;
+ prevent_garbage_collection((*slot)->value);
+ CACHE_FAST_INC(cache, cache->header->num_hits);
+ retval = *slot;
+ CACHE_RDUNLOCK(cache);
+ return (slot_t*)retval;
+ }
+ }
+ }
+ slot = &(*slot)->next;
+ }
+ CACHE_FAST_INC(cache, cache->header->num_misses);
+ CACHE_RDUNLOCK(cache);
+ return NULL;
+}
+/* }}} */
+
+/* {{{ apc_cache_find */
+apc_cache_entry_t* apc_cache_find(apc_cache_t* cache, apc_cache_key_t key, time_t t TSRMLS_DC)
+{
+ slot_t * slot = apc_cache_find_slot(cache, key, t TSRMLS_CC);
+ apc_debug("apc_cache_find [%i]\n" TSRMLS_CC, key.h);
+ 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 TSRMLS_DC)
+{
+ slot_t** slot;
+ volatile apc_cache_entry_t* value = NULL;
+ unsigned long h;
+
+ if(apc_cache_busy(cache))
+ {
+ /* cache cleanup in progress */
+ return NULL;
+ }
+
+ CACHE_RDLOCK(cache);
+
+ h = string_nhash_8(strkey, keylen);
+
+ slot = &cache->slots[h % cache->num_slots];
+
+ while (*slot) {
+ if ((h == (*slot)->key.h) &&
+ !memcmp((*slot)->key.data.user.identifier, strkey, keylen)) {
+ /* Check to make sure this entry isn't expired by a hard TTL */
+ if((*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t) {
+ #if (USE_READ_LOCKS == 0)
+ /* this is merely a memory-friendly optimization, if we do have a write-lock
+ * might as well move this to the deleted_list right-away. Otherwise an insert
+ * of the same key wil do it (or an expunge, *eventually*).
+ */
+ remove_slot(cache, slot TSRMLS_CC);
+ #endif
+ CACHE_FAST_INC(cache, cache->header->num_misses);
+ CACHE_RDUNLOCK(cache);
+ return NULL;
+ }
+ /* Otherwise we are fine, increase counters and return the cache entry */
+ CACHE_SAFE_INC(cache, (*slot)->num_hits);
+ CACHE_SAFE_INC(cache, (*slot)->value->ref_count);
+ (*slot)->access_time = t;
+
+ CACHE_FAST_INC(cache, cache->header->num_hits);
+ value = (*slot)->value;
+ CACHE_RDUNLOCK(cache);
+ return (apc_cache_entry_t*)value;
+ }
+ slot = &(*slot)->next;
+ }
+
+ CACHE_FAST_INC(cache, cache->header->num_misses);
+ CACHE_RDUNLOCK(cache);
+ return NULL;
+}
+/* }}} */
+
+/* {{{ apc_cache_user_exists */
+apc_cache_entry_t* apc_cache_user_exists(apc_cache_t* cache, char *strkey, int keylen, time_t t TSRMLS_DC)
+{
+ slot_t** slot;
+ volatile apc_cache_entry_t* value = NULL;
+ unsigned long h;
+
+ if(apc_cache_busy(cache))
+ {
+ /* cache cleanup in progress */
+ return NULL;
+ }
+
+ CACHE_RDLOCK(cache);
+
+ h = string_nhash_8(strkey, keylen);
+
+ slot = &cache->slots[h % cache->num_slots];
+
+ while (*slot) {
+ if ((h == (*slot)->key.h) &&
+ !memcmp((*slot)->key.data.user.identifier, strkey, keylen)) {
+ /* Check to make sure this entry isn't expired by a hard TTL */
+ if((*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t) {
+ CACHE_UNLOCK(cache);
+ return NULL;
+ }
+ /* Return the cache entry ptr */
+ value = (*slot)->value;
+ CACHE_RDUNLOCK(cache);
+ return (apc_cache_entry_t*)value;
+ }
+ slot = &(*slot)->next;
+ }
+ CACHE_RDUNLOCK(cache);
+ return NULL;
+}
+/* }}} */
+
+/* {{{ apc_cache_user_update */
+int _apc_cache_user_update(apc_cache_t* cache, char *strkey, int keylen, apc_cache_updater_t updater, void* data TSRMLS_DC)
+{
+ slot_t** slot;
+ int retval;
+ unsigned long h;
+
+ if(apc_cache_busy(cache))
+ {
+ /* cache cleanup in progress */
+ return 0;
+ }
+
+ CACHE_LOCK(cache);
+
+ h = string_nhash_8(strkey, keylen);
+ slot = &cache->slots[h % cache->num_slots];
+
+ while (*slot) {
+ if ((h == (*slot)->key.h) &&
+ !memcmp((*slot)->key.data.user.identifier, strkey, keylen)) {
+ switch(Z_TYPE_P((*slot)->value->data.user.val) & ~IS_CONSTANT_INDEX) {
+ case IS_ARRAY:
+ case IS_CONSTANT_ARRAY:
+ case IS_OBJECT:
+ {
+ if(APCG(serializer)) {
+ retval = 0;
+ break;
+ } else {
+ /* fall through */
+ }
+ }
+ /* fall through */
+ default:
+ {
+ retval = updater(cache, (*slot)->value, data);
+ (*slot)->key.mtime = apc_time();
+ }
+ break;
+ }
+ CACHE_UNLOCK(cache);
+ return retval;
+ }
+ slot = &(*slot)->next;
+ }
+ CACHE_UNLOCK(cache);
+ return 0;
+}
+/* }}} */
+
+/* {{{ apc_cache_user_delete */
+int apc_cache_user_delete(apc_cache_t* cache, char *strkey, int keylen TSRMLS_DC)
+{
+ slot_t** slot;
+ unsigned long h;
+
+ CACHE_LOCK(cache);
+
+ h = string_nhash_8(strkey, keylen);
+
+ slot = &cache->slots[h % cache->num_slots];
+
+ while (*slot) {
+ if ((h == (*slot)->key.h) &&
+ !memcmp((*slot)->key.data.user.identifier, strkey, keylen)) {
+ remove_slot(cache, slot TSRMLS_CC);
+ CACHE_UNLOCK(cache);
+ return 1;
+ }
+ slot = &(*slot)->next;
+ }
+
+ CACHE_UNLOCK(cache);
+ return 0;
+}
+/* }}} */
+
+/* {{{ apc_cache_delete */
+int apc_cache_delete(apc_cache_t* cache, char *filename, int filename_len TSRMLS_DC)
+{
+ slot_t** slot;
+ time_t t;
+ apc_cache_key_t key;
+
+ t = apc_time();
+
+ /* try to create a cache key; if we fail, give up on caching */
+ if (!apc_cache_make_file_key(&key, filename, PG(include_path), t TSRMLS_CC)) {
+ apc_warning("Could not stat file %s, unable to delete from cache." TSRMLS_CC, filename);
+ return -1;
+ }
+
+ CACHE_LOCK(cache);
+
+ if(key.type == APC_CACHE_KEY_FILE) slot = &cache->slots[hash(key) % cache->num_slots];
+ else slot = &cache->slots[key.h % cache->num_slots];
+
+ while(*slot) {
+ if(key.type == (*slot)->key.type) {
+ if(key.type == APC_CACHE_KEY_FILE) {
+ if(key_equals((*slot)->key.data.file, key.data.file)) {
+ remove_slot(cache, slot TSRMLS_CC);
+ CACHE_UNLOCK(cache);
+ return 1;
+ }
+ } else { /* APC_CACHE_KEY_FPFILE */
+ if(((*slot)->key.h == key.h) &&
+ (!memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1))) {
+ remove_slot(cache, slot TSRMLS_CC);
+ CACHE_UNLOCK(cache);
+ return 1;
+ }
+ }
+ }
+ slot = &(*slot)->next;
+ }
+
+ memset(&cache->header->lastkey, 0, sizeof(apc_keyid_t));
+
+ CACHE_UNLOCK(cache);
+ return 0;
+
+}
+/* }}} */
+
+/* {{{ apc_cache_release */
+void apc_cache_release(apc_cache_t* cache, apc_cache_entry_t* entry TSRMLS_DC)
+{
+ CACHE_SAFE_DEC(cache, entry->ref_count);
+}
+/* }}} */
+
+/* {{{ apc_cache_make_file_key */
+int apc_cache_make_file_key(apc_cache_key_t* key,
+ const char* filename,
+ const char* include_path,
+ time_t t
+ TSRMLS_DC)
+{
+ struct stat *tmp_buf=NULL;
+ struct apc_fileinfo_t *fileinfo = NULL;
+ int len;
+
+ assert(key != NULL);
+
+ if (!filename || !SG(request_info).path_translated) {
+ apc_debug("No filename and no path_translated - bailing\n" TSRMLS_CC);
+ goto cleanup;
+ }
+
+ len = strlen(filename);
+ if(APCG(fpstat)==0) {
+ if(IS_ABSOLUTE_PATH(filename,len)) {
+ key->data.fpfile.fullpath = filename;
+ key->data.fpfile.fullpath_len = len;
+ key->h = string_nhash_8(key->data.fpfile.fullpath, key->data.fpfile.fullpath_len);
+ key->mtime = t;
+ key->type = APC_CACHE_KEY_FPFILE;
+ goto success;
+ } else if(APCG(canonicalize)) {
+
+ fileinfo = apc_php_malloc(sizeof(apc_fileinfo_t) TSRMLS_CC);
+
+ if (apc_search_paths(filename, include_path, fileinfo TSRMLS_CC) != 0) {
+ apc_warning("apc failed to locate %s - bailing" TSRMLS_CC, filename);
+ goto cleanup;
+ }
+
+ if(!VCWD_REALPATH(fileinfo->fullpath, APCG(canon_path))) {
+ apc_warning("realpath failed to canonicalize %s - bailing" TSRMLS_CC, filename);
+ goto cleanup;
+ }
+
+ key->data.fpfile.fullpath = APCG(canon_path);
+ key->data.fpfile.fullpath_len = strlen(APCG(canon_path));
+ key->h = string_nhash_8(key->data.fpfile.fullpath, key->data.fpfile.fullpath_len);
+ key->mtime = t;
+ key->type = APC_CACHE_KEY_FPFILE;
+ goto success;
+ }
+ /* fall through to stat mode */
+ }
+
+ fileinfo = apc_php_malloc(sizeof(apc_fileinfo_t) TSRMLS_CC);
+
+ assert(fileinfo != NULL);
+
+ if(!strcmp(SG(request_info).path_translated, filename)) {
+ tmp_buf = sapi_get_stat(TSRMLS_C); /* Apache has already done this stat() for us */
+ }
+
+ if(tmp_buf) {
+ fileinfo->st_buf.sb = *tmp_buf;
+ } else {
+ if (apc_search_paths(filename, include_path, fileinfo TSRMLS_CC) != 0) {
+ apc_debug("Stat failed %s - bailing (%s) (%d)\n" TSRMLS_CC, filename,SG(request_info).path_translated);
+ goto cleanup;
+ }
+ }
+
+ if(APCG(max_file_size) < fileinfo->st_buf.sb.st_size) {
+ apc_debug("File is too big %s (%d - %ld) - bailing\n" TSRMLS_CC, filename,t,fileinfo->st_buf.sb.st_size);
+ goto cleanup;
+ }
+
+ /*
+ * This is a bit of a hack.
+ *
+ * Here I am checking to see if the file is at least 2 seconds old.
+ * The idea is that if the file is currently being written to then its
+ * mtime is going to match or at most be 1 second off of the current
+ * request time and we want to avoid caching files that have not been
+ * completely written. Of course, people should be using atomic
+ * mechanisms to push files onto live web servers, but adding this
+ * tiny safety is easier than educating the world. This is now
+ * configurable, but the default is still 2 seconds.
+ */
+ if(APCG(file_update_protection) && (t - fileinfo->st_buf.sb.st_mtime < APCG(file_update_protection)) && !APCG(force_file_update)) {
+ apc_debug("File is too new %s (%d - %d) - bailing\n" TSRMLS_CC,filename,t,fileinfo->st_buf.sb.st_mtime);
+ goto cleanup;
+ }
+
+ key->data.file.device = fileinfo->st_buf.sb.st_dev;
+ key->data.file.inode = fileinfo->st_buf.sb.st_ino;
+ key->h = (unsigned long) key->data.file.device + (unsigned long) key->data.file.inode;
+
+ /*
+ * If working with content management systems that like to munge the mtime,
+ * it might be appropriate to key off of the ctime to be immune to systems
+ * that try to backdate a template. If the mtime is set to something older
+ * than the previous mtime of a template we will obviously never see this
+ * "older" template. At some point the Smarty templating system did this.
+ * I generally disagree with using the ctime here because you lose the
+ * ability to warm up new content by saving it to a temporary file, hitting
+ * it once to cache it and then renaming it into its permanent location so
+ * set the apc.stat_ctime=true to enable this check.
+ */
+ if(APCG(stat_ctime)) {
+ key->mtime = (fileinfo->st_buf.sb.st_ctime > fileinfo->st_buf.sb.st_mtime) ? fileinfo->st_buf.sb.st_ctime : fileinfo->st_buf.sb.st_mtime;
+ } else {
+ key->mtime = fileinfo->st_buf.sb.st_mtime;
+ }
+ key->type = APC_CACHE_KEY_FILE;
+
+success:
+
+ if(fileinfo != NULL) {
+ apc_php_free(fileinfo TSRMLS_CC);
+ }
+
+ return 1;
+
+cleanup:
+
+ if(fileinfo != NULL) {
+ apc_php_free(fileinfo TSRMLS_CC);
+ }
+
+ return 0;
+}
+/* }}} */
+
+/* {{{ apc_cache_make_user_key */
+int apc_cache_make_user_key(apc_cache_key_t* key, char* identifier, int identifier_len, const time_t t)
+{
+ assert(key != NULL);
+
+ if (!identifier)
+ return 0;
+
+ key->data.user.identifier = identifier;
+ key->data.user.identifier_len = identifier_len;
+ key->h = string_nhash_8(key->data.user.identifier, key->data.user.identifier_len);
+ key->mtime = t;
+ key->type = APC_CACHE_KEY_USER;
+ return 1;
+}
+/* }}} */
+
+/* {{{ apc_cache_make_file_entry */
+apc_cache_entry_t* apc_cache_make_file_entry(const char* filename,
+ zend_op_array* op_array,
+ apc_function_t* functions,
+ apc_class_t* classes,
+ apc_context_t* ctxt
+ TSRMLS_DC)
+{
+ apc_cache_entry_t* entry;
+ apc_pool* pool = ctxt->pool;
+
+ entry = (apc_cache_entry_t*) apc_pool_alloc(pool, sizeof(apc_cache_entry_t));
+ if (!entry) return NULL;
+
+ entry->data.file.filename = apc_pstrdup(filename, pool TSRMLS_CC);
+ if(!entry->data.file.filename) {
+ apc_debug("apc_cache_make_file_entry: entry->data.file.filename is NULL - bailing\n" TSRMLS_CC);
+ return NULL;
+ }
+ apc_debug("apc_cache_make_file_entry: entry->data.file.filename is [%s]\n" TSRMLS_CC,entry->data.file.filename);
+ entry->data.file.op_array = op_array;
+ entry->data.file.functions = functions;
+ entry->data.file.classes = classes;
+
+ entry->data.file.halt_offset = apc_file_halt_offset(filename TSRMLS_CC);
+
+ entry->type = APC_CACHE_ENTRY_FILE;
+ entry->ref_count = 0;
+ entry->mem_size = 0;
+ entry->pool = pool;
+ return entry;
+}
+/* }}} */
+
+/* {{{ apc_cache_store_zval */
+zval* apc_cache_store_zval(zval* dst, const zval* src, apc_context_t* ctxt TSRMLS_DC)
+{
+ if (Z_TYPE_P(src) == IS_ARRAY) {
+ /* Maintain a list of zvals we've copied to properly handle recursive structures */
+ zend_hash_init(&APCG(copied_zvals), 0, NULL, NULL, 0);
+ dst = apc_copy_zval(dst, src, ctxt TSRMLS_CC);
+ zend_hash_destroy(&APCG(copied_zvals));
+ APCG(copied_zvals).nTableSize=0;
+ } else {
+ dst = apc_copy_zval(dst, src, ctxt TSRMLS_CC);
+ }
+
+
+ return dst;
+}
+/* }}} */
+
+/* {{{ apc_cache_fetch_zval */
+zval* apc_cache_fetch_zval(zval* dst, const zval* src, apc_context_t* ctxt TSRMLS_DC)
+{
+ if (Z_TYPE_P(src) == IS_ARRAY) {
+ /* Maintain a list of zvals we've copied to properly handle recursive structures */
+ zend_hash_init(&APCG(copied_zvals), 0, NULL, NULL, 0);
+ dst = apc_copy_zval(dst, src, ctxt TSRMLS_CC);
+ zend_hash_destroy(&APCG(copied_zvals));
+ APCG(copied_zvals).nTableSize=0;
+ } else {
+ dst = apc_copy_zval(dst, src, ctxt TSRMLS_CC);
+ }
+
+
+ return dst;
+}
+/* }}} */
+
+/* {{{ apc_cache_make_user_entry */
+apc_cache_entry_t* apc_cache_make_user_entry(const char* info, int info_len, const zval* val, apc_context_t* ctxt, const unsigned int ttl TSRMLS_DC)
+{
+ apc_cache_entry_t* entry;
+ apc_pool* pool = ctxt->pool;
+
+ entry = (apc_cache_entry_t*) apc_pool_alloc(pool, sizeof(apc_cache_entry_t));
+ if (!entry) return NULL;
+
+ entry->data.user.info = apc_pmemcpy(info, info_len, pool TSRMLS_CC);
+ entry->data.user.info_len = info_len;
+ if(!entry->data.user.info) {
+ return NULL;
+ }
+ entry->data.user.val = apc_cache_store_zval(NULL, val, ctxt TSRMLS_CC);
+ if(!entry->data.user.val) {
+ return NULL;
+ }
+ INIT_PZVAL(entry->data.user.val);
+ entry->data.user.ttl = ttl;
+ entry->type = APC_CACHE_ENTRY_USER;
+ entry->ref_count = 0;
+ entry->mem_size = 0;
+ entry->pool = pool;
+ return entry;
+}
+/* }}} */
+
+/* {{{ */
+static zval* apc_cache_link_info(apc_cache_t *cache, slot_t* p TSRMLS_DC)
+{
+ zval *link = NULL;
+ char md5str[33];
+
+ ALLOC_INIT_ZVAL(link);
+
+ if(!link) {
+ return NULL;
+ }
+
+ array_init(link);
+
+ if(p->value->type == APC_CACHE_ENTRY_FILE) {
+ add_assoc_string(link, "type", "file", 1);
+ if(p->key.type == APC_CACHE_KEY_FILE) {
+
+ #ifdef PHP_WIN32
+ {
+ char buf[20];
+ sprintf(buf, "%I64d", p->key.data.file.device);
+ add_assoc_string(link, "device", buf, 1);
+
+ sprintf(buf, "%I64d", p->key.data.file.inode);
+ add_assoc_string(link, "inode", buf, 1);
+ }
+ #else
+ add_assoc_long(link, "device", p->key.data.file.device);
+ add_assoc_long(link, "inode", p->key.data.file.inode);
+ #endif
+
+ add_assoc_string(link, "filename", p->value->data.file.filename, 1);
+ } else { /* This is a no-stat fullpath file entry */
+ add_assoc_long(link, "device", 0);
+ add_assoc_long(link, "inode", 0);
+ add_assoc_string(link, "filename", (char*)p->key.data.fpfile.fullpath, 1);
+ }
+ if (APCG(file_md5)) {
+ make_digest(md5str, p->key.md5);
+ add_assoc_string(link, "md5", md5str, 1);
+ }
+ } else if(p->value->type == APC_CACHE_ENTRY_USER) {
+ add_assoc_stringl(link, "info", p->value->data.user.info, p->value->data.user.info_len-1, 1);
+ add_assoc_long(link, "ttl", (long)p->value->data.user.ttl);
+ add_assoc_string(link, "type", "user", 1);
+ }
+
+ add_assoc_double(link, "num_hits", (double)p->num_hits);
+ add_assoc_long(link, "mtime", p->key.mtime);
+ add_assoc_long(link, "creation_time", p->creation_time);
+ add_assoc_long(link, "deletion_time", p->deletion_time);
+ add_assoc_long(link, "access_time", p->access_time);
+ add_assoc_long(link, "ref_count", p->value->ref_count);
+ add_assoc_long(link, "mem_size", p->value->mem_size);
+
+ return link;
+}
+/* }}} */
+
+/* {{{ apc_cache_info */
+zval* apc_cache_info(apc_cache_t* cache, zend_bool limited TSRMLS_DC)
+{
+ zval *info = NULL;
+ zval *list = NULL;
+ zval *deleted_list = NULL;
+ zval *slots = NULL;
+ slot_t* p;
+ int i, j;
+
+ if(!cache) return NULL;
+
+ CACHE_RDLOCK(cache);
+
+ ALLOC_INIT_ZVAL(info);
+
+ if(!info) {
+ CACHE_RDUNLOCK(cache);
+ return NULL;
+ }
+
+ array_init(info);
+ add_assoc_long(info, "num_slots", cache->num_slots);
+ add_assoc_long(info, "ttl", cache->ttl);
+
+ add_assoc_double(info, "num_hits", (double)cache->header->num_hits);
+ add_assoc_double(info, "num_misses", (double)cache->header->num_misses);
+ add_assoc_double(info, "num_inserts", (double)cache->header->num_inserts);
+ add_assoc_double(info, "expunges", (double)cache->header->expunges);
+
+ add_assoc_long(info, "start_time", cache->header->start_time);
+ add_assoc_double(info, "mem_size", (double)cache->header->mem_size);
+ add_assoc_long(info, "num_entries", cache->header->num_entries);
+#ifdef MULTIPART_EVENT_FORMDATA
+ add_assoc_long(info, "file_upload_progress", 1);
+#else
+ add_assoc_long(info, "file_upload_progress", 0);
+#endif
+#if APC_MMAP
+ add_assoc_stringl(info, "memory_type", "mmap", sizeof("mmap")-1, 1);
+#else
+ add_assoc_stringl(info, "memory_type", "IPC shared", sizeof("IPC shared")-1, 1);
+#endif
+ add_assoc_stringl(info, "locking_type", APC_LOCK_TYPE, sizeof(APC_LOCK_TYPE)-1, 1);
+
+ if(!limited) {
+ /* For each hashtable slot */
+ ALLOC_INIT_ZVAL(list);
+ array_init(list);
+
+ ALLOC_INIT_ZVAL(slots);
+ array_init(slots);
+
+ for (i = 0; i < cache->num_slots; i++) {
+ p = cache->slots[i];
+ j = 0;
+ for (; p != NULL; p = p->next) {
+ zval *link = apc_cache_link_info(cache, p TSRMLS_CC);
+ add_next_index_zval(list, link);
+ j++;
+ }
+ add_next_index_long(slots, j);
+ }
+
+ /* For each slot pending deletion */
+ ALLOC_INIT_ZVAL(deleted_list);
+ array_init(deleted_list);
+
+ for (p = cache->header->deleted_list; p != NULL; p = p->next) {
+ zval *link = apc_cache_link_info(cache, p TSRMLS_CC);
+ add_next_index_zval(deleted_list, link);
+ }
+
+ add_assoc_zval(info, "cache_list", list);
+ add_assoc_zval(info, "deleted_list", deleted_list);
+ add_assoc_zval(info, "slot_distribution", slots);
+ }
+
+ CACHE_RDUNLOCK(cache);
+ return info;
+}
+/* }}} */
+
+/* {{{ apc_cache_unlock */
+void apc_cache_unlock(apc_cache_t* cache TSRMLS_DC)
+{
+ CACHE_UNLOCK(cache);
+}
+/* }}} */
+
+/* {{{ apc_cache_busy */
+zend_bool apc_cache_busy(apc_cache_t* cache)
+{
+ return cache->header->busy;
+}
+/* }}} */
+
+/* {{{ apc_cache_is_last_key */
+zend_bool apc_cache_is_last_key(apc_cache_t* cache, apc_cache_key_t* key, time_t t TSRMLS_DC)
+{
+ apc_keyid_t *lastkey = &cache->header->lastkey;
+ unsigned int keylen = key->data.user.identifier_len;
+#ifdef ZTS
+ THREAD_T tid = tsrm_thread_id();
+ #define FROM_DIFFERENT_THREAD(k) (memcmp(&((k)->tid), &tid, sizeof(THREAD_T))!=0)
+#else
+ pid_t pid = getpid();
+ #define FROM_DIFFERENT_THREAD(k) (pid != (k)->pid)
+#endif
+
+
+ /* unlocked reads, but we're not shooting for 100% success with this */
+ if(lastkey->h == key->h && keylen == lastkey->keylen) {
+ if(lastkey->mtime == t && FROM_DIFFERENT_THREAD(lastkey)) {
+ /* potential cache slam */
+ if(APCG(slam_defense)) {
+ apc_debug("Potential cache slam averted for key '%s'" TSRMLS_CC, key->data.user.identifier);
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+/* }}} */
+
+#if NONBLOCKING_LOCK_AVAILABLE
+/* {{{ apc_cache_write_lock */
+zend_bool apc_cache_write_lock(apc_cache_t* cache TSRMLS_DC)
+{
+ return apc_lck_nb_lock(cache->header->wrlock);
+}
+/* }}} */
+
+/* {{{ apc_cache_write_unlock */
+void apc_cache_write_unlock(apc_cache_t* cache TSRMLS_DC)
+{
+ apc_lck_unlock(cache->header->wrlock);
+}
+/* }}} */
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker
+ * vim<600: expandtab sw=4 ts=4 sts=4
+ */
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_cache.h
^
|
(renamed from APC-3.1.8/apc_cache.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_cache.h
^
|
(renamed from APC-3.1.8/apc_cache.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_compile.c
^
|
(renamed from APC-3.1.8/apc_compile.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_compile.c
^
|
(renamed from APC-3.1.8/apc_compile.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_compile.h
^
|
(renamed from APC-3.1.8/apc_compile.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_compile.h
^
|
(renamed from APC-3.1.8/apc_compile.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_debug.c
^
|
(renamed from APC-3.1.8/apc_debug.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_debug.c
^
|
(renamed from APC-3.1.8/apc_debug.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_debug.h
^
|
(renamed from APC-3.1.8/apc_debug.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_debug.h
^
|
(renamed from APC-3.1.8/apc_debug.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_fcntl.c
^
|
(renamed from APC-3.1.8/apc_fcntl.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_fcntl.c
^
|
(renamed from APC-3.1.8/apc_fcntl.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_fcntl.h
^
|
(renamed from APC-3.1.8/apc_fcntl.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_fcntl.h
^
|
(renamed from APC-3.1.8/apc_fcntl.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_fcntl_win32.c
^
|
(renamed from APC-3.1.8/apc_fcntl_win32.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_fcntl_win32.c
^
|
(renamed from APC-3.1.8/apc_fcntl_win32.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_globals.h
^
|
(renamed from APC-3.1.8/apc_globals.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_globals.h
^
|
(renamed from APC-3.1.8/apc_globals.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_iterator.c
^
|
(renamed from APC-3.1.8/apc_iterator.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_iterator.c
^
|
(renamed from APC-3.1.8/apc_iterator.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_iterator.h
^
|
(renamed from APC-3.1.8/apc_iterator.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_iterator.h
^
|
(renamed from APC-3.1.8/apc_iterator.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_lock.h
^
|
(renamed from APC-3.1.8/apc_lock.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_lock.h
^
|
(renamed from APC-3.1.8/apc_lock.h)
|
[-]
[+]
|
Added |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_main.c
^
|
@@ -0,0 +1,1026 @@
+/*
+ +----------------------------------------------------------------------+
+ | APC |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2006-2011 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Daniel Cowgill <dcowgill@communityconnect.com> |
+ | Rasmus Lerdorf <rasmus@php.net> |
+ | Arun C. Murthy <arunc@yahoo-inc.com> |
+ | Gopal Vijayaraghavan <gopalv@yahoo-inc.com> |
+ +----------------------------------------------------------------------+
+
+ This software was contributed to PHP by Community Connect Inc. in 2002
+ and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
+ Future revisions and derivatives of this source code must acknowledge
+ Community Connect Inc. as the original contributor of this module by
+ leaving this note intact in the source code.
+
+ All other licensing and usage conditions are those of the PHP Group.
+
+ */
+
+/* $Id: apc_main.c 309002 2011-03-07 19:50:18Z pajoye $ */
+
+#include "apc_php.h"
+#include "apc_main.h"
+#include "apc.h"
+#include "apc_lock.h"
+#include "apc_cache.h"
+#include "apc_compile.h"
+#include "apc_globals.h"
+#include "apc_sma.h"
+#include "apc_stack.h"
+#include "apc_zend.h"
+#include "apc_pool.h"
+#include "apc_string.h"
+#include "SAPI.h"
+#include "php_scandir.h"
+#include "ext/standard/php_var.h"
+#include "ext/standard/md5.h"
+
+#define APC_MAX_SERIALIZERS 16
+
+/* {{{ module variables */
+
+/* pointer to the original Zend engine compile_file function */
+typedef zend_op_array* (zend_compile_t)(zend_file_handle*, int TSRMLS_DC);
+static zend_compile_t *old_compile_file;
+static apc_serializer_t apc_serializers[APC_MAX_SERIALIZERS] = {{0,}};
+
+/* }}} */
+
+/* {{{ get/set old_compile_file (to interact with other extensions that need the compile hook) */
+static zend_compile_t* set_compile_hook(zend_compile_t *ptr)
+{
+ zend_compile_t *retval = old_compile_file;
+
+ if (ptr != NULL) old_compile_file = ptr;
+ return retval;
+}
+/* }}} */
+
+/* {{{ install_function */
+static int install_function(apc_function_t fn, apc_context_t* ctxt, int lazy TSRMLS_DC)
+{
+ int status;
+
+#if APC_HAVE_LOOKUP_HOOKS
+ if(lazy && fn.name[0] != '\0' && strncmp(fn.name, "__autoload", fn.name_len) != 0) {
+ status = zend_hash_add(APCG(lazy_function_table),
+ fn.name,
+ fn.name_len+1,
+ &fn,
+ sizeof(apc_function_t),
+ NULL);
+#else
+ if(0) {
+#endif
+ } else {
+ zend_function *func = apc_copy_function_for_execution(fn.function, ctxt TSRMLS_CC);
+ status = zend_hash_add(EG(function_table),
+ fn.name,
+ fn.name_len+1,
+ func,
+ sizeof(fn.function[0]),
+ NULL);
+ efree(func);
+ }
+
+ if (status == FAILURE) {
+ /* apc_error("Cannot redeclare %s()" TSRMLS_CC, fn.name); */
+ }
+
+ return status;
+}
+/* }}} */
+
+/* {{{ apc_lookup_function_hook */
+int apc_lookup_function_hook(char *name, int len, ulong hash, zend_function **fe) {
+ apc_function_t *fn;
+ int status = FAILURE;
+ apc_context_t ctxt = {0,};
+ TSRMLS_FETCH();
+
+ ctxt.pool = apc_pool_create(APC_UNPOOL, apc_php_malloc, apc_php_free, apc_sma_protect, apc_sma_unprotect TSRMLS_CC);
+ ctxt.copy = APC_COPY_OUT_OPCODE;
+
+ if(zend_hash_quick_find(APCG(lazy_function_table), name, len, hash, (void**)&fn) == SUCCESS) {
+ *fe = apc_copy_function_for_execution(fn->function, &ctxt TSRMLS_CC);
+ status = zend_hash_add(EG(function_table),
+ fn->name,
+ fn->name_len+1,
+ *fe,
+ sizeof(zend_function),
+ NULL);
+ }
+
+ return status;
+}
+/* }}} */
+
+/* {{{ install_class */
+static int install_class(apc_class_t cl, apc_context_t* ctxt, int lazy TSRMLS_DC)
+{
+ zend_class_entry* class_entry = cl.class_entry;
+ zend_class_entry* parent = NULL;
+ int status;
+ zend_class_entry** allocated_ce = NULL;
+
+ /* Special case for mangled names. Mangled names are unique to a file.
+ * There is no way two classes with the same mangled name will occur,
+ * unless a file is included twice. And if in case, a file is included
+ * twice, all mangled name conflicts can be ignored and the class redeclaration
+ * error may be deferred till runtime of the corresponding DECLARE_CLASS
+ * calls.
+ */
+
+ if(cl.name_len != 0 && cl.name[0] == '\0') {
+ if(zend_hash_exists(CG(class_table), cl.name, cl.name_len+1)) {
+ return SUCCESS;
+ }
+ }
+
+ if(lazy && cl.name_len != 0 && cl.name[0] != '\0') {
+ status = zend_hash_add(APCG(lazy_class_table),
+ cl.name,
+ cl.name_len+1,
+ &cl,
+ sizeof(apc_class_t),
+ NULL);
+ if(status == FAILURE) {
+ zend_error(E_ERROR, "Cannot redeclare class %s", cl.name);
+ }
+ return status;
+ }
+
+ /*
+ * XXX: We need to free this somewhere...
+ */
+ allocated_ce = apc_php_malloc(sizeof(zend_class_entry*) TSRMLS_CC);
+
+ if(!allocated_ce) {
+ return FAILURE;
+ }
+
+ *allocated_ce =
+ class_entry =
+ apc_copy_class_entry_for_execution(cl.class_entry, ctxt TSRMLS_CC);
+
+
+ /* restore parent class pointer for compile-time inheritance */
+ if (cl.parent_name != NULL) {
+ zend_class_entry** parent_ptr = NULL;
+ /*
+ * __autoload brings in the old issues with mixed inheritance.
+ * When a statically inherited class triggers autoload, it runs
+ * afoul of a potential require_once "parent.php" in the previous
+ * line, which when executed provides the parent class, but right
+ * now goes and hits __autoload which could fail.
+ *
+ * missing parent == re-compile.
+ *
+ * whether __autoload is enabled or not, because __autoload errors
+ * cause php to die.
+ *
+ * Aside: Do NOT pass *strlen(cl.parent_name)+1* because
+ * zend_lookup_class_ex does it internally anyway!
+ */
+ status = zend_lookup_class_ex(cl.parent_name,
+ strlen(cl.parent_name),
+#ifdef ZEND_ENGINE_2_4
+ NULL,
+#endif
+ 0,
+ &parent_ptr TSRMLS_CC);
+ if (status == FAILURE) {
+ if(APCG(report_autofilter)) {
+ apc_warning("Dynamic inheritance detected for class %s" TSRMLS_CC, cl.name);
+ }
+ class_entry->parent = NULL;
+ return status;
+ }
+ else {
+ parent = *parent_ptr;
+ class_entry->parent = parent;
+ zend_do_inheritance(class_entry, parent TSRMLS_CC);
+ }
+
+
+ }
+
+ status = zend_hash_add(EG(class_table),
+ cl.name,
+ cl.name_len+1,
+ allocated_ce,
+ sizeof(zend_class_entry*),
+ NULL);
+
+ if (status == FAILURE) {
+ apc_error("Cannot redeclare class %s" TSRMLS_CC, cl.name);
+ }
+ return status;
+}
+/* }}} */
+
+/* {{{ apc_lookup_class_hook */
+int apc_lookup_class_hook(char *name, int len, ulong hash, zend_class_entry ***ce) {
+
+ apc_class_t *cl;
+ apc_context_t ctxt = {0,};
+ TSRMLS_FETCH();
+
+ if(zend_is_compiling(TSRMLS_C)) { return FAILURE; }
+
+ if(zend_hash_quick_find(APCG(lazy_class_table), name, len, hash, (void**)&cl) == FAILURE) {
+ return FAILURE;
+ }
+
+ ctxt.pool = apc_pool_create(APC_UNPOOL, apc_php_malloc, apc_php_free, apc_sma_protect, apc_sma_unprotect TSRMLS_CC);
+ ctxt.copy = APC_COPY_OUT_OPCODE;
+
+ if(install_class(*cl, &ctxt, 0 TSRMLS_CC) == FAILURE) {
+ apc_warning("apc_lookup_class_hook: could not install %s" TSRMLS_CC, name);
+ return FAILURE;
+ }
+
+ if(zend_hash_quick_find(EG(class_table), name, len, hash, (void**)ce) == FAILURE) {
+ apc_warning("apc_lookup_class_hook: known error trying to fetch class %s" TSRMLS_CC, name);
+ return FAILURE;
+ }
+
+ return SUCCESS;
+
+}
+/* }}} */
+
+/* {{{ uninstall_class */
+static int uninstall_class(apc_class_t cl TSRMLS_DC)
+{
+ int status;
+
+ status = zend_hash_del(EG(class_table),
+ cl.name,
+ cl.name_len+1);
+ if (status == FAILURE) {
+ apc_error("Cannot delete class %s" TSRMLS_CC, cl.name);
+ }
+ return status;
+}
+/* }}} */
+
+/* {{{ copy_function_name (taken from zend_builtin_functions.c to ensure future compatibility with APC) */
+static int copy_function_name(apc_function_t *pf TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
+{
+ zval *internal_ar = va_arg(args, zval *),
+ *user_ar = va_arg(args, zval *);
+ zend_function *func = pf->function;
+
+ if (hash_key->nKeyLength == 0 || hash_key->arKey[0] == 0) {
+ return 0;
+ }
+
+ if (func->type == ZEND_INTERNAL_FUNCTION) {
+ add_next_index_stringl(internal_ar, hash_key->arKey, hash_key->nKeyLength-1, 1);
+ } else if (func->type == ZEND_USER_FUNCTION) {
+ add_next_index_stringl(user_ar, hash_key->arKey, hash_key->nKeyLength-1, 1);
+ }
+
+ return 0;
+}
+
+/* {{{ copy_class_or_interface_name (taken from zend_builtin_functions.c to ensure future compatibility with APC) */
+static int copy_class_or_interface_name(apc_class_t *cl TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
+{
+ zval *array = va_arg(args, zval *);
+ zend_uint mask = va_arg(args, zend_uint);
+ zend_uint comply = va_arg(args, zend_uint);
+ zend_uint comply_mask = (comply)? mask:0;
+ zend_class_entry *ce = cl->class_entry;
+
+ if ((hash_key->nKeyLength==0 || hash_key->arKey[0]!=0)
+ && (comply_mask == (ce->ce_flags & mask))) {
+ add_next_index_stringl(array, ce->name, ce->name_length, 1);
+ }
+ return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+
+/* }}} */
+
+/* {{{ apc_defined_function_hook */
+int apc_defined_function_hook(zval *internal, zval *user) {
+ TSRMLS_FETCH();
+ zend_hash_apply_with_arguments(APCG(lazy_function_table)
+#ifdef ZEND_ENGINE_2_3
+ TSRMLS_CC
+#endif
+ ,(apply_func_args_t) copy_function_name, 2, internal, user);
+ return 1;
+}
+/* }}} */
+
+/* {{{ apc_declared_class_hook */
+int apc_declared_class_hook(zval *classes, zend_uint mask, zend_uint comply) {
+ TSRMLS_FETCH();
+ zend_hash_apply_with_arguments(APCG(lazy_class_table)
+#ifdef ZEND_ENGINE_2_3
+ TSRMLS_CC
+#endif
+ , (apply_func_args_t) copy_class_or_interface_name, 3, classes, mask, comply);
+ return 1;
+}
+/* }}} */
+
+/* {{{ cached_compile */
+static zend_op_array* cached_compile(zend_file_handle* h,
+ int type,
+ apc_context_t* ctxt TSRMLS_DC)
+{
+ apc_cache_entry_t* cache_entry;
+ int i, ii;
+
+ cache_entry = (apc_cache_entry_t*) apc_stack_top(APCG(cache_stack));
+ assert(cache_entry != NULL);
+
+ if (cache_entry->data.file.classes) {
+ int lazy_classes = APCG(lazy_classes);
+ for (i = 0; cache_entry->data.file.classes[i].class_entry != NULL; i++) {
+ if(install_class(cache_entry->data.file.classes[i], ctxt, lazy_classes TSRMLS_CC) == FAILURE) {
+ goto default_compile;
+ }
+ }
+ }
+
+ if (cache_entry->data.file.functions) {
+ int lazy_functions = APCG(lazy_functions);
+ for (i = 0; cache_entry->data.file.functions[i].function != NULL; i++) {
+ install_function(cache_entry->data.file.functions[i], ctxt, lazy_functions TSRMLS_CC);
+ }
+ }
+
+ apc_do_halt_compiler_register(cache_entry->data.file.filename, cache_entry->data.file.halt_offset TSRMLS_CC);
+
+
+ return apc_copy_op_array_for_execution(NULL, cache_entry->data.file.op_array, ctxt TSRMLS_CC);
+
+default_compile:
+
+ if(cache_entry->data.file.classes) {
+ for(ii = 0; ii < i ; ii++) {
+ uninstall_class(cache_entry->data.file.classes[ii] TSRMLS_CC);
+ }
+ }
+
+ apc_stack_pop(APCG(cache_stack)); /* pop out cache_entry */
+
+ apc_cache_release(apc_cache, cache_entry TSRMLS_CC);
+
+ /* cannot free up cache data yet, it maybe in use */
+
+ return NULL;
+}
+/* }}} */
+
+/* {{{ apc_compile_cache_entry */
+zend_bool apc_compile_cache_entry(apc_cache_key_t key, zend_file_handle* h, int type, time_t t, zend_op_array** op_array, apc_cache_entry_t** cache_entry TSRMLS_DC) {
+ int num_functions, num_classes;
+ apc_function_t* alloc_functions;
+ zend_op_array* alloc_op_array;
+ apc_class_t* alloc_classes;
+ char *path;
+ apc_context_t ctxt;
+
+ /* remember how many functions and classes existed before compilation */
+ num_functions = zend_hash_num_elements(CG(function_table));
+ num_classes = zend_hash_num_elements(CG(class_table));
+
+ /* compile the file using the default compile function, *
+ * we set *op_array here so we return opcodes during *
+ * a failure. We should not return prior to this line. */
+ *op_array = old_compile_file(h, type TSRMLS_CC);
+ if (*op_array == NULL) {
+ return FAILURE;
+ }
+
+ ctxt.pool = apc_pool_create(APC_MEDIUM_POOL, apc_sma_malloc, apc_sma_free,
+ apc_sma_protect, apc_sma_unprotect TSRMLS_CC);
+ if (!ctxt.pool) {
+ apc_warning("Unable to allocate memory for pool." TSRMLS_CC);
+ return FAILURE;
+ }
+ ctxt.copy = APC_COPY_IN_OPCODE;
+
+ if(APCG(file_md5)) {
+ int n;
+ unsigned char buf[1024];
+ PHP_MD5_CTX context;
+ php_stream *stream;
+ char *filename;
+
+ if(h->opened_path) {
+ filename = h->opened_path;
+ } else {
+ filename = h->filename;
+ }
+ stream = php_stream_open_wrapper(filename, "rb", REPORT_ERRORS | ENFORCE_SAFE_MODE, NULL);
+ if(stream) {
+ PHP_MD5Init(&context);
+ while((n = php_stream_read(stream, (char*)buf, sizeof(buf))) > 0) {
+ PHP_MD5Update(&context, buf, n);
+ }
+ PHP_MD5Final(key.md5, &context);
+ php_stream_close(stream);
+ if(n<0) {
+ apc_warning("Error while reading '%s' for md5 generation." TSRMLS_CC, filename);
+ }
+ } else {
+ apc_warning("Unable to open '%s' for md5 generation." TSRMLS_CC, filename);
+ }
+ }
+
+ if(!(alloc_op_array = apc_copy_op_array(NULL, *op_array, &ctxt TSRMLS_CC))) {
+ goto freepool;
+ }
+
+ if(!(alloc_functions = apc_copy_new_functions(num_functions, &ctxt TSRMLS_CC))) {
+ goto freepool;
+ }
+ if(!(alloc_classes = apc_copy_new_classes(*op_array, num_classes, &ctxt TSRMLS_CC))) {
+ goto freepool;
+ }
+
+ path = h->opened_path;
+ if(!path && key.type == APC_CACHE_KEY_FPFILE) path = (char*)key.data.fpfile.fullpath;
+ if(!path) path=h->filename;
+
+ apc_debug("2. h->opened_path=[%s] h->filename=[%s]\n" TSRMLS_CC, h->opened_path?h->opened_path:"null",h->filename);
+
+ if(!(*cache_entry = apc_cache_make_file_entry(path, alloc_op_array, alloc_functions, alloc_classes, &ctxt TSRMLS_CC))) {
+ goto freepool;
+ }
+
+ return SUCCESS;
+
+freepool:
+ apc_pool_destroy(ctxt.pool TSRMLS_CC);
+ ctxt.pool = NULL;
+
+ return FAILURE;
+
+}
+/* }}} */
+
+/* {{{ my_compile_file
+ Overrides zend_compile_file */
+static zend_op_array* my_compile_file(zend_file_handle* h,
+ int type TSRMLS_DC)
+{
+ apc_cache_key_t key;
+ apc_cache_entry_t* cache_entry;
+ zend_op_array* op_array = NULL;
+ time_t t;
+ apc_context_t ctxt = {0,};
+ int bailout=0;
+ const char* filename = NULL;
+
+ if (!APCG(enabled) || apc_cache_busy(apc_cache)) {
+ return old_compile_file(h, type TSRMLS_CC);
+ }
+
+ if(h->opened_path) {
+ filename = h->opened_path;
+ } else {
+ filename = h->filename;
+ }
+
+ /* check our regular expression filters */
+ if (APCG(filters) && APCG(compiled_filters) && filename) {
+ int ret = apc_regex_match_array(APCG(compiled_filters), filename);
+
+ if(ret == APC_NEGATIVE_MATCH || (ret != APC_POSITIVE_MATCH && !APCG(cache_by_default))) {
+ return old_compile_file(h, type TSRMLS_CC);
+ }
+ } else if(!APCG(cache_by_default)) {
+ return old_compile_file(h, type TSRMLS_CC);
+ }
+ APCG(current_cache) = apc_cache;
+
+
+ t = apc_time();
+
+ apc_debug("1. h->opened_path=[%s] h->filename=[%s]\n" TSRMLS_CC, h->opened_path?h->opened_path:"null",h->filename);
+
+ /* try to create a cache key; if we fail, give up on caching */
+ if (!apc_cache_make_file_key(&key, h->filename, PG(include_path), t TSRMLS_CC)) {
+ return old_compile_file(h, type TSRMLS_CC);
+ }
+
+ if(!APCG(force_file_update)) {
+ /* search for the file in the cache */
+ cache_entry = apc_cache_find(apc_cache, key, t TSRMLS_CC);
+ ctxt.force_update = 0;
+ } else {
+ cache_entry = NULL;
+ ctxt.force_update = 1;
+ }
+
+ if (cache_entry != NULL) {
+ int dummy = 1;
+
+ ctxt.pool = apc_pool_create(APC_UNPOOL, apc_php_malloc, apc_php_free,
+ apc_sma_protect, apc_sma_unprotect TSRMLS_CC);
+ if (!ctxt.pool) {
+ apc_warning("Unable to allocate memory for pool." TSRMLS_CC);
+ return old_compile_file(h, type TSRMLS_CC);
+ }
+ ctxt.copy = APC_COPY_OUT_OPCODE;
+
+ zend_hash_add(&EG(included_files), cache_entry->data.file.filename,
+ strlen(cache_entry->data.file.filename)+1,
+ (void *)&dummy, sizeof(int), NULL);
+
+ apc_stack_push(APCG(cache_stack), cache_entry TSRMLS_CC);
+ op_array = cached_compile(h, type, &ctxt TSRMLS_CC);
+
+ if(op_array) {
+#ifdef APC_FILEHITS
+ /* If the file comes from the cache, add it to the global request file list */
+ add_next_index_string(APCG(filehits), h->filename, 1);
+#endif
+ /* this is an unpool, which has no cleanup - this only free's the pool header */
+ apc_pool_destroy(ctxt.pool TSRMLS_CC);
+
+ /* We might leak fds without this hack */
+ if (h->type != ZEND_HANDLE_FILENAME) {
+ zend_llist_add_element(&CG(open_files), h);
+ }
+ return op_array;
+ }
+ if(APCG(report_autofilter)) {
+ apc_warning("Autofiltering %s" TSRMLS_CC,
+ (h->opened_path ? h->opened_path : h->filename));
+ apc_warning("Recompiling %s" TSRMLS_CC, cache_entry->data.file.filename);
+ }
+ /* TODO: check what happens with EG(included_files) */
+ }
+
+ /* Make sure the mtime reflects the files last known mtime, and we respect max_file_size in the case of fpstat==0 */
+ if(key.type == APC_CACHE_KEY_FPFILE) {
+ apc_fileinfo_t fileinfo;
+ struct stat *tmp_buf = NULL;
+ if(!strcmp(SG(request_info).path_translated, h->filename)) {
+ tmp_buf = sapi_get_stat(TSRMLS_C); /* Apache has already done this stat() for us */
+ }
+ if(tmp_buf) {
+ fileinfo.st_buf.sb = *tmp_buf;
+ } else {
+ if (apc_search_paths(h->filename, PG(include_path), &fileinfo TSRMLS_CC) != 0) {
+ apc_debug("Stat failed %s - bailing (%s) (%d)\n" TSRMLS_CC,h->filename,SG(request_info).path_translated);
+ return old_compile_file(h, type TSRMLS_CC);
+ }
+ }
+ if (APCG(max_file_size) < fileinfo.st_buf.sb.st_size) {
+ apc_debug("File is too big %s (%ld) - bailing\n" TSRMLS_CC, h->filename, fileinfo.st_buf.sb.st_size);
+ return old_compile_file(h, type TSRMLS_CC);
+ }
+ key.mtime = fileinfo.st_buf.sb.st_mtime;
+ }
+
+ HANDLE_BLOCK_INTERRUPTIONS();
+
+#if NONBLOCKING_LOCK_AVAILABLE
+ if(APCG(write_lock)) {
+ if(!apc_cache_write_lock(apc_cache TSRMLS_CC)) {
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ return old_compile_file(h, type TSRMLS_CC);
+ }
+ }
+#endif
+
+ zend_try {
+ if (apc_compile_cache_entry(key, h, type, t, &op_array, &cache_entry TSRMLS_CC) == SUCCESS) {
+ ctxt.pool = cache_entry->pool;
+ ctxt.copy = APC_COPY_IN_OPCODE;
+ if (apc_cache_insert(apc_cache, key, cache_entry, &ctxt, t TSRMLS_CC) != 1) {
+ apc_pool_destroy(ctxt.pool TSRMLS_CC);
+ ctxt.pool = NULL;
+ }
+ }
+ } zend_catch {
+ bailout=1; /* in the event of a bailout, ensure we don't create a dead-lock */
+ } zend_end_try();
+
+ APCG(current_cache) = NULL;
+
+#if NONBLOCKING_LOCK_AVAILABLE
+ if(APCG(write_lock)) {
+ apc_cache_write_unlock(apc_cache TSRMLS_CC);
+ }
+#endif
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+
+ if (bailout) zend_bailout();
+
+ return op_array;
+}
+/* }}} */
+
+/* {{{ data preload */
+
+extern int _apc_store(char *strkey, int strkey_len, const zval *val, const unsigned int ttl, const int exclusive TSRMLS_DC);
+
+static zval* data_unserialize(const char *filename TSRMLS_DC)
+{
+ zval* retval;
+ long len = 0;
+ struct stat sb;
+ char *contents, *tmp;
+ FILE *fp;
+ php_unserialize_data_t var_hash;
+
+ if(VCWD_STAT(filename, &sb) == -1) {
+ return NULL;
+ }
+
+ fp = fopen(filename, "rb");
+
+ len = sizeof(char)*sb.st_size;
+
+ tmp = contents = malloc(len);
+
+ if(!contents) {
+ return NULL;
+ }
+
+ if(fread(contents, 1, len, fp) < 1) {
+ free(contents);
+ return NULL;
+ }
+
+ MAKE_STD_ZVAL(retval);
+
+ PHP_VAR_UNSERIALIZE_INIT(var_hash);
+
+ /* I wish I could use json */
+ if(!php_var_unserialize(&retval, (const unsigned char**)&tmp, (const unsigned char*)(contents+len), &var_hash TSRMLS_CC)) {
+ zval_ptr_dtor(&retval);
+ return NULL;
+ }
+
+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
+
+ free(contents);
+ fclose(fp);
+
+ return retval;
+}
+
+static int apc_load_data(const char *data_file TSRMLS_DC)
+{
+ char *p;
+ char key[MAXPATHLEN] = {0,};
+ unsigned int key_len;
+ zval *data;
+
+ p = strrchr(data_file, DEFAULT_SLASH);
+
+ if(p && p[1]) {
+ strlcpy(key, p+1, sizeof(key));
+ p = strrchr(key, '.');
+
+ if(p) {
+ p[0] = '\0';
+ key_len = strlen(key);
+
+ data = data_unserialize(data_file TSRMLS_CC);
+ if(data) {
+ _apc_store(key, key_len, data, 0, 1 TSRMLS_CC);
+ }
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int apc_walk_dir(const char *path TSRMLS_DC)
+{
+ char file[MAXPATHLEN]={0,};
+ int ndir, i;
+ char *p = NULL;
+ struct dirent **namelist = NULL;
+
+ if ((ndir = php_scandir(path, &namelist, 0, php_alphasort)) > 0)
+ {
+ for (i = 0; i < ndir; i++)
+ {
+ /* check for extension */
+ if (!(p = strrchr(namelist[i]->d_name, '.'))
+ || (p && strcmp(p, ".data")))
+ {
+ free(namelist[i]);
+ continue;
+ }
+ snprintf(file, MAXPATHLEN, "%s%c%s",
+ path, DEFAULT_SLASH, namelist[i]->d_name);
+ if(!apc_load_data(file TSRMLS_CC))
+ {
+ /* print error */
+ }
+ free(namelist[i]);
+ }
+ free(namelist);
+ }
+
+ return 1;
+}
+
+void apc_data_preload(TSRMLS_D)
+{
+ if(!APCG(preload_path)) return;
+
+ apc_walk_dir(APCG(preload_path) TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ apc_serializer hooks */
+static int _apc_register_serializer(const char* name, apc_serialize_t serialize,
+ apc_unserialize_t unserialize,
+ void *config TSRMLS_DC)
+{
+ int i;
+ apc_serializer_t *serializer;
+
+ for(i = 0; i < APC_MAX_SERIALIZERS; i++) {
+ serializer = &apc_serializers[i];
+ if(!serializer->name) {
+ /* empty entry */
+ serializer->name = name; /* assumed to be const */
+ serializer->serialize = serialize;
+ serializer->unserialize = unserialize;
+ serializer->config = config;
+ apc_serializers[i+1].name = NULL;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+apc_serializer_t* apc_find_serializer(const char* name TSRMLS_DC)
+{
+ int i;
+ apc_serializer_t *serializer;
+
+ for(i = 0; i < APC_MAX_SERIALIZERS; i++) {
+ serializer = &apc_serializers[i];
+ if(serializer->name && (strcmp(serializer->name, name) == 0)) {
+ return serializer;
+ }
+ }
+ return NULL;
+}
+
+apc_serializer_t* apc_get_serializers(TSRMLS_D)
+{
+ return &(apc_serializers[0]);
+}
+/* }}} */
+
+/* {{{ module init and shutdown */
+
+int apc_module_init(int module_number TSRMLS_DC)
+{
+ /* apc initialization */
+#if APC_MMAP
+ apc_sma_init(APCG(shm_segments), APCG(shm_size), APCG(mmap_file_mask) TSRMLS_CC);
+#else
+ apc_sma_init(APCG(shm_segments), APCG(shm_size), NULL TSRMLS_CC);
+#endif
+ apc_cache = apc_cache_create(APCG(num_files_hint), APCG(gc_ttl), APCG(ttl) TSRMLS_CC);
+ apc_user_cache = apc_cache_create(APCG(user_entries_hint), APCG(gc_ttl), APCG(user_ttl) TSRMLS_CC);
+
+ /* override compilation */
+ old_compile_file = zend_compile_file;
+ zend_compile_file = my_compile_file;
+ REGISTER_LONG_CONSTANT("\000apc_magic", (long)&set_compile_hook, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("\000apc_compile_file", (long)&my_compile_file, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT(APC_SERIALIZER_CONSTANT, (long)&_apc_register_serializer, CONST_PERSISTENT | CONST_CS);
+
+ /* test out the constant function pointer */
+ apc_register_serializer("php", APC_SERIALIZER_NAME(php), APC_UNSERIALIZER_NAME(php), NULL TSRMLS_CC);
+
+ assert(apc_serializers[0].name != NULL);
+
+ apc_pool_init();
+
+ apc_data_preload(TSRMLS_C);
+
+#if APC_HAVE_LOOKUP_HOOKS
+ if(APCG(lazy_functions)) {
+ zend_set_lookup_function_hook(apc_lookup_function_hook TSRMLS_CC);
+ zend_set_defined_function_hook(apc_defined_function_hook TSRMLS_CC);
+ }
+ if(APCG(lazy_classes)) {
+ zend_set_lookup_class_hook(apc_lookup_class_hook TSRMLS_CC);
+ zend_set_declared_class_hook(apc_declared_class_hook TSRMLS_CC);
+ }
+#else
+ if(APCG(lazy_functions) || APCG(lazy_classes)) {
+ apc_warning("Lazy function/class loading not available with this version of PHP, please disable APC lazy loading." TSRMLS_CC);
+ APCG(lazy_functions) = APCG(lazy_classes) = 0;
+ }
+#endif
+
+#ifdef ZEND_ENGINE_2_4
+ apc_interned_strings_init(TSRMLS_C);
+#endif
+
+ APCG(initialized) = 1;
+ return 0;
+}
+
+int apc_module_shutdown(TSRMLS_D)
+{
+ if (!APCG(initialized))
+ return 0;
+
+ /* restore compilation */
+ zend_compile_file = old_compile_file;
+
+ /*
+ * In case we got interrupted by a SIGTERM or something else during execution
+ * we may have cache entries left on the stack that we need to check to make
+ * sure that any functions or classes these may have added to the global function
+ * and class tables are removed before we blow away the memory that hold them.
+ *
+ * This is merely to remove memory leak warnings - as the process is terminated
+ * immediately after shutdown. The following while loop can be removed without
+ * affecting anything else.
+ */
+ while (apc_stack_size(APCG(cache_stack)) > 0) {
+ int i;
+ apc_cache_entry_t* cache_entry = (apc_cache_entry_t*) apc_stack_pop(APCG(cache_stack));
+ if (cache_entry->data.file.functions) {
+ for (i = 0; cache_entry->data.file.functions[i].function != NULL; i++) {
+ zend_hash_del(EG(function_table),
+ cache_entry->data.file.functions[i].name,
+ cache_entry->data.file.functions[i].name_len+1);
+ }
+ }
+ if (cache_entry->data.file.classes) {
+ for (i = 0; cache_entry->data.file.classes[i].class_entry != NULL; i++) {
+ zend_hash_del(EG(class_table),
+ cache_entry->data.file.classes[i].name,
+ cache_entry->data.file.classes[i].name_len+1);
+ }
+ }
+ apc_cache_release(apc_cache, cache_entry TSRMLS_CC);
+ }
+
+ apc_cache_destroy(apc_cache TSRMLS_CC);
+ apc_cache_destroy(apc_user_cache TSRMLS_CC);
+ apc_sma_cleanup(TSRMLS_C);
+
+#ifdef ZEND_ENGINE_2_4
+ apc_interned_strings_shutdown(TSRMLS_C);
+#endif
+
+ APCG(initialized) = 0;
+ return 0;
+}
+
+/* }}} */
+
+/* {{{ process init and shutdown */
+int apc_process_init(int module_number TSRMLS_DC)
+{
+ return 0;
+}
+
+int apc_process_shutdown(TSRMLS_D)
+{
+ return 0;
+}
+/* }}} */
+
+
+/* {{{ apc_deactivate */
+static void apc_deactivate(TSRMLS_D)
+{
+ /* The execution stack was unwound, which prevented us from decrementing
+ * the reference counts on active cache entries in `my_execute`.
+ */
+ while (apc_stack_size(APCG(cache_stack)) > 0) {
+ int i;
+ zend_class_entry* zce = NULL;
+ void ** centry = (void*)(&zce);
+ zend_class_entry** pzce = NULL;
+
+ apc_cache_entry_t* cache_entry =
+ (apc_cache_entry_t*) apc_stack_pop(APCG(cache_stack));
+
+ if (cache_entry->data.file.classes) {
+ for (i = 0; cache_entry->data.file.classes[i].class_entry != NULL; i++) {
+ centry = (void**)&pzce; /* a triple indirection to get zend_class_entry*** */
+ if(zend_hash_find(EG(class_table),
+ cache_entry->data.file.classes[i].name,
+ cache_entry->data.file.classes[i].name_len+1,
+ (void**)centry) == FAILURE)
+ {
+ /* double inclusion of conditional classes ends up failing
+ * this lookup the second time around.
+ */
+ continue;
+ }
+
+ zce = *pzce;
+
+ zend_hash_del(EG(class_table),
+ cache_entry->data.file.classes[i].name,
+ cache_entry->data.file.classes[i].name_len+1);
+
+ apc_free_class_entry_after_execution(zce TSRMLS_CC);
+ }
+ }
+ apc_cache_release(apc_cache, cache_entry TSRMLS_CC);
+ }
+}
+/* }}} */
+
+/* {{{ request init and shutdown */
+
+int apc_request_init(TSRMLS_D)
+{
+ apc_stack_clear(APCG(cache_stack));
+ if (!APCG(compiled_filters) && APCG(filters)) {
+ /* compile regex filters here to avoid race condition between MINIT of PCRE and APC.
+ * This should be moved to apc_cache_create() if this race condition between modules is resolved */
+ APCG(compiled_filters) = apc_regex_compile_array(APCG(filters) TSRMLS_CC);
+ }
+
+ if (!APCG(serializer) && APCG(serializer_name)) {
+ /* Avoid race conditions between MINIT of apc and serializer exts like igbinary */
+ APCG(serializer) = apc_find_serializer(APCG(serializer_name) TSRMLS_CC);
+ }
+
+#if APC_HAVE_LOOKUP_HOOKS
+ if(APCG(lazy_functions)) {
+ APCG(lazy_function_table) = emalloc(sizeof(HashTable));
+ zend_hash_init(APCG(lazy_function_table), 0, NULL, NULL, 0);
+ }
+ if(APCG(lazy_classes)) {
+ APCG(lazy_class_table) = emalloc(sizeof(HashTable));
+ zend_hash_init(APCG(lazy_class_table), 0, NULL, NULL, 0);
+ }
+#endif
+
+#ifdef APC_FILEHITS
+ ALLOC_INIT_ZVAL(APCG(filehits));
+ array_init(APCG(filehits));
+#endif
+
+ return 0;
+}
+
+int apc_request_shutdown(TSRMLS_D)
+{
+#if APC_HAVE_LOOKUP_HOOKS
+ if(APCG(lazy_class_table)) {
+ zend_hash_destroy(APCG(lazy_class_table));
+ efree(APCG(lazy_class_table));
+ }
+ if(APCG(lazy_function_table)) {
+ zend_hash_destroy(APCG(lazy_function_table));
+ efree(APCG(lazy_function_table));
+ }
+#endif
+
+ apc_deactivate(TSRMLS_C);
+
+#ifdef APC_FILEHITS
+ zval_ptr_dtor(&APCG(filehits));
+#endif
+ return 0;
+}
+
+/* }}} */
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker
+ * vim<600: expandtab sw=4 ts=4 sts=4
+ */
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_main.h
^
|
(renamed from APC-3.1.8/apc_main.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_main.h
^
|
(renamed from APC-3.1.8/apc_main.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_mmap.c
^
|
(renamed from APC-3.1.8/apc_mmap.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_mmap.c
^
|
(renamed from APC-3.1.8/apc_mmap.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_mmap.h
^
|
(renamed from APC-3.1.8/apc_mmap.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_mmap.h
^
|
(renamed from APC-3.1.8/apc_mmap.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_php.h
^
|
(renamed from APC-3.1.8/apc_php.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_php.h
^
|
(renamed from APC-3.1.8/apc_php.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_php_pcre.h
^
|
(renamed from APC-3.1.8/apc_php_pcre.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_php_pcre.h
^
|
(renamed from APC-3.1.8/apc_php_pcre.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_pool.c
^
|
(renamed from APC-3.1.8/apc_pool.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_pool.c
^
|
(renamed from APC-3.1.8/apc_pool.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_pool.h
^
|
(renamed from APC-3.1.8/apc_pool.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_pool.h
^
|
(renamed from APC-3.1.8/apc_pool.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_pthreadmutex.c
^
|
(renamed from APC-3.1.8/apc_pthreadmutex.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_pthreadmutex.c
^
|
(renamed from APC-3.1.8/apc_pthreadmutex.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_pthreadmutex.h
^
|
(renamed from APC-3.1.8/apc_pthreadmutex.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_pthreadmutex.h
^
|
(renamed from APC-3.1.8/apc_pthreadmutex.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_pthreadrwlock.c
^
|
(renamed from APC-3.1.8/apc_pthreadrwlock.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_pthreadrwlock.c
^
|
(renamed from APC-3.1.8/apc_pthreadrwlock.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_pthreadrwlock.h
^
|
(renamed from APC-3.1.8/apc_pthreadrwlock.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_pthreadrwlock.h
^
|
(renamed from APC-3.1.8/apc_pthreadrwlock.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_rfc1867.c
^
|
(renamed from APC-3.1.8/apc_rfc1867.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_rfc1867.c
^
|
(renamed from APC-3.1.8/apc_rfc1867.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_sem.c
^
|
(renamed from APC-3.1.8/apc_sem.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_sem.c
^
|
(renamed from APC-3.1.8/apc_sem.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_sem.h
^
|
(renamed from APC-3.1.8/apc_sem.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_sem.h
^
|
(renamed from APC-3.1.8/apc_sem.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_serializer.h
^
|
(renamed from APC-3.1.8/apc_serializer.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_serializer.h
^
|
(renamed from APC-3.1.8/apc_serializer.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_shm.c
^
|
(renamed from APC-3.1.8/apc_shm.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_shm.c
^
|
(renamed from APC-3.1.8/apc_shm.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_shm.h
^
|
(renamed from APC-3.1.8/apc_shm.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_shm.h
^
|
(renamed from APC-3.1.8/apc_shm.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_signal.c
^
|
(renamed from APC-3.1.8/apc_signal.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_signal.c
^
|
(renamed from APC-3.1.8/apc_signal.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_signal.h
^
|
(renamed from APC-3.1.8/apc_signal.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_signal.h
^
|
(renamed from APC-3.1.8/apc_signal.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_sma.c
^
|
(renamed from APC-3.1.8/apc_sma.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_sma.c
^
|
(renamed from APC-3.1.8/apc_sma.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_sma.h
^
|
(renamed from APC-3.1.8/apc_sma.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_sma.h
^
|
(renamed from APC-3.1.8/apc_sma.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_spin.c
^
|
(renamed from APC-3.1.8/apc_spin.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_spin.c
^
|
(renamed from APC-3.1.8/apc_spin.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_spin.h
^
|
(renamed from APC-3.1.8/apc_spin.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_spin.h
^
|
(renamed from APC-3.1.8/apc_spin.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_stack.c
^
|
(renamed from APC-3.1.8/apc_stack.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_stack.c
^
|
(renamed from APC-3.1.8/apc_stack.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_stack.h
^
|
(renamed from APC-3.1.8/apc_stack.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_stack.h
^
|
(renamed from APC-3.1.8/apc_stack.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_string.c
^
|
(renamed from APC-3.1.8/apc_string.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_string.c
^
|
(renamed from APC-3.1.8/apc_string.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_string.h
^
|
(renamed from APC-3.1.8/apc_string.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_string.h
^
|
(renamed from APC-3.1.8/apc_string.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_windows_srwlock_kernel.c
^
|
(renamed from APC-3.1.8/apc_windows_srwlock_kernel.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_windows_srwlock_kernel.c
^
|
(renamed from APC-3.1.8/apc_windows_srwlock_kernel.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_windows_srwlock_kernel.h
^
|
(renamed from APC-3.1.8/apc_windows_srwlock_kernel.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_windows_srwlock_kernel.h
^
|
(renamed from APC-3.1.8/apc_windows_srwlock_kernel.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_zend.c
^
|
(renamed from APC-3.1.8/apc_zend.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_zend.c
^
|
(renamed from APC-3.1.8/apc_zend.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_zend.h
^
|
(renamed from APC-3.1.8/apc_zend.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/apc_zend.h
^
|
(renamed from APC-3.1.8/apc_zend.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/config.m4
^
|
(renamed from APC-3.1.8/config.m4)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/config.m4
^
|
(renamed from APC-3.1.8/config.m4)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/config.w32
^
|
(renamed from APC-3.1.8/config.w32)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/config.w32
^
|
(renamed from APC-3.1.8/config.w32)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/pgsql_s_lock.c
^
|
(renamed from APC-3.1.8/pgsql_s_lock.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/pgsql_s_lock.c
^
|
(renamed from APC-3.1.8/pgsql_s_lock.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/pgsql_s_lock.h
^
|
(renamed from APC-3.1.8/pgsql_s_lock.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/pgsql_s_lock.h
^
|
(renamed from APC-3.1.8/pgsql_s_lock.h)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/php_apc.c
^
|
(renamed from APC-3.1.8/php_apc.c)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/php_apc.c
^
|
(renamed from APC-3.1.8/php_apc.c)
|
[-]
[+]
|
Added |
APC-3.1.9.tar.bz2/APC-3.1.9/php_apc.h
^
|
@@ -0,0 +1,54 @@
+/*
+ +----------------------------------------------------------------------+
+ | APC |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2006-2011 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Daniel Cowgill <dcowgill@communityconnect.com> |
+ | George Schlossnagle <george@omniti.com> |
+ | Rasmus Lerdorf <rasmus@php.net> |
+ +----------------------------------------------------------------------+
+
+ This software was contributed to PHP by Community Connect Inc. in 2002
+ and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
+ Future revisions and derivatives of this source code must acknowledge
+ Community Connect Inc. as the original contributor of this module by
+ leaving this note intact in the source code.
+
+ All other licensing and usage conditions are those of the PHP Group.
+
+ */
+
+/* $Id: php_apc.h 311026 2011-05-14 22:09:47Z pajoye $ */
+
+#ifndef PHP_APC_H
+#define PHP_APC_H
+
+#include "apc_php.h"
+#include "apc_globals.h"
+
+#define PHP_APC_VERSION "3.1.9"
+
+extern zend_module_entry apc_module_entry;
+#define apc_module_ptr &apc_module_entry
+
+#define phpext_apc_ptr apc_module_ptr
+
+#endif /* PHP_APC_H */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker
+ * vim<600: expandtab sw=4 ts=4 sts=4
+ */
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc53_001.phpt
^
|
(renamed from APC-3.1.8/tests/apc53_001.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc53_001.phpt
^
|
(renamed from APC-3.1.8/tests/apc53_001.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc53_002.phpt
^
|
(renamed from APC-3.1.8/tests/apc53_002.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc53_002.phpt
^
|
(renamed from APC-3.1.8/tests/apc53_002.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc53_003.phpt
^
|
(renamed from APC-3.1.8/tests/apc53_003.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc53_003.phpt
^
|
(renamed from APC-3.1.8/tests/apc53_003.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc53_004.phpt
^
|
(renamed from APC-3.1.8/tests/apc53_004.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc53_004.phpt
^
|
(renamed from APC-3.1.8/tests/apc53_004.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc53_005.phpt
^
|
(renamed from APC-3.1.8/tests/apc53_005.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc53_005.phpt
^
|
(renamed from APC-3.1.8/tests/apc53_005.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_001.phpt
^
|
(renamed from APC-3.1.8/tests/apc_001.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_001.phpt
^
|
(renamed from APC-3.1.8/tests/apc_001.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_002.phpt
^
|
(renamed from APC-3.1.8/tests/apc_002.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_002.phpt
^
|
(renamed from APC-3.1.8/tests/apc_002.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_003.phpt
^
|
(renamed from APC-3.1.8/tests/apc_003.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_003.phpt
^
|
(renamed from APC-3.1.8/tests/apc_003.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_003b.phpt
^
|
(renamed from APC-3.1.8/tests/apc_003b.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_003b.phpt
^
|
(renamed from APC-3.1.8/tests/apc_003b.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_004.phpt
^
|
(renamed from APC-3.1.8/tests/apc_004.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_004.phpt
^
|
(renamed from APC-3.1.8/tests/apc_004.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_005.phpt
^
|
(renamed from APC-3.1.8/tests/apc_005.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_005.phpt
^
|
(renamed from APC-3.1.8/tests/apc_005.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_006.phpt
^
|
(renamed from APC-3.1.8/tests/apc_006.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_006.phpt
^
|
(renamed from APC-3.1.8/tests/apc_006.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_007.phpt
^
|
(renamed from APC-3.1.8/tests/apc_007.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_007.phpt
^
|
(renamed from APC-3.1.8/tests/apc_007.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_008.phpt
^
|
(renamed from APC-3.1.8/tests/apc_008.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_008.phpt
^
|
(renamed from APC-3.1.8/tests/apc_008.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_009.phpt
^
|
(renamed from APC-3.1.8/tests/apc_009.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_009.phpt
^
|
(renamed from APC-3.1.8/tests/apc_009.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_010.phpt
^
|
(renamed from APC-3.1.8/tests/apc_010.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_010.phpt
^
|
(renamed from APC-3.1.8/tests/apc_010.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_bin_001.phpt
^
|
(renamed from APC-3.1.8/tests/apc_bin_001.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_bin_001.phpt
^
|
(renamed from APC-3.1.8/tests/apc_bin_001.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_bin_002-1.inc
^
|
(renamed from APC-3.1.8/tests/apc_bin_002-1.inc)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_bin_002-1.inc
^
|
(renamed from APC-3.1.8/tests/apc_bin_002-1.inc)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_bin_002-2.inc
^
|
(renamed from APC-3.1.8/tests/apc_bin_002-2.inc)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_bin_002-2.inc
^
|
(renamed from APC-3.1.8/tests/apc_bin_002-2.inc)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_bin_002.phpt
^
|
(renamed from APC-3.1.8/tests/apc_bin_002.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_bin_002.phpt
^
|
(renamed from APC-3.1.8/tests/apc_bin_002.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_001.phpt
^
|
(renamed from APC-3.1.8/tests/iterator_001.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_001.phpt
^
|
(renamed from APC-3.1.8/tests/iterator_001.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_002.phpt
^
|
(renamed from APC-3.1.8/tests/iterator_002.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_002.phpt
^
|
(renamed from APC-3.1.8/tests/iterator_002.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_003.phpt
^
|
(renamed from APC-3.1.8/tests/iterator_003.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_003.phpt
^
|
(renamed from APC-3.1.8/tests/iterator_003.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_004.phpt
^
|
(renamed from APC-3.1.8/tests/iterator_004.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_004.phpt
^
|
(renamed from APC-3.1.8/tests/iterator_004.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_005.phpt
^
|
(renamed from APC-3.1.8/tests/iterator_005.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_005.phpt
^
|
(renamed from APC-3.1.8/tests/iterator_005.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_006.phpt
^
|
(renamed from APC-3.1.8/tests/iterator_006.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_006.phpt
^
|
(renamed from APC-3.1.8/tests/iterator_006.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_007.phpt
^
|
(renamed from APC-3.1.8/tests/iterator_007.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_007.phpt
^
|
(renamed from APC-3.1.8/tests/iterator_007.phpt)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/php_5_3_ns.inc
^
|
(renamed from APC-3.1.8/tests/php_5_3_ns.inc)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/php_5_3_ns.inc
^
|
(renamed from APC-3.1.8/tests/php_5_3_ns.inc)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/skipif.inc
^
|
(renamed from APC-3.1.8/tests/skipif.inc)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/APC-3.1.9/tests/skipif.inc
^
|
(renamed from APC-3.1.8/tests/skipif.inc)
|
[-]
[+]
|
Changed |
APC-3.1.9.tar.bz2/package.xml
^
|
@@ -70,10 +70,10 @@
<email>pierre@php.net</email>
<active>yes</active>
</developer>
- <date>2011-05-03</date>
- <time>00:03:03</time>
+ <date>2011-05-14</date>
+ <time>22:14:56</time>
<version>
- <release>3.1.8</release>
+ <release>3.1.9</release>
<api>3.1.0</api>
</version>
<stability>
@@ -82,13 +82,7 @@
</stability>
<license uri="http://www.php.net/license">PHP License</license>
<notes>
-- Windows read-write locks support on Windows XP or later and Windows Win7
- or later (use php_apc-xp.dll or php_apc-win7.dll)
-- Fix variable type check in user cache update
-- Make warnings that user cannot do anything about debug messages
-- Fixed bug #21400 (Minor memory leak in MINFO)
-- Fixed bug #18890: Ensure that --enable-apc-debug=no disables debug mode.
-- Fixed bug #19459: check for expiry while looping through the iterator slots
+- Fix regression introduced in 3.1.8 (#22687)
</notes>
<contents>
<dir name="/">
@@ -131,7 +125,7 @@
<file md5sum="42a72f3101326949f86209dec05444e3" name="apc.h" role="src" />
<file md5sum="596a95143feb4d53c5dd6d77fa4cc2c4" name="apc_bin.c" role="src" />
<file md5sum="2a471d33e6073a488c58423c4afa9118" name="apc_bin.h" role="src" />
- <file md5sum="cd387b684c0f03b09a9e7c0b7085b534" name="apc_cache.c" role="src" />
+ <file md5sum="91eb8777c494ff85b0a655720d894d49" name="apc_cache.c" role="src" />
<file md5sum="67ab3e67b85e41b3ba2c22798e1f097e" name="apc_cache.h" role="src" />
<file md5sum="260bac1697f30ee2256c582b233648c6" name="apc_compile.c" role="src" />
<file md5sum="a75411f0dc7cde9257839ad688d59d72" name="apc_compile.h" role="src" />
@@ -141,7 +135,7 @@
<file md5sum="fc1133b9f93f8d756146aff47e02644c" name="apc_fcntl.h" role="src" />
<file md5sum="dfb1941a4e6782d08e72f6273032e467" name="apc_globals.h" role="src" />
<file md5sum="559af28331f80c051a7c757f897284a8" name="apc_lock.h" role="src" />
- <file md5sum="7d798e83f2bef2e1759035f79a167d78" name="apc_main.c" role="src" />
+ <file md5sum="afd6de81f908eba39cac5befd539a578" name="apc_main.c" role="src" />
<file md5sum="fbe1d110e5c3e53144617291d279705f" name="apc_main.h" role="src" />
<file md5sum="7a8be65b98fb812e88d3e58b81787ef6" name="apc_mmap.c" role="src" />
<file md5sum="e6ce0f97275d5b248427c43b5e57612b" name="apc_mmap.h" role="src" />
@@ -176,7 +170,7 @@
<file md5sum="4cbe31c6d02a132e2bd39295b60bd76b" name="config.m4" role="src" />
<file md5sum="ce19b60cb46446fd14a1e7bd610affab" name="config.w32" role="src" />
<file md5sum="36ecc3629dea331619d0567a9fa46d5a" name="php_apc.c" role="src" />
- <file md5sum="2a7a1ac773a86e633ea16b88857c3c58" name="php_apc.h" role="src" />
+ <file md5sum="05ee2b43d64b97cf0cfc070ecc352d71" name="php_apc.h" role="src" />
<file md5sum="c0df9bd11d18a5b45a5e45458702def4" name="pgsql_s_lock.c" role="src" />
<file md5sum="b60f9504f82c958966c885fadc97fd15" name="pgsql_s_lock.h" role="src" />
<file md5sum="bbc2c54389717c4519befa7fbd68f5f2" name="apc_fcntl_win32.c" role="src" />
@@ -206,6 +200,27 @@
</extsrcrelease>
<changelog>
<release>
+ <date>2011-05-03</date>
+ <version>
+ <release>3.1.8</release>
+ <api>3.1.0</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <license uri="http://www.php.net/license">PHP License</license>
+ <notes>
+- Windows read-write locks support on Windows XP or later and Windows Win7
+ or later (use php_apc-xp.dll or php_apc-win7.dll)
+- Fix variable type check in user cache update
+- Make warnings that user cannot do anything about debug messages
+- Fixed bug #21400 (Minor memory leak in MINFO)
+- Fixed bug #18890: Ensure that --enable-apc-debug=no disables debug mode.
+- Fixed bug #19459: check for expiry while looping through the iterator slots
+ </notes>
+ </release>
+ <release>
<date>2011-01-11</date>
<version>
<release>3.1.7</release>
|