diff options
-rw-r--r-- | netfs/fuse/fuseFiles.cpp | 41 | ||||
-rw-r--r-- | netfs/unittests/testEdgeCases.cpp | 52 |
2 files changed, 72 insertions, 21 deletions
diff --git a/netfs/fuse/fuseFiles.cpp b/netfs/fuse/fuseFiles.cpp index c1709cd..c50dcf1 100644 --- a/netfs/fuse/fuseFiles.cpp +++ b/netfs/fuse/fuseFiles.cpp @@ -1,10 +1,12 @@ #include "fuseFiles.h" #include "fuseApp.impl.h" #include "lockHelpers.h" +#include <Ice/BuiltinSequences.h> #include <cstring> #include <entCache.h> #include <mutex> #include <numeric.h> +#include <numeric> namespace NetFS { FuseApp::OpenFile::WriteState::WriteState() : future(promise.get_future().share()) { } @@ -167,20 +169,47 @@ namespace NetFS { FuseApp::read(const char *, char * buf, size_t s, off_t o, struct fuse_file_info * fi) { try { - auto cpy = [buf](const auto && data) -> int { - std::copy(data.begin(), data.end(), buf); + struct bgOp { + bgOp(int o, std::future<Ice::ByteSeq> r) : offset {o}, response {std::move(r)} { } + int offset; + std::future<Ice::ByteSeq> response; + }; + auto cpy = [buf](off_t blockOffset, const auto && data) -> int { + std::copy(data.begin(), data.end(), buf + blockOffset); return safe {data.size()}; }; auto of = getProxy<OpenFilePtr>(fi->fh); auto remote = of->remote; + auto blockSizes = of->blockSizes(s); if (fcr->Async) { - auto p = waitOnWriteRangeAndThen<std::future<Buffer>>(s, o, of, [o, s, &remote](const auto &) { - return remote->readAsync(o, safe {s}); + std::vector<bgOp> ops; + blockSizeIterate( + blockSizes, [&ops, &o, &of, &remote, blockOffset = 0U](safe<size_t> blockSize) mutable { + ops.emplace_back(blockOffset, + waitOnWriteRangeAndThen<std::future<Buffer>>( + blockSize, o, of, [o, blockSize, &remote](const auto &) { + return remote->readAsync(o, blockSize); + })); + o += blockSize; + blockOffset += blockSize; + }); + return std::accumulate(ops.begin(), ops.end(), 0, [cpy](auto && total, auto & op) { + return total += cpy(op.offset, op.response.get()); + }); + } + else if (of->bodyMaxSize < s) { + std::vector<bgOp> ops; + blockSizeIterate(blockSizes, [&ops, &o, &remote, blockOffset = 0U](safe<size_t> blockSize) mutable { + ops.emplace_back(blockOffset, remote->readAsync(o, blockSize)); + o += blockSize; + blockOffset += blockSize; + }); + return std::accumulate(ops.begin(), ops.end(), 0, [cpy](auto && total, auto & op) { + return total += cpy(op.offset, op.response.get()); }); - return cpy(p.get()); } else { - return cpy(remote->read(o, safe {s})); + return cpy(0, remote->read(o, safe {s})); } } catch (SystemError & e) { diff --git a/netfs/unittests/testEdgeCases.cpp b/netfs/unittests/testEdgeCases.cpp index c2e101f..0c78084 100644 --- a/netfs/unittests/testEdgeCases.cpp +++ b/netfs/unittests/testEdgeCases.cpp @@ -6,6 +6,7 @@ #include <boost/test/data/test_case.hpp> #include <boost/test/unit_test.hpp> #include <definedDirs.h> +#include <fcntl.h> #include <fileUtils.h> const std::string testEndpoint("tcp -h localhost -p 12014"); @@ -189,24 +190,45 @@ BOOST_DATA_TEST_CASE(blockSizes_scatter, BOOST_CHECK_NE(bs.size1, bs.sizeN); } -BOOST_DATA_TEST_CASE(bigWrites, +BOOST_DATA_TEST_CASE(bigWritesAndReads, boost::unit_test::data::make({"defaultFuseNoAsync.xml", "defaultFuse.xml"}) - * boost::unit_test::data::xrange<size_t>(1024UL * 100UL, 4096UL * 1024UL, 512UL * 1024UL), - config, size) + * boost::unit_test::data::xrange<size_t>(1024UL * 100UL, 4096UL * 1024UL, 512UL * 1024UL) + * boost::unit_test::data::make<off_t>(0, 317, 4096UL * 1024UL), + config, size, offset) { MockDaemonHost daemon(testEndpoint, {"--NetFSD.ConfigPath=" + (rootDir / "defaultDaemon.xml").string()}); FuseMockHost fuse(testEndpoint, {(rootDir / config).string() + ":testvol", (rootDir / "test").string()}); - 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); - BOOST_CHECK_EQUAL(buf.size(), fuse.fuse->write("/big", buf.data(), buf.size(), 0, &fi)); - BOOST_REQUIRE_EQUAL(0, fuse.fuse->release("/big", &fi)); - - AdHoc::FileUtils::MemMap mm(daemon.TestExportRoot / "big"); - const auto file {mm.sv()}; - BOOST_CHECK_EQUAL_COLLECTIONS(buf.begin(), buf.end(), file.begin(), file.end()); + { + 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); + BOOST_REQUIRE_EQUAL(buf.size(), fuse.fuse->write("/big", buf.data(), buf.size(), offset, &fi)); + BOOST_REQUIRE_EQUAL(0, fuse.fuse->release("/big", &fi)); + } + + AdHoc::FileUtils::MemMap mm(daemon.TestExportRoot / "big"); + const auto file {mm.sv()}; + BOOST_CHECK_EQUAL_COLLECTIONS(buf.begin(), buf.end(), file.begin() + offset, file.end()); + } + { + auto buf = FuseMock::genRandomData(size); + { + fuse_file_info fi {}; + fi.flags = O_RDONLY; + auto fd = fuse.fuse->open("/big", &fi); + BOOST_REQUIRE_GE(fd, 0); + BOOST_REQUIRE_NE(fi.fh, 0); + BOOST_REQUIRE_EQUAL(buf.size(), fuse.fuse->read("/big", buf.data(), buf.size(), offset, &fi)); + BOOST_REQUIRE_EQUAL(0, fuse.fuse->release("/big", &fi)); + } + + AdHoc::FileUtils::MemMap mm(daemon.TestExportRoot / "big"); + const auto file {mm.sv()}; + BOOST_CHECK_EQUAL_COLLECTIONS(buf.begin(), buf.end(), file.begin() + offset, file.end()); + } } |