commit 9cfb64d: [Minor] Another try to fight with hiredis...

Vsevolod Stakhov vsevolod at highsecure.ru
Mon Sep 13 14:14:04 UTC 2021


Author: Vsevolod Stakhov
Date: 2021-09-13 15:07:09 +0100
URL: https://github.com/rspamd/rspamd/commit/9cfb64d5afd8a523d353e6b5a0c83f8579071876 (HEAD -> master)

[Minor] Another try to fight with hiredis...

---
 src/libserver/redis_pool.cxx | 111 ++++++++++++++++++++++++-------------------
 1 file changed, 63 insertions(+), 48 deletions(-)

diff --git a/src/libserver/redis_pool.cxx b/src/libserver/redis_pool.cxx
index 26b5f2f81..8a460b7fe 100644
--- a/src/libserver/redis_pool.cxx
+++ b/src/libserver/redis_pool.cxx
@@ -202,7 +202,7 @@ private:
 	}
 };
 
-class redis_pool {
+class redis_pool final {
 	static constexpr const double default_timeout = 10.0;
 	static constexpr const unsigned default_max_conns = 100;
 
@@ -210,6 +210,7 @@ class redis_pool {
 	robin_hood::unordered_flat_map<redisAsyncContext *,
 			redis_pool_connection *> conns_by_ctx;
 	robin_hood::unordered_node_map<redis_pool_key_t, redis_pool_elt> elts_by_key;
+	bool wanna_die = false; /* Hiredis is 'clever' so we can call ourselves from destructor */
 public:
 	double timeout = default_timeout;
 	unsigned max_conns = default_max_conns;
@@ -244,6 +245,14 @@ public:
 	{
 		conns_by_ctx.emplace(ctx, conn);
 	}
+
+	~redis_pool() {
+		/*
+		 * XXX: this will prevent hiredis to unregister connections that
+		 * are already destroyed during redisAsyncFree...
+		 */
+		wanna_die = true;
+	}
 };
 
 
@@ -479,69 +488,75 @@ redis_pool::new_connection(const gchar *db, const gchar *password,
 						   const char *ip, int port) -> redisAsyncContext *
 {
 
-	auto key = redis_pool_elt::make_key(db, password, ip, port);
-	auto found_elt = elts_by_key.find(key);
+	if (!wanna_die) {
+		auto key = redis_pool_elt::make_key(db, password, ip, port);
+		auto found_elt = elts_by_key.find(key);
 
-	if (found_elt != elts_by_key.end()) {
-		auto &elt = found_elt->second;
+		if (found_elt != elts_by_key.end()) {
+			auto &elt = found_elt->second;
 
-		return elt.new_connection();
-	}
-	else {
-		/* Need to create a pool */
-		auto nelt = elts_by_key.emplace(std::piecewise_construct,
-				std::forward_as_tuple(key),
-				std::forward_as_tuple(this, db, password, ip, port));
+			return elt.new_connection();
+		}
+		else {
+			/* Need to create a pool */
+			auto nelt = elts_by_key.emplace(std::piecewise_construct,
+					std::forward_as_tuple(key),
+					std::forward_as_tuple(this, db, password, ip, port));
 
-		return nelt.first->second.new_connection();
+			return nelt.first->second.new_connection();
+		}
 	}
+
+	return nullptr;
 }
 
 auto redis_pool::release_connection(redisAsyncContext *ctx,
 									enum rspamd_redis_pool_release_type how) -> void
 {
-	auto conn_it = conns_by_ctx.find(ctx);
-	if (conn_it != conns_by_ctx.end()) {
-		auto *conn = conn_it->second;
-		g_assert (conn->state == RSPAMD_REDIS_POOL_CONN_ACTIVE);
-
-		if (ctx->err != REDIS_OK) {
-			/* We need to terminate connection forcefully */
-			msg_debug_rpool ("closed connection %p due to an error", conn->ctx);
-		}
-		else {
-			if (how == RSPAMD_REDIS_RELEASE_DEFAULT) {
-				/* Ensure that there are no callbacks attached to this conn */
-				if (ctx->replies.head == nullptr) {
-					/* Just move it to the inactive queue */
-					conn->state = RSPAMD_REDIS_POOL_CONN_INACTIVE;
-					conn->elt->move_to_inactive(conn);
-					conn->schedule_timeout();
-					msg_debug_rpool("mark connection %p inactive", conn->ctx);
-
-					return;
-				}
-				else {
-					msg_debug_rpool("closed connection %p due to callbacks left",
-							conn->ctx);
-				}
+	if (!wanna_die) {
+		auto conn_it = conns_by_ctx.find(ctx);
+		if (conn_it != conns_by_ctx.end()) {
+			auto *conn = conn_it->second;
+			g_assert (conn->state == RSPAMD_REDIS_POOL_CONN_ACTIVE);
+
+			if (ctx->err != REDIS_OK) {
+				/* We need to terminate connection forcefully */
+				msg_debug_rpool ("closed connection %p due to an error", conn->ctx);
 			}
 			else {
-				if (how == RSPAMD_REDIS_RELEASE_FATAL) {
-					msg_debug_rpool("closed connection %p due to an fatal termination",
-							conn->ctx);
+				if (how == RSPAMD_REDIS_RELEASE_DEFAULT) {
+					/* Ensure that there are no callbacks attached to this conn */
+					if (ctx->replies.head == nullptr) {
+						/* Just move it to the inactive queue */
+						conn->state = RSPAMD_REDIS_POOL_CONN_INACTIVE;
+						conn->elt->move_to_inactive(conn);
+						conn->schedule_timeout();
+						msg_debug_rpool("mark connection %p inactive", conn->ctx);
+
+						return;
+					}
+					else {
+						msg_debug_rpool("closed connection %p due to callbacks left",
+								conn->ctx);
+					}
 				}
 				else {
-					msg_debug_rpool("closed connection %p due to explicit termination",
-							conn->ctx);
+					if (how == RSPAMD_REDIS_RELEASE_FATAL) {
+						msg_debug_rpool("closed connection %p due to an fatal termination",
+								conn->ctx);
+					}
+					else {
+						msg_debug_rpool("closed connection %p due to explicit termination",
+								conn->ctx);
+					}
 				}
 			}
-		}
 
-		conn->elt->release_connection(conn);
-	}
-	else {
-		RSPAMD_UNREACHABLE;
+			conn->elt->release_connection(conn);
+		}
+		else {
+			RSPAMD_UNREACHABLE;
+		}
 	}
 }
 


More information about the Commits mailing list