1 /*************************************************************************
3 * Copyright 2016 Realm Inc.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 **************************************************************************/
19 #ifndef REALM_COLUMN_BACKLINK_HPP
20 #define REALM_COLUMN_BACKLINK_HPP
24 #include <realm/column.hpp>
25 #include <realm/column_linkbase.hpp>
26 #include <realm/table.hpp>
30 /// A column of backlinks (BacklinkColumn) is a single B+-tree, and the root of
31 /// the column is the root of the B+-tree. All leaf nodes are single arrays of
32 /// type Array with the hasRefs bit set.
34 /// The individual values in the column are either refs to Columns containing
35 /// the row indexes in the origin table that links to it, or in the case where
36 /// there is a single link, a tagged ref encoding the origin row position.
37 class BacklinkColumn : public IntegerColumn, public ArrayParent {
39 BacklinkColumn(Allocator&, ref_type, size_t col_ndx = npos);
40 ~BacklinkColumn() noexcept override
44 static ref_type create(Allocator&, size_t size = 0);
46 bool has_backlinks(size_t row_ndx) const noexcept;
47 size_t get_backlink_count(size_t row_ndx) const noexcept;
48 size_t get_backlink(size_t row_ndx, size_t backlink_ndx) const noexcept;
50 void add_backlink(size_t row_ndx, size_t origin_row_ndx);
51 void remove_one_backlink(size_t row_ndx, size_t origin_row_ndx);
52 void remove_all_backlinks(size_t num_rows);
53 void update_backlink(size_t row_ndx, size_t old_origin_row_ndx, size_t new_origin_row_ndx);
54 void swap_backlinks(size_t row_ndx, size_t origin_row_ndx_1, size_t origin_row_ndx_2);
58 // Link origination info
59 Table& get_origin_table() const noexcept;
60 void set_origin_table(Table&) noexcept;
61 LinkColumnBase& get_origin_column() const noexcept;
62 size_t get_origin_column_index() const noexcept;
63 void set_origin_column(LinkColumnBase& column) noexcept;
65 void insert_rows(size_t, size_t, size_t, bool) override;
66 void erase_rows(size_t, size_t, size_t, bool) override;
67 void move_last_row_over(size_t, size_t, bool) override;
68 void swap_rows(size_t, size_t) override;
69 void clear(size_t, bool) override;
70 void adj_acc_insert_rows(size_t, size_t) noexcept override;
71 void adj_acc_erase_row(size_t) noexcept override;
72 void adj_acc_move_over(size_t, size_t) noexcept override;
73 void adj_acc_swap_rows(size_t, size_t) noexcept override;
74 void adj_acc_move_row(size_t, size_t) noexcept override;
75 void adj_acc_merge_rows(size_t, size_t) noexcept override;
76 void adj_acc_clear_root_table() noexcept override;
77 void mark(int) noexcept override;
79 void bump_link_origin_table_version() noexcept override;
81 void cascade_break_backlinks_to(size_t row_ndx, CascadeState& state) override;
82 void cascade_break_backlinks_to_all_rows(size_t num_rows, CascadeState&) override;
84 int compare_values(size_t, size_t) const noexcept override;
86 void verify() const override;
87 void verify(const Table&, size_t) const override;
90 size_t origin_row_ndx, target_row_ndx;
91 bool operator<(const VerifyPair&) const noexcept;
93 void get_backlinks(std::vector<VerifyPair>&); // Sorts
97 // ArrayParent overrides
98 void update_child_ref(size_t child_ndx, ref_type new_ref) override;
99 ref_type get_child_ref(size_t child_ndx) const noexcept override;
101 std::pair<ref_type, size_t> get_to_dot_parent(size_t) const override;
104 TableRef m_origin_table;
105 LinkColumnBase* m_origin_column = nullptr;
107 template <typename Func>
108 size_t for_each_link(size_t row_ndx, bool do_destroy, Func&& f);
114 inline BacklinkColumn::BacklinkColumn(Allocator& alloc, ref_type ref, size_t col_ndx)
115 : IntegerColumn(alloc, ref, col_ndx) // Throws
119 inline ref_type BacklinkColumn::create(Allocator& alloc, size_t size)
121 return IntegerColumn::create(alloc, Array::type_HasRefs, size); // Throws
124 inline bool BacklinkColumn::has_backlinks(size_t ndx) const noexcept
126 return IntegerColumn::get(ndx) != 0;
129 inline Table& BacklinkColumn::get_origin_table() const noexcept
131 return *m_origin_table;
134 inline void BacklinkColumn::set_origin_table(Table& table) noexcept
136 REALM_ASSERT(!m_origin_table);
137 m_origin_table = table.get_table_ref();
140 inline LinkColumnBase& BacklinkColumn::get_origin_column() const noexcept
142 return *m_origin_column;
145 inline size_t BacklinkColumn::get_origin_column_index() const noexcept
147 return m_origin_column ? m_origin_column->get_column_index() : npos;
150 inline void BacklinkColumn::set_origin_column(LinkColumnBase& column) noexcept
152 m_origin_column = &column;
155 inline void BacklinkColumn::add_row()
157 IntegerColumn::add(0);
160 inline void BacklinkColumn::adj_acc_insert_rows(size_t row_ndx, size_t num_rows) noexcept
162 IntegerColumn::adj_acc_insert_rows(row_ndx, num_rows);
164 typedef _impl::TableFriend tf;
165 tf::mark(*m_origin_table);
168 inline void BacklinkColumn::adj_acc_erase_row(size_t row_ndx) noexcept
170 IntegerColumn::adj_acc_erase_row(row_ndx);
172 typedef _impl::TableFriend tf;
173 tf::mark(*m_origin_table);
176 inline void BacklinkColumn::adj_acc_move_over(size_t from_row_ndx, size_t to_row_ndx) noexcept
178 IntegerColumn::adj_acc_move_over(from_row_ndx, to_row_ndx);
180 typedef _impl::TableFriend tf;
181 tf::mark(*m_origin_table);
184 inline void BacklinkColumn::adj_acc_swap_rows(size_t row_ndx_1, size_t row_ndx_2) noexcept
186 Column::adj_acc_swap_rows(row_ndx_1, row_ndx_2);
188 using tf = _impl::TableFriend;
189 tf::mark(*m_origin_table);
192 inline void BacklinkColumn::adj_acc_move_row(size_t from_ndx, size_t to_ndx) noexcept
194 Column::adj_acc_move_row(from_ndx, to_ndx);
196 using tf = _impl::TableFriend;
197 tf::mark(*m_origin_table);
200 inline void BacklinkColumn::adj_acc_merge_rows(size_t old_row_ndx, size_t new_row_ndx) noexcept
202 Column::adj_acc_merge_rows(old_row_ndx, new_row_ndx);
204 using tf = _impl::TableFriend;
205 tf::mark(*m_origin_table);
208 inline void BacklinkColumn::adj_acc_clear_root_table() noexcept
210 IntegerColumn::adj_acc_clear_root_table();
212 typedef _impl::TableFriend tf;
213 tf::mark(*m_origin_table);
216 inline void BacklinkColumn::mark(int type) noexcept
218 if (type & mark_LinkOrigins) {
219 typedef _impl::TableFriend tf;
220 tf::mark(*m_origin_table);
224 inline void BacklinkColumn::bump_link_origin_table_version() noexcept
226 // It is important to mark connected tables as modified.
227 // Also see LinkColumnBase::bump_link_origin_table_version().
228 typedef _impl::TableFriend tf;
229 if (m_origin_table) {
230 bool bump_global = false;
231 tf::bump_version(*m_origin_table, bump_global);
237 inline bool BacklinkColumn::VerifyPair::operator<(const VerifyPair& p) const noexcept
239 return origin_row_ndx < p.origin_row_ndx;
242 #endif // REALM_DEBUG
246 #endif // REALM_COLUMN_BACKLINK_HPP