dovecot-2.0: master: Fixes to handling logging.

dovecot at dovecot.org dovecot at dovecot.org
Tue May 5 03:25:03 EEST 2009


details:   http://hg.dovecot.org/dovecot-2.0/rev/7def7fa61d68
changeset: 9214:7def7fa61d68
user:      Timo Sirainen <tss at iki.fi>
date:      Mon May 04 20:24:57 2009 -0400
description:
master: Fixes to handling logging.
Master now has a non-blocking write pipe to log process, so it no longer
blocks if log process is hanging. Also it's cleaner to send log commands via
a pipe specifically meant for them.

diffstat:

11 files changed, 277 insertions(+), 147 deletions(-)
src/lib-master/master-interface.h |    1 
src/lib-master/master-service.c   |   14 +++
src/log/log-connection.c          |  136 ++++++++++++++++++++++--------------
src/log/log-connection.h          |    1 
src/log/main.c                    |    1 
src/master/service-log.c          |  137 ++++++++++++++++++++++++-------------
src/master/service-log.h          |    1 
src/master/service-process.c      |  111 ++++++++++++++++++-----------
src/master/service-process.h      |    2 
src/master/service.c              |    7 +
src/master/service.h              |   13 +++

diffs (truncated from 794 to 300 lines):

diff -r 7b3accdf44f8 -r 7def7fa61d68 src/lib-master/master-interface.h
--- a/src/lib-master/master-interface.h	Mon May 04 18:28:17 2009 -0400
+++ b/src/lib-master/master-interface.h	Mon May 04 20:24:57 2009 -0400
@@ -28,6 +28,7 @@ struct log_service_handshake {
 	unsigned int max_lines_per_sec;
 
 	/* Add this previs to each logged line */
+#define MASTER_LOG_PREFIX_NAME "MASTER"
 	unsigned int prefix_len;
 	/* unsigned char prefix[]; */
 };
diff -r 7b3accdf44f8 -r 7def7fa61d68 src/lib-master/master-service.c
--- a/src/lib-master/master-service.c	Mon May 04 18:28:17 2009 -0400
+++ b/src/lib-master/master-service.c	Mon May 04 20:24:57 2009 -0400
@@ -64,8 +64,19 @@ master_service_init(const char *name, en
 		    int argc, char *argv[])
 {
 	struct master_service *service;
+	const char *str;
 
 	i_assert(name != NULL);
+
+#ifdef DEBUG
+	if (getenv("GDB") == NULL) {
+		int count;
+
+		str = getenv("SOCKET_COUNT");
+		count = str == NULL ? 0 : atoi(str);
+		fd_debug_verify_leaks(MASTER_LISTEN_FD_FIRST + count, 1024);
+	}
+#endif
 
 	/* NOTE: we start rooted, so keep the code minimal until
 	   restrict_access_by_env() is called */
@@ -95,6 +106,9 @@ master_service_init(const char *name, en
 	} else {
 		service->version_string = PACKAGE_VERSION;
 	}
+	str = getenv("SOCKET_COUNT");
+	if (str != NULL)
+		service->socket_count = atoi(str);
 
 	/* set up some kind of logging until we know exactly how and where
 	   we want to log */
diff -r 7b3accdf44f8 -r 7def7fa61d68 src/log/log-connection.c
--- a/src/log/log-connection.c	Mon May 04 18:28:17 2009 -0400
+++ b/src/log/log-connection.c	Mon May 04 20:24:57 2009 -0400
@@ -1,6 +1,7 @@
 /* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
 
 #include "common.h"
+#include "array.h"
 #include "ioloop.h"
 #include "llist.h"
 #include "hash.h"
@@ -8,6 +9,8 @@
 #include "master-service.h"
 #include "log-connection.h"
 
+#include <stdio.h>
+#include <stdlib.h>
 #include <unistd.h>
 
 #define FATAL_QUEUE_TIMEOUT_MSECS 500
@@ -26,10 +29,12 @@ struct log_connection {
 	char *prefix;
 	struct hash_table *clients;
 
+	unsigned int master:1;
 	unsigned int handshaked:1;
 };
 
 static struct log_connection *log_connections = NULL;
+static ARRAY_DEFINE(logs_by_fd, struct log_connection *);
 
 static struct log_client *log_client_get(struct log_connection *log, pid_t pid)
 {
@@ -52,53 +57,71 @@ static void log_parse_ip(struct log_conn
 	(void)net_addr2ip(failure->text + 3, &client->ip);
 }
 
-static void log_remove_pid(struct log_connection *log, pid_t pid)
-{
-	struct log_client *client;
-
+static void log_parse_option(struct log_connection *log,
+			     const struct failure_line *failure)
+{
+	if (strncmp(failure->text, "ip=", 3) == 0)
+		log_parse_ip(log, failure);
+}
+
+static void log_parse_master_line(const char *line)
+{
+	struct log_connection *const *logs, *log;
+	struct log_client *client;
+	const char *p, *p2;
+	unsigned int count;
+	int service_fd;
+	long pid;
+
+	p = strchr(line, ' ');
+	if (p == NULL || (p2 = strchr(++p, ' ')) == NULL) {
+		i_error("Received invalid input from master: %s", line);
+		return;
+	}
+	service_fd = atoi(t_strcut(line, ' '));
+	pid = strtol(t_strcut(p, ' '), NULL, 10);
+
+	logs = array_get(&logs_by_fd, &count);
+	if (service_fd >= (int)count || logs[service_fd] == NULL) {
+		i_error("Received master input for invalid service_fd %d: %s",
+			service_fd, line);
+		return;
+	}
+	log = logs[service_fd];
 	client = hash_table_lookup(log->clients, POINTER_CAST(pid));
-	if (client != NULL) {
+	line = p2 + 1;
+
+	if (strcmp(line, "BYE") == 0) {
+		if (client == NULL) {
+			/* we haven't seen anything important from this client.
+			   it's not an error. */
+			return;
+		}
 		hash_table_remove(log->clients, POINTER_CAST(pid));
 		i_free(client);
