Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Динамический буфер для кеша


Автор: Alex13 30.11.2010, 19:13
Бекграунд.
Дабы вы смогли луше понять мой вопрос, изложу общую задачу. Пишу кеширующий HTTP прокси-сервер с пулом рабочих потоков и poll()'ом в основе, в рамках курсовой, кеш должен жить в оперативной памяти. Помимо прочего требуется корректно отрабатывать такой сценарий:
1) Приходит запрос, в целом удовлетворяющий требованиям для помещения в кеш.
2) Начинается загрузка файла в кеш. При этом файл отдается в chunked encoding, т. е. в заголовке его длина не указывается.
3) Параллельно из записи в кеше данные начинают отдаваться клиенту.
4) В это время приходит второй запрос к тому же адресу. Вместо того, чтобы начать его качать еще раз мы, естественно, присасываемся к существующей (недокачанной) записи кеша и так же начинаем отдавать оттуда данные по мере появления.
5) Спустя некоторое время мы видим, что файл оказался большой (например, скачали 100 мб и продолжаем качать) и в память рискует не поместиться, поэтому мы переключаемся в "разрушающий" режим работы буффера кеша. При этом данные, которые были отправлены всем успевшим подключиться должны из буфера удаляться, чтобы освободить память. Естественно, после этого момента подключение новых клиентов к этой записи кеша уже невозможно.
6) После того, как файл докачался и был отдан всем клиентам, запись кеша уничтожается.

Задача
По замыслу происходить это будет так: один "логический" поток (т. е. общая последовательность действий, хоть она и может исполняться разными воркерами) будет качать файл и писать в кеш, другой - отдавать клиенту. Мне требуется структура данных, буффер, удовлетворяющий следующим требованиям:
1) Динамически расширяющийся, хранящийся в памяти.
2) Поддержка нескольких независимых читателей, каждый со всоим "курсором".
3) Данные, записанные в буффер тут же становятся доступны всем читателям.
4) Возможность на лету переключиться в "разрушающий" режим, описанный выше.
5) Желательно, чтобы довыделение памяти происходило блоками настраиваемого размера, чтобы уменьшить количество выделений памяти.
6) Желательно, чтобы все это реализовывало интерфейс стандартных потоков ввода-вывода.
Понимаю, что требования довольно крутые, но если удастся их выполнить, что будет прямо рай на земле, а не прокси.

Найденные решения
Ничего лучше std::stringstream я так и не нашел, но он удовлетворяет лишь двум требованиям из 6.

Вопрос
Знает ли кто-нибудь готовый класс, реализующий все эти плюшки или компоненты, от которых можно оттолкнуться при написании такого класса самостоятельно?

Автор: Леопольд 30.11.2010, 22:07
http://www.cplusplus.com/reference/stl/deque/
за основу

Автор: Alex13 1.12.2010, 06:28
Спасибо за ответ, однако этот класс фактически решает только проблему динамического расширения и быстрого добавления/удаления элементов. Однако он при этом дает пачку новых проблем:
1) Если элементами очереди делать просто char, то операция чтения становится убийственно медленной штукой, поскольку разрозненные чары (по спецификации они не обязаны храниться подряд в памяти) надо будет собрать в один блок и только потом вернуть. Но по логике кеша чтение из него производится несколько раз, а запись - только один и лучше уж иметь быстрое чтение и медленную запись, чем наоборот.
2) Если элементами очереди сделать блоки чаров, то будут сложности с позиционированием курсора чтения с точностью большей чем до одного блока и обработкой кусков данных, не кратных размеру блока.

В свете вышесказанного мне больше нравится vector или string, но для них все равно придется самостоятельно реализовывать большую часть требований.

Автор: Леопольд 1.12.2010, 14:13
Цитата(Alex13 @  1.12.2010,  06:28 Найти цитируемый пост)
vector
Этот умеет незаметно перераспределять память. Операция push_back (и даже push_front) лекго может заинвалидить все текущие итераторы (aka указатели).  А ещё он хорошо растёт вверх, но вниз не очень. Т.е. не освобождает выделенную память, а оставляет на потом. 

deque этим не страдает, и из/в неё можно удалять/добавлять не по одному инстансу а пачками. 
http://cplusplus.com/reference/stl/deque/insert/
http://cplusplus.com/reference/stl/deque/erase/
Память она выделяет/освобождает блоками фиксированного размера. Итераторы с рандомным доступом. Несколько медленнее чем у вектора, ведь надо сперва посчитать к какому блоку итератор относится, потом вычислить индекс (указатель) в этом блоке, после чего можно получить элемент. Но не настолько:
Цитата(Alex13 @  1.12.2010,  06:28 Найти цитируемый пост)
1) Если элементами очереди делать просто char, то операция чтения становится убийственно медленной штукой,


Из STL, deque лучше всего подходит под предъявленные требования.

Автор: Alex13 1.12.2010, 15:20
А вот это уже звучит интереснее, спасибо.
Хотя мне не обязательно было использовать только STL, решение звучит заманчиво. Пока я дожидался ответа, я наткнулся на Boost.Iostreams, что дает уже неплохую базу вместе с deque.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)