TT#63000 db_redis: use KEYS instead of SCAN

KEYS is considerably faster then SCAN, even with just one iteration, and
since we're always reading the full set of keys in one go anyway,
there's no benefit of using multiple SCAN invocations.

Change-Id: I0771db1b90273bf3bf73cb6b53e7d9ef8c43fcc6
(cherry picked from commit 053e45bdfa)
changes/14/32414/1
Richard Fuchs 7 years ago
parent 0fcb821185
commit fa52db1f18

@ -46,3 +46,4 @@ sipwise/db_redis_skip_not_eq_type_keys.patch
sipwise/db_redis_update_type_keys.patch
sipwise/db_redis_range_compare_timestamps.patch
sipwise/db_redis_bigint_min_len.patch
sipwise/db_redis_use_keys_instead_of_scan.patch

@ -0,0 +1,91 @@
--- a/src/modules/db_redis/redis_dbase.c
+++ b/src/modules/db_redis/redis_dbase.c
@@ -695,15 +695,21 @@
size_t i = 0;
redis_key_t *query_v = NULL;
- char cursor_str[32] = "";
redisReply *reply = NULL;
- unsigned long cursor = 0;
+ redisReply *keys_list = NULL;
size_t j;
int l;
+
+
+#undef USE_SCAN
+
+#ifdef USE_SCAN
+
+ char cursor_str[32] = "";
+ unsigned long cursor = 0;
unsigned int match_count = match_count_start_val;
char match_count_str[16];
-
do {
snprintf(cursor_str, sizeof(cursor_str), "%lu", cursor);
@@ -763,16 +769,37 @@
}
LM_DBG("cursor is %lu\n", cursor);
- if (reply->element[1]->type != REDIS_REPLY_ARRAY) {
+ keys_list = reply->element[1];
+
+#else // use KEYS
+
+ if (db_redis_key_add_string(&query_v, "KEYS", 4) != 0) {
+ LM_ERR("Failed to add scan command to scan query\n");
+ goto err;
+ }
+ if (db_redis_key_add_string(&query_v, match_pattern->s, match_pattern->len) != 0) {
+ LM_ERR("Failed to add match pattern to scan query\n");
+ goto err;
+ }
+
+ reply = db_redis_command_argv(con, query_v);
+ db_redis_key_free(&query_v);
+ db_redis_check_reply(con, reply, err);
+
+ keys_list = reply;
+
+#endif
+
+ if (keys_list->type != REDIS_REPLY_ARRAY) {
LM_ERR("Invalid content type for scan on table '%.*s', expected array\n",
match_pattern->len, match_pattern->s);
goto err;
}
- *query_keys_count += reply->element[1]->elements;
+ *query_keys_count += keys_list->elements;
- for (j = 0; j < reply->element[1]->elements; ++i, ++j) {
- redisReply *key = reply->element[1]->element[j];
+ for (j = 0; j < keys_list->elements; ++i, ++j) {
+ redisReply *key = keys_list->element[j];
if (!key) {
LM_ERR("Invalid null key at cursor result index %lu while scanning table '%.*s'\n",
j, match_pattern->len, match_pattern->s);
@@ -789,14 +816,19 @@
}
}
+#ifdef USE_SCAN
// exponential increase and falloff, hovering around 1000 results
- if (reply->element[1]->elements > 1300 && match_count > 500)
+ if (keys_list->elements > 1300 && match_count > 500)
match_count /= 2;
- else if (reply->element[1]->elements < 700 && match_count < 500000)
+ else if (keys_list->elements < 700 && match_count < 500000)
match_count *= 2;
+#endif
db_redis_free_reply(&reply);
+
+#ifdef USE_SCAN
} while (cursor > 0);
+#endif
// for full table scans, we have to manually match all given keys
// but only do this once for repeated invocations
Loading…
Cancel
Save