dovecot-2.1: auth: Monitor how fast userdb passwd lookups are. I...

dovecot at dovecot.org dovecot at dovecot.org
Fri Jan 27 22:15:46 EET 2012


details:   http://hg.dovecot.org/dovecot-2.1/rev/c9b5ea1b9709
changeset: 14013:c9b5ea1b9709
user:      Timo Sirainen <tss at iki.fi>
date:      Fri Jan 27 22:15:29 2012 +0200
description:
auth: Monitor how fast userdb passwd lookups are. If they're too slow, suggest blocking=yes

diffstat:

 src/auth/userdb-passwd.c |  62 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 61 insertions(+), 1 deletions(-)

diffs (96 lines):

diff -r e9a816eaa0e2 -r c9b5ea1b9709 src/auth/userdb-passwd.c
--- a/src/auth/userdb-passwd.c	Fri Jan 27 21:52:30 2012 +0200
+++ b/src/auth/userdb-passwd.c	Fri Jan 27 22:15:29 2012 +0200
@@ -7,13 +7,21 @@
 
 #include "ioloop.h"
 #include "ipwd.h"
+#include "time-util.h"
 #include "userdb-template.h"
 
 #define USER_CACHE_KEY "%u"
+#define PASSWD_SLOW_WARN_MSECS (10*1000)
+#define PASSWD_SLOW_MASTER_WARN_MSECS 50
+#define PASSDB_SLOW_MASTER_WARN_COUNT_INTERVAL 100
+#define PASSDB_SLOW_MASTER_WARN_MIN_PERCENTAGE 5
 
 struct passwd_userdb_module {
 	struct userdb_module module;
 	struct userdb_template *tmpl;
+
+	unsigned int fast_count, slow_count;
+	unsigned int slow_warned:1;
 };
 
 struct passwd_userdb_iterate_context {
@@ -24,6 +32,50 @@
 static struct passwd_userdb_iterate_context *cur_userdb_iter = NULL;
 static struct timeout *cur_userdb_iter_to = NULL;
 
+static void
+passwd_check_warnings(struct auth_request *auth_request,
+		      struct passwd_userdb_module *module,
+		      const struct timeval *start_tv)
+{
+	struct timeval end_tv;
+	unsigned int msecs, percentage;
+
+	if (gettimeofday(&end_tv, NULL) < 0)
+		return;
+
+	msecs = timeval_diff_msecs(&end_tv, start_tv);
+	if (msecs >= PASSWD_SLOW_WARN_MSECS) {
+		i_warning("passwd: Lookup for %s took %u secs",
+			  auth_request->user, msecs/1000);
+		return;
+	}
+	if (worker || module->slow_warned)
+		return;
+
+	if (msecs < PASSWD_SLOW_MASTER_WARN_MSECS) {
+		module->fast_count++;
+		return;
+	}
+	module->slow_count++;
+	if (module->fast_count + module->slow_count <
+	    PASSDB_SLOW_MASTER_WARN_COUNT_INTERVAL)
+		return;
+
+	percentage = module->slow_count * 100 /
+		(module->slow_count + module->fast_count);
+	if (percentage < PASSDB_SLOW_MASTER_WARN_MIN_PERCENTAGE) {
+		/* start from beginning */
+		module->slow_count = module->fast_count = 0;
+	} else {
+		i_warning("passwd: %u%% of last %u lookups took over "
+			  "%u milliseconds, "
+			  "you may want to set blocking=yes for userdb",
+			  percentage, PASSDB_SLOW_MASTER_WARN_COUNT_INTERVAL,
+			  PASSWD_SLOW_MASTER_WARN_MSECS);
+		module->slow_warned = TRUE;
+	}
+}
+
 static void passwd_lookup(struct auth_request *auth_request,
 			  userdb_callback_t *callback)
 {
@@ -31,10 +83,18 @@
 	struct passwd_userdb_module *module =
 		(struct passwd_userdb_module *)_module;
 	struct passwd pw;
+	struct timeval start_tv;
+	int ret;
 
 	auth_request_log_debug(auth_request, "passwd", "lookup");
 
-	switch (i_getpwnam(auth_request->user, &pw)) {
+	if (gettimeofday(&start_tv, NULL) < 0)
+		start_tv.tv_sec = 0;
+	ret = i_getpwnam(auth_request->user, &pw);
+	if (start_tv.tv_sec != 0)
+		passwd_check_warnings(auth_request, module, &start_tv);
+
+	switch (ret) {
 	case -1:
 		auth_request_log_error(auth_request, "passwd",
 				       "getpwnam() failed: %m");


More information about the dovecot-cvs mailing list