Skip to content

Commit d76c65c

Browse files
committed
Support for 64-bit offsets for increment and decrement
While the memcached protocol allows for 64-bit increments or decrements, there is a quirk in the libmemcached API that the memcached_increment() and memcached_decrement() functions take only a 32-bit adjustment value. Since the memcached_increment_by_key() and memcached_decrement_by_key() functions do accept 64-bit adjustment values, and the memcached_increment() and memcached_decrement() functions are simply wrappers around those, we'll use them directly and thus support 64-bit adjustments in all cases.
1 parent 6ee6166 commit d76c65c

File tree

3 files changed

+51
-18
lines changed

3 files changed

+51
-18
lines changed

php_memcached.c

+15-10
Original file line numberDiff line numberDiff line change
@@ -2185,7 +2185,7 @@ static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by
21852185
static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, zend_bool incr)
21862186
{
21872187
zend_string *key, *server_key = NULL;
2188-
long offset = 1;
2188+
zend_long offset = 1;
21892189
uint64_t value = UINT64_MAX, initial = 0;
21902190
time_t expiry = 0;
21912191
memcached_return status;
@@ -2208,22 +2208,27 @@ static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key,
22082208
MEMC_CHECK_KEY(intern, key);
22092209

22102210
if (offset < 0) {
2211-
php_error_docref(NULL, E_WARNING, "offset has to be > 0");
2211+
php_error_docref(NULL, E_WARNING, "offset cannot be a negative value");
22122212
RETURN_FALSE;
22132213
}
22142214

22152215
if ((!by_key && n_args < 3) || (by_key && n_args < 4)) {
22162216
if (by_key) {
22172217
if (incr) {
2218-
status = memcached_increment_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, &value);
2218+
status = memcached_increment_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), offset, &value);
22192219
} else {
2220-
status = memcached_decrement_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, &value);
2220+
status = memcached_decrement_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), offset, &value);
22212221
}
22222222
} else {
2223+
/* The libmemcached API has a quirk that memcached_increment() takes only a 32-bit
2224+
* offset, but memcached_increment_by_key() and all other increment and decrement
2225+
* functions take a 64-bit offset. The memcached protocol allows increment/decrement
2226+
* greater than UINT_MAX, so we just work around memcached_increment() here.
2227+
*/
22232228
if (incr) {
2224-
status = memcached_increment(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, &value);
2229+
status = memcached_increment_by_key(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(key), ZSTR_LEN(key), offset, &value);
22252230
} else {
2226-
status = memcached_decrement(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, &value);
2231+
status = memcached_decrement_by_key(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(key), ZSTR_LEN(key), offset, &value);
22272232
}
22282233
}
22292234

@@ -2237,15 +2242,15 @@ static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key,
22372242
}
22382243
if (by_key) {
22392244
if (incr) {
2240-
status = memcached_increment_with_initial_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, initial, expiry, &value);
2245+
status = memcached_increment_with_initial_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), offset, initial, expiry, &value);
22412246
} else {
2242-
status = memcached_decrement_with_initial_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, initial, expiry, &value);
2247+
status = memcached_decrement_with_initial_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), offset, initial, expiry, &value);
22432248
}
22442249
} else {
22452250
if (incr) {
2246-
status = memcached_increment_with_initial(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, initial, expiry, &value);
2251+
status = memcached_increment_with_initial(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), offset, initial, expiry, &value);
22472252
} else {
2248-
status = memcached_decrement_with_initial(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, initial, expiry, &value);
2253+
status = memcached_decrement_with_initial(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), offset, initial, expiry, &value);
22492254
}
22502255
}
22512256
if (s_should_retry_write(intern, status) && retries-- > 0) {

tests/incrdecr.phpt

+18-4
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,25 @@ $m->decrement('foo', 2);
2929
var_dump($m->get('foo'));
3030

3131
error_reporting(0);
32-
echo "Invalid offset\n";
32+
33+
echo "Negative offset\n";
34+
$php_errormsg = '';
3335
$m->increment('foo', -1);
3436
echo $php_errormsg, "\n";
3537
var_dump($m->get('foo'));
38+
39+
$php_errormsg = '';
3640
$m->decrement('foo', -1);
3741
echo $php_errormsg, "\n";
3842
var_dump($m->get('foo'));
3943

44+
echo "Enormous offset\n";
45+
$m->increment('foo', 4294967295);
46+
var_dump($m->get('foo'));
47+
48+
$m->decrement('foo', 4294967295);
49+
var_dump($m->get('foo'));
50+
4051
--EXPECT--
4152
Not there
4253
bool(false)
@@ -51,8 +62,11 @@ int(2)
5162
int(4)
5263
int(3)
5364
int(1)
54-
Invalid offset
55-
Memcached::increment(): offset has to be > 0
65+
Negative offset
66+
Memcached::increment(): offset cannot be a negative value
67+
int(1)
68+
Memcached::decrement(): offset cannot be a negative value
5669
int(1)
57-
Memcached::decrement(): offset has to be > 0
70+
Enormous offset
71+
int(4294967296)
5872
int(1)

tests/incrdecr_bykey.phpt

+18-4
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,25 @@ $m->decrementByKey('foo', 'foo', 2);
2626
var_dump($m->get('foo'));
2727

2828
error_reporting(0);
29-
echo "Invalid offset\n";
29+
30+
echo "Negative offset\n";
31+
$php_errormsg = '';
3032
$m->incrementByKey('foo', 'foo', -1);
3133
echo $php_errormsg, "\n";
3234
var_dump($m->get('foo'));
35+
36+
$php_errormsg = '';
3337
$m->decrementByKey('foo', 'foo', -1);
3438
echo $php_errormsg, "\n";
3539
var_dump($m->get('foo'));
3640

41+
echo "Enormous offset\n";
42+
$m->incrementByKey('foo', 'foo', 4294967295);
43+
var_dump($m->get('foo'));
44+
45+
$m->decrementByKey('foo', 'foo', 4294967295);
46+
var_dump($m->get('foo'));
47+
3748
--EXPECT--
3849
Not there
3950
bool(false)
@@ -45,8 +56,11 @@ int(2)
4556
int(4)
4657
int(3)
4758
int(1)
48-
Invalid offset
49-
Memcached::incrementByKey(): offset has to be > 0
59+
Negative offset
60+
Memcached::incrementByKey(): offset cannot be a negative value
61+
int(1)
62+
Memcached::decrementByKey(): offset cannot be a negative value
5063
int(1)
51-
Memcached::decrementByKey(): offset has to be > 0
64+
Enormous offset
65+
int(4294967296)
5266
int(1)

0 commit comments

Comments
 (0)