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