@@ -69,23 +69,103 @@ class InboundLedgersImp : public InboundLedgers
69
69
std::uint32_t seq,
70
70
InboundLedger::Reason reason) override
71
71
{
72
+ std::stringstream ss;
73
+ ss << " InboundLedger::acquire: "
74
+ << " Request: " << to_string (hash) << " , " << seq
75
+ << " NeedNetworkLedger: "
76
+ << (app_.getOPs ().isNeedNetworkLedger () ? " yes" : " no" )
77
+ << " Reason: " << to_string (reason) << " Old rule: " ;
78
+ if (app_.getOPs ().isNeedNetworkLedger () &&
79
+ (reason != InboundLedger::Reason::GENERIC) &&
80
+ (reason != InboundLedger::Reason::CONSENSUS))
81
+ ss << " false" ;
82
+ else
83
+ ss << " true" ;
84
+
72
85
assert (hash.isNonZero ());
73
86
assert (
74
87
reason != InboundLedger::Reason::SHARD ||
75
88
(seq != 0 && app_.getShardStore ()));
76
89
77
- // probably not the right rule
78
- if (app_.getOPs ().isNeedNetworkLedger () &&
79
- (reason != InboundLedger::Reason::GENERIC) &&
80
- (reason != InboundLedger::Reason::CONSENSUS))
90
+ /* Acquiring ledgers is somewhat expensive. It requires lots of
91
+ * computation and network communication. Avoid it when it's not
92
+ * appropriate. Every validation from a peer for a ledger that
93
+ * we do not have locally results in a call to this function: even
94
+ * if we are moments away from validating the same ledger.
95
+ */
96
+ // If the node is not in "full" state, it needs to sync to the network,
97
+ // and doesn't have the necessary tx's and ledger entries to build the
98
+ // ledger.
99
+ bool const isFull = app_.getOPs ().isFull ();
100
+ // fallingBehind means the last closed ledger is at least 2 behind the
101
+ // validated ledger. If the node is falling behind the network, it
102
+ // probably needs information from the network to catch up.
103
+ //
104
+ // The reason this should not simply be only at least 1 behind the
105
+ // validated ledger is that a slight lag is normal case because some
106
+ // nodes get there slightly later than others. A difference of 2 means
107
+ // that at least a full ledger interval has passed, so the node is
108
+ // beginning to fall behind.
109
+ bool const fallingBehind = app_.getOPs ().isFallingBehind ();
110
+ // If everything else is ok, don't try to acquire the ledger if the
111
+ // requested seq is in the near future relative to the validated ledger.
112
+ // If the requested ledger is between 1 and 19 inclusive ledgers ahead
113
+ // of the valid ledger this node has not built it yet, but it's
114
+ // possible/likely it has the tx's necessary to build it and get caught
115
+ // up. Plus it might not become validated. On the other hand, if it's
116
+ // more than 20 in the future, this node should request it so that it
117
+ // can jump ahead and get caught up.
118
+ LedgerIndex const validSeq =
119
+ app_.getLedgerMaster ().getValidLedgerIndex ();
120
+ constexpr std::size_t lagLeeway = 20 ;
121
+ bool const nearFuture =
122
+ (seq > validSeq) && (seq < validSeq + lagLeeway);
123
+ // If everything else is ok, don't try to acquire the ledger if the
124
+ // request is related to consensus. (Note that consensus calls usually
125
+ // pass a seq of 0, so nearFuture will be false other than on a brand
126
+ // new network.)
127
+ bool const consensus = reason == InboundLedger::Reason::CONSENSUS;
128
+
129
+ bool const shouldAcquire = [&]() {
130
+ // If the node is not synced, try to get the ledger.
131
+ if (!isFull)
132
+ return true ;
133
+ // If the node is falling behind, try to get the ledger.
134
+ if (fallingBehind)
135
+ return true ;
136
+ // If the ledger is in the near future, do NOT get the ledger. This
137
+ // node is probably about to build it.
138
+ if (nearFuture)
139
+ return false ;
140
+ // If the request is because of consensus, do NOT get the ledger.
141
+ // This node is probably about to build it.
142
+ if (consensus)
143
+ return false ;
144
+ return true ;
145
+ }();
146
+ ss << " Evaluating whether to acquire ledger " << hash
147
+ << " . full: " << (isFull ? " true" : " false" )
148
+ << " . falling behind: " << (fallingBehind ? " true" : " false" )
149
+ << " . ledger sequence " << seq << " . Valid sequence: " << validSeq
150
+ << " . Lag leeway: " << lagLeeway
151
+ << " . request for near future ledger: "
152
+ << (nearFuture ? " true" : " false" )
153
+ << " . Consensus: " << (consensus ? " true" : " false" )
154
+ << " . Acquiring ledger? " << (shouldAcquire ? " true" : " false" );
155
+
156
+ if (!shouldAcquire)
157
+ {
158
+ JLOG (j_.debug ()) << " Abort(rule): " << ss.str ();
81
159
return {};
160
+ }
82
161
83
162
bool isNew = true ;
84
163
std::shared_ptr<InboundLedger> inbound;
85
164
{
86
165
ScopedLockType sl (mLock );
87
166
if (stopping_)
88
167
{
168
+ JLOG (j_.debug ()) << " Abort(stopping): " << ss.str ();
89
169
return {};
90
170
}
91
171
@@ -111,13 +191,19 @@ class InboundLedgersImp : public InboundLedgers
111
191
}
112
192
113
193
if (inbound->isFailed ())
194
+ {
195
+ JLOG (j_.debug ()) << " Abort(failed): " << ss.str ();
114
196
return {};
197
+ }
115
198
116
199
if (!isNew)
117
200
inbound->update (seq);
118
201
119
202
if (!inbound->isComplete ())
203
+ {
204
+ JLOG (j_.debug ()) << " Abort(incomplete): " << ss.str ();
120
205
return {};
206
+ }
121
207
122
208
if (reason == InboundLedger::Reason::HISTORY)
123
209
{
@@ -130,14 +216,17 @@ class InboundLedgersImp : public InboundLedgers
130
216
if (!shardStore)
131
217
{
132
218
JLOG (j_.error ())
133
- << " Acquiring shard with no shard store available" ;
219
+ << " Acquiring shard with no shard store available"
220
+ << ss.str ();
134
221
return {};
135
222
}
136
223
if (inbound->getLedger ()->stateMap ().family ().isShardBacked ())
137
224
shardStore->setStored (inbound->getLedger ());
138
225
else
139
226
shardStore->storeLedger (inbound->getLedger ());
140
227
}
228
+
229
+ JLOG (j_.debug ()) << " Requesting: " << ss.str ();
141
230
return inbound->getLedger ();
142
231
}
143
232
0 commit comments