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 ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.