Skip to content

Commit ebae515

Browse files
committed
Fix hashhead sieve collision propagation and restore error handler.
1 parent 988990e commit ebae515

2 files changed

Lines changed: 30 additions & 35 deletions

File tree

include/bitcoin/database/impl/primitives/hashhead.ipp

Lines changed: 27 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,8 @@ TEMPLATE
149149
inline bool CLASS::push(bool& collision, const Link& current, bytes& next,
150150
const Key& key) NOEXCEPT
151151
{
152-
// TODO: need independent error sentinel.
153-
const auto previous = set_cell(next, current, key);
154-
////if (previous == terminal)
155-
//// return false;
156-
157-
// Conflict (body) search is bypassed by filter when key is not screened.
158-
// If collision false it is assured that table does not contain the key.
159-
collision = screened(previous, key);
160-
return true;
152+
// next holds previous top and can searched for dups if collision is true.
153+
return set_cell(collision, next, current, key);
161154
}
162155

163156
// protected
@@ -185,25 +178,25 @@ inline CLASS::cell CLASS::get_cell(const Link& index) const NOEXCEPT
185178
}
186179
else
187180
{
188-
cell top{};
189-
const auto& head = cell_array(raw);
181+
const auto& top = cell_array(raw);
182+
cell head{};
190183

191184
mutex_.lock_shared();
192-
cell_array(top) = head;
185+
cell_array(head) = top;
193186
mutex_.unlock_shared();
194187

195-
return top;
188+
return head;
196189
}
197190
}
198191

199192
TEMPLATE
200-
inline CLASS::cell CLASS::set_cell(bytes& next, const Link& current,
193+
inline bool CLASS::set_cell(bool& collision, bytes& next, const Link& current,
201194
const Key& key) NOEXCEPT
202195
{
203196
using namespace system;
204197
const auto raw = file_.get_raw(link_to_position(index(key)));
205198
if (is_null(raw))
206-
return terminal;
199+
return false;
207200

208201
if constexpr (aligned)
209202
{
@@ -212,35 +205,34 @@ inline CLASS::cell CLASS::set_cell(bytes& next, const Link& current,
212205
////const std::atomic_ref<cell> head(unsafe_byte_cast<cell>(raw));
213206
auto& top = *pointer_cast<std::atomic<cell>>(raw);
214207
auto head = top.load(std::memory_order_acquire);
208+
cell update{};
215209
do
216210
{
217-
next = link_array(head);
218-
219211
// Compiler could order this after top.store, which would expose key
220212
// to search before next entry is linked. Thread fence imposes order.
221213
// A release fence ensures that all prior writes (like next) are
222214
// completed before any subsequent atomic store.
215+
next = link_array(head);
216+
update = to_cell(collision, head, current, key);
223217
std::atomic_thread_fence(std::memory_order_release);
224218
}
225-
while (!top.compare_exchange_weak(head, to_cell(head, current, key),
219+
while (!top.compare_exchange_weak(head, update,
226220
std::memory_order_release, std::memory_order_acquire));
227-
228-
return top;
229221
}
230222
else
231223
{
232-
cell top{};
233-
auto& head = cell_array(raw);
224+
auto& top = cell_array(raw);
225+
cell head{};
234226

235227
mutex_.lock();
236-
cell_array(top) = head;
237-
next = link_array(top);
238-
auto bytes = to_cell(top, current, key);
239-
head = cell_array(bytes);
228+
cell_array(head) = top;
229+
next = link_array(head);
230+
auto update = to_cell(collision, head, current, key);
231+
top = cell_array(update);
240232
mutex_.unlock();
241-
242-
return top;
243233
}
234+
235+
return true;
244236
}
245237

246238
// protected
@@ -293,18 +285,21 @@ INLINE constexpr CLASS::link CLASS::to_link(cell value) NOEXCEPT
293285
}
294286

295287
TEMPLATE
296-
INLINE constexpr CLASS::cell CLASS::to_cell(cell previous, link current,
297-
const Key& key) NOEXCEPT
288+
INLINE constexpr CLASS::cell CLASS::to_cell(bool& collision, cell previous,
289+
link current, const Key& key) NOEXCEPT
298290
{
299291
if constexpr (sieve_t::disabled)
300292
{
293+
collision = true;
301294
return current;
302295
}
303296
else
304297
{
305298
using namespace system;
306-
const auto value = sieve_t::screen(to_filter(previous), fingerprint(key));
307-
return bit_or<cell>(shift_left<cell>(value, link_bits), current);
299+
const auto sieve = to_filter(previous);
300+
const auto next = sieve_t::screen(sieve, fingerprint(key));
301+
collision = (next == sieve || sieve_t::is_saturated(next));
302+
return bit_or<cell>(shift_left<cell>(next, link_bits), current);
308303
}
309304
}
310305

include/bitcoin/database/primitives/hashhead.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,11 @@ class hashhead
9898
static INLINE constexpr filter fingerprint(const Key& key) NOEXCEPT;
9999
static INLINE constexpr filter to_filter(cell value) NOEXCEPT;
100100
static INLINE constexpr link to_link(cell value) NOEXCEPT;
101-
static INLINE constexpr cell to_cell(cell previous, link current,
102-
const Key& key) NOEXCEPT;
101+
static INLINE constexpr cell to_cell(bool& collision, cell previous,
102+
link current, const Key& key) NOEXCEPT;
103103

104104
inline cell get_cell(const Link& index) const NOEXCEPT;
105-
inline cell set_cell(bytes& next, const Link& current,
105+
inline bool set_cell(bool& collision, bytes& next, const Link& current,
106106
const Key& key) NOEXCEPT;
107107

108108
private:

0 commit comments

Comments
 (0)