Exemple #1
0
/* {{{ apc_cache_real_expunge */
PHP_APCU_API void apc_cache_real_expunge(apc_cache_t* cache) {
	/* increment counter */	
	cache->header->nexpunges++;
    
	/* expunge */
    {
		zend_ulong i;

		for (i = 0; i < cache->nslots; i++) {
			apc_cache_slot_t* p = cache->slots[i];
			while (p) {
				apc_cache_remove_slot(cache, &p);
			}
			cache->slots[i] = NULL;
		}
	}
	
	/* set new time so counters make sense */
	cache->header->stime = apc_time();

	/* reset counters */
	cache->header->ninserts = 0;
	cache->header->nentries = 0;
    cache->header->nhits = 0;
    cache->header->nmisses = 0;
	
	/* resets lastkey */
	memset(&cache->header->lastkey, 0, sizeof(apc_cache_key_t));
} /* }}} */
Exemple #2
0
/* {{{ apc_cache_clear */
PHP_APCU_API void apc_cache_clear(apc_cache_t* cache)
{
	/* check there is a cache and it is not busy */
    if(!cache || apc_cache_busy(cache)) {
		return;
	}
	
	/* lock header */
	APC_LOCK(cache->header);
	
	/* set busy */
	cache->header->state |= APC_CACHE_ST_BUSY;
	
	/* expunge cache */
	apc_cache_real_expunge(cache);

	/* set info */
    cache->header->stime = apc_time();
    cache->header->nexpunges = 0;
	
	/* unset busy */
    cache->header->state &= ~APC_CACHE_ST_BUSY;
	
	/* unlock header */
	APC_UNLOCK(cache->header);
}
Exemple #3
0
/* {{{ apc_iterator_fetch_active */
static int apc_iterator_fetch_active(apc_iterator_t *iterator) {
    int count=0;
    apc_cache_slot_t **slot;
    apc_iterator_item_t *item;
    time_t t;

    t = apc_time();

    while (apc_stack_size(iterator->stack) > 0) {
        apc_iterator_item_dtor(apc_stack_pop(iterator->stack));
    }

	php_apc_try(APC_RLOCK(apc_user_cache->header), {
		while(count <= iterator->chunk_size && iterator->slot_idx < apc_user_cache->nslots) {
		    slot = &apc_user_cache->slots[iterator->slot_idx];
		    while(*slot) {
		        if (apc_iterator_check_expiry(apc_user_cache, slot, t)) {
		            if (apc_iterator_search_match(iterator, slot)) {
		                count++;
		                item = apc_iterator_item_ctor(iterator, slot);
		                if (item) {
		                    apc_stack_push(iterator->stack, item);
		                }
		            }
		        }
		        slot = &(*slot)->next;
		    }
		    iterator->slot_idx++;
		}
	}, {
Exemple #4
0
/* {{{ apc_cache_make_key */
PHP_APCU_API zend_bool apc_cache_make_key(apc_cache_key_t* key, zend_string *str)
{
    assert(key != NULL);

    if (!str) {
		return 0;
    }
	
    key->str = str;
    key->mtime = apc_time();

    return 1;
}
Exemple #5
0
/* {{{ apc_cache_defense */
PHP_APCU_API zend_bool apc_cache_defense(apc_cache_t* cache, apc_cache_key_t* key)
{
	zend_bool result = 0;

#ifdef ZTS
#	define FROM_DIFFERENT_THREAD(k) ((key->owner = TSRMLS_CACHE) != (k)->owner) 
#else
#	define FROM_DIFFERENT_THREAD(k) ((key->owner = getpid()) != (k)->owner) 
#endif

	/* only continue if slam defense is enabled */
	if (cache->defend) {

		/* for copy of locking key struct */
		apc_cache_key_t *last = &cache->header->lastkey;

		if (!last->str) {
			return 0;
		}
		
		/* check the hash and length match */
		if(ZSTR_HASH(last->str) == ZSTR_HASH(key->str) && ZSTR_LEN(last->str) == ZSTR_LEN(key->str)) {
			/* check the time ( last second considered slam ) and context */
			if(last->mtime == key->mtime && FROM_DIFFERENT_THREAD(last)) {
				/* potential cache slam */
				apc_debug(
					"Potential cache slam averted for key '%s'", key->str);
				result = 1;
			} else {
				/* sets enough information for an educated guess, but is not exact */
				last->str = key->str;
				last->mtime = apc_time();

				/* required to tell contexts apart */
#ifdef ZTS
				last->owner = TSRMLS_CACHE;	
#else
				last->owner = getpid();		
#endif	
			}
		}
	}

    return result;
}
Exemple #6
0
/* {{{ apc_cache_store */
PHP_APCU_API zend_bool apc_cache_store(apc_cache_t* cache, zend_string *strkey, const zval *val, const int32_t ttl, const zend_bool exclusive) {
    apc_cache_entry_t *entry;
    apc_cache_key_t key;
    time_t t;
    apc_context_t ctxt={0,};
    zend_bool ret = 0;

    t = apc_time();

	/* initialize a context suitable for making an insert */
    if (apc_cache_make_context(cache, &ctxt, APC_CONTEXT_SHARE, APC_SMALL_POOL, APC_COPY_IN, 0)) {

        /* initialize the key for insertion */
        if (apc_cache_make_key(&key, strkey)) {

            /* run cache defense */
            if (!apc_cache_defense(cache, &key)) {
                
                /* initialize the entry for insertion */
                if ((entry = apc_cache_make_entry(&ctxt, &key, val, ttl))) {
                
                    /* execute an insertion */
                    if (apc_cache_insert(cache, &key, entry, &ctxt, t, exclusive)) {
                        ret = 1;
                    }
                }
            }
        }

        /* in any case of failure the context should be destroyed */
        if (!ret) {
            apc_cache_destroy_context(&ctxt);
        }
    }

    return ret;
} /* }}} */
Exemple #7
0
/* {{{ apc_cache_default_expunge */
PHP_APCU_API void apc_cache_default_expunge(apc_cache_t* cache, size_t size)
{
    time_t t;
	size_t suitable = 0L;
    size_t available = 0L;

    t = apc_time();

	/* check there is a cache, and it is not busy */
    if(!cache || apc_cache_busy(cache)) {
		return;
	}
	
	/* get the lock for header */
	APC_LOCK(cache->header);

	/* update state in header */
	cache->header->state |= APC_CACHE_ST_BUSY;

	/* make suitable selection */
	suitable = (cache->smart > 0L) ? (size_t) (cache->smart * size) : (size_t) (cache->sma->size/2);

	/* gc */
    apc_cache_gc(cache);

    /* get available */
	available = cache->sma->get_avail_mem();

	/* perform expunge processing */
    if(!cache->ttl) {

		/* check it is necessary to expunge */
		if (available < suitable) {
			apc_cache_real_expunge(cache);
		}
    } else {
		apc_cache_slot_t **slot;

		/* check that expunge is necessary */
        if (available < suitable) {
			zend_ulong i;

			/* look for junk */
			for (i = 0; i < cache->nslots; i++) {
				slot = &cache->slots[i];
				while (*slot) {
					/*
					 * Entry TTL has precedence over cache TTL
					 */
					if((*slot)->value->ttl) {
						if((time_t) ((*slot)->ctime + (*slot)->value->ttl) < t) {
							apc_cache_remove_slot(cache, slot);
							continue;
						}
					} else if(cache->ttl) {
						if((time_t) ((*slot)->ctime + cache->ttl) < t) {
							apc_cache_remove_slot(cache, slot);
							continue;
						}
					}
					
					/* grab next slot */
					slot = &(*slot)->next;				
				}
			}

			/* if the cache now has space, then reset last key */
			if (cache->sma->get_avail_size(size)) {
				/* wipe lastkey */
				memset(&cache->header->lastkey, 0, sizeof(apc_cache_key_t));
			} else {
				/* with not enough space left in cache, we are forced to expunge */
				apc_cache_real_expunge(cache);
			}
        }
    }

	/* we are done */
	cache->header->state &= ~APC_CACHE_ST_BUSY;

	/* unlock header */
	APC_UNLOCK(cache->header);
}
Exemple #8
0
/* {{{ apc_cache_update */
PHP_APCU_API zend_bool apc_cache_update(apc_cache_t* cache, zend_string *key, apc_cache_updater_t updater, void* data)
{
    apc_cache_slot_t** slot;
    apc_cache_entry_t tmp_entry;
	
    zend_bool retval = 0;
    zend_ulong h, s;

    if(apc_cache_busy(cache))
    {
        /* cannot service request right now */ 
        return 0;
    }

    /* calculate hash */
    apc_cache_hash_slot(cache, key, &h, &s);
	
	/* lock header */
	APC_LOCK(cache->header);

	/* find head */
    slot = &cache->slots[s];

    while (*slot) {
		/* check for a match by hash and identifier */
        if ((h == ZSTR_HASH((*slot)->key.str)) &&
            memcmp(ZSTR_VAL((*slot)->key.str), ZSTR_VAL(key), ZSTR_LEN(key)) == SUCCESS) {
			/* attempt to perform update */
            switch(Z_TYPE((*slot)->value->val)) {
                case IS_ARRAY:
                case IS_OBJECT:
                {
                    if(cache->serializer) {
                        retval = 0;
                        break;
                    }
                }

                /* break intentionally omitted */

                default:
                {
					/* executing update */
                    retval = updater(cache, (*slot)->value, data);
					/* set modified time */
                    (*slot)->key.mtime = apc_time();
                }
                break;
            }
			/* unlock header */
			APC_UNLOCK(cache->header);

            return retval;
        }

		/* set next slot */
        slot = &(*slot)->next;
	}

	/* unlock header */
	APC_UNLOCK(cache->header);

	/* failed to find matching entry, create it */
	ZVAL_LONG(&tmp_entry.val, 0);
	updater(cache, &tmp_entry, data);

	if(apc_cache_store(cache, key, &tmp_entry.val, 0, 0)) {
		return 1;
	}

    return 0;
}