merge: lane/core
This commit is contained in:
@@ -20,6 +20,7 @@ add_library(veloxcore STATIC
|
|||||||
src/net/probe.cpp
|
src/net/probe.cpp
|
||||||
src/io/sparse_file.cpp
|
src/io/sparse_file.cpp
|
||||||
src/io/write_buffer.cpp
|
src/io/write_buffer.cpp
|
||||||
|
src/io/platform/linux/file_ops.cpp
|
||||||
src/meta/veloxpart.cpp
|
src/meta/veloxpart.cpp
|
||||||
src/segment/segmenter.cpp
|
src/segment/segmenter.cpp
|
||||||
src/segment/budget.cpp
|
src/segment/budget.cpp
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
// vdm/io/platform/file_ops.hpp — platform seam for the three Linux-only file-I/O
|
||||||
|
// primitives sparse_file.cpp and meta/veloxpart.cpp use (ADR 0020, docs/08-porting.md).
|
||||||
|
//
|
||||||
|
// One implementation file per OS under platform/<os>/, selected at build time. No #ifdef
|
||||||
|
// here, no OS-specific types in the signatures — a reader of the callers must not need to
|
||||||
|
// know which OS they're on. Linux (platform/linux/file_ops.cpp) is the reference
|
||||||
|
// implementation and is the only one that exists until the PORT lane adds macOS.
|
||||||
|
//
|
||||||
|
// This header compiles standalone.
|
||||||
|
|
||||||
|
#ifndef VDM_IO_PLATFORM_FILE_OPS_HPP
|
||||||
|
#define VDM_IO_PLATFORM_FILE_OPS_HPP
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "vdm/util/result.hpp"
|
||||||
|
|
||||||
|
namespace vdm::io::platform {
|
||||||
|
|
||||||
|
// Reserve `bytes` for `fd` so a large transfer doesn't fragment or hit ENOSPC mid-write.
|
||||||
|
// Linux: posix_fallocate, falling back to ftruncate on EOPNOTSUPP/ENOSYS/EINVAL exactly as
|
||||||
|
// SparseFile did before this seam existed. Returns whether a true extent-reserving
|
||||||
|
// preallocation happened (false when the ftruncate fallback was used) so callers can keep
|
||||||
|
// reporting SparseFile::preallocated() unchanged.
|
||||||
|
[[nodiscard]] Result<bool> preallocate(int fd, std::uint64_t bytes);
|
||||||
|
|
||||||
|
// Drop cached pages for [offset, offset+len) from the OS page cache, best-effort. A
|
||||||
|
// platform with no equivalent (macOS) is a documented no-op, not a failure — never let
|
||||||
|
// this block or fail the transfer path.
|
||||||
|
void advise_dontneed(int fd, std::uint64_t offset, std::uint64_t len) noexcept;
|
||||||
|
|
||||||
|
// Flush `fd`'s data to durable storage without waiting on metadata that doesn't affect
|
||||||
|
// data readback. Linux: fdatasync.
|
||||||
|
[[nodiscard]] Result<void> flush_durable(int fd);
|
||||||
|
|
||||||
|
} // namespace vdm::io::platform
|
||||||
|
|
||||||
|
#endif // VDM_IO_PLATFORM_FILE_OPS_HPP
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
// vdm/io/platform/linux/file_ops.cpp — Linux backend for the file_ops seam.
|
||||||
|
//
|
||||||
|
// Reference implementation (ADR 0020): moved unchanged from sparse_file.cpp and
|
||||||
|
// meta/veloxpart.cpp. Linux behaviour must never change as a result of a port; if a port
|
||||||
|
// needs a semantic change here, that's an ADR, not a seam edit.
|
||||||
|
|
||||||
|
#include "io/platform/file_ops.hpp"
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace vdm::io::platform {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
Error errno_to_error(int e) noexcept {
|
||||||
|
switch (e) {
|
||||||
|
case ENOSPC:
|
||||||
|
case EDQUOT:
|
||||||
|
return Error::disk_full;
|
||||||
|
case EACCES:
|
||||||
|
case EPERM:
|
||||||
|
case EROFS:
|
||||||
|
return Error::permission_denied;
|
||||||
|
case ENOENT:
|
||||||
|
case ENOTDIR:
|
||||||
|
case EISDIR:
|
||||||
|
case ENAMETOOLONG:
|
||||||
|
case ELOOP:
|
||||||
|
return Error::path_rejected;
|
||||||
|
default:
|
||||||
|
return Error::io_error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorInfo sys_error(std::string_view what, int e) {
|
||||||
|
return ErrorInfo(errno_to_error(e), std::string(what) + ": " + std::strerror(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Result<bool> preallocate(int fd, std::uint64_t bytes) {
|
||||||
|
// posix_fallocate returns the error number directly and does not set errno.
|
||||||
|
int rc = ::posix_fallocate(fd, 0, static_cast<off_t>(bytes));
|
||||||
|
if (rc == 0)
|
||||||
|
return true;
|
||||||
|
if (rc == EOPNOTSUPP || rc == ENOSYS || rc == EINVAL) {
|
||||||
|
if (::ftruncate(fd, static_cast<off_t>(bytes)) != 0)
|
||||||
|
return sys_error("ftruncate", errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return sys_error("posix_fallocate", rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void advise_dontneed(int fd, std::uint64_t offset, std::uint64_t len) noexcept {
|
||||||
|
if (len == 0)
|
||||||
|
return;
|
||||||
|
::posix_fadvise(fd, static_cast<off_t>(offset), static_cast<off_t>(len), POSIX_FADV_DONTNEED);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> flush_durable(int fd) {
|
||||||
|
while (::fdatasync(fd) != 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
return sys_error("fdatasync", errno);
|
||||||
|
}
|
||||||
|
return ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace vdm::io::platform
|
||||||
@@ -9,6 +9,8 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "io/platform/file_ops.hpp"
|
||||||
|
|
||||||
namespace vdm::io {
|
namespace vdm::io {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@@ -90,20 +92,12 @@ Result<void> SparseFile::open(std::string_view path, const OpenOptions &opts) {
|
|||||||
bool prealloc = false;
|
bool prealloc = false;
|
||||||
if (opts.total_size > 0) {
|
if (opts.total_size > 0) {
|
||||||
if (opts.preallocate) {
|
if (opts.preallocate) {
|
||||||
// posix_fallocate returns the error number directly and does not set errno.
|
Result<bool> r = platform::preallocate(fd, opts.total_size);
|
||||||
int rc = ::posix_fallocate(fd, 0, static_cast<off_t>(opts.total_size));
|
if (!r.has_value()) {
|
||||||
if (rc == 0) {
|
|
||||||
prealloc = true;
|
|
||||||
} else if (rc == EOPNOTSUPP || rc == ENOSYS || rc == EINVAL) {
|
|
||||||
if (::ftruncate(fd, static_cast<off_t>(opts.total_size)) != 0) {
|
|
||||||
int e = errno;
|
|
||||||
::close(fd);
|
::close(fd);
|
||||||
return sys_error("ftruncate " + p, e);
|
return std::move(r).error();
|
||||||
}
|
|
||||||
} else {
|
|
||||||
::close(fd);
|
|
||||||
return sys_error("posix_fallocate " + p, rc);
|
|
||||||
}
|
}
|
||||||
|
prealloc = *r;
|
||||||
} else if (!opts.truncate_existing) {
|
} else if (!opts.truncate_existing) {
|
||||||
// Resuming: make sure the file is at least total_size so pwrite offsets land.
|
// Resuming: make sure the file is at least total_size so pwrite offsets land.
|
||||||
if (::ftruncate(fd, static_cast<off_t>(opts.total_size)) != 0) {
|
if (::ftruncate(fd, static_cast<off_t>(opts.total_size)) != 0) {
|
||||||
@@ -147,18 +141,13 @@ Result<void> SparseFile::write_at(std::uint64_t offset, ConstByteSpan data) {
|
|||||||
Result<void> SparseFile::sync() {
|
Result<void> SparseFile::sync() {
|
||||||
if (fd_ < 0)
|
if (fd_ < 0)
|
||||||
return ErrorInfo(Error::internal, "sync on a closed SparseFile");
|
return ErrorInfo(Error::internal, "sync on a closed SparseFile");
|
||||||
while (::fdatasync(fd_) != 0) {
|
return platform::flush_durable(fd_);
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
return sys_error("fdatasync", errno);
|
|
||||||
}
|
|
||||||
return ok();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SparseFile::advise_dontneed(std::uint64_t offset, std::uint64_t len) noexcept {
|
void SparseFile::advise_dontneed(std::uint64_t offset, std::uint64_t len) noexcept {
|
||||||
if (fd_ < 0 || len == 0)
|
if (fd_ < 0 || len == 0)
|
||||||
return;
|
return;
|
||||||
::posix_fadvise(fd_, static_cast<off_t>(offset), static_cast<off_t>(len), POSIX_FADV_DONTNEED);
|
platform::advise_dontneed(fd_, offset, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<void> SparseFile::resize(std::uint64_t size) {
|
Result<void> SparseFile::resize(std::uint64_t size) {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "io/platform/file_ops.hpp"
|
||||||
#include "vdm/util/crc32.hpp"
|
#include "vdm/util/crc32.hpp"
|
||||||
|
|
||||||
namespace vdm::meta {
|
namespace vdm::meta {
|
||||||
@@ -272,13 +273,11 @@ Result<void> write_veloxpart_file(std::string_view path, const VeloxPart &vp, bo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (fsync) {
|
if (fsync) {
|
||||||
while (::fdatasync(fd) != 0) {
|
Result<void> r = vdm::io::platform::flush_durable(fd);
|
||||||
if (errno == EINTR)
|
if (!r.has_value()) {
|
||||||
continue;
|
|
||||||
int e = errno;
|
|
||||||
::close(fd);
|
::close(fd);
|
||||||
::unlink(tmp.c_str());
|
::unlink(tmp.c_str());
|
||||||
return sys_error("fdatasync " + tmp, e);
|
return ErrorInfo(r.error().code, "fdatasync " + tmp + ": " + r.error().context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (::close(fd) != 0) {
|
if (::close(fd) != 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user