/* Integration test kernel for mapped view
(C) 2017 Niall Douglas (2 commits)
File Created: Aug 2017
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License in the accompanying file
Licence.txt or at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file Licence.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
#include "../test_kernel_decl.hpp"
static inline void TestMappedView1()
{
using namespace LLFIO_V2_NAMESPACE;
using LLFIO_V2_NAMESPACE::file_handle;
file_handle fh = file_handle::file({}, "testfile", file_handle::mode::write, file_handle::creation::if_needed, file_handle::caching::all, file_handle::flag::unlink_on_first_close).value();
fh.truncate(10000 * sizeof(int)).value();
section_handle sh(section_handle::section(fh).value());
mapped v1(sh, 5);
mapped v2(sh);
mapped v3(50);
BOOST_CHECK(v1.size() == 5);
BOOST_CHECK(v2.size() == 10000);
BOOST_CHECK(v3.size() == 50);
v1[0] = 78;
BOOST_CHECK(v2[0] == 78);
v3[0] = 78;
v3[49] = 5;
BOOST_CHECK(v3[0] == 78);
BOOST_CHECK(v3[49] == 5);
try
{
// Overly large views must not extend the file until written to
mapped v4(sh, 20000);
BOOST_CHECK(fh.maximum_extent().value() == 10000 * sizeof(int));
}
catch(...)
{
#ifdef _WIN32
// Unlike POSIX, Windows refuses to map a view exceeding the length of the file
BOOST_CHECK(true);
#else
BOOST_CHECK(false);
#endif
}
}
static inline void TestMappedView2()
{
using namespace LLFIO_V2_NAMESPACE;
using LLFIO_V2_NAMESPACE::file_handle;
using LLFIO_V2_NAMESPACE::byte;
#ifndef _WIN32
std::cout << "NOTE: utils::running_under_wsl() = " << utils::running_under_wsl() << std::endl;
#endif
{
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_first_close).value();
BOOST_CHECK(mfh.address() == nullptr);
mfh.truncate(10000 * sizeof(int)).value();
byte *addr = mfh.address();
BOOST_CHECK(addr != nullptr);
attached v1(mfh);
BOOST_CHECK(v1.size() == 10000);
v1[0] = 78;
v1[9999] = 79;
mfh.truncate(20000 * sizeof(int)).value();
BOOST_CHECK(addr == mfh.address());
BOOST_CHECK(mfh.maximum_extent().value() == 20000 * sizeof(int));
BOOST_CHECK(mfh.underlying_file_maximum_extent().value() == 20000 * sizeof(int));
v1 = attached(mfh);
BOOST_CHECK(v1.size() == 20000);
BOOST_CHECK(v1[0] == 78);
BOOST_CHECK(v1[9999] == 79);
mfh.truncate(2 * 1024 * 1024).value(); // exceed reservation, cause hidden reserve
BOOST_CHECK(addr != nullptr);
v1 = attached(mfh);
BOOST_CHECK(v1.size() == 2 * 1024 * 1024 / sizeof(int));
BOOST_CHECK(v1[0] == 78);
BOOST_CHECK(v1[9999] == 79);
mfh.reserve(2 * 1024 * 1024).value();
BOOST_CHECK(mfh.address() != nullptr);
v1 = attached(mfh);
BOOST_CHECK(v1.size() == 2 * 1024 * 1024 / sizeof(int));
BOOST_CHECK(v1[0] == 78);
BOOST_CHECK(v1[9999] == 79);
#ifndef _WIN32
// Microsoft WSL hasn't implemented the shrinking of open maps yet
if(utils::running_under_wsl())
{
return;
}
#endif
mfh.truncate(1 * sizeof(int)).value();
BOOST_CHECK(mfh.address() != nullptr);
v1 = attached(mfh);
BOOST_CHECK(v1.size() == 1);
BOOST_CHECK(v1[0] == 78);
// Use a different handle to extend the file
mapped_file_handle mfh2 = mapped_file_handle::mapped_file(1024 * 1024, {}, "testfile", file_handle::mode::write, file_handle::creation::open_existing, file_handle::caching::all, file_handle::flag::unlink_on_first_close).value();
mfh2.truncate(10000 * sizeof(int)).value();
v1 = attached(mfh2);
BOOST_CHECK(v1.size() == 10000);
v1[0] = 78;
v1[9999] = 79;
// On Windows this will have updated the mapping, on POSIX it will not, so prod POSIX
mfh.update_map().value();
v1 = attached(mfh);
BOOST_CHECK(v1.size() == 10000);
BOOST_CHECK(v1[0] == 78);
BOOST_CHECK(v1[9999] == 79);
mfh2.map().close().value();
mfh2.section().close().value();
mfh.truncate(1 * sizeof(int)).value();
// Use a normal file handle to extend the file
file_handle fh = file_handle::file({}, "testfile", file_handle::mode::write, file_handle::creation::open_existing, file_handle::caching::all, file_handle::flag::unlink_on_first_close).value();
fh.truncate(10000 * sizeof(int)).value();
// On POSIX this will have updated the mapping, on Windows it will not, so prod Windows
mfh.update_map().value();
v1 = attached(mfh);
BOOST_REQUIRE(v1.size() == 10000);
BOOST_CHECK(v1[0] == 78);
BOOST_CHECK(v1[9999] == 0);
v1 = {};
mfh.truncate(0).value();
BOOST_CHECK(mfh.address() == nullptr);
}
KERNELTEST_TEST_KERNEL(integration, llfio, algorithm, mapped_span1, "Tests that llfio::mapped works as expected", TestMappedView1())
KERNELTEST_TEST_KERNEL(integration, llfio, algorithm, mapped_span2, "Tests that llfio::attached works as expected", TestMappedView2())