Verified Commit 4d39b371 authored by Alberto Miranda's avatar Alberto Miranda ♨️
Browse files

Refactor I/O error propagation in `mpioxx` and `posix_file`

parent c4895fd6
Loading
Loading
Loading
Loading
+33 −10
Original line number Diff line number Diff line
@@ -30,11 +30,39 @@
#include <boost/mpi/error_string.hpp>
#include <filesystem>
#include <fmt/format.h>
#include <logger/logger.hpp>

// very simple RAII wrappers for some MPI types + utility functions

namespace mpioxx {

class io_error : public std::exception {

public:
    io_error(std::string_view fun, int ec) : m_fun(fun), m_error_code(ec) {}

    [[nodiscard]] std::uint32_t
    error_code() const noexcept {
        return m_error_code;
    }

    [[nodiscard]] const char*
    what() const noexcept override {
        m_message.assign(boost::mpi::error_string(m_error_code));
        return m_message.c_str();
    }

    [[nodiscard]] std::string_view
    where() const noexcept {
        return m_fun;
    }

private:
    mutable std::string m_message;
    std::string_view m_fun;
    int m_error_code;
};

using offset = MPI_Offset;

enum file_open_mode : int {
@@ -86,6 +114,7 @@ operator^=(file_open_mode& a, file_open_mode b) {
}

class file {

public:
    explicit file(const MPI_File& file) : m_file(file) {}

@@ -109,9 +138,7 @@ public:
                   MPI_File_open(comm, filepath.c_str(), static_cast<int>(mode),
                                 MPI_INFO_NULL, &result);
           ec != MPI_SUCCESS) {
            LOGGER_ERROR("MPI_File_open() failed: {}",
                         boost::mpi::error_string(ec));
            MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
            throw io_error("MPI_File_open", ec);
        }

        return file{result};
@@ -120,20 +147,16 @@ public:
    void
    close() {
        if(const auto ec = MPI_File_close(&m_file); ec != MPI_SUCCESS) {
            LOGGER_ERROR("MPI_File_close() failed: {}",
                         boost::mpi::error_string(ec));
            MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
            throw io_error("MPI_File_close", ec);
        }
    }

    offset
    [[nodiscard]] offset
    size() const {
        MPI_Offset result;
        if(const auto ec = MPI_File_get_size(m_file, &result);
           ec != MPI_SUCCESS) {
            LOGGER_ERROR("MPI_File_get_size() failed: {}",
                         boost::mpi::error_string(ec));
            MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
            throw io_error("MPI_File_get_size", ec);
        }
        return result;
    }
+44 −24
Original line number Diff line number Diff line
@@ -120,6 +120,35 @@ public:
    }
};

class io_error : public std::exception {

public:
    io_error(std::string_view fun, int ec) : m_fun(fun), m_error_code(ec) {}

    [[nodiscard]] std::uint32_t
    error_code() const noexcept {
        return m_error_code;
    }

    [[nodiscard]] const char*
    what() const noexcept override {
        m_message.assign(
                std::make_error_code(static_cast<std::errc>(m_error_code))
                        .message());
        return m_message.c_str();
    }

    [[nodiscard]] std::string_view
    where() const noexcept {
        return m_fun;
    }

private:
    mutable std::string m_message;
    std::string_view m_fun;
    int m_error_code;
};

class file {

public:
@@ -149,34 +178,29 @@ public:
        return std::filesystem::remove(m_path);
    }

    tl::expected<void, std::error_code>
    fallocate(int mode, offset offset, std::size_t len) const noexcept {
    void
    fallocate(int mode, offset offset, std::size_t len) const {

        if(!m_handle) {
            return tl::make_unexpected(
                    std::error_code{EBADF, std::generic_category()});
            throw io_error("posix_file::file::fallocate", EBADF);
        }

        int ret = ::fallocate(m_handle.native(), mode, offset,
                              static_cast<off_t>(len));

        if(ret == -1) {
            return tl::make_unexpected(
                    std::error_code{errno, std::generic_category()});
            throw io_error("posix_file::file::fallocate", errno);
        }

        return {};
    }

    template <typename MemoryBuffer>
    tl::expected<std::size_t, std::error_code>
    pread(MemoryBuffer&& buf, offset offset, std::size_t size) const noexcept {
    std::size_t
    pread(MemoryBuffer&& buf, offset offset, std::size_t size) const {

        assert(buf.size() >= size);

        if(!m_handle) {
            return tl::make_unexpected(
                    std::error_code{EBADF, std::generic_category()});
            throw io_error("posix_file::file::pread", EBADF);
        }

        std::size_t bytes_read = 0;
@@ -199,8 +223,7 @@ public:
                }

                // Some other error condition, report
                return tl::make_unexpected(
                        std::error_code{errno, std::generic_category()});
                throw io_error("posix_file::file::pread", errno);
            }

            bytes_read += n;
@@ -211,14 +234,13 @@ public:
    }

    template <typename MemoryBuffer>
    tl::expected<std::size_t, std::error_code>
    pwrite(MemoryBuffer&& buf, offset offset, std::size_t size) const noexcept {
    std::size_t
    pwrite(MemoryBuffer&& buf, offset offset, std::size_t size) const {

        assert(buf.size() >= size);

        if(!m_handle) {
            return tl::make_unexpected(
                    std::error_code{EBADF, std::generic_category()});
            throw io_error("posix_file::file::pwrite", EBADF);
        }

        std::size_t bytes_written = 0;
@@ -236,8 +258,7 @@ public:
                }

                // Some other error condition, report
                return tl::make_unexpected(
                        std::error_code{errno, std::generic_category()});
                throw io_error("posix_file::file::pwrite", errno);
            }

            bytes_written += n;
@@ -252,20 +273,19 @@ protected:
    file_handle m_handle;
};

static inline tl::expected<file, std::error_code>
static inline file
open(const std::filesystem::path& filepath, int flags, ::mode_t mode = 0) {

    int fd = ::open(filepath.c_str(), flags, mode);

    if(fd == -1) {
        return tl::make_unexpected(
                std::error_code{errno, std::generic_category()});
        throw io_error("posix_file::open", errno);
    }

    return file{filepath, fd};
}

static inline tl::expected<file, std::error_code>
static inline file
create(const std::filesystem::path& filepath, int flags, ::mode_t mode) {
    return open(filepath, O_CREAT | flags, mode);
}