@@ -135,7 +135,8 @@ typedef enum {
135135 MEMC_OP_ADD ,
136136 MEMC_OP_REPLACE ,
137137 MEMC_OP_APPEND ,
138- MEMC_OP_PREPEND
138+ MEMC_OP_PREPEND ,
139+ MEMC_OP_CAS
139140} php_memc_write_op ;
140141
141142typedef struct {
@@ -400,7 +401,7 @@ static
400401 memcached_return s_server_cursor_version_cb (const memcached_st * ptr , php_memcached_instance_st instance , void * in_context );
401402
402403static
403- zend_bool s_memc_write_zval (php_memc_object_t * intern , php_memc_write_op op , zend_string * server_key , zend_string * key , zval * value , time_t expiration );
404+ zend_bool s_memc_write_zval (php_memc_object_t * intern , php_memc_write_op op , zend_string * server_key , zend_string * key , zval * value , time_t expiration , uint64_t cas_token );
404405
405406static
406407 void php_memc_destroy (memcached_st * memc , php_memc_user_data_t * memc_user_data );
@@ -750,44 +751,32 @@ zend_bool s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcal
750751 php_memc_object_t * intern = Z_MEMC_OBJ_P (zobject );
751752
752753 /* Prepare params */
753- ZVAL_COPY (& params [0 ], zobject );
754+ ZVAL_COPY (& params [0 ], zobject ); /* memc */
754755 ZVAL_STR_COPY (& params [1 ], key ); /* key */
755756 ZVAL_NEW_REF (& params [2 ], value ); /* value */
757+ ZVAL_NEW_EMPTY_REF (& params [3 ]); /* expiration */
758+ ZVAL_NULL (Z_REFVAL (params [3 ]));
756759
757- if (with_cas ) {
758- fci -> param_count = 3 ;
759- } else {
760- ZVAL_NEW_EMPTY_REF (& params [3 ]); /* expiration */
761- ZVAL_NULL (Z_REFVAL (params [3 ]));
762- fci -> param_count = 4 ;
763- }
764-
760+ fci -> param_count = 4 ;
765761 fci -> retval = & retval ;
766762 fci -> params = params ;
767763
768- if (zend_call_function (fci , fcc ) == SUCCESS ) {
769- if (zend_is_true (& retval )) {
770- time_t expiration ;
771- zval * val = Z_REFVAL (params [2 ]);
772-
773- if (with_cas ) {
774- if (Z_TYPE_P (val ) == IS_ARRAY ) {
775- zval * rv = zend_hash_str_find (Z_ARRVAL_P (val ), "value" , sizeof ("value" ) - 1 );
776- if (rv ) {
777- zval * cas = zend_hash_str_find (Z_ARRVAL_P (val ), "cas" , sizeof ("cas" ) - 1 );
778- expiration = cas ? Z_LVAL_P (cas ) : 0 ;
779- status = s_memc_write_zval (intern , MEMC_OP_SET , NULL , key , rv , expiration );
780- }
781- /* memleak? zval_ptr_dtor(value); */
782- ZVAL_COPY (value , val );
783- }
784- } else {
785- expiration = zval_get_long (Z_REFVAL (params [3 ]));
786- status = s_memc_write_zval (intern , MEMC_OP_SET , NULL , key , val , expiration );
787- /* memleak? zval_ptr_dtor(value); */
788- ZVAL_COPY (value , val );
789- }
764+ if (zend_call_function (fci , fcc ) == SUCCESS && zend_is_true (& retval )) {
765+ time_t expiration ;
766+ zval * val = Z_REFVAL (params [2 ]);
767+ zval * rv = NULL ;
768+ zval * zv_cas = NULL ;
769+ uint64_t cas ;
770+
771+ if (Z_TYPE_P (val ) == IS_ARRAY ) {
772+ rv = zend_hash_str_find (Z_ARRVAL_P (val ), "value" , sizeof ("value" ) - 1 );
773+ zv_cas = zend_hash_str_find (Z_ARRVAL_P (val ), "cas" , sizeof ("cas" ) - 1 );
790774 }
775+
776+ expiration = zval_get_long (Z_REFVAL (params [3 ]));
777+ cas = zv_cas ? s_zval_to_uint64 (zv_cas ) : 0 ;
778+ status = s_memc_write_zval (intern , MEMC_OP_SET , NULL , key , rv ? rv : val , expiration , cas );
779+ ZVAL_COPY (value , val );
791780 }
792781 else {
793782 s_memc_set_status (intern , MEMCACHED_NOTFOUND , 0 );
@@ -1054,7 +1043,7 @@ zend_bool s_should_retry_write (php_memc_object_t *intern, memcached_return stat
10541043}
10551044
10561045static
1057- zend_bool s_memc_write_zval (php_memc_object_t * intern , php_memc_write_op op , zend_string * server_key , zend_string * key , zval * value , time_t expiration )
1046+ zend_bool s_memc_write_zval (php_memc_object_t * intern , php_memc_write_op op , zend_string * server_key , zend_string * key , zval * value , time_t expiration , uint64_t cas )
10581047{
10591048 uint32_t flags = 0 ;
10601049 zend_string * payload = NULL ;
@@ -1099,6 +1088,10 @@ zend_bool s_memc_write_zval (php_memc_object_t *intern, php_memc_write_op op, ze
10991088 case MEMC_OP_PREPEND :
11001089 status = memc_write_using_fn_by_key (memcached_prepend_by_key );
11011090 break ;
1091+
1092+ case MEMC_OP_CAS :
1093+ status = memcached_cas_by_key (intern -> memc , ZSTR_VAL (server_key ), ZSTR_LEN (server_key ), ZSTR_VAL (key ), ZSTR_LEN (key ), ZSTR_VAL (payload ), ZSTR_LEN (payload ), expiration , flags , cas );
1094+ break ;
11021095 }
11031096
11041097 if (status == MEMCACHED_END ) {
@@ -1131,6 +1124,10 @@ zend_bool s_memc_write_zval (php_memc_object_t *intern, php_memc_write_op op, ze
11311124 case MEMC_OP_PREPEND :
11321125 status = memc_write_using_fn (memcached_prepend );
11331126 break ;
1127+
1128+ case MEMC_OP_CAS :
1129+ status = memcached_cas (intern -> memc , ZSTR_VAL (key ), ZSTR_LEN (key ), ZSTR_VAL (payload ), ZSTR_LEN (payload ), expiration , flags , cas );
1130+ break ;
11341131 }
11351132 if (status == MEMCACHED_END ) {
11361133 status = MEMCACHED_SUCCESS ;
@@ -1820,7 +1817,7 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke
18201817 str_key = zend_string_init (tmp_key , tmp_len , 0 );
18211818 }
18221819
1823- if (!s_memc_write_zval (intern , MEMC_OP_SET , server_key , str_key , value , expiration )) {
1820+ if (!s_memc_write_zval (intern , MEMC_OP_SET , server_key , str_key , value , expiration , 0 )) {
18241821 php_error_docref (NULL , E_WARNING , "failed to set key %s" , ZSTR_VAL (str_key ));
18251822 }
18261823
@@ -1898,6 +1895,22 @@ PHP_METHOD(Memcached, replaceByKey)
18981895}
18991896/* }}} */
19001897
1898+ /* {{{ Memcached::cas(double cas_token, string key, mixed value [, int expiration ])
1899+ Sets the value for the given key, failing if the cas_token doesn't match the one in memcache */
1900+ PHP_METHOD (Memcached , cas )
1901+ {
1902+ php_memc_store_impl (INTERNAL_FUNCTION_PARAM_PASSTHRU , MEMC_OP_CAS , 0 );
1903+ }
1904+ /* }}} */
1905+
1906+ /* {{{ Memcached::casByKey(double cas_token, string server_key, string key, mixed value [, int expiration ])
1907+ Sets the value for the given key on the server identified by the server_key, failing if the cas_token doesn't match the one in memcache */
1908+ PHP_METHOD (Memcached , casByKey )
1909+ {
1910+ php_memc_store_impl (INTERNAL_FUNCTION_PARAM_PASSTHRU , MEMC_OP_CAS , 1 );
1911+ }
1912+ /* }}} */
1913+
19011914/* {{{ -- php_memc_store_impl */
19021915static void php_memc_store_impl (INTERNAL_FUNCTION_PARAMETERS , int op , zend_bool by_key )
19031916{
@@ -1906,7 +1919,9 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool
19061919 zend_string * s_value ;
19071920 zval s_zvalue ;
19081921 zval * value = NULL ;
1922+ zval * zv_cas = NULL ;
19091923 zend_long expiration = 0 ;
1924+ uint64_t cas = 0 ;
19101925 MEMC_METHOD_INIT_VARS ;
19111926
19121927 if (by_key ) {
@@ -1920,6 +1935,11 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool
19201935 if (zend_parse_parameters (ZEND_NUM_ARGS (), "SS|l" , & server_key , & key , & expiration ) == FAILURE ) {
19211936 return ;
19221937 }
1938+ } else if (op == MEMC_OP_CAS ) {
1939+ if (zend_parse_parameters (ZEND_NUM_ARGS (), "zSSz|l" , & zv_cas , & server_key , & key , & value , & expiration ) == FAILURE ) {
1940+ return ;
1941+ }
1942+ cas = s_zval_to_uint64 (zv_cas );
19231943 } else {
19241944 if (zend_parse_parameters (ZEND_NUM_ARGS (), "SSz|l" , & server_key , & key , & value , & expiration ) == FAILURE ) {
19251945 return ;
@@ -1936,6 +1956,11 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool
19361956 if (zend_parse_parameters (ZEND_NUM_ARGS (), "S|l" , & key , & expiration ) == FAILURE ) {
19371957 return ;
19381958 }
1959+ } else if (op == MEMC_OP_CAS ) {
1960+ if (zend_parse_parameters (ZEND_NUM_ARGS (), "zSz|l" , & zv_cas , & key , & value , & expiration ) == FAILURE ) {
1961+ return ;
1962+ }
1963+ cas = s_zval_to_uint64 (zv_cas );
19391964 } else {
19401965 if (zend_parse_parameters (ZEND_NUM_ARGS (), "Sz|l" , & key , & value , & expiration ) == FAILURE ) {
19411966 return ;
@@ -1959,82 +1984,13 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool
19591984 }
19601985 }
19611986
1962- if (!s_memc_write_zval (intern , op , server_key , key , value , expiration )) {
1987+ if (!s_memc_write_zval (intern , op , server_key , key , value , expiration , cas )) {
19631988 RETURN_FALSE ;
19641989 }
19651990 RETURN_TRUE ;
19661991}
19671992/* }}} */
19681993
1969- /* {{{ -- php_memc_cas_impl */
1970- static void php_memc_cas_impl (INTERNAL_FUNCTION_PARAMETERS , zend_bool by_key )
1971- {
1972- zval * zv_cas ;
1973- uint64_t cas ;
1974- zend_string * key ;
1975- zend_string * server_key = NULL ;
1976- zval * value ;
1977- time_t expiration = 0 ;
1978- zend_string * payload ;
1979- uint32_t flags = 0 ;
1980- memcached_return status ;
1981- MEMC_METHOD_INIT_VARS ;
1982-
1983- if (by_key ) {
1984- if (zend_parse_parameters (ZEND_NUM_ARGS (), "zSSz|ll" , & zv_cas , & server_key , & key ,
1985- & value , & expiration ) == FAILURE ) {
1986- return ;
1987- }
1988- } else {
1989- if (zend_parse_parameters (ZEND_NUM_ARGS (), "zSz|ll" , & zv_cas , & key , & value ,
1990- & expiration ) == FAILURE ) {
1991- return ;
1992- }
1993- }
1994-
1995- MEMC_METHOD_FETCH_OBJECT ;
1996- s_memc_set_status (intern , MEMCACHED_SUCCESS , 0 );
1997- MEMC_CHECK_KEY (intern , key );
1998-
1999- cas = s_zval_to_uint64 (zv_cas );
2000-
2001- payload = s_zval_to_payload (intern , value , & flags );
2002- if (payload == NULL ) {
2003- intern -> rescode = MEMC_RES_PAYLOAD_FAILURE ;
2004- RETURN_FALSE ;
2005- }
2006-
2007- if (by_key ) {
2008- status = memcached_cas_by_key (intern -> memc , ZSTR_VAL (server_key ), ZSTR_LEN (server_key ), ZSTR_VAL (key ), ZSTR_LEN (key ), ZSTR_VAL (payload ), ZSTR_LEN (payload ), expiration , flags , cas );
2009- } else {
2010- status = memcached_cas (intern -> memc , ZSTR_VAL (key ), ZSTR_LEN (key ), ZSTR_VAL (payload ), ZSTR_LEN (payload ), expiration , flags , cas );
2011- }
2012-
2013- zend_string_release (payload );
2014- if (s_memc_status_handle_result_code (intern , status ) == FAILURE ) {
2015- RETURN_FALSE ;
2016- }
2017-
2018- RETURN_TRUE ;
2019- }
2020- /* }}} */
2021-
2022- /* {{{ Memcached::cas(double cas_token, string key, mixed value [, int expiration ])
2023- Sets the value for the given key, failing if the cas_token doesn't match the one in memcache */
2024- PHP_METHOD (Memcached , cas )
2025- {
2026- php_memc_cas_impl (INTERNAL_FUNCTION_PARAM_PASSTHRU , 0 );
2027- }
2028- /* }}} */
2029-
2030- /* {{{ Memcached::casByKey(double cas_token, string server_key, string key, mixed value [, int expiration ])
2031- Sets the value for the given key on the server identified by the server_key, failing if the cas_token doesn't match the one in memcache */
2032- PHP_METHOD (Memcached , casByKey )
2033- {
2034- php_memc_cas_impl (INTERNAL_FUNCTION_PARAM_PASSTHRU , 1 );
2035- }
2036- /* }}} */
2037-
20381994/* {{{ Memcached::delete(string key [, int time ])
20391995 Deletes the given key */
20401996PHP_METHOD (Memcached , delete )
0 commit comments