26#include <system_error>
29#if defined(__APPLE__) || defined(__linux__)
36 template <
class P,
class Ops>
struct object_stream;
54 std::filesystem::path
final;
60 if (
id.hex().size() != 32 || attempt.
hex().size() != 32)
61 throw std::invalid_argument(
"invalid Everett object or attempt identity");
63 auto temporary =
final.parent_path() /
64 (
"." +
final.filename().string() +
".attempt-" + attempt.
hex());
65 return {std::move(
final), std::move(temporary)};
75 : std::system_error(error, std::generic_category(),
operation),
91 std::filesystem::path
path;
101#if defined(__APPLE__) || defined(__linux__)
102 static constexpr bool supported =
sizeof(off_t) >=
sizeof(std::int64_t);
104#if defined(__APPLE__)
110 int open_root(std::filesystem::path
const & path)
noexcept {
111 return ::open(path.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
113 int make_directory(
int parent,
char const * name)
noexcept {
114 return ::mkdirat(parent, name, 0700);
116 int open_directory(
int parent,
char const * name)
noexcept {
117 return ::openat(parent, name, O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
119 int create_private(
int parent,
char const * name)
noexcept {
120 return ::openat(parent, name, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC | O_NOFOLLOW, 0600);
122 std::ptrdiff_t write(
int fd, std::span<std::byte const> bytes)
noexcept {
123 return ::write(fd, bytes.data(), bytes.size());
125 std::ptrdiff_t write_at(
int fd, std::span<std::byte const> bytes, std::uint64_t at)
noexcept {
126 return ::pwrite(fd, bytes.data(), bytes.size(),
static_cast<off_t
>(at));
128 int make_read_only(
int fd)
noexcept { return ::fchmod(fd, 0400); }
129 int sync_file(
int fd)
noexcept {
130#if defined(__APPLE__)
132 return ::fcntl(fd, F_FULLFSYNC);
137 int sync_directory(
int fd)
noexcept { return ::fsync(fd); }
138 int install(
int parent,
char const * from,
char const * to)
noexcept {
139 return ::linkat(parent, from, parent, to, 0);
141 int remove_private(
int parent,
char const * name)
noexcept { return ::unlinkat(parent, name, 0); }
142 int close(
int fd)
noexcept { return ::close(fd); }
166 std::span<std::span<std::byte const>
const> chunks, Ops & ops) {
167 if constexpr (!Ops::supported) {
168 (void)root; (void)
id; (void)attempt; (void)header; (void)chunks; (void)ops;
169 throw std::system_error(std::make_error_code(std::errc::operation_not_supported),
170 "Everett object writer is unsupported on this platform");
173 auto body_size = file_detail::body_bytes<P>(header.
extent);
174 auto total_size = file_detail::total_bytes<P>(header.
extent);
177 if (total_size > std::uint64_t(std::numeric_limits<std::int64_t>::max()))
178 throw std::length_error(
"Everett object exceeds supported file offsets");
179 std::uint64_t supplied = 0;
181 for (
auto chunk : chunks) {
182 if (chunk.size() > body_size - supplied)
183 throw std::invalid_argument(
"Everett body extent mismatch");
184 supplied += chunk.size();
185 if (!chunk.empty()) last = chunk.back();
187 if (supplied != body_size)
throw std::invalid_argument(
"Everett body extent mismatch");
189 if ((header.
extent & 7) && (std::to_integer<unsigned>(last) & ((1u << (8 - (header.
extent & 7))) - 1)))
190 throw std::invalid_argument(
"noncanonical bit-profile tail padding");
194 std::array<std::byte, file_detail::header_bytes> placeholder{};
195 run.write_all(placeholder);
196 std::uint32_t crc = 0;
197 for (
auto chunk : chunks) {
200 while (!chunk.empty()) {
201 auto part = chunk.first(std::min(chunk.size(), std::size_t{1} << 20));
203 crc = crc32c<typename P::architecture>(part, crc);
204 chunk = chunk.subspan(part.size());
208 run.write_header(encoded_header);
211 return {id, attempt, run.paths.final, total_size, crc, ops.barrier()};
217 std::span<std::span<std::byte const>
const> chunks) {
219 return seal(root,
id, attempt, header, chunks, ops);
223 std::span<std::byte const> body, Ops & ops) {
224 return seal(root,
id, attempt, header, std::span{&body, 1}, ops);
228 std::span<std::byte const> body) {
230 return seal(root,
id, attempt, header, body, ops);
236 std::filesystem::path
const &
root;
242 std::array<int, 4>
fds{-1, -1, -1, -1};
256 for (
auto it =
fds.rbegin(); it !=
fds.rend(); ++it)
257 if (*it >= 0) (void)
ops.close(std::exchange(*it, -1));
259 [[noreturn]]
void fail(
char const * what,
int error = errno)
const {
264 if (
fds[0] < 0)
fail(
"open object root");
265 for (
unsigned i = 1; i <= 2; ++i) {
267 if (
ops.make_directory(
fds[i - 1], name.c_str()) < 0 && errno != EEXIST)
268 fail(
"create object shard");
269 fds[i] =
ops.open_directory(
fds[i - 1], name.c_str());
270 if (
fds[i] < 0)
fail(
"open object shard");
273 if (
fds[3] < 0)
fail(
"create private object");
277 while (!bytes.empty()) {
278 auto part = bytes.first(std::min(bytes.size(), std::size_t{1} << 20));
279 auto count =
ops.write(
fds[3], part);
280 if (count < 0) {
if (errno == EINTR)
continue;
fail(
"write object body"); }
281 if (count == 0 || std::uint64_t(count) > part.size())
fail(
"write object body", EIO);
282 bytes = bytes.subspan(
static_cast<std::size_t
>(count));
286 write_at(bytes, 0,
"write object header");
289 while (!bytes.empty()) {
290 auto part = bytes.first(std::min(bytes.size(), std::size_t{1} << 20));
291 auto count =
ops.write_at(
fds[3], part, offset);
292 if (count < 0) {
if (errno == EINTR)
continue;
fail(
operation); }
293 if (count == 0 || std::uint64_t(count) > part.size())
fail(
operation, EIO);
294 offset +=
static_cast<std::uint64_t
>(count);
295 bytes = bytes.subspan(
static_cast<std::size_t
>(count));
299 if (
ops.make_read_only(
fds[3]) < 0)
fail(
"protect object");
301 if (
ops.sync_file(
fds[3]) < 0)
fail(
"sync object contents");
304 fail(
"install object without replacement");
308 for (
unsigned i = 3; i-- > 0;)
309 if (
ops.sync_directory(
fds[i]) < 0)
fail(
"sync object directory");
313 if (
ops.sync_directory(
fds[2]) < 0)
fail(
"sync private name removal");
316 if (
ops.sync_file(
fds[3]) < 0)
fail(
"sync installed object");
317 for (
unsigned i = 4; i-- > 0;) {
318 auto fd = std::exchange(
fds[i], -1);
319 if (
ops.close(fd) < 0)
fail(
"close sealed object handles");
Declares Everett's file support.
void validate_metadata(file_header< P > const &header)
Definition file.h:93
Definition active_engine.h:18
object_write_stage
Definition object_writer.h:48
object_write_paths object_output_paths(std::filesystem::path const &root, object_id const &id, object_attempt_id const &attempt, file_kind kind)
Definition object_writer.h:58
std::array< std::byte, file_detail::header_bytes > encode_file_header(file_header< P > const &header, std::uint32_t body_crc)
Definition file.h:194
object_sync_barrier
Definition object_writer.h:47
std::filesystem::path object_path(object_id const &id, file_kind kind)
Definition object_path.h:52
file_kind
Definition object_path.h:25
Definition object_writer.h:39
std::string const & hex() const noexcept
Definition object_writer.h:41
object_attempt_id(std::string hex)
Definition object_writer.h:40
bool operator==(object_attempt_id const &) const =default
object_id value_
Definition object_writer.h:44
Definition object_path.h:38
std::string const & hex() const noexcept
Definition object_path.h:46
Definition object_writer.h:88
object_attempt_id attempt
Definition object_writer.h:90
std::filesystem::path path
Definition object_writer.h:91
object_id object
Definition object_writer.h:89
std::uint32_t body_crc32c
Definition object_writer.h:93
std::uint64_t bytes
Definition object_writer.h:92
object_sync_barrier barrier
Definition object_writer.h:94
Definition object_stream.h:32
Definition object_writer.h:72
object_attempt_id attempt
Definition object_writer.h:79
char const * operation
Definition object_writer.h:82
object_id object
Definition object_writer.h:78
object_write_stage stage
Definition object_writer.h:81
object_write_paths paths
Definition object_writer.h:80
object_write_error(int error, char const *operation, object_id object, object_attempt_id attempt, object_write_paths paths, object_write_stage stage)
Definition object_writer.h:73
Definition object_writer.h:53
std::filesystem::path private_output
Definition object_writer.h:55
Definition object_writer.h:235
operation(operation const &)=delete
void write_all(std::span< std::byte const > bytes)
Definition object_writer.h:276
object_write_stage stage
Definition object_writer.h:243
void finish()
Definition object_writer.h:298
operation & operator=(operation const &)=delete
std::string private_name
Definition object_writer.h:241
void write_header(std::span< std::byte const > bytes)
Definition object_writer.h:285
object_write_paths paths
Definition object_writer.h:240
object_attempt_id const & attempt
Definition object_writer.h:238
void fail(char const *what, int error=errno) const
Definition object_writer.h:259
void write_at(std::span< std::byte const > bytes, std::uint64_t offset, char const *operation)
Definition object_writer.h:288
std::array< int, 4 > fds
Definition object_writer.h:242
void open()
Definition object_writer.h:262
~operation()
Definition object_writer.h:253
operation(std::filesystem::path const &root, object_id const &id, object_attempt_id const &attempt, file_kind kind, Ops &ops)
Definition object_writer.h:245
std::string final_name
Definition object_writer.h:241
std::string second
Definition object_writer.h:241
std::filesystem::path const & root
Definition object_writer.h:236
Ops & ops
Definition object_writer.h:239
std::string first
Definition object_writer.h:241
object_id const & id
Definition object_writer.h:237
Definition object_writer.h:161
static object_seal_receipt seal(std::filesystem::path const &root, object_id const &id, object_attempt_id const &attempt, file_header< P > const &header, std::span< std::span< std::byte const > const > chunks, Ops &ops)
Definition object_writer.h:164
static object_seal_receipt seal(std::filesystem::path const &root, object_id const &id, object_attempt_id const &attempt, file_header< P > const &header, std::span< std::byte const > body)
Definition object_writer.h:226
static object_seal_receipt seal(std::filesystem::path const &root, object_id const &id, object_attempt_id const &attempt, file_header< P > const &header, std::span< std::span< std::byte const > const > chunks)
Definition object_writer.h:215
static object_seal_receipt seal(std::filesystem::path const &root, object_id const &id, object_attempt_id const &attempt, file_header< P > const &header, std::span< std::byte const > body, Ops &ops)
Definition object_writer.h:221
P policy_type
Definition object_writer.h:162
Definition object_writer.h:100
static constexpr bool supported
Definition object_writer.h:144