changeset 8649:67c08c386702 HEAD

Added dict_process_count setting for creating multiple dict processes.
author Timo Sirainen <tss@iki.fi>
date Sat, 17 Jan 2009 13:56:24 -0500
parents 5bd547dbb8fc
children 81fd92599c7f
files src/master/dict-process.c src/master/dict-process.h src/master/main.c src/master/master-settings-defs.c src/master/master-settings.c src/master/master-settings.h
diffstat 6 files changed, 111 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
--- a/src/master/dict-process.c	Sat Jan 17 13:41:44 2009 -0500
+++ b/src/master/dict-process.c	Sat Jan 17 13:56:24 2009 -0500
@@ -16,27 +16,37 @@
 
 #define DICT_SERVER_SOCKET_NAME "dict-server"
 
-struct dict_process {
-	struct child_process process;
+struct dict_listener {
 	char *path;
 	int fd;
+	struct io *io;
 
-	struct log_io *log;
-	struct io *io;
+	struct dict_process *processes;
 };
 
-static struct dict_process *dict_process;
+struct dict_process {
+	struct child_process process;
+	struct dict_process *next;
 
-static void dict_process_unlisten(struct dict_process *process);
+	struct dict_listener *listener;
+	struct log_io *log;
+};
 
-static int dict_process_start(struct dict_process *process)
+static struct dict_listener *dict_listener;
+
+static int dict_process_create(struct dict_listener *listener)
 {
+	struct dict_process *process;
 	struct log_io *log;
 	const char *executable, *const *dicts;
 	unsigned int i, count;
 	int log_fd;
 	pid_t pid;
 
+	process = i_new(struct dict_process, 1);
+	process->process.type = PROCESS_TYPE_DICT;
+	process->listener = listener;
+
 	log_fd = log_create_pipe(&log, 0);
 	if (log_fd < 0)
 		pid = -1;
@@ -48,11 +58,15 @@
 
 	if (pid < 0) {
 		(void)close(log_fd);
+		i_free(process);
 		return -1;
 	}
 
 	if (pid != 0) {
 		/* master */
+		process->next = process->listener->processes;
+		process->listener->processes = process;
+
 		child_process_add(pid, &process->process);
 		log_set_prefix(log, "dict: ");
 		log_set_pid(log, pid);
@@ -60,7 +74,6 @@
 
 		process->log = log;
 		log_ref(process->log);
-                dict_process_unlisten(process);
 		return 0;
 	}
 	log_set_prefix(log, "master-dict: ");
@@ -75,14 +88,15 @@
 	/* stderr = log, 3 = listener */
 	if (dup2(log_fd, 2) < 0)
 		i_fatal("dup2(stderr) failed: %m");
-	if (dup2(process->fd, 3) < 0)
+	if (dup2(process->listener->fd, 3) < 0)
 		i_fatal("dup2(3) failed: %m");
 
 	for (i = 0; i <= 3; i++)
 		fd_close_on_exec(i, FALSE);
 
 	child_process_init_env();
-	env_put(t_strconcat("DICT_LISTEN_FROM_FD=", process->path, NULL));
+	env_put(t_strconcat("DICT_LISTEN_FROM_FD=",
+			    process->listener->path, NULL));
 
 	if (settings_root->defaults->dict_db_config != NULL) {
 		env_put(t_strconcat("DB_CONFIG=",
@@ -105,92 +119,118 @@
 	return -1;
 }
 
-static void dict_process_listen_input(struct dict_process *process)
+static void dict_process_deinit(struct dict_process *process)
 {
-	i_assert(process->log == NULL);
-	dict_process_start(process);
+	struct dict_process **p;
+
+	for (p = &process->listener->processes; *p != NULL; p++) {
+		if (*p == process) {
+			*p = process->next;
+			break;
+		}
+	}
+
+	if (process->log != NULL)
+		log_unref(process->log);
+	i_free(process);
 }
 
-static int dict_process_listen(struct dict_process *process)
+static void dict_listener_input(struct dict_listener *listener)
 {
+	unsigned int i;
+	int fd;
+
+	i_assert(listener->processes == NULL);
+
+	for (i = 0; i < settings_root->defaults->dict_process_count; i++) {
+		if (dict_process_create(listener) < 0)
+			break;
+	}
+	if (i > 0)
+		io_remove(&listener->io);
+	else {
+		/* failed to create dict process, so just reject this
+		   connection and try again later */
+		fd = net_accept(listener->fd, NULL, NULL);
+		if (fd >= 0)
+			(void)close(fd);
+	}
+}
+
+static struct dict_listener *dict_listener_init(const char *path)
+{
+	struct dict_listener *listener;
 	mode_t old_umask;
 
+	listener = i_new(struct dict_listener, 1);
+	listener->path = i_strdup(path);
 	old_umask = umask(0);
-	process->fd = net_listen_unix_unlink_stale(process->path, 128);
+	listener->fd = net_listen_unix_unlink_stale(path, 128);
 	umask(old_umask);
-	if (process->fd == -1) {
+	if (listener->fd == -1) {
 		if (errno == EADDRINUSE)
-			i_error("Socket already exists: %s", process->path);
+			i_fatal("Socket already exists: %s", path);
 		else
-			i_error("net_listen_unix(%s) failed: %m", process->path);
-		return -1;
+			i_fatal("net_listen_unix(%s) failed: %m", path);
 	}
-	fd_close_on_exec(process->fd, TRUE);
-	process->io = io_add(process->fd, IO_READ,
-			     dict_process_listen_input, process);
-
-	return process->fd != -1 ? 0 : -1;
+	fd_close_on_exec(listener->fd, TRUE);
+	listener->io = io_add(listener->fd, IO_READ,
+			      dict_listener_input, listener);
+	return listener;
 }
 
-static void dict_process_unlisten(struct dict_process *process)
+static void dict_listener_deinit(struct dict_listener *listener)
 {
-	if (process->fd == -1)
-		return;
+	if (listener->io != NULL)
+		io_remove(&listener->io);
+	if (close(listener->fd) < 0)
+		i_error("close(dict listener) failed: %m");
 
-	io_remove(&process->io);
-
-	if (close(process->fd) < 0)
-		i_error("close(dict) failed: %m");
-	process->fd = -1;
+	while (listener->processes != NULL)
+		dict_process_deinit(listener->processes);
 }
 
 static void
-dict_process_destroyed(struct child_process *process,
-		       pid_t pid ATTR_UNUSED,
-		       bool abnormal_exit ATTR_UNUSED)
+dict_process_destroyed(struct child_process *_process,
+		       pid_t pid ATTR_UNUSED, bool abnormal_exit ATTR_UNUSED)
 {
-	struct dict_process *p = (struct dict_process *)process;
+	struct dict_process *process = (struct dict_process *)_process;
+	struct dict_listener *listener = process->listener;
 
-	if (p->log != NULL) {
-		/* not killed by ourself */
-		log_unref(p->log);
-		p->log = NULL;
+	dict_process_deinit(process);
+	if (listener->processes == NULL) {
+		/* last listener died, create new ones */
+		listener->io = io_add(listener->fd, IO_READ,
+				      dict_listener_input, listener);
 	}
-	(void)dict_process_listen(p);
 }
 
-void dict_process_init(void)
+void dict_processes_init(void)
 {
-	struct dict_process *process;
+	const char *path;
 
-	process = dict_process = i_new(struct dict_process, 1);
-	process->process.type = PROCESS_TYPE_DICT;
-	process->fd = -1;
-	process->path = i_strconcat(settings_root->defaults->base_dir,
-				    "/"DICT_SERVER_SOCKET_NAME, NULL);
-	(void)dict_process_listen(process);
+	path = t_strconcat(settings_root->defaults->base_dir,
+			   "/"DICT_SERVER_SOCKET_NAME, NULL);
+	dict_listener = dict_listener_init(path);
 
 	child_process_set_destroy_callback(PROCESS_TYPE_DICT,
 					   dict_process_destroyed);
 }
 
-void dict_process_deinit(void)
+void dict_processes_deinit(void)
 {
-	struct dict_process *process = dict_process;
-
-	dict_process_unlisten(process);
-	if (process->log != NULL)
-		log_unref(process->log);
-	i_free(process->path);
-	i_free(process);
+	dict_listener_deinit(dict_listener);
 }
 
-void dict_process_kill(void)
+void dict_processes_kill(void)
 {
-	struct dict_process *process = dict_process;
+	struct dict_process *process;
 
-	if (process->log != NULL) {
-		log_unref(process->log);
-		process->log = NULL;
+	process = dict_listener->processes;
+	for (; process != NULL; process = process->next) {
+		if (process->log != NULL) {
+			log_unref(process->log);
+			process->log = NULL;
+		}
 	}
 }
--- a/src/master/dict-process.h	Sat Jan 17 13:41:44 2009 -0500
+++ b/src/master/dict-process.h	Sat Jan 17 13:56:24 2009 -0500
@@ -1,8 +1,8 @@
 #ifndef DICT_PROCESS_H
 #define DICT_PROCESS_H
 
-void dict_process_init(void);
-void dict_process_deinit(void);
-void dict_process_kill(void);
+void dict_processes_init(void);
+void dict_processes_deinit(void);
+void dict_processes_kill(void);
 
 #endif
--- a/src/master/main.c	Sat Jan 17 13:41:44 2009 -0500
+++ b/src/master/main.c	Sat Jan 17 13:56:24 2009 -0500
@@ -151,7 +151,7 @@
 	/* restart auth and login processes */
         login_processes_destroy_all();
         auth_processes_destroy_all();
-        dict_process_kill();
+        dict_processes_kill();
 
 	/* see if hostname changed */
 	hostpid_init();
@@ -304,7 +304,7 @@
 	child_processes_init();
 	log_init();
 	ssl_init();
-	dict_process_init();
+	dict_processes_init();
 	auth_processes_init();
 	login_processes_init();
 	mail_processes_init();
@@ -323,7 +323,7 @@
 	mail_processes_deinit();
 	login_processes_deinit();
 	auth_processes_deinit();
-	dict_process_deinit();
+	dict_processes_deinit();
 	ssl_deinit();
 	child_processes_deinit();
 
--- a/src/master/master-settings-defs.c	Sat Jan 17 13:41:44 2009 -0500
+++ b/src/master/master-settings-defs.c	Sat Jan 17 13:56:24 2009 -0500
@@ -128,6 +128,7 @@
 
 	/* dict */
 	DEF_STR(dict_db_config),
+	DEF_INT(dict_process_count),
 
 	{ 0, NULL, 0 }
 };
--- a/src/master/master-settings.c	Sat Jan 17 13:41:44 2009 -0500
+++ b/src/master/master-settings.c	Sat Jan 17 13:56:24 2009 -0500
@@ -294,6 +294,7 @@
 
 	/* dict */
 	MEMBER(dict_db_config) NULL,
+	MEMBER(dict_process_count) 1,
 
 	/* .. */
 };
--- a/src/master/master-settings.h	Sat Jan 17 13:41:44 2009 -0500
+++ b/src/master/master-settings.h	Sat Jan 17 13:56:24 2009 -0500
@@ -140,6 +140,7 @@
 
 	/* dict */
 	const char *dict_db_config;
+	unsigned int dict_process_count;
 
 	/* .. */
 	ARRAY_TYPE(listener) listens;