From 0bc1362fd1e9e0eb578760a4abbf172f8aec1908 Mon Sep 17 00:00:00 2001
From: Sergey Poznyakoff <gray@Pirx.gnu.org.ua>
Date: Fri, 12 Jun 2009 17:24:07 +0300
Subject: [PATCH] Configurable max. number of threads in pmilter.

* include/sm/pmfapi.h (include/sm/pmfapi.h): New members pmfi_thrmax_s,
pmfi_thrmax_h, pmfi_fdmax. Tailor pmfi_unused.
* libpmilter/pmilter_init.c (sm_pmilt_init1): Set arguments to
evthr_init from the new struct pmilter_S members.
* doc/README.tex: Document changes.
---
 doc/README.tex            |   39 ++++++++++++++++++++++++++++++++++++++-
 include/sm/pmfapi.h       |    6 +++++-
 libpmilter/pmilter_init.c |   16 +++++++++++-----
 3 files changed, 54 insertions(+), 7 deletions(-)

diff --git a/doc/README.tex b/doc/README.tex
index 5e34419..7a6a1ac 100644
--- a/doc/README.tex
+++ b/doc/README.tex
@@ -1610,6 +1610,19 @@ the pathname of the Unix domain socket
 port for inet socket
 (type {\tt socket} only).
 \item
+\verb|min_connections|\index{min_connections}:
+minumum number of simultaneously open connections
+(type {\tt socket} only). Default is 1. See below for
+a description.
+\item
+\verb|max_connections|\index{min_connections}:
+maximum number of simultaneously open connections
+(type {\tt socket} only).
+\item
+\verb|timeout|\index{timeout}:
+time to wait for the answer from the socket map.
+Default is 5 seconds (type {\tt socket} only).
+\item
 \verb|maps|\index{maps}:
 list of map names to use in the map
 (type {\tt sequence} only).
@@ -1619,7 +1632,7 @@ Note:
 for {\tt socket} maps either
 a Unix domain socket (\verb|path|)
 or an inet socket (\verb|address| and \verb|port|)
-must be specified.
+must be specified. 
 
 Example:
 
@@ -1631,6 +1644,30 @@ map seq1 { type = sequence; maps = { localusers, otherusers }; }
 map seq2 { type = sequence; maps = { password, otherusers }; }
 \end{verbatim}
 
+By default, SMAR opens a single connection to each socket map
+configured, which means that accesses to this map are serialized. As a
+result, each incoming connection waits in a queue while all
+previous connections are served. This may create intolerable
+delays on loaded servers. To avoid this, use {\tt min\_connections}
+and {\tt max\_connections} to create a spool of map connections, e.g.:
+
+\begin{verbatim}
+map userdb {
+    type = socket;
+    path = "/var/spool/meta1/smap/userdb";
+    mapname = userdb;
+    min_connections = 10;
+    max_connections = 512;
+}
+\end{verbatim}
+
+This way, when a need to consult the map arrives, SMAR looks
+for the first free connection among the opened ones and uses it. If
+there are no more free connections and the number of opened
+connections is less than {\tt max\_connections}, SMAR will create a
+new connection to serve the request. Otherwise, if the maximum number
+of connections is reached, SMAR will wait until any of them becomes
+available again.
 
 \subsection{Configuration Options for SMAR}
 \label{ConfigurationOptionsforSMAR}
diff --git a/include/sm/pmfapi.h b/include/sm/pmfapi.h
index 4e7a86b..010d060 100644
--- a/include/sm/pmfapi.h
+++ b/include/sm/pmfapi.h
@@ -313,7 +313,11 @@ struct pmilter_S
 
 	pmfi_msg_rplc_stat_F	 pmfi_msg_rplc_stat;
 
-	char		 pmfi_unused[64];
+	uint32_t         pmfi_thrmax_s;
+	uint32_t         pmfi_thrmax_h;
+	uint32_t         pmfi_fdmax;
+	
+	char		 pmfi_unused[52];
 };
 
 LIBMILTER_API sm_ret_T sm_pmfi_init(pmg_ctx_P *_pmg_ctx);
diff --git a/libpmilter/pmilter_init.c b/libpmilter/pmilter_init.c
index 47322b0..7624764 100644
--- a/libpmilter/pmilter_init.c
+++ b/libpmilter/pmilter_init.c
@@ -13,6 +13,7 @@ SM_RCSID("@(#)$Id: pmilter_init.c,v 1.14 2006/10/05 04:27:38 ca Exp $")
 #include "sm/assert.h"
 #include "sm/memops.h"
 #include "sm/evthr.h"
+#include "sm/pmfapi.h"
 #include "pmilter.h"
 
 #if MTA_USE_PMILTER
@@ -111,7 +112,7 @@ sm_pmilt_init1(pmg_ctx_P pmg_ctx)
 	if (sm_is_err(ret))
 	{
 		sm_io_fprintf(smioerr,
-			"sev=ERROR, func=sm_pmilt_init, thr_init=%x\n", ret);
+			"sev=ERROR, func=sm_pmilt_init, thr_init=%m\n", ret);
 		goto error;
 	}
 
@@ -120,16 +121,21 @@ sm_pmilt_init1(pmg_ctx_P pmg_ctx)
 	{
 		ret = sm_error_perm(SM_EM_Q, i);
 		sm_io_fprintf(smioerr,
-			"sev=ERROR, func=sm_pmilt_init, mutex_init=%x\n", i);
+			"sev=ERROR, func=sm_pmilt_init, mutex_init=%m\n", ret);
 		goto error;
 	}
 
-	/* initialize event threads system; CONF */
-	ret = evthr_init(&pmg_ctx->pmg_ev_ctx, 2, 6, 10);
+	/* initialize event threads system */
+#define SM_PMFI_DEF_VAL(val, dfl) (((val) > 0) ? (val) : dfl)
+	ret = evthr_init(&pmg_ctx->pmg_ev_ctx,
+		       SM_PMFI_DEF_VAL(pmg_ctx->pmg_pmilter->pmfi_thrmax_s, 2),
+		       SM_PMFI_DEF_VAL(pmg_ctx->pmg_pmilter->pmfi_thrmax_h, 6),
+		       SM_PMFI_DEF_VAL(pmg_ctx->pmg_pmilter->pmfi_fdmax, 10));
+
 	if (sm_is_err(ret))
 	{
 		sm_io_fprintf(smioerr,
-			"sev=ERROR, func=sm_pmilt_init, evthr_init=%x\n", ret);
+			"sev=ERROR, func=sm_pmilt_init, evthr_init=%m\n", ret);
 		goto error;
 	}
 
-- 
1.6.0

