feat(cpp-object-oriented-modular-refactoring): step 23 - hdf5-writer-modules
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
#define NOMINMAX
|
||||
#include "io/hdf5/hdf5_atomic_file.h"
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "io/hdf5/hdf5_primitives.h"
|
||||
#include "io/hdf5/hdf5_raii.h"
|
||||
|
||||
namespace fesa::hdf5_internal {
|
||||
namespace {
|
||||
|
||||
bool AtomicReplace(const std::filesystem::path& candidate_path,
|
||||
const std::filesystem::path& output_path) {
|
||||
const DWORD attributes = GetFileAttributesW(output_path.c_str());
|
||||
if (attributes != INVALID_FILE_ATTRIBUTES) {
|
||||
return ReplaceFileW(output_path.c_str(), candidate_path.c_str(), nullptr,
|
||||
0U, nullptr, nullptr) != FALSE;
|
||||
}
|
||||
const DWORD error = GetLastError();
|
||||
if (error != ERROR_FILE_NOT_FOUND && error != ERROR_PATH_NOT_FOUND) {
|
||||
return false;
|
||||
}
|
||||
return MoveFileExW(candidate_path.c_str(), output_path.c_str(),
|
||||
MOVEFILE_WRITE_THROUGH) != FALSE;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
CandidateFileGuard::CandidateFileGuard(std::filesystem::path path)
|
||||
: path_{std::move(path)} {}
|
||||
|
||||
CandidateFileGuard::~CandidateFileGuard() {
|
||||
if (active_) {
|
||||
std::error_code ignored;
|
||||
(void)std::filesystem::remove(path_, ignored);
|
||||
}
|
||||
}
|
||||
|
||||
void CandidateFileGuard::Release() noexcept { active_ = false; }
|
||||
|
||||
std::filesystem::path MakeCandidatePath(
|
||||
const std::filesystem::path& output_path) {
|
||||
static std::atomic<std::uint64_t> sequence{0U};
|
||||
const std::filesystem::path parent = output_path.parent_path();
|
||||
for (std::size_t attempt = 0U; attempt < 1024U; ++attempt) {
|
||||
const std::wstring filename =
|
||||
L"." + output_path.filename().wstring() + L".tmp." +
|
||||
std::to_wstring(GetCurrentProcessId()) + L"." +
|
||||
std::to_wstring(sequence.fetch_add(1U));
|
||||
const std::filesystem::path candidate = parent / filename;
|
||||
std::error_code error;
|
||||
const bool exists = std::filesystem::exists(candidate, error);
|
||||
if (error) {
|
||||
throw Hdf5Failure{"Unable to inspect the temporary output path."};
|
||||
}
|
||||
if (!exists) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
throw Hdf5Failure{"Unable to allocate a unique temporary output path."};
|
||||
}
|
||||
|
||||
Status AtomicFinalizeValidatedCandidate(
|
||||
const std::filesystem::path& candidate_path,
|
||||
const std::filesystem::path& output_path, const Status& validation) {
|
||||
if (!validation.IsOk()) {
|
||||
std::error_code ignored;
|
||||
(void)std::filesystem::remove(candidate_path, ignored);
|
||||
return validation;
|
||||
}
|
||||
if (!AtomicReplace(candidate_path, output_path)) {
|
||||
std::error_code ignored;
|
||||
(void)std::filesystem::remove(candidate_path, ignored);
|
||||
return OutputFailure("hdf5-finalization-failure",
|
||||
"The checked temporary HDF5 file could not replace "
|
||||
"the final output.");
|
||||
}
|
||||
return Status::Ok();
|
||||
}
|
||||
|
||||
} // namespace fesa::hdf5_internal
|
||||
Reference in New Issue
Block a user