diff --git a/memcached-api.php b/memcached-api.php index f2eb46c..51ddfc2 100644 --- a/memcached-api.php +++ b/memcached-api.php @@ -69,7 +69,7 @@ class Memcached { const OPT_PREFIX_KEY; - public function __construct( $locale ) {} + public function __construct( $persistent_id = '' ) {} public function get( $key, $cache_cb = null ) {} diff --git a/memcached.c b/memcached.c index a507096..7f44eb5 100644 --- a/memcached.c +++ b/memcached.c @@ -15,9 +15,6 @@ /* $ Id: $ */ /* TODO - * - refcount on php_memc_t - * - persistent_id in php_memc_t - * - persistent switch-over in constructor */ #ifdef HAVE_CONFIG_H @@ -48,16 +45,169 @@ typedef struct { unsigned int in_set:1; memcached_st *conn; + unsigned is_persistent:1; + const char *plist_key; + int plist_key_len; } php_memc_t; +#ifdef COMPILE_DL_MEMCACHED +ZEND_GET_MODULE(memcached) +#endif + +/**************************************** + Forward declarations +****************************************/ +int php_memc_list_entry(void); + + +/**************************************** + Function implementations +****************************************/ +static PHP_METHOD(Memcached, __construct) +{ + zval *object = getThis(); + php_memc_t *i_obj; + char *persistent_id = NULL; + int persistent_id_len; + zend_bool skip_ctor = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &persistent_id, + &persistent_id_len) == FAILURE) { + ZVAL_NULL(object); + return; + } + + i_obj = (php_memc_t *) zend_object_store_get_object(object TSRMLS_CC); + + if (persistent_id) { + char *plist_key = NULL; + int plist_key_len = 0; + zend_rsrc_list_entry *le; + php_memc_t *pi_obj = NULL; + + plist_key_len = spprintf(&plist_key, 0, "memcached:id=%s", persistent_id); + if (zend_hash_find(&EG(persistent_list), plist_key, plist_key_len+1, (void *)&le) == SUCCESS) { + if (le->type == php_memc_list_entry()) { + pi_obj = (php_memc_t *) le->ptr; + } + } + + if (pi_obj) { + skip_ctor = 1; + } else { + pi_obj = pecalloc(1, sizeof(*pi_obj), 1); + + if (pi_obj == NULL) { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory: cannot allocate handle"); + /* not reached */ + } + + pi_obj->is_persistent = 1; + if ((pi_obj->plist_key = pemalloc(plist_key_len + 1, 1)) == NULL) { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory: cannot allocate handle"); + /* not reached */ + } + memcpy((char *)pi_obj->plist_key, plist_key, plist_key_len + 1); + pi_obj->plist_key_len = plist_key_len + 1; + } + + pi_obj->ce = i_obj->ce; + pi_obj->properties = i_obj->properties; + efree(i_obj); + i_obj = pi_obj; + zend_object_store_set_object(object, i_obj TSRMLS_CC); + + if (plist_key) { + efree(plist_key); + } + } + + if (skip_ctor) { + return; + } + + if (persistent_id) { + zend_rsrc_list_entry le; + + le.type = php_memc_list_entry(); + le.ptr = i_obj; + if (zend_hash_update(&EG(persistent_list), (char *)i_obj->plist_key, + i_obj->plist_key_len, (void *)&le, sizeof(le), NULL) == FAILURE) { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "could not register persistent entry"); + /* not reached */ + } + } +} + + +/**************************************** + Internal support code +****************************************/ +static void php_memc_free(php_memc_t *i_obj TSRMLS_DC) +{ + pefree(i_obj, i_obj->is_persistent); +} + +static void php_memc_free_storage(php_memc_t *i_obj TSRMLS_DC) +{ + if (i_obj->properties) { + zend_hash_destroy(i_obj->properties); + efree(i_obj->properties); + i_obj->properties = NULL; + } + + if (!i_obj->is_persistent) { + php_memc_free(i_obj TSRMLS_CC); + } +} + +zend_object_value php_memc_new(zend_class_entry *ce TSRMLS_DC) +{ + zend_object_value retval; + php_memc_t *i_obj; + zval *tmp; + + i_obj = emalloc(sizeof(*i_obj)); + memset(i_obj, 0, sizeof(*i_obj)); + i_obj->ce = ce; + ALLOC_HASHTABLE(i_obj->properties); + zend_hash_init(i_obj->properties, 0, NULL, ZVAL_PTR_DTOR, 0); + zend_hash_copy(i_obj->properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + + retval.handle = zend_objects_store_put(i_obj, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)php_memc_free_storage, NULL TSRMLS_CC); + retval.handlers = &std_object_handlers; + + return retval; +} + +ZEND_RSRC_DTOR_FUNC(php_memc_dtor) +{ + FILE *fp; + fp = fopen("/tmp/a.log", "a"); + if (rsrc->ptr) { + php_memc_t *i_obj = (php_memc_t *)rsrc->ptr; + fprintf(fp, "destroying list entry for '%s'\n", i_obj->plist_key); + php_memc_free(i_obj TSRMLS_CC); + rsrc->ptr = NULL; + } + fclose(fp); +} + +int php_memc_list_entry(void) +{ + return le_memc; +} + /* {{{ memcached_functions[] */ static zend_function_entry memcached_functions[] = { { NULL, NULL, NULL } }; /* }}} */ -static zend_function_entry memcached_class_functions[] = { +/* {{{ memcached_class_methods */ +static zend_function_entry memcached_class_methods[] = { + PHP_ME(Memcached, __construct, NULL, ZEND_ACC_PUBLIC) { NULL, NULL, NULL } }; /* }}} */ @@ -78,54 +228,6 @@ zend_module_entry memcached_module_entry = { }; /* }}} */ -#ifdef COMPILE_DL_MEMCACHED -ZEND_GET_MODULE(memcached) -#endif - -ZEND_RSRC_DTOR_FUNC(php_memc_dtor) -{ - if (rsrc->ptr) { - php_memc_t *obj = (php_memc_t *)rsrc->ptr; - /* TODO dtor code */ - rsrc->ptr = NULL; - } -} - -static void php_memc_free(php_memc_t *obj TSRMLS_DC) -{ - pefree(obj, obj->is_persistent); -} - -static void php_memc_free_storage(php_memc_t *obj TSRMLS_DC) -{ - if (obj->properties) { - zend_hash_destroy(obj->properties); - efree(obj->properties); - obj->properties = NULL; - } - - php_memc_free(obj TSRMLS_CC); -} - -zend_object_value php_memc_new(zend_class_entry *ce TSRMLS_DC) -{ - zend_object_value retval; - php_memc_t *obj; - zval *tmp; - - obj = emalloc(sizeof(*obj)); - memset(obj, 0, sizeof(*obj)); - obj->ce = ce; - ALLOC_HASHTABLE(obj->properties); - zend_hash_init(obj->properties, 0, NULL, ZVAL_PTR_DTOR, 0); - zend_hash_copy(obj->properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); - - retval.handle = zend_objects_store_put(obj, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)php_memc_free_storage, NULL TSRMLS_CC); - retval.handlers = &std_object_handlers; - - return retval; -} - /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(memcached) @@ -134,7 +236,7 @@ PHP_MINIT_FUNCTION(memcached) le_memc = zend_register_list_destructors_ex(NULL, php_memc_dtor, "Memcached persistent connection", module_number); - INIT_CLASS_ENTRY(ce, "Memcached", memcached_class_functions); + INIT_CLASS_ENTRY(ce, "Memcached", memcached_class_methods); memcached_ce = zend_register_internal_class(&ce TSRMLS_CC); memcached_ce->create_object = php_memc_new;