/* * tests/dynamic_extension_tests.cpp * * Unit tests for Dynamic Extension Framework * * Copyright (C) 2023 Douglas Rumbaugh * Dong Xie * * All rights reserved. Published under the Modified BSD License. * */ #include #include #include #include "testing.h" #include "framework/DynamicExtension.h" #include "shard/WIRS.h" #include using namespace de; START_TEST(t_create) { auto ext_wirs = new DynamicExtension>(100, 100, 2, 1, 1, g_rng); ck_assert_ptr_nonnull(ext_wirs); ck_assert_int_eq(ext_wirs->get_record_cnt(), 0); ck_assert_int_eq(ext_wirs->get_height(), 0); delete ext_wirs; } END_TEST START_TEST(t_append) { auto ext_wirs = new DynamicExtension>(100, 100, 2, 1, 1, g_rng); uint64_t key = 0; uint32_t val = 0; for (size_t i=0; i<100; i++) { WRec r = {key, val, 1}; ck_assert_int_eq(ext_wirs->append(r, g_rng), 1); key++; val++; } ck_assert_int_eq(ext_wirs->get_height(), 0); ck_assert_int_eq(ext_wirs->get_record_cnt(), 100); delete ext_wirs; } END_TEST START_TEST(t_append_with_mem_merges) { auto ext_wirs = new DynamicExtension>(100, 100, 2, 1, 1, g_rng); uint64_t key = 0; uint32_t val = 0; for (size_t i=0; i<300; i++) { WRec r = {key, val, 1}; ck_assert_int_eq(ext_wirs->append(r, g_rng), 1); key++; val++; } ck_assert_int_eq(ext_wirs->get_record_cnt(), 300); ck_assert_int_eq(ext_wirs->get_height(), 1); delete ext_wirs; } END_TEST START_TEST(t_range_sample_memtable) { auto ext_wirs = new DynamicExtension>(100, 100, 2, 1, 1, g_rng); uint64_t key = 0; uint32_t val = 0; for (size_t i=0; i<100; i++) { WRec r = {key, val, 1}; ck_assert_int_eq(ext_wirs->append(r, g_rng), 1); key++; val++; } uint64_t lower_bound = 20; uint64_t upper_bound = 50; char *buf = (char *) std::aligned_alloc(SECTOR_SIZE, PAGE_SIZE); char *util_buf = (char *) std::aligned_alloc(SECTOR_SIZE, PAGE_SIZE); WRec sample_set[100]; ext_wirs->range_sample(sample_set, lower_bound, upper_bound, 100, g_rng); for(size_t i=0; i<100; i++) { ck_assert_int_le(sample_set[i].key, upper_bound); ck_assert_int_ge(sample_set[i].key, lower_bound); } free(buf); free(util_buf); delete ext_wirs; } END_TEST START_TEST(t_range_sample_memlevels) { auto ext_wirs = new DynamicExtension>(100, 100, 2, 1, 1, g_rng); uint64_t key = 0; uint32_t val = 0; for (size_t i=0; i<300; i++) { WRec r = {key, val, 1}; ck_assert_int_eq(ext_wirs->append(r, g_rng), 1); key++; val++; } uint64_t lower_bound = 100; uint64_t upper_bound = 250; char *buf = (char *) std::aligned_alloc(SECTOR_SIZE, PAGE_SIZE); char *util_buf = (char *) std::aligned_alloc(SECTOR_SIZE, PAGE_SIZE); WRec sample_set[100]; ext_wirs->range_sample(sample_set, lower_bound, upper_bound, 100, g_rng); for(size_t i=0; i<100; i++) { ck_assert_int_le(sample_set[i].key, upper_bound); ck_assert_int_ge(sample_set[i].key, lower_bound); } free(buf); free(util_buf); delete ext_wirs; } END_TEST START_TEST(t_range_sample_weighted) { auto ext_wirs = new DynamicExtension>(100, 100, 2, 1, 1, g_rng); size_t n = 10000; std::vector keys; uint64_t key = 1; for (size_t i=0; i< n / 2; i++) { keys.push_back(key); } // put in a quarter of the count with weight two. key = 2; for (size_t i=0; i< n / 4; i++) { keys.push_back(key); } // the remaining quarter with weight four. key = 3; for (size_t i=0; i< n / 4; i++) { keys.push_back(key); } std::random_device rd; std::mt19937 gen{rd()}; std::shuffle(keys.begin(), keys.end(), gen); for (size_t i=0; iappend(r, g_rng); } size_t k = 1000; uint64_t lower_key = 0; uint64_t upper_key = 5; WRec* buffer = new WRec[k](); char *buffer1 = (char *) std::aligned_alloc(SECTOR_SIZE, PAGE_SIZE); char *buffer2 = (char *) std::aligned_alloc(SECTOR_SIZE, PAGE_SIZE); size_t cnt[3] = {0}; for (size_t i=0; i<1000; i++) { ext_wirs->range_sample(buffer, lower_key, upper_key, k, g_rng); for (size_t j=0; j>(100, 100, 2, .01, 1, g_rng); std::set> records; std::set> to_delete; std::set> deleted; while (records.size() < reccnt) { uint64_t key = rand(); uint32_t val = rand(); if (records.find({key, val}) != records.end()) continue; records.insert({key, val}); } size_t deletes = 0; size_t cnt=0; for (auto rec : records) { WRec r = {rec.first, rec.second, 1, 0}; ck_assert_int_eq(ext_wirs->append(r, g_rng), 1); if (gsl_rng_uniform(g_rng) < 0.05 && !to_delete.empty()) { std::vector> del_vec; std::sample(to_delete.begin(), to_delete.end(), std::back_inserter(del_vec), 3, std::mt19937{std::random_device{}()}); for (size_t i=0; iappend(dr, g_rng); deletes++; to_delete.erase(del_vec[i]); deleted.insert(del_vec[i]); } } if (gsl_rng_uniform(g_rng) < 0.25 && deleted.find(rec) == deleted.end()) { to_delete.insert(rec); } ck_assert(ext_wirs->validate_tombstone_proportion()); } ck_assert(ext_wirs->validate_tombstone_proportion()); delete ext_wirs; } END_TEST DynamicExtension> *create_test_tree(size_t reccnt, size_t memlevel_cnt) { auto ext_wirs = new DynamicExtension>(1000, 1000, 2, 1, 1, g_rng); std::set records; std::set to_delete; std::set deleted; while (records.size() < reccnt) { uint64_t key = rand(); uint32_t val = rand(); if (records.find({key, val}) != records.end()) continue; records.insert({key, val}); } size_t deletes = 0; for (auto rec : records) { ck_assert_int_eq(ext_wirs->append(rec, g_rng), 1); if (gsl_rng_uniform(g_rng) < 0.05 && !to_delete.empty()) { std::vector del_vec; std::sample(to_delete.begin(), to_delete.end(), std::back_inserter(del_vec), 3, std::mt19937{std::random_device{}()}); for (size_t i=0; iappend(del_vec[i], g_rng); deletes++; to_delete.erase(del_vec[i]); deleted.insert(del_vec[i]); } } if (gsl_rng_uniform(g_rng) < 0.25 && deleted.find(rec) == deleted.end()) { to_delete.insert(rec); } } return ext_wirs; } START_TEST(t_sorted_array) { size_t reccnt = 100000; auto ext_wirs = new DynamicExtension>(100, 100, 2, 1, 1, g_rng); std::set> records; std::set> to_delete; std::set> deleted; while (records.size() < reccnt) { uint64_t key = rand(); uint32_t val = rand(); if (records.find({key, val}) != records.end()) continue; records.insert({key, val}); } size_t deletes = 0; for (auto rec : records) { WRec r = {rec.first, rec.second, 1}; ck_assert_int_eq(ext_wirs->append(r, g_rng), 1); if (gsl_rng_uniform(g_rng) < 0.05 && !to_delete.empty()) { std::vector> del_vec; std::sample(to_delete.begin(), to_delete.end(), std::back_inserter(del_vec), 3, std::mt19937{std::random_device{}()}); for (size_t i=0; iappend(dr , g_rng); deletes++; to_delete.erase(del_vec[i]); deleted.insert(del_vec[i]); } } if (gsl_rng_uniform(g_rng) < 0.25 && deleted.find(rec) == deleted.end()) { to_delete.insert(rec); } } auto flat = ext_wirs->create_ssi(); ck_assert_int_eq(flat->get_record_count(), reccnt - deletes); uint64_t prev_key = 0; for (size_t i=0; iget_record_count(); i++) { auto k = flat->get_record_at(i)->key; ck_assert_int_ge(k, prev_key); prev_key = k; } delete flat; delete ext_wirs; } END_TEST Suite *unit_testing() { Suite *unit = suite_create("de::DynamicExtension Unit Testing"); TCase *create = tcase_create("de::DynamicExtension::constructor Testing"); tcase_add_test(create, t_create); suite_add_tcase(unit, create); TCase *append = tcase_create("de::DynamicExtension::append Testing"); tcase_add_test(append, t_append); tcase_add_test(append, t_append_with_mem_merges); suite_add_tcase(unit, append); TCase *sampling = tcase_create("de::DynamicExtension::range_sample Testing"); tcase_add_test(sampling, t_range_sample_memtable); tcase_add_test(sampling, t_range_sample_memlevels); tcase_add_test(sampling, t_range_sample_weighted); suite_add_tcase(unit, sampling); TCase *ts = tcase_create("de::DynamicExtension::tombstone_compaction Testing"); tcase_add_test(ts, t_tombstone_merging_01); tcase_set_timeout(ts, 500); suite_add_tcase(unit, ts); TCase *flat = tcase_create("de::DynamicExtension::get_flattened_wirs_run Testing"); tcase_add_test(flat, t_sorted_array); tcase_set_timeout(flat, 500); suite_add_tcase(unit, flat); return unit; } int run_unit_tests() { int failed = 0; Suite *unit = unit_testing(); SRunner *unit_runner = srunner_create(unit); srunner_run_all(unit_runner, CK_NORMAL); failed = srunner_ntests_failed(unit_runner); srunner_free(unit_runner); return failed; } int main() { int unit_failed = run_unit_tests(); return (unit_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; }