HashIndex.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. /*
  2. * Copyright (c) 2021, Jan de Visser <jan@de-visser.net>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibSQL/HashIndex.h>
  7. #include <LibSQL/Heap.h>
  8. #include <LibSQL/Key.h>
  9. #include <LibSQL/Serialize.h>
  10. namespace SQL {
  11. HashDirectoryNode::HashDirectoryNode(HashIndex& index, u32 node_number, size_t offset)
  12. : IndexNode(index.node_pointer(node_number))
  13. , m_hash_index(index)
  14. , m_node_number(node_number)
  15. , m_offset(offset)
  16. {
  17. }
  18. HashDirectoryNode::HashDirectoryNode(HashIndex& index, u32 pointer, ByteBuffer& buffer)
  19. : IndexNode(pointer)
  20. , m_hash_index(index)
  21. {
  22. dbgln_if(SQL_DEBUG, "Deserializing Hash Directory Node");
  23. size_t offset = 0;
  24. deserialize_from<u32>(buffer, offset, index.m_global_depth);
  25. u32 size;
  26. deserialize_from<u32>(buffer, offset, size);
  27. dbgln_if(SQL_DEBUG, "Global Depth {}, #Bucket pointers {}", index.global_depth(), size);
  28. u32 next_node;
  29. deserialize_from<u32>(buffer, offset, next_node);
  30. if (next_node) {
  31. dbgln_if(SQL_DEBUG, "Next node {}", next_node);
  32. m_hash_index.m_nodes.append(next_node);
  33. } else {
  34. dbgln_if(SQL_DEBUG, "This is the last directory node");
  35. m_is_last = true;
  36. }
  37. for (auto ix = 0u; ix < size; ix++) {
  38. u32 bucket_pointer;
  39. deserialize_from(buffer, offset, bucket_pointer);
  40. u32 local_depth;
  41. deserialize_from(buffer, offset, local_depth);
  42. dbgln_if(SQL_DEBUG, "Bucket pointer {} local depth {}", bucket_pointer, local_depth);
  43. index.append_bucket(ix, local_depth, bucket_pointer);
  44. }
  45. }
  46. void HashDirectoryNode::serialize(ByteBuffer& buffer) const
  47. {
  48. dbgln_if(SQL_DEBUG, "Serializing directory node #{}. Offset {}", m_node_number, m_offset);
  49. serialize_to(buffer, m_hash_index.global_depth());
  50. serialize_to(buffer, number_of_pointers());
  51. dbgln_if(SQL_DEBUG, "Global depth {}, #bucket pointers {}", m_hash_index.global_depth(), number_of_pointers());
  52. u32 next_node;
  53. if (m_node_number < (m_hash_index.m_nodes.size() - 1)) {
  54. next_node = m_hash_index.m_nodes[m_node_number + 1];
  55. dbgln_if(SQL_DEBUG, "Next directory node pointer {}", next_node);
  56. } else {
  57. next_node = 0u;
  58. dbgln_if(SQL_DEBUG, "This is the last directory node");
  59. }
  60. serialize_to(buffer, next_node);
  61. for (auto ix = 0u; ix < number_of_pointers(); ix++) {
  62. auto& bucket = m_hash_index.m_buckets[m_offset + ix];
  63. dbgln_if(SQL_DEBUG, "Bucket pointer {} local depth {}", bucket->pointer(), bucket->local_depth());
  64. serialize_to(buffer, bucket->pointer());
  65. serialize_to(buffer, bucket->local_depth());
  66. }
  67. }
  68. HashBucket::HashBucket(HashIndex& hash_index, u32 index, u32 local_depth, u32 pointer)
  69. : IndexNode(pointer)
  70. , m_hash_index(hash_index)
  71. , m_local_depth(local_depth)
  72. , m_index(index)
  73. {
  74. }
  75. void HashBucket::serialize(ByteBuffer& buffer) const
  76. {
  77. dbgln_if(SQL_DEBUG, "Serializing bucket: pointer {}, index #{}, local depth {} size {}",
  78. pointer(), index(), local_depth(), size());
  79. dbgln_if(SQL_DEBUG, "key_length: {} max_entries: {}", m_hash_index.descriptor()->data_length(), max_entries_in_bucket());
  80. serialize_to(buffer, local_depth());
  81. serialize_to(buffer, size());
  82. dbgln_if(SQL_DEBUG, "buffer size after prolog {}", buffer.size());
  83. for (auto& key : m_entries) {
  84. key.serialize(buffer);
  85. dbgln_if(SQL_DEBUG, "Key {} buffer size {}", key.to_string(), buffer.size());
  86. }
  87. }
  88. void HashBucket::inflate()
  89. {
  90. if (m_inflated || !pointer())
  91. return;
  92. dbgln_if(SQL_DEBUG, "Inflating Hash Bucket {}", pointer());
  93. auto buffer = m_hash_index.read_block(pointer());
  94. size_t offset = 0;
  95. deserialize_from(buffer, offset, m_local_depth);
  96. dbgln_if(SQL_DEBUG, "Bucket Local Depth {}", m_local_depth);
  97. u32 size;
  98. deserialize_from(buffer, offset, size);
  99. dbgln_if(SQL_DEBUG, "Bucket has {} keys", size);
  100. for (auto ix = 0u; ix < size; ix++) {
  101. Key key(m_hash_index.descriptor(), buffer, offset);
  102. dbgln_if(SQL_DEBUG, "Key {}: {}", ix, key.to_string());
  103. m_entries.append(key);
  104. }
  105. m_inflated = true;
  106. }
  107. size_t HashBucket::max_entries_in_bucket() const
  108. {
  109. auto key_size = m_hash_index.descriptor()->data_length() + sizeof(u32);
  110. return (BLOCKSIZE - 2 * sizeof(u32)) / key_size;
  111. }
  112. Optional<u32> HashBucket::get(Key& key)
  113. {
  114. auto optional_index = find_key_in_bucket(key);
  115. if (optional_index.has_value()) {
  116. auto& k = m_entries[optional_index.value()];
  117. key.set_pointer(k.pointer());
  118. return k.pointer();
  119. }
  120. return {};
  121. }
  122. bool HashBucket::insert(Key const& key)
  123. {
  124. inflate();
  125. if (find_key_in_bucket(key).has_value()) {
  126. return false;
  127. }
  128. if (size() >= max_entries_in_bucket()) {
  129. return false;
  130. }
  131. m_entries.append(key);
  132. m_hash_index.add_to_write_ahead_log(this);
  133. return true;
  134. }
  135. Optional<size_t> HashBucket::find_key_in_bucket(Key const& key)
  136. {
  137. for (auto ix = 0u; ix < size(); ix++) {
  138. auto& k = entries()[ix];
  139. if (k == key) {
  140. return ix;
  141. }
  142. }
  143. return {};
  144. }
  145. HashBucket const* HashBucket::next_bucket()
  146. {
  147. for (auto ix = m_index + 1; ix < m_hash_index.size(); ix++) {
  148. auto bucket = m_hash_index.get_bucket_by_index(ix);
  149. bucket->inflate();
  150. if (bucket->size())
  151. return bucket;
  152. }
  153. return nullptr;
  154. }
  155. HashBucket const* HashBucket::previous_bucket()
  156. {
  157. for (auto ix = m_index - 1; ix > 0; ix--) {
  158. auto bucket = m_hash_index.get_bucket_by_index(ix);
  159. if (bucket->pointer())
  160. return bucket;
  161. }
  162. return nullptr;
  163. }
  164. Key const& HashBucket::operator[](size_t ix)
  165. {
  166. inflate();
  167. VERIFY(ix < size());
  168. return m_entries[ix];
  169. }
  170. void HashBucket::list_bucket()
  171. {
  172. warnln("Bucket #{} size {} local depth {} pointer {}{}",
  173. index(), size(), local_depth(), pointer(), (pointer() ? "" : " (VIRTUAL)"));
  174. for (auto& key : entries()) {
  175. warnln(" {} hash {}", key.to_string(), key.hash());
  176. }
  177. }
  178. HashIndex::HashIndex(Heap& heap, NonnullRefPtr<TupleDescriptor> const& descriptor, u32 first_node)
  179. : Index(heap, descriptor, true, first_node)
  180. , m_nodes()
  181. , m_buckets()
  182. {
  183. if (!first_node) {
  184. set_pointer(new_record_pointer());
  185. }
  186. if (this->heap().has_block(first_node)) {
  187. u32 pointer = first_node;
  188. do {
  189. VERIFY(this->heap().has_block(pointer));
  190. auto buffer = read_block(pointer);
  191. auto node = HashDirectoryNode(*this, pointer, buffer);
  192. if (node.is_last())
  193. break;
  194. pointer = m_nodes.last(); // FIXME Ugly
  195. } while (pointer);
  196. } else {
  197. auto bucket = append_bucket(0u, 1u, new_record_pointer());
  198. bucket->m_inflated = true;
  199. add_to_write_ahead_log(bucket);
  200. bucket = append_bucket(1u, 1u, new_record_pointer());
  201. bucket->m_inflated = true;
  202. add_to_write_ahead_log(bucket);
  203. m_nodes.append(first_node);
  204. write_directory_to_write_ahead_log();
  205. }
  206. }
  207. HashBucket* HashIndex::get_bucket(u32 index)
  208. {
  209. VERIFY(index < m_buckets.size());
  210. auto divisor = size() / 2;
  211. while (!m_buckets[index]->pointer()) {
  212. VERIFY(divisor > 1);
  213. index = index % divisor;
  214. divisor /= 2;
  215. }
  216. auto& bucket = m_buckets[index];
  217. return bucket;
  218. }
  219. HashBucket* HashIndex::get_bucket_for_insert(Key const& key)
  220. {
  221. auto key_hash = key.hash();
  222. do {
  223. auto bucket = get_bucket(key_hash % size());
  224. if (bucket->size() < bucket->max_entries_in_bucket()) {
  225. return bucket;
  226. }
  227. // We previously doubled the directory but the target bucket is
  228. // still at an older depth. Create new buckets at the current global
  229. // depth and allocate the contents of the existing buckets to the
  230. // newly created ones:
  231. while (bucket->local_depth() < global_depth()) {
  232. auto base_index = bucket->index();
  233. auto step = 1 << (global_depth() - bucket->local_depth());
  234. for (auto ix = base_index + step; ix < size(); ix += step) {
  235. auto& sub_bucket = m_buckets[ix];
  236. sub_bucket->set_local_depth(bucket->local_depth() + 1);
  237. for (auto entry_index = (int)bucket->m_entries.size() - 1; entry_index >= 0; entry_index--) {
  238. if (bucket->m_entries[entry_index].hash() % size() == ix) {
  239. if (!sub_bucket->pointer()) {
  240. sub_bucket->set_pointer(new_record_pointer());
  241. }
  242. sub_bucket->insert(bucket->m_entries.take(entry_index));
  243. }
  244. }
  245. if (m_buckets[ix]->pointer())
  246. add_to_write_ahead_log(m_buckets[ix]);
  247. }
  248. bucket->set_local_depth(bucket->local_depth() + 1);
  249. add_to_write_ahead_log(bucket);
  250. write_directory_to_write_ahead_log();
  251. auto bucket_after_redistribution = get_bucket(key_hash % size());
  252. if (bucket_after_redistribution->size() < bucket_after_redistribution->max_entries_in_bucket()) {
  253. return bucket_after_redistribution;
  254. }
  255. }
  256. expand();
  257. } while (true);
  258. }
  259. void HashIndex::expand()
  260. {
  261. auto sz = size();
  262. for (auto i = 0u; i < sz; i++) {
  263. auto bucket = get_bucket(i);
  264. bucket = append_bucket(sz + i, bucket->local_depth(), 0u);
  265. bucket->m_inflated = true;
  266. }
  267. m_global_depth++;
  268. write_directory_to_write_ahead_log();
  269. }
  270. void HashIndex::write_directory_to_write_ahead_log()
  271. {
  272. auto num_nodes_required = (size() / HashDirectoryNode::max_pointers_in_node()) + 1;
  273. while (m_nodes.size() < num_nodes_required)
  274. m_nodes.append(new_record_pointer());
  275. size_t offset = 0u;
  276. size_t num_node = 0u;
  277. while (offset < size()) {
  278. HashDirectoryNode node(*this, num_node, offset);
  279. add_to_write_ahead_log(node.as_index_node());
  280. offset += node.number_of_pointers();
  281. }
  282. }
  283. HashBucket* HashIndex::append_bucket(u32 index, u32 local_depth, u32 pointer)
  284. {
  285. m_buckets.append(make<HashBucket>(*this, index, local_depth, pointer));
  286. return m_buckets.last();
  287. }
  288. HashBucket* HashIndex::get_bucket_by_index(u32 index)
  289. {
  290. if (index >= size())
  291. return nullptr;
  292. return m_buckets[index];
  293. }
  294. Optional<u32> HashIndex::get(Key& key)
  295. {
  296. auto hash = key.hash();
  297. auto bucket_index = hash % size();
  298. auto bucket = get_bucket(bucket_index);
  299. return bucket->get(key);
  300. }
  301. bool HashIndex::insert(Key const& key)
  302. {
  303. auto bucket = get_bucket_for_insert(key);
  304. bucket->insert(key);
  305. return true;
  306. }
  307. HashIndexIterator HashIndex::begin()
  308. {
  309. return HashIndexIterator(get_bucket(0));
  310. }
  311. HashIndexIterator HashIndex::end()
  312. {
  313. return HashIndexIterator::end();
  314. }
  315. HashIndexIterator HashIndex::find(Key const& key)
  316. {
  317. auto hash = key.hash();
  318. auto bucket_index = hash % size();
  319. auto bucket = get_bucket(bucket_index);
  320. auto optional_index = bucket->find_key_in_bucket(key);
  321. if (!optional_index.has_value())
  322. return end();
  323. return HashIndexIterator(bucket, optional_index.value());
  324. }
  325. void HashIndex::list_hash()
  326. {
  327. warnln("Number of buckets: {} (Global depth {})", size(), global_depth());
  328. warn("Directory pointer(s): ");
  329. for (auto ptr : m_nodes) {
  330. warn("{}, ", ptr);
  331. }
  332. warnln();
  333. bool first_bucket = true;
  334. for (auto& bucket : m_buckets) {
  335. if (first_bucket) {
  336. warnln("Max. keys in bucket {}", bucket->max_entries_in_bucket());
  337. first_bucket = false;
  338. }
  339. bucket->list_bucket();
  340. }
  341. }
  342. HashIndexIterator::HashIndexIterator(HashBucket const* bucket, size_t index)
  343. : m_current(bucket)
  344. , m_index(index)
  345. {
  346. VERIFY(!m_current || !index || (index < m_current->size()));
  347. while (m_current && (m_current->size() == 0)) {
  348. m_current = m_current->next_bucket();
  349. m_index = 0;
  350. }
  351. }
  352. HashIndexIterator HashIndexIterator::next()
  353. {
  354. if (is_end())
  355. return *this;
  356. if (m_index < (m_current->size() - 1))
  357. return HashIndexIterator(m_current.ptr(), m_index + 1);
  358. return HashIndexIterator(m_current->next_bucket());
  359. }
  360. HashIndexIterator HashIndexIterator::previous()
  361. {
  362. TODO();
  363. }
  364. bool HashIndexIterator::operator==(HashIndexIterator const& other) const
  365. {
  366. if (is_end())
  367. return other.is_end();
  368. if (other.is_end())
  369. return false;
  370. VERIFY(&other.m_current->hash_index() == &m_current->hash_index());
  371. return (m_current.ptr() == other.m_current.ptr()) && (m_index == other.m_index);
  372. }
  373. bool HashIndexIterator::operator==(Key const& other) const
  374. {
  375. if (is_end())
  376. return false;
  377. if (other.is_null())
  378. return false;
  379. return (**this).compare(other);
  380. }
  381. }