2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-30 05:38:06 +00:00

snapshot-20010720

This commit is contained in:
Wietse Venema 2001-07-20 00:00:00 -05:00 committed by Viktor Dukhovni
parent 0491e41ef6
commit 57cf9e9793
24 changed files with 301 additions and 16 deletions

View File

@ -5347,3 +5347,16 @@ Apologies for any names omitted.
Logging: the queue manager now logs a "status=expired"
record when it returns a message that is too old. Files:
*qmgr/qmgr_active.c.
20010719
Feature: stiffer coupling between mail arrival rates and
mail delivery rates, using a trivial token-based scheme
where qmgr provides a token when it retrieves mail from
the incoming queue, and where the cleanup daemon wants a
token after enqueueing mail. If no token is available the
cleanup server pauses briefly and proceeds anyway. This
allows input rates to gradually exceed output rates. After
sustained exposure to high input loads Postfix reverts to
the old situation where it sacrifices output rates in favor
of receiving mail.

View File

@ -163,7 +163,8 @@ mail_owner = postfix
# address.
#
# You can also specify the absolute pathname of a pattern file instead
# of listing the patterns here.
# of listing the patterns here. Specify type:name for table-based lookups
# (the value on the table right-hand side is not used).
#
#mynetworks = 168.100.189.0/28, 127.0.0.0/8
#mynetworks = $config_directory/mynetworks

View File

@ -135,7 +135,8 @@ mynetworks_style = subnet
# address.
#
# You can also specify the absolute pathname of a pattern file instead
# of listing the patterns here.
# of listing the patterns here. Specify type:name for table-based lookups
# (the value on the table right-hand side is not used).
#
#mynetworks = 168.100.189.0/28, 127.0.0.0/8
#mynetworks = $config_directory/mynetworks

View File

@ -75,6 +75,7 @@ cleanup.o: ../../include/iostuff.h
cleanup.o: ../../include/mail_params.h
cleanup.o: ../../include/record.h
cleanup.o: ../../include/rec_type.h
cleanup.o: ../../include/mail_flow.h
cleanup.o: ../../include/mail_server.h
cleanup.o: cleanup.h
cleanup.o: ../../include/maps.h

View File

@ -271,5 +271,6 @@ int main(int argc, char **argv)
MAIL_SERVER_PRE_INIT, cleanup_pre_jail,
MAIL_SERVER_POST_INIT, cleanup_post_jail,
MAIL_SERVER_PRE_ACCEPT, pre_accept,
MAIL_SERVER_FLOW_CTL,
0);
}

View File

