Ключевые слова:patch, sendmail, (найти похожие документы)
Date: Thu, 7 Feb 2002 20:22:40 +0000 (UTC)
From: Valentin Nechayev <netch@segfault.kiev.ua>
Newsgroups: fido7.ru.unix.bsd
Subject: Патч для ограничения колличества sendmail процессов
> > Я искал как ограничить количество тех процессов, что отфоркиваются при
> > 1) генерации отлупов, 2) фоновом запуске доставки при DeliveryMode=background.
> Тогда решение - в студию (и FAQ) :-))))
Вот такой он - сразу ему решение подавай...
Ладно, см. конец письма. Это для sendall() - через него управление
проходит, если не поднят флаг doublequeue. Если поднят - тогда идет через
dowork(), там аналогично, но в cvs еще не вносил.
FAQ не может быть потому что вопросы еще никто не задавал;))
> > Тормозов не заметил, абсолютно. Причем не три access() а три open()+flock()
> Что ещё хуже.
Чем хуже-то? Номера инодов фактически в name cache, каталог очереди -
в dir cache.
> > Типа да. Ассманн, Шапиро...
> В таких развесистых долгих проектах код расползается, как тараканы.
Это без качественного дизайна.
sendmail в этом плане вообще ужас. В качестве примера, рекомендую почитать
dropenvelope(): с одной стороны, там генерируются отлупы; с другой стороны,
это деструктор объекта "письмо"; с третьей стороны, это часть конструктора
объекта "письмо", которая действует после начального bzero()!
Я вообще не понимаю как можно в таком бардаке достигать какого-то
существенного прогресса...
> Удивительно, что всего в двух (?) местах пришлось править - у M$
> каждый программист с собой копию stdlib тянет со своими isalpha()/isdigit()/etc :-))
Sendmail 8.12 тянет вообще свой stdio. Правда, под BSD его не включает -
возможности BSD'шного удовлетворяют. Под glibc не смотрел, что делает.
Два места - это уже специфика того, как sendmail обходится с ситуацией
изменения списка получателей. В srvrsmtp.c есть такой кусок:
SmtpPhase = "delivery";
e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp);
id = e->e_id;
if (doublequeue)
{
/* make sure it is in the queue */
queueup(e, FALSE);
}
else
{
/* send to all recipients */
sendall(e, SM_DEFAULT);
}
e->e_to = NULL;
/* issue success message */
message("250 %s Message accepted for delivery", id);
/* if we just queued, poke it */
if (doublequeue &&
e->e_sendmode != SM_QUEUE &&
e->e_sendmode != SM_DEFER)
{
CurrentLA = getla();
if (!shouldqueue(e->e_msgpriority, e->e_ctime))
{
unlockqueue(e);
(void) dowork(id, TRUE, TRUE, e);
}
}
вот в нем и заключена злополучная развилка. Вызовы sendall() и dowork() здесь -
два варианта, когда доставка уходит в фоновый процесс; doublequeue -
флаг, который подымается, если получатели раскрывались (по крайней мере,
я так понял - логика там темная, замечал уже по результатам).
Когда-то это, наверно, имело заметный смысл. Но сейчас от этого больше
путаницы, чем пользы.
> > оседают в своп - чтобы в памяти не лежать - и оттуда обычно не возвращаются.
> > Часто лежит еще что-то.
> О нашёл - на DDT после 64 дней в свопе аж 116 кил! :-)))
> Сильно бездельничающей я бы её не назвал - одних nnrpd 180 штук,
> и CGP на ней нет :((( Видимо, всё же нужно памяти в ваши релеи
> довоткнуть - говорят, она всё ещё дешёвая.
BSD будет высвоплять ненужное независимо от объема памяти, так уж
VM устроена. А подымать этим память только ради того чтобы оно делало
thrashing на один раз в сутки меньше... не думаю, что это того стоит.;))
Хотя память добавлять, естественно, будем. По плану.;))
/netch
Index: deliver.c
RCS file: /usr/homes/netch/Cvsroot/luckynet/sendmail/8.9/src/deliver.c,v
retrieving revision 1.7
retrieving revision 1.11
diff -u -r1.7 -r1.11
--- deliver.c 2000/12/04 13:41:21 1.7
+++ deliver.c 2001/12/19 12:59:02 1.11
@@ -8,10 +8,11 @@
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
+ * @(#)deliver.c 8.367 (Berkeley) 1/18/1999
*/
#ifndef lint
-static char sccsid[] = "@(#)deliver.c 8.367 (Berkeley) 1/18/1999";
+static char sccsid[] = "@(#)$Id: deliver.c,v 1.11 2001/12/19 12:59:02 netch Exp $";
#endif /* not lint */
#include "sendmail.h"
@@ -65,6 +66,12 @@
bool somedeliveries = FALSE, expensive = FALSE;
pid_t pid;
void sendenvelope __P((ENVELOPE *, int));
+#define _NXLA
+#if defined(_NXLA)
+ int fd_worklock = -1;
+ char P[1024];
+ int ii, rval, nmax;
+#endif
/*
** If this message is to be discarded, don't bother sending
@@ -544,6 +551,47 @@
pid = fork();
if (pid > 0)
exit(EX_OK);
+ /*sm_syslog( LOG_INFO, e->e_id, "_: sendall(): double fork" );*/
+#if defined(_NXLA)
+ nmax = MaxChildren;
+ if( nmax <= 0 )
+ nmax = RefuseLA;
+ if( nmax <= 0 )
+ nmax = 10;
+ fd_worklock = -1;
+ srand(time(NULL)+getpid());
+ for( ii = 1; ii <= 3; ii++ ) {
+ int se;
+ rval = rand() % nmax;
+ snprintf( P, sizeof P,
+ "%s/dowork_lock.%d",
+ QueueDir, rval );
+ fd_worklock = safeopen( P,
+ O_RDWR|O_CREAT,
+ 0644,
+ SFF_NOLINK|SFF_ROOTOK|\
+ SFF_SAFEDIRPATH|SFF_CREAT|\
+ SFF_REGONLY|SFF_NOWLINK|\
+ SFF_OPENASROOT|SFF_NOLOCK
+ );
+ se = errno;
+ if( fd_worklock < 0 )
+ continue;
+ if( flock( fd_worklock, LOCK_EX|LOCK_NB ) ) {
+ close( fd_worklock );
+ fd_worklock = -1;
+ continue;
+ }
+ break;
+ }
+ if( fd_worklock < 0 ) {
+ if( LogLevel > 8 ) {
+ sm_syslog( LOG_INFO, e->e_id,
+ "worklock: denynow" );
+ }
+ finis( TRUE, EX_TEMPFAIL );
+ }
+#endif /* _NXLA */
/* be sure we are immune from the terminal */
disconnect(2, e);
@@ -616,8 +664,12 @@
CurEnv = e;
Verbose = oldverbose;
- if (mode == SM_FORK)
+ if (mode == SM_FORK) {
+#if defined(_NXLA)
+ close( fd_worklock );
+#endif
finis(TRUE, ExitStat);
+ }
}
void