From 2096982a8022527e2820ab9cc78a238cc07f4289 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Tue, 19 Jan 2021 16:16:30 +0100 Subject: [PATCH 01/16] fix MemcachedServer related: #418, m6w6/libmemcached#94 --- php_memcached.c | 3 ++ php_memcached_server.c | 80 +++++++++++++++++++++++------------ server-example/run-server.php | 2 +- 3 files changed, 56 insertions(+), 29 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index 1e218a00..adf2348d 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -3502,6 +3502,8 @@ static void php_memc_server_free_storage(zend_object *object) { php_memc_server_t *intern = php_memc_server_fetch_object(object); + + php_memc_proto_handler_destroy(&intern->handler); zend_object_std_dtor(&intern->zo); } @@ -3515,6 +3517,7 @@ zend_object *php_memc_server_new(zend_class_entry *ce) object_properties_init(&intern->zo, ce); intern->zo.handlers = &memcached_server_object_handlers; + intern->handler = php_memc_proto_handler_new(); return &intern->zo; } diff --git a/php_memcached_server.c b/php_memcached_server.c index 870209c1..e816b90d 100644 --- a/php_memcached_server.c +++ b/php_memcached_server.c @@ -17,13 +17,16 @@ #include "php_memcached.h" #include "php_memcached_private.h" #include "php_memcached_server.h" +#include "php_network.h" #include -#undef NDEBUG -#undef _NDEBUG #include +#if HAVE_ARPA_INET_H +# include +#endif + #define MEMC_GET_CB(cb_type) (MEMC_SERVER_G(callbacks)[cb_type]) #define MEMC_HAS_CB(cb_type) (MEMC_GET_CB(cb_type).fci.size > 0) @@ -58,9 +61,9 @@ typedef struct { static long s_invoke_php_callback (php_memc_server_cb_t *cb, zval *params, ssize_t param_count) { - zval *retval = NULL; + zval retval; - cb->fci.retval = retval; + cb->fci.retval = &retval; cb->fci.params = params; cb->fci.param_count = param_count; #if PHP_VERSION_ID < 80000 @@ -73,7 +76,7 @@ long s_invoke_php_callback (php_memc_server_cb_t *cb, zval *params, ssize_t para efree (buf); } - return retval == NULL ? PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND : zval_get_long(retval); + return Z_ISUNDEF(retval) ? PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND : zval_get_long(&retval); } // memcached protocol callbacks @@ -96,6 +99,7 @@ protocol_binary_response_status s_add_handler(const void *cookie, const void *ke ZVAL_LONG(&zflags, flags); ZVAL_LONG(&zexptime, exptime); ZVAL_NULL(&zresult_cas); + ZVAL_MAKE_REF(&zresult_cas); ZVAL_COPY(¶ms[0], &zcookie); ZVAL_COPY(¶ms[1], &zkey); @@ -142,6 +146,7 @@ protocol_binary_response_status s_append_prepend_handler (php_memc_event_t event ZVAL_STRINGL(&zvalue, data, data_len); ZVAL_DOUBLE(&zcas, cas); ZVAL_NULL(&zresult_cas); + ZVAL_MAKE_REF(&zresult_cas); ZVAL_COPY(¶ms[0], &zcookie); ZVAL_COPY(¶ms[1], &zkey); @@ -198,11 +203,13 @@ protocol_binary_response_status s_incr_decr_handler (php_memc_event_t event, con MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); ZVAL_STRINGL(&zkey, key, key_len); - ZVAL_LONG(&zdelta, (long) delta); - ZVAL_LONG(&zinital, (long) initial); - ZVAL_LONG(&zexpiration, (long) expiration); + ZVAL_LONG(&zdelta, (zend_long) delta); + ZVAL_LONG(&zinital, (zend_long) initial); + ZVAL_LONG(&zexpiration, (zend_long) expiration); ZVAL_LONG(&zresult, 0); + ZVAL_MAKE_REF(&zresult); ZVAL_NULL(&zresult_cas); + ZVAL_MAKE_REF(&zresult_cas); ZVAL_COPY(¶ms[0], &zcookie); ZVAL_COPY(¶ms[1], &zkey); @@ -322,6 +329,13 @@ protocol_binary_response_status s_get_handler (const void *cookie, const void *k } MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); + ZVAL_STRINGL(&zkey, key, key_len); + ZVAL_NULL(&zvalue); + ZVAL_MAKE_REF(&zvalue); + ZVAL_NULL(&zflags); + ZVAL_MAKE_REF(&zflags); + ZVAL_NULL(&zresult_cas); + ZVAL_MAKE_REF(&zresult_cas); ZVAL_COPY(¶ms[0], &zcookie); ZVAL_COPY(¶ms[1], &zkey); @@ -436,11 +450,12 @@ protocol_binary_response_status s_set_replace_handler (php_memc_event_t event, c MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); ZVAL_STRINGL(&zkey, key, key_len); - ZVAL_STRINGL(&zdata, ((char *) data), (int) data_len); - ZVAL_LONG(&zflags, (long) flags); - ZVAL_LONG(&zexpiration, (long) expiration); + ZVAL_STRINGL(&zdata, data, data_len); + ZVAL_LONG(&zflags, (zend_long) flags); + ZVAL_LONG(&zexpiration, (zend_long) expiration); ZVAL_DOUBLE(&zcas, (double) cas); ZVAL_NULL(&zresult_cas); + ZVAL_MAKE_REF(&zresult_cas); ZVAL_COPY(¶ms[0], &zcookie); ZVAL_COPY(¶ms[1], &zkey); @@ -504,6 +519,7 @@ protocol_binary_response_status s_stat_handler (const void *cookie, const void * ZVAL_STRINGL(&zkey, key, key_len); ZVAL_NULL(&zbody); + ZVAL_MAKE_REF(&zbody); ZVAL_COPY(¶ms[0], &zcookie); ZVAL_COPY(¶ms[1], &zkey); @@ -584,17 +600,27 @@ void s_handle_memcached_event (evutil_socket_t fd, short what, void *arg) zval zremoteip, zremoteport; zval params[2]; protocol_binary_response_status retval; - - struct sockaddr_in addr_in; - socklen_t addr_in_len = sizeof(addr_in); - - if (getpeername (fd, (struct sockaddr *) &addr_in, &addr_in_len) == 0) { - ZVAL_STRING(&zremoteip, inet_ntoa (addr_in.sin_addr)); - ZVAL_LONG(&zremoteport, ntohs (addr_in.sin_port)); + struct sockaddr_storage ss; + socklen_t ss_len = sizeof(ss); + + ZVAL_NULL(&zremoteip); + ZVAL_NULL(&zremoteport); + + if (getpeername (fd, (struct sockaddr *) &ss, &ss_len) == 0) { + char addr_buf[0x100]; + + switch (ss.ss_family) { + case AF_INET6: + ZVAL_STRING(&zremoteip, inet_ntop(ss.ss_family, &((struct sockaddr_in6 *) &ss)->sin6_addr, addr_buf, sizeof(addr_buf))); + ZVAL_LONG(&zremoteport, ntohs(((struct sockaddr_in6 *) &ss)->sin6_port)); + break; + case AF_INET: + ZVAL_STRING(&zremoteip, inet_ntop(ss.ss_family, &((struct sockaddr_in *) &ss)->sin_addr, addr_buf, sizeof(addr_buf))); + ZVAL_LONG(&zremoteport, ntohs(((struct sockaddr_in *) &ss)->sin_port)); + break; + } } else { php_error_docref(NULL, E_WARNING, "getpeername failed: %s", strerror (errno)); - ZVAL_NULL(&zremoteip); - ZVAL_NULL(&zremoteport); } ZVAL_COPY(¶ms[0], &zremoteip); @@ -714,22 +740,20 @@ php_memc_proto_handler_t *php_memc_proto_handler_new () } static -evutil_socket_t s_create_listening_socket (const char *spec) +evutil_socket_t s_create_listening_socket (const zend_string *spec) { evutil_socket_t sock; struct sockaddr_storage addr; - int addr_len; - + socklen_t addr_len; int rc; addr_len = sizeof (struct sockaddr); - rc = evutil_parse_sockaddr_port (spec, (struct sockaddr *) &addr, &addr_len); - if (rc != 0) { - php_error_docref(NULL, E_WARNING, "Failed to parse bind address"); + if (SUCCESS != php_network_parse_network_address_with_port(spec->val, spec->len, (struct sockaddr *) &addr, &addr_len)) { + php_error_docref(NULL, E_WARNING, "Failed to parse bind address: %s", spec->val); return -1; } - sock = socket (AF_INET, SOCK_STREAM, 0); + sock = socket (addr.ss_family, SOCK_STREAM, 0); if (sock < 0) { php_error_docref(NULL, E_WARNING, "socket failed: %s", strerror (errno)); return -1; @@ -770,7 +794,7 @@ evutil_socket_t s_create_listening_socket (const char *spec) zend_bool php_memc_proto_handler_run (php_memc_proto_handler_t *handler, zend_string *address) { struct event *accept_event; - evutil_socket_t sock = s_create_listening_socket (address->val); + evutil_socket_t sock = s_create_listening_socket (address); if (sock == -1) { return 0; From 277ce3b20ec9753b994d63f4e99c2506ca2cdd5f Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Tue, 19 Jan 2021 16:32:52 +0100 Subject: [PATCH 02/16] use php_network_get_peer_name --- php_memcached_server.c | 38 ++++++++++------------------------- server-example/run-server.php | 4 ++-- 2 files changed, 13 insertions(+), 29 deletions(-) diff --git a/php_memcached_server.c b/php_memcached_server.c index e816b90d..fee8d28d 100644 --- a/php_memcached_server.c +++ b/php_memcached_server.c @@ -597,41 +597,25 @@ void s_handle_memcached_event (evutil_socket_t fd, short what, void *arg) if (!client->on_connect_invoked) { if (MEMC_HAS_CB(MEMC_SERVER_ON_CONNECT)) { - zval zremoteip, zremoteport; - zval params[2]; + zend_string *zremoteaddr_str; + zval zremoteaddr; + zval params[1]; protocol_binary_response_status retval; - struct sockaddr_storage ss; - socklen_t ss_len = sizeof(ss); - - ZVAL_NULL(&zremoteip); - ZVAL_NULL(&zremoteport); - - if (getpeername (fd, (struct sockaddr *) &ss, &ss_len) == 0) { - char addr_buf[0x100]; - - switch (ss.ss_family) { - case AF_INET6: - ZVAL_STRING(&zremoteip, inet_ntop(ss.ss_family, &((struct sockaddr_in6 *) &ss)->sin6_addr, addr_buf, sizeof(addr_buf))); - ZVAL_LONG(&zremoteport, ntohs(((struct sockaddr_in6 *) &ss)->sin6_port)); - break; - case AF_INET: - ZVAL_STRING(&zremoteip, inet_ntop(ss.ss_family, &((struct sockaddr_in *) &ss)->sin_addr, addr_buf, sizeof(addr_buf))); - ZVAL_LONG(&zremoteport, ntohs(((struct sockaddr_in *) &ss)->sin_port)); - break; - } + + ZVAL_NULL(&zremoteaddr); + + if (SUCCESS == php_network_get_peer_name (fd, &zremoteaddr_str, NULL, NULL)) { + ZVAL_STR(&zremoteaddr, zremoteaddr_str); } else { php_error_docref(NULL, E_WARNING, "getpeername failed: %s", strerror (errno)); } - ZVAL_COPY(¶ms[0], &zremoteip); - ZVAL_COPY(¶ms[1], &zremoteport); + ZVAL_COPY(¶ms[0], &zremoteaddr); - retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_CONNECT), params, 2); + retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_CONNECT), params, 1); zval_ptr_dtor(¶ms[0]); - zval_ptr_dtor(¶ms[1]); - zval_ptr_dtor(&zremoteip); - zval_ptr_dtor(&zremoteport); + zval_ptr_dtor(&zremoteaddr); if (retval != PROTOCOL_BINARY_RESPONSE_SUCCESS) { memcached_protocol_client_destroy (client->protocol_client); From f7731bfe65c9f9312e11018035e7a560e7dde702 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Tue, 19 Jan 2021 16:34:08 +0100 Subject: [PATCH 03/16] remove unused include again --- php_memcached_server.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/php_memcached_server.c b/php_memcached_server.c index fee8d28d..ce93a2bf 100644 --- a/php_memcached_server.c +++ b/php_memcached_server.c @@ -23,10 +23,6 @@ #include -#if HAVE_ARPA_INET_H -# include -#endif - #define MEMC_GET_CB(cb_type) (MEMC_SERVER_G(callbacks)[cb_type]) #define MEMC_HAS_CB(cb_type) (MEMC_GET_CB(cb_type).fci.size > 0) From c7a2084ac958e93a094866889b56a7b37698ef40 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Tue, 19 Jan 2021 16:57:39 +0100 Subject: [PATCH 04/16] as per https://github.com/php-memcached-dev/php-memcached/pull/474#issuecomment-762934191 --- php_memcached_server.c | 1 + 1 file changed, 1 insertion(+) diff --git a/php_memcached_server.c b/php_memcached_server.c index ce93a2bf..1f28d936 100644 --- a/php_memcached_server.c +++ b/php_memcached_server.c @@ -299,6 +299,7 @@ protocol_binary_response_status s_flush_handler(const void *cookie, uint32_t whe } MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); + ZVAL_LONG(&zwhen, when); ZVAL_COPY(¶ms[0], &zcookie); ZVAL_COPY(¶ms[1], &zwhen); From 09d0f27b6298e525e0bae45db8d915fa1d140466 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Wed, 20 Jan 2021 10:54:13 +0100 Subject: [PATCH 05/16] add 1 test for MemcachedServer --- tests/memcachedserver.phpt | 58 +++++++++++++++++++++++ tests/server.inc | 78 +++++++++++++++++++++++++++++++ tests/server.php | 94 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 230 insertions(+) create mode 100644 tests/memcachedserver.phpt create mode 100644 tests/server.inc create mode 100644 tests/server.php diff --git a/tests/memcachedserver.phpt b/tests/memcachedserver.phpt new file mode 100644 index 00000000..54b7fe45 --- /dev/null +++ b/tests/memcachedserver.phpt @@ -0,0 +1,58 @@ +--TEST-- +Memcached::get() with cache callback +--SKIPIF-- + +--FILE-- +setOption(Memcached::OPT_BINARY_PROTOCOL, true); +$cache->setOption(Memcached::OPT_COMPRESSION, false); +$cache->addServer('127.0.0.1', 3434); + +$cache->add("add_key", "hello", 500); +$cache->append("append_key", "world"); +$cache->prepend("prepend_key", "world"); + +$cache->increment("incr", 2, 1, 500); +$cache->decrement("decr", 2, 1, 500); + +$cache->delete("delete_k"); +$cache->flush(1); + +var_dump($cache->get('get_this')); + +$cache->set ('set_key', 'value 1', 100); +$cache->replace ('replace_key', 'value 2', 200); + +var_dump($cache->getStats()); + +$cache->quit(); + +memcached_server_stop($server); +?> +Done +--EXPECTF-- +Listening on 127.0.0.1:3434 +Incoming connection from 127.0.0.1:%s +Incoming connection from 127.0.0.1:%s +client_id=[%s]: Add key=[add_key], value=[hello], flags=[0], expiration=[500] +client_id=[%s]: Append key=[append_key], value=[world], cas=[0] +client_id=[%s]: Prepend key=[prepend_key], value=[world], cas=[0] +client_id=[%s]: Incrementing key=[incr], delta=[2], initial=[1], expiration=[500] +client_id=[%s]: Decrementing key=[decr], delta=[2], initial=[1], expiration=[500] +client_id=[%s]: Delete key=[delete_k], cas=[0] +client_id=[%s]: Flush when=[1] +client_id=[%s]: Get key=[get_this] +client_id=[%s]: Noop +string(20) "Hello to you client!" +client_id=[%s]: Set key=[set_key], value=[value 1], flags=[0], expiration=[100], cas=[0] +client_id=[%s]: Replace key=[replace_key], value=[value 2], flags=[0], expiration=[200], cas=[0] +bool(false) +Done diff --git a/tests/server.inc b/tests/server.inc new file mode 100644 index 00000000..96cc942f --- /dev/null +++ b/tests/server.inc @@ -0,0 +1,78 @@ + STDIN, + 1 => STDOUT, + 2 => STDERR, + ); + + $cmd = "{$php_executable} {$php_args} {$code} {$host}:{$port} "; + if (substr(PHP_OS, 0, 3) == 'WIN') { + $cmd = "{$php_executable} {$php_args} {$code} {$host}:{$port} "; + + $handle = proc_open(addslashes($cmd), $descriptorspec, $pipes, __DIR__, NULL, array("bypass_shell" => true, "suppress_errors" => true)); + } else { + $cmd = "exec {$cmd} 2>/dev/null"; + + $handle = proc_open($cmd, $descriptorspec, $pipes, __DIR__); + } + + // note: even when server prints 'Listening on localhost:8964...Press Ctrl-C to quit.' + // it might not be listening yet...need to wait until fsockopen() call returns + $error = "Unable to connect to server\n"; + for ($i=0; $i < 60; $i++) { + usleep(50000); // 50ms per try + $status = proc_get_status($handle); + $fp = @fsockopen($host, $port); + // Failure, the server is no longer running + if (!($status && $status['running'])) { + $error = "Server is not running\n"; + break; + } + // Success, Connected to servers + if ($fp) { + $error = ''; + break; + } + } + + if ($fp) { + fclose($fp); + } + + if ($error) { + echo $error; + proc_terminate($handle); + exit(1); + } + + register_shutdown_function( + function($handle) { + proc_terminate($handle); + }, + $handle + ); + + return $handle; +} + +function memcached_server_stop($handle) { + $success = FALSE; + if ($handle) { + proc_terminate($handle); + /* Wait for server to shutdown */ + for ($i = 0; $i < 60; $i++) { + $status = proc_get_status($handle); + if (!($status && $status['running'])) { + $success = TRUE; + break; + } + usleep(50000); + } + } + return $success; +} + diff --git a/tests/server.php b/tests/server.php new file mode 100644 index 00000000..674f91ac --- /dev/null +++ b/tests/server.php @@ -0,0 +1,94 @@ +on (Memcached::ON_CONNECT, + function ($remote_addr) { + echo "Incoming connection from {$remote_addr}" . PHP_EOL; + return Memcached::RESPONSE_SUCCESS; + }); + +$server->on (Memcached::ON_ADD, + function ($client_id, $key, $value, $flags, $expiration, &$cas) { + echo "client_id=[$client_id]: Add key=[$key], value=[$value], flags=[$flags], expiration=[$expiration]" . PHP_EOL; + $cas = 15; + return Memcached::RESPONSE_SUCCESS; + }); + +$server->on (Memcached::ON_APPEND, + function ($client_id, $key, $value, $cas, &$result_cas) { + echo "client_id=[$client_id]: Append key=[$key], value=[$value], cas=[$cas]" . PHP_EOL; + return Memcached::RESPONSE_SUCCESS; + }); + +$server->on (Memcached::ON_PREPEND, + function ($client_id, $key, $value, $cas, &$result_cas) { + echo "client_id=[$client_id]: Prepend key=[$key], value=[$value], cas=[$cas]" . PHP_EOL; + return Memcached::RESPONSE_SUCCESS; + }); + +$server->on (Memcached::ON_INCREMENT, + function ($client_id, $key, $delta, $initial, $expiration, &$result, &$result_cas) { + echo "client_id=[$client_id]: Incrementing key=[$key], delta=[$delta], initial=[$initial], expiration=[$expiration]" . PHP_EOL; + return Memcached::RESPONSE_SUCCESS; + }); + +$server->on (Memcached::ON_DECREMENT, + function ($client_id, $key, $delta, $initial, $expiration, &$result, &$result_cas) { + echo "client_id=[$client_id]: Decrementing key=[$key], delta=[$delta], initial=[$initial], expiration=[$expiration]" . PHP_EOL; + return Memcached::RESPONSE_SUCCESS; + }); + +$server->on (Memcached::ON_DELETE, + function ($client_id, $key, $cas) { + echo "client_id=[$client_id]: Delete key=[$key], cas=[$cas]" . PHP_EOL; + return Memcached::RESPONSE_SUCCESS; + }); + +$server->on (Memcached::ON_FLUSH, + function ($client_id, $when) { + echo "client_id=[$client_id]: Flush when=[$when]" . PHP_EOL; + return Memcached::RESPONSE_SUCCESS; + }); + +$server->on (Memcached::ON_GET, + function ($client_id, $key, &$value, &$flags, &$cas) { + echo "client_id=[$client_id]: Get key=[$key]" . PHP_EOL; + $value = "Hello to you client!"; + return Memcached::RESPONSE_SUCCESS; + }); + +$server->on (Memcached::ON_NOOP, + function ($client_id) { + echo "client_id=[$client_id]: Noop" . PHP_EOL; + return Memcached::RESPONSE_SUCCESS; + }); + +$server->on (Memcached::ON_REPLACE, + function ($client_id, $key, $value, $flags, $expiration, $cas, &$result_cas) { + echo "client_id=[$client_id]: Replace key=[$key], value=[$value], flags=[$flags], expiration=[$expiration], cas=[$cas]" . PHP_EOL; + return Memcached::RESPONSE_SUCCESS; + }); + +$server->on (Memcached::ON_SET, + function ($client_id, $key, $value, $flags, $expiration, $cas, &$result_cas) { + echo "client_id=[$client_id]: Set key=[$key], value=[$value], flags=[$flags], expiration=[$expiration], cas=[$cas]" . PHP_EOL; + return Memcached::RESPONSE_SUCCESS; + }); + +$server->on (Memcached::ON_STAT, + function ($client_id, $key, &$value) { + echo "client_id=[$client_id]: Stat key=[$key]" . PHP_EOL; + $value = "Stat reply"; + return Memcached::RESPONSE_SUCCESS; + }); + +$server->on (Memcached::ON_QUIT, + function ($client_id) { + echo "client_id=[$client_id]: Client quit" . PHP_EOL; + return Memcached::RESPONSE_SUCCESS; + }); + +$addr = ($_SERVER['argv'][1] ?? "127.0.0.1:3434"); +echo "Listening on $addr" . PHP_EOL; +$server->run($addr); From 2b32140d08acb64bc087de37ea17c8ba2d99092a Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Wed, 20 Jan 2021 12:08:53 +0100 Subject: [PATCH 06/16] minor fix for version handler --- php_memcached_server.c | 1 + tests/memcachedserver.phpt | 5 +++-- tests/server.php | 7 +++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/php_memcached_server.c b/php_memcached_server.c index 1f28d936..57cb749b 100644 --- a/php_memcached_server.c +++ b/php_memcached_server.c @@ -560,6 +560,7 @@ protocol_binary_response_status s_version_handler (const void *cookie, MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); ZVAL_NULL(&zversion); + ZVAL_MAKE_REF(&zversion); ZVAL_COPY(¶ms[0], &zcookie); ZVAL_COPY(¶ms[1], &zversion); diff --git a/tests/memcachedserver.phpt b/tests/memcachedserver.phpt index 54b7fe45..6d4abb9d 100644 --- a/tests/memcachedserver.phpt +++ b/tests/memcachedserver.phpt @@ -31,7 +31,8 @@ var_dump($cache->get('get_this')); $cache->set ('set_key', 'value 1', 100); $cache->replace ('replace_key', 'value 2', 200); -var_dump($cache->getStats()); +// TODO var_dump($cache->getVersion()); +// TODO var_dump($cache->getStats()); $cache->quit(); @@ -54,5 +55,5 @@ client_id=[%s]: Noop string(20) "Hello to you client!" client_id=[%s]: Set key=[set_key], value=[value 1], flags=[0], expiration=[100], cas=[0] client_id=[%s]: Replace key=[replace_key], value=[value 2], flags=[0], expiration=[200], cas=[0] -bool(false) +client_id=[%s]: Client quit Done diff --git a/tests/server.php b/tests/server.php index 674f91ac..c39b04e8 100644 --- a/tests/server.php +++ b/tests/server.php @@ -79,6 +79,13 @@ function ($client_id, $key, $value, $flags, $expiration, $cas, &$result_cas) { $server->on (Memcached::ON_STAT, function ($client_id, $key, &$value) { echo "client_id=[$client_id]: Stat key=[$key]" . PHP_EOL; + $value = "Stat reply for $key"; + return Memcached::RESPONSE_SUCCESS; + }); + +$server->on (Memcached::ON_VERSION, + function ($client_id, &$value) { + echo "client_id=[$client_id]: Version" . PHP_EOL; $value = "Stat reply"; return Memcached::RESPONSE_SUCCESS; }); From 7562317131d7ef75cf35abf982ca3efa44c5e495 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Wed, 20 Jan 2021 16:43:57 +0100 Subject: [PATCH 07/16] handle empty STATS key --- php_memcached_server.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/php_memcached_server.c b/php_memcached_server.c index 57cb749b..d1e903a1 100644 --- a/php_memcached_server.c +++ b/php_memcached_server.c @@ -514,7 +514,11 @@ protocol_binary_response_status s_stat_handler (const void *cookie, const void * MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); - ZVAL_STRINGL(&zkey, key, key_len); + if (key && key_len) { + ZVAL_STRINGL(&zkey, key, key_len); + } else { + ZVAL_NULL(&zkey); + } ZVAL_NULL(&zbody); ZVAL_MAKE_REF(&zbody); @@ -566,7 +570,6 @@ protocol_binary_response_status s_version_handler (const void *cookie, ZVAL_COPY(¶ms[1], &zversion); retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_VERSION), params, 2); - if (retval == PROTOCOL_BINARY_RESPONSE_SUCCESS) { if (Z_TYPE(zversion) != IS_STRING) { convert_to_string(&zversion); From a3f9b928b65abc3daa743c709b6404e038b5af7b Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Wed, 20 Jan 2021 16:51:34 +0100 Subject: [PATCH 08/16] fix running the server from command line --- tests/server.inc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/server.inc b/tests/server.inc index 96cc942f..5700a9d2 100644 --- a/tests/server.inc +++ b/tests/server.inc @@ -1,7 +1,7 @@ STDIN, @@ -29,7 +29,7 @@ function memcached_server_start($code = 'server.php', $host = "127.0.0.1", $port $fp = @fsockopen($host, $port); // Failure, the server is no longer running if (!($status && $status['running'])) { - $error = "Server is not running\n"; + $error = "Server is not running {$status['command']}\n"; break; } // Success, Connected to servers @@ -75,4 +75,3 @@ function memcached_server_stop($handle) { } return $success; } - From c18e8bb36ff634f1dc9f6927fd98b1a20029f50f Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Wed, 20 Jan 2021 16:52:31 +0100 Subject: [PATCH 09/16] add stats/version tests --- tests/memcachedserver.phpt | 31 ++++++++++++++++++++++++++++--- tests/server.php | 2 +- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/tests/memcachedserver.phpt b/tests/memcachedserver.phpt index 6d4abb9d..82601e12 100644 --- a/tests/memcachedserver.phpt +++ b/tests/memcachedserver.phpt @@ -1,10 +1,13 @@ --TEST-- -Memcached::get() with cache callback +MemcachedServer --SKIPIF-- --FILE-- get('get_this')); $cache->set ('set_key', 'value 1', 100); $cache->replace ('replace_key', 'value 2', 200); -// TODO var_dump($cache->getVersion()); -// TODO var_dump($cache->getStats()); +var_dump($cache->getVersion()); +var_dump($cache->getStats()); +var_dump($cache->getStats("foobar")); $cache->quit(); @@ -55,5 +59,26 @@ client_id=[%s]: Noop string(20) "Hello to you client!" client_id=[%s]: Set key=[set_key], value=[value 1], flags=[0], expiration=[100], cas=[0] client_id=[%s]: Replace key=[replace_key], value=[value 2], flags=[0], expiration=[200], cas=[0] +client_id=[%s]: Version +array(1) { + ["127.0.0.1:3434"]=> + string(5) "1.1.1" +} +client_id=[%s]: Stat key=[] +array(1) { + ["127.0.0.1:3434"]=> + array(1) { + [""]=> + string(15) "Stat reply for " + } +} +client_id=[%s]: Stat key=[foobar] +array(1) { + ["127.0.0.1:3434"]=> + array(1) { + ["foobar"]=> + string(21) "Stat reply for foobar" + } +} client_id=[%s]: Client quit Done diff --git a/tests/server.php b/tests/server.php index c39b04e8..b6ab1cf6 100644 --- a/tests/server.php +++ b/tests/server.php @@ -86,7 +86,7 @@ function ($client_id, $key, &$value) { $server->on (Memcached::ON_VERSION, function ($client_id, &$value) { echo "client_id=[$client_id]: Version" . PHP_EOL; - $value = "Stat reply"; + $value = "1.1.1"; return Memcached::RESPONSE_SUCCESS; }); From 4cb3b015e05018fccc17d4e40e065ab307e35f22 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Wed, 20 Jan 2021 17:42:58 +0100 Subject: [PATCH 10/16] expect an array as STATS value and reply foreach key/value --- php_memcached_server.c | 36 +++++++++++++++++++++++++----------- tests/memcachedserver.phpt | 16 ++++++++++------ tests/server.php | 7 +++++-- 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/php_memcached_server.c b/php_memcached_server.c index d1e903a1..a166051e 100644 --- a/php_memcached_server.c +++ b/php_memcached_server.c @@ -506,7 +506,7 @@ protocol_binary_response_status s_stat_handler (const void *cookie, const void * { zval params[3]; protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; - zval zcookie, zkey, zbody; + zval zcookie, zkey, zstats; if (!MEMC_HAS_CB(MEMC_SERVER_ON_STAT)) { return retval; @@ -519,24 +519,38 @@ protocol_binary_response_status s_stat_handler (const void *cookie, const void * } else { ZVAL_NULL(&zkey); } - ZVAL_NULL(&zbody); - ZVAL_MAKE_REF(&zbody); + ZVAL_NULL(&zstats); + ZVAL_MAKE_REF(&zstats); ZVAL_COPY(¶ms[0], &zcookie); ZVAL_COPY(¶ms[1], &zkey); - ZVAL_COPY(¶ms[2], &zbody); + ZVAL_COPY(¶ms[2], &zstats); retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_STAT), params, 3); if (retval == PROTOCOL_BINARY_RESPONSE_SUCCESS) { - if (Z_TYPE(zbody) == IS_NULL) { + if (Z_ISNULL(zstats)) { retval = response_handler(cookie, NULL, 0, NULL, 0); - } - else { - if (Z_TYPE(zbody) != IS_STRING) { - convert_to_string(&zbody); + } else { + zval *zarray = &zstats; + zend_string *key; + zval *val; + + ZVAL_DEREF(zarray); + if (Z_TYPE_P(zarray) != IS_ARRAY) { + convert_to_array(zarray); + } + + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zarray), key, val) + { + zend_string *val_str = zval_get_string(val); + retval = response_handler(cookie, key->val, key->len, val_str->val, val_str->len); + if (retval != PROTOCOL_BINARY_RESPONSE_SUCCESS) { + break; + } + zend_string_release(val_str); } - retval = response_handler(cookie, key, key_len, Z_STRVAL(zbody), (uint32_t) Z_STRLEN(zbody)); + ZEND_HASH_FOREACH_END(); } } @@ -545,7 +559,7 @@ protocol_binary_response_status s_stat_handler (const void *cookie, const void * zval_ptr_dtor(¶ms[2]); zval_ptr_dtor (&zcookie); zval_ptr_dtor (&zkey); - zval_ptr_dtor (&zbody); + zval_ptr_dtor (&zstats); return retval; } diff --git a/tests/memcachedserver.phpt b/tests/memcachedserver.phpt index 82601e12..d47dd73b 100644 --- a/tests/memcachedserver.phpt +++ b/tests/memcachedserver.phpt @@ -67,17 +67,21 @@ array(1) { client_id=[%s]: Stat key=[] array(1) { ["127.0.0.1:3434"]=> - array(1) { - [""]=> - string(15) "Stat reply for " + array(2) { + ["key"]=> + string(0) "" + ["foo"]=> + string(3) "bar" } } client_id=[%s]: Stat key=[foobar] array(1) { ["127.0.0.1:3434"]=> - array(1) { - ["foobar"]=> - string(21) "Stat reply for foobar" + array(2) { + ["key"]=> + string(6) "foobar" + ["foo"]=> + string(3) "bar" } } client_id=[%s]: Client quit diff --git a/tests/server.php b/tests/server.php index b6ab1cf6..f5ff2f6a 100644 --- a/tests/server.php +++ b/tests/server.php @@ -77,9 +77,12 @@ function ($client_id, $key, $value, $flags, $expiration, $cas, &$result_cas) { }); $server->on (Memcached::ON_STAT, - function ($client_id, $key, &$value) { + function ($client_id, $key, array &$values = null) { echo "client_id=[$client_id]: Stat key=[$key]" . PHP_EOL; - $value = "Stat reply for $key"; + $values = [ + "key" => $key, + "foo" => "bar", + ]; return Memcached::RESPONSE_SUCCESS; }); From 3de2b4d7e27c61be0e4f0017b0b5528d0500b56c Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Wed, 20 Jan 2021 18:00:52 +0100 Subject: [PATCH 11/16] valgrind --- php_memcached.c | 5 ++++- tests/server.inc | 9 +++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index adf2348d..8f464283 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -3907,7 +3907,6 @@ static PHP_GINIT_FUNCTION(php_memcached) { #ifdef HAVE_MEMCACHED_SESSION - php_memcached_globals->session.lock_enabled = 0; php_memcached_globals->session.lock_wait_max = 150; php_memcached_globals->session.lock_wait_min = 150; @@ -3926,8 +3925,12 @@ PHP_GINIT_FUNCTION(php_memcached) php_memcached_globals->session.persistent_enabled = 0; php_memcached_globals->session.sasl_username = NULL; php_memcached_globals->session.sasl_password = NULL; +#endif +#ifdef HAVE_MEMCACHED_PROTOCOL + memset(&php_memcached_globals->server, 0, sizeof(php_memcached_globals->server)); #endif + php_memcached_globals->memc.serializer_name = NULL; php_memcached_globals->memc.serializer_type = SERIALIZER_DEFAULT; php_memcached_globals->memc.compression_name = NULL; diff --git a/tests/server.inc b/tests/server.inc index 5700a9d2..9678f043 100644 --- a/tests/server.inc +++ b/tests/server.inc @@ -23,7 +23,7 @@ function memcached_server_start($code = 'server.php', $host = "127.0.0.1", $port // note: even when server prints 'Listening on localhost:8964...Press Ctrl-C to quit.' // it might not be listening yet...need to wait until fsockopen() call returns $error = "Unable to connect to server\n"; - for ($i=0; $i < 60; $i++) { + for ($i=0; $i < getenv("VALGRIND") ? 1000 : 60; $i++) { usleep(50000); // 50ms per try $status = proc_get_status($handle); $fp = @fsockopen($host, $port); @@ -46,12 +46,16 @@ function memcached_server_start($code = 'server.php', $host = "127.0.0.1", $port if ($error) { echo $error; proc_terminate($handle); + proc_close($handle); exit(1); } register_shutdown_function( function($handle) { - proc_terminate($handle); + if (is_resource($handle)) { + proc_terminate($handle); + proc_close($handle); + } }, $handle ); @@ -72,6 +76,7 @@ function memcached_server_stop($handle) { } usleep(50000); } + proc_close($handle); } return $success; } From cebd8513bd1cb0a5a67642072cc4dad1907a2e5e Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 25 Jan 2021 14:45:03 +0100 Subject: [PATCH 13/16] implement stats callback suggestions by Remi --- php_memcached_server.c | 45 +++++++++++++++++++++----------------- tests/memcachedserver.phpt | 22 +++++++++++++++++++ tests/server.php | 19 ++++++++++------ 3 files changed, 59 insertions(+), 27 deletions(-) diff --git a/php_memcached_server.c b/php_memcached_server.c index a166051e..24c328f8 100644 --- a/php_memcached_server.c +++ b/php_memcached_server.c @@ -519,7 +519,7 @@ protocol_binary_response_status s_stat_handler (const void *cookie, const void * } else { ZVAL_NULL(&zkey); } - ZVAL_NULL(&zstats); + array_init(&zstats); ZVAL_MAKE_REF(&zstats); ZVAL_COPY(¶ms[0], &zcookie); @@ -529,29 +529,34 @@ protocol_binary_response_status s_stat_handler (const void *cookie, const void * retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_STAT), params, 3); if (retval == PROTOCOL_BINARY_RESPONSE_SUCCESS) { - if (Z_ISNULL(zstats)) { - retval = response_handler(cookie, NULL, 0, NULL, 0); - } else { - zval *zarray = &zstats; - zend_string *key; - zval *val; - - ZVAL_DEREF(zarray); - if (Z_TYPE_P(zarray) != IS_ARRAY) { - convert_to_array(zarray); - } + zval *zarray = &zstats; + zend_string *key; + zend_long idx; + zval *val; + + ZVAL_DEREF(zarray); + if (Z_TYPE_P(zarray) != IS_ARRAY) { + convert_to_array(zarray); + } - ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zarray), key, val) - { - zend_string *val_str = zval_get_string(val); + ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(zarray), idx, key, val) + { + zend_string *val_str = zval_get_string(val); + + if (key) { retval = response_handler(cookie, key->val, key->len, val_str->val, val_str->len); - if (retval != PROTOCOL_BINARY_RESPONSE_SUCCESS) { - break; - } - zend_string_release(val_str); + } else { + char buf[0x20], *ptr, *end = &buf[sizeof(buf) - 1]; + ptr = zend_print_long_to_buf(end, idx); + retval = response_handler(cookie, ptr, end - ptr, val_str->val, val_str->len); + } + zend_string_release(val_str); + + if (retval != PROTOCOL_BINARY_RESPONSE_SUCCESS) { + break; } - ZEND_HASH_FOREACH_END(); } + ZEND_HASH_FOREACH_END(); } zval_ptr_dtor(¶ms[0]); diff --git a/tests/memcachedserver.phpt b/tests/memcachedserver.phpt index d47dd73b..8d6bf222 100644 --- a/tests/memcachedserver.phpt +++ b/tests/memcachedserver.phpt @@ -37,6 +37,8 @@ $cache->replace ('replace_key', 'value 2', 200); var_dump($cache->getVersion()); var_dump($cache->getStats()); var_dump($cache->getStats("foobar")); +var_dump($cache->getStats("scalar")); +var_dump($cache->getStats("numeric array")); $cache->quit(); @@ -84,5 +86,25 @@ array(1) { string(3) "bar" } } +client_id=[%s]: Stat key=[scalar] +array(1) { + ["127.0.0.1:3434"]=> + array(1) { + [0]=> + string(%d) "you want it, you get it" + } +} +client_id=[%s]: Stat key=[numeric array] +array(1) { + ["127.0.0.1:3434"]=> + array(3) { + [-1]=> + string(3) "one" + [0]=> + string(3) "two" + [1]=> + string(5) "three" + } +} client_id=[%s]: Client quit Done diff --git a/tests/server.php b/tests/server.php index f5ff2f6a..bce4c0bf 100644 --- a/tests/server.php +++ b/tests/server.php @@ -77,13 +77,18 @@ function ($client_id, $key, $value, $flags, $expiration, $cas, &$result_cas) { }); $server->on (Memcached::ON_STAT, - function ($client_id, $key, array &$values = null) { - echo "client_id=[$client_id]: Stat key=[$key]" . PHP_EOL; - $values = [ - "key" => $key, - "foo" => "bar", - ]; - return Memcached::RESPONSE_SUCCESS; + function ($client_id, $key, array &$values) { + echo "client_id=[$client_id]: Stat key=[$key]" . PHP_EOL; + + if ($key === "scalar") { + $values = "you want it, you get it"; + } elseif ($key === "numeric array") { + $values = [-1 => "one", "two", "three"]; + } else { + $values["key"] = $key; + $values["foo"] = "bar"; + } + return Memcached::RESPONSE_SUCCESS; }); $server->on (Memcached::ON_VERSION, From af7ffcf0a11d653e427d3b2dacd4fdef1623daa6 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 25 Jan 2021 14:54:24 +0100 Subject: [PATCH 14/16] skip test with libmemcached < 1.1.0 --- tests/memcachedserver.phpt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/memcachedserver.phpt b/tests/memcachedserver.phpt index 8d6bf222..145acfba 100644 --- a/tests/memcachedserver.phpt +++ b/tests/memcachedserver.phpt @@ -8,6 +8,10 @@ if (!extension_loaded("memcached")) { if (!class_exists("MemcachedServer")) { die("skip memcached not built with libmemcachedprotocol support\n"); } + +if (Memcached::LIBMEMCACHED_VERSION_HEX < 0x1001000) { + die("skip needs at least libmemcached 1.1.0\n"); +} ?> --FILE-- Date: Tue, 26 Jan 2021 11:38:12 +0100 Subject: [PATCH 15/16] add IPv6 test --- tests/memcachedserver.phpt | 4 ++ tests/memcachedserver6.phpt | 114 ++++++++++++++++++++++++++++++++++++ tests/server.php | 2 + 3 files changed, 120 insertions(+) create mode 100644 tests/memcachedserver6.phpt diff --git a/tests/memcachedserver.phpt b/tests/memcachedserver.phpt index 8d6bf222..c4fdd7c6 100644 --- a/tests/memcachedserver.phpt +++ b/tests/memcachedserver.phpt @@ -36,6 +36,7 @@ $cache->replace ('replace_key', 'value 2', 200); var_dump($cache->getVersion()); var_dump($cache->getStats()); +var_dump($cache->getStats("empty")); var_dump($cache->getStats("foobar")); var_dump($cache->getStats("scalar")); var_dump($cache->getStats("numeric array")); @@ -76,6 +77,9 @@ array(1) { string(3) "bar" } } +client_id=[%s]: Stat key=[empty] +array(0) { +} client_id=[%s]: Stat key=[foobar] array(1) { ["127.0.0.1:3434"]=> diff --git a/tests/memcachedserver6.phpt b/tests/memcachedserver6.phpt new file mode 100644 index 00000000..8ae0b362 --- /dev/null +++ b/tests/memcachedserver6.phpt @@ -0,0 +1,114 @@ +--TEST-- +MemcachedServer +--SKIPIF-- + +--FILE-- +setOption(Memcached::OPT_BINARY_PROTOCOL, true); +$cache->setOption(Memcached::OPT_COMPRESSION, false); +$cache->addServer('[::1]', 3434); + +$cache->add("add_key", "hello", 500); +$cache->append("append_key", "world"); +$cache->prepend("prepend_key", "world"); + +$cache->increment("incr", 2, 1, 500); +$cache->decrement("decr", 2, 1, 500); + +$cache->delete("delete_k"); +$cache->flush(1); + +var_dump($cache->get('get_this')); + +$cache->set ('set_key', 'value 1', 100); +$cache->replace ('replace_key', 'value 2', 200); + +var_dump($cache->getVersion()); +var_dump($cache->getStats()); +var_dump($cache->getStats("empty")); +var_dump($cache->getStats("foobar")); +var_dump($cache->getStats("scalar")); +var_dump($cache->getStats("numeric array")); + +$cache->quit(); + +memcached_server_stop($server); +?> +Done +--EXPECTF-- +Listening on [::1]:3434 +Incoming connection from [::1]:%s +Incoming connection from [::1]:%s +client_id=[%s]: Add key=[add_key], value=[hello], flags=[0], expiration=[500] +client_id=[%s]: Append key=[append_key], value=[world], cas=[0] +client_id=[%s]: Prepend key=[prepend_key], value=[world], cas=[0] +client_id=[%s]: Incrementing key=[incr], delta=[2], initial=[1], expiration=[500] +client_id=[%s]: Decrementing key=[decr], delta=[2], initial=[1], expiration=[500] +client_id=[%s]: Delete key=[delete_k], cas=[0] +client_id=[%s]: Flush when=[1] +client_id=[%s]: Get key=[get_this] +client_id=[%s]: Noop +string(20) "Hello to you client!" +client_id=[%s]: Set key=[set_key], value=[value 1], flags=[0], expiration=[100], cas=[0] +client_id=[%s]: Replace key=[replace_key], value=[value 2], flags=[0], expiration=[200], cas=[0] +client_id=[%s]: Version +array(1) { + ["[::1]:3434"]=> + string(5) "1.1.1" +} +client_id=[%s]: Stat key=[] +array(1) { + ["[::1]:3434"]=> + array(2) { + ["key"]=> + string(0) "" + ["foo"]=> + string(3) "bar" + } +} +client_id=[%s]: Stat key=[empty] +array(0) { +} +client_id=[%s]: Stat key=[foobar] +array(1) { + ["[::1]:3434"]=> + array(2) { + ["key"]=> + string(6) "foobar" + ["foo"]=> + string(3) "bar" + } +} +client_id=[%s]: Stat key=[scalar] +array(1) { + ["[::1]:3434"]=> + array(1) { + [0]=> + string(%d) "you want it, you get it" + } +} +client_id=[%s]: Stat key=[numeric array] +array(1) { + ["[::1]:3434"]=> + array(3) { + [-1]=> + string(3) "one" + [0]=> + string(3) "two" + [1]=> + string(5) "three" + } +} +client_id=[%s]: Client quit +Done diff --git a/tests/server.php b/tests/server.php index bce4c0bf..9a50eb06 100644 --- a/tests/server.php +++ b/tests/server.php @@ -84,6 +84,8 @@ function ($client_id, $key, array &$values) { $values = "you want it, you get it"; } elseif ($key === "numeric array") { $values = [-1 => "one", "two", "three"]; + } elseif ($key === "empty") { + $values = []; } else { $values["key"] = $key; $values["foo"] = "bar"; From abf4add8a1761a319e533197cf65b9b6abdc028a Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Tue, 26 Jan 2021 11:42:37 +0100 Subject: [PATCH 16/16] small sleep to avoid loosing message from subprocess --- tests/memcachedserver.phpt | 1 + tests/memcachedserver6.phpt | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/memcachedserver.phpt b/tests/memcachedserver.phpt index c4fdd7c6..c46a4ccd 100644 --- a/tests/memcachedserver.phpt +++ b/tests/memcachedserver.phpt @@ -42,6 +42,7 @@ var_dump($cache->getStats("scalar")); var_dump($cache->getStats("numeric array")); $cache->quit(); +usleep(50000); memcached_server_stop($server); ?> diff --git a/tests/memcachedserver6.phpt b/tests/memcachedserver6.phpt index 8ae0b362..a2277b4a 100644 --- a/tests/memcachedserver6.phpt +++ b/tests/memcachedserver6.phpt @@ -42,6 +42,7 @@ var_dump($cache->getStats("scalar")); var_dump($cache->getStats("numeric array")); $cache->quit(); +usleep(50000); memcached_server_stop($server); ?>