From 033554a4e791af5d957067cc5cd68cd90c71f105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Edelbo?= Date: Tue, 4 Jun 2024 15:07:37 +0200 Subject: [PATCH 1/2] Optimize IntegerNode::find_first_local If you are just testing one element, use simple compare instead of leaf->find_first. This will speed up queries where secondary nodes are IntegerNodes. --- src/realm/query_engine.hpp | 11 +++++++++++ test/util/test_path.cpp | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/realm/query_engine.hpp b/src/realm/query_engine.hpp index 8b7ecf2d1e8..a5a4d96e1ab 100644 --- a/src/realm/query_engine.hpp +++ b/src/realm/query_engine.hpp @@ -425,6 +425,17 @@ class IntegerNode : public IntegerNodeBase { size_t find_first_local(size_t start, size_t end) override { + TConditionFunction c; + if (end - start == 1) { + if constexpr (std::is_same_v) { + return c(this->m_leaf->get(start), this->m_value) ? start : realm::not_found; + } + else { + std::optional opt_int = this->m_leaf->get(start); + return c(opt_int, this->m_value, !opt_int, !this->m_value) ? start : realm::not_found; + } + } + return this->m_leaf->template find_first(this->m_value, start, end); } diff --git a/test/util/test_path.cpp b/test/util/test_path.cpp index 1f08441479d..c7cfd26115b 100644 --- a/test/util/test_path.cpp +++ b/test/util/test_path.cpp @@ -148,7 +148,7 @@ bool initialize_test_path(int argc, const char* argv[]) return false; } g_resource_path = File::resolve("resources", directory) + "/"; - g_path_prefix = directory; + g_path_prefix = std::string(directory) + "/"; #endif if (argc > 0) { From a43660e51c0f7c4dbfc04527284bc0692b89cafc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Edelbo?= Date: Thu, 6 Jun 2024 11:17:46 +0200 Subject: [PATCH 2/2] Move optimization to Array... --- src/realm/array.hpp | 4 ++++ src/realm/array_integer_tpl.hpp | 12 ++++++++---- src/realm/query_engine.hpp | 16 ---------------- test/test_query.cpp | 9 +++++---- 4 files changed, 17 insertions(+), 24 deletions(-) diff --git a/src/realm/array.hpp b/src/realm/array.hpp index 26990e6cfd4..af6fee1efa6 100644 --- a/src/realm/array.hpp +++ b/src/realm/array.hpp @@ -392,7 +392,11 @@ class Array : public Node, public ArrayParent { template size_t find_first(int64_t value, size_t start = 0, size_t end = size_t(-1)) const { + static cond c; REALM_ASSERT(start <= m_size && (end <= m_size || end == size_t(-1)) && start <= end); + if (end - start == 1) { + return c(get(start), value) ? start : realm::not_found; + } // todo, would be nice to avoid this in order to speed up find_first loops QueryStateFindFirst state; Finder finder = m_vtable->finder[cond::condition]; diff --git a/src/realm/array_integer_tpl.hpp b/src/realm/array_integer_tpl.hpp index 9d96584ab3c..5b97e257593 100644 --- a/src/realm/array_integer_tpl.hpp +++ b/src/realm/array_integer_tpl.hpp @@ -104,13 +104,17 @@ bool ArrayIntNull::find_impl(value_type opt_value, size_t start, size_t end, Que template size_t ArrayIntNull::find_first(value_type value, size_t start, size_t end) const { + static cond c; + REALM_ASSERT(start <= m_size && (end <= m_size || end == size_t(-1)) && start <= end); + if (end - start == 1) { + std::optional opt_int = get(start); + return c(opt_int, value, !opt_int, !value) ? start : realm::not_found; + } + QueryStateFindFirst state; find_impl(value, start, end, &state); - if (state.match_count() > 0) - return to_size_t(state.m_state); - else - return not_found; + return static_cast(state.m_state); } template diff --git a/src/realm/query_engine.hpp b/src/realm/query_engine.hpp index a5a4d96e1ab..7a4d01e0496 100644 --- a/src/realm/query_engine.hpp +++ b/src/realm/query_engine.hpp @@ -425,17 +425,6 @@ class IntegerNode : public IntegerNodeBase { size_t find_first_local(size_t start, size_t end) override { - TConditionFunction c; - if (end - start == 1) { - if constexpr (std::is_same_v) { - return c(this->m_leaf->get(start), this->m_value) ? start : realm::not_found; - } - else { - std::optional opt_int = this->m_leaf->get(start); - return c(opt_int, this->m_value, !opt_int, !this->m_value) ? start : realm::not_found; - } - } - return this->m_leaf->template find_first(this->m_value, start, end); } @@ -587,11 +576,6 @@ class IntegerNode : public IntegerNodeBase { else if (m_index_evaluator) { return m_index_evaluator->do_search_index(BaseType::m_cluster, start, end); } - else if (end - start == 1) { - if (this->m_leaf->get(start) == this->m_value) { - s = start; - } - } else { s = this->m_leaf->template find_first(this->m_value, start, end); } diff --git a/test/test_query.cpp b/test/test_query.cpp index 6df86fb2b1f..53b0a68b0df 100644 --- a/test/test_query.cpp +++ b/test/test_query.cpp @@ -706,17 +706,18 @@ TEST(Query_NextGenSyntaxMonkey0) } } -TEST(Query_NextGenSyntaxMonkey) +TEST_TYPES(Query_NextGenSyntaxMonkey, std::true_type, std::false_type) { + static const bool nullable = TEST_TYPE::value; Random random(random_int()); // Seed from slow global generator for (int iter = 1; iter < 5 * (TEST_DURATION * TEST_DURATION * TEST_DURATION + 1); iter++) { // Set 'rows' to at least '* 20' else some tests will give 0 matches and bad coverage const size_t rows = 1 + random.draw_int_mod(REALM_MAX_BPNODE_SIZE * 20 * (TEST_DURATION * TEST_DURATION * TEST_DURATION + 1)); Table table; - auto col_int0 = table.add_column(type_Int, "first"); - auto col_int1 = table.add_column(type_Int, "second"); - auto col_int2 = table.add_column(type_Int, "third"); + auto col_int0 = table.add_column(type_Int, "first", nullable); + auto col_int1 = table.add_column(type_Int, "second", nullable); + auto col_int2 = table.add_column(type_Int, "third", nullable); for (size_t r = 0; r < rows; r++) { Obj obj = table.create_object();