From fa52db1f187b3ccedc6c8966286237f090841b70 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Tue, 13 Aug 2019 11:42:32 -0400 Subject: [PATCH] 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 053e45bdfa9bed47ce6fe735ade5d16155eeadf0) --- debian/patches/series | 1 + .../db_redis_use_keys_instead_of_scan.patch | 91 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 debian/patches/sipwise/db_redis_use_keys_instead_of_scan.patch diff --git a/debian/patches/series b/debian/patches/series index a2fac4db2..a895b1dca 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -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 diff --git a/debian/patches/sipwise/db_redis_use_keys_instead_of_scan.patch b/debian/patches/sipwise/db_redis_use_keys_instead_of_scan.patch new file mode 100644 index 000000000..bc7a711c2 --- /dev/null +++ b/debian/patches/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