@ -69,6 +69,7 @@
/* char *var_export_environ;
/* char *var_debug_peer_list;
/* int var_debug_peer_level;
/* int var_glob_flow_ctl;
/*
/* void mail_params_init()
/* DESCRIPTION
@ -185,6 +186,7 @@ char *var_def_transport;
char *var_mynetworks_style;
char *var_verp_delims;
char *var_verp_filter;
int var_glob_flow_ctl;
char *var_import_environ;
char *var_export_environ;
@ -325,6 +327,7 @@ void mail_params_init()
VAR_FORK_TRIES, DEF_FORK_TRIES, &var_fork_tries, 1, 0,
VAR_FLOCK_TRIES, DEF_FLOCK_TRIES, &var_flock_tries, 1, 0,
VAR_DEBUG_PEER_LEVEL, DEF_DEBUG_PEER_LEVEL, &var_debug_peer_level, 1, 0,
VAR_GLOB_FLOW_CTL, DEF_GLOB_FLOW_CTL, &var_glob_flow_ctl, 0, 0,
0,
};
static CONFIG_TIME_TABLE time_defaults[] = {

View File

@ -1283,6 +1283,17 @@ extern char *var_verp_delims;
#define DEF_VERP_FILTER "-=+"
extern char *var_verp_filter;
/*
* Global flow control. This allows for a stiffer coupling between receiving
* programs and the queue manager, so that receiving processes cannot easily
* overwhelm the file system. The coupling is not so tight that Postfix
* stops receiving mail althogether. It just slows down a bit so that
* sending processes get a chance to read from the disk.
*/
#define VAR_GLOB_FLOW_CTL "global_mail_flow_control"
#define DEF_GLOB_FLOW_CTL 0
extern int var_glob_flow_ctl;
/* LICENSE
/* .ad
/* .fi

View File

@ -15,7 +15,7 @@
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "Snapshot-20010714"
#define DEF_MAIL_VERSION "Snapshot-20010720"
extern char *var_mail_version;
/* LICENSE

View File

@ -2,12 +2,13 @@ SHELL = /bin/sh
SRCS = master.c master_conf.c master_ent.c master_sig.c master_avail.c \
master_spawn.c master_service.c master_status.o master_listen.c \
master_proto.c single_server.c multi_server.c master_vars.c \
master_wakeup.c
master_wakeup.c master_flow.c mail_flow.c
OBJS = master.o master_conf.o master_ent.o master_sig.o master_avail.o \
master_spawn.o master_service.o master_status.o master_listen.o \
master_vars.o master_wakeup.o
LIB_OBJ = single_server.o multi_server.o trigger_server.o master_proto.o
HDRS = mail_server.h master_proto.h
master_vars.o master_wakeup.o master_flow.o
LIB_OBJ = single_server.o multi_server.o trigger_server.o master_proto.o \
mail_flow.o
HDRS = mail_server.h master_proto.h mail_flow.h
INT_HDR = master.h
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
-Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
@ -78,6 +79,11 @@ depend: $(MAKES)
@$(EXPORT) make -f Makefile.in Makefile 1>&2
# do not edit below this line - it is generated by 'make depend'
mail_flow.o: mail_flow.c
mail_flow.o: ../../include/sys_defs.h
mail_flow.o: ../../include/msg.h
mail_flow.o: mail_flow.h
mail_flow.o: master_proto.h
master.o: master.c
master.o: ../../include/sys_defs.h
master.o: ../../include/events.h
@ -129,6 +135,12 @@ master_ent.o: ../../include/mail_params.h
master_ent.o: ../../include/own_inet_addr.h
master_ent.o: master_proto.h
master_ent.o: master.h
master_flow.o: master_flow.c
master_flow.o: ../../include/sys_defs.h
master_flow.o: ../../include/msg.h
master_flow.o: ../../include/iostuff.h
master_flow.o: master.h
master_flow.o: master_proto.h
master_listen.o: master_listen.c
master_listen.o: ../../include/sys_defs.h
master_listen.o: ../../include/msg.h

View File

@ -0,0 +1,112 @@
/*++
/* NAME
/* mail_flow 3
/* SUMMARY
/* global mail flow control
/* SYNOPSIS
/* #include <mail_flow.h>
/*
/* int mail_flow_get(count)
/* int count;
/*
/* void mail_flow_put(count)
/* int count;
/* DESCRIPTION
/* This module implements a simple flow control mechanism that
/* is based on tokens that are consumed by mail receiving processes
/* and that are produced by mail sending processes.
/*
/* mail_flow_get() attempts to read specified number of tokens. The
/* result is > 0 for success, < 0 for failure. In the latter case,
/* the process is expected to slow down a little.
/*
/* mail_flow_put() produces the specified number of tokens. The
/* token producing process is expected to produce new tokens
/* whenever it falls idle and no more tokens are available.
/* BUGS
/* The producer needs to wake up periodically to ensure that
/* tokens are not lost due to leakage.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/
/* System library. */
#include <sys_defs.h>
#include <unistd.h>
#include <stdlib.h>
/* Utility library. */
#include <msg.h>
/* Global library. */
#include <mail_flow.h>
/* Master library. */
#include <master_proto.h>
#define BUFFER_SIZE 1024
/* mail_flow_get - read N tokens */
int mail_flow_get(int len)
{
char *myname = "mail_flow_get";
char buf[BUFFER_SIZE];
int count;
int n = 0;
/*
* Sanity check.
*/
if (len <= 0)
msg_panic("%s: bad length %d", myname, len);
/*
* Read and discard N bytes.
*/
for (count = len; count > 0; count -= n)
if ((n = read(MASTER_FLOW_READ, buf, count > BUFFER_SIZE ?
BUFFER_SIZE : count)) < 0)
return (-1);
if (msg_verbose)
msg_info("%s: %d %d", myname, len, len - count);
return (len - count);
}
/* mail_flow_put - put N tokens */
int mail_flow_put(int len)
{
char *myname = "mail_flow_put";
char buf[BUFFER_SIZE];
int count;
int n = 0;
/*
* Sanity check.
*/
if (len <= 0)
msg_panic("%s: bad length %d", myname, len);
/*
* Read and discard N bytes.
*/
for (count = len; count > 0; count -= n)
if ((n = read(MASTER_FLOW_READ, buf, count > BUFFER_SIZE ?
BUFFER_SIZE : count)) < 0)
return (-1);
if (msg_verbose)
msg_info("%s: %d %d", myname, len, len - count);
return (len - count);
}

View File

@ -0,0 +1,31 @@
#ifndef _MAIL_FLOW_H_INCLUDED_
#define _MAIL_FLOW_H_INCLUDED_
/*++
/* NAME
/* mail_flow 3h
/* SUMMARY
/* global mail flow control
/* SYNOPSIS
/* #include <mail_flow.h>
/* DESCRIPTION
/* .nf
/*
* Functional interface.
*/
extern int mail_flow_get(int);
extern int mail_flow_put(int);
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/
#endif

