mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Wrap Output in a coroutine that periodically yields.
This commit is contained in:
committed by
Vinnie Falco
parent
192cdd028e
commit
7cfac1a91a
59
src/ripple/rpc/impl/Coroutine.cpp
Normal file
59
src/ripple/rpc/impl/Coroutine.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/rpc/Coroutine.h>
|
||||
#include <ripple/rpc/impl/TestOutputSuite.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace RPC {
|
||||
|
||||
using CoroutinePull = boost::coroutines::coroutine <void>::pull_type;
|
||||
|
||||
struct Coroutine::Impl : CoroutinePull
|
||||
{
|
||||
Impl (CoroutinePull&& p) : CoroutinePull (std::move(p)) {}
|
||||
};
|
||||
|
||||
Coroutine::Coroutine (YieldFunction const& yieldFunction)
|
||||
{
|
||||
CoroutinePull pull ([yieldFunction] (
|
||||
boost::coroutines::coroutine <void>::push_type& push)
|
||||
{
|
||||
Yield yield = [&push] () { push(); };
|
||||
yield ();
|
||||
yieldFunction (yield);
|
||||
});
|
||||
|
||||
impl_ = std::make_shared<Impl> (std::move (pull));
|
||||
}
|
||||
|
||||
Coroutine::~Coroutine() = default;
|
||||
|
||||
Coroutine::operator bool() const
|
||||
{
|
||||
return bool (*impl_);
|
||||
}
|
||||
|
||||
void Coroutine::operator()() const
|
||||
{
|
||||
(*impl_)();
|
||||
}
|
||||
|
||||
} // RPC
|
||||
} // ripple
|
||||
74
src/ripple/rpc/impl/Coroutine.test.cpp
Normal file
74
src/ripple/rpc/impl/Coroutine.test.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/rpc/Coroutine.h>
|
||||
#include <ripple/rpc/Yield.h>
|
||||
#include <ripple/rpc/impl/TestOutputSuite.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace RPC {
|
||||
|
||||
class Coroutine_test : public TestOutputSuite
|
||||
{
|
||||
public:
|
||||
using Strings = std::vector <std::string>;
|
||||
|
||||
void test (std::string const& name, int chunkSize, Strings const& expected)
|
||||
{
|
||||
setup (name);
|
||||
|
||||
std::string buffer;
|
||||
Output output = stringOutput (buffer);
|
||||
|
||||
auto coroutine = Coroutine ([=] (Yield yield)
|
||||
{
|
||||
auto out = chunkedYieldingOutput (output, yield, chunkSize);
|
||||
out ("hello ");
|
||||
out ("there ");
|
||||
out ("world.");
|
||||
});
|
||||
|
||||
Strings result;
|
||||
while (coroutine)
|
||||
{
|
||||
coroutine();
|
||||
result.push_back (buffer);
|
||||
}
|
||||
|
||||
auto r = strJoin (result.begin(), result.end(), ", ");
|
||||
auto e = strJoin (expected.begin(), expected.end(), ", ");
|
||||
expectEquals (r, e);
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
test ("zero", 0, {"hello ", "hello there ", "hello there world."});
|
||||
test ("three", 3, {"hello ", "hello there ", "hello there world."});
|
||||
test ("five", 5, {"hello ", "hello there ", "hello there world."});
|
||||
test ("seven", 7, {"hello there ", "hello there world."});
|
||||
test ("ten", 10, {"hello there ", "hello there world."});
|
||||
test ("thirteen", 13, {"hello there world."});
|
||||
test ("fifteen", 15, {"hello there world."});
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(Coroutine, RPC, ripple);
|
||||
|
||||
} // RPC
|
||||
} // ripple
|
||||
@@ -45,11 +45,12 @@ protected:
|
||||
// Test the result and report values.
|
||||
void expectResult (std::string const& expected)
|
||||
{
|
||||
expectResult (output_, expected);
|
||||
writer_.reset ();
|
||||
expectEquals (output_, expected);
|
||||
}
|
||||
|
||||
// Test the result and report values.
|
||||
void expectResult (std::string const& result, std::string const& expected)
|
||||
void expectEquals (std::string const& result, std::string const& expected)
|
||||
{
|
||||
expect (result == expected,
|
||||
"\n" "result: '" + result + "'" +
|
||||
|
||||
76
src/ripple/rpc/impl/Yield.cpp
Normal file
76
src/ripple/rpc/impl/Yield.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/rpc/Yield.h>
|
||||
#include <ripple/rpc/impl/TestOutputSuite.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace RPC {
|
||||
|
||||
Output chunkedYieldingOutput (
|
||||
Output const& output, Yield const& yield, std::size_t chunkSize)
|
||||
{
|
||||
auto count = std::make_shared <std::size_t> (0);
|
||||
return [chunkSize, count, output, yield] (boost::string_ref const& bytes)
|
||||
{
|
||||
if (*count > chunkSize)
|
||||
{
|
||||
yield();
|
||||
*count = 0;
|
||||
}
|
||||
output (bytes);
|
||||
*count += bytes.size();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
CountedYield::CountedYield (std::size_t yieldCount, Yield const& yield)
|
||||
: yieldCount_ (yieldCount), yield_ (yield)
|
||||
{
|
||||
}
|
||||
|
||||
void CountedYield::yield()
|
||||
{
|
||||
if (yieldCount_) {
|
||||
if (++count_ >= yieldCount_)
|
||||
{
|
||||
yield_();
|
||||
count_ = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
YieldStrategy makeYieldStrategy (Section const& s)
|
||||
{
|
||||
YieldStrategy ys;
|
||||
ys.streaming = get<bool> (s, "streaming") ?
|
||||
YieldStrategy::Streaming::yes :
|
||||
YieldStrategy::Streaming::no;
|
||||
ys.useCoroutines = get<bool> (s, "use_coroutines") ?
|
||||
YieldStrategy::UseCoroutines::yes :
|
||||
YieldStrategy::UseCoroutines::no;
|
||||
ys.byteYieldCount = get<std::size_t> (s, "byte_yield_count");
|
||||
ys.accountYieldCount = get<std::size_t> (s, "account_yield_count");
|
||||
ys.transactionYieldCount = get<std::size_t> (s, "transaction_yield_count");
|
||||
|
||||
return ys;
|
||||
}
|
||||
|
||||
} // RPC
|
||||
} // ripple
|
||||
105
src/ripple/rpc/impl/Yield.test.cpp
Normal file
105
src/ripple/rpc/impl/Yield.test.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/rpc/Yield.h>
|
||||
#include <ripple/rpc/impl/TestOutputSuite.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace RPC {
|
||||
|
||||
struct Yield_test : TestOutputSuite
|
||||
{
|
||||
void chunkedYieldingTest ()
|
||||
{
|
||||
setup ("chunkedYieldingTest");
|
||||
std::string lastYield;
|
||||
|
||||
auto yield = [&]() { lastYield = output_; };
|
||||
auto output = chunkedYieldingOutput (stringOutput (output_), yield, 5);
|
||||
output ("hello");
|
||||
expectResult ("hello");
|
||||
expectEquals (lastYield, "");
|
||||
|
||||
output (", th"); // Goes over the boundary.
|
||||
expectResult ("hello, th");
|
||||
expectEquals (lastYield, "");
|
||||
|
||||
output ("ere!"); // Forces a yield.
|
||||
expectResult ("hello, there!");
|
||||
expectEquals (lastYield, "hello, th");
|
||||
|
||||
output ("!!");
|
||||
expectResult ("hello, there!!!");
|
||||
expectEquals (lastYield, "hello, th");
|
||||
|
||||
output (""); // Forces a yield.
|
||||
expectResult ("hello, there!!!");
|
||||
expectEquals (lastYield, "hello, there!!!");
|
||||
}
|
||||
|
||||
void trivialCountedYieldTest()
|
||||
{
|
||||
setup ("trivialCountedYield");
|
||||
|
||||
auto didYield = false;
|
||||
auto yield = [&]() { didYield = true; };
|
||||
|
||||
CountedYield cy (0, yield);
|
||||
|
||||
for (auto i = 0; i < 4; ++i)
|
||||
{
|
||||
cy.yield();
|
||||
expect (!didYield, "We yielded when we shouldn't have.");
|
||||
}
|
||||
}
|
||||
|
||||
void countedYieldTest()
|
||||
{
|
||||
setup ("countedYield");
|
||||
|
||||
auto didYield = false;
|
||||
auto yield = [&]() { didYield = true; };
|
||||
|
||||
CountedYield cy (5, yield);
|
||||
|
||||
for (auto j = 0; j < 3; ++j)
|
||||
{
|
||||
for (auto i = 0; i < 4; ++i)
|
||||
{
|
||||
cy.yield();
|
||||
expect (!didYield, "We yielded when we shouldn't have.");
|
||||
}
|
||||
cy.yield();
|
||||
expect (didYield, "We didn't yield");
|
||||
didYield = false;
|
||||
}
|
||||
}
|
||||
|
||||
void run () override
|
||||
{
|
||||
chunkedYieldingTest();
|
||||
trivialCountedYieldTest();
|
||||
countedYieldTest();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(Yield, ripple_basics, ripple);
|
||||
|
||||
} // RPC
|
||||
} // ripple
|
||||
Reference in New Issue
Block a user