diff --git a/src/query/interpreter.cpp b/src/query/interpreter.cpp index 916043e7b..4d6f54595 100644 --- a/src/query/interpreter.cpp +++ b/src/query/interpreter.cpp @@ -53,7 +53,9 @@ #include "query/typed_value.hpp" #include "storage/v2/edge.hpp" #include "storage/v2/id_types.hpp" +#include "storage/v2/isolation_level.hpp" #include "storage/v2/property_value.hpp" +#include "storage/v2/storage_mode.hpp" #include "utils/algorithm.hpp" #include "utils/csv_parsing.hpp" #include "utils/event_counter.hpp" @@ -2318,8 +2320,10 @@ PreparedQuery PrepareVersionQuery(ParsedQuery parsed_query, bool in_explicit_tra } PreparedQuery PrepareInfoQuery(ParsedQuery parsed_query, bool in_explicit_transaction, - std::map *summary, InterpreterContext *interpreter_context, - storage::Storage *db, utils::MemoryResource *execution_memory) { + std::map * /*summary*/, InterpreterContext *interpreter_context, + storage::Storage *db, utils::MemoryResource * /*execution_memory*/, + std::optional interpreter_isolation_level, + std::optional next_transaction_isolation_level) { if (in_explicit_transaction) { throw InfoInMulticommandTxException(); } @@ -2331,7 +2335,8 @@ PreparedQuery PrepareInfoQuery(ParsedQuery parsed_query, bool in_explicit_transa switch (info_query->info_type_) { case InfoQuery::InfoType::STORAGE: header = {"storage info", "value"}; - handler = [db] { + + handler = [db, interpreter_isolation_level, next_transaction_isolation_level] { auto info = db->GetInfo(); std::vector> results{ {TypedValue("vertex_count"), TypedValue(static_cast(info.vertex_count))}, @@ -2340,8 +2345,12 @@ PreparedQuery PrepareInfoQuery(ParsedQuery parsed_query, bool in_explicit_transa {TypedValue("memory_usage"), TypedValue(static_cast(info.memory_usage))}, {TypedValue("disk_usage"), TypedValue(static_cast(info.disk_usage))}, {TypedValue("memory_allocated"), TypedValue(static_cast(utils::total_memory_tracker.Amount()))}, - {TypedValue("allocation_limit"), - TypedValue(static_cast(utils::total_memory_tracker.HardLimit()))}}; + {TypedValue("allocation_limit"), TypedValue(static_cast(utils::total_memory_tracker.HardLimit()))}, + {TypedValue("global_isolation_level"), TypedValue(IsolationLevelToString(db->GetIsolationLevel()))}, + {TypedValue("session_isolation_level"), TypedValue(IsolationLevelToString(interpreter_isolation_level))}, + {TypedValue("next_session_isolation_level"), + TypedValue(IsolationLevelToString(next_transaction_isolation_level))}, + {TypedValue("storage_mode"), TypedValue(StorageModeToString(db->GetStorageMode()))}}; return std::pair{results, QueryHandlerResult::COMMIT}; }; break; @@ -2813,7 +2822,8 @@ Interpreter::PrepareResult Interpreter::Prepare(const std::string &query_string, } else if (utils::Downcast(parsed_query.query)) { prepared_query = PrepareInfoQuery(std::move(parsed_query), in_explicit_transaction_, &query_execution->summary, interpreter_context_, interpreter_context_->db, - &query_execution->execution_memory_with_exception); + &query_execution->execution_memory_with_exception, interpreter_isolation_level, + next_transaction_isolation_level); } else if (utils::Downcast(parsed_query.query)) { prepared_query = PrepareConstraintQuery(std::move(parsed_query), in_explicit_transaction_, &query_execution->notifications, interpreter_context_); diff --git a/src/storage/v2/CMakeLists.txt b/src/storage/v2/CMakeLists.txt index 505ae45ec..984f63a65 100644 --- a/src/storage/v2/CMakeLists.txt +++ b/src/storage/v2/CMakeLists.txt @@ -10,7 +10,9 @@ set(storage_v2_src_files indices.cpp property_store.cpp vertex_accessor.cpp - storage.cpp) + storage.cpp + storage_mode.cpp + isolation_level.cpp) set(storage_v2_src_files diff --git a/src/storage/v2/isolation_level.cpp b/src/storage/v2/isolation_level.cpp new file mode 100644 index 000000000..d9c09d2f3 --- /dev/null +++ b/src/storage/v2/isolation_level.cpp @@ -0,0 +1,34 @@ +// Copyright 2023 Memgraph Ltd. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source +// License, and you may not use this file except in compliance with the Business Source License. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +#include "isolation_level.hpp" + +namespace memgraph::storage { + +std::string_view IsolationLevelToString(IsolationLevel isolation_level) { + switch (isolation_level) { + case IsolationLevel::READ_COMMITTED: + return "READ_COMMITTED"; + case IsolationLevel::READ_UNCOMMITTED: + return "READ_UNCOMMITTED"; + case IsolationLevel::SNAPSHOT_ISOLATION: + return "SNAPSHOT_ISOLATION"; + } +} + +std::string_view IsolationLevelToString(std::optional isolation_level) { + if (isolation_level) { + return IsolationLevelToString(*isolation_level); + } + return ""; +} + +} // namespace memgraph::storage diff --git a/src/storage/v2/isolation_level.hpp b/src/storage/v2/isolation_level.hpp index b655e5e51..b83d14f4e 100644 --- a/src/storage/v2/isolation_level.hpp +++ b/src/storage/v2/isolation_level.hpp @@ -1,4 +1,4 @@ -// Copyright 2022 Memgraph Ltd. +// Copyright 2023 Memgraph Ltd. // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source @@ -12,9 +12,14 @@ #pragma once #include +#include +#include namespace memgraph::storage { enum class IsolationLevel : std::uint8_t { SNAPSHOT_ISOLATION, READ_COMMITTED, READ_UNCOMMITTED }; +std::string_view IsolationLevelToString(IsolationLevel isolation_level); +std::string_view IsolationLevelToString(std::optional isolation_level); + } // namespace memgraph::storage diff --git a/src/storage/v2/storage.cpp b/src/storage/v2/storage.cpp index 196bbaec1..4ebc144c0 100644 --- a/src/storage/v2/storage.cpp +++ b/src/storage/v2/storage.cpp @@ -2173,6 +2173,8 @@ utils::BasicResult Storage::SetIsolationLevel(I return {}; } +IsolationLevel Storage::GetIsolationLevel() const noexcept { return isolation_level_; } + void Storage::SetStorageMode(StorageMode storage_mode) { std::unique_lock main_guard{main_lock_}; storage_mode_ = storage_mode; diff --git a/src/storage/v2/storage.hpp b/src/storage/v2/storage.hpp index aeea9d6f8..60541ed63 100644 --- a/src/storage/v2/storage.hpp +++ b/src/storage/v2/storage.hpp @@ -513,6 +513,7 @@ class Storage final { enum class SetIsolationLevelError : uint8_t { DisabledForAnalyticalMode }; utils::BasicResult SetIsolationLevel(IsolationLevel isolation_level); + IsolationLevel GetIsolationLevel() const noexcept; void SetStorageMode(StorageMode storage_mode); diff --git a/src/storage/v2/storage_mode.cpp b/src/storage/v2/storage_mode.cpp new file mode 100644 index 000000000..a05017f1d --- /dev/null +++ b/src/storage/v2/storage_mode.cpp @@ -0,0 +1,25 @@ +// Copyright 2023 Memgraph Ltd. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source +// License, and you may not use this file except in compliance with the Business Source License. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +#include "storage_mode.hpp" + +namespace memgraph::storage { + +std::string_view StorageModeToString(memgraph::storage::StorageMode storage_mode) { + switch (storage_mode) { + case memgraph::storage::StorageMode::IN_MEMORY_ANALYTICAL: + return "IN_MEMORY_ANALYTICAL"; + case memgraph::storage::StorageMode::IN_MEMORY_TRANSACTIONAL: + return "IN_MEMORY_TRANSACTIONAL"; + } +} + +} // namespace memgraph::storage diff --git a/src/storage/v2/storage_mode.hpp b/src/storage/v2/storage_mode.hpp index 270d63955..2da6435cd 100644 --- a/src/storage/v2/storage_mode.hpp +++ b/src/storage/v2/storage_mode.hpp @@ -12,9 +12,12 @@ #pragma once #include +#include namespace memgraph::storage { enum class StorageMode : std::uint8_t { IN_MEMORY_ANALYTICAL, IN_MEMORY_TRANSACTIONAL }; +std::string_view StorageModeToString(memgraph::storage::StorageMode storage_mode); + } // namespace memgraph::storage diff --git a/tests/e2e/configuration/CMakeLists.txt b/tests/e2e/configuration/CMakeLists.txt index 7fe4d5c00..0411c70e3 100644 --- a/tests/e2e/configuration/CMakeLists.txt +++ b/tests/e2e/configuration/CMakeLists.txt @@ -4,3 +4,4 @@ endfunction() copy_configuration_check_e2e_python_files(default_config.py) copy_configuration_check_e2e_python_files(configuration_check.py) +copy_configuration_check_e2e_python_files(storage_info.py) diff --git a/tests/e2e/configuration/storage_info.py b/tests/e2e/configuration/storage_info.py new file mode 100644 index 000000000..7644c8d3c --- /dev/null +++ b/tests/e2e/configuration/storage_info.py @@ -0,0 +1,109 @@ +# Copyright 2022 Memgraph Ltd. +# +# Use of this software is governed by the Business Source License +# included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source +# License, and you may not use this file except in compliance with the Business Source License. +# +# As of the Change Date specified in that file, in accordance with +# the Business Source License, use of this software will be governed +# by the Apache License, Version 2.0, included in the file +# licenses/APL.txt. + +import sys + +import default_config +import mgclient +import pytest + +default_storage_info_dict = { + "vertex_count": 0, + "edge_count": 0, + "average_degree": 0, + "memory_usage": "", # machine dependent + "disk_usage": "", # machine dependent + "memory_allocated": "", # machine dependent + "allocation_limit": "", # machine dependent + "global_isolation_level": "SNAPSHOT_ISOLATION", + "session_isolation_level": "", + "next_session_isolation_level": "", + "storage_mode": "IN_MEMORY_TRANSACTIONAL", +} + + +def apply_queries_and_check_for_storage_info(cursor, setup_query_list, expected_values): + for query in setup_query_list: + cursor.execute(query) + + cursor.execute("SHOW STORAGE INFO") + config = cursor.fetchall() + + for conf in config: + conf_name = conf[0] + if conf_name in expected_values: + assert expected_values[conf_name] == conf[1] + + +def test_does_default_config_match(): + connection = mgclient.connect(host="localhost", port=7687) + connection.autocommit = True + + cursor = connection.cursor() + cursor.execute("SHOW STORAGE INFO") + config = cursor.fetchall() + + # The default value of these is dependent on the given machine. + machine_dependent_configurations = ["memory_usage", "disk_usage", "memory_allocated", "allocation_limit"] + + # Number of different data-points returned by SHOW STORAGE INFO + assert len(config) == 11 + + for conf in config: + conf_name = conf[0] + if conf_name in machine_dependent_configurations: + continue + assert default_storage_info_dict[conf_name] == conf[1] + + +def test_info_change(): + connection = mgclient.connect(host="localhost", port=7687) + connection.autocommit = True + + cursor = connection.cursor() + + # Check for vertex and edge changes + setup_query_list = [ + "CREATE(n{id: 1}),(m{id: 2})", + "MATCH(n),(m) WHERE n.id = 1 AND m.id = 2 CREATE (n)-[r:relation]->(m)", + ] + expected_values = { + "vertex_count": 2, + "edge_count": 1, + } + + apply_queries_and_check_for_storage_info(cursor, setup_query_list, expected_values) + + # Check for isolation level changes + setup_query_list = [ + "SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED", + "SET NEXT TRANSACTION ISOLATION LEVEL READ COMMITTED", + "SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED", + ] + + expected_values = { + "global_isolation_level": "READ_UNCOMMITTED", + "session_isolation_level": "READ_COMMITTED", + "next_session_isolation_level": "READ_COMMITTED", + } + + apply_queries_and_check_for_storage_info(cursor, setup_query_list, expected_values) + + # Check for storage mode change + setup_query_list = ["STORAGE MODE IN_MEMORY_ANALYTICAL"] + + expected_values = {"storage_mode": "IN_MEMORY_ANALYTICAL"} + + apply_queries_and_check_for_storage_info(cursor, setup_query_list, expected_values) + + +if __name__ == "__main__": + sys.exit(pytest.main([__file__, "-rA"])) diff --git a/tests/e2e/configuration/workloads.yaml b/tests/e2e/configuration/workloads.yaml index 3a8517d90..edead4eef 100644 --- a/tests/e2e/configuration/workloads.yaml +++ b/tests/e2e/configuration/workloads.yaml @@ -18,3 +18,8 @@ workloads: binary: "tests/e2e/pytest_runner.sh" args: ["configuration/configuration_check.py"] <<: *template_cluster + + - name: "SHOW STORAGE INFO check" + binary: "tests/e2e/pytest_runner.sh" + args: ["configuration/storage_info.py"] + <<: *template_cluster diff --git a/tests/unit/storage_test_utils.cpp b/tests/unit/storage_test_utils.cpp index aef87b985..8efcfa0b5 100644 --- a/tests/unit/storage_test_utils.cpp +++ b/tests/unit/storage_test_utils.cpp @@ -18,12 +18,3 @@ size_t CountVertices(memgraph::storage::Storage::Accessor &storage_accessor, mem ; return count; } - -std::string_view StorageModeToString(memgraph::storage::StorageMode storage_mode) { - switch (storage_mode) { - case memgraph::storage::StorageMode::IN_MEMORY_ANALYTICAL: - return "IN_MEMORY_ANALYTICAL"; - case memgraph::storage::StorageMode::IN_MEMORY_TRANSACTIONAL: - return "IN_MEMORY_TRANSACTIONAL"; - } -} diff --git a/tests/unit/storage_test_utils.hpp b/tests/unit/storage_test_utils.hpp index a24146735..96fdfd4f6 100644 --- a/tests/unit/storage_test_utils.hpp +++ b/tests/unit/storage_test_utils.hpp @@ -16,7 +16,5 @@ size_t CountVertices(memgraph::storage::Storage::Accessor &storage_accessor, memgraph::storage::View view); -std::string_view StorageModeToString(memgraph::storage::StorageMode storage_mode); - inline constexpr std::array storage_modes{memgraph::storage::StorageMode::IN_MEMORY_ANALYTICAL, memgraph::storage::StorageMode::IN_MEMORY_TRANSACTIONAL}; diff --git a/tests/unit/storage_v2_isolation_level.cpp b/tests/unit/storage_v2_isolation_level.cpp index c626d5952..dc0bb0d62 100644 --- a/tests/unit/storage_v2_isolation_level.cpp +++ b/tests/unit/storage_v2_isolation_level.cpp @@ -1,4 +1,4 @@ -// Copyright 2022 Memgraph Ltd. +// Copyright 2023 Memgraph Ltd. // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source @@ -28,16 +28,6 @@ inline constexpr std::array isolation_levels{memgraph::storage::IsolationLevel:: memgraph::storage::IsolationLevel::READ_COMMITTED, memgraph::storage::IsolationLevel::READ_UNCOMMITTED}; -std::string_view IsolationLevelToString(const memgraph::storage::IsolationLevel isolation_level) { - switch (isolation_level) { - case memgraph::storage::IsolationLevel::SNAPSHOT_ISOLATION: - return "SNAPSHOT_ISOLATION"; - case memgraph::storage::IsolationLevel::READ_COMMITTED: - return "READ_COMMITTED"; - case memgraph::storage::IsolationLevel::READ_UNCOMMITTED: - return "READ_UNCOMMITTED"; - } -} } // namespace class StorageIsolationLevelTest : public ::testing::TestWithParam {