summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2022-05-07 02:30:20 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2022-05-07 02:30:20 +0100
commit5b36659096afb86daa81496560a496f33f413d9c (patch)
treec3e951dad014d5fd1b1352fb9286bb6c61d1c56f
parentHelper function to generate a vector of random data of a given size (diff)
downloadnetfs-5b36659096afb86daa81496560a496f33f413d9c.tar.bz2
netfs-5b36659096afb86daa81496560a496f33f413d9c.tar.xz
netfs-5b36659096afb86daa81496560a496f33f413d9c.zip
Fix and test performing large writes
Merges sync and async tests, variety sizes of random data, validated with direct file map
-rw-r--r--netfs/fuse/fuseFiles.cpp62
-rw-r--r--netfs/unittests/testEdgeCases.cpp36
2 files changed, 58 insertions, 40 deletions
diff --git a/netfs/fuse/fuseFiles.cpp b/netfs/fuse/fuseFiles.cpp
index a44f56e..9baf51f 100644
--- a/netfs/fuse/fuseFiles.cpp
+++ b/netfs/fuse/fuseFiles.cpp
@@ -184,24 +184,56 @@ namespace NetFS {
auto remote = of->remote;
auto bytes = reinterpret_cast<const ::Ice::Byte *>(buf);
if (fcr->Async) {
- waitOnWriteRangeAndThen<void>(s, o, of, [o, s, bytes, &of, remote](const auto & key) {
- auto p = std::make_shared<OpenFile::WriteState>();
- of->bg.insert({key, p});
- remote->writeAsync(
- o, safe {s}, std::make_pair(bytes, bytes + s),
- [p, of, key]() {
- p->promise.set_value();
- ScopeLock(of->mutex) {
- of->bg.erase(key);
- }
- },
- [p, of](auto e) {
- p->promise.set_exception(e);
+ auto sendSome = [&bytes, &o, &remote, &of](safe<size_t> blockSize) {
+ waitOnWriteRangeAndThen<void>(
+ blockSize, o, of, [o, blockSize, bytes, &of, remote](const auto & key) {
+ auto p = std::make_shared<OpenFile::WriteState>();
+ of->bg.insert({key, p});
+ remote->writeAsync(
+ o, blockSize, std::make_pair(bytes, bytes + blockSize),
+ [p, of, key]() {
+ p->promise.set_value();
+ ScopeLock(of->mutex) {
+ of->bg.erase(key);
+ }
+ },
+ [p, of](auto e) {
+ p->promise.set_exception(e);
+ });
});
- });
+ bytes += blockSize;
+ o += blockSize;
+ };
+ auto bs = of->blockSizes(s);
+ if (bs.size1) {
+ sendSome(bs.size1);
+ }
+ while (bs.N--) {
+ sendSome(bs.sizeN);
+ }
}
else {
- remote->write(o, safe {s}, std::make_pair(bytes, bytes + s));
+ if (of->bodyMaxSize < s) {
+ std::vector<std::future<void>> ops;
+ auto sendSome = [&ops, &bytes, &o, &remote](safe<size_t> blockSize) {
+ ops.emplace_back(remote->writeAsync(o, blockSize, std::make_pair(bytes, bytes + blockSize)));
+ bytes += blockSize;
+ o += blockSize;
+ };
+ auto bs = of->blockSizes(s);
+ if (bs.size1) {
+ sendSome(bs.size1);
+ }
+ while (bs.N--) {
+ sendSome(bs.sizeN);
+ }
+ std::for_each(ops.begin(), ops.end(), [](auto && op) {
+ op.get();
+ });
+ }
+ else {
+ remote->write(o, safe {s}, std::make_pair(bytes, bytes + s));
+ }
}
return safe {s};
}
diff --git a/netfs/unittests/testEdgeCases.cpp b/netfs/unittests/testEdgeCases.cpp
index f47ecd4..d587b13 100644
--- a/netfs/unittests/testEdgeCases.cpp
+++ b/netfs/unittests/testEdgeCases.cpp
@@ -6,7 +6,7 @@
#include <boost/test/data/test_case.hpp>
#include <boost/test/unit_test.hpp>
#include <definedDirs.h>
-#include <random>
+#include <fileUtils.h>
const std::string testEndpoint("tcp -h localhost -p 12014");
@@ -189,38 +189,24 @@ BOOST_DATA_TEST_CASE(blockSizes_scatter,
BOOST_CHECK_NE(bs.size1, bs.sizeN);
}
-BOOST_AUTO_TEST_CASE(bigWritesAsync)
+BOOST_DATA_TEST_CASE(bigWrites,
+ boost::unit_test::data::make({"defaultFuseNoAsync.xml", "defaultFuse.xml"})
+ * boost::unit_test::data::xrange<size_t>(1024 * 100, 4096 * 1024, 512UL * 1024),
+ config, size)
{
MockDaemonHost daemon(testEndpoint, {"--NetFSD.ConfigPath=" + (rootDir / "defaultDaemon.xml").string()});
- FuseMockHost fuse(testEndpoint, {(rootDir / "defaultFuse.xml").string() + ":testvol", (rootDir / "test").string()});
+ FuseMockHost fuse(testEndpoint, {(rootDir / config).string() + ":testvol", (rootDir / "test").string()});
- std::vector<char> buf(1 * 1024 * 1024);
+ const auto buf = FuseMock::genRandomData(size);
fuse_file_info fi {};
fi.flags = O_RDWR;
auto fd = fuse.fuse->create("/big", 0600, &fi);
BOOST_REQUIRE_GE(fd, 0);
BOOST_REQUIRE_NE(fi.fh, 0);
- // async success
BOOST_CHECK_EQUAL(buf.size(), fuse.fuse->write("/big", buf.data(), buf.size(), 0, &fi));
- // failure on flush/close
- BOOST_REQUIRE_EQUAL(-EIO, fuse.fuse->release("/big", &fi));
- BOOST_CHECK_EQUAL(0, std::filesystem::file_size(daemon.TestExportRoot / "big"));
-}
-
-BOOST_AUTO_TEST_CASE(bigWritesNoAsync)
-{
- MockDaemonHost daemon(testEndpoint, {"--NetFSD.ConfigPath=" + (rootDir / "defaultDaemon.xml").string()});
- FuseMockHost fuse(
- testEndpoint, {(rootDir / "defaultFuseNoAsync.xml").string() + ":testvol", (rootDir / "test").string()});
-
- std::vector<char> buf(1 * 1024 * 1024);
- fuse_file_info fi {};
- fi.flags = O_RDWR;
- auto fd = fuse.fuse->create("/big", 0600, &fi);
- BOOST_REQUIRE_GE(fd, 0);
- BOOST_REQUIRE_NE(fi.fh, 0);
- // sync fail
- BOOST_CHECK_EQUAL(-EIO, fuse.fuse->write("/big", buf.data(), buf.size(), 0, &fi));
BOOST_REQUIRE_EQUAL(0, fuse.fuse->release("/big", &fi));
- BOOST_CHECK_EQUAL(0, std::filesystem::file_size(daemon.TestExportRoot / "big"));
+
+ AdHoc::FileUtils::MemMap mm(daemon.TestExportRoot / "big");
+ const auto file {mm.sv()};
+ BOOST_CHECK_EQUAL_COLLECTIONS(buf.begin(), buf.end(), file.begin(), file.end());
}