/
election_scheduler.cpp
129 lines (117 loc) · 3.72 KB
/
election_scheduler.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <nano/node/election_scheduler.hpp>
#include <nano/node/node.hpp>
nano::election_scheduler::election_scheduler (nano::node & node) :
node{ node },
stopped{ false },
thread{ [this] () { run (); } }
{
}
nano::election_scheduler::~election_scheduler ()
{
stop ();
thread.join ();
}
void nano::election_scheduler::manual (std::shared_ptr<nano::block> const & block_a, boost::optional<nano::uint128_t> const & previous_balance_a, nano::election_behavior election_behavior_a, std::function<void (std::shared_ptr<nano::block> const &)> const & confirmation_action_a)
{
nano::lock_guard<nano::mutex> lock{ mutex };
manual_queue.push_back (std::make_tuple (block_a, previous_balance_a, election_behavior_a, confirmation_action_a));
notify ();
}
void nano::election_scheduler::activate (nano::account const & account_a, nano::transaction const & transaction)
{
debug_assert (!account_a.is_zero ());
nano::account_info account_info;
if (!node.store.account_get (transaction, account_a, account_info))
{
nano::confirmation_height_info conf_info;
node.store.confirmation_height_get (transaction, account_a, conf_info);
if (conf_info.height < account_info.block_count)
{
debug_assert (conf_info.frontier != account_info.head);
auto hash = conf_info.height == 0 ? account_info.open_block : node.store.block_successor (transaction, conf_info.frontier);
auto block = node.store.block_get (transaction, hash);
debug_assert (block != nullptr);
if (node.ledger.dependents_confirmed (transaction, *block))
{
nano::lock_guard<nano::mutex> lock{ mutex };
priority.push (account_info.modified, block);
notify ();
}
}
}
}
void nano::election_scheduler::stop ()
{
nano::unique_lock<nano::mutex> lock{ mutex };
stopped = true;
notify ();
}
void nano::election_scheduler::flush ()
{
nano::unique_lock<nano::mutex> lock{ mutex };
condition.wait (lock, [this] () {
return stopped || empty_locked () || node.active.vacancy () <= 0;
});
}
void nano::election_scheduler::notify ()
{
condition.notify_all ();
}
size_t nano::election_scheduler::size () const
{
nano::lock_guard<nano::mutex> lock{ mutex };
return priority.size () + manual_queue.size ();
}
bool nano::election_scheduler::empty_locked () const
{
return priority.empty () && manual_queue.empty ();
}
bool nano::election_scheduler::empty () const
{
nano::lock_guard<nano::mutex> lock{ mutex };
return empty_locked ();
}
size_t nano::election_scheduler::priority_queue_size () const
{
return priority.size ();
}
void nano::election_scheduler::run ()
{
nano::thread_role::set (nano::thread_role::name::election_scheduler);
nano::unique_lock<nano::mutex> lock{ mutex };
while (!stopped)
{
condition.wait (lock, [this] () {
auto vacancy = node.active.vacancy ();
auto has_vacancy = vacancy > 0;
auto available = !priority.empty () || !manual_queue.empty ();
return stopped || (has_vacancy && available);
});
debug_assert ((std::this_thread::yield (), true)); // Introduce some random delay in debug builds
if (!stopped)
{
if (!priority.empty ())
{
auto block = priority.top ();
std::shared_ptr<nano::election> election;
nano::unique_lock<nano::mutex> lock2 (node.active.mutex);
election = node.active.insert_impl (lock2, block).election;
if (election != nullptr)
{
election->transition_active ();
}
priority.pop ();
++priority_queued;
}
if (!manual_queue.empty ())
{
auto const [block, previous_balance, election_behavior, confirmation_action] = manual_queue.front ();
nano::unique_lock<nano::mutex> lock2 (node.active.mutex);
node.active.insert_impl (lock2, block, previous_balance, election_behavior, confirmation_action);
manual_queue.pop_front ();
++manual_queued;
}
notify ();
}
}
}