diff --git a/src/lib/core/random.c b/src/lib/core/random.c index 994230c540afde7c94bf196c65b6c4a99ed8e135..621f462181610a7edc68e947a7d86966edc93c12 100644 --- a/src/lib/core/random.c +++ b/src/lib/core/random.c @@ -148,6 +148,15 @@ xoshiro_random(void) return result; } +void +xoshiro_srand(uint64_t *seed) +{ + state[0] = seed[0]; + state[1] = seed[1]; + state[2] = seed[2]; + state[3] = seed[3]; +} + const char * xoshiro_state_str(void) { diff --git a/src/lib/core/random.h b/src/lib/core/random.h index 9108eab58cd97ae7324ac88e61226e33383e41fe..66ef70f2f225bb8fb30c5396b3fab142f7f621bf 100644 --- a/src/lib/core/random.h +++ b/src/lib/core/random.h @@ -60,6 +60,14 @@ real_random(void); uint64_t xoshiro_random(void); +/** + * Sets the `seed` for a new sequence of pseudo-random integers to be returned + * by xoshiro_random(). These sequences are repeatable by calling xoshiro_srand + * with the same seed value. + */ +void +xoshiro_srand(uint64_t *seed); + const char * xoshiro_state_str(void); diff --git a/src/lib/salad/light.h b/src/lib/salad/light.h index 61c800aaf21650010efb08e2d90fde669d75f35b..94f53d2e2184512f4c3015d19ead9f5c254d6ec1 100644 --- a/src/lib/salad/light.h +++ b/src/lib/salad/light.h @@ -845,6 +845,15 @@ LIGHT(grow)(struct LIGHT(common) *ht) { assert(!matras_is_read_view_created(ht->view)); assert(ht->empty_slot == LIGHT(end)); + /* + * The number UINT32_MAX has a special meaning (see LIGHT(end)), hence + * it can not be used as a record identifier. Given that the table is + * enlarged by 8 records (see LIGHT_GROW_INCREMENT), the maximum table + * size is limited by (2^32)-8 records. + */ + if ((size_t)ht->table_size + LIGHT_GROW_INCREMENT >= UINT32_MAX) + return -1; + uint32_t new_slot; struct LIGHT(record) *new_record = (struct LIGHT(record) *) matras_alloc_range(ht->mtable, &new_slot, LIGHT_GROW_INCREMENT); diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 03e3a6d9f3683655d88b359524d4d7e6a5d7fc88..27b52768e203b77f5252ef2d3c2f0942acc1a63a 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -161,8 +161,8 @@ create_unit_test(PREFIX rtree_multidim LIBRARIES salad small ) create_unit_test(PREFIX light - SOURCES light.cc - LIBRARIES small + SOURCES light.cc core_test_utils.c + LIBRARIES core small ) create_unit_test(PREFIX light_view SOURCES light_view.c diff --git a/test/unit/light.cc b/test/unit/light.cc index a0d829b27579ac5027cd3c2a92e374376e45ed19..521c6cf1e2db235571c4057d1472c7d5c66ab44c 100644 --- a/test/unit/light.cc +++ b/test/unit/light.cc @@ -4,6 +4,7 @@ #include <inttypes.h> #include <vector> #include <time.h> +#include <core/random.h> #include "unit.h" @@ -350,16 +351,72 @@ slot_in_big_table_test() footer(); } +/** + * Insert nearly 2^32 records into the hash table. + */ +static void +max_capacity_test() +{ + /* + * XXX: The test is disabled, because it requires 64 GB of RAM. + */ + return; + + header(); + + /* The maximum number of records that can be stored in the table. */ + const size_t data_count = (size_t)UINT32_MAX + 1 - LIGHT_GROW_INCREMENT; + + struct light_core ht; + light_create(&ht, 0, light_extent_size, my_light_alloc, my_light_free, + &extents_count, NULL); + + uint64_t seed[4]; + random_bytes((char *)seed, sizeof(seed)); + + /* Test light_insert(). */ + xoshiro_srand(seed); + for (size_t i = 0; i < data_count; i++) { + hash_value_t val = xoshiro_random(); + hash_t id = light_insert(&ht, hash(val), val); + fail_if(id == light_end); + if ((i & 0xfffff) == 0) + printf("%f%%\n", i * 100.0 / data_count); + } + /* Try to exceed the maximum capacity. */ + hash_value_t val = xoshiro_random(); + hash_t id = light_insert(&ht, hash(val), val); + fail_if(id != light_end); + + /* Test light_find(). */ + xoshiro_srand(seed); + for (size_t i = 0; i < data_count; i++) { + hash_value_t val = xoshiro_random(); + hash_t id = light_find(&ht, hash(val), val); + fail_if(id == light_end); + if ((i & 0xfffff) == 0) + printf("%f%%\n", i * 100.0 / data_count); + } + + light_destroy(&ht); + + footer(); +} + int main(int, const char**) { - srand(time(0)); + random_init(); + simple_test(); collision_test(); iterator_test(); iterator_freeze_check(); slot_in_big_table_test(); + max_capacity_test(); if (extents_count != 0) fail("memory leak!", "true"); + + random_free(); }