aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/bench/checkqueue.cpp7
-rw-r--r--src/checkqueue.h25
-rw-r--r--src/test/checkqueue_tests.cpp51
-rw-r--r--src/test/fuzz/checkqueue.cpp12
-rw-r--r--src/test/transaction_tests.cpp6
-rw-r--r--src/validation.cpp5
-rw-r--r--src/validation.h21
7 files changed, 45 insertions, 82 deletions
diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp
index dfd7275f46..8ad6fde6bf 100644
--- a/src/bench/checkqueue.cpp
+++ b/src/bench/checkqueue.cpp
@@ -29,7 +29,6 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench)
struct PrevectorJob {
prevector<PREVECTOR_SIZE, uint8_t> p;
- PrevectorJob() = default;
explicit PrevectorJob(FastRandomContext& insecure_rand){
p.resize(insecure_rand.randrange(PREVECTOR_SIZE*2));
}
@@ -37,10 +36,6 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench)
{
return true;
}
- void swap(PrevectorJob& x) noexcept
- {
- p.swap(x.p);
- };
};
CCheckQueue<PrevectorJob> queue {QUEUE_BATCH_SIZE};
// The main thread should be counted to prevent thread oversubscription, and
@@ -60,7 +55,7 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench)
// Make insecure_rand here so that each iteration is identical.
CCheckQueueControl<PrevectorJob> control(&queue);
for (auto vChecks : vBatches) {
- control.Add(vChecks);
+ control.Add(std::move(vChecks));
}
// control waits for completion by RAII, but
// it is done explicitly here for clarity
diff --git a/src/checkqueue.h b/src/checkqueue.h
index d83f717fb7..2c21e5f7d0 100644
--- a/src/checkqueue.h
+++ b/src/checkqueue.h
@@ -11,6 +11,7 @@
#include <util/threadnames.h>
#include <algorithm>
+#include <iterator>
#include <vector>
template <typename T>
@@ -111,13 +112,9 @@ private:
// * Try to account for idle jobs which will instantly start helping.
// * Don't do batches smaller than 1 (duh), or larger than nBatchSize.
nNow = std::max(1U, std::min(nBatchSize, (unsigned int)queue.size() / (nTotal + nIdle + 1)));
- vChecks.resize(nNow);
- for (unsigned int i = 0; i < nNow; i++) {
- // We want the lock on the m_mutex to be as short as possible, so swap jobs from the global
- // queue to the local batch vector instead of copying.
- vChecks[i].swap(queue.back());
- queue.pop_back();
- }
+ auto start_it = queue.end() - nNow;
+ vChecks.assign(std::make_move_iterator(start_it), std::make_move_iterator(queue.end()));
+ queue.erase(start_it, queue.end());
// Check whether we need to do work at all
fOk = fAllOk;
}
@@ -165,7 +162,7 @@ public:
}
//! Add a batch of checks to the queue
- void Add(std::vector<T>& vChecks) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
+ void Add(std::vector<T>&& vChecks) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
{
if (vChecks.empty()) {
return;
@@ -173,10 +170,7 @@ public:
{
LOCK(m_mutex);
- for (T& check : vChecks) {
- queue.emplace_back();
- check.swap(queue.back());
- }
+ queue.insert(queue.end(), std::make_move_iterator(vChecks.begin()), std::make_move_iterator(vChecks.end()));
nTodo += vChecks.size();
}
@@ -239,10 +233,11 @@ public:
return fRet;
}
- void Add(std::vector<T>& vChecks)
+ void Add(std::vector<T>&& vChecks)
{
- if (pqueue != nullptr)
- pqueue->Add(vChecks);
+ if (pqueue != nullptr) {
+ pqueue->Add(std::move(vChecks));
+ }
}
~CCheckQueueControl()
diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp
index 135f107159..012b0eb321 100644
--- a/src/test/checkqueue_tests.cpp
+++ b/src/test/checkqueue_tests.cpp
@@ -43,7 +43,6 @@ struct FakeCheck {
{
return true;
}
- void swap(FakeCheck& x) noexcept {};
};
struct FakeCheckCheckCompletion {
@@ -53,7 +52,6 @@ struct FakeCheckCheckCompletion {
n_calls.fetch_add(1, std::memory_order_relaxed);
return true;
}
- void swap(FakeCheckCheckCompletion& x) noexcept {};
};
struct FailingCheck {
@@ -64,10 +62,6 @@ struct FailingCheck {
{
return !fails;
}
- void swap(FailingCheck& x) noexcept
- {
- std::swap(fails, x.fails);
- };
};
struct UniqueCheck {
@@ -82,10 +76,6 @@ struct UniqueCheck {
results.insert(check_id);
return true;
}
- void swap(UniqueCheck& x) noexcept
- {
- std::swap(x.check_id, check_id);
- };
};
@@ -113,19 +103,13 @@ struct MemoryCheck {
{
fake_allocated_memory.fetch_sub(b, std::memory_order_relaxed);
};
- void swap(MemoryCheck& x) noexcept
- {
- std::swap(b, x.b);
- };
};
struct FrozenCleanupCheck {
static std::atomic<uint64_t> nFrozen;
static std::condition_variable cv;
static std::mutex m;
- // Freezing can't be the default initialized behavior given how the queue
- // swaps in default initialized Checks.
- bool should_freeze {false};
+ bool should_freeze{true};
bool operator()() const
{
return true;
@@ -140,10 +124,17 @@ struct FrozenCleanupCheck {
cv.wait(l, []{ return nFrozen.load(std::memory_order_relaxed) == 0;});
}
}
- void swap(FrozenCleanupCheck& x) noexcept
+ FrozenCleanupCheck(FrozenCleanupCheck&& other) noexcept
{
- std::swap(should_freeze, x.should_freeze);
- };
+ should_freeze = other.should_freeze;
+ other.should_freeze = false;
+ }
+ FrozenCleanupCheck& operator=(FrozenCleanupCheck&& other) noexcept
+ {
+ should_freeze = other.should_freeze;
+ other.should_freeze = false;
+ return *this;
+ }
};
// Static Allocations
@@ -173,14 +164,16 @@ static void Correct_Queue_range(std::vector<size_t> range)
small_queue->StartWorkerThreads(SCRIPT_CHECK_THREADS);
// Make vChecks here to save on malloc (this test can be slow...)
std::vector<FakeCheckCheckCompletion> vChecks;
+ vChecks.reserve(9);
for (const size_t i : range) {
size_t total = i;
FakeCheckCheckCompletion::n_calls = 0;
CCheckQueueControl<FakeCheckCheckCompletion> control(small_queue.get());
while (total) {
- vChecks.resize(std::min(total, (size_t) InsecureRandRange(10)));
+ vChecks.clear();
+ vChecks.resize(std::min<size_t>(total, InsecureRandRange(10)));
total -= vChecks.size();
- control.Add(vChecks);
+ control.Add(std::move(vChecks));
}
BOOST_REQUIRE(control.Wait());
if (FakeCheckCheckCompletion::n_calls != i) {
@@ -242,7 +235,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure)
vChecks.reserve(r);
for (size_t k = 0; k < r && remaining; k++, remaining--)
vChecks.emplace_back(remaining == 1);
- control.Add(vChecks);
+ control.Add(std::move(vChecks));
}
bool success = control.Wait();
if (i > 0) {
@@ -267,7 +260,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure)
std::vector<FailingCheck> vChecks;
vChecks.resize(100, false);
vChecks[99] = end_fails;
- control.Add(vChecks);
+ control.Add(std::move(vChecks));
}
bool r =control.Wait();
BOOST_REQUIRE(r != end_fails);
@@ -293,7 +286,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck)
std::vector<UniqueCheck> vChecks;
for (size_t k = 0; k < r && total; k++)
vChecks.emplace_back(--total);
- control.Add(vChecks);
+ control.Add(std::move(vChecks));
}
}
{
@@ -331,7 +324,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory)
// to catch any sort of deallocation failure
vChecks.emplace_back(total == 0 || total == i || total == i/2);
}
- control.Add(vChecks);
+ control.Add(std::move(vChecks));
}
}
BOOST_REQUIRE_EQUAL(MemoryCheck::fake_allocated_memory, 0U);
@@ -349,11 +342,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup)
std::thread t0([&]() {
CCheckQueueControl<FrozenCleanupCheck> control(queue.get());
std::vector<FrozenCleanupCheck> vChecks(1);
- // Freezing can't be the default initialized behavior given how the queue
- // swaps in default initialized Checks (otherwise freezing destructor
- // would get called twice).
- vChecks[0].should_freeze = true;
- control.Add(vChecks);
+ control.Add(std::move(vChecks));
bool waitResult = control.Wait(); // Hangs here
assert(waitResult);
});
diff --git a/src/test/fuzz/checkqueue.cpp b/src/test/fuzz/checkqueue.cpp
index 6256aefaa3..429570526f 100644
--- a/src/test/fuzz/checkqueue.cpp
+++ b/src/test/fuzz/checkqueue.cpp
@@ -13,9 +13,7 @@
namespace {
struct DumbCheck {
- const bool result = false;
-
- DumbCheck() = default;
+ bool result = false;
explicit DumbCheck(const bool _result) : result(_result)
{
@@ -25,10 +23,6 @@ struct DumbCheck {
{
return result;
}
-
- void swap(DumbCheck& x) noexcept
- {
- }
};
} // namespace
@@ -48,7 +42,7 @@ FUZZ_TARGET(checkqueue)
checks_2.emplace_back(result);
}
if (fuzzed_data_provider.ConsumeBool()) {
- check_queue_1.Add(checks_1);
+ check_queue_1.Add(std::move(checks_1));
}
if (fuzzed_data_provider.ConsumeBool()) {
(void)check_queue_1.Wait();
@@ -56,7 +50,7 @@ FUZZ_TARGET(checkqueue)
CCheckQueueControl<DumbCheck> check_queue_control{&check_queue_2};
if (fuzzed_data_provider.ConsumeBool()) {
- check_queue_control.Add(checks_2);
+ check_queue_control.Add(std::move(checks_2));
}
if (fuzzed_data_provider.ConsumeBool()) {
(void)check_queue_control.Wait();
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 11efb6a5c3..7511dff9e8 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -547,10 +547,8 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction)
for(uint32_t i = 0; i < mtx.vin.size(); i++) {
std::vector<CScriptCheck> vChecks;
- CScriptCheck check(coins[tx.vin[i].prevout.n].out, tx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false, &txdata);
- vChecks.push_back(CScriptCheck());
- check.swap(vChecks.back());
- control.Add(vChecks);
+ vChecks.emplace_back(coins[tx.vin[i].prevout.n].out, tx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false, &txdata);
+ control.Add(std::move(vChecks));
}
bool controlCheck = control.Wait();
diff --git a/src/validation.cpp b/src/validation.cpp
index 2af7e2cc8d..e82fead89e 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -1815,8 +1815,7 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
// Verify signature
CScriptCheck check(txdata.m_spent_outputs[i], tx, i, flags, cacheSigStore, &txdata);
if (pvChecks) {
- pvChecks->push_back(CScriptCheck());
- check.swap(pvChecks->back());
+ pvChecks->emplace_back(std::move(check));
} else if (!check()) {
if (flags & STANDARD_NOT_MANDATORY_VERIFY_FLAGS) {
// Check whether the failure was caused by a
@@ -2325,7 +2324,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
return error("ConnectBlock(): CheckInputScripts on %s failed with %s",
tx.GetHash().ToString(), state.ToString());
}
- control.Add(vChecks);
+ control.Add(std::move(vChecks));
}
CTxUndo undoDummy;
diff --git a/src/validation.h b/src/validation.h
index 53e9a7ee50..aba863db09 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -314,26 +314,19 @@ private:
unsigned int nIn;
unsigned int nFlags;
bool cacheStore;
- ScriptError error;
+ ScriptError error{SCRIPT_ERR_UNKNOWN_ERROR};
PrecomputedTransactionData *txdata;
public:
- CScriptCheck(): ptxTo(nullptr), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {}
CScriptCheck(const CTxOut& outIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) :
- m_tx_out(outIn), ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { }
+ m_tx_out(outIn), ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), txdata(txdataIn) { }
- bool operator()();
+ CScriptCheck(const CScriptCheck&) = delete;
+ CScriptCheck& operator=(const CScriptCheck&) = delete;
+ CScriptCheck(CScriptCheck&&) = default;
+ CScriptCheck& operator=(CScriptCheck&&) = default;
- void swap(CScriptCheck& check) noexcept
- {
- std::swap(ptxTo, check.ptxTo);
- std::swap(m_tx_out, check.m_tx_out);
- std::swap(nIn, check.nIn);
- std::swap(nFlags, check.nFlags);
- std::swap(cacheStore, check.cacheStore);
- std::swap(error, check.error);
- std::swap(txdata, check.txdata);
- }
+ bool operator()();
ScriptError GetScriptError() const { return error; }
};