ПРОЕКТЫ 


  АРХИВ 


Apache-Talk @lexa.ru 

Inet-Admins @info.east.ru 

Filmscanners @halftone.co.uk 

Security-alerts @yandex-team.ru 

nginx-ru @sysoev.ru 


  СТАТЬИ 


  ПЕРСОНАЛЬНОЕ 


  ПРОГРАММЫ 



ПИШИТЕ
ПИСЬМА












     АРХИВ :: nginx-ru
Nginx-ru mailing list archive (nginx-ru@sysoev.ru)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Вопросов накопилось по работе с буферами. И как оптимально буферизовать весь исходящий поток вн утри фильтра?


  • To: nginx-ru@xxxxxxxxx
  • Subject: Re: Вопросов накопилось по работе с буферами. И как оптимально буферизовать весь исходящий поток вн утри фильтра?
  • From: Valery Kholodkov <valery+nginxru@xxxxxxxxxxx>
  • Date: Thu, 2 Dec 2010 12:39:42 +0000 (GMT)
  • In-reply-to: <201012021113.57397.ne@xxxxxxxx>

----- Валентин Бартенев <ne@xxxxxxxx> wrote:
> Добрый день. Надеюсь на помощь гораздо более опытных, чем я.
> 
> Мне в модуле-фильтре необходимо буферизовать весь ответ, сложив все in chains 
> в два целиковых буфера. Размер первого всегда заранее известен, размер 
> второго 
> зависит от размера данных и известен только в случае если уже установлен 
> заголовок content-length. После этого, на основе этих двух полученных буферов 
> формируется совершенно новый набор данных, которые уже посылаются дальше.
> 
> 
> Как сделал я. Я создаю первый буфер, его размер всегда известен заранее и 
> копирую туда данные из приходящих in chains, пока он не заполнится. Также я 
> решил сделать небольшую оптимизацию, в случае, если все необходимые для него 
> данные и так содержатся в пределах одного пришедшего буфера, я использую его, 
> вместо создания своего и копирования туда.
> 
> И тут первый вопрос возник. Я обнаружил, что таким образом я блокирую 
> механизм 
> повторного использования освобожденных буферов в ngx_output_chain, которую 
> передо мной вызывает copy-фильтр. Вызывается функция ngx_chain_update_chains, 
> которая в случае использования мной первого пришедшего буфера в итоге всегда 
> делает break на первой же итерации. Получается фиговая оптимизация, и лучше в 
> моем случае всегда копировать данные в свой созданный буфер, или эту пустяки?

На основе этого описания мне трудно понять что там происходит, но могу 
предположить, что после копирования пришедшего буфера Вы не обновляете 
указатель buf->pos до buf->last. Таким образом copy-фильтр думает, что эти 
данные всё ещё не обработаны и они зависают в busy.
 
> Далее, мне нужно заполнить оставшимися данными второй буфер. Если заголовок 
> content-length установлен, то я поступаю аналогично первому буферу. Если нет, 
> то я сначала складываю отдельно все приходящие цепочки образуя одну большую 
> единую цепь из данных, попутно считая их размер, а затем уже, по получении 
> последнего буфера с признаком last_buf, создаю свой второй единый буфер, зная 
> размер всех данных, и копирую туда их из собранной цепи.
> 
> Опять же такой подход не дает высвобождать буфера до последнего момента. 
> Кроме 
> этого, как я понял, я не могу просто соединять цепочки, используя приходящие 
> звенья. Мне необходимо создавать свою цепь звеньев, копируя в них указатели 
> на 
> буфера. Просто соединение приходящих цепей в некоторых случаях приводит к 
> зацикливанию nginx уже упомянутым вызовом ngx_chain_update_chains из 
> ngx_output_chain, так цепь в busy замыкается сама на себя при определенных 
> обстоятельствах.

Да, нужно копировать цепь. Иначе фильтры, стоящие раньше в цепи, не смогут 
отслеживать прогресс обработки.

Исключением является ситуация, когда фильтр без изменений передет цепь 
следующему фильтру.

> В image_filter сделано гораздо проще, там если размер картинки заранее 
> неизвестен, то выделяется буфер размером "image_filter_buffer" (по-молчанию 
> 1Мб) и данные складываются в него, если их оказывается больше, то не повезло, 
> ошибочка, если меньше, то излишек простаивает впустую. Неужели такой подход 
> оптимальнее, чем буферизация цепочки с целью вычисления размера данных? Может 
> мне тоже так сделать?

Думаю, так сделано с одной стороны для простоты, а с другой стороны потому что 
редкая универсальная графическая библиотека поддерживает поточную обработку (я 
такой не знаю, если кто-то знает, скажите).

> Заполнили два буфера всеми пришедшими данными. Теперь, если все Ок, 
> происходит 
> генерация нового потока данных. Я начинаю выделять буфера по мере наполнения 
> размером ngx_pagesize выстраивая из них новую цепочку, которую затем и 
> посылаю 
> далее. Как бы тут сэкономить? В принципе, я могу использовать один из уже 
> созданных буферов, но этого, как правило недостаточно. В то же время, в цепях 
> busy и free внутри ngx_output_chain_ctx_t скопилось куча уже неиспользуемых 
> буферов, можно ли взять от туда?

В Вашем случае можно, но это не совсем корректно. Могут возникнуть последствия.

> Или можно их сразу складывать у себя 
> "прозапас"? И как лучше сделать? Или еще откуда-то можно взять? Или лучше не 
> стоит, и я все правильно делаю?

Если генератор данных умеет генерировать по частям, то используйте один буфер, 
сделайте его размер конфигурируемым. Когда фильтр позовут и спросят больше 
данных, заполните буфер, отдайте его, подождите пока все данные в нем будут 
обработаны, сгенерируйте больше и т.д.

> Надеюсь на ваши разъяснения и подсказки. Возможно некоторые механизмы в 
> nginx, 
> я еще пока плохо понимаю.
> 
> И не могли бы кто-нибудь пояснить назначение и использование в некоторых 
> местах shadow и last_shadow у буферов?

Предположим есть буфер, в котором данные перемешаны с какой-нибудь 
метаинформацией. Например:

|AAABBBAABBBBAAABBAAAABAAAAA|

Предположим, из этого буфера нужно вырезать все данные B. Как это выглядит:

|AAABBBAAABBBAAABBBAAABBBAAA| <-----------------------------------------+
shadow -> |BBB|.shadow -> |BBBB|.shadow -> |BB|.shadow -> |B|.shadow ---+

Первый указатель shadow принадлежит исходному буферу. У последнего буфера |B| 
last_shadow = 1, а поле shadow указывает на исходный буфер.

Иными словами, shadow -- это односвязный список буферов, которые указыват где в 
исходном буфере находятся данные B.

У модуля fastcgi входной фильтр умеет генерировать такие списки. Кроме того, 
upstream умеет с этими списками работать.

Как-то так.

-- 
Regards,
Valery Kholodkov
_______________________________________________
nginx-ru mailing list
nginx-ru@xxxxxxxxx
http://nginx.org/mailman/listinfo/nginx-ru


 




Copyright © Lexa Software, 1996-2009.