Skip to content

Commit a709114

Browse files
committed
Merge bitcoin/bitcoin#26749: refactor: Use move semantics instead of custom swap functions
95ad70a test: Default initialize `should_freeze` to `true` (Hennadii Stepanov) cea5052 refactor: Drop no longer used `swap` member functions (Hennadii Stepanov) a87fb6b clang-tidy: Fix modernize-use-default-member-init in `CScriptCheck` (Hennadii Stepanov) b4bed5c refactor: Drop no longer used `CScriptCheck()` default constructor (Hennadii Stepanov) d8427cc refactor: Use move semantics in `CCheckQueue::Loop` (Hennadii Stepanov) 9a0b524 clang-tidy, test: Fix bugprone-use-after-move in `Correct_Queue_range()` (Hennadii Stepanov) 04831fe refactor: Make move semantics explicit for callers (Hennadii Stepanov) 6c2d597 refactor: Use move semantics in `CCheckQueue::Add` (Hennadii Stepanov) 0682003 test, refactor: Avoid `CScriptCheck::swap` in `transaction_tests` (Hennadii Stepanov) 15209d9 consensus, refactor: Avoid `CScriptCheck::swap` in `CheckInputScripts` (Hennadii Stepanov) Pull request description: This PR makes code more succinct and readable by using move semantics. ACKs for top commit: martinus: re-ACK 95ad70a achow101: ACK 95ad70a TheCharlatan: re-ACK bitcoin/bitcoin@95ad70a MarcoFalke: re-ACK 95ad70a 🚥 Tree-SHA512: adda760891b12d252dc9b823fe7c41eed660364b6fb1a69f17607d7a31eb0bbb82a80d154a7acfaa241b5de37d42a293c2b6e059f26a8e92d88d3a87c99768fb
2 parents 6e69fea + 95ad70a commit a709114

File tree

7 files changed

+45
-82
lines changed

7 files changed

+45
-82
lines changed

src/bench/checkqueue.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,13 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench)
2929

3030
struct PrevectorJob {
3131
prevector<PREVECTOR_SIZE, uint8_t> p;
32-
PrevectorJob() = default;
3332
explicit PrevectorJob(FastRandomContext& insecure_rand){
3433
p.resize(insecure_rand.randrange(PREVECTOR_SIZE*2));
3534
}
3635
bool operator()()
3736
{
3837
return true;
3938
}
40-
void swap(PrevectorJob& x) noexcept
41-
{
42-
p.swap(x.p);
43-
};
4439
};
4540
CCheckQueue<PrevectorJob> queue {QUEUE_BATCH_SIZE};
4641
// The main thread should be counted to prevent thread oversubscription, and
@@ -60,7 +55,7 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench)
6055
// Make insecure_rand here so that each iteration is identical.
6156
CCheckQueueControl<PrevectorJob> control(&queue);
6257
for (auto vChecks : vBatches) {
63-
control.Add(vChecks);
58+
control.Add(std::move(vChecks));
6459
}
6560
// control waits for completion by RAII, but
6661
// it is done explicitly here for clarity

src/checkqueue.h

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <util/threadnames.h>
1212

1313
#include <algorithm>
14+
#include <iterator>
1415
#include <vector>
1516

1617
template <typename T>
@@ -111,13 +112,9 @@ class CCheckQueue
111112
// * Try to account for idle jobs which will instantly start helping.
112113
// * Don't do batches smaller than 1 (duh), or larger than nBatchSize.
113114
nNow = std::max(1U, std::min(nBatchSize, (unsigned int)queue.size() / (nTotal + nIdle + 1)));
114-
vChecks.resize(nNow);
115-
for (unsigned int i = 0; i < nNow; i++) {
116-
// We want the lock on the m_mutex to be as short as possible, so swap jobs from the global
117-
// queue to the local batch vector instead of copying.
118-
vChecks[i].swap(queue.back());
119-
queue.pop_back();
120-
}
115+
auto start_it = queue.end() - nNow;
116+
vChecks.assign(std::make_move_iterator(start_it), std::make_move_iterator(queue.end()));
117+
queue.erase(start_it, queue.end());
121118
// Check whether we need to do work at all
122119
fOk = fAllOk;
123120
}
@@ -165,18 +162,15 @@ class CCheckQueue
165162
}
166163

