TestSqlHashIndex.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  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/Meta.h>
  9. #include <LibSQL/Tuple.h>
  10. #include <LibSQL/Value.h>
  11. #include <LibTest/TestCase.h>
  12. #include <unistd.h>
  13. constexpr static int keys[] = {
  14. 39,
  15. 87,
  16. 77,
  17. 42,
  18. 98,
  19. 40,
  20. 53,
  21. 8,
  22. 37,
  23. 12,
  24. 90,
  25. 72,
  26. 73,
  27. 11,
  28. 88,
  29. 22,
  30. 10,
  31. 82,
  32. 25,
  33. 61,
  34. 97,
  35. 18,
  36. 60,
  37. 68,
  38. 21,
  39. 3,
  40. 58,
  41. 29,
  42. 13,
  43. 17,
  44. 89,
  45. 81,
  46. 16,
  47. 64,
  48. 5,
  49. 41,
  50. 36,
  51. 91,
  52. 38,
  53. 24,
  54. 32,
  55. 50,
  56. 34,
  57. 94,
  58. 49,
  59. 47,
  60. 1,
  61. 6,
  62. 44,
  63. 76,
  64. };
  65. constexpr static u32 pointers[] = {
  66. 92,
  67. 4,
  68. 50,
  69. 47,
  70. 68,
  71. 73,
  72. 24,
  73. 28,
  74. 50,
  75. 93,
  76. 60,
  77. 36,
  78. 92,
  79. 72,
  80. 53,
  81. 26,
  82. 91,
  83. 84,
  84. 25,
  85. 43,
  86. 88,
  87. 12,
  88. 62,
  89. 35,
  90. 96,
  91. 27,
  92. 96,
  93. 27,
  94. 99,
  95. 30,
  96. 21,
  97. 89,
  98. 54,
  99. 60,
  100. 37,
  101. 68,
  102. 35,
  103. 55,
  104. 80,
  105. 2,
  106. 33,
  107. 26,
  108. 93,
  109. 70,
  110. 45,
  111. 44,
  112. 3,
  113. 66,
  114. 75,
  115. 4,
  116. };
  117. NonnullRefPtr<SQL::HashIndex> setup_hash_index(SQL::Serializer&);
  118. void insert_and_get_to_and_from_hash_index(int);
  119. void insert_into_and_scan_hash_index(int);
  120. NonnullRefPtr<SQL::HashIndex> setup_hash_index(SQL::Serializer& serializer)
  121. {
  122. NonnullRefPtr<SQL::TupleDescriptor> tuple_descriptor = adopt_ref(*new SQL::TupleDescriptor);
  123. tuple_descriptor->append({ "key_value", SQL::SQLType::Integer, SQL::Order::Ascending });
  124. tuple_descriptor->append({ "text_value", SQL::SQLType::Text, SQL::Order::Ascending });
  125. auto directory_pointer = serializer.heap().user_value(0);
  126. if (!directory_pointer) {
  127. directory_pointer = serializer.heap().new_record_pointer();
  128. serializer.heap().set_user_value(0, directory_pointer);
  129. }
  130. auto hash_index = SQL::HashIndex::construct(serializer, tuple_descriptor, directory_pointer);
  131. return hash_index;
  132. }
  133. void insert_and_get_to_and_from_hash_index(int num_keys)
  134. {
  135. ScopeGuard guard([]() { unlink("/tmp/test.db"); });
  136. {
  137. auto heap = SQL::Heap::construct("/tmp/test.db");
  138. SQL::Serializer serializer(heap);
  139. auto hash_index = setup_hash_index(serializer);
  140. for (auto ix = 0; ix < num_keys; ix++) {
  141. SQL::Key k(hash_index->descriptor());
  142. k[0] = keys[ix];
  143. k[1] = String::formatted("The key value is {} and the pointer is {}", keys[ix], pointers[ix]);
  144. k.set_pointer(pointers[ix]);
  145. hash_index->insert(k);
  146. }
  147. #ifdef LIST_HASH_INDEX
  148. hash_index->list_hash();
  149. #endif
  150. }
  151. {
  152. auto heap = SQL::Heap::construct("/tmp/test.db");
  153. SQL::Serializer serializer(heap);
  154. auto hash_index = setup_hash_index(serializer);
  155. for (auto ix = 0; ix < num_keys; ix++) {
  156. SQL::Key k(hash_index->descriptor());
  157. k[0] = keys[ix];
  158. k[1] = String::formatted("The key value is {} and the pointer is {}", keys[ix], pointers[ix]);
  159. auto pointer_opt = hash_index->get(k);
  160. VERIFY(pointer_opt.has_value());
  161. EXPECT_EQ(pointer_opt.value(), pointers[ix]);
  162. }
  163. }
  164. }
  165. TEST_CASE(hash_index_one_key)
  166. {
  167. insert_and_get_to_and_from_hash_index(1);
  168. }
  169. TEST_CASE(hash_index_four_keys)
  170. {
  171. insert_and_get_to_and_from_hash_index(4);
  172. }
  173. TEST_CASE(hash_index_five_keys)
  174. {
  175. insert_and_get_to_and_from_hash_index(5);
  176. }
  177. TEST_CASE(hash_index_10_keys)
  178. {
  179. insert_and_get_to_and_from_hash_index(10);
  180. }
  181. TEST_CASE(hash_index_13_keys)
  182. {
  183. insert_and_get_to_and_from_hash_index(13);
  184. }
  185. TEST_CASE(hash_index_20_keys)
  186. {
  187. insert_and_get_to_and_from_hash_index(20);
  188. }
  189. TEST_CASE(hash_index_25_keys)
  190. {
  191. insert_and_get_to_and_from_hash_index(25);
  192. }
  193. TEST_CASE(hash_index_30_keys)
  194. {
  195. insert_and_get_to_and_from_hash_index(30);
  196. }
  197. TEST_CASE(hash_index_35_keys)
  198. {
  199. insert_and_get_to_and_from_hash_index(35);
  200. }
  201. TEST_CASE(hash_index_40_keys)
  202. {
  203. insert_and_get_to_and_from_hash_index(40);
  204. }
  205. TEST_CASE(hash_index_45_keys)
  206. {
  207. insert_and_get_to_and_from_hash_index(45);
  208. }
  209. TEST_CASE(hash_index_50_keys)
  210. {
  211. insert_and_get_to_and_from_hash_index(50);
  212. }
  213. void insert_into_and_scan_hash_index(int num_keys)
  214. {
  215. ScopeGuard guard([]() { unlink("/tmp/test.db"); });
  216. {
  217. auto heap = SQL::Heap::construct("/tmp/test.db");
  218. SQL::Serializer serializer(heap);
  219. auto hash_index = setup_hash_index(serializer);
  220. for (auto ix = 0; ix < num_keys; ix++) {
  221. SQL::Key k(hash_index->descriptor());
  222. k[0] = keys[ix];
  223. k[1] = String::formatted("The key value is {} and the pointer is {}", keys[ix], pointers[ix]);
  224. k.set_pointer(pointers[ix]);
  225. hash_index->insert(k);
  226. }
  227. #ifdef LIST_HASH_INDEX
  228. hash_index->list_hash();
  229. #endif
  230. }
  231. {
  232. auto heap = SQL::Heap::construct("/tmp/test.db");
  233. SQL::Serializer serializer(heap);
  234. auto hash_index = setup_hash_index(serializer);
  235. Vector<bool> found;
  236. for (auto ix = 0; ix < num_keys; ix++) {
  237. found.append(false);
  238. }
  239. int count = 0;
  240. for (auto iter = hash_index->begin(); !iter.is_end(); iter++, count++) {
  241. auto key = (*iter);
  242. auto key_value = (int)key[0];
  243. for (auto ix = 0; ix < num_keys; ix++) {
  244. if (keys[ix] == key_value) {
  245. EXPECT_EQ(key.pointer(), pointers[ix]);
  246. if (found[ix])
  247. FAIL(String::formatted("Key {}, index {} already found previously", key_value, ix));
  248. found[ix] = true;
  249. break;
  250. }
  251. }
  252. }
  253. #ifdef LIST_HASH_INDEX
  254. hash_index->list_hash();
  255. #endif
  256. EXPECT_EQ(count, num_keys);
  257. for (auto ix = 0; ix < num_keys; ix++) {
  258. if (!found[ix])
  259. FAIL(String::formatted("Key {}, index {} not found", keys[ix], ix));
  260. }
  261. }
  262. }
  263. TEST_CASE(hash_index_scan_one_key)
  264. {
  265. insert_into_and_scan_hash_index(1);
  266. }
  267. TEST_CASE(hash_index_scan_four_keys)
  268. {
  269. insert_into_and_scan_hash_index(4);
  270. }
  271. TEST_CASE(hash_index_scan_five_keys)
  272. {
  273. insert_into_and_scan_hash_index(5);
  274. }
  275. TEST_CASE(hash_index_scan_10_keys)
  276. {
  277. insert_into_and_scan_hash_index(10);
  278. }
  279. TEST_CASE(hash_index_scan_15_keys)
  280. {
  281. insert_into_and_scan_hash_index(15);
  282. }
  283. TEST_CASE(hash_index_scan_20_keys)
  284. {
  285. insert_into_and_scan_hash_index(20);
  286. }
  287. TEST_CASE(hash_index_scan_30_keys)
  288. {
  289. insert_into_and_scan_hash_index(30);
  290. }
  291. TEST_CASE(hash_index_scan_40_keys)
  292. {
  293. insert_into_and_scan_hash_index(40);
  294. }
  295. TEST_CASE(hash_index_scan_50_keys)
  296. {
  297. insert_into_and_scan_hash_index(50);
  298. }