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