diff options
author | Niall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) <spamtrap@nedprod.com> | 2017-09-10 06:24:45 +0300 |
---|---|---|
committer | Niall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) <spamtrap@nedprod.com> | 2017-09-10 06:24:45 +0300 |
commit | 5145f65004a7834cb1fc0a57c4e8c53cf97e78ec (patch) | |
tree | 3684ce1d52aa13482caafb510e48c724f5c25ca6 | |
parent | 3afebec0fd8750ff8a83eebc4f8de0480dd67e09 (diff) |
Now fully working on POSIX
m--------- | doc/html | 8 | ||||
-rw-r--r-- | include/afio/revision.hpp | 6 | ||||
-rw-r--r-- | include/afio/v2.0/detail/impl/posix/map_handle.ipp | 84 | ||||
-rw-r--r-- | include/afio/v2.0/detail/impl/posix/mapped_file_handle.ipp | 10 | ||||
-rw-r--r-- | include/afio/v2.0/map_handle.hpp | 6 | ||||
-rw-r--r-- | include/afio/v2.0/mapped_file_handle.hpp | 21 | ||||
-rw-r--r-- | test/tests/mapped_view.cpp | 7 |
7 files changed, 97 insertions, 45 deletions
diff --git a/doc/html b/doc/html -Subproject 29c456437d320dbe7ddbc33e491984af0b14583 +Subproject 1d80781cac7cb087435fb798c636896045b2daa diff --git a/include/afio/revision.hpp b/include/afio/revision.hpp index a6b8436c..7be09270 100644 --- a/include/afio/revision.hpp +++ b/include/afio/revision.hpp @@ -1,4 +1,4 @@ // Note the second line of this file must ALWAYS be the git SHA, third line ALWAYS the git SHA update time -#define AFIO_PREVIOUS_COMMIT_REF afa177fe7e944a5adc015d5237a5bed2c9cc5e2e -#define AFIO_PREVIOUS_COMMIT_DATE "2017-09-10 00:09:57 +00:00" -#define AFIO_PREVIOUS_COMMIT_UNIQUE afa177fe +#define AFIO_PREVIOUS_COMMIT_REF 3afebec0fd8750ff8a83eebc4f8de0480dd67e09 +#define AFIO_PREVIOUS_COMMIT_DATE "2017-09-10 01:53:53 +00:00" +#define AFIO_PREVIOUS_COMMIT_UNIQUE 3afebec0 diff --git a/include/afio/v2.0/detail/impl/posix/map_handle.ipp b/include/afio/v2.0/detail/impl/posix/map_handle.ipp index 72927cd6..1032421d 100644 --- a/include/afio/v2.0/detail/impl/posix/map_handle.ipp +++ b/include/afio/v2.0/detail/impl/posix/map_handle.ipp @@ -29,39 +29,60 @@ Distributed under the Boost Software License, Version 1.0. AFIO_V2_NAMESPACE_BEGIN -result<section_handle> section_handle::section(file_handle &backing, extent_type maximum_size, flag _flag) noexcept +section_handle::~section_handle() { - extent_type length = 0; - if(backing.is_valid()) + if(_v) { - OUTCOME_TRY(_length, backing.length()); - length = _length; - if(length == 0) - { - // Some systems allow zero sized maps, POSIX bans it - return std::errc::invalid_argument; - } - if(maximum_size > 0 && maximum_size > length) - { - // For compatibility with Windows, disallow sections larger than the file - return std::errc::value_too_large; - } + (void) section_handle::close(); } - if(!maximum_size) +} +result<void> section_handle::close() noexcept +{ + AFIO_LOG_FUNCTION_CALL(this); + // We don't want ~handle() to close our fake handle + _v = native_handle_type(); + return success(); +} + +result<section_handle> section_handle::section(file_handle &backing, extent_type maximum_size, flag _flag) noexcept +{ + if(!(_flag & flag::posix_skip_length_checks)) { + extent_type length = 0; if(backing.is_valid()) { - maximum_size = length; + OUTCOME_TRY(_length, backing.length()); + length = _length; + if(length == 0) + { + // Some systems allow zero sized maps, POSIX bans it + return std::errc::invalid_argument; + } + if(maximum_size > 0 && maximum_size > length) + { + // For compatibility with Windows, disallow sections larger than the file + return std::errc::value_too_large; + } } - else + if(!maximum_size) { - return std::errc::invalid_argument; + if(backing.is_valid()) + { + maximum_size = length; + } + else + { + return std::errc::invalid_argument; + } } } if(!backing.is_valid()) maximum_size = utils::round_up_to_page_size(maximum_size); result<section_handle> ret(section_handle(native_handle_type(), backing.is_valid() ? &backing : nullptr, maximum_size, _flag)); // There are no section handles on POSIX, so do nothing + native_handle_type &nativeh = ret.value()._v; + nativeh.fd = INT_MAX; + nativeh.behaviour |= native_handle_type::disposition::section; AFIO_LOG_FUNCTION_CALL(&ret); return ret; } @@ -75,20 +96,23 @@ result<section_handle::extent_type> section_handle::length() const noexcept result<section_handle::extent_type> section_handle::truncate(extent_type newsize) noexcept { AFIO_LOG_FUNCTION_CALL(this); - extent_type length = 0; if(_backing) { - OUTCOME_TRY(_length, _backing->length()); - length = _length; - if(length == 0) + extent_type length = 0; + if(!(_flag & flag::posix_skip_length_checks)) { - // Some systems allow zero sized maps, POSIX bans it - return std::errc::invalid_argument; - } - if(newsize > 0 && newsize > length) - { - // For compatibility with Windows, disallow sections larger than the file - return std::errc::value_too_large; + OUTCOME_TRY(_length, _backing->length()); + length = _length; + if(length == 0) + { + // Some systems allow zero sized maps, POSIX bans it + return std::errc::invalid_argument; + } + if(newsize > 0 && newsize > length) + { + // For compatibility with Windows, disallow sections larger than the file + return std::errc::value_too_large; + } } } else diff --git a/include/afio/v2.0/detail/impl/posix/mapped_file_handle.ipp b/include/afio/v2.0/detail/impl/posix/mapped_file_handle.ipp index eff0ef77..0eac991e 100644 --- a/include/afio/v2.0/detail/impl/posix/mapped_file_handle.ipp +++ b/include/afio/v2.0/detail/impl/posix/mapped_file_handle.ipp @@ -30,16 +30,20 @@ AFIO_V2_NAMESPACE_BEGIN result<mapped_file_handle::size_type> mapped_file_handle::reserve(size_type reservation) noexcept { AFIO_LOG_FUNCTION_CALL(this); + OUTCOME_TRY(length, underlying_file_length()); + if(length == 0) + { + return std::errc::invalid_argument; + } if(reservation == 0) { - OUTCOME_TRY(length, underlying_file_length()); reservation = length; } reservation = utils::round_up_to_page_size(reservation); if(!_sh.is_valid()) { - section_handle::flag sectionflags = section_handle::flag::readwrite; - OUTCOME_TRY(sh, section_handle::section(*this, 0, sectionflags)); + section_handle::flag sectionflags = section_handle::flag::readwrite | section_handle::flag::posix_skip_length_checks; + OUTCOME_TRY(sh, section_handle::section(*this, length, sectionflags)); _sh = std::move(sh); } if(_mh.is_valid() && reservation == _mh.length()) diff --git a/include/afio/v2.0/map_handle.hpp b/include/afio/v2.0/map_handle.hpp index 1d25974e..e2f44685 100644 --- a/include/afio/v2.0/map_handle.hpp +++ b/include/afio/v2.0/map_handle.hpp @@ -63,6 +63,8 @@ public: barrier_on_close = 1 << 16, //!< Maps of this section, if writable, issue a `barrier()` when destructed blocking until data (not metadata) reaches physical storage. // NOTE: IF UPDATING THIS UPDATE THE std::ostream PRINTER BELOW!!! + + posix_skip_length_checks = 1 << 28, readwrite = (read | write)}; QUICKCPPLIB_BITFIELD_END(flag); @@ -73,6 +75,10 @@ protected: flag _flag; public: +#ifndef _WIN32 + AFIO_HEADERS_ONLY_VIRTUAL_SPEC ~section_handle(); + AFIO_HEADERS_ONLY_VIRTUAL_SPEC result<void> close() noexcept override; +#endif //! Default constructor constexpr section_handle() : _backing(nullptr) diff --git a/include/afio/v2.0/mapped_file_handle.hpp b/include/afio/v2.0/mapped_file_handle.hpp index 64d79a44..ff1b8b5c 100644 --- a/include/afio/v2.0/mapped_file_handle.hpp +++ b/include/afio/v2.0/mapped_file_handle.hpp @@ -84,6 +84,7 @@ data, you can call `update_map()` which guarantees that the mapping your process sees is up to date, rather than relying on any kernel-specific automatic mapping. Whether automatic or enforced by `update_map()`, the reservation limit will not be exceeded nor will `address()` suddenly return something different. + It is thus up to you to detect that the reservation has been exhausted, and to reserve a new reservation which will change the value returned by `address()`. This entirely manual system is a bit tedious and cumbersome to use, but as mapping files @@ -100,9 +101,15 @@ Automatic mapping of growing files on various kernels: <dl> <dt>Microsoft Windows</dt> <dd>For the current Terminal Services Session, the first `mapped_file_handle::truncate()` or -`mapped_file_handle::update_map()` by any process update maps in all processes simultaneously.</dd> +`mapped_file_handle::update_map()` by any process update maps in all processes simultaneously. +Other methods for extending the file will require a `mapped_file_handle::update_map()` +by any process per Terminal Services Session to synchronise. +</dd> <dt>Linux</dt> -<dd>?</dd> +<dd>The Linux kernel automatically maps newly appended data to a file into all over extended +maps of that file. `mapped_file_handle::length()` will continue to return the old value until +`mapped_file_handle::update_map()` is called to refresh it. +</dd> <dt>FreeBSD</dt> <dd>?</dd> <dt>Apple MacOS</dt> @@ -115,7 +122,13 @@ Automatic mapping of shrinking files on various kernels: <dd>All maps and open section handles on the file anywhere in the system must be removed before any shrinkage of a file is permitted.</dd> <dt>Linux</dt> -<dd>?</dd> +<dd>Data written after the maximum extent up to the page boundary appears to be zeroed on flush +and any pages thereafter appear to be unmapped. Just to be safe, on all POSIX platforms +`mapped_file_handle::truncate()` specifically +undirties any pages about to be freed on newer kernels, or specifically deallocates them from +memory and physical storage on older kernels before doing the file shrink. This ensures +truncated pages don't get zombified. +</dd> <dt>FreeBSD</dt> <dd>?</dd> <dt>Apple MacOS</dt> @@ -152,7 +165,7 @@ public: mapped_file_handle() = default; //! Implicit move construction of mapped_file_handle permitted - mapped_file_handle(mapped_file_handle &&o) noexcept : file_handle(std::move(o)), _sh(std::move(o._sh)), _mh(std::move(o._mh)) + mapped_file_handle(mapped_file_handle &&o) noexcept : file_handle(std::move(o)), _reservation(std::move(o._reservation)), _sh(std::move(o._sh)), _mh(std::move(o._mh)) { _sh.set_backing(this); _mh.set_section(&_sh); diff --git a/test/tests/mapped_view.cpp b/test/tests/mapped_view.cpp index f849d4ec..124a5865 100644 --- a/test/tests/mapped_view.cpp +++ b/test/tests/mapped_view.cpp @@ -65,6 +65,10 @@ static inline void TestMappedView2() { using namespace AFIO_V2_NAMESPACE; using AFIO_V2_NAMESPACE::file_handle; + { + std::error_code ec; + filesystem::remove("testfile", ec); + } mapped_file_handle mfh = mapped_file_handle::mapped_file(1024 * 1024, {}, "testfile", file_handle::mode::write, file_handle::creation::if_needed, file_handle::caching::all, file_handle::flag::unlink_on_close).value(); BOOST_CHECK(mfh.address() == nullptr); mfh.truncate(10000 * sizeof(int)).value(); @@ -106,7 +110,8 @@ static inline void TestMappedView2() BOOST_CHECK(v1.size() == 10000); v1[0] = 78; v1[9999] = 79; - // Should have auto informed mfh of the change and remapped it for us + // On Windows this will have updated the mapping, on POSIX it will not, so prod POSIX + mfh.update_map().value(); v1 = mfh; BOOST_CHECK(v1.size() == 10000); BOOST_CHECK(v1[0] == 78); |