167164
//! Add a batch of checks to the queue
168-
void Add(std::vector<T>& vChecks) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
165+
void Add(std::vector<T>&& vChecks) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
169166
{
170167
if (vChecks.empty()) {
171168
return;
172169
}
173170

174171
{
175172
LOCK(m_mutex);
176-
for (T& check : vChecks) {
177-
queue.emplace_back();
178-
check.swap(queue.back());
179-
}
173+
queue.insert(queue.end(), std::make_move_iterator(vChecks.begin()), std::make_move_iterator(vChecks.end()));
180174
nTodo += vChecks.size();
181175
}
182176

@@ -239,10 +233,11 @@ class CCheckQueueControl
239233
return fRet;
240234
}
241235

242-
void Add(std::vector<T>& vChecks)
236+
void Add(std::vector<T>&& vChecks)
243237
{
244-
if (pqueue != nullptr)
245-
pqueue->Add(vChecks);
238+
if (pqueue != nullptr) {
239+
pqueue->Add(std::move(vChecks));
240+
}
246241
}
247242

248243
~CCheckQueueControl()

src/test/checkqueue_tests.cpp

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ struct FakeCheck {
4343
{
4444
return true;
4545
}
46-
void swap(FakeCheck& x) noexcept {};
4746
};
4847

4948
struct FakeCheckCheckCompletion {
@@ -53,7 +52,6 @@ struct FakeCheckCheckCompletion {
5352
n_calls.fetch_add(1, std::memory_order_relaxed);
5453
return true;
5554
}
56-
void swap(FakeCheckCheckCompletion& x) noexcept {};
5755
};
5856

5957
struct FailingCheck {
@@ -64,10 +62,6 @@ struct FailingCheck {
6462
{
6563
return !fails;
6664
}
67-
void swap(FailingCheck& x) noexcept
68-
{
69-
std::swap(fails, x.fails);
70-
};
7165
};
7266

7367
struct UniqueCheck {
@@ -82,10 +76,6 @@ struct UniqueCheck {
8276
results.insert(check_id);
8377
return true;
8478
}
85-
void swap(UniqueCheck& x) noexcept
86-
{
87-
std::swap(x.check_id, check_id);
88-
};
8979
};
9080

9181

@@ -113,19 +103,13 @@ struct MemoryCheck {
113103
{
114104
fake_allocated_memory.fetch_sub(b, std::memory_order_relaxed);
115105
};
116-
void swap(MemoryCheck& x) noexcept
117-
{
118-
std::swap(b, x.b);
119-
};
120106
};
121107

122108
struct FrozenCleanupCheck {
123109
static std::atomic<uint64_t> nFrozen;
124110
static std::condition_variable cv;
125111
static std::mutex m;
126-
// Freezing can't be the default initialized behavior given how the queue
127-
// swaps in default initialized Checks.
128-
bool should_freeze {false};
112+
bool should_freeze{true};
129113
bool operator()() const
130114
{
131115
return true;
@@ -140,10 +124,17 @@ struct FrozenCleanupCheck {
140124
cv.wait(l, []{ return nFrozen.load(std::memory_order_relaxed) == 0;});
141125
}
142126
}
143-
void swap(FrozenCleanupCheck& x) noexcept
127+
FrozenCleanupCheck(FrozenCleanupCheck&& other) noexcept
144128
{
145-
std::swap(should_freeze, x.should_freeze);
146-
};
129+
should_freeze = other.should_freeze;
130+
other.should_freeze = false;
131+
}
132+
FrozenCleanupCheck& operator=(FrozenCleanupCheck&& other) noexcept
133+
{
134+
should_freeze = other.should_freeze;
135+
other.should_freeze = false;
136+
return *this;
137+
}
147138
};
148139

