diff options
author | John Ericson <John.Ericson@Obsidian.Systems> | 2020-07-11 23:40:49 +0000 |
---|---|---|
committer | John Ericson <John.Ericson@Obsidian.Systems> | 2020-07-14 13:56:36 +0000 |
commit | 592851fb67cd15807109d6f65fb81f6af89af966 (patch) | |
tree | 500c2246b6ae93bfe589fa45ded1f2788c8c7f8e /src/libutil | |
parent | 9de96ef7d409fedea092045c4dbae7177f88962a (diff) |
LocalStore::addToStoreFromDump copy in chunks
Rather than copying byte-by-byte, we let the coroutine know how much
data we would like it to send back to us.
Diffstat (limited to 'src/libutil')
-rw-r--r-- | src/libutil/serialise.cc | 33 | ||||
-rw-r--r-- | src/libutil/serialise.hh | 11 |
2 files changed, 30 insertions, 14 deletions
diff --git a/src/libutil/serialise.cc b/src/libutil/serialise.cc index c8b71188f..141e9e976 100644 --- a/src/libutil/serialise.cc +++ b/src/libutil/serialise.cc @@ -165,35 +165,43 @@ size_t StringSource::read(unsigned char * data, size_t len) #endif std::unique_ptr<Source> sinkToSource( - std::function<void(Sink &)> fun, + std::function<void(Sink &, size_t &)> fun, std::function<void()> eof) { struct SinkToSource : Source { - typedef boost::coroutines2::coroutine<std::string> coro_t; + typedef boost::coroutines2::coroutine<std::basic_string<uint8_t>> coro_t; - std::function<void(Sink &)> fun; + std::function<void(Sink &, size_t &)> fun; std::function<void()> eof; std::optional<coro_t::pull_type> coro; bool started = false; - SinkToSource(std::function<void(Sink &)> fun, std::function<void()> eof) + /* It would be nicer to have the co-routines have both args and a + return value, but unfortunately that was removed from Boost's + implementation for some reason, so we use some extra state instead. + */ + size_t wanted = 0; + + SinkToSource(std::function<void(Sink &, size_t &)> fun, std::function<void()> eof) : fun(fun), eof(eof) { } - std::string cur; + std::basic_string<uint8_t> cur; size_t pos = 0; size_t read(unsigned char * data, size_t len) override { - if (!coro) + wanted = len < cur.size() ? 0 : len - cur.size(); + if (!coro) { coro = coro_t::pull_type([&](coro_t::push_type & yield) { - LambdaSink sink([&](const unsigned char * data, size_t len) { - if (len) yield(std::string((const char *) data, len)); + LambdaSink sink([&](const uint8_t * data, size_t len) { + if (len) yield(std::basic_string<uint8_t> { data, len }); }); - fun(sink); + fun(sink, wanted); }); + } if (!*coro) { eof(); abort(); } @@ -203,11 +211,10 @@ std::unique_ptr<Source> sinkToSource( pos = 0; } - auto n = std::min(cur.size() - pos, len); - memcpy(data, (unsigned char *) cur.data() + pos, n); - pos += n; + auto numCopied = cur.copy(data, len, pos); + pos += numCopied; - return n; + return numCopied; } }; diff --git a/src/libutil/serialise.hh b/src/libutil/serialise.hh index 8386a4991..6cb9d1bf5 100644 --- a/src/libutil/serialise.hh +++ b/src/libutil/serialise.hh @@ -260,11 +260,20 @@ struct LambdaSource : Source /* Convert a function that feeds data into a Sink into a Source. The Source executes the function as a coroutine. */ std::unique_ptr<Source> sinkToSource( - std::function<void(Sink &)> fun, + std::function<void(Sink &, size_t &)> fun, std::function<void()> eof = []() { throw EndOfFile("coroutine has finished"); }); +static inline std::unique_ptr<Source> sinkToSource( + std::function<void(Sink &)> fun, + std::function<void()> eof = []() { + throw EndOfFile("coroutine has finished"); + }) +{ + return sinkToSource([fun](Sink & s, size_t & _) { fun(s); }, eof); +} + void writePadding(size_t len, Sink & sink); void writeString(const unsigned char * buf, size_t len, Sink & sink); |