|
@@ -24,6 +24,100 @@
|
|
|
#include "redis_connection.h"
|
|
|
#include "redis_table.h"
|
|
|
|
|
|
+static void print_query(redis_key_t *query) {
|
|
|
+ LM_DBG("Query dump:\n");
|
|
|
+ for (redis_key_t *k = query; k; k = k->next) {
|
|
|
+ LM_DBG(" %s\n", k->key.s);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int db_redis_push_query(km_redis_con_t *con, redis_key_t *query) {
|
|
|
+
|
|
|
+ redis_command_t *cmd = NULL;
|
|
|
+ redis_command_t *tmp = NULL;
|
|
|
+ redis_key_t *new_query = NULL;
|
|
|
+
|
|
|
+ if (!query)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ cmd = (redis_command_t*)pkg_malloc(sizeof(redis_command_t));
|
|
|
+ if (!cmd) {
|
|
|
+ LM_ERR("Failed to allocate memory for redis command\n");
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ // duplicate query, as original one might be free'd after being
|
|
|
+ // appended
|
|
|
+ while(query) {
|
|
|
+ if (db_redis_key_add_str(&new_query, &query->key) != 0) {
|
|
|
+ LM_ERR("Failed to duplicate query\n");
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+ query = query->next;
|
|
|
+ }
|
|
|
+
|
|
|
+ cmd->query = new_query;
|
|
|
+ cmd->next = NULL;
|
|
|
+
|
|
|
+ if (!con->command_queue) {
|
|
|
+ con->command_queue = cmd;
|
|
|
+ } else {
|
|
|
+ tmp = con->command_queue;
|
|
|
+ while (tmp->next)
|
|
|
+ tmp = tmp->next;
|
|
|
+ tmp->next = cmd;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+err:
|
|
|
+ if (new_query) {
|
|
|
+ db_redis_key_free(&new_query);
|
|
|
+ }
|
|
|
+ if (cmd) {
|
|
|
+ pkg_free(cmd);
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+static redis_key_t* db_redis_shift_query(km_redis_con_t *con) {
|
|
|
+ redis_command_t *cmd;
|
|
|
+ redis_key_t *query;
|
|
|
+
|
|
|
+ query = NULL;
|
|
|
+ cmd = con->command_queue;
|
|
|
+
|
|
|
+ if (cmd) {
|
|
|
+ query = cmd->query;
|
|
|
+ con->command_queue = cmd->next;
|
|
|
+ pkg_free(cmd);
|
|
|
+ }
|
|
|
+
|
|
|
+ return query;
|
|
|
+}
|
|
|
+
|
|
|
+static redis_key_t* db_redis_pop_query(km_redis_con_t *con) {
|
|
|
+ redis_command_t **current;
|
|
|
+ redis_command_t *prev;
|
|
|
+ redis_key_t *query;
|
|
|
+
|
|
|
+ current = &con->command_queue;
|
|
|
+ if (!*current)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ do {
|
|
|
+ query = (*current)->query;
|
|
|
+ prev = *current;
|
|
|
+ *current = (*current)->next;
|
|
|
+ } while (*current);
|
|
|
+
|
|
|
+ prev->next = NULL;
|
|
|
+ pkg_free(*current);
|
|
|
+ *current = NULL;
|
|
|
+
|
|
|
+ return query;
|
|
|
+}
|
|
|
+
|
|
|
int db_redis_connect(km_redis_con_t *con) {
|
|
|
struct timeval tv;
|
|
|
redisReply *reply;
|
|
@@ -189,16 +283,6 @@ void db_redis_free_connection(struct pool_con* con) {
|
|
|
pkg_free(_c);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-static void print_query(redis_key_t *query) {
|
|
|
- redis_key_t *k;
|
|
|
-
|
|
|
- LM_DBG("Query dump:\n");
|
|
|
- for (k = query; k; k = k->next) {
|
|
|
- LM_DBG(" %s\n", k->key.s);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
void *db_redis_command_argv(km_redis_con_t *con, redis_key_t *query) {
|
|
|
char **argv = NULL;
|
|
|
int argc;
|
|
@@ -229,12 +313,17 @@ void *db_redis_command_argv(km_redis_con_t *con, redis_key_t *query) {
|
|
|
return reply;
|
|
|
}
|
|
|
|
|
|
-int db_redis_append_command_argv(km_redis_con_t *con, redis_key_t *query) {
|
|
|
+int db_redis_append_command_argv(km_redis_con_t *con, redis_key_t *query, int queue) {
|
|
|
char **argv = NULL;
|
|
|
int ret, argc;
|
|
|
|
|
|
print_query(query);
|
|
|
|
|
|
+ if (queue > 0 && db_redis_push_query(con, query) != 0) {
|
|
|
+ LM_ERR("Failed to queue redis command\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
argc = db_redis_key_list2arr(query, &argv);
|
|
|
if (argc < 0) {
|
|
|
LM_ERR("Failed to allocate memory for query array\n");
|
|
@@ -243,6 +332,10 @@ int db_redis_append_command_argv(km_redis_con_t *con, redis_key_t *query) {
|
|
|
LM_DBG("query has %d args\n", argc);
|
|
|
|
|
|
ret = redisAppendCommandArgv(con->con, argc, (const char**)argv, NULL);
|
|
|
+
|
|
|
+ // this should actually never happen, because if all replies
|
|
|
+ // are properly consumed for the previous command, it won't send
|
|
|
+ // out a new query until redisGetReply is called
|
|
|
if (con->con->err == REDIS_ERR_EOF) {
|
|
|
if (db_redis_connect(con) != 0) {
|
|
|
LM_ERR("Failed to reconnect to redis db\n");
|
|
@@ -264,22 +357,40 @@ int db_redis_append_command_argv(km_redis_con_t *con, redis_key_t *query) {
|
|
|
|
|
|
int db_redis_get_reply(km_redis_con_t *con, void **reply) {
|
|
|
int ret;
|
|
|
+ redis_key_t *query;
|
|
|
|
|
|
*reply = NULL;
|
|
|
ret = redisGetReply(con->con, reply);
|
|
|
if (con->con->err == REDIS_ERR_EOF) {
|
|
|
+ LM_DBG("redis connection is gone, try reconnect\n");
|
|
|
+ con->append_counter = 0;
|
|
|
if (db_redis_connect(con) != 0) {
|
|
|
LM_ERR("Failed to reconnect to redis db\n");
|
|
|
if (con->con) {
|
|
|
redisFree(con->con);
|
|
|
con->con = NULL;
|
|
|
}
|
|
|
- return ret;
|
|
|
+ }
|
|
|
+ // take commands from oldest to newest and re-do again,
|
|
|
+ // but don't queue them once again in retry-mode
|
|
|
+ while ((query = db_redis_shift_query(con))) {
|
|
|
+ LM_DBG("re-queueing appended command\n");
|
|
|
+ if (db_redis_append_command_argv(con, query, 0) != 0) {
|
|
|
+ LM_ERR("Failed to re-queue redis command");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ db_redis_key_free(&query);
|
|
|
}
|
|
|
ret = redisGetReply(con->con, reply);
|
|
|
- }
|
|
|
- if (!con->con->err)
|
|
|
+ if (con->con->err != REDIS_ERR_EOF) {
|
|
|
+ con->append_counter--;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ LM_DBG("get_reply successful, popping query\n");
|
|
|
+ query = db_redis_pop_query(con);
|
|
|
+ db_redis_key_free(&query);
|
|
|
con->append_counter--;
|
|
|
+ }
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -292,6 +403,7 @@ void db_redis_free_reply(redisReply **reply) {
|
|
|
|
|
|
void db_redis_consume_replies(km_redis_con_t *con) {
|
|
|
redisReply *reply = NULL;
|
|
|
+ redis_key_t *query;
|
|
|
while (con->append_counter > 0 && !con->con->err) {
|
|
|
LM_DBG("consuming outstanding reply %u", con->append_counter);
|
|
|
db_redis_get_reply(con, (void**)&reply);
|
|
@@ -300,4 +412,8 @@ void db_redis_consume_replies(km_redis_con_t *con) {
|
|
|
reply = NULL;
|
|
|
}
|
|
|
}
|
|
|
+ while ((query = db_redis_shift_query(con))) {
|
|
|
+ LM_DBG("consuming queued command\n");
|
|
|
+ db_redis_key_free(&query);
|
|
|
+ }
|
|
|
}
|