Skip to content

Commit 2acda39

Browse files
authored
Merge pull request #579 from evoskuil/master
Restore hash_head memory fence with corrected CAS writer.
2 parents c08c6c5 + 4e7e737 commit 2acda39

6 files changed

Lines changed: 54 additions & 6 deletions

File tree

include/bitcoin/database/error.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ enum error_t : uint8_t
4848
integrity9,
4949
integrity10,
5050
integrity11,
51+
integrity12,
52+
integrity13,
53+
integrity14,
54+
integrity15,
55+
integrity16,
56+
integrity17,
5157

5258
/// memory map
5359
open_open,

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ Link CLASS::at(size_t key) const NOEXCEPT
137137
// xcode clang++16 does not support C++20 std::atomic_ref.
138138
////const std::atomic_ref<integer> head(unsafe_byte_cast<integer>(raw));
139139
const auto& head = *pointer_cast<std::atomic<integer>>(raw);
140-
return head.load(std::memory_order_acquire);
140+
return head.load(std::memory_order_relaxed);
141141
}
142142
else
143143
{
@@ -167,7 +167,7 @@ bool CLASS::push(const Link& link, const Link& index) NOEXCEPT
167167
// xcode clang++16 does not support C++20 std::atomic_ref.
168168
////const std::atomic_ref<integer> head(unsafe_byte_cast<integer>(raw));
169169
auto& head = *pointer_cast<std::atomic<integer>>(raw);
170-
head.store(link, std::memory_order_acq_rel);
170+
head.store(link, std::memory_order_relaxed);
171171
}
172172
else
173173
{

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ inline Link CLASS::top(const Link& index) const NOEXCEPT
135135
// xcode clang++16 does not support C++20 std::atomic_ref.
136136
////const std::atomic_ref<integer> head(unsafe_byte_cast<integer>(raw));
137137
const auto& head = *pointer_cast<std::atomic<integer>>(raw);
138+
139+
// Acquire is necessary to synchronize with push release.
140+
// Relaxed would miss next updates, so acquire is optimal.
138141
return head.load(std::memory_order_acquire);
139142
}
140143
else
@@ -169,7 +172,19 @@ inline bool CLASS::push(const Link& current, bytes& next,
169172
// xcode clang++16 does not support C++20 std::atomic_ref.
170173
////const std::atomic_ref<integer> head(unsafe_byte_cast<integer>(raw));
171174
auto& head = *pointer_cast<std::atomic<integer>>(raw);
172-
next = Link(head.exchange(current, std::memory_order_acq_rel));
175+
176+
integer top = head.load(std::memory_order_acquire);
177+
do
178+
{
179+
// Compiler could order this after head.store, which would expose key
180+
// to search before next entry is linked. Thread fence imposes order.
181+
// A release fence ensures that all prior writes (like next) are
182+
// completed before any subsequent atomic store.
183+
next = Link{ top };
184+
std::atomic_thread_fence(std::memory_order_release);
185+
}
186+
while (!head.compare_exchange_weak(top, current,
187+
std::memory_order_release, std::memory_order_acquire));
173188
}
174189
else
175190
{

include/bitcoin/database/impl/query/consensus.ipp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,29 @@ code CLASS::push_spenders(tx_links& out, const point& point,
204204
{
205205
auto it = store_.point.it(table::point::compose(point));
206206
if (!it)
207+
{
208+
const auto key1 = it.key();
209+
const auto link1 = it.self();
210+
const auto get1 = it.get();
211+
it.reset();
212+
213+
if (key1 != table::point::compose(point))
214+
return error::integrity12;
215+
if (!link1.is_terminal())
216+
return error::integrity13;
217+
if (is_null(get1))
218+
return error::integrity14;
219+
220+
table::point::record get{};
221+
if (!store_.point.get(self, get))
222+
return error::integrity15;
223+
if (get.hash != point.hash())
224+
return error::integrity16;
225+
if (get.index != point.index())
226+
return error::integrity17;
227+
207228
return error::integrity4;
229+
}
208230

209231
point_links points{};
210232
do

include/bitcoin/database/primitives/iterator.hpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,16 @@ class iterator
5050
iterator(memory_ptr&& data, const Link& start, Key&& key) NOEXCEPT;
5151
iterator(memory_ptr&& data, const Link& start, const Key& key) NOEXCEPT;
5252

53-
/// Advance to and return next iterator.
53+
/// Advance to next and return false if none found.
5454
inline bool advance() NOEXCEPT;
5555

5656
/// Expose the search key.
5757
inline const Key& key() const NOEXCEPT;
5858

59-
/// Advance to next match and return false if terminal (not found).
59+
/// Return current link, terminal if not found.
6060
inline const Link& self() const NOEXCEPT;
6161

6262
/// Access the underlying memory pointer.
63-
// TODO: for use by hashmap, make exclusive via friend.
6463
inline const memory_ptr& get() const NOEXCEPT;
6564

6665
/// Release the memory pointer, invalidates iterator.

src/error.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ DEFINE_ERROR_T_MESSAGE_MAP(error)
4141
{ integrity9, "store corrupted9" },
4242
{ integrity10, "store corrupted10" },
4343
{ integrity11, "store corrupted11" },
44+
{ integrity12, "store corrupted12" },
45+
{ integrity13, "store corrupted13" },
46+
{ integrity14, "store corrupted14" },
47+
{ integrity15, "store corrupted15" },
48+
{ integrity16, "store corrupted16" },
49+
{ integrity17, "store corrupted17" },
4450

4551
// memory map
4652
{ open_open, "opening open file" },

0 commit comments

Comments
 (0)