View File

@ -28,6 +28,8 @@
#define MAIL_SERVER_EXIT 13
#define MAIL_SERVER_PRE_ACCEPT 14
#define MAIL_SERVER_FLOW_CTL 20
typedef void (*MAIL_SERVER_INIT_FN) (char *, char **);
typedef int (*MAIL_SERVER_LOOP_FN) (char *, char **);
typedef void (*MAIL_SERVER_EXIT_FN) (char *, char **);

View File

@ -256,8 +256,11 @@ int main(int argc, char **argv)
* when a service listens on many ports. In order to do this right we
* must change the master-child interface so that descriptors do not need
* to have fixed numbers.
*
* In a child we need two descriptors for the flow control pipe, one for
* child->master status updates and at least one for listening.
*/
for (n = 0; n < 3; n++) {
for (n = 0; n < 5; n++) {
if (close_on_exec(dup(0), CLOSE_ON_EXEC) < 0)
msg_fatal("dup(0): %m");
}
@ -349,6 +352,7 @@ int main(int argc, char **argv)
*/
master_config();
master_sigsetup();
master_flow_init();
msg_info("daemon started");
/*

View File

@ -162,6 +162,12 @@ extern void master_spawn(MASTER_SERV *);
extern void master_reap_child(void);
extern void master_delete_children(MASTER_SERV *);
/*
* master_flow.c
*/
void master_flow_init(void);
int master_flow_pipe[2];
/* DIAGNOSTICS
/* BUGS
/* SEE ALSO

View File

@ -0,0 +1,30 @@
/* System library. */
#include <sys_defs.h>
#include <unistd.h>
#include <stdlib.h>
/* Utility library. */
#include <msg.h>
#include <iostuff.h>
/* Application-specific. */
#include <master.h>
#include <master_proto.h>
int master_flow_pipe[2];
/* master_flow_init - initialize the flow control channel */
void master_flow_init(void)
{
char *myname = "master_flow_init";
if (pipe(master_flow_pipe) < 0)
msg_fatal("%s: pipe: %m", myname);
non_blocking(master_flow_pipe[0], NON_BLOCKING);
non_blocking(master_flow_pipe[1], NON_BLOCKING);
}

View File

@ -31,6 +31,14 @@ typedef struct MASTER_STATUS {
extern int master_notify(int, int); /* encapsulate status msg */
/*
* File descriptors inherited from the master process. The flow control pipe
* is read by receive processes and is written to by send processes. If
* receive processes get too far ahead they will pause for a brief moment.
*/
#define MASTER_FLOW_READ 3
#define MASTER_FLOW_WRITE 4
/*
* File descriptors inherited from the master process. All processes that
* provide a given service share the same status file descriptor, and listen
@ -41,8 +49,8 @@ extern int master_notify(int, int); /* encapsulate status msg */
* actually the lowest-numbered descriptor of a sequence of descriptors to
* listen on.
*/
#define MASTER_STATUS_FD 3 /* shared channel to parent */
#define MASTER_LISTEN_FD 4 /* accept connections here */
#define MASTER_STATUS_FD 5 /* shared channel to parent */
#define MASTER_LISTEN_FD 6 /* accept connections here */
/* LICENSE
/* .ad

View File

@ -175,6 +175,23 @@ void master_spawn(MASTER_SERV *serv)
case 0:
msg_cleanup((void (*) (void)) 0); /* disable exit handler */
closelog(); /* avoid filedes leak */
if (master_flow_pipe[0] <= MASTER_FLOW_READ)
msg_fatal("%s: flow pipe read descriptor <= %d",
myname, MASTER_FLOW_READ);
if (DUP2(master_flow_pipe[0], MASTER_FLOW_READ) < 0)
msg_fatal("%s: dup2: %m", myname);
if (close(master_flow_pipe[0]) < 0)
msg_fatal("close %d: %m", master_flow_pipe[0]);
if (master_flow_pipe[1] <= MASTER_FLOW_WRITE)
msg_fatal("%s: flow pipe read descriptor <= %d",
myname, MASTER_FLOW_WRITE);
if (DUP2(master_flow_pipe[1], MASTER_FLOW_WRITE) < 0)
msg_fatal("%s: dup2: %m", myname);
if (close(master_flow_pipe[1]) < 0)
msg_fatal("close %d: %m", master_flow_pipe[1]);
close(serv->status_fd[0]); /* status channel */
if (serv->status_fd[1] <= MASTER_STATUS_FD)
msg_fatal("%s: status file descriptor collision", myname);

View File

@ -611,6 +611,8 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
}
event_enable_read(MASTER_STATUS_FD, multi_server_abort, (char *) 0);
close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC);
close_on_exec(MASTER_FLOW_READ, CLOSE_ON_EXEC);
close_on_exec(MASTER_FLOW_WRITE, CLOSE_ON_EXEC);
watchdog = watchdog_create(var_daemon_timeout, (WATCHDOG_FN) 0, (char *) 0);
/*

View File

@ -162,6 +162,7 @@
#include <mail_conf.h>
#include <timed_ipc.h>
#include <resolve_local.h>
#include <mail_flow.h>
/* Process manager. */
@ -183,6 +184,7 @@ static void (*single_server_accept) (int, char *);
static void (*single_server_onexit) (char *, char **);
static void (*single_server_pre_accept) (char *, char **);
static VSTREAM *single_server_lock;
static int single_server_flow_ctl;
/* single_server_exit - normal termination */
@ -238,6 +240,9 @@ static void single_server_wakeup(int fd)
if (msg_verbose)
msg_info("connection closed");
use_count++;
if (single_server_flow_ctl)
if (mail_flow_get(1) < 0)
rand_sleep(single_server_flow_ctl, 0);
if (var_idle_limit > 0)
event_request_timer(single_server_timeout, (char *) 0, var_idle_limit);
}
@ -469,6 +474,9 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
case MAIL_SERVER_PRE_ACCEPT:
single_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN);
break;
case MAIL_SERVER_FLOW_CTL:
single_server_flow_ctl = var_glob_flow_ctl;
break;
default:
msg_panic("%s: unknown argument type: %d", myname, key);
}
@ -582,6 +590,8 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
}
event_enable_read(MASTER_STATUS_FD, single_server_abort, (char *) 0);
close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC);
close_on_exec(MASTER_FLOW_READ, CLOSE_ON_EXEC);
close_on_exec(MASTER_FLOW_WRITE, CLOSE_ON_EXEC);
watchdog = watchdog_create(var_daemon_timeout, (WATCHDOG_FN) 0, (char *) 0);
/*

View File

@ -593,6 +593,8 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,..
}
event_enable_read(MASTER_STATUS_FD, trigger_server_abort, (char *) 0);
close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC);
close_on_exec(MASTER_FLOW_READ, CLOSE_ON_EXEC);
close_on_exec(MASTER_FLOW_WRITE, CLOSE_ON_EXEC);
watchdog = watchdog_create(1000, (WATCHDOG_FN) 0, (char *) 0);
/*

View File

@ -298,6 +298,7 @@
#include <mail_conf.h>
#include <mail_params.h>
#include <mail_proto.h> /* QMGR_SCAN constants */
#include <mail_flow.h>
/* Master process interface */
@ -448,6 +449,17 @@ static int qmgr_loop(char *unused_name, char **unused_argv)
if (qmgr_message_count < var_qmgr_active_limit)
if ((df_path = qmgr_scan_next(qmgr_deferred)) != 0)
qmgr_active_feed(qmgr_deferred, df_path);
/*
* Global flow control. If enabled, slow down receiving processes that
* get ahead of the queue manager, but don't block them completely.
*/
if (var_glob_flow_ctl) {
if (in_path)
mail_flow_put(1);
else
mail_flow_get(1000);
}
if (in_path || df_path)
return (DONT_WAIT);
return (WAIT_FOR_EVENT);

