Skip to content

Commit e0ccf87

Browse files
committed
Avoid hanging getStats() when binary protocol and non-blocking are both enabled
Fixes #348.
1 parent dfcbc02 commit e0ccf87

File tree

3 files changed

+102
-0
lines changed

3 files changed

+102
-0
lines changed

Diff for: package.xml

+1
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ Fixes
168168
<file role='test' name='session_lazy_warning.phpt'/>
169169
<file role='test' name='session_regenerate.phpt'/>
170170
<file role='test' name='stats.phpt'/>
171+
<file role='test' name='stats_hang.phpt'/>
171172
<file role='test' name='default_behavior.phpt'/>
172173
<file role='test' name='reset_keyprefix.phpt'/>
173174
<file role='test' name='session_lock-php71.phpt'/>

Diff for: php_memcached.c

+12
Original file line numberDiff line numberDiff line change
@@ -2757,6 +2757,7 @@ PHP_METHOD(Memcached, getStats)
27572757
memcached_return status;
27582758
char *args = NULL;
27592759
zend_string *args_string = NULL;
2760+
uint64_t orig_no_block, orig_protocol;
27602761
MEMC_METHOD_INIT_VARS;
27612762

27622763
/* "|S!" */
@@ -2770,8 +2771,19 @@ PHP_METHOD(Memcached, getStats)
27702771
if (args_string)
27712772
args = ZSTR_VAL(args_string);
27722773

2774+
/* stats hangs in nonblocking mode, turn off during the call. Only change the
2775+
* value if needed, because libmemcached reconnects for this behavior_set. */
2776+
orig_no_block = memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_NO_BLOCK);
2777+
orig_protocol = memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL);
2778+
if (orig_no_block && orig_protocol)
2779+
memcached_behavior_set(intern->memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 0);
2780+
27732781
array_init(return_value);
27742782
status = memcached_stat_execute(intern->memc, args, s_stat_execute_cb, return_value);
2783+
2784+
if (orig_no_block && orig_protocol)
2785+
memcached_behavior_set(intern->memc, MEMCACHED_BEHAVIOR_NO_BLOCK, orig_no_block);
2786+
27752787
if (s_memc_status_handle_result_code(intern, status) == FAILURE) {
27762788
zval_ptr_dtor(return_value);
27772789
RETURN_FALSE;

Diff for: tests/stats_hang.phpt

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
--TEST--
2+
Check stats does not hang on non-blocking binary protocol
3+
--SKIPIF--
4+
<?php include "skipif.inc";?>
5+
--FILE--
6+
<?php
7+
include dirname (__FILE__) . '/config.inc';
8+
$m = memc_get_instance ();
9+
10+
$key = MEMC_SERVER_HOST . ':' . MEMC_SERVER_PORT;
11+
12+
// Both options set means we have to reconnect to get stats
13+
$m->setOption(Memcached::OPT_NO_BLOCK, true);
14+
$m->setOption(Memcached::OPT_BINARY_PROTOCOL, true);
15+
16+
$stats = $m->getStats();
17+
$conns1 = $stats[$key]['total_connections'];
18+
19+
$stats = $m->getStats();
20+
$conns2 = $stats[$key]['total_connections'];
21+
22+
var_dump($conns1 == $conns2);
23+
var_dump($m->getOption(Memcached::OPT_NO_BLOCK));
24+
var_dump($m->getOption(Memcached::OPT_BINARY_PROTOCOL));
25+
echo "OK" . PHP_EOL;
26+
27+
// If either or both options are false no need to reconnect
28+
$m->setOption(Memcached::OPT_NO_BLOCK, false);
29+
$m->setOption(Memcached::OPT_BINARY_PROTOCOL, true);
30+
31+
$stats = $m->getStats();
32+
$conns1 = $stats[$key]['total_connections'];
33+
34+
$stats = $m->getStats();
35+
$conns2 = $stats[$key]['total_connections'];
36+
37+
var_dump($conns1 == $conns2);
38+
var_dump($m->getOption(Memcached::OPT_NO_BLOCK));
39+
var_dump($m->getOption(Memcached::OPT_BINARY_PROTOCOL));
40+
echo "OK" . PHP_EOL;
41+
42+
// If either or both options are false no need to reconnect
43+
$m->setOption(Memcached::OPT_NO_BLOCK, true);
44+
$m->setOption(Memcached::OPT_BINARY_PROTOCOL, false);
45+
46+
$stats = $m->getStats();
47+
$conns1 = $stats[$key]['total_connections'];
48+
49+
$stats = $m->getStats();
50+
$conns2 = $stats[$key]['total_connections'];
51+
52+
var_dump($conns1 == $conns2);
53+
var_dump($m->getOption(Memcached::OPT_NO_BLOCK));
54+
var_dump($m->getOption(Memcached::OPT_BINARY_PROTOCOL));
55+
echo "OK" . PHP_EOL;
56+
57+
// If either or both options are false no need to reconnect
58+
$m->setOption(Memcached::OPT_NO_BLOCK, false);
59+
$m->setOption(Memcached::OPT_BINARY_PROTOCOL, false);
60+
61+
$stats = $m->getStats();
62+
$conns1 = $stats[$key]['total_connections'];
63+
64+
$stats = $m->getStats();
65+
$conns2 = $stats[$key]['total_connections'];
66+
67+
var_dump($conns1 == $conns2);
68+
var_dump($m->getOption(Memcached::OPT_NO_BLOCK));
69+
var_dump($m->getOption(Memcached::OPT_BINARY_PROTOCOL));
70+
echo "OK" . PHP_EOL;
71+
72+
?>
73+
--EXPECT--
74+
bool(false)
75+
int(1)
76+
int(1)
77+
OK
78+
bool(true)
79+
int(0)
80+
int(1)
81+
OK
82+
bool(true)
83+
int(1)
84+
int(0)
85+
OK
86+
bool(true)
87+
int(0)
88+
int(0)
89+
OK

0 commit comments

Comments
 (0)