149140
// Static Allocations
@@ -173,14 +164,16 @@ static void Correct_Queue_range(std::vector<size_t> range)
173164
small_queue->StartWorkerThreads(SCRIPT_CHECK_THREADS);
174165
// Make vChecks here to save on malloc (this test can be slow...)
175166
std::vector<FakeCheckCheckCompletion> vChecks;
167+
vChecks.reserve(9);
176168
for (const size_t i : range) {
177169
size_t total = i;
178170
FakeCheckCheckCompletion::n_calls = 0;
179171
CCheckQueueControl<FakeCheckCheckCompletion> control(small_queue.get());
180172
while (total) {
181-
vChecks.resize(std::min(total, (size_t) InsecureRandRange(10)));
173+
vChecks.clear();
174+
vChecks.resize(std::min<size_t>(total, InsecureRandRange(10)));
182175
total -= vChecks.size();
183-
control.Add(vChecks);
176+
control.Add(std::move(vChecks));
184177
}
185178
BOOST_REQUIRE(control.Wait());
186179
if (FakeCheckCheckCompletion::n_calls != i) {
@@ -242,7 +235,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure)
242235
vChecks.reserve(r);
243236
for (size_t k = 0; k < r && remaining; k++, remaining--)
244237
vChecks.emplace_back(remaining == 1);
245-
control.Add(vChecks);
238+
control.Add(std::move(vChecks));
246239
}
247240
bool success = control.Wait();
248241
if (i > 0) {
@@ -267,7 +260,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure)
267260
std::vector<FailingCheck> vChecks;
268261
vChecks.resize(100, false);
269262
vChecks[99] = end_fails;
270-
control.Add(vChecks);
263+
control.Add(std::move(vChecks));
271264
}
272265
bool r =control.Wait();
273266
BOOST_REQUIRE(r != end_fails);
@@ -293,7 +286,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck)
293286
std::vector<UniqueCheck> vChecks;
294287
for (size_t k = 0; k < r && total; k++)
295288
vChecks.emplace_back(--total);
296-
control.Add(vChecks);
289+
control.Add(std::move(vChecks));
297290
}
298291
}
299292
{
@@ -331,7 +324,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory)
331324
// to catch any sort of deallocation failure
332325
vChecks.emplace_back(total == 0 || total == i || total == i/2);
333326
}
334-
control.Add(vChecks);
327+
control.Add(std::move(vChecks));
335328
}
336329
}
337330
BOOST_REQUIRE_EQUAL(MemoryCheck::fake_allocated_memory, 0U);
@@ -349,11 +342,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup)
349342
std::thread t0([&]() {
350343
CCheckQueueControl<FrozenCleanupCheck> control(queue.get());
351344
std::vector<FrozenCleanupCheck> vChecks(1);
352-
// Freezing can't be the default initialized behavior given how the queue
353-
// swaps in default initialized Checks (otherwise freezing destructor
354-
// would get called twice).
355-
vChecks[0].should_freeze = true;
356-
control.Add(vChecks);
345+
control.Add(std::move(vChecks));
357346
bool waitResult = control.Wait(); // Hangs here
358347
assert(waitResult);
359348
});

src/test/fuzz/checkqueue.cpp

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@
1313

