summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--netfs/fuse/fuseFiles.cpp41
-rw-r--r--netfs/unittests/testEdgeCases.cpp52
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());
+ }
}