11#include <system_error>
20 :
std::system_error(error,
std::generic_category(), operation),
40 file_.set_store(store);
45 : file_(std::move(other.file_)),
46 fixture_io_(std::exchange(other.fixture_io_,
nullptr)) {}
50 file_ = std::move(other.file_);
51 fixture_io_ = std::exchange(other.fixture_io_,
nullptr);
57 bool opened() const noexcept {
return file_.opened(); }
58 void reset() noexcept { file_.clear(); }
59 void open(
const std::string& directory) {
61 file_.set_directory(directory);
62 auxiliary(
"id table create", [&] { file_.open(
"pineforge-id-pairs"); });
65 check_range(0, bytes);
69 auxiliary(
"id table resize", [&] { file_.ensure_size(bytes); });
71 void read(std::uint64_t offset,
void* destination, std::size_t length)
const {
72 check_range(offset, length);
73 auto* bytes =
static_cast<unsigned char*
>(destination);
74 std::size_t received = 0;
75 while (received < length) {
76 if (fixture_io_) ++fixture_io_->reads;
77 const ssize_t count = auxiliary(
"id table read", [&] {
78 return file_.read_some(offset + received, bytes + received, length - received);
80 if (count < 0 && errno == EINTR)
continue;
83 if (fixture_io_) fixture_io_->read_bytes +=
static_cast<std::uint64_t
>(count);
84 received +=
static_cast<std::size_t
>(count);
87 void write(std::uint64_t offset,
const void*
source, std::size_t length) {
88 check_range(offset, length);
89 const auto* bytes =
static_cast<const unsigned char*
>(
source);
90 std::size_t written = 0;
91 while (written < length) {
92 if (fixture_io_ && ++fixture_io_->writes == fixture_io_->fail_write) {
93 const auto prefix = std::min(fixture_io_->partial_write, length - written);
95 const auto count = auxiliary(
"id table fixture short write", [&] {
96 return file_.write_some(offset + written, bytes + written, prefix);
98 if (count > 0) fixture_io_->write_bytes +=
static_cast<std::uint64_t
>(count);
102 const ssize_t count = auxiliary(
"id table write", [&] {
103 return file_.write_some(offset + written, bytes + written, length - written);
105 if (count < 0 && errno == EINTR)
continue;
108 if (fixture_io_) fixture_io_->write_bytes +=
static_cast<std::uint64_t
>(count);
109 written +=
static_cast<std::size_t
>(count);
114 template<
class Operation>
115 static auto auxiliary(
const char* operation, Operation transfer) ->
decltype(transfer()) {
116 try {
return transfer(); }
117 catch (
const AuxiliaryScratchIoError& error) {
118 throw IdPairStoreError(error.code().value(),
scratch_with_detail(operation, error.what(), error.code().value()).c_str());
123 static void check_range(std::uint64_t offset, std::uint64_t length) {
124 constexpr auto maximum =
static_cast<std::uint64_t
>(std::numeric_limits<off_t>::max());
125 if (offset > maximum || length > maximum - offset)
126 throw IdPairStoreError(EFBIG,
"id table offset exhausted");
RunFailureInfo(RunFailureCode code, const RunFailureArgs &args) noexcept
void fixture_count_io(FixtureIO *io) noexcept
~IdPairScratchFile()=default
bool opened() const noexcept
FixtureIO * fixture_io() const noexcept
IdPairScratchFile & operator=(IdPairScratchFile &&other) noexcept
IdPairScratchFile & operator=(const IdPairScratchFile &)=delete
void write(std::uint64_t offset, const void *source, std::size_t length)
IdPairScratchFile(ScratchStore store=ScratchStore::unknown)
void resize(std::uint64_t bytes)
IdPairScratchFile(const IdPairScratchFile &)=delete
void set_store(ScratchStore store) noexcept
IdPairScratchFile(IdPairScratchFile &&other) noexcept
void open(const std::string &directory)
void read(std::uint64_t offset, void *destination, std::size_t length) const
IdPairStoreError(int error, const char *operation)
std::string scratch_with_detail(const char *prefix, const char *what, int errno_value)
std::size_t partial_write
std::uint64_t write_bytes