From d73f3f4b08c09aec5700b2e076ea84433f66d575 Mon Sep 17 00:00:00 2001 From: Pavlo Yatsukhnenko Date: Thu, 26 May 2022 18:12:01 +0300 Subject: [PATCH 1/2] Issue #2106 --- common.h | 1 + library.c | 2 +- redis.c | 9 +++++++++ redis.stub.php | 2 ++ redis_arginfo.h | 7 ++++++- redis_cluster.c | 4 ++++ redis_cluster.stub.php | 2 ++ redis_cluster_arginfo.h | 7 ++++++- redis_cluster_legacy_arginfo.h | 6 +++++- redis_legacy_arginfo.h | 6 +++++- tests/RedisClusterTest.php | 1 + tests/RedisTest.php | 7 +++++++ 12 files changed, 49 insertions(+), 5 deletions(-) diff --git a/common.h b/common.h index 7abaecd..258f7d7 100644 --- a/common.h +++ b/common.h @@ -323,6 +323,7 @@ typedef struct { int null_mbulk_as_null; int tcp_keepalive; int sentinel; + size_t txBytes; } RedisSock; /* }}} */ diff --git a/library.c b/library.c index 66d6178..b2e7923 100644 --- a/library.c +++ b/library.c @@ -3128,7 +3128,7 @@ redis_sock_write(RedisSock *redis_sock, char *cmd, size_t sz) if (redis_check_eof(redis_sock, 0, 0) == 0 && php_stream_write(redis_sock->stream, cmd, sz) == sz ) { - return sz; + return redis_sock->txBytes = sz; } return -1; } diff --git a/redis.c b/redis.c index 7360cdb..f84cb90 100644 --- a/redis.c +++ b/redis.c @@ -3131,6 +3131,15 @@ PHP_METHOD(Redis, getDBNum) { } } +PHP_METHOD(Redis, getTransferredBytes) { + RedisSock *redis_sock; + + if ((redis_sock = redis_sock_get_connected(INTERNAL_FUNCTION_PARAM_PASSTHRU)) == NULL) { + RETURN_FALSE; + } + RETURN_LONG(redis_sock->txBytes); +} + /* {{{ proto Redis::getTimeout */ PHP_METHOD(Redis, getTimeout) { RedisSock *redis_sock; diff --git a/redis.stub.php b/redis.stub.php index ddf6a26..d50aed2 100644 --- a/redis.stub.php +++ b/redis.stub.php @@ -294,6 +294,8 @@ class Redis { public function getTimeout(): int; + public function getTransferredBytes(): int|false; + public function hDel(string $key, string $member, string ...$other_members): Redis|int|false; public function hExists(string $key, string $member): Redis|bool; diff --git a/redis_arginfo.h b/redis_arginfo.h index 216f515..406d445 100644 --- a/redis_arginfo.h +++ b/redis_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 0ff60ed233053935cfc7c5a5ecacd6adaf06a458 */ + * Stub hash: 894a03b9e9db1e8ded0f016a00e7e7150dc26f31 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "null") @@ -359,6 +359,9 @@ ZEND_END_ARG_INFO() #define arginfo_class_Redis_getTimeout arginfo_class_Redis_getDBNum +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_Redis_getTransferredBytes, 0, 0, MAY_BE_LONG|MAY_BE_FALSE) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_hDel, 0, 2, Redis, MAY_BE_LONG|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, member, IS_STRING, 0) @@ -1191,6 +1194,7 @@ ZEND_METHOD(Redis, lcs); ZEND_METHOD(Redis, getReadTimeout); ZEND_METHOD(Redis, getset); ZEND_METHOD(Redis, getTimeout); +ZEND_METHOD(Redis, getTransferredBytes); ZEND_METHOD(Redis, hDel); ZEND_METHOD(Redis, hExists); ZEND_METHOD(Redis, hGet); @@ -1436,6 +1440,7 @@ static const zend_function_entry class_Redis_methods[] = { ZEND_ME(Redis, getReadTimeout, arginfo_class_Redis_getReadTimeout, ZEND_ACC_PUBLIC) ZEND_ME(Redis, getset, arginfo_class_Redis_getset, ZEND_ACC_PUBLIC) ZEND_ME(Redis, getTimeout, arginfo_class_Redis_getTimeout, ZEND_ACC_PUBLIC) + ZEND_ME(Redis, getTransferredBytes, arginfo_class_Redis_getTransferredBytes, ZEND_ACC_PUBLIC) ZEND_ME(Redis, hDel, arginfo_class_Redis_hDel, ZEND_ACC_PUBLIC) ZEND_ME(Redis, hExists, arginfo_class_Redis_hExists, ZEND_ACC_PUBLIC) ZEND_ME(Redis, hGet, arginfo_class_Redis_hGet, ZEND_ACC_PUBLIC) diff --git a/redis_cluster.c b/redis_cluster.c index 8d38989..22a83e0 100644 --- a/redis_cluster.c +++ b/redis_cluster.c @@ -1710,6 +1710,10 @@ PHP_METHOD(RedisCluster, clearlasterror) { RETURN_TRUE; } + +PHP_METHOD(RedisCluster, gettransferredbytes) { + CLUSTER_THROW_EXCEPTION("Not implemented", 0); +} /* }}} */ /* {{{ proto long RedisCluster::getOption(long option */ diff --git a/redis_cluster.stub.php b/redis_cluster.stub.php index 88ca6c0..daf0fa6 100644 --- a/redis_cluster.stub.php +++ b/redis_cluster.stub.php @@ -155,6 +155,8 @@ class RedisCluster { public function getset(string $key, mixed $value): RedisCluster|string|bool; + public function gettransferredbytes(): int|false; + public function hdel(string $key, string $member, string ...$other_members): RedisCluster|int|false; public function hexists(string $key, string $member): RedisCluster|bool; diff --git a/redis_cluster_arginfo.h b/redis_cluster_arginfo.h index 9357e62..457f967 100644 --- a/redis_cluster_arginfo.h +++ b/redis_cluster_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 3d10a4c161f9a4bcf65ac9acfebbb86d11f9cf0d */ + * Stub hash: b9d2d6314c74dbf1e80662aa867b36c4a3ecfe8d */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 1) @@ -306,6 +306,9 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_getset, 0 ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_RedisCluster_gettransferredbytes, 0, 0, MAY_BE_LONG|MAY_BE_FALSE) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_hdel, 0, 2, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, member, IS_STRING, 0) @@ -1012,6 +1015,7 @@ ZEND_METHOD(RedisCluster, getoption); ZEND_METHOD(RedisCluster, getrange); ZEND_METHOD(RedisCluster, lcs); ZEND_METHOD(RedisCluster, getset); +ZEND_METHOD(RedisCluster, gettransferredbytes); ZEND_METHOD(RedisCluster, hdel); ZEND_METHOD(RedisCluster, hexists); ZEND_METHOD(RedisCluster, hget); @@ -1219,6 +1223,7 @@ static const zend_function_entry class_RedisCluster_methods[] = { ZEND_ME(RedisCluster, getrange, arginfo_class_RedisCluster_getrange, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, lcs, arginfo_class_RedisCluster_lcs, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, getset, arginfo_class_RedisCluster_getset, ZEND_ACC_PUBLIC) + ZEND_ME(RedisCluster, gettransferredbytes, arginfo_class_RedisCluster_gettransferredbytes, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, hdel, arginfo_class_RedisCluster_hdel, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, hexists, arginfo_class_RedisCluster_hexists, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, hget, arginfo_class_RedisCluster_hget, ZEND_ACC_PUBLIC) diff --git a/redis_cluster_legacy_arginfo.h b/redis_cluster_legacy_arginfo.h index e3f41e2..2d20625 100644 --- a/redis_cluster_legacy_arginfo.h +++ b/redis_cluster_legacy_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 3d10a4c161f9a4bcf65ac9acfebbb86d11f9cf0d */ + * Stub hash: b9d2d6314c74dbf1e80662aa867b36c4a3ecfe8d */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster___construct, 0, 0, 1) ZEND_ARG_INFO(0, name) @@ -272,6 +272,8 @@ ZEND_END_ARG_INFO() #define arginfo_class_RedisCluster_getset arginfo_class_RedisCluster_append +#define arginfo_class_RedisCluster_gettransferredbytes arginfo_class_RedisCluster__masters + #define arginfo_class_RedisCluster_hdel arginfo_class_RedisCluster_geohash ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_hexists, 0, 0, 2) @@ -864,6 +866,7 @@ ZEND_METHOD(RedisCluster, getoption); ZEND_METHOD(RedisCluster, getrange); ZEND_METHOD(RedisCluster, lcs); ZEND_METHOD(RedisCluster, getset); +ZEND_METHOD(RedisCluster, gettransferredbytes); ZEND_METHOD(RedisCluster, hdel); ZEND_METHOD(RedisCluster, hexists); ZEND_METHOD(RedisCluster, hget); @@ -1071,6 +1074,7 @@ static const zend_function_entry class_RedisCluster_methods[] = { ZEND_ME(RedisCluster, getrange, arginfo_class_RedisCluster_getrange, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, lcs, arginfo_class_RedisCluster_lcs, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, getset, arginfo_class_RedisCluster_getset, ZEND_ACC_PUBLIC) + ZEND_ME(RedisCluster, gettransferredbytes, arginfo_class_RedisCluster_gettransferredbytes, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, hdel, arginfo_class_RedisCluster_hdel, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, hexists, arginfo_class_RedisCluster_hexists, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, hget, arginfo_class_RedisCluster_hget, ZEND_ACC_PUBLIC) diff --git a/redis_legacy_arginfo.h b/redis_legacy_arginfo.h index 4eedda7..0bb816e 100644 --- a/redis_legacy_arginfo.h +++ b/redis_legacy_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 0ff60ed233053935cfc7c5a5ecacd6adaf06a458 */ + * Stub hash: 894a03b9e9db1e8ded0f016a00e7e7150dc26f31 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0) ZEND_ARG_INFO(0, options) @@ -326,6 +326,8 @@ ZEND_END_ARG_INFO() #define arginfo_class_Redis_getTimeout arginfo_class_Redis___destruct +#define arginfo_class_Redis_getTransferredBytes arginfo_class_Redis___destruct + #define arginfo_class_Redis_hDel arginfo_class_Redis_geohash ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_hExists, 0, 0, 2) @@ -1023,6 +1025,7 @@ ZEND_METHOD(Redis, lcs); ZEND_METHOD(Redis, getReadTimeout); ZEND_METHOD(Redis, getset); ZEND_METHOD(Redis, getTimeout); +ZEND_METHOD(Redis, getTransferredBytes); ZEND_METHOD(Redis, hDel); ZEND_METHOD(Redis, hExists); ZEND_METHOD(Redis, hGet); @@ -1268,6 +1271,7 @@ static const zend_function_entry class_Redis_methods[] = { ZEND_ME(Redis, getReadTimeout, arginfo_class_Redis_getReadTimeout, ZEND_ACC_PUBLIC) ZEND_ME(Redis, getset, arginfo_class_Redis_getset, ZEND_ACC_PUBLIC) ZEND_ME(Redis, getTimeout, arginfo_class_Redis_getTimeout, ZEND_ACC_PUBLIC) + ZEND_ME(Redis, getTransferredBytes, arginfo_class_Redis_getTransferredBytes, ZEND_ACC_PUBLIC) ZEND_ME(Redis, hDel, arginfo_class_Redis_hDel, ZEND_ACC_PUBLIC) ZEND_ME(Redis, hExists, arginfo_class_Redis_hExists, ZEND_ACC_PUBLIC) ZEND_ME(Redis, hGet, arginfo_class_Redis_hGet, ZEND_ACC_PUBLIC) diff --git a/tests/RedisClusterTest.php b/tests/RedisClusterTest.php index 6df481d..88e8469 100644 --- a/tests/RedisClusterTest.php +++ b/tests/RedisClusterTest.php @@ -50,6 +50,7 @@ class Redis_Cluster_Test extends Redis_Test { public function testReset() { return $this->markTestSkipped(); } public function testInvalidAuthArgs() { return $this->markTestSkipped(); } public function testScanErrors() { return $this->markTestSkipped(); } + public function testTransferredBytes() { return $this->markTestSkipped(); } public function testlMove() { return $this->markTestSkipped(); } public function testlPos() { return $this->marktestSkipped(); } diff --git a/tests/RedisTest.php b/tests/RedisTest.php index 2a5085c..53226a9 100644 --- a/tests/RedisTest.php +++ b/tests/RedisTest.php @@ -5752,6 +5752,13 @@ class Redis_Test extends TestSuite $this->assertTrue($this->redis->getAuth() === $this->getAuth()); } + public function testTransferredBytes() { + $this->assertTrue($this->redis->ping()); + $this->assertEquals(strlen("*1\r\n$4\r\nPING\r\n"), $this->redis->getTransferredBytes()); + $this->assertEquals(['cluster_enabled' => 0], $this->redis->info('cluster')); + $this->assertEquals(strlen("*2\r\n$4\r\nINFO\r\n$7\r\ncluster\r\n"), $this->redis->getTransferredBytes()); + } + /** * Scan and variants */ From e0a88b7bdfe3adc3319224a76bc69d5efddfa9ee Mon Sep 17 00:00:00 2001 From: Pavlo Yatsukhnenko Date: Thu, 13 Oct 2022 08:14:12 +0300 Subject: [PATCH 2/2] Issue #2106 Expose the transferred number of bytes --- cluster_library.c | 9 ++++++--- library.c | 7 ++++++- redis_cluster.c | 5 ++++- tests/RedisClusterTest.php | 10 +++++++++- tests/RedisTest.php | 2 ++ 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/cluster_library.c b/cluster_library.c index 90a6f95..a2b0264 100644 --- a/cluster_library.c +++ b/cluster_library.c @@ -299,9 +299,8 @@ static int cluster_send_readonly(RedisSock *redis_sock) { /* Send MULTI to a specific ReidsSock */ static int cluster_send_multi(redisCluster *c, short slot) { - if (cluster_send_direct(SLOT_SOCK(c,slot), RESP_MULTI_CMD, - sizeof(RESP_MULTI_CMD) - 1, TYPE_LINE) == 0) - { + if (cluster_send_direct(SLOT_SOCK(c,slot), ZEND_STRL(RESP_MULTI_CMD), TYPE_LINE) == 0) { + c->flags->txBytes += sizeof(RESP_MULTI_CMD) - 1; c->cmd_sock->mode = MULTI; return 0; } @@ -1513,6 +1512,9 @@ PHP_REDIS_API int cluster_send_slot(redisCluster *c, short slot, char *cmd, /* Point our cluster to this slot and it's socket */ c->cmd_slot = slot; c->cmd_sock = SLOT_SOCK(c, slot); + if (c->flags->mode != MULTI) { + c->flags->txBytes = 0; + } /* Enable multi mode on this slot if we've been directed to but haven't * send it to this node yet */ @@ -1527,6 +1529,7 @@ PHP_REDIS_API int cluster_send_slot(redisCluster *c, short slot, char *cmd, if (cluster_sock_write(c, cmd, cmd_len, 1) == -1) { return -1; } + c->flags->txBytes += cmd_len; /* Check our response */ if (cluster_check_response(c, &c->reply_type) != 0 || diff --git a/library.c b/library.c index b2e7923..0709963 100644 --- a/library.c +++ b/library.c @@ -3128,7 +3128,12 @@ redis_sock_write(RedisSock *redis_sock, char *cmd, size_t sz) if (redis_check_eof(redis_sock, 0, 0) == 0 && php_stream_write(redis_sock->stream, cmd, sz) == sz ) { - return redis_sock->txBytes = sz; + if (IS_MULTI(redis_sock)) { + redis_sock->txBytes += sz; + } else { + redis_sock->txBytes = sz; + } + return sz; } return -1; } diff --git a/redis_cluster.c b/redis_cluster.c index 22a83e0..b0afe85 100644 --- a/redis_cluster.c +++ b/redis_cluster.c @@ -1712,7 +1712,8 @@ PHP_METHOD(RedisCluster, clearlasterror) { } PHP_METHOD(RedisCluster, gettransferredbytes) { - CLUSTER_THROW_EXCEPTION("Not implemented", 0); + redisCluster *c = GET_CONTEXT(); + RETURN_LONG(c->flags->txBytes); } /* }}} */ @@ -1833,6 +1834,8 @@ PHP_METHOD(RedisCluster, multi) { /* Flag that we're in MULTI mode */ c->flags->mode = MULTI; + c->flags->txBytes = 0; + /* Return our object so we can chain MULTI calls */ RETVAL_ZVAL(getThis(), 1, 0); } diff --git a/tests/RedisClusterTest.php b/tests/RedisClusterTest.php index 88e8469..b9fff00 100644 --- a/tests/RedisClusterTest.php +++ b/tests/RedisClusterTest.php @@ -50,7 +50,6 @@ class Redis_Cluster_Test extends Redis_Test { public function testReset() { return $this->markTestSkipped(); } public function testInvalidAuthArgs() { return $this->markTestSkipped(); } public function testScanErrors() { return $this->markTestSkipped(); } - public function testTransferredBytes() { return $this->markTestSkipped(); } public function testlMove() { return $this->markTestSkipped(); } public function testlPos() { return $this->marktestSkipped(); } @@ -759,6 +758,15 @@ class Redis_Cluster_Test extends Redis_Test { ini_set('redis.pconnect.pooling_enabled', $prev_value); } + public function testTransferredBytes() { + $this->assertTrue($this->redis->ping('')); + $this->assertEquals(strlen("*1\r\n$4\r\nPING\r\n"), $this->redis->getTransferredBytes()); + $this->assertEquals(['cluster_enabled' => 1], $this->redis->info('', 'cluster')); + $this->assertEquals(strlen("*2\r\n$4\r\nINFO\r\n$7\r\ncluster\r\n"), $this->redis->getTransferredBytes()); + $this->assertEquals([true, true], $this->redis->multi()->ping('')->ping('')->exec()); + $this->assertEquals(strlen("*1\r\n$5\r\nMULTI\r\n*1\r\n$4\r\nEXEC\r\n") + 2 * strlen("*2\r\n$4\r\nPING\r\n"), $this->redis->getTransferredBytes()); + } + /** * @inheritdoc */ diff --git a/tests/RedisTest.php b/tests/RedisTest.php index 53226a9..57ca4c2 100644 --- a/tests/RedisTest.php +++ b/tests/RedisTest.php @@ -5757,6 +5757,8 @@ class Redis_Test extends TestSuite $this->assertEquals(strlen("*1\r\n$4\r\nPING\r\n"), $this->redis->getTransferredBytes()); $this->assertEquals(['cluster_enabled' => 0], $this->redis->info('cluster')); $this->assertEquals(strlen("*2\r\n$4\r\nINFO\r\n$7\r\ncluster\r\n"), $this->redis->getTransferredBytes()); + $this->assertEquals([true, true], $this->redis->multi()->ping()->ping()->exec()); + $this->assertEquals(strlen("*1\r\n$5\r\nMULTI\r\n*1\r\n$4\r\nEXEC\r\n") + 2 * strlen("*2\r\n$4\r\nPING\r\n"), $this->redis->getTransferredBytes()); } /**