Re: [PECL-CVS] svn: /pecl/apc/trunk/ apc_cache.c apc_cache.h php_apc.c php_apc.h

[email protected] (shire) Thu, 24 Dec 2009 01:34:13 -0800
Newsgroups php.apc.dev
Message-ID <[email protected]>
hrm, yeah I don't think we can get away without the lock here, simply because of the (*slot)->next/key type pointer usage.  I believe the structure would allow that to be an invalid pointer if it's still in the process of being updated, inserted, removed etc.

-shire


Rasmus Lerdorf wrote:
> rasmus                                   Wed, 23 Dec 2009 22:56:44 +0000
>
> Revision: http://svn.php.net/viewvc?view=revision&revision=292569
>
> Log:
> I think apc_exists() is useful.  Here is a non-locking version.
> Still mulling over whether we can get away without the lock here.
> I think we can.  Requested in bug #16981
>
> Bug: http://pecl.php.net/bugs/16981 (unknown)
>
> Changed paths:
>      U   pecl/apc/trunk/apc_cache.c
>      U   pecl/apc/trunk/apc_cache.h
>      U   pecl/apc/trunk/php_apc.c
>      U   pecl/apc/trunk/php_apc.h
>
> Modified: pecl/apc/trunk/apc_cache.c
> ===================================================================
> --- pecl/apc/trunk/apc_cache.c	2009-12-23 22:33:12 UTC (rev 292568)
> +++ pecl/apc/trunk/apc_cache.c	2009-12-23 22:56:44 UTC (rev 292569)
> @@ -635,6 +635,36 @@
>   }
>   /* }}} */
>
> +/* {{{ apc_cache_user_exists */
> +apc_cache_entry_t* apc_cache_user_exists(apc_cache_t* cache, char *strkey, int keylen, time_t t)
> +{
> +    slot_t** slot;
> +    volatile apc_cache_entry_t* value = NULL;
> +
> +    if(apc_cache_busy(cache))
> +    {
> +        /* cache cleanup in progress */
> +        return NULL;
> +    }
> +
> +    slot =&cache->slots[string_nhash_8(strkey, keylen) % cache->num_slots];
> +
> +    while (*slot) {
> +        if (!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) {
> +                return NULL;
> +            }
> +            /* Otherwise we are fine, increase counters and return the cache entry */
> +            value = (*slot)->value;
> +            return (apc_cache_entry_t*)value;
> +        }
> +        slot =&(*slot)->next;
> +    }
> +    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)
>   {
>
> Modified: pecl/apc/trunk/apc_cache.h
> ===================================================================
> --- pecl/apc/trunk/apc_cache.h	2009-12-23 22:33:12 UTC (rev 292568)
> +++ pecl/apc/trunk/apc_cache.h	2009-12-23 22:56:44 UTC (rev 292569)
> @@ -198,6 +198,15 @@
>   extern apc_cache_entry_t* apc_cache_user_find(T cache, char* strkey, int keylen, time_t t);
>
>   /*
> + * apc_cache_user_exists searches for a cache entry by its hashed identifier,
> + * and returns a pointer to the entry if found, NULL otherwise.  This is a
> + * quick non-locking version of apc_cache_user_find that does not modify the
> + * shared memory segment in any way.
> + *
> + */
> +extern apc_cache_entry_t* apc_cache_user_exists(T cache, char* strkey, int keylen, time_t t);
> +
> +/*
>    * apc_cache_delete and apc_cache_user_delete finds an entry in the cache and deletes it.
>    */
>   extern int apc_cache_delete(apc_cache_t* cache, char *filename, int filename_len);
>
> Modified: pecl/apc/trunk/php_apc.c
> ===================================================================
> --- pecl/apc/trunk/php_apc.c	2009-12-23 22:33:12 UTC (rev 292568)
> +++ pecl/apc/trunk/php_apc.c	2009-12-23 22:56:44 UTC (rev 292569)
> @@ -984,7 +984,69 @@
>   }
>   /* }}} */
>
> +/* {{{ proto mixed apc_exists(mixed key)
> + */
> +PHP_FUNCTION(apc_exists) {
> +    zval *key;
> +    HashTable *hash;
> +    HashPosition hpos;
> +    zval **hentry;
> +    char *strkey;
> +    int strkey_len;
> +    apc_cache_entry_t* entry;
> +    zval *result;
> +    zval *result_entry;
> +    time_t t;
>
> +    if(!APCG(enabled)) RETURN_FALSE;
> +
> +    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z",&key) == FAILURE) {
> +        return;
> +    }
> +
> +    t = apc_time();
> +
> +    if(Z_TYPE_P(key) != IS_STRING&&  Z_TYPE_P(key) != IS_ARRAY) {
> +        convert_to_string(key);
> +    }
> +
> +    if(Z_TYPE_P(key) == IS_STRING) {
> +        strkey = Z_STRVAL_P(key);
> +        strkey_len = Z_STRLEN_P(key);
> +        if(!strkey_len) RETURN_FALSE;
> +        entry = apc_cache_user_exists(apc_user_cache, strkey, strkey_len + 1, t);
> +        if(entry) {
> +            RETURN_TRUE;
> +        }
> +    } else if(Z_TYPE_P(key) == IS_ARRAY) {
> +        hash = Z_ARRVAL_P(key);
> +        MAKE_STD_ZVAL(result);
> +        array_init(result);
> +        zend_hash_internal_pointer_reset_ex(hash,&hpos);
> +        while(zend_hash_get_current_data_ex(hash, (void**)&hentry,&hpos) == SUCCESS) {
> +            if(Z_TYPE_PP(hentry) != IS_STRING) {
> +                apc_wprint("apc_exists() expects a string or array of strings.");
> +                goto done;
> +            }
> +            entry = apc_cache_user_exists(apc_user_cache, Z_STRVAL_PP(hentry), Z_STRLEN_PP(hentry) + 1, t);
> +            if(entry) {
> +                MAKE_STD_ZVAL(result_entry);
> +                ZVAL_BOOL(result_entry, 1);
> +                zend_hash_add(Z_ARRVAL_P(result), Z_STRVAL_PP(hentry), Z_STRLEN_PP(hentry) +1,&result_entry, sizeof(zval*), NULL);
> +            } /* don't set values we didn't find */
> +            zend_hash_move_forward_ex(hash,&hpos);
> +        }
> +        RETVAL_ZVAL(result, 0, 1);
> +    } else {
> +        apc_wprint("apc_exists() expects a string or array of strings.");
> +    }
> +
> +done:
> +    RETURN_FALSE;
> +}
> +/* }}} */
> +
> +
>   /* {{{ proto mixed apc_delete(mixed keys)
>    */
>   PHP_FUNCTION(apc_delete) {
> @@ -1680,6 +1742,11 @@
>       ZEND_ARG_INFO(0, context)
>       ZEND_ARG_INFO(0, flags)
>   ZEND_END_ARG_INFO()
> +
> +PHP_APC_ARGINFO
> +ZEND_BEGIN_ARG_INFO(arginfo_apc_exists, 0)
> +	ZEND_ARG_INFO(0, keys)
> +ZEND_END_ARG_INFO()
>   /* }}} */
>
>   /* {{{ apc_functions[] */
> @@ -1702,6 +1769,7 @@
>       PHP_FE(apc_bin_load,            arginfo_apc_bin_load)
>       PHP_FE(apc_bin_dumpfile,        arginfo_apc_bin_dumpfile)
>       PHP_FE(apc_bin_loadfile,        arginfo_apc_bin_loadfile)
> +    PHP_FE(apc_exists,              arginfo_apc_exists)
>       {NULL, NULL, NULL}
>   };
>   /* }}} */
>
> Modified: pecl/apc/trunk/php_apc.h
> ===================================================================
> --- pecl/apc/trunk/php_apc.h	2009-12-23 22:33:12 UTC (rev 292568)
> +++ pecl/apc/trunk/php_apc.h	2009-12-23 22:56:44 UTC (rev 292569)
> @@ -35,7 +35,7 @@
>   #include "apc_php.h"
>   #include "apc_globals.h"
>
> -#define PHP_APC_VERSION "3.1.3p1"
> +#define PHP_APC_VERSION "3.1.4-dev"
>
>   extern zend_module_entry apc_module_entry;
>   #define apc_module_ptr&apc_module_entry
>
>