From 5271b74ac7b6ebdbe3d1f5241e1435a94918d14d Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 7 May 2022 01:35:41 +0100 Subject: Add functions for calculating the block sizes for large read/writes --- netfs/fuse/fuseFiles.cpp | 25 ++++++++++++++ netfs/fuse/fuseFiles.h | 14 ++++++++ netfs/unittests/testEdgeCases.cpp | 68 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) diff --git a/netfs/fuse/fuseFiles.cpp b/netfs/fuse/fuseFiles.cpp index 3ecb37f..a44f56e 100644 --- a/netfs/fuse/fuseFiles.cpp +++ b/netfs/fuse/fuseFiles.cpp @@ -210,6 +210,31 @@ namespace NetFS { } } + FuseApp::OpenFile::BlockSizes + FuseApp::OpenFile::blockSizes(size_t total, size_t max) noexcept + { + if (max >= total) { // Simple case, all in remainder block + return {total, 0, 0}; + } + else if (total % max == 0) { // Simplish case, multiples of max + return {0, max, total / max}; + } + else { + const auto blocks = (total / max); + const auto blockSize = (total / (blocks + 1)) + 1; + const auto batchTotal = blockSize * blocks; + const auto remainder = total - batchTotal; + + return {remainder, blockSize, blocks}; + } + } + + size_t + FuseApp::OpenFile::BlockSizes::total() const noexcept + { + return size1 + (sizeN * N); + } + ssize_t FuseApp::copy_file_range(const char *, struct fuse_file_info * fi_in, off_t offset_in, const char *, struct fuse_file_info * fi_out, off_t offset_out, size_t size, int flags) diff --git a/netfs/fuse/fuseFiles.h b/netfs/fuse/fuseFiles.h index 37e3dec..087e1ee 100644 --- a/netfs/fuse/fuseFiles.h +++ b/netfs/fuse/fuseFiles.h @@ -11,6 +11,20 @@ namespace NetFS { void flush(); void wait() const; + struct BlockSizes { + size_t size1, sizeN, N; + auto operator<=>(const BlockSizes &) const = default; + [[nodiscard]] size_t total() const noexcept; + }; + + [[nodiscard]] static BlockSizes blockSizes(size_t total, size_t max) noexcept; + + [[nodiscard]] auto + blockSizes(size_t total) const noexcept + { + return blockSizes(total, bodyMaxSize); + } + FilePrxPtr remote; const std::string path; const int flags; diff --git a/netfs/unittests/testEdgeCases.cpp b/netfs/unittests/testEdgeCases.cpp index 5249aed..f47ecd4 100644 --- a/netfs/unittests/testEdgeCases.cpp +++ b/netfs/unittests/testEdgeCases.cpp @@ -1,6 +1,9 @@ #define BOOST_TEST_MODULE TestNetFSEdgeCases + +#include "fuseFiles.h" #include "mockDaemon.h" #include "mockFuse.h" +#include #include #include #include @@ -121,6 +124,71 @@ BOOST_AUTO_TEST_CASE(manyThreads) BOOST_CHECK_EQUAL(failure, 0); } +namespace std { + ostream & + operator<<(ostream & s, const FuseMock::OpenFile::BlockSizes & b) + { + return s << '(' << b.size1 << '+' << b.sizeN << '*' << b.N << ')'; + } +} + +BOOST_AUTO_TEST_CASE(blockSizes) +{ + using BS = NetFS::FuseApp::OpenFile::BlockSizes; + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(1, 1), (BS {1, 0, 0})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(1, 5), (BS {1, 0, 0})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(5, 5), (BS {5, 0, 0})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(0, 1), (BS {0, 0, 0})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(5, 2), (BS {1, 2, 2})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(5, 3), (BS {2, 3, 1})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(29, 10), (BS {9, 10, 2})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(30, 10), (BS {0, 10, 3})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(31, 10), (BS {7, 8, 3})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(32, 10), (BS {5, 9, 3})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(33, 10), (BS {6, 9, 3})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(34, 10), (BS {7, 9, 3})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(35, 10), (BS {8, 9, 3})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(36, 10), (BS {6, 10, 3})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(37, 10), (BS {7, 10, 3})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(38, 10), (BS {8, 10, 3})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(39, 10), (BS {9, 10, 3})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(40, 10), (BS {0, 10, 4})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(41, 10), (BS {5, 9, 4})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(1234, 100), (BS {94, 95, 12})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(1235, 100), (BS {83, 96, 12})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(1236, 100), (BS {84, 96, 12})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(1237, 100), (BS {85, 96, 12})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(1238, 100), (BS {86, 96, 12})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(1239, 100), (BS {87, 96, 12})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(1240, 100), (BS {88, 96, 12})); + BOOST_CHECK_EQUAL(NetFS::FuseApp::OpenFile::blockSizes(1241, 100), (BS {89, 96, 12})); +} + +BOOST_DATA_TEST_CASE(blockSizes_range, + boost::unit_test::data::xrange(1, 200) + * boost::unit_test::data::make({1, 5, 10, 16, 32, 256, 1024}), + total, max) +{ + const auto bs = NetFS::FuseApp::OpenFile::blockSizes(total, max); + BOOST_CHECK_LE(bs.size1, max); + BOOST_CHECK_LE(bs.sizeN, max); + BOOST_CHECK_EQUAL(bs.total(), total); + BOOST_CHECK_NE(bs.size1, bs.sizeN); +} + +BOOST_DATA_TEST_CASE(blockSizes_scatter, + (boost::unit_test::data::xrange(1, 200, 17LU) + boost::unit_test::data::xrange(1200, 1300, 3LU)) + * (boost::unit_test::data::xrange(1, 100) + + boost::unit_test::data::xrange(256, 4096, 256LU)), + total, max) +{ + const auto bs = NetFS::FuseApp::OpenFile::blockSizes(total, max); + BOOST_CHECK_LE(bs.size1, max); + BOOST_CHECK_LE(bs.sizeN, max); + BOOST_CHECK_EQUAL(bs.total(), total); + BOOST_CHECK_NE(bs.size1, bs.sizeN); +} + BOOST_AUTO_TEST_CASE(bigWritesAsync) { MockDaemonHost daemon(testEndpoint, {"--NetFSD.ConfigPath=" + (rootDir / "defaultDaemon.xml").string()}); -- cgit v1.2.3