View File

@ -90,9 +90,6 @@
/* \fBpostalias\fR terminates with zero exit status in case of success
/* (including successful \fBpostmap -q\fR lookup) and terminates
/* with non-zero exit status in case of failure.
/* BUGS
/* The "delete key" support is limited to one delete operation
/* per command invocation.
/* ENVIRONMENT
/* .ad
/* .fi

View File

@ -107,9 +107,6 @@
/* \fBpostmap\fR terminates with zero exit status in case of success
/* (including successful \fBpostmap -q\fR lookup) and terminates
/* with non-zero exit status in case of failure.
/* BUGS
/* The "delete key" support is limited to one delete operation
/* per command invocation.
/* ENVIRONMENT
/* .ad
/* .fi

View File

@ -262,6 +262,7 @@
#include <mail_conf.h>
#include <mail_params.h>
#include <mail_proto.h> /* QMGR_SCAN constants */
#include <mail_flow.h>
/* Master process interface */
@ -410,6 +411,17 @@ static int qmgr_loop(char *unused_name, char **unused_argv)
&& qmgr_recipient_count < var_qmgr_rcpt_limit)
if ((df_path = qmgr_scan_next(qmgr_deferred)) != 0)
qmgr_active_feed(qmgr_deferred, df_path);
/*
* Global flow control. If enabled, slow down receiving processes that
* get ahead of the queue manager, but don't block them completely.
*/
if (var_glob_flow_ctl) {
if (in_path)
mail_flow_put(1);
else
mail_flow_get(1000);
}
if (in_path || df_path)
return (DONT_WAIT);
return (WAIT_FOR_EVENT);