]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
redis: keep DB conns open and stored in conn_pool
authorLibor Peltan <libor.peltan@nic.cz>
Mon, 11 Aug 2025 13:45:13 +0000 (15:45 +0200)
committerDaniel Salzman <daniel.salzman@nic.cz>
Fri, 12 Sep 2025 14:58:52 +0000 (16:58 +0200)
src/contrib/conn_pool.c
src/contrib/conn_pool.h
src/knot/common/hiredis.c
src/knot/common/hiredis.h
src/knot/events/handlers/load.c
src/knot/server/server.c
src/knot/updates/zone-update.c
src/knot/zone/redis.c
src/knot/zone/redis.h

index 2cc4e397e411f742a57a0f31f8f3b68a1ac49420..3832eff243070c93f62f8ab4c6a069f68d2768e3 100644 (file)
@@ -17,6 +17,7 @@
 
 conn_pool_t *global_conn_pool = NULL;
 conn_pool_t *global_sessticket_pool = NULL;
+conn_pool_t *global_redis_pool = NULL;
 
 const conn_pool_fd_t CONN_POOL_FD_INVALID = -1;
 
index 3d81f4b520a87918edd87bcde88d4dffa10f0f09..a18858292db7262c076dd1e9cd45a74eef8b5ccd 100644 (file)
@@ -37,6 +37,7 @@ typedef struct {
 
 extern conn_pool_t *global_conn_pool;
 extern conn_pool_t *global_sessticket_pool; // pool for outgoing QUIC connection session tickets
+extern conn_pool_t *global_redis_pool; // pool for connections to Redis database
 
 /*!
  * \brief Allocate connection pool.
index ca72df5ec68e70a1984c44b6528713ff32070f5a..0590687b4ba0625cb69632d6d8bcadd1e7f662be 100644 (file)
@@ -4,7 +4,7 @@
  */
 
 #include "knot/common/hiredis.h"
-
+#include "contrib/conn_pool.h"
 #include "contrib/sockaddr.h"
 #include "knot/common/log.h"
 #include "libknot/errcode.h"
@@ -134,6 +134,11 @@ redisContext *rdb_connect(conf_t *conf)
        conf_val_t db_listen = conf_db_param(conf, C_ZONE_DB_LISTEN);
        struct sockaddr_storage addr = conf_addr(&db_listen, NULL);
 
+       redisContext *rdb = (void *)conn_pool_get(global_redis_pool, &addr, &addr);
+       if (rdb != NULL && (intptr_t)rdb != CONN_POOL_FD_INVALID) {
+               return rdb;
+       }
+
        int port = sockaddr_port(&addr);
        sockaddr_port_set(&addr, 0);
 
@@ -144,7 +149,6 @@ redisContext *rdb_connect(conf_t *conf)
 
        const struct timeval timeout = { 10, 0 };
 
-       redisContext *rdb;
        if (addr.ss_family == AF_UNIX) {
                rdb = redisConnectUnixWithTimeout(addr_str, timeout);
        } else {
@@ -223,10 +227,19 @@ redisContext *rdb_connect(conf_t *conf)
        return rdb;
 }
 
-void rdb_disconnect(redisContext* rdb)
+void rdb_disconnect(redisContext *rdb, bool pool_save)
 {
-       if (rdb != NULL) {
-               // TODO: is anything more needed for TLS case?
+       if (rdb != NULL && pool_save) {
+               struct sockaddr_storage addr = { 0 };
+               // struct redisContext seems not to have a way to read out sockaddr, only a string, so try-and-error parse the string
+               if (sockaddr_set(&addr, AF_INET6, rdb->tcp.host, rdb->tcp.port) == KNOT_EOK ||
+                   sockaddr_set(&addr, AF_INET, rdb->tcp.host, rdb->tcp.port) == KNOT_EOK ||
+                   sockaddr_set(&addr, AF_UNIX, rdb->unix_sock.path, 0) == KNOT_EOK) {
+                       rdb = (void *)conn_pool_put(global_redis_pool, &addr, &addr, (intptr_t)rdb);
+               }
+       }
+
+       if (rdb != NULL && (intptr_t)rdb != CONN_POOL_FD_INVALID) {
                redisFree(rdb);
        }
 }
index 9064ed7dfcc172a97f16d048e2885dab95a5f6dd..e432e87bf472630ec47838d9b4af4f3eb0426cde 100644 (file)
@@ -15,6 +15,6 @@
 
 redisContext *rdb_connect(conf_t *conf);
 
-void rdb_disconnect(redisContext* rdb);
+void rdb_disconnect(redisContext *rdb, bool pool_save);
 
 bool rdb_compatible(redisContext *rdb);
index 3fe68262bdba577df20881ffc445d56814687aad..9352d06891af46ab99453af8d112656dd97ff436 100644 (file)
@@ -512,7 +512,7 @@ load_end:
        if (!zone_timers_serial_notified(&zone->timers, new_serial)) {
                zone_schedule_notify(conf, zone, 0);
        }
-       zone_redis_disconnect(db_ctx);
+       zone_redis_disconnect(db_ctx, true);
        zone_skip_free(&skip);
        zone->started = true;
 
@@ -525,7 +525,7 @@ cleanup:
        zone_update_clear(&up);
        zone_contents_deep_free(zf_conts);
        zone_contents_deep_free(journal_conts);
-       zone_redis_disconnect(db_ctx);
+       zone_redis_disconnect(db_ctx, true);
        zone_skip_free(&skip);
        zone->started = true;
 
index f6d73f8e47ae687513d5bde60f34eb9bd7e68cec..3b62af2744db7c9867cabfaa277d3aa5326264be 100644 (file)
@@ -31,6 +31,7 @@
 #include "knot/server/udp-handler.h"
 #include "knot/server/tcp-handler.h"
 #include "knot/updates/acl.h"
+#include "knot/zone/redis.h"
 #include "knot/zone/timers.h"
 #include "knot/zone/zonedb-load.h"
 #include "knot/worker/pool.h"
@@ -52,6 +53,7 @@
 #endif
 
 #define SESSION_TICKET_POOL_TIMEOUT 1200
+#define REDIS_CONN_POOL_TIMEOUT (4 * 60)
 
 #define QUIC_LOG "QUIC/TLS, "
 
@@ -972,7 +974,7 @@ static int rdb_listener_run(struct dthread *thread)
                freeReplyObject(reply);
        }
 
-       rdb_disconnect(s->rdb_ctx);
+       rdb_disconnect(s->rdb_ctx, false);
        s->rdb_ctx = NULL;
 
        return KNOT_EOK;
@@ -1101,6 +1103,8 @@ void server_deinit(server_t *server)
        global_conn_pool = NULL;
        conn_pool_deinit(global_sessticket_pool);
        global_sessticket_pool = NULL;
+       conn_pool_deinit(global_redis_pool);
+       global_redis_pool = NULL;
        knot_unreachables_deinit(&global_unreachables);
 
        knot_creds_free(server->quic_creds);
@@ -1658,6 +1662,18 @@ static void free_sess_ticket(intptr_t ptr)
        }
 }
 
