HashIndex.h 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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. Key const& operator[](size_t);
  28. Key const& operator[](size_t ix) const;
  29. [[nodiscard]] u32 local_depth() const { return m_local_depth; }
  30. [[nodiscard]] u32 size() { return entries().size(); }
  31. [[nodiscard]] size_t length() const;
  32. [[nodiscard]] u32 size() const { return m_entries.size(); }
  33. [[nodiscard]] u32 index() const { return m_index; }
  34. void serialize(Serializer&) const;
  35. void deserialize(Serializer&);
  36. [[nodiscard]] HashIndex const& hash_index() const { return m_hash_index; }
  37. [[nodiscard]] HashBucket const* next_bucket();
  38. [[nodiscard]] HashBucket const* previous_bucket();
  39. void list_bucket();
  40. private:
  41. Optional<size_t> find_key_in_bucket(Key const&);
  42. void set_index(u32 index) { m_index = index; }
  43. void set_local_depth(u32 depth) { m_local_depth = depth; }
  44. HashIndex& m_hash_index;
  45. u32 m_local_depth { 1 };
  46. u32 m_index { 0 };
  47. Vector<Key> m_entries;
  48. bool m_inflated { false };
  49. friend HashIndex;
  50. };
  51. class HashIndex : public Index {
  52. C_OBJECT(HashIndex);
  53. public:
  54. ~HashIndex() override = default;
  55. Optional<u32> get(Key&);
  56. bool insert(Key const&);
  57. bool insert(Key const&& entry) { return insert(entry); }
  58. HashIndexIterator find(Key const&);
  59. HashIndexIterator begin();
  60. static HashIndexIterator end();
  61. [[nodiscard]] u32 global_depth() const { return m_global_depth; }
  62. [[nodiscard]] u32 size() const { return 1 << m_global_depth; }
  63. [[nodiscard]] HashBucket* get_bucket(u32);
  64. [[nodiscard]] u32 node_pointer(u32 node_number) const { return m_nodes[node_number]; }
  65. [[nodiscard]] u32 first_node_pointer() const { return m_nodes[0]; }
  66. [[nodiscard]] size_t nodes() const { return m_nodes.size(); }
  67. void list_hash();
  68. private:
  69. HashIndex(Serializer&, NonnullRefPtr<TupleDescriptor> const&, u32);
  70. void expand();
  71. void write_directory_to_write_ahead_log();
  72. HashBucket* append_bucket(u32 index, u32 local_depth, u32 pointer);
  73. HashBucket* get_bucket_for_insert(Key const&);
  74. [[nodiscard]] HashBucket* get_bucket_by_index(u32 index);
  75. u32 m_global_depth { 1 };
  76. Vector<u32> m_nodes;
  77. Vector<OwnPtr<HashBucket>> m_buckets;
  78. friend HashBucket;
  79. friend HashDirectoryNode;
  80. };
  81. class HashDirectoryNode : public IndexNode {
  82. public:
  83. HashDirectoryNode(HashIndex&, u32, size_t);
  84. HashDirectoryNode(HashIndex&, u32);
  85. HashDirectoryNode(HashDirectoryNode const& other) = default;
  86. void deserialize(Serializer&);
  87. void serialize(Serializer&) const;
  88. [[nodiscard]] u32 number_of_pointers() const { return min(max_pointers_in_node(), m_hash_index.size() - m_offset); }
  89. [[nodiscard]] bool is_last() const { return m_is_last; }
  90. static constexpr size_t max_pointers_in_node() { return (BLOCKSIZE - 3 * sizeof(u32)) / (2 * sizeof(u32)); }
  91. private:
  92. HashIndex& m_hash_index;
  93. size_t m_node_number { 0 };
  94. size_t m_offset { 0 };
  95. bool m_is_last { false };
  96. };
  97. class HashIndexIterator {
  98. public:
  99. [[nodiscard]] bool is_end() const { return !m_current; }
  100. bool operator==(HashIndexIterator const& other) const;
  101. bool operator==(Key const& other) const;
  102. HashIndexIterator operator++()
  103. {
  104. *this = next();
  105. return *this;
  106. }
  107. HashIndexIterator operator++(int)
  108. {
  109. *this = next();
  110. return *this;
  111. }
  112. HashIndexIterator operator--()
  113. {
  114. *this = previous();
  115. return *this;
  116. }
  117. HashIndexIterator const operator--(int)
  118. {
  119. *this = previous();
  120. return *this;
  121. }
  122. Key const& operator*() const
  123. {
  124. VERIFY(!is_end());
  125. return (*m_current)[m_index];
  126. }
  127. Key const& operator->() const
  128. {
  129. VERIFY(!is_end());
  130. return (*m_current)[m_index];
  131. }
  132. HashIndexIterator& operator=(HashIndexIterator const&) = default;
  133. HashIndexIterator(HashIndexIterator const&) = default;
  134. private:
  135. HashIndexIterator() = default;
  136. explicit HashIndexIterator(HashBucket const*, size_t key_index = 0);
  137. static HashIndexIterator end() { return HashIndexIterator(); }
  138. [[nodiscard]] HashIndexIterator next();
  139. [[nodiscard]] HashIndexIterator previous();
  140. [[nodiscard]] Key key() const { return **this; }
  141. WeakPtr<HashBucket> m_current;
  142. size_t m_index { 0 };
  143. friend HashIndex;
  144. };
  145. }