summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--netfs/fuse/fuseFiles.cpp151
-rw-r--r--netfs/fuse/fuseFiles.h15
-rw-r--r--netfs/unittests/testEdgeCases.cpp65
3 files changed, 56 insertions, 175 deletions
diff --git a/netfs/fuse/fuseFiles.cpp b/netfs/fuse/fuseFiles.cpp
index f47138d..fd313e5 100644
--- a/netfs/fuse/fuseFiles.cpp
+++ b/netfs/fuse/fuseFiles.cpp
@@ -5,13 +5,13 @@
#include <algorithm>
#include <cstring>
#include <entCache.h>
-#include <functional>
#include <future>
-#include <iterator>
#include <memory>
#include <mutex>
#include <numeric.h>
#include <numeric>
+#include <ranges>
+#include <span>
#include <utility>
#include <vector>
@@ -164,74 +164,61 @@ namespace NetFS {
}
}
- namespace {
- void
- blockSizeIterate(FuseApp::OpenFile::BlockSizes blockSizes, auto && callback)
- {
- if (blockSizes.size1) {
- callback(blockSizes.size1);
- }
- while (blockSizes.countN--) {
- callback(blockSizes.sizeN);
- }
- }
- }
-
int
FuseApp::read(const char *, char * buf, size_t size, off_t offset, struct fuse_file_info * fileInfo)
{
try {
+ const std::span out(buf, size);
using BackgroundOps = std::vector<std::promise<int>>;
- auto cpy = [buf](off_t blockOffset, const auto && data) -> int {
- std::copy(data.begin(), data.end(), buf + blockOffset);
+ const auto cpy = [out](off_t blockOffset, const auto && data) -> int {
+ std::ranges::copy(data, out.begin() + blockOffset);
return safe {data.size()};
};
- auto collateTotal = [](auto && ops) {
+ const auto collateTotal = [](auto && ops) {
return std::accumulate(ops.begin(), ops.end(), 0, [](auto && total, auto & operation) {
return total += operation.get_future().get();
});
};
auto openFile = getProxy<OpenFilePtr>(fileInfo->fh);
auto remote = openFile->remote;
- auto blockSizes = openFile->blockSizes(size);
if (fcr->Async) {
- BackgroundOps ops(blockSizes.count());
- blockSizeIterate(blockSizes,
- [&offset, &openFile, &remote, blockOffset = 0U, &cpy, opIter = ops.begin()](
- safe<size_t> blockSize) mutable {
- waitOnWriteRangeAndThen(blockSize, offset, openFile,
- [thisOp = opIter++, offset, blockOffset, blockSize, &remote, &cpy](const auto &) {
+ const auto blocks = out | std::views::chunk(openFile->bodyMaxSize);
+ BackgroundOps ops(blocks.size());
+ std::ranges::for_each(
+ blocks, [offset, &openFile, &remote, &cpy, opIter = ops.begin(), out](auto && block) mutable {
+ waitOnWriteRangeAndThen(block.size(), offset, openFile,
+ [thisOp = opIter++, offset, &remote, &cpy, block, out](const auto &) {
+ const auto outPosition = block.begin() - out.begin();
+ const auto position = offset + outPosition;
return remote->readAsync(
- offset, blockSize,
- [cpy, thisOp, blockOffset](auto && resultBuf) {
+ position, safe(block.size()),
+ [cpy, thisOp, outPosition](auto && resultBuf) {
thisOp->set_value(
- cpy(blockOffset, std::forward<Ice::ByteSeq>(resultBuf)));
+ cpy(outPosition, std::forward<Ice::ByteSeq>(resultBuf)));
},
[thisOp](auto error) {
thisOp->set_exception(std::move(error));
});
});
- offset += blockSize;
- blockOffset += blockSize;
});
return collateTotal(ops);
}
if (openFile->bodyMaxSize < size) {
- BackgroundOps ops(blockSizes.count());
- blockSizeIterate(blockSizes,
- [&offset, &remote, blockOffset = 0U, &cpy, opIter = ops.begin()](
- safe<size_t> blockSize) mutable {
+ const auto blocks = out | std::views::chunk(openFile->bodyMaxSize);
+ BackgroundOps ops(blocks.size());
+ std::ranges::for_each(
+ blocks, [offset, &remote, out, &cpy, opIter = ops.begin()](auto && block) mutable {
auto thisOp = opIter++;
+ const auto outPosition = block.begin() - out.begin();
+ const auto position = offset + outPosition;
remote->readAsync(
- offset, blockSize,
- [cpy, thisOp, blockOffset](auto && resultBuf) {
- thisOp->set_value(cpy(blockOffset, std::forward<Ice::ByteSeq>(resultBuf)));
+ position, safe(block.size()),
+ [cpy, thisOp, outPosition](auto && resultBuf) {
+ thisOp->set_value(cpy(outPosition, std::forward<Ice::ByteSeq>(resultBuf)));
},
[thisOp](auto error) {
thisOp->set_exception(std::move(error));
});
- offset += blockSize;
- blockOffset += blockSize;
});
return collateTotal(ops);
}
@@ -245,44 +232,47 @@ namespace NetFS {
int
FuseApp::write(const char *, const char * buf, size_t size, off_t offset, struct fuse_file_info * fileInfo)
{
+ static auto toBuffer = [](auto block) {
+ return std::make_pair(std::to_address(block.begin()), std::to_address(block.end()));
+ };
try {
auto openFile = getProxy<OpenFilePtr>(fileInfo->fh);
auto remote = openFile->remote;
- auto bytes = reinterpret_cast<const ::Ice::Byte *>(buf);
+ const std::span bytes {reinterpret_cast<const ::Ice::Byte *>(buf), size};
if (fcr->Async) {
- blockSizeIterate(
- openFile->blockSizes(size), [&bytes, &offset, &remote, &openFile](safe<size_t> blockSize) {
- waitOnWriteRangeAndThen(blockSize, offset, openFile,
- [offset, blockSize, bytes, &openFile, remote](const auto & key) {
- auto p = std::make_shared<OpenFile::WriteState>();
- openFile->bg.insert({key, p});
- remote->writeAsync(
- offset, blockSize, std::make_pair(bytes, bytes + blockSize),
- [p, openFile, key]() {
- p->promise.set_value();
- ScopeLock(openFile->mutex) {
- openFile->bg.erase(key);
- }
- },
- [p, openFile](auto error) {
- p->promise.set_exception(std::move(error));
- });
- });
- bytes += blockSize;
- offset += blockSize;
- });
+ const auto blocks = bytes | std::views::chunk(openFile->bodyMaxSize);
+ std::ranges::for_each(blocks, [&remote, bytes, offset, &openFile](auto && block) {
+ const auto position = offset + (block.begin() - bytes.begin());
+ waitOnWriteRangeAndThen(
+ block.size(), position, openFile, [position, block, &openFile, remote](const auto & key) {
+ auto pendingWrite = std::make_shared<OpenFile::WriteState>();
+ openFile->bg.insert({key, pendingWrite});
+ remote->writeAsync(
+ position, safe(block.size()), toBuffer(block),
+ [pendingWrite, openFile, key]() {
+ pendingWrite->promise.set_value();
+ ScopeLock(openFile->mutex) {
+ openFile->bg.erase(key);
+ }
+ },
+ [pendingWrite, openFile](auto error) {
+ pendingWrite->promise.set_exception(std::move(error));
+ });
+ });
+ });
}
else if (openFile->bodyMaxSize < size) {
+ const auto blocks = bytes | std::views::chunk(openFile->bodyMaxSize);
std::vector<std::future<void>> ops;
- blockSizeIterate(openFile->blockSizes(size), [&ops, &bytes, &offset, &remote](safe<size_t> blockSize) {
- ops.emplace_back(remote->writeAsync(offset, blockSize, std::make_pair(bytes, bytes + blockSize)));
- bytes += blockSize;
- offset += blockSize;
+ ops.reserve(blocks.size());
+ std::ranges::transform(blocks, std::back_inserter(ops), [&remote, bytes, offset](auto && block) {
+ const auto position = offset + (block.begin() - bytes.begin());
+ return remote->writeAsync(position, safe(block.size()), toBuffer(block));
});
std::ranges::for_each(ops, &std::future<void>::get);
}
else {
- remote->write(offset, safe {size}, std::make_pair(bytes, bytes + size));
+ remote->write(offset, safe {size}, toBuffer(bytes));
}
return safe {size};
}
@@ -291,35 +281,6 @@ 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 {.size1 = total, .sizeN = 0, .countN = 0};
- }
- if (total % max == 0) { // Simplish case, multiples of max
- return {.size1 = 0, .sizeN = max, .countN = total / max};
- }
- const auto blocks = (total / max);
- const auto blockSize = (total / (blocks + 1)) + 1;
- const auto batchTotal = blockSize * blocks;
- const auto remainder = total - batchTotal;
-
- return {.size1 = remainder, .sizeN = blockSize, .countN = blocks};
- }
-
- size_t
- FuseApp::OpenFile::BlockSizes::total() const noexcept
- {
- return size1 + (sizeN * countN);
- }
-
- size_t
- FuseApp::OpenFile::BlockSizes::count() const noexcept
- {
- return countN + (size1 ? 1 : 0);
- }
-
ssize_t
FuseApp::copy_file_range(const char *, struct fuse_file_info * fileInfoIn, off_t offsetIn, const char *,
struct fuse_file_info * fileInfoOut, off_t offsetOut, size_t size, int flags)
diff --git a/netfs/fuse/fuseFiles.h b/netfs/fuse/fuseFiles.h
index 9742236..672d30f 100644
--- a/netfs/fuse/fuseFiles.h
+++ b/netfs/fuse/fuseFiles.h
@@ -11,21 +11,6 @@ namespace NetFS {
void flush();
void wait() const;
- struct BlockSizes {
- size_t size1, sizeN, countN;
- auto operator<=>(const BlockSizes &) const = default;
- [[nodiscard]] size_t total() const noexcept;
- [[nodiscard]] size_t count() 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 07f2c18..5eb8d5d 100644
--- a/netfs/unittests/testEdgeCases.cpp
+++ b/netfs/unittests/testEdgeCases.cpp
@@ -127,71 +127,6 @@ 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.countN << ')';
- }
-}
-
-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<size_t>(1, 200)
- * boost::unit_test::data::make<size_t>({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<size_t>(1, 200, 17LU) + boost::unit_test::data::xrange<size_t>(1200, 1300, 3LU))
- * (boost::unit_test::data::xrange<size_t>(1, 100)
- + boost::unit_test::data::xrange<size_t>(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_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)