+static void free_redis_conn(intptr_t ptr)
+{
+       if (ptr != CONN_POOL_FD_INVALID) {
+               zone_redis_disconnect((void *)ptr, false);
+       }
+}
+
+static bool invalid_redis_conn(intptr_t ptr)
+{
+       return ptr == CONN_POOL_FD_INVALID || !zone_redis_ping((void *)ptr);
+}
+
 static int reconfigure_remote_pool(conf_t *conf, server_t *server)
 {
        conf_val_t val = conf_get(conf, C_SRV, C_RMT_POOL_LIMIT);
@@ -1697,6 +1713,17 @@ static int reconfigure_remote_pool(conf_t *conf, server_t *server)
                hash = curr_hash;
        }
 
+       val = conf_get(conf, C_DB, C_ZONE_DB_LISTEN);
+       if (global_redis_pool == NULL && val.code == KNOT_EOK) {
+               size_t bg_wrkrs = conf_bg_threads(conf);
+               conn_pool_t *new_pool = conn_pool_init(bg_wrkrs, REDIS_CONN_POOL_TIMEOUT,
+                                                      free_redis_conn, invalid_redis_conn);
+               if (new_pool == NULL) {
+                       return KNOT_ENOMEM;
+               }
+               global_redis_pool = new_pool;
+       }
+
        val = conf_get(conf, C_SRV, C_RMT_RETRY_DELAY);
        int delay_ms = conf_int(&val);
        if (global_unreachables == NULL && delay_ms > 0) {
index f9e11d9b87fb2d080ed32668d0b8e7e126d04445..9dcb4a31c2883e871e7c8e2be4a9f04117b1fb6d 100644 (file)
@@ -734,7 +734,7 @@ static int commit_redis(conf_t *conf, zone_update_t *update)
        zone_redis_txn_t txn;
        int ret = zone_redis_txn_begin(&txn, db_ctx, db_instance, update->zone->name, incremental);
        if (ret != KNOT_EOK) {
-               zone_redis_disconnect(db_ctx);
+               zone_redis_disconnect(db_ctx, true);
                return ret;
        }
 
@@ -765,7 +765,7 @@ static int commit_redis(conf_t *conf, zone_update_t *update)
                              db_instance, zone_contents_serial(update->new_cont));
        }
 
