HashIndex.h 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /*
  2. * Copyright (c) 2021, Jan de Visser <jan@de-visser.net>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/WeakPtr.h>
  8. #include <LibCore/Object.h>
  9. #include <LibSQL/Forward.h>
  10. #include <LibSQL/Heap.h>
  11. #include <LibSQL/Index.h>
  12. #include <LibSQL/Key.h>
  13. namespace SQL {
  14. /**
  15. * The HashIndex class is a straightforward implementation of a persisted
  16. * extendible hash table (see
  17. * https://en.wikipedia.org/wiki/Extendible_hashing).
  18. */
  19. class HashBucket : public IndexNode
  20. , public Weakable<HashBucket> {
  21. public:
  22. HashBucket(HashIndex&, u32 index, u32 local_depth, u32 pointer);
  23. ~HashBucket() override = default;
  24. Optional<u32> get(Key&);
  25. bool insert(Key const&);
  26. Vector<Key> const& entries()
  27. {
  28. inflate();
  29. return m_entries;
  30. }
  31. Key const& operator[](size_t);
  32. Key const& operator[](size_t ix) const
  33. {
  34. VERIFY(ix < m_entries.size());
  35. return m_entries[ix];
  36. }
  37. [[nodiscard]] u32 local_depth() const { return m_local_depth; }
  38. [[nodiscard]] u32 size() { return entries().size(); }
  39. [[nodiscard]] u32 size() const { return m_entries.size(); }
  40. [[nodiscard]] u32 index() const { return m_index; }
  41. void serialize(ByteBuffer&) const override;
  42. IndexNode* as_index_node() override { return dynamic_cast<IndexNode*>(this); }
  43. [[nodiscard]] HashIndex const& hash_index() const { return m_hash_index; }
  44. [[nodiscard]] HashBucket const* next_bucket();
  45. [[nodiscard]] HashBucket const* previous_bucket();
  46. void list_bucket();
  47. private:
  48. Optional<size_t> find_key_in_bucket(Key const&);
  49. void set_index(u32 index) { m_index = index; }
  50. void set_local_depth(u32 depth) { m_local_depth = depth; }
  51. [[nodiscard]] size_t max_entries_in_bucket() const;
  52. void inflate();
  53. HashIndex& m_hash_index;
  54. u32 m_local_depth { 1 };
  55. u32 m_index { 0 };
  56. Vector<Key> m_entries;
  57. bool m_inflated { false };
  58. friend HashIndex;
  59. };
  60. class HashIndex : public Index {
  61. C_OBJECT(HashIndex);
  62. public:
  63. ~HashIndex() override = default;
  64. Optional<u32> get(Key&);
  65. bool insert(Key const&);
  66. bool insert(Key const&& entry) { return insert(entry); }
  67. HashIndexIterator find(Key const&);
  68. HashIndexIterator begin();
  69. static HashIndexIterator end();
  70. [[nodiscard]] u32 global_depth() const { return m_global_depth; }
  71. [[nodiscard]] u32 size() const { return 1 << m_global_depth; }
  72. [[nodiscard]] HashBucket* get_bucket(u32);
  73. [[nodiscard]] u32 node_pointer(u32 node_number) const { return m_nodes[node_number]; }
  74. [[nodiscard]] u32 first_node_pointer() const { return m_nodes[0]; }
  75. [[nodiscard]] size_t nodes() const { return m_nodes.size(); }
  76. void list_hash();
  77. private:
  78. HashIndex(Heap&, NonnullRefPtr<TupleDescriptor> const&, u32);
  79. void expand();
  80. void write_directory_to_write_ahead_log();
  81. HashBucket* append_bucket(u32 index, u32 local_depth, u32 pointer);
  82. HashBucket* get_bucket_for_insert(Key const&);
  83. [[nodiscard]] HashBucket* get_bucket_by_index(u32 index);
  84. u32 m_global_depth { 1 };
  85. Vector<u32> m_nodes;
  86. Vector<OwnPtr<HashBucket>> m_buckets;
  87. friend HashBucket;
  88. friend HashDirectoryNode;
  89. };
  90. class HashDirectoryNode : public IndexNode {
  91. public:
  92. HashDirectoryNode(HashIndex&, u32, size_t);
  93. HashDirectoryNode(HashIndex&, u32, ByteBuffer&);
  94. HashDirectoryNode(HashDirectoryNode const& other) = default;
  95. void serialize(ByteBuffer&) const override;
  96. IndexNode* as_index_node() override { return dynamic_cast<IndexNode*>(this); }
  97. [[nodiscard]] u32 number_of_pointers() const { return min(max_pointers_in_node(), m_hash_index.size() - m_offset); }
  98. [[nodiscard]] bool is_last() const { return m_is_last; }
  99. static constexpr size_t max_pointers_in_node() { return (BLOCKSIZE - 3 * sizeof(u32)) / (2 * sizeof(u32)); }
  100. private:
  101. HashIndex& m_hash_index;
  102. size_t m_node_number { 0 };
  103. size_t m_offset { 0 };
  104. bool m_is_last { false };
  105. };
  106. class HashIndexIterator {
  107. public:
  108. [[nodiscard]] bool is_end() const { return !m_current; }
  109. bool operator==(HashIndexIterator const& other) const;
  110. bool operator!=(HashIndexIterator const& other) const { return !(*this == other); }
  111. bool operator==(Key const& other) const;
  112. bool operator!=(Key const& other) const { return !(*this == other); }
  113. HashIndexIterator operator++()
  114. {
  115. *this = next();
  116. return *this;
  117. }
  118. HashIndexIterator operator++(int)
  119. {
  120. *this = next();
  121. return *this;
  122. }
  123. HashIndexIterator operator--()
  124. {
  125. *this = previous();
  126. return *this;
  127. }
  128. HashIndexIterator const operator--(int)
  129. {
  130. *this = previous();
  131. return *this;
  132. }
  133. Key const& operator*() const
  134. {
  135. VERIFY(!is_end());
  136. return (*m_current)[m_index];
  137. }
  138. Key const& operator->() const
  139. {
  140. VERIFY(!is_end());
  141. return (*m_current)[m_index];
  142. }
  143. HashIndexIterator& operator=(HashIndexIterator const&) = default;
  144. HashIndexIterator(HashIndexIterator const&) = default;
  145. private:
  146. HashIndexIterator() = default;
  147. explicit HashIndexIterator(HashBucket const*, size_t key_index = 0);
  148. static HashIndexIterator end() { return HashIndexIterator(); }
  149. [[nodiscard]] HashIndexIterator next();
  150. [[nodiscard]] HashIndexIterator previous();
  151. [[nodiscard]] Key key() const { return **this; }
  152. WeakPtr<HashBucket> m_current;
  153. size_t m_index { 0 };
  154. friend HashIndex;
  155. };
  156. }