cluster.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /*************************************************************************
  2. *
  3. * Copyright 2016 Realm Inc.
  4. *
  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
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  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.
  16. *
  17. **************************************************************************/
  18. #ifndef REALM_CLUSTER_HPP
  19. #define REALM_CLUSTER_HPP
  20. #include <realm/keys.hpp>
  21. #include <realm/mixed.hpp>
  22. #include <realm/array.hpp>
  23. #include <realm/array_unsigned.hpp>
  24. #include <realm/data_type.hpp>
  25. #include <realm/column_type_traits.hpp>
  26. namespace realm {
  27. class Spec;
  28. class Table;
  29. class Obj;
  30. class Cluster;
  31. class ClusterNodeInner;
  32. class ClusterTree;
  33. class ColumnAttrMask;
  34. class CascadeState;
  35. struct FieldValue {
  36. FieldValue(ColKey k, Mixed val, bool is_default = false) noexcept
  37. : col_key(k)
  38. , value(val)
  39. , is_default(is_default)
  40. {
  41. }
  42. ColKey col_key;
  43. Mixed value;
  44. bool is_default;
  45. };
  46. class FieldValues {
  47. public:
  48. FieldValues() {}
  49. FieldValues(std::initializer_list<FieldValue>);
  50. void insert(ColKey k, Mixed val, bool is_default = false);
  51. auto begin() const noexcept
  52. {
  53. return m_values.begin();
  54. }
  55. auto end() const noexcept
  56. {
  57. return m_values.end();
  58. }
  59. auto begin() noexcept
  60. {
  61. return m_values.begin();
  62. }
  63. auto end() noexcept
  64. {
  65. return m_values.end();
  66. }
  67. private:
  68. std::vector<FieldValue> m_values;
  69. };
  70. class ClusterNode : public Array {
  71. public:
  72. // This structure is used to bring information back to the upper nodes when
  73. // inserting new objects or finding existing ones.
  74. struct State {
  75. int64_t split_key; // When a node is split, this variable holds the value of the
  76. // first key in the new node. (Relative to the key offset)
  77. MemRef mem; // MemRef to the Cluster holding the new/found object
  78. size_t index = realm::npos; // The index within the Cluster at which the object is stored.
  79. operator bool() const
  80. {
  81. return index != realm::npos;
  82. }
  83. };
  84. struct IteratorState {
  85. IteratorState(Cluster& leaf)
  86. : m_current_leaf(leaf)
  87. {
  88. }
  89. IteratorState(const IteratorState&);
  90. void clear();
  91. void init(State&, ObjKey);
  92. Cluster& m_current_leaf;
  93. int64_t m_key_offset = 0;
  94. size_t m_current_index = 0;
  95. };
  96. ClusterNode(uint64_t offset, Allocator& allocator, const ClusterTree& tree_top)
  97. : Array(allocator)
  98. , m_tree_top(tree_top)
  99. , m_keys(allocator)
  100. , m_offset(offset)
  101. {
  102. m_keys.set_parent(this, 0);
  103. }
  104. virtual ~ClusterNode()
  105. {
  106. }
  107. void init_from_parent()
  108. {
  109. ref_type ref = get_ref_from_parent();
  110. char* header = m_alloc.translate(ref);
  111. init(MemRef(header, ref, m_alloc));
  112. }
  113. int64_t get_key_value(size_t ndx) const
  114. {
  115. return m_keys.get(ndx);
  116. }
  117. const Table* get_owning_table() const noexcept;
  118. virtual void update_from_parent() noexcept = 0;
  119. virtual bool is_leaf() const = 0;
  120. virtual int get_sub_tree_depth() const = 0;
  121. virtual size_t node_size() const = 0;
  122. /// Number of elements in this subtree
  123. virtual size_t get_tree_size() const = 0;
  124. /// Last key in this subtree
  125. virtual int64_t get_last_key_value() const = 0;
  126. virtual void ensure_general_form() = 0;
  127. /// Initialize node from 'mem'
  128. virtual void init(MemRef mem) = 0;
  129. /// Descend the tree from the root and copy-on-write the leaf
  130. /// This will update all parents accordingly
  131. virtual MemRef ensure_writeable(ObjKey k) = 0;
  132. /// A leaf cluster has got a new ref. Descend the tree from the root,
  133. /// find the leaf and update the ref in the parent node
  134. virtual void update_ref_in_parent(ObjKey k, ref_type ref) = 0;
  135. /// Init and potentially Insert a column
  136. virtual void insert_column(ColKey col) = 0;
  137. /// Clear and potentially Remove a column
  138. virtual void remove_column(ColKey col) = 0;
  139. /// Return number of columns created. To be used by upgrade logic
  140. virtual size_t nb_columns() const
  141. {
  142. return realm::npos;
  143. }
  144. /// Create a new object identified by 'key' and update 'state' accordingly
  145. /// Return reference to new node created (if any)
  146. virtual ref_type insert(ObjKey k, const FieldValues& init_values, State& state) = 0;
  147. /// Locate object identified by 'key' and update 'state' accordingly
  148. void get(ObjKey key, State& state) const;
  149. /// Locate object identified by 'key' and update 'state' accordingly
  150. /// Returns `false` if the object doesn't not exist.
  151. virtual bool try_get(ObjKey key, State& state) const noexcept = 0;
  152. /// Locate object identified by 'ndx' and update 'state' accordingly
  153. virtual ObjKey get(size_t ndx, State& state) const = 0;
  154. /// Return the index at which key is stored
  155. virtual size_t get_ndx(ObjKey key, size_t ndx) const noexcept = 0;
  156. /// Erase element identified by 'key'
  157. virtual size_t erase(ObjKey key, CascadeState& state) = 0;
  158. /// Nullify links pointing to element identified by 'key'
  159. virtual void nullify_incoming_links(ObjKey key, CascadeState& state) = 0;
  160. /// Move elements from position 'ndx' to 'new_node'. The new node is supposed
  161. /// to be a sibling positioned right after this one. All key values must
  162. /// be subtracted 'key_adj'
  163. virtual void move(size_t ndx, ClusterNode* new_leaf, int64_t key_adj) = 0;
  164. virtual void dump_objects(int64_t key_offset, std::string lead) const = 0;
  165. ObjKey get_real_key(size_t ndx) const
  166. {
  167. return ObjKey(get_key_value(ndx) + m_offset);
  168. }
  169. const ArrayUnsigned* get_key_array() const
  170. {
  171. return m_keys.is_attached() ? &m_keys : nullptr;
  172. }
  173. void set_offset(uint64_t offs)
  174. {
  175. m_offset = offs;
  176. }
  177. uint64_t get_offset() const
  178. {
  179. return m_offset;
  180. }
  181. protected:
  182. #if REALM_MAX_BPNODE_SIZE > 256
  183. static constexpr int node_shift_factor = 8;
  184. #else
  185. static constexpr int node_shift_factor = 2;
  186. #endif
  187. static constexpr size_t cluster_node_size = 1 << node_shift_factor;
  188. class ClusterKeyArray : public ArrayUnsigned {
  189. public:
  190. using ArrayUnsigned::ArrayUnsigned;
  191. uint64_t get(size_t ndx) const
  192. {
  193. return (m_data != nullptr) ? ArrayUnsigned::get(ndx) : uint64_t(ndx);
  194. }
  195. };
  196. const ClusterTree& m_tree_top;
  197. ClusterKeyArray m_keys;
  198. uint64_t m_offset;
  199. };
  200. class Cluster : public ClusterNode {
  201. public:
  202. Cluster(uint64_t offset, Allocator& allocator, const ClusterTree& tree_top)
  203. : ClusterNode(offset, allocator, tree_top)
  204. {
  205. }
  206. ~Cluster() override;
  207. static MemRef create_empty_cluster(Allocator& alloc);
  208. void create(); // Note: leaf columns - may include holes
  209. void init(MemRef mem) override;
  210. void update_from_parent() noexcept override;
  211. bool is_writeable() const
  212. {
  213. return !Array::is_read_only();
  214. }
  215. MemRef ensure_writeable(ObjKey k) override;
  216. void update_ref_in_parent(ObjKey, ref_type ref) override;
  217. bool is_leaf() const override
  218. {
  219. return true;
  220. }
  221. int get_sub_tree_depth() const override
  222. {
  223. return 0;
  224. }
  225. static size_t node_size_from_header(Allocator& alloc, const char* header);
  226. size_t node_size() const override
  227. {
  228. if (!is_attached()) {
  229. return 0;
  230. }
  231. return m_keys.is_attached() ? m_keys.size() : get_size_in_compact_form();
  232. }
  233. size_t get_tree_size() const override
  234. {
  235. return node_size();
  236. }
  237. int64_t get_last_key_value() const override
  238. {
  239. auto sz = node_size();
  240. return sz ? get_key_value(sz - 1) : -1;
  241. }
  242. size_t lower_bound_key(ObjKey key) const
  243. {
  244. if (m_keys.is_attached()) {
  245. return m_keys.lower_bound(uint64_t(key.value));
  246. }
  247. else {
  248. size_t sz = size_t(Array::get(0)) >> 1;
  249. if (key.value < 0)
  250. return 0;
  251. if (size_t(key.value) > sz)
  252. return sz;
  253. }
  254. return size_t(key.value);
  255. }
  256. void adjust_keys(int64_t offset)
  257. {
  258. ensure_general_form();
  259. m_keys.adjust(0, m_keys.size(), offset);
  260. }
  261. ColKey get_col_key(size_t ndx_in_parent) const;
  262. void ensure_general_form() override;
  263. void insert_column(ColKey col) override; // Does not move columns!
  264. void remove_column(ColKey col) override; // Does not move columns - may leave a 'hole'
  265. size_t nb_columns() const override
  266. {
  267. return size() - s_first_col_index;
  268. }
  269. ref_type insert(ObjKey k, const FieldValues& init_values, State& state) override;
  270. bool try_get(ObjKey k, State& state) const noexcept override;
  271. ObjKey get(size_t, State& state) const override;
  272. size_t get_ndx(ObjKey key, size_t ndx) const noexcept override;
  273. size_t erase(ObjKey k, CascadeState& state) override;
  274. void nullify_incoming_links(ObjKey key, CascadeState& state) override;
  275. void upgrade_string_to_enum(ColKey col, ArrayString& keys);
  276. void init_leaf(ColKey col, ArrayPayload* leaf) const;
  277. void add_leaf(ColKey col, ref_type ref);
  278. void verify() const;
  279. void dump_objects(int64_t key_offset, std::string lead) const override;
  280. private:
  281. friend class ClusterTree;
  282. static constexpr size_t s_key_ref_or_size_index = 0;
  283. static constexpr size_t s_first_col_index = 1;
  284. size_t get_size_in_compact_form() const
  285. {
  286. return size_t(Array::get(s_key_ref_or_size_index)) >> 1; // Size is stored as tagged value
  287. }
  288. void insert_row(size_t ndx, ObjKey k, const FieldValues& init_values);
  289. void move(size_t ndx, ClusterNode* new_node, int64_t key_adj) override;
  290. template <class T>
  291. void do_create(ColKey col);
  292. template <class T>
  293. void do_insert_column(ColKey col, bool nullable);
  294. template <class T>
  295. void do_insert_row(size_t ndx, ColKey col, Mixed init_val, bool nullable);
  296. template <class T>
  297. void do_move(size_t ndx, ColKey col, Cluster* to);
  298. template <class T>
  299. void do_erase(size_t ndx, ColKey col);
  300. void remove_backlinks(ObjKey origin_key, ColKey col, const std::vector<ObjKey>& keys, CascadeState& state) const;
  301. void remove_backlinks(ObjKey origin_key, ColKey col, const std::vector<ObjLink>& links,
  302. CascadeState& state) const;
  303. void do_erase_key(size_t ndx, ColKey col, CascadeState& state);
  304. void do_insert_key(size_t ndx, ColKey col, Mixed init_val, ObjKey origin_key);
  305. void do_insert_link(size_t ndx, ColKey col, Mixed init_val, ObjKey origin_key);
  306. void do_insert_mixed(size_t ndx, ColKey col_key, Mixed init_value, ObjKey origin_key);
  307. template <class T>
  308. void set_spec(T&, ColKey::Idx) const;
  309. template <class ArrayType>
  310. void verify(ref_type ref, size_t index, util::Optional<size_t>& sz) const;
  311. };
  312. }
  313. #endif /* SRC_REALM_CLUSTER_HPP_ */