-       zone_redis_disconnect(db_ctx);
+       zone_redis_disconnect(db_ctx, true);
        return ret;
 }
 
index 7de92b3d1f5c41e1ce2033574b7ed1ac9c738383..d287fc56c5fc82a17625a0db918f90dea0a52e85 100644 (file)
@@ -17,9 +17,25 @@ struct redisContext *zone_redis_connect(conf_t *conf)
        return rdb_connect(conf);
 }
 
-void zone_redis_disconnect(struct redisContext *ctx)
+void zone_redis_disconnect(struct redisContext *ctx, bool pool_save)
 {
-       return rdb_disconnect(ctx);
+       return rdb_disconnect(ctx, pool_save);
+}
+
+bool zone_redis_ping(struct redisContext *ctx)
+{
+       if (ctx == NULL) {
+               return false;
+       }
+
+       redisReply *reply = redisCommand(ctx, "PING");
+       bool res = (reply != NULL &&
+                   reply->type == REDIS_REPLY_STATUS &&
+                   strcmp(reply->str, "PONG") == 0);
+
+       freeReplyObject(reply);
+
+       return res;
 }
 
 static int check_reply(struct redisContext *rdb, redisReply *reply,
@@ -363,11 +379,16 @@ struct redisContext *zone_redis_connect(conf_t *conf)
        return NULL;
 }
 
-void zone_redis_disconnect(struct redisContext *ctx)
+void zone_redis_disconnect(struct redisContext *ctx, bool pool_save)
 {
        return;
 }
 
+bool zone_redis_ping(struct redisContext *ctx)
+{
+       return false;
+}
+
 int zone_redis_txn_begin(zone_redis_txn_t *txn, struct redisContext *rdb,
                          uint8_t instance, const knot_dname_t *zone_name,
                          bool incremental)
index 9b347cd72c8a444206c73db4f3d747e8890958ed..8be96dfc7562a917a5820536220da3a7f3f7e7be 100644 (file)
@@ -36,7 +36,12 @@ typedef struct {
  * \brief Wrappers to rdb_connect and rdb_disconnect not needing #ifdef ENABLE_REDIS around.
  */
 struct redisContext *zone_redis_connect(conf_t *conf);
-void zone_redis_disconnect(struct redisContext *ctx);
+void zone_redis_disconnect(struct redisContext *ctx, bool pool_save);
+
+/*!
+ * \brief Check if the conection to the DB is still alive.
+ */
+bool zone_redis_ping(struct redisContext *ctx);
 
 /*!
  * \brief Start a writing stransaction into Redis zone database.