diff options
6 files changed, 161 insertions, 0 deletions
diff --git a/document/CMakeLists.txt b/document/CMakeLists.txt index fd347ca492d..7de1b0c0b89 100644 --- a/document/CMakeLists.txt +++ b/document/CMakeLists.txt @@ -34,6 +34,7 @@ vespa_define_module( src/tests/annotation src/tests/base src/tests/datatype + src/tests/document_type_repo_factory src/tests/fieldvalue src/tests/predicate src/tests/repo diff --git a/document/src/tests/document_type_repo_factory/CMakeLists.txt b/document/src/tests/document_type_repo_factory/CMakeLists.txt new file mode 100644 index 00000000000..c872559c3b5 --- /dev/null +++ b/document/src/tests/document_type_repo_factory/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(document_document_type_repo_factory_test_app TEST + SOURCES + document_type_repo_factory_test.cpp + DEPENDS + document + AFTER + document_documentconfig +) +vespa_add_test(NAME document_document_type_repo_factory_test_app COMMAND document_document_type_repo_factory_test_app) diff --git a/document/src/tests/document_type_repo_factory/document_type_repo_factory_test.cpp b/document/src/tests/document_type_repo_factory/document_type_repo_factory_test.cpp new file mode 100644 index 00000000000..a6b6044023e --- /dev/null +++ b/document/src/tests/document_type_repo_factory/document_type_repo_factory_test.cpp @@ -0,0 +1,52 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include <vespa/document/datatype/documenttype.h> +#include <vespa/document/repo/configbuilder.h> +#include <vespa/document/repo/documenttyperepo.h> +#include <vespa/document/repo/document_type_repo_factory.h> +#include <vespa/vespalib/stllike/string.h> +#include <vespa/vespalib/testkit/testapp.h> + +using vespalib::string; +using namespace document::config_builder; +using namespace document; + +namespace { + +const string type_name = "test"; +const int32_t doc_type_id = 787121340; +const string header_name = type_name + ".header"; +const string body_name = type_name + ".body"; + +std::shared_ptr<const DocumenttypesConfig> +makeDocumentTypesConfig(const string &field_name) +{ + document::config_builder::DocumenttypesConfigBuilderHelper builder; + builder.document(doc_type_id, type_name, + Struct(header_name), + Struct(body_name).addField(field_name, + DataType::T_STRING)); + return std::make_shared<const DocumenttypesConfig>(builder.config()); +} + +TEST("requireThatEqualConfigsGivesSameRepo") +{ + auto config1 = makeDocumentTypesConfig("a"); + auto config2 = makeDocumentTypesConfig("b"); + auto config3 = std::make_shared<const DocumenttypesConfig>(*config1); + auto config4 = std::make_shared<const DocumenttypesConfig>(*config2); + auto repo1 = DocumentTypeRepoFactory::make(*config1); + auto repo2 = DocumentTypeRepoFactory::make(*config2); + auto repo3 = DocumentTypeRepoFactory::make(*config3); + auto repo4 = DocumentTypeRepoFactory::make(*config4); + EXPECT_NOT_EQUAL(repo1, repo2); + EXPECT_EQUAL(repo1, repo3); + EXPECT_NOT_EQUAL(repo1, repo4); + EXPECT_NOT_EQUAL(repo2, repo3); + EXPECT_EQUAL(repo2, repo4); + EXPECT_NOT_EQUAL(repo3, repo4); +} + +} + +TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/document/src/vespa/document/repo/CMakeLists.txt b/document/src/vespa/document/repo/CMakeLists.txt index b5042ebd4b6..48265ca15b2 100644 --- a/document/src/vespa/document/repo/CMakeLists.txt +++ b/document/src/vespa/document/repo/CMakeLists.txt @@ -3,6 +3,7 @@ vespa_add_library(document_repo OBJECT SOURCES configbuilder.cpp documenttyperepo.cpp + document_type_repo_factory.cpp fixedtyperepo.cpp DEPENDS AFTER diff --git a/document/src/vespa/document/repo/document_type_repo_factory.cpp b/document/src/vespa/document/repo/document_type_repo_factory.cpp new file mode 100644 index 00000000000..61a515f5566 --- /dev/null +++ b/document/src/vespa/document/repo/document_type_repo_factory.cpp @@ -0,0 +1,52 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "document_type_repo_factory.h" +#include "documenttyperepo.h" +#include <vespa/document/config/config-documenttypes.h> +#include <functional> + +namespace document { + +std::mutex DocumentTypeRepoFactory::_mutex; +DocumentTypeRepoFactory::DocumentTypeRepoMap DocumentTypeRepoFactory::_repos; + +/* + * Class handling deletion of document type repo after last reference is gone. + */ +class DocumentTypeRepoFactory::Deleter +{ +public: + void operator()(DocumentTypeRepo *repoRawPtr) const noexcept { + deleteRepo(repoRawPtr); + } +}; + +void +DocumentTypeRepoFactory::deleteRepo(DocumentTypeRepo *repoRawPtr) noexcept +{ + std::unique_ptr<const DocumentTypeRepo> repo(repoRawPtr); + std::lock_guard guard(_mutex); + _repos.erase(repo.get()); +} + +std::shared_ptr<const DocumentTypeRepo> +DocumentTypeRepoFactory::make(const DocumenttypesConfig &config) +{ + std::lock_guard guard(_mutex); + // Return existing instance if config matches + for (const auto &entry : _repos) { + const auto repo = entry.second.repo.lock(); + const auto &repoConfig = *entry.second.config; + if (repo && repoConfig == config) { + return repo; + } + } + auto repoConfig = std::make_unique<const DocumenttypesConfig>(config); + auto repoup1 = std::make_unique<DocumentTypeRepo>(*repoConfig); + auto repoup2 = std::unique_ptr<DocumentTypeRepo, Deleter>(repoup1.release(), Deleter()); + auto repo = std::shared_ptr<const DocumentTypeRepo>(std::move(repoup2)); + _repos.emplace(repo.get(), DocumentTypeRepoEntry(repo, std::move(repoConfig))); + return repo; +} + +} diff --git a/document/src/vespa/document/repo/document_type_repo_factory.h b/document/src/vespa/document/repo/document_type_repo_factory.h new file mode 100644 index 00000000000..0c8eecb035d --- /dev/null +++ b/document/src/vespa/document/repo/document_type_repo_factory.h @@ -0,0 +1,45 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#pragma once + +#include <memory> +#include <mutex> +#include <map> + +namespace document { + +namespace internal { + class InternalDocumenttypesType; +} + +class DocumentTypeRepo; + +/* + * Factory class for document type repos. Same instance is returned + * for equal config. + */ +class DocumentTypeRepoFactory { + using DocumenttypesConfig = const internal::InternalDocumenttypesType; + struct DocumentTypeRepoEntry { + std::weak_ptr<const DocumentTypeRepo> repo; + std::unique_ptr<const DocumenttypesConfig> config; + + DocumentTypeRepoEntry(std::weak_ptr<const DocumentTypeRepo> repo_in, + std::unique_ptr<const DocumenttypesConfig> config_in) + : repo(std::move(repo_in)), + config(std::move(config_in)) + { + } + }; + using DocumentTypeRepoMap = std::map<const void *, DocumentTypeRepoEntry>; + class Deleter; + + static std::mutex _mutex; + static DocumentTypeRepoMap _repos; + + static void deleteRepo(DocumentTypeRepo *repoRawPtr) noexcept; +public: + static std::shared_ptr<const DocumentTypeRepo> make(const DocumenttypesConfig &config); +}; + +} |