From 510f2909aeb4186dbfd4dafbe1667d09d3406a50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Pu=C5=A1i=C4=87?= Date: Fri, 22 Dec 2023 14:42:12 +0100 Subject: [PATCH] Add functioning basic proof of concept --- src/storage/v2/property_store.cpp | 44 +++++++++++++++++++-- src/storage/v2/property_store.hpp | 41 ++++++++++++++++++-- tests/unit/storage_v2_property_store.cpp | 49 +++++++++++------------- 3 files changed, 100 insertions(+), 34 deletions(-) diff --git a/src/storage/v2/property_store.cpp b/src/storage/v2/property_store.cpp index 84abbcdc0..57f62db2d 100644 --- a/src/storage/v2/property_store.cpp +++ b/src/storage/v2/property_store.cpp @@ -106,7 +106,6 @@ enum class Type : uint8_t { LIST = 0x60, MAP = 0x70, TEMPORAL_DATA = 0x80, - EXTERNALLY_STORED = 0x90 }; const uint8_t kMaskType = 0xf0; @@ -1023,7 +1022,20 @@ PropertyStore::~PropertyStore() { } } -PropertyValue PropertyStore::GetProperty(PropertyId property) const { +PropertyValue PropertyStore::GetProperty(PropertyId property, const bool external, + ExternalStoreMock *external_store_mock) const { + if (external) { + int DUMMY_GRAPH_ELEMENT_ID = 1; + + auto key = property.ToString(); + auto properties = external_store_mock->GetDocument(DUMMY_GRAPH_ELEMENT_ID)["properties"]; + if (!properties.contains(key)) { + return PropertyValue(); + } + + return PropertyValue(properties.at(key).get()); + } + uint64_t size; const uint8_t *data; std::tie(size, data) = GetSizeData(buffer_); @@ -1038,7 +1050,15 @@ PropertyValue PropertyStore::GetProperty(PropertyId property) const { return value; } -bool PropertyStore::HasProperty(PropertyId property) const { +bool PropertyStore::HasProperty(PropertyId property, const bool external, + ExternalStoreMock *external_store_mock) const { + if (external) { + int DUMMY_GRAPH_ELEMENT_ID = 1; + + auto properties = external_store_mock->GetDocument(DUMMY_GRAPH_ELEMENT_ID)["properties"]; + return properties.contains(property.ToString()); + } + uint64_t size; const uint8_t *data; std::tie(size, data) = GetSizeData(buffer_); @@ -1121,7 +1141,23 @@ std::map PropertyStore::Properties() const { return props; } -bool PropertyStore::SetProperty(PropertyId property, const PropertyValue &value) { +bool PropertyStore::SetProperty(PropertyId property, const PropertyValue &value, const bool external, + ExternalStoreMock *external_store_mock) { + if (external) { + int DUMMY_GRAPH_ELEMENT_ID = 1; + nlohmann::json document; + nlohmann::json property_map; + + if (!value.IsNull()) { + property_map[property.ToString()] = value.ValueInt(); + } + + document["id"] = DUMMY_GRAPH_ELEMENT_ID; + document["properties"] = property_map; + external_store_mock->AddDocument(DUMMY_GRAPH_ELEMENT_ID, document); + return true; + } + uint64_t property_size = 0; if (!value.IsNull()) { Writer writer; diff --git a/src/storage/v2/property_store.hpp b/src/storage/v2/property_store.hpp index 6a458641b..d900ad0de 100644 --- a/src/storage/v2/property_store.hpp +++ b/src/storage/v2/property_store.hpp @@ -11,6 +11,7 @@ #pragma once +#include #include #include @@ -19,6 +20,37 @@ namespace memgraph::storage { +struct SearchResult { + std::uint64_t id; + nlohmann::json document; + double score; +}; + +class ExternalStoreMock { + private: + std::string INDEX = ""; // placeholder (Tantivy supports multiple indices) + std::map> storage{}; // index_name: {document_id: document} + + public: + enum class Consistency : uint8_t { DEFAULT }; + + void CreateAllPropsIndex(std::string name, std::string tokenizer = "DUMMY_TOKENIZER", + Consistency consistency = Consistency::DEFAULT) {} + + void DropIndex(std::string index_name) { storage.erase(index_name); } + + void AddDocument(std::uint64_t id, nlohmann::json document) { storage[INDEX][id] = document; } + + nlohmann::json GetDocument(std::uint64_t id) { return storage[INDEX][id]; } + + void DeleteDocument(std::uint64_t id) { storage[INDEX].erase(id); } + + SearchResult Search(std::string index_name, std::string search_query) { + auto mock_result = storage[index_name].begin(); + return SearchResult{.id = mock_result->first, .document = mock_result->second, .score = 1.0}; + } +}; + class PropertyStore { static_assert(std::endian::native == std::endian::little, "PropertyStore supports only architectures using little-endian."); @@ -43,11 +75,13 @@ class PropertyStore { /// property doesn't exist a Null value is returned. The time complexity of /// this function is O(n). /// @throw std::bad_alloc - PropertyValue GetProperty(PropertyId property) const; + PropertyValue GetProperty(PropertyId property, const bool external = false, + ExternalStoreMock *external_store_mock = nullptr) const; /// Checks whether the property `property` exists in the store. The time /// complexity of this function is O(n). - bool HasProperty(PropertyId property) const; + bool HasProperty(PropertyId property, const bool external = false, + ExternalStoreMock *external_store_mock = nullptr) const; /// Checks whether all properties in the set `properties` exist in the store. The time /// complexity of this function is O(n^2). @@ -77,7 +111,8 @@ class PropertyStore { /// returned if assignment took place. The time complexity of this function is /// O(n). /// @throw std::bad_alloc - bool SetProperty(PropertyId property, const PropertyValue &value); + bool SetProperty(PropertyId property, const PropertyValue &value, const bool external = false, + ExternalStoreMock *external_store_mock = nullptr); /// Init property values and return `true` if insertion took place. `false` is /// returned if there is any existing property in property store and insertion couldn't take place. The time diff --git a/tests/unit/storage_v2_property_store.cpp b/tests/unit/storage_v2_property_store.cpp index 4b4c8078d..3f3718803 100644 --- a/tests/unit/storage_v2_property_store.cpp +++ b/tests/unit/storage_v2_property_store.cpp @@ -22,33 +22,6 @@ using testing::UnorderedElementsAre; -struct SearchResult { - std::uint64_t id; - nlohmann::json document; - double score; -}; - -class TantivyMock { - enum class Consistency : uint8_t { DEFAULT }; - - std::string INDEX = ""; // placeholder - - std::map> storage{}; // index_name: {document_id: document} - - void CreateAllPropsIndex(std::string name, std::string tokenizer, Consistency consistency = Consistency::DEFAULT) {} - - void DropIndex(std::string index_name) { storage.erase(index_name); } - - void AddDocument(std::uint64_t id, nlohmann::json document) { storage[INDEX][id] = document; } - - void DeleteDocument(std::uint64_t id) { storage[INDEX].erase(id); } - - SearchResult Search(std::string index_name, std::string search_query) { - auto mock_result = storage[index_name].begin(); - return SearchResult{.id = mock_result->first, .document = mock_result->second, .score = 1.0}; - } -}; - const memgraph::storage::PropertyValue kSampleValues[] = { memgraph::storage::PropertyValue(), memgraph::storage::PropertyValue(false), @@ -95,6 +68,28 @@ void TestIsPropertyEqual(const memgraph::storage::PropertyStore &store, memgraph } } +TEST(PropertyStore, SimpleExternallyStored) { + auto mock = memgraph::storage::ExternalStoreMock(); + + memgraph::storage::PropertyStore props; + auto prop = memgraph::storage::PropertyId::FromInt(42); + auto value = memgraph::storage::PropertyValue(42); + + ASSERT_TRUE(props.SetProperty(prop, value, true, &mock)); + + ASSERT_EQ(props.GetProperty(prop, true, &mock), value); + + ASSERT_TRUE(props.HasProperty(prop, true, &mock)); + + ASSERT_TRUE(props.SetProperty(prop, memgraph::storage::PropertyValue(), true, &mock)); + + ASSERT_TRUE(props.GetProperty(prop, true, &mock).IsNull()); + + ASSERT_FALSE(props.HasProperty(prop, true, &mock)); + + TestIsPropertyEqual(props, prop, memgraph::storage::PropertyValue()); +} + TEST(PropertyStore, Simple) { memgraph::storage::PropertyStore props; auto prop = memgraph::storage::PropertyId::FromInt(42);