diff --git a/examples/splinterdb_custom_ipv4_addr_sortcmp_example.c b/examples/splinterdb_custom_ipv4_addr_sortcmp_example.c index 04e42b34..6a5113f0 100644 --- a/examples/splinterdb_custom_ipv4_addr_sortcmp_example.c +++ b/examples/splinterdb_custom_ipv4_addr_sortcmp_example.c @@ -345,7 +345,8 @@ do_iterate_from(splinterdb *spl_handle, const char *from_key) // Initialize start key if initial search key was provided. slice start_key = (from_key ? slice_create(strlen(from_key), from_key) : NULL_SLICE); - int rc = splinterdb_iterator_init(spl_handle, &it, start_key); + int rc = splinterdb_iterator_init( + spl_handle, &it, start_key, greater_than_or_equal); int i = 0; diff --git a/examples/splinterdb_intro_example.c b/examples/splinterdb_intro_example.c index 6438c0a5..c75cdec8 100644 --- a/examples/splinterdb_intro_example.c +++ b/examples/splinterdb_intro_example.c @@ -112,7 +112,8 @@ main() " returning keys in lexicographic sort order:\n"); splinterdb_iterator *it = NULL; - rc = splinterdb_iterator_init(spl_handle, &it, NULL_SLICE); + rc = splinterdb_iterator_init( + spl_handle, &it, NULL_SLICE, greater_than_or_equal); int i = 0; for (; splinterdb_iterator_valid(it); splinterdb_iterator_next(it)) { diff --git a/examples/splinterdb_iterators_example.c b/examples/splinterdb_iterators_example.c index cfb767ec..1462c510 100644 --- a/examples/splinterdb_iterators_example.c +++ b/examples/splinterdb_iterators_example.c @@ -145,7 +145,8 @@ do_iterate_from(splinterdb *spl_handle, const char *from_key) // Initialize start key if initial search key was provided. slice start_key = (from_key ? slice_create(strlen(from_key), from_key) : NULL_SLICE); - int rc = splinterdb_iterator_init(spl_handle, &it, start_key); + int rc = splinterdb_iterator_init( + spl_handle, &it, start_key, greater_than_or_equal); int i = 0; diff --git a/include/splinterdb/splinterdb.h b/include/splinterdb/splinterdb.h index 03bee60d..f6fcb830 100644 --- a/include/splinterdb/splinterdb.h +++ b/include/splinterdb/splinterdb.h @@ -300,8 +300,8 @@ Known issue: a live iterator may block inserts and deletes from the same thread. Sample application code: splinterdb_iterator* it; - int rc = splinterdb_iterator_init(kvs, &it, NULL_SLICE); - if (rc != 0) { ... handle error ... } + int rc = splinterdb_iterator_init(kvs, &it, NULL_SLICE, +greater_than_or_equal); if (rc != 0) { ... handle error ... } slice key, value; @@ -321,13 +321,26 @@ Sample application code: typedef struct splinterdb_iterator splinterdb_iterator; +// should the iterator start at the first key that is <, <=, >, or >= than the +// start_key? +typedef enum comparison { + less_than, + less_than_or_equal, + greater_than, + greater_than_or_equal, +} comparison; + + // Initialize a new iterator, starting at the given key // -// If start_key is NULL_SLICE, the iterator will start before the minimum key +// If start_key is NULL_SLICE, the iterator will start at: +// - greater_than_or_equal: the minimum key +// - less_than_or_equal: the maximum key int -splinterdb_iterator_init(splinterdb *kvs, // IN - splinterdb_iterator **iter, // OUT - slice start_key // IN +splinterdb_iterator_init(splinterdb *kvs, // IN + splinterdb_iterator **iter, // OUT + slice start_key, // IN + comparison start_type // IN ); // Deinitialize an iterator diff --git a/src/iterator.h b/src/iterator.h index 5c554605..60903787 100644 --- a/src/iterator.h +++ b/src/iterator.h @@ -3,19 +3,12 @@ #pragma once +#include "splinterdb/splinterdb.h" #include "data_internal.h" #include "vector.h" typedef struct iterator iterator; -// for seek -typedef enum comparison { - less_than, - less_than_or_equal, - greater_than, - greater_than_or_equal, -} comparison; - typedef void (*iterator_curr_fn)(iterator *itor, key *curr_key, message *msg); typedef bool32 (*iterator_bound_fn)(iterator *itor); typedef platform_status (*iterator_step_fn)(iterator *itor); diff --git a/src/splinterdb.c b/src/splinterdb.c index 8567187c..8b1c6ac9 100644 --- a/src/splinterdb.c +++ b/src/splinterdb.c @@ -15,6 +15,7 @@ #include "splinterdb/splinterdb.h" #include "clockcache.h" +#include "data_internal.h" #include "rc_allocator.h" #include "core.h" #include "lookup_result.h" @@ -608,9 +609,10 @@ struct splinterdb_iterator { }; int -splinterdb_iterator_init(splinterdb *kvs, // IN - splinterdb_iterator **iter, // OUT - slice user_start_key // IN +splinterdb_iterator_init(splinterdb *kvs, // IN + splinterdb_iterator **iter, // OUT + slice user_start_key, // IN + comparison start_type // IN ) { splinterdb_iterator *it = TYPED_MALLOC(kvs->spl.heap_id, it); @@ -624,7 +626,11 @@ splinterdb_iterator_init(splinterdb *kvs, // IN key start_key; if (slice_is_null(user_start_key)) { - start_key = NEGATIVE_INFINITY_KEY; + if (start_type <= less_than_or_equal) { + start_key = POSITIVE_INFINITY_KEY; + } else { + start_key = NEGATIVE_INFINITY_KEY; + } } else { start_key = key_create_from_slice(TRUE, user_start_key); } @@ -634,7 +640,7 @@ splinterdb_iterator_init(splinterdb *kvs, // IN NEGATIVE_INFINITY_KEY, POSITIVE_INFINITY_KEY, start_key, - greater_than_or_equal, + start_type, UINT64_MAX); if (!SUCCESS(rc)) { platform_free(kvs->spl.heap_id, *iter); diff --git a/tests/unit/splinterdb_quick_test.c b/tests/unit/splinterdb_quick_test.c index a8703554..ba44eb41 100644 --- a/tests/unit/splinterdb_quick_test.c +++ b/tests/unit/splinterdb_quick_test.c @@ -453,7 +453,8 @@ CTEST2(splinterdb_quick, test_basic_iterator) splinterdb_iterator *it = NULL; - rc = splinterdb_iterator_init(data->kvsb, &it, NULL_SLICE); + rc = splinterdb_iterator_init( + data->kvsb, &it, NULL_SLICE, greater_than_or_equal); ASSERT_EQUAL(0, rc); for (; splinterdb_iterator_valid(it); splinterdb_iterator_next(it)) { @@ -475,7 +476,8 @@ CTEST2(splinterdb_quick, test_basic_iterator) CTEST2(splinterdb_quick, test_empty_iterator) { splinterdb_iterator *it = NULL; - int rc = splinterdb_iterator_init(data->kvsb, &it, NULL_SLICE); + int rc = splinterdb_iterator_init( + data->kvsb, &it, NULL_SLICE, greater_than_or_equal); ASSERT_EQUAL(0, rc); ASSERT_FALSE(splinterdb_iterator_valid(it)); @@ -506,7 +508,8 @@ CTEST2(splinterdb_quick, test_splinterdb_iterator_with_startkey) // Initialize the i'th key snprintf(key, sizeof(key), key_fmt, ictr); slice start_key = slice_create(strlen(key), key); - rc = splinterdb_iterator_init(data->kvsb, &it, start_key); + rc = splinterdb_iterator_init( + data->kvsb, &it, start_key, greater_than_or_equal); ASSERT_EQUAL(0, rc); bool32 is_valid = splinterdb_iterator_valid(it); @@ -540,7 +543,8 @@ CTEST2(splinterdb_quick, test_splinterdb_iterator_with_non_existent_startkey) char *keystring = "unknownKey"; slice start_key = slice_create(strlen(keystring), keystring); - rc = splinterdb_iterator_init(data->kvsb, &it, start_key); + rc = splinterdb_iterator_init( + data->kvsb, &it, start_key, greater_than_or_equal); // Iterator should be invalid, as lookup key is non-existent. bool32 is_valid = splinterdb_iterator_valid(it); @@ -553,7 +557,8 @@ CTEST2(splinterdb_quick, test_splinterdb_iterator_with_non_existent_startkey) // before 'key...', which is what key's format is.) keystring = "UnknownKey"; start_key = slice_create(strlen(keystring), keystring); - rc = splinterdb_iterator_init(data->kvsb, &it, start_key); + rc = splinterdb_iterator_init( + data->kvsb, &it, start_key, greater_than_or_equal); ASSERT_EQUAL(0, rc); int ictr = 0; @@ -606,7 +611,8 @@ CTEST2(splinterdb_quick, splinterdb_iterator *it = NULL; slice start_key = slice_create(strlen(key), key); - rc = splinterdb_iterator_init(data->kvsb, &it, start_key); + rc = splinterdb_iterator_init( + data->kvsb, &it, start_key, greater_than_or_equal); ASSERT_EQUAL(0, rc); bool32 is_valid = splinterdb_iterator_valid(it); @@ -625,7 +631,8 @@ CTEST2(splinterdb_quick, snprintf(key, sizeof(key), key_fmt, kctr); start_key = slice_create(strlen(key), key); - rc = splinterdb_iterator_init(data->kvsb, &it, start_key); + rc = splinterdb_iterator_init( + data->kvsb, &it, start_key, greater_than_or_equal); ASSERT_EQUAL(0, rc); is_valid = splinterdb_iterator_valid(it); @@ -643,7 +650,8 @@ CTEST2(splinterdb_quick, kctr = 5; snprintf(key, sizeof(key), key_fmt, kctr); start_key = slice_create(strlen(key), key); - rc = splinterdb_iterator_init(data->kvsb, &it, start_key); + rc = splinterdb_iterator_init( + data->kvsb, &it, start_key, greater_than_or_equal); ASSERT_EQUAL(0, rc); is_valid = splinterdb_iterator_valid(it); @@ -661,7 +669,8 @@ CTEST2(splinterdb_quick, kctr = minkey + 3 * num_inserts; snprintf(key, sizeof(key), key_fmt, kctr); start_key = slice_create(strlen(key), key); - rc = splinterdb_iterator_init(data->kvsb, &it, start_key); + rc = splinterdb_iterator_init( + data->kvsb, &it, start_key, greater_than_or_equal); ASSERT_EQUAL(0, rc); is_valid = splinterdb_iterator_valid(it); @@ -944,7 +953,8 @@ CTEST2(splinterdb_quick, test_iterator_custom_comparator) ASSERT_EQUAL(0, rc); splinterdb_iterator *it = NULL; - rc = splinterdb_iterator_init(data->kvsb, &it, NULL_SLICE); + rc = splinterdb_iterator_init( + data->kvsb, &it, NULL_SLICE, greater_than_or_equal); ASSERT_EQUAL(0, rc); int i = 0; @@ -986,7 +996,8 @@ CTEST2(splinterdb_quick, test_iterator_init_bug) // Iterator init should find nothing when no keys were inserted, yet. splinterdb_iterator *it = NULL; - rc = splinterdb_iterator_init(data->kvsb, &it, NULL_SLICE); + rc = splinterdb_iterator_init( + data->kvsb, &it, NULL_SLICE, greater_than_or_equal); ASSERT_EQUAL(0, rc); bool32 iter_valid = splinterdb_iterator_valid(it); @@ -1000,7 +1011,8 @@ CTEST2(splinterdb_quick, test_iterator_init_bug) ASSERT_EQUAL(0, rc); it = NULL; - rc = splinterdb_iterator_init(data->kvsb, &it, NULL_SLICE); + rc = splinterdb_iterator_init( + data->kvsb, &it, NULL_SLICE, greater_than_or_equal); ASSERT_EQUAL(0, rc); iter_valid = splinterdb_iterator_valid(it); @@ -1200,7 +1212,7 @@ test_two_step_iterator(splinterdb *kvsb, { int rc; splinterdb_iterator *it = NULL; - rc = splinterdb_iterator_init(kvsb, &it, start_key); + rc = splinterdb_iterator_init(kvsb, &it, start_key, greater_than_or_equal); ASSERT_EQUAL(0, rc); for (int i = start_i; i < num_keys; i++) { diff --git a/tests/unit/splinterdb_stress_test.c b/tests/unit/splinterdb_stress_test.c index 08645c3d..89248bd3 100644 --- a/tests/unit/splinterdb_stress_test.c +++ b/tests/unit/splinterdb_stress_test.c @@ -163,7 +163,9 @@ CTEST2(splinterdb_stress, test_iterator_over_many_kvs) splinterdb_iterator *it = NULL; snprintf(key_str, sizeof(key_str), "key-%08x", inserts); slice start_key = slice_create(sizeof(key_str), key_str); - ASSERT_EQUAL(0, splinterdb_iterator_init(data->kvsb, &it, start_key)); + ASSERT_EQUAL(0, + splinterdb_iterator_init( + data->kvsb, &it, start_key, greater_than_or_equal)); // assert that the iterator is in the state we expect ASSERT_FALSE(splinterdb_iterator_valid(it)); @@ -316,7 +318,8 @@ naive_range_delete(splinterdb *kvsb, slice start_key, uint32 count) splinterdb_iterator *it; - int rc = splinterdb_iterator_init(kvsb, &it, start_key); + int rc = + splinterdb_iterator_init(kvsb, &it, start_key, greater_than_or_equal); ASSERT_EQUAL(0, rc); slice key, value;