bplustree.hpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. /*************************************************************************
  2. *
  3. * Copyright 2018 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_BPLUSTREE_HPP
  19. #define REALM_BPLUSTREE_HPP
  20. #include <realm/aggregate_ops.hpp>
  21. #include <realm/column_type_traits.hpp>
  22. #include <realm/decimal128.hpp>
  23. #include <realm/timestamp.hpp>
  24. #include <realm/object_id.hpp>
  25. #include <realm/util/function_ref.hpp>
  26. namespace realm {
  27. class BPlusTreeBase;
  28. class BPlusTreeInner;
  29. /*****************************************************************************/
  30. /* BPlusTreeNode */
  31. /* Base class for all nodes in the BPlusTree. Provides an abstract interface */
  32. /* that can be used by the BPlusTreeBase class to manipulate the tree. */
  33. /*****************************************************************************/
  34. class BPlusTreeNode {
  35. public:
  36. struct State {
  37. int64_t split_offset;
  38. size_t split_size;
  39. };
  40. // Insert an element at 'insert_pos'. May cause node to be split
  41. using InsertFunc = util::FunctionRef<size_t(BPlusTreeNode*, size_t insert_pos)>;
  42. // Access element at 'ndx'. Insertion/deletion not allowed
  43. using AccessFunc = util::FunctionRef<void(BPlusTreeNode*, size_t ndx)>;
  44. // Erase element at erase_pos. May cause nodes to be merged
  45. using EraseFunc = util::FunctionRef<size_t(BPlusTreeNode*, size_t erase_pos)>;
  46. // Function to be called for all leaves in the tree until the function
  47. // returns 'true'. 'offset' gives index of the first element in the leaf.
  48. using TraverseFunc = util::FunctionRef<bool(BPlusTreeNode*, size_t offset)>;
  49. BPlusTreeNode(BPlusTreeBase* tree)
  50. : m_tree(tree)
  51. {
  52. }
  53. void change_owner(BPlusTreeBase* tree)
  54. {
  55. m_tree = tree;
  56. }
  57. bool get_context_flag() const noexcept;
  58. void set_context_flag(bool) noexcept;
  59. virtual ~BPlusTreeNode();
  60. virtual bool is_leaf() const = 0;
  61. virtual bool is_compact() const = 0;
  62. virtual ref_type get_ref() const = 0;
  63. virtual void init_from_ref(ref_type ref) noexcept = 0;
  64. virtual void bp_set_parent(ArrayParent* parent, size_t ndx_in_parent) = 0;
  65. virtual void update_parent() = 0;
  66. // Number of elements in this node
  67. virtual size_t get_node_size() const = 0;
  68. // Size of subtree
  69. virtual size_t get_tree_size() const = 0;
  70. virtual ref_type bptree_insert(size_t n, State& state, InsertFunc) = 0;
  71. virtual void bptree_access(size_t n, AccessFunc) = 0;
  72. virtual size_t bptree_erase(size_t n, EraseFunc) = 0;
  73. virtual bool bptree_traverse(TraverseFunc) = 0;
  74. // Move elements over in new node, starting with element at position 'ndx'.
  75. // If this is an inner node, the index offsets should be adjusted with 'adj'
  76. virtual void move(BPlusTreeNode* new_node, size_t ndx, int64_t offset_adj) = 0;
  77. virtual void verify() const = 0;
  78. protected:
  79. BPlusTreeBase* m_tree;
  80. };
  81. /*****************************************************************************/
  82. /* BPlusTreeLeaf */
  83. /* Base class for all leaf nodes. */
  84. /*****************************************************************************/
  85. class BPlusTreeLeaf : public BPlusTreeNode {
  86. public:
  87. using BPlusTreeNode::BPlusTreeNode;
  88. bool is_leaf() const override
  89. {
  90. return true;
  91. }
  92. bool is_compact() const override
  93. {
  94. return true;
  95. }
  96. ref_type bptree_insert(size_t n, State& state, InsertFunc) override;
  97. void bptree_access(size_t n, AccessFunc) override;
  98. size_t bptree_erase(size_t n, EraseFunc) override;
  99. bool bptree_traverse(TraverseFunc) override;
  100. };
  101. /*****************************************************************************/
  102. /* BPlusTreeBase */
  103. /* Base class for the actual tree classes. */
  104. /*****************************************************************************/
  105. class BPlusTreeBase {
  106. public:
  107. BPlusTreeBase(Allocator& alloc)
  108. : m_alloc(alloc)
  109. {
  110. invalidate_leaf_cache();
  111. }
  112. virtual ~BPlusTreeBase();
  113. Allocator& get_alloc() const
  114. {
  115. return m_alloc;
  116. }
  117. bool is_attached() const
  118. {
  119. return bool(m_root);
  120. }
  121. bool get_context_flag() const noexcept
  122. {
  123. return m_root->get_context_flag();
  124. }
  125. void set_context_flag(bool cf) noexcept
  126. {
  127. m_root->set_context_flag(cf);
  128. }
  129. size_t size() const
  130. {
  131. return m_size;
  132. }
  133. bool is_empty() const
  134. {
  135. return m_size == 0;
  136. }
  137. ref_type get_ref() const
  138. {
  139. REALM_ASSERT(is_attached());
  140. return m_root->get_ref();
  141. }
  142. void init_from_ref(ref_type ref)
  143. {
  144. auto new_root = create_root_from_ref(ref);
  145. new_root->bp_set_parent(m_parent, m_ndx_in_parent);
  146. m_root = std::move(new_root);
  147. invalidate_leaf_cache();
  148. m_size = m_root->get_tree_size();
  149. }
  150. bool init_from_parent()
  151. {
  152. ref_type ref = m_parent->get_child_ref(m_ndx_in_parent);
  153. if (!ref) {
  154. return false;
  155. }
  156. auto new_root = create_root_from_ref(ref);
  157. new_root->bp_set_parent(m_parent, m_ndx_in_parent);
  158. m_root = std::move(new_root);
  159. invalidate_leaf_cache();
  160. m_size = m_root->get_tree_size();
  161. return true;
  162. }
  163. void set_parent(ArrayParent* parent, size_t ndx_in_parent)
  164. {
  165. m_parent = parent;
  166. m_ndx_in_parent = ndx_in_parent;
  167. if (is_attached())
  168. m_root->bp_set_parent(parent, ndx_in_parent);
  169. }
  170. void create();
  171. void destroy();
  172. void verify() const
  173. {
  174. m_root->verify();
  175. }
  176. protected:
  177. template <class U>
  178. struct LeafTypeTrait {
  179. using type = typename ColumnTypeTraits<U>::cluster_leaf_type;
  180. };
  181. friend class BPlusTreeInner;
  182. friend class BPlusTreeLeaf;
  183. std::unique_ptr<BPlusTreeNode> m_root;
  184. Allocator& m_alloc;
  185. ArrayParent* m_parent = nullptr;
  186. size_t m_ndx_in_parent = 0;
  187. size_t m_size = 0;
  188. size_t m_cached_leaf_begin;
  189. size_t m_cached_leaf_end;
  190. void set_leaf_bounds(size_t b, size_t e)
  191. {
  192. m_cached_leaf_begin = b;
  193. m_cached_leaf_end = e;
  194. }
  195. void invalidate_leaf_cache()
  196. {
  197. m_cached_leaf_begin = size_t(-1);
  198. m_cached_leaf_end = size_t(-1);
  199. }
  200. void adjust_leaf_bounds(int incr)
  201. {
  202. m_cached_leaf_end += incr;
  203. }
  204. void bptree_insert(size_t n, BPlusTreeNode::InsertFunc func);
  205. void bptree_erase(size_t n, BPlusTreeNode::EraseFunc func);
  206. // Create an un-attached leaf node
  207. virtual std::unique_ptr<BPlusTreeLeaf> create_leaf_node() = 0;
  208. // Create a leaf node and initialize it with 'ref'
  209. virtual std::unique_ptr<BPlusTreeLeaf> init_leaf_node(ref_type ref) = 0;
  210. // Initialize the leaf cache with 'mem'
  211. virtual BPlusTreeLeaf* cache_leaf(MemRef mem) = 0;
  212. virtual void replace_root(std::unique_ptr<BPlusTreeNode> new_root);
  213. std::unique_ptr<BPlusTreeNode> create_root_from_ref(ref_type ref);
  214. };
  215. template <>
  216. struct BPlusTreeBase::LeafTypeTrait<ObjKey> {
  217. using type = ArrayKeyNonNullable;
  218. };
  219. /*****************************************************************************/
  220. /* BPlusTree */
  221. /* Actual implementation of the BPlusTree to hold elements of type T. */
  222. /*****************************************************************************/
  223. template <class T>
  224. class BPlusTree : public BPlusTreeBase {
  225. public:
  226. using LeafArray = typename LeafTypeTrait<T>::type;
  227. /**
  228. * Actual class for the leaves. Maps the abstract interface defined
  229. * in BPlusTreeNode onto the specific array class
  230. **/
  231. class LeafNode : public BPlusTreeLeaf, public LeafArray {
  232. public:
  233. LeafNode(BPlusTreeBase* tree)
  234. : BPlusTreeLeaf(tree)
  235. , LeafArray(tree->get_alloc())
  236. {
  237. }
  238. void init_from_ref(ref_type ref) noexcept override
  239. {
  240. LeafArray::init_from_ref(ref);
  241. }
  242. ref_type get_ref() const override
  243. {
  244. return LeafArray::get_ref();
  245. }
  246. void bp_set_parent(realm::ArrayParent* p, size_t n) override
  247. {
  248. LeafArray::set_parent(p, n);
  249. }
  250. void update_parent() override
  251. {
  252. LeafArray::update_parent();
  253. }
  254. size_t get_node_size() const override
  255. {
  256. return LeafArray::size();
  257. }
  258. size_t get_tree_size() const override
  259. {
  260. return LeafArray::size();
  261. }
  262. void move(BPlusTreeNode* new_node, size_t ndx, int64_t) override
  263. {
  264. LeafNode* dst(static_cast<LeafNode*>(new_node));
  265. LeafArray::move(*dst, ndx);
  266. }
  267. void verify() const override
  268. {
  269. LeafArray::verify();
  270. }
  271. };
  272. BPlusTree(Allocator& alloc)
  273. : BPlusTreeBase(alloc)
  274. , m_leaf_cache(this)
  275. {
  276. }
  277. /************ Tree manipulation functions ************/
  278. static T default_value(bool nullable = false)
  279. {
  280. return LeafArray::default_value(nullable);
  281. }
  282. void add(T value)
  283. {
  284. insert(npos, value);
  285. }
  286. void insert(size_t n, T value)
  287. {
  288. auto func = [value](BPlusTreeNode* node, size_t ndx) {
  289. LeafNode* leaf = static_cast<LeafNode*>(node);
  290. leaf->LeafArray::insert(ndx, value);
  291. return leaf->size();
  292. };
  293. bptree_insert(n, func);
  294. m_size++;
  295. }
  296. inline T get(size_t n) const
  297. {
  298. // Fast path
  299. if (m_cached_leaf_begin <= n && n < m_cached_leaf_end) {
  300. return m_leaf_cache.get(n - m_cached_leaf_begin);
  301. }
  302. else {
  303. // Slow path
  304. return get_uncached(n);
  305. }
  306. }
  307. REALM_NOINLINE T get_uncached(size_t n) const
  308. {
  309. T value;
  310. auto func = [&value](BPlusTreeNode* node, size_t ndx) {
  311. LeafNode* leaf = static_cast<LeafNode*>(node);
  312. value = leaf->get(ndx);
  313. };
  314. m_root->bptree_access(n, func);
  315. return value;
  316. }
  317. std::vector<T> get_all() const
  318. {
  319. std::vector<T> all_values;
  320. all_values.reserve(m_size);
  321. auto func = [&all_values](BPlusTreeNode* node, size_t) {
  322. LeafNode* leaf = static_cast<LeafNode*>(node);
  323. size_t sz = leaf->size();
  324. for (size_t i = 0; i < sz; i++) {
  325. all_values.push_back(leaf->get(i));
  326. }
  327. return false;
  328. };
  329. m_root->bptree_traverse(func);
  330. return all_values;
  331. }
  332. void set(size_t n, T value)
  333. {
  334. auto func = [value](BPlusTreeNode* node, size_t ndx) {
  335. LeafNode* leaf = static_cast<LeafNode*>(node);
  336. leaf->set(ndx, value);
  337. };
  338. m_root->bptree_access(n, func);
  339. }
  340. void swap(size_t ndx1, size_t ndx2)
  341. {
  342. if constexpr (std::is_same_v<T, StringData> || std::is_same_v<T, BinaryData>) {
  343. struct SwapBuffer {
  344. std::string val;
  345. bool n;
  346. SwapBuffer(T v)
  347. : val(v.data(), v.size())
  348. , n(v.is_null())
  349. {
  350. }
  351. T get()
  352. {
  353. return n ? T() : T(val);
  354. }
  355. };
  356. SwapBuffer tmp1{get(ndx1)};
  357. SwapBuffer tmp2{get(ndx2)};
  358. set(ndx1, tmp2.get());
  359. set(ndx2, tmp1.get());
  360. }
  361. else if constexpr (std::is_same_v<T, Mixed>) {
  362. std::string buf1;
  363. std::string buf2;
  364. Mixed tmp1 = get(ndx1);
  365. Mixed tmp2 = get(ndx2);
  366. if (tmp1.is_type(type_String, type_Binary)) {
  367. tmp1.use_buffer(buf1);
  368. }
  369. if (tmp2.is_type(type_String, type_Binary)) {
  370. tmp2.use_buffer(buf2);
  371. }
  372. set(ndx1, tmp2);
  373. set(ndx2, tmp1);
  374. }
  375. else {
  376. T tmp = get(ndx1);
  377. set(ndx1, get(ndx2));
  378. set(ndx2, tmp);
  379. }
  380. }
  381. void erase(size_t n)
  382. {
  383. auto func = [](BPlusTreeNode* node, size_t ndx) {
  384. LeafNode* leaf = static_cast<LeafNode*>(node);
  385. leaf->LeafArray::erase(ndx);
  386. return leaf->size();
  387. };
  388. bptree_erase(n, func);
  389. m_size--;
  390. }
  391. void clear()
  392. {
  393. if (m_root->is_leaf()) {
  394. LeafNode* leaf = static_cast<LeafNode*>(m_root.get());
  395. leaf->clear();
  396. }
  397. else {
  398. destroy();
  399. create();
  400. if (m_parent) {
  401. m_parent->update_child_ref(m_ndx_in_parent, get_ref());
  402. }
  403. }
  404. m_size = 0;
  405. }
  406. void traverse(BPlusTreeNode::TraverseFunc func) const
  407. {
  408. if (m_root) {
  409. m_root->bptree_traverse(func);
  410. }
  411. }
  412. size_t find_first(T value) const noexcept
  413. {
  414. size_t result = realm::npos;
  415. auto func = [&result, value](BPlusTreeNode* node, size_t offset) {
  416. LeafNode* leaf = static_cast<LeafNode*>(node);
  417. size_t sz = leaf->size();
  418. auto i = leaf->find_first(value, 0, sz);
  419. if (i < sz) {
  420. result = i + offset;
  421. return true;
  422. }
  423. return false;
  424. };
  425. m_root->bptree_traverse(func);
  426. return result;
  427. }
  428. template <typename Func>
  429. void find_all(T value, Func&& callback) const noexcept
  430. {
  431. auto func = [&callback, value](BPlusTreeNode* node, size_t offset) {
  432. LeafNode* leaf = static_cast<LeafNode*>(node);
  433. size_t i = -1, sz = leaf->size();
  434. while ((i = leaf->find_first(value, i + 1, sz)) < sz) {
  435. callback(i + offset);
  436. }
  437. return false;
  438. };
  439. m_root->bptree_traverse(func);
  440. }
  441. void dump_values(std::ostream& o, int level) const
  442. {
  443. std::string indent(" ", level * 2);
  444. auto func = [&o, indent](BPlusTreeNode* node, size_t) {
  445. LeafNode* leaf = static_cast<LeafNode*>(node);
  446. size_t sz = leaf->size();
  447. for (size_t i = 0; i < sz; i++) {
  448. o << indent << leaf->get(i) << std::endl;
  449. }
  450. return false;
  451. };
  452. m_root->bptree_traverse(func);
  453. }
  454. protected:
  455. LeafNode m_leaf_cache;
  456. /******** Implementation of abstract interface *******/
  457. std::unique_ptr<BPlusTreeLeaf> create_leaf_node() override
  458. {
  459. std::unique_ptr<BPlusTreeLeaf> leaf = std::make_unique<LeafNode>(this);
  460. static_cast<LeafNode*>(leaf.get())->create();
  461. return leaf;
  462. }
  463. std::unique_ptr<BPlusTreeLeaf> init_leaf_node(ref_type ref) override
  464. {
  465. std::unique_ptr<BPlusTreeLeaf> leaf = std::make_unique<LeafNode>(this);
  466. leaf->init_from_ref(ref);
  467. return leaf;
  468. }
  469. BPlusTreeLeaf* cache_leaf(MemRef mem) override
  470. {
  471. m_leaf_cache.init_from_mem(mem);
  472. return &m_leaf_cache;
  473. }
  474. void replace_root(std::unique_ptr<BPlusTreeNode> new_root) override
  475. {
  476. // Only copy context flag over in a linklist.
  477. // The flag is in use in other list types
  478. if constexpr (std::is_same_v<T, ObjKey>) {
  479. auto cf = m_root ? m_root->get_context_flag() : false;
  480. BPlusTreeBase::replace_root(std::move(new_root));
  481. m_root->set_context_flag(cf);
  482. }
  483. else {
  484. BPlusTreeBase::replace_root(std::move(new_root));
  485. }
  486. }
  487. template <class R>
  488. friend R bptree_sum(const BPlusTree<T>& tree);
  489. };
  490. template <class T>
  491. using SumAggType = typename aggregate_operations::Sum<typename util::RemoveOptional<T>::type>;
  492. template <class T>
  493. typename SumAggType<T>::ResultType bptree_sum(const BPlusTree<T>& tree, size_t* return_cnt = nullptr)
  494. {
  495. SumAggType<T> agg;
  496. auto func = [&agg](BPlusTreeNode* node, size_t) {
  497. auto leaf = static_cast<typename BPlusTree<T>::LeafNode*>(node);
  498. size_t sz = leaf->size();
  499. for (size_t i = 0; i < sz; i++) {
  500. auto val = leaf->get(i);
  501. agg.accumulate(val);
  502. }
  503. return false;
  504. };
  505. tree.traverse(func);
  506. if (return_cnt)
  507. *return_cnt = agg.items_counted();
  508. return agg.result();
  509. }
  510. template <class AggType, class T>
  511. util::Optional<typename util::RemoveOptional<T>::type> bptree_min_max(const BPlusTree<T>& tree,
  512. size_t* return_ndx = nullptr)
  513. {
  514. AggType agg;
  515. if (tree.size() == 0) {
  516. return util::none;
  517. }
  518. auto func = [&agg, return_ndx](BPlusTreeNode* node, size_t offset) {
  519. auto leaf = static_cast<typename BPlusTree<T>::LeafNode*>(node);
  520. size_t sz = leaf->size();
  521. for (size_t i = 0; i < sz; i++) {
  522. auto val_or_null = leaf->get(i);
  523. bool found_new_min = agg.accumulate(val_or_null);
  524. if (found_new_min && return_ndx) {
  525. *return_ndx = i + offset;
  526. }
  527. }
  528. return false;
  529. };
  530. tree.traverse(func);
  531. return agg.is_null() ? util::none : util::Optional{agg.result()};
  532. }
  533. template <class T>
  534. using MinAggType = typename aggregate_operations::Minimum<typename util::RemoveOptional<T>::type>;
  535. template <class T>
  536. util::Optional<typename util::RemoveOptional<T>::type> bptree_minimum(const BPlusTree<T>& tree,
  537. size_t* return_ndx = nullptr)
  538. {
  539. return bptree_min_max<MinAggType<T>, T>(tree, return_ndx);
  540. }
  541. template <class T>
  542. using MaxAggType = typename aggregate_operations::Maximum<typename util::RemoveOptional<T>::type>;
  543. template <class T>
  544. util::Optional<typename util::RemoveOptional<T>::type> bptree_maximum(const BPlusTree<T>& tree,
  545. size_t* return_ndx = nullptr)
  546. {
  547. return bptree_min_max<MaxAggType<T>, T>(tree, return_ndx);
  548. }
  549. template <class T>
  550. ColumnAverageType<T> bptree_average(const BPlusTree<T>& tree, size_t* return_cnt = nullptr)
  551. {
  552. size_t cnt;
  553. auto sum = bptree_sum(tree, &cnt);
  554. ColumnAverageType<T> avg{};
  555. if (cnt != 0)
  556. avg = ColumnAverageType<T>(sum) / cnt;
  557. if (return_cnt)
  558. *return_cnt = cnt;
  559. return avg;
  560. }
  561. } // namespace realm
  562. #endif /* REALM_BPLUSTREE_HPP */