merge: lane/core

This commit is contained in:
2026-09-15 17:57:36 +04:00
5 changed files with 124 additions and 24 deletions
+1
View File
@@ -20,6 +20,7 @@ add_library(veloxcore STATIC
src/net/probe.cpp
src/io/sparse_file.cpp
src/io/write_buffer.cpp
src/io/platform/linux/file_ops.cpp
src/meta/veloxpart.cpp
src/segment/segmenter.cpp
src/segment/budget.cpp
+38
View File
@@ -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
+73
View File
@@ -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
+8 -19
View File
@@ -9,6 +9,8 @@
#include <cstring>
#include <utility>
#include "io/platform/file_ops.hpp"
namespace vdm::io {
namespace {
@@ -90,20 +92,12 @@ Result<void> SparseFile::open(std::string_view path, const OpenOptions &opts) {
bool prealloc = false;
if (opts.total_size > 0) {
if (opts.preallocate) {
// posix_fallocate returns the error number directly and does not set errno.
int rc = ::posix_fallocate(fd, 0, static_cast<off_t>(opts.total_size));
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;
Result<bool> r = platform::preallocate(fd, opts.total_size);
if (!r.has_value()) {
::close(fd);
return sys_error("ftruncate " + p, e);
}
} else {
::close(fd);
return sys_error("posix_fallocate " + p, rc);
return std::move(r).error();
}
prealloc = *r;
} else if (!opts.truncate_existing) {
// 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) {
@@ -147,18 +141,13 @@ Result<void> SparseFile::write_at(std::uint64_t offset, ConstByteSpan data) {
Result<void> SparseFile::sync() {
if (fd_ < 0)
return ErrorInfo(Error::internal, "sync on a closed SparseFile");
while (::fdatasync(fd_) != 0) {
if (errno == EINTR)
continue;
return sys_error("fdatasync", errno);
}
return ok();
return platform::flush_durable(fd_);
}
void SparseFile::advise_dontneed(std::uint64_t offset, std::uint64_t len) noexcept {
if (fd_ < 0 || len == 0)
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) {
+4 -5
View File
@@ -13,6 +13,7 @@
#include <string>
#include <utility>
#include "io/platform/file_ops.hpp"
#include "vdm/util/crc32.hpp"
namespace vdm::meta {
@@ -272,13 +273,11 @@ Result<void> write_veloxpart_file(std::string_view path, const VeloxPart &vp, bo
}
if (fsync) {
while (::fdatasync(fd) != 0) {
if (errno == EINTR)
continue;
int e = errno;
Result<void> r = vdm::io::platform::flush_durable(fd);
if (!r.has_value()) {
::close(fd);
::unlink(tmp.c_str());
return sys_error("fdatasync " + tmp, e);
return ErrorInfo(r.error().code, "fdatasync " + tmp + ": " + r.error().context);
}
}
if (::close(fd) != 0) {