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 bool disk_backed() const noexcept {
return file_.disk_backed(); }
59 void reset() noexcept { file_.clear(); }
60 void open(
const std::string& directory) {
62 file_.set_directory(directory);
63 auxiliary(
"id table create", [&] { file_.open(
"pineforge-id-pairs"); });
66 check_range(0, bytes);
70 auxiliary(
"id table resize", [&] { file_.ensure_size(bytes); });
72 void read(std::uint64_t offset,
void* destination, std::size_t length)
const {
73 check_range(offset, length);
74 auto* bytes =
static_cast<unsigned char*
>(destination);
75 std::size_t received = 0;
76 while (received < length) {
77 if (fixture_io_) ++fixture_io_->reads;
78 const ssize_t count = auxiliary(
"id table read", [&] {
79 return file_.read_some(offset + received, bytes + received, length - received);
81 if (count < 0 && errno == EINTR)
continue;
84 if (fixture_io_) fixture_io_->read_bytes +=
static_cast<std::uint64_t
>(count);
85 received +=
static_cast<std::size_t
>(count);
88 void write(std::uint64_t offset,
const void*
source, std::size_t length) {
89 check_range(offset, length);
90 const auto* bytes =
static_cast<const unsigned char*
>(
source);
91 std::size_t written = 0;
92 while (written < length) {
93 if (fixture_io_ && ++fixture_io_->writes == fixture_io_->fail_write) {
94 const auto prefix = std::min(fixture_io_->partial_write, length - written);
96 const auto count = auxiliary(
"id table fixture short write", [&] {
97 return file_.write_some(offset + written, bytes + written, prefix);
99 if (count > 0) fixture_io_->write_bytes +=
static_cast<std::uint64_t
>(count);
103 const ssize_t count = auxiliary(
"id table write", [&] {
104 return file_.write_some(offset + written, bytes + written, length - written);
106 if (count < 0 && errno == EINTR)
continue;
109 if (fixture_io_) fixture_io_->write_bytes +=
static_cast<std::uint64_t
>(count);
110 written +=
static_cast<std::size_t
>(count);
115 template<
class Operation>
116 static auto auxiliary(
const char* operation, Operation transfer) ->
decltype(transfer()) {
117 try {
return transfer(); }
118 catch (
const AuxiliaryScratchIoError& error) {
119 throw IdPairStoreError(error.code().value(),
scratch_with_detail(operation, error.what(), error.code().value()).c_str());
124 static void check_range(std::uint64_t offset, std::uint64_t length) {
125 constexpr auto maximum =
static_cast<std::uint64_t
>(std::numeric_limits<off_t>::max());
126 if (offset > maximum || length > maximum - offset)
127 throw IdPairStoreError(EFBIG,
"id table offset exhausted");
RunFailureInfo(RunFailureCode code, const RunFailureArgs &args) noexcept
bool disk_backed() const 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