2828#include < ranges>
2929#include < span>
3030#include < stdexcept>
31- #include < vector>
3231
3332#include " assert-printf.h"
3433#include " i-dirty-page-tree.h"
34+ #include " os-mapped-memory.h"
3535#include " ranges.h"
3636
3737namespace cartesi {
3838
3939// / \brief Dirty page tree
4040class dirty_page_tree final : public i_dirty_page_tree {
41- public:
4241 // / \brief Each node in tree is either clean or dirty
43- enum class status_type : uint8_t { clean, dirty };
42+ enum class status_type : uint8_t { clean = 0 , dirty = 1 };
4443
45- private:
46- using container_type = std::vector<status_type>;
44+ using container_type = std::span<status_type>;
4745
4846 // / \brief Checks if we can represent a tree with this many levels
4947 static int check_level_count (int level_count, size_type leaf_count) {
@@ -57,7 +55,7 @@ class dirty_page_tree final : public i_dirty_page_tree {
5755 throw std::invalid_argument{" too many leaves for level count" };
5856 }
5957 // Make sure we can allocate a vector of size 1 << level_count
60- if ((container_type{}. max_size () >> level_count) == 0 ) {
58+ if ((std::numeric_limits< container_type::size_type>:: max () >> level_count) == 0 ) {
6159 throw std::invalid_argument{" too many levels" };
6260 }
6361 // Make sure we can address position 1 << level_count
@@ -78,35 +76,43 @@ class dirty_page_tree final : public i_dirty_page_tree {
7876 }
7977 }
8078
79+ // / \brief Tells if the tree has been initialized
80+ // / \returns True if initialized, false otherwise
81+ bool is_initialized () const {
82+ // Use tree position 0 as initialization flag, if it's not clean, then the tree is initialized
83+ return m_tree[*position_iterator{0 }] != status_type::clean;
84+ }
85+
86+ // / \brief Marks the tree as initialized
87+ void set_initialized () const {
88+ // Use tree position 0 as initialization flag, marking it as dirty makes the tree initialized
89+ m_tree[*position_iterator{0 }] = status_type::dirty;
90+ }
91+
8192public:
8293 // / \brief Constructor for leaves marked the same way
8394 // / \param leaf_count Number of leaves in tree. This is rounded up to the next power of 2.
8495 // / \param init Status of the first \p leaf_count leaves (the ones past leaf_count start clean)
85- explicit dirty_page_tree (int level_count, size_type leaf_count, status_type init = status_type::dirty) :
96+ explicit dirty_page_tree (int level_count, size_type leaf_count, const std::string &backing_filename, bool shared,
97+ status_type init = status_type::dirty) :
8698 i_dirty_page_tree{check_level_count (level_count, leaf_count)},
8799 m_leaf_positions{level_positions_view (0 )},
88100 m_valid_positions{position_iterator (1 ), position_iterator (position_iterator::value_type{1 } << level_count)},
89- m_tree{typename container_type::size_type{1 } << level_count, status_type::clean} {
90- const auto lp = m_leaf_positions;
91- const auto first_leaf = *lp.begin ();
92- const auto first_pad = first_leaf + leaf_count;
93- const auto pad_count = *lp.end () - first_pad;
94- std::ranges::fill (std::span (m_tree).subspan (first_leaf, leaf_count), init);
95- std::ranges::fill (std::span (m_tree).subspan (first_pad, pad_count), status_type::dirty);
96- build_from_leaves ();
97- }
98-
99- // / \brief Constructor from initializer list
100- // / \param leaves Status of first few leaves in tree.
101- // / \details This is a constructor mostly used in simple tests
102- explicit dirty_page_tree (int level_count, std::initializer_list<status_type> leaves) :
103- i_dirty_page_tree{check_level_count (level_count, leaves.size ())},
104- m_leaf_positions{level_positions_view (0 )},
105- m_valid_positions{position_iterator (1 ), position_iterator (position_iterator::value_type{1 } << level_count)},
106- m_tree{typename container_type::size_type{1 } << level_count, status_type::clean} {
107- const auto lp = m_leaf_positions;
108- std::ranges::copy (leaves, &m_tree[*lp.begin ()]);
109- build_from_leaves ();
101+ m_mapped_memory{get_storage_length (level_count, leaf_count), os::mapped_memory_flags{.shared = shared},
102+ backing_filename},
103+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
104+ m_tree{reinterpret_cast <status_type *>(m_mapped_memory.get_ptr ()), size_type{1 } << level_count} {
105+ if (!is_initialized ()) {
106+ const auto lp = m_leaf_positions;
107+ const auto first_leaf = *lp.begin ();
108+ const auto first_pad = first_leaf + leaf_count;
109+ const auto pad_count = *lp.end () - first_pad;
110+ std::ranges::fill (m_tree, status_type::clean);
111+ std::ranges::fill (m_tree.subspan (first_leaf, leaf_count), init);
112+ std::ranges::fill (m_tree.subspan (first_pad, pad_count), status_type::dirty);
113+ build_from_leaves ();
114+ set_initialized ();
115+ }
110116 }
111117
112118 // No copy or move constructors or assignments
@@ -118,6 +124,10 @@ class dirty_page_tree final : public i_dirty_page_tree {
118124 // / \brief Destructor
119125 ~dirty_page_tree () override = default ;
120126
127+ static uint64_t get_storage_length (int level_count, size_type leaf_count) {
128+ return (UINT64_C (1 ) << check_level_count (level_count, leaf_count)) * sizeof (status_type);
129+ }
130+
121131 // Dump tree in DOT format
122132 void dump () const {
123133 std::cout << " digraph HashTree {\n " ;
@@ -328,6 +338,11 @@ class dirty_page_tree final : public i_dirty_page_tree {
328338 return m_tree[*pos] == status_type::dirty;
329339 }
330340
341+ // / \brief Tells if the dirty page tree is clean
342+ bool do_is_clean () const noexcept override {
343+ return m_tree[*get_root_position ()] == status_type::clean;
344+ }
345+
331346 // / \brief Clean entire tree
332347 void do_clean () noexcept override {
333348 for (auto pos : dirty_positions_view (leaf_positions_view ())) {
@@ -336,14 +351,19 @@ class dirty_page_tree final : public i_dirty_page_tree {
336351 assert (m_tree[*get_root_position ()] == status_type::clean);
337352 }
338353
354+ // / \brief Gets storage data
355+ std::span<const unsigned char > do_get_storage_data () const noexcept override {
356+ return m_mapped_memory.get_storage_data ();
357+ }
358+
339359 // -----
340360 // Fields
341361 // -----
342362
343- positions_range m_leaf_positions; // Bounds on leaf positions
344- positions_range m_valid_positions; // Bounds on all positions
345- // ??(edubart): convert to std::span over mapped memory
346- container_type m_tree; // Complete tree of flags
363+ positions_range m_leaf_positions; // /< Bounds on leaf positions
364+ positions_range m_valid_positions; // /< Bounds on all positions
365+ os::mapped_memory m_mapped_memory; // /< Mapped memory for tree storage
366+ container_type m_tree; // /< Complete tree of flags
347367};
348368
349369} // namespace cartesi
0 commit comments