HashIndex.cpp 14 KB

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