@@ -21,13 +21,15 @@ BucketApplicator::BucketApplicator(Application& app,
21
21
uint32_t minProtocolVersionSeen,
22
22
uint32_t level,
23
23
std::shared_ptr<Bucket const > bucket,
24
- std::function<bool (LedgerEntryType)> filter)
24
+ std::function<bool (LedgerEntryType)> filter,
25
+ std::unordered_set<LedgerKey>& seenKeys)
25
26
: mApp (app)
26
27
, mMaxProtocolVersion (maxProtocolVersion)
27
28
, mMinProtocolVersionSeen (minProtocolVersionSeen)
28
29
, mLevel (level)
29
30
, mBucketIter (bucket)
30
31
, mEntryTypeFilter (filter)
32
+ , mSeenKeys (seenKeys)
31
33
{
32
34
auto protocolVersion = mBucketIter .getMetadata ().ledgerVersion ;
33
35
if (protocolVersion > mMaxProtocolVersion )
@@ -37,11 +39,33 @@ BucketApplicator::BucketApplicator(Application& app,
37
39
" bucket protocol version {:d} exceeds maxProtocolVersion {:d}" ),
38
40
protocolVersion, mMaxProtocolVersion ));
39
41
}
42
+
43
+ // Only apply offers if BucketListDB is enabled
44
+ if (mApp .getConfig ().isUsingBucketListDB () && !bucket->isEmpty ())
45
+ {
46
+ auto offsetOp = bucket->getOfferRange ();
47
+ if (offsetOp)
48
+ {
49
+ auto [lowOffset, highOffset] = *offsetOp;
50
+ mBucketIter .seek (lowOffset);
51
+ mUpperBoundOffset = highOffset;
52
+ }
53
+ else
54
+ {
55
+ // No offers in Bucket
56
+ mOffersRemaining = false ;
57
+ }
58
+ }
40
59
}
41
60
42
61
BucketApplicator::operator bool () const
43
62
{
44
- return (bool )mBucketIter ;
63
+ // There is more work to do (i.e. (bool) *this == true) iff:
64
+ // 1. The underlying bucket iterator is not EOF and
65
+ // 2. Either BucketListDB is not enabled (so we must apply all entry types)
66
+ // or BucketListDB is enabled and we have offers still remaining.
67
+ return static_cast <bool >(mBucketIter ) &&
68
+ (!mApp .getConfig ().isUsingBucketListDB () || mOffersRemaining );
45
69
}
46
70
47
71
size_t
@@ -99,11 +123,43 @@ BucketApplicator::advance(BucketApplicator::Counters& counters)
99
123
100
124
for (; mBucketIter ; ++mBucketIter )
101
125
{
126
+ // Note: mUpperBoundOffset is not inclusive. However, mBucketIter.pos()
127
+ // returns the file offset at the end of the currently loaded entry.
128
+ // This means we must read until pos is strictly greater than the upper
129
+ // bound so that we don't skip the last offer in the range.
130
+ auto isUsingBucketListDB = mApp .getConfig ().isUsingBucketListDB ();
131
+ if (isUsingBucketListDB && mBucketIter .pos () > mUpperBoundOffset )
132
+ {
133
+ mOffersRemaining = false ;
134
+ break ;
135
+ }
136
+
102
137
BucketEntry const & e = *mBucketIter ;
103
138
Bucket::checkProtocolLegality (e, mMaxProtocolVersion );
104
139
105
140
if (shouldApplyEntry (mEntryTypeFilter , e))
106
141
{
142
+ if (isUsingBucketListDB)
143
+ {
144
+ if (e.type () == LIVEENTRY || e.type () == INITENTRY)
145
+ {
146
+ auto [_, wasInserted] =
147
+ mSeenKeys .emplace (LedgerEntryKey (e.liveEntry ()));
148
+
149
+ // Skip seen keys
150
+ if (!wasInserted)
151
+ {
152
+ continue ;
153
+ }
154
+ }
155
+ else
156
+ {
157
+ // Only apply INIT and LIVE entries
158
+ mSeenKeys .emplace (e.deadEntry ());
159
+ continue ;
160
+ }
161
+ }
162
+
107
163
counters.mark (e);
108
164
109
165
if (e.type () == LIVEENTRY || e.type () == INITENTRY)
@@ -148,6 +204,7 @@ BucketApplicator::advance(BucketApplicator::Counters& counters)
148
204
}
149
205
else
150
206
{
207
+ releaseAssertOrThrow (!isUsingBucketListDB);
151
208
if (protocolVersionIsBefore (
152
209
mMinProtocolVersionSeen ,
153
210
Bucket::
0 commit comments