Skip to content

Commit ad1899d

Browse files
authored
Merge pull request #733 from evoskuil/master
Set dirty on candidate pop.
2 parents d1c9426 + 5b0bbcd commit ad1899d

5 files changed

Lines changed: 38 additions & 9 deletions

File tree

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,10 @@ code CLASS::set_code(const tx_link& tx_fk, const transaction& tx,
164164
if (!store_.point.expand(ins_fk + inputs))
165165
return error::tx_point_allocate;
166166

167-
// If dirty we must guard against duplicates.
168-
// Dirty doesn't hold up in the case of an invalidated block, as that
169-
// may result in a duplicated tx. So dirty should be false in the case
170-
// of a non-bypass (valid) block.
167+
// If dirty we must guard against duplicates. Dirty is caused by disk,
168+
// full, disorganized or reorganized block, and tx pooling. It is set
169+
// to true at runtime by any of these and in case of duplicate table
170+
// non-empty at store startup. disorg/reorg indicated by candidate pop.
171171
// Must be set after tx.set and before tx.commit, since searchable and
172172
// produces association to tx.link, and is also an integral part of tx.
173173
if (store_.is_dirty() || !bypass)

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,9 @@ bool CLASS::pop_candidate() NOEXCEPT
343343
// ========================================================================
344344
const auto scope = store_.get_transactor();
345345

346+
// Candidate pop implies reorg or disorg, which implies future duplicates.
347+
store_.set_dirty();
348+
346349
///////////////////////////////////////////////////////////////////////////
347350
std::unique_lock interlock{ candidate_reorganization_mutex_ };
348351
return store_.candidate.truncate(top);

include/bitcoin/database/impl/store.ipp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#ifndef LIBBITCOIN_DATABASE_STORE_IPP
2020
#define LIBBITCOIN_DATABASE_STORE_IPP
2121

22+
#include <atomic>
2223
#include <chrono>
2324
#include <unordered_map>
2425
#include <bitcoin/database/boost.hpp>
@@ -561,7 +562,7 @@ code CLASS::reload(const event_handler& handler) NOEXCEPT
561562
{
562563
handler(event_t::load_file, table);
563564
ec = storage.reload();
564-
this->dirty_ = true;
565+
this->dirty_.store(true, std::memory_order_relaxed);
565566
}
566567
}
567568
};
@@ -774,7 +775,8 @@ code CLASS::open_load(const event_handler& handler) NOEXCEPT
774775
load(ec, filter_tx_body_, table_t::filter_tx_body);
775776

776777
// create, open, and restore each invoke open_load.
777-
dirty_ = header_body_.size() > schema::header::minrow;
778+
const auto dirty = header_body_.size() > schema::header::minrow;
779+
dirty_.store(dirty, std::memory_order_relaxed);
778780
return ec;
779781
}
780782

@@ -1164,7 +1166,13 @@ const typename CLASS::transactor CLASS::get_transactor() NOEXCEPT
11641166
TEMPLATE
11651167
bool CLASS::is_dirty() const NOEXCEPT
11661168
{
1167-
return dirty_;
1169+
return dirty_.load(std::memory_order_relaxed);
1170+
}
1171+
1172+
TEMPLATE
1173+
void CLASS::set_dirty() NOEXCEPT
1174+
{
1175+
return dirty_.store(true, std::memory_order_relaxed);
11681176
}
11691177

11701178
TEMPLATE

include/bitcoin/database/store.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#ifndef LIBBITCOIN_DATABASE_STORE_HPP
2020
#define LIBBITCOIN_DATABASE_STORE_HPP
2121

22+
#include <atomic>
2223
#include <filesystem>
2324
#include <shared_mutex>
2425
#include <unordered_map>
@@ -95,6 +96,7 @@ class store
9596

9697
/// Determine if the store is non-empty/initialized.
9798
bool is_dirty() const NOEXCEPT;
99+
void set_dirty() NOEXCEPT;
98100

99101
/// Get first fault code or error::success.
100102
code get_fault() const NOEXCEPT;
@@ -235,7 +237,9 @@ class store
235237
flush_lock flush_lock_;
236238
interprocess_lock process_lock_;
237239
std::shared_timed_mutex transactor_mutex_{};
238-
bool dirty_{ true };
240+
241+
// This is thread safe.
242+
std::atomic_bool dirty_{ true };
239243

240244
private:
241245
using path = std::filesystem::path;

test/store.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ BOOST_AUTO_TEST_CASE(store__is_dirty__uninitialized__true)
5252
BOOST_REQUIRE(instance.is_dirty());
5353
}
5454

55-
BOOST_AUTO_TEST_CASE(store__is_dirty__initialized__true)
55+
BOOST_AUTO_TEST_CASE(store__is_dirty__initialized___false)
5656
{
5757
settings configuration{};
5858
configuration.path = TEST_DIRECTORY;
@@ -64,6 +64,20 @@ BOOST_AUTO_TEST_CASE(store__is_dirty__initialized__true)
6464
BOOST_REQUIRE(!instance.close(events));
6565
}
6666

67+
BOOST_AUTO_TEST_CASE(store__set_dirty__initialized__is_dirty)
68+
{
69+
settings configuration{};
70+
configuration.path = TEST_DIRECTORY;
71+
store<map> instance{ configuration };
72+
query<store<map>> query_{ instance };
73+
BOOST_REQUIRE(!instance.create(events));
74+
BOOST_REQUIRE(query_.initialize(test::genesis));
75+
BOOST_REQUIRE(!instance.is_dirty());
76+
instance.set_dirty();
77+
BOOST_REQUIRE(instance.is_dirty());
78+
BOOST_REQUIRE(!instance.close(events));
79+
}
80+
6781
BOOST_AUTO_TEST_CASE(store__is_dirty__open__false)
6882
{
6983
settings configuration{};

0 commit comments

Comments
 (0)