boost :: iostreams :: copy — sink — ENOSPC (на устройстве не осталось места) обработка ошибок

Во фрагменте кода ниже есть способ обработки ENOSPC?

#include <fstream>
#include <iostream>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/bzip2.hpp>

// open input file stream of the bzip2 file
std::ifstream ifs("file.bz2");

// open output stream to the "full" device
// full device is a "utility-device" to check how applications handle ENOSPC
// more details in "man full"std::ofstream ofs("/dev/full");

// Setup the iostreams filter
boost::iostreams::filtering_streambuf<boost::iostreams::output> filters;
filters.push(boost::iostreams::bzip2_decompressor());
filters.push(ofs);

// "run" the filter
boost::iostreams::copy(ifs, filters);

Если я сделаю strace скомпилированного двоичного кода, кажется, код бесконечно writev() с теми же данными и возвращает ENOSPC ошибка.

writev(4, [{NULL, 0}, {"DATA DATA "..., 4096}], 2) = -1 ENOSPC (No space left on device)

Как эта ошибка может быть обработана или брошена как ошибка от boost::iostreams::copy(),

Можно ли установить соответствующие exceptions() на ofstream объект? Я старался ofs.exceptions(std::ios::badbit | std::ios::failbit) но это не имело никакого значения.

Приведенный выше код был скомпилирован с GCC и запущен в Linux. Boost версия 1.55.

3

Решение

Он застрял в бесконечном цикле non_blocking_adaptor<Device>::write(...):

std::streamsize result = 0;
while (result < n) {
std::streamsize amt =
iostreams::write(device_, s + result, n - result);
result += amt;
}
return result;

iostream::write(device_, ... продолжает возвращать 0 (таким образом, n остается n, amt и результат остается 0).


Казалось бы, ошибка в Boost IOstreams. Возможно, это было введено, когда была добавлена ​​предварительная поддержка неблокирующего (синхронного) ввода-вывода. Согласно документации, это должно быть в стадии разработки.

Особенно поучительно было: http://www.boost.org/doc/libs/1_55_0/libs/iostreams/doc/guide/asynchronous.html

фильтры

Фильтрам разрешено распространять временные уведомления о сбоях: если нижестоящее Устройство потребляет или производит меньше символов, чем запрошено Фильтром, и если в результате Фильтр не может удовлетворить запрос на чтение или запись, Фильтр может вернуть значение, указывающее, что вход или выход временно недоступны. Есть надежда, что этой способности будет достаточно, чтобы позволить использовать текущие концепции фильтров как с асинхронным, так и с неблокирующим вводом-выводом. Тем не менее, чтобы быть полезным при блокировке ввода-вывода, фильтр никогда не должен возвращать временное уведомление о сбое, если он не получил такое уведомление от нижестоящего устройства.. Это требование сводится к тому, что фильтры должны сохранять блокировку. Смотрите Блокировка.

(жирный мойПохоже, что IOStreams нарушили этот принцип, преобразовав условие E_NOSPC в уведомление о временном сбое.


boost::iostreams::copy Особые случаи — случай, когда источник и пункт назначения Косвенные устройства. В этом случае оба являются косвенными. Теперь особый случай оборачивает раковину в non_blocking_adaptor, Я не знаю почему, и это, кажется, противоречит следующему общему совету, взятому на той же странице документации:

Потоки и потоковые буферы

Хотя концепции Boost.Iostreams Filter и Device могут работать с неблокирующим вводом-выводом, интерфейсы потоковой библиотеки и потокового буфера стандартной библиотеки C ++ не могут этого сделать, поскольку у них нет средств, позволяющих различать временные и постоянные сбои для удовлетворения запроса на чтение или запись. В результате неблокирующие устройства не работают должным образом с шаблонами stream, stream_buffer, filtering_stream и filtering_streambuf.

Я пытался заменить файлы с file_sink а также file_source вместо этого, но не было никаких изменений. 🙁

Вот мой сокращенный контрольный пример, который все еще воспроизводит проблему:

#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filtering_streambuf.hpp>

int main()
{
using namespace boost::iostreams;
file_source ifs("/dev/zero");
file_sink   ofs("/dev/full");

filtering_streambuf<output> filters(ofs);
copy(ifs, filters);
}

Возможно, вы должны сообщить об этом как об ошибке в списке разработчиков / рассылки.

3

Другие решения

Я думаю, что нашел решение этой проблемы. Что я сделал, так это сделал свою собственную раковину в соответствии с документация здесь.

В основном sink что бы обработать запись, а затем проверить поток good государство.

struct safe_ofstream_sink
{
typedef char char_type;
typedef boost::iostreams::sink_tag category;

std::ofstream& ofs;

safe_ofstream_sink(std::ofstream& ofs) :
ofs(ofs)
{
}

std::streamsize write(const char* s, std::streamsize n)
{
ofs.write(s, n);
if (!ofs)
throw std::runtime_error("Failed writing to fstream");

return n;
}
};boost::iostreams::filtering_streambuf<boost::iostreams::output> filters;
filters.push(boost::iostreams::bzip2_decompressor());
filters.push(safe_ofstream_sink(ofs));
boost::iostreams::copy(ifs, filters);
1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector