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

Валентин Бартенев ne на vbart.ru
Чт Дек 2 19:13:21 MSK 2010


> > Как сделал я. Я создаю первый буфер, его размер всегда известен заранее и
> > копирую туда данные из приходящих in chains, пока он не заполнится. Также
> > я решил сделать небольшую оптимизацию, в случае, если все необходимые
> > для него данные и так содержатся в пределах одного пришедшего буфера, я
> > использую его, вместо создания своего и копирования туда.
> > 
> > И тут первый вопрос возник. Я обнаружил, что таким образом я блокирую
> > механизм повторного использования освобожденных буферов в
> > ngx_output_chain, которую передо мной вызывает copy-фильтр. Вызывается
> > функция ngx_chain_update_chains, которая в случае использования мной
> > первого пришедшего буфера в итоге всегда делает break на первой же
> > итерации. Получается фиговая оптимизация, и лучше в моем случае всегда
> > копировать данные в свой созданный буфер, или эту пустяки?
> 
> На основе этого описания мне трудно понять что там происходит, но могу
> предположить, что после копирования пришедшего буфера Вы не обновляете
> указатель buf->pos до buf->last. Таким образом copy-фильтр думает, что эти
> данные всё ещё не обработаны и они зависают в busy.

Разумеется, если я буфер копирую, то buf->pos = buf->last у переданных фильтру 
буферов. Но чтобы избежать лишней операции копирования, в довольно 
распространенном случае, когда нужное единым куском и так пришло в одном 
буфере, то использую этот самый буфер. Естественно, в этом случае, buf->pos 
остается указывать на начало. Буфер, как раз, в этом случае не обработан, он 
мне нужен до самого конца.

Вроде бы все хорошо, но вот последующие данные (для второго буфера) довольно 
часто приходят в нескольких буферах, и их уже приходится копировать. По идее 
они свободны, у них buf->pos = buf->last, но они дальше висят в busy, из-за 
первого буфера.

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

Сначала идет байт-код шаблона, а затем Json-данные от бэкэнда. Мне нужно все 
это сложить в два целиковых буфера (один - байткод, другой - данные), чтобы 
запустить виртуальную машину.

> 
> Если генератор данных умеет генерировать по частям, то используйте один
> буфер, сделайте его размер конфигурируемым. Когда фильтр позовут и спросят
> больше данных, заполните буфер, отдайте его, подождите пока все данные в
> нем будут обработаны, сгенерируйте больше и т.д.
> 
В принципе, выплевываются они частями да, разного размера, может два байта 
выйти, а может 500. Но тут мне не хотелось бы прерывать работу виртуальной 
машины, если сразу засылать данные дальше, то там на выполнение пойдет много 
совсем другого кода, и процессорные кэши забьются совсем другим, не тем, что 
нужно ей. Мне кажется все же рациональнее дать ей полностью отработать.


Благодарю за разъяснения про shadow, одним темным местом в nginx для меня 
стало меньше.

--
Валентин Бартенев


Подробная информация о списке рассылки nginx-ru