LINUX.ORG.RU

Exim, при объеме письма больше 8192 время увеличивается координально. receive.c


0

1

Уважаемые товарищи! Уже какой день бьюсь над одной проблемой - при объеме письма больше 8192 символов - время отправки письма увеличивается в 25 раз! Я начал курить исходные коды и выяснил, что утечка где-то в этой функции

static int
read_message_data_smtp(FILE *fout)
{
debug_printf("  function called \n");

int ch_state = 0;
register int ch;
register int linelength = 0;


while ((ch = (receive_getc)()) != EOF)
  {
  if (ch == 0) body_zerocount++;
  switch (ch_state)
    {
    case 0:                             /* After LF or CRLF */
    if (ch == '.')
      {
      ch_state = 3;
      continue;                         /* Don't ever write . after LF */
      }
    ch_state = 1;

    /* Else fall through to handle as normal uschar. */

    case 1:                             /* Normal state */
    if (ch == '\n')
      {
      ch_state = 0;
      body_linecount++;
      if (linelength > max_received_linelength)
        max_received_linelength = linelength;
      linelength = -1;
      }
    else if (ch == '\r')
      {
      ch_state = 2;
      continue;
      }
    break;

    case 2:                             /* After (unwritten) CR */
    body_linecount++;
    if (linelength > max_received_linelength)
      max_received_linelength = linelength;
    linelength = -1;
    if (ch == '\n')
      {
      ch_state = 0;
      }
    else
      {
      message_size++;
      if (fout != NULL && fputc('\n', fout) == EOF) return END_WERROR;
      if (ch != '\r') ch_state = 1; else continue;
      }
    break;

    case 3:                             /* After [CR] LF . */
    if (ch == '\n')
      return END_DOT;
    if (ch == '\r')
      {
      ch_state = 4;
      continue;
      }
    ch_state = 1;                       /* The dot itself is removed */
    break;

    case 4:                             /* After [CR] LF . CR */
    if (ch == '\n') return END_DOT;
    message_size++;
    body_linecount++;
    if (fout != NULL && fputc('\n', fout) == EOF) return END_WERROR;
    if (ch == '\r')
      {
      ch_state = 2;
      continue;
      }
    ch_state = 1;
    break;
    }

  /* Add the character to the spool file, unless skipping; then loop for the
  next. */

  message_size++;
  linelength++;
  if (fout != NULL)
    {
    if (fputc(ch, fout) == EOF) return END_WERROR;
    if (message_size > thismessage_size_limit) return END_SIZE;
    }
  }

/* Fall through here if EOF encountered. This indicates some kind of error,
since a correct message is terminated by [CR] LF . [CR] LF. */

return END_EOF;
}
Резко появляется задержка в 0.1с когда обрабатывается вродебы 7000+ какой-то символ(но как-то все всеравно связано с числом 8192) Функция receive_getc = fgetc(stdin) С чем это может быть связано? В какую сторону копать? Что за «блок» в 8192 и почему выходя за рамки его резко падает скорость, что там физически может происходит? Файл, который fout храню на ram-диске. FreeBSD 8.2


видимо 8192 и есть размер буффера для файла. вылезаешь - ос полезла на диск. но код какой то мутный даже для С. машина состояний в которой легко запутатся. лучше читать fread/писать fwrite ом и обрабатывать цыклами.

bga_ ★★★★
()

> while ((ch = (receive_getc)()) != EOF)

И эти люди пишут серьёзный софт? Кто додумался посимвольно читать поток?

Sadler ★★★
()
Ответ на: комментарий от anonymous

> Просто чувак про разного рода дисковые кеши не слышал

Слышал. Но всё равно писать такой код - моветон.

Sadler ★★★
()

DELIVER_IN_BUFFER_SIZE=8192
DELIVER_OUT_BUFFER_SIZE=8192

src/EDITME, файл прекомпилинг настроек.


bass ★★★★★
()
Ответ на: комментарий от Sadler

> Слышал. Но всё равно писать такой код - моветон.

Конечно, ведь гораздо лучше внести код по работе с буферами в основной алгоритм и всё это хорошенько перемешать ;)

Eshkin_kot ★★
()
Ответ на: комментарий от Eshkin_kot

> Конечно, ведь гораздо лучше внести код по работе с буферами в основной алгоритм и всё это хорошенько перемешать

Гораздо лучше написать одну функцию вместо getc, работающую с буферами.

Sadler ★★★
()

Я тут экспериментально выяснил одну вещь.. если замедлить внутри функции это чтение отправка мелкого письма стала 0.07с(значительно увеличилась), а большого как было так и осталось 0.1с. Exim ведь обрабатывает в новом процессе все это и передает туда stdin/stout. Может ли быть проблема на уровень выше - т.е. на этапе передачи от одного процесса данных в stdin в другой?

P.s. не силен в сишном программировании, может чего-то недопонимаю в физике процесса.

vuliad
() автор топика

координально

/0
прежде, чем изучать языки программирования, стоит выучить русский, хотя бы орфографию.

buddhist ★★★★★
()
Ответ на: комментарий от Sadler

Ему скорее всего там надо делать разбор текста. Это такой reader/интерпретатор, и от наличия символа может зависеть дальнейшее поведение, напр. перестать читать вобще.

g1itch ★
()

во первых можно посмотреть что будет если увеличить буфер fout (man setbuffer)

во вторых при выходе из функции стоит всё-таки делать fflush(fout)

напоследок поиграться с неблокирующими опциями потоков (O_NONBLOCK,O_NDELAY)

(фанфары) хотя скорее всего тормозит receive_getc()

p.s. для поиска тормозов есть gprof :)

p.p.s. давно не видел функций с таким числов side-effects..оно по ходу ещё считает размер в байтах, число строк, максимальную длинну строки и всё это через глобальные переменные. Вообще код чумовой..linelength = -1 чего стоит

MKuznetsov ★★★★★
()
Вы не можете добавлять комментарии в эту тему: топик перемещен в архив.