1414
namespace {
1515
struct DumbCheck {
16-
const bool result = false;
17-
18-
DumbCheck() = default;
16+
bool result = false;
1917

2018
explicit DumbCheck(const bool _result) : result(_result)
2119
{
@@ -25,10 +23,6 @@ struct DumbCheck {
2523
{
2624
return result;
2725
}
28-
29-
void swap(DumbCheck& x) noexcept
30-
{
31-
}
3226
};
3327
} // namespace
3428

@@ -48,15 +42,15 @@ FUZZ_TARGET(checkqueue)
4842
checks_2.emplace_back(result);
4943
}
5044
if (fuzzed_data_provider.ConsumeBool()) {
51-
check_queue_1.Add(checks_1);
45+
check_queue_1.Add(std::move(checks_1));
5246
}
5347
if (fuzzed_data_provider.ConsumeBool()) {
5448
(void)check_queue_1.Wait();
5549
}
5650

5751
CCheckQueueControl<DumbCheck> check_queue_control{&check_queue_2};
5852
if (fuzzed_data_provider.ConsumeBool()) {
59-
check_queue_control.Add(checks_2);
53+
check_queue_control.Add(std::move(checks_2));
6054
}
6155
if (fuzzed_data_provider.ConsumeBool()) {
6256
(void)check_queue_control.Wait();

src/test/transaction_tests.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -547,10 +547,8 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction)
547547

548548
for(uint32_t i = 0; i < mtx.vin.size(); i++) {
549549
std::vector<CScriptCheck> vChecks;
550-
CScriptCheck check(coins[tx.vin[i].prevout.n].out, tx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false, &txdata);
551-
vChecks.push_back(CScriptCheck());
552-
check.swap(vChecks.back());
553-
control.Add(vChecks);
550+
vChecks.emplace_back(coins[tx.vin[i].prevout.n].out, tx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false, &txdata);
551+
control.Add(std::move(vChecks));
554552
}
555553

556554
bool controlCheck = control.Wait();

src/validation.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1815,8 +1815,7 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
18151815
// Verify signature
18161816
CScriptCheck check(txdata.m_spent_outputs[i], tx, i, flags, cacheSigStore, &txdata);
18171817
if (pvChecks) {
1818-
pvChecks->push_back(CScriptCheck());
1819-
check.swap(pvChecks->back());
1818+
pvChecks->emplace_back(std::move(check));
18201819
} else if (!check()) {
18211820
if (flags & STANDARD_NOT_MANDATORY_VERIFY_FLAGS) {
18221821
// Check whether the failure was caused by a
@@ -2325,7 +2324,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
23252324
return error("ConnectBlock(): CheckInputScripts on %s failed with %s",
23262325
tx.GetHash().ToString(), state.ToString());
23272326
}
2328-
control.Add(vChecks);
2327+
control.Add(std::move(vChecks));
23292328
}
23302329

23312330
CTxUndo undoDummy;

src/validation.h

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -314,26 +314,19 @@ class CScriptCheck
314314
unsigned int nIn;
315315
unsigned int nFlags;
316316
bool cacheStore;
317-
ScriptError error;
317+
ScriptError error{SCRIPT_ERR_UNKNOWN_ERROR};
318318
PrecomputedTransactionData *txdata;
319319

320320
public:
321-
CScriptCheck(): ptxTo(nullptr), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {}
322321
CScriptCheck(const CTxOut& outIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) :
323-
m_tx_out(outIn), ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { }
322+
m_tx_out(outIn), ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), txdata(txdataIn) { }
324323

325-
bool operator()();
324+
CScriptCheck(const CScriptCheck&) = delete;
325+
CScriptCheck& operator=(const CScriptCheck&) = delete;
326+
CScriptCheck(CScriptCheck&&) = default;
327+
CScriptCheck& operator=(CScriptCheck&&) = default;
326328

327-
void swap(CScriptCheck& check) noexcept
328-
{
329-
std::swap(ptxTo, check.ptxTo);
330-
std::swap(m_tx_out, check.m_tx_out);
331-
std::swap(nIn, check.nIn);
332-
std::swap(nFlags, check.nFlags);
333-
std::swap(cacheStore, check.cacheStore);
334-
std::swap(error, check.error);
335-
std::swap(txdata, check.txdata);
336-
}
329+
bool operator()();
337330

338331
ScriptError GetScriptError() const { return error; }
339332
};

0 commit comments

Comments
 (0)