-	}
-}
-
-static void log_parse_option(struct log_connection *log,
-			     const struct failure_line *failure)
-{
-	if (strncmp(failure->text, "ip=", 3) == 0)
-		log_parse_ip(log, failure);
-	else if (strcmp(failure->text, "bye") == 0)
-		log_remove_pid(log, failure->pid);
-}
-
-static bool
-log_handle_seen_fatal(struct log_connection *log, const char **_text)
-{
-	const char *text = *_text;
-	struct log_client *client;
-	pid_t pid = 0;
-
-	while (*text >= '0' && *text <= '9') {
-		pid = pid*10 + (*text - '0');
-		text++;
-	}
-	if (*text != ' ' || pid == 0)
-		return FALSE;
-	*_text = text;
-
-	client = hash_table_lookup(log->clients, POINTER_CAST(pid));
-	if (client != NULL && client->fatal_logged) {
-		log_remove_pid(log, pid);
-		return TRUE;
-	}
-	return FALSE;
+	} else if (strncmp(line, "DEFAULT-FATAL ", 14) == 0) {
+		/* If the client has logged a fatal/panic, don't log this
+		   message. */
+		if (client == NULL || !client->fatal_logged)
+			i_error("%s", line + 14);
+		else {
+			hash_table_remove(log->clients, POINTER_CAST(pid));
+			i_free(client);
+		}
+	} else {
+		i_error("Received unknown command from master: %s", line);
+	}
 }
 
 static void log_it(struct log_connection *log, const char *line)
 {
 	struct failure_line failure;
 	struct log_client *client;
+
+	if (log->master) {
+		log_parse_master_line(line);
+		return;
+	}
 
 	i_failure_parse_line(line, &failure);
 	switch (failure.log_type) {
@@ -107,20 +130,6 @@ static void log_it(struct log_connection
 		client = log_client_get(log, failure.pid);
 		client->fatal_logged = TRUE;
 		break;
-	case LOG_TYPE_ERROR_IGNORE_IF_SEEN_FATAL:
-		/* Special case for master connection. If the following PID
-		   has logged a fatal/panic, don't log this message. */
-		failure.log_type = LOG_TYPE_ERROR;
-		if (failure.pid != master_pid) {
-			i_error("Non-master process %s "
-				"sent LOG_TYPE_ERROR_IGNORE_IF_SEEN_FATAL",
-				dec2str(failure.pid));
-			break;
-		}
-
-		if (log_handle_seen_fatal(log, &failure.text))
-			return;
-		break;
 	case LOG_TYPE_OPTION:
 		log_parse_option(log, &failure);
 		return;
@@ -150,6 +159,14 @@ static bool log_connection_handshake(str
 		log->prefix = i_strndup(*data + sizeof(handshake),
 					handshake.prefix_len);
 		*data += sizeof(handshake) + handshake.prefix_len;
+	}
+	if (strcmp(log->prefix, MASTER_LOG_PREFIX_NAME) == 0) {
+		if (log->fd != MASTER_LISTEN_FD_FIRST) {
+			i_error("Received master prefix in handshake "
+				"from non-master fd %d", log->fd);
+			return FALSE;
+		}
+		log->master = TRUE;
 	}
 	log->handshaked = TRUE;
 	return TRUE;
@@ -171,7 +188,7 @@ static void log_connection_input(struct 
 
 	line = data;
 	if (!log->handshaked)
-		log_connection_handshake(log, &line, ret);
+		(void)log_connection_handshake(log, &line, ret);
 
 	p = line;
 	while ((p = strchr(line, '\n')) != NULL) {
@@ -194,6 +211,7 @@ struct log_connection *log_connection_cr
 	log->io = io_add(fd, IO_READ, log_connection_input, log);
 	log->clients = hash_table_create(default_pool, default_pool, 0,
 					 NULL, NULL);
+	array_idx_set(&logs_by_fd, fd, &log);
 
 	DLLIST_PREPEND(&log_connections, log);
 	log_connection_input(log);
@@ -204,6 +222,8 @@ void log_connection_destroy(struct log_c
 {
 	struct hash_iterate_context *iter;
 	void *key, *value;
+
+	array_idx_clear(&logs_by_fd, log->fd);
 
 	DLLIST_REMOVE(&log_connections, log);
 
@@ -215,10 +235,17 @@ void log_connection_destroy(struct log_c
 
 	if (log->io != NULL)
 		io_remove(&log->io);
+	if (close(log->fd) < 0)
+		i_error("close(log connection fd) failed: %m");
 	i_free(log->prefix);
 	i_free(log);
 
         master_service_client_connection_destroyed(service);
+}
+
+void log_connections_init(void)
+{
+	i_array_init(&logs_by_fd, 64);
 }
 
 void log_connections_deinit(void)
@@ -227,4 +254,5 @@ void log_connections_deinit(void)
 	   but we could get here when we're being killed by a signal */
 	while (log_connections != NULL)
 		log_connection_destroy(log_connections);
-}
+	array_free(&logs_by_fd);
+}
diff -r 7b3accdf44f8 -r 7def7fa61d68 src/log/log-connection.h
--- a/src/log/log-connection.h	Mon May 04 18:28:17 2009 -0400
+++ b/src/log/log-connection.h	Mon May 04 20:24:57 2009 -0400
@@ -4,6 +4,7 @@ struct log_connection *log_connection_cr
 struct log_connection *log_connection_create(int fd);
 void log_connection_destroy(struct log_connection *log);
 
+void log_connections_init(void);
 void log_connections_deinit(void);
 
 #endif
diff -r 7b3accdf44f8 -r 7def7fa61d68 src/log/main.c
--- a/src/log/main.c	Mon May 04 18:28:17 2009 -0400
+++ b/src/log/main.c	Mon May 04 20:24:57 2009 -0400
@@ -31,6 +31,7 @@ static void main_init(void)
 	lib_signals_set_handler(SIGUSR1, TRUE, sig_reopen_logs, NULL);
 
 	master_pid = getppid();
+	log_connections_init();
 }
 
 static void main_deinit(void)
diff -r 7b3accdf44f8 -r 7def7fa61d68 src/master/service-log.c
--- a/src/master/service-log.c	Mon May 04 18:28:17 2009 -0400
+++ b/src/master/service-log.c	Mon May 04 20:24:57 2009 -0400
@@ -2,61 +2,86 @@


More information about the dovecot-cvs mailing list