From 4a56c0a1cd4965b3a86d08b6064f365d30bf1301 Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Mon, 5 Feb 2018 23:28:33 -0800 Subject: [PATCH] ircd::fs: Asynchronous writes to local filesystem. --- include/ircd/fs/fs.h | 7 +--- include/ircd/fs/write.h | 73 +++++++++++++++++++++++++++++++++++++++ ircd/aio.cc | 75 +++++++++++++++++++++++++++++++++++++++++ ircd/aio.h | 8 +++++ ircd/fs.cc | 63 ++++++++++++++++++++-------------- 5 files changed, 195 insertions(+), 31 deletions(-) create mode 100644 include/ircd/fs/write.h diff --git a/include/ircd/fs/fs.h b/include/ircd/fs/fs.h index ba78ee35b..12ea7df8d 100644 --- a/include/ircd/fs/fs.h +++ b/include/ircd/fs/fs.h @@ -84,16 +84,11 @@ namespace ircd::fs void chdir(const std::string &path); bool mkdir(const std::string &path); - // This suite of IO functions may yield your context. - bool write(const std::string &name, const const_buffer &buf); - bool append(const std::string &name, const const_buffer &buf); - bool overwrite(const std::string &name, const const_buffer &buf); - bool overwrite(const string_view &name, const const_buffer &buf); - extern aio *aioctx; } #include "read.h" +#include "write.h" struct ircd::fs::init { diff --git a/include/ircd/fs/write.h b/include/ircd/fs/write.h new file mode 100644 index 000000000..e2913986e --- /dev/null +++ b/include/ircd/fs/write.h @@ -0,0 +1,73 @@ +// Matrix Construct +// +// Copyright (C) Matrix Construct Developers, Authors & Contributors +// Copyright (C) 2016-2018 Jason Volk +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice is present in all copies. The +// full license for this software is available in the LICENSE file. + +#pragma once +#define HAVE_IRCD_FS_WRITE_H + +namespace ircd::fs +{ + struct write_opts extern const write_opts_default; + + // Yields ircd::ctx for write from buffer; returns view of written portion + string_view write(const string_view &path, const const_buffer &, const write_opts & = write_opts_default); + + // Yields ircd::ctx to overwrite (trunc) file from buffer; returns view of written portion + string_view overwrite(const string_view &path, const const_buffer &, const write_opts & = write_opts_default); + + // Yields ircd::ctx to append to file from buffer; returns view of written portion + string_view append(const string_view &path, const const_buffer &, const write_opts & = write_opts_default); +} + +/// Options for a write operation +struct ircd::fs::write_opts +{ + write_opts() = default; + write_opts(const off_t &); + + /// Overwrite (trunc) the file + bool overwrite {false}; + + /// Append to the file (offset is ignored) + bool append {false}; + + /// Create the file if necessary (default) + bool create {true}; + + /// Offset in the file to start the write from. + off_t offset {0}; + + /// Request priority (this option may be improved, avoid for now) + int16_t priority {0}; +}; + +inline +ircd::fs::write_opts::write_opts(const off_t &offset) +:offset{offset} +{} + +inline ircd::string_view +ircd::fs::overwrite(const string_view &path, + const const_buffer &buf, + const write_opts &opts_) +{ + auto opts(opts_); + opts.overwrite = true; + return write(path, buf, opts); +} + +inline ircd::string_view +ircd::fs::append(const string_view &path, + const const_buffer &buf, + const write_opts &opts_) +{ + auto opts(opts_); + opts.append = true; + return write(path, buf, opts); +} diff --git a/ircd/aio.cc b/ircd/aio.cc index 3eb6ca9e1..50f7f4167 100644 --- a/ircd/aio.cc +++ b/ircd/aio.cc @@ -319,3 +319,78 @@ ircd::fs::read__aio(const string_view &path, return view; } + +/////////////////////////////////////////////////////////////////////////////// +// +// fs/write.h +// + +// +// request::write +// + +ircd::fs::aio::request::write::write(const int &fd, + const const_buffer &buf, + const write_opts &opts) +:request{fd} +{ + aio_reqprio = opts.priority; + aio_lio_opcode = IOCB_CMD_PWRITE; + + aio_buf = uintptr_t(buffer::data(buf)); + aio_nbytes = buffer::size(buf); + aio_offset = opts.offset; +} + +// +// ircd::fs interface +// + +ircd::string_view +ircd::fs::write__aio(const string_view &path, + const const_buffer &buf, + const write_opts &opts) +{ + // Path to open(2) must be null terminated; + static thread_local char pathstr[2048]; + strlcpy(pathstr, path, sizeof(pathstr)); + + uint flags{0}; + flags |= O_WRONLY; + flags |= O_CLOEXEC; + flags |= opts.create? O_CREAT : 0; + flags |= opts.append? O_APPEND : 0; + flags |= opts.overwrite? O_TRUNC : 0; + + const mode_t mask + { + opts.create? S_IRUSR | S_IWUSR : 0U + }; + + const auto fd + { + syscall(::open, pathstr, flags, mask) + }; + + const unwind cfd{[&fd] + { + syscall(::close, fd); + }}; + + aio::request::write request + { + int(fd), buf, opts + }; + + const size_t bytes + { + request() + }; + + const string_view view + { + data(buf), bytes + }; + + return view; +} diff --git a/ircd/aio.h b/ircd/aio.h index 2beb4fc77..1040ff364 100644 --- a/ircd/aio.h +++ b/ircd/aio.h @@ -70,6 +70,7 @@ struct ircd::fs::aio::request namespace ircd::fs { + string_view write__aio(const string_view &path, const const_buffer &, const write_opts &); string_view read__aio(const string_view &path, const mutable_buffer &, const read_opts &); std::string read__aio(const string_view &path, const read_opts &); } @@ -80,3 +81,10 @@ struct ircd::fs::aio::request::read { read(const int &fd, const mutable_buffer &, const read_opts &); }; + +/// Write request control block +struct ircd::fs::aio::request::write +:request +{ + write(const int &fd, const const_buffer &, const write_opts &); +}; diff --git a/ircd/fs.cc b/ircd/fs.cc index c3415da6a..1a8d8fb03 100644 --- a/ircd/fs.cc +++ b/ircd/fs.cc @@ -147,39 +147,52 @@ ircd::fs::read__std(const string_view &path, // fs/write.h // -bool -ircd::fs::write(const std::string &path, - const const_buffer &buf) +namespace ircd::fs { - if(fs::exists(path)) - return false; - - return overwrite(path, buf); + string_view write__std(const string_view &path, const const_buffer &, const write_opts &); } -bool -ircd::fs::overwrite(const string_view &path, - const const_buffer &buf) +ircd::fs::write_opts +const ircd::fs::write_opts_default +{}; + +ircd::string_view +ircd::fs::write(const string_view &path, + const const_buffer &buf, + const write_opts &opts) { - return overwrite(std::string{path}, buf); + #ifdef IRCD_USE_AIO + if(likely(aioctx)) + return write__aio(path, buf, opts); + #endif + + return write__std(path, buf, opts); } -bool -ircd::fs::overwrite(const std::string &path, - const const_buffer &buf) +ircd::string_view +ircd::fs::write__std(const string_view &path, + const const_buffer &buf, + const write_opts &opts) { - std::ofstream file{path, std::ios::trunc}; + const auto open_mode + { + opts.append? + std::ios::app: + + opts.overwrite? + std::ios::trunc: + + std::ios::out + }; + + std::ofstream file + { + std::string{path}, open_mode + }; + + file.seekp(opts.offset, file.beg); file.write(data(buf), size(buf)); - return true; -} - -bool -ircd::fs::append(const std::string &path, - const const_buffer &buf) -{ - std::ofstream file{path, std::ios::app}; - file.write(data(buf), size(buf)); - return true; + return buf; } void