From e117c554fa8bcfbcf6f8b23fb386a4beab53ee5e Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Tue, 19 Mar 2019 13:03:26 +0100 Subject: [PATCH] [#103,!277] Added CBControlBase::fetchConfigElement function. --- src/lib/process/cb_ctl_base.h | 45 ++++++++++++++++++- .../process/tests/cb_ctl_base_unittests.cc | 38 ++++++++++++++++ 2 files changed, 81 insertions(+), 2 deletions(-) diff --git a/src/lib/process/cb_ctl_base.h b/src/lib/process/cb_ctl_base.h index 90e8811170..8547cacc97 100644 --- a/src/lib/process/cb_ctl_base.h +++ b/src/lib/process/cb_ctl_base.h @@ -180,9 +180,12 @@ public: /// @todo We need a separate API call for the latter case to only /// fetch the last audit entry rather than all of them. + // Save the timestamp indicating last audit entry time. + auto lb_modification_time = last_audit_entry_time_; + audit_entries = getMgr().getPool()->getRecentAuditEntries(backend_selector, server_selector, - last_audit_entry_time_); + lb_modification_time); // Store the last audit entry time. It should be set to the most recent // audit entry fetched. If returned audit is empty we don't update. updateLastAuditEntryTime(audit_entries); @@ -198,12 +201,47 @@ public: // execute the server specific function that fetches and merges the data // into the given configuration. if (!fetch_updates_only || !audit_entries.empty()) { - databaseConfigApply(srv_cfg, backend_selector, server_selector, audit_entries); + databaseConfigApply(srv_cfg, backend_selector, server_selector, + lb_modification_time, audit_entries); } } protected: + /// @brief Checks if there are new or updated configuration elements of + /// specific type to be fetched from the database. + /// + /// This is convenience method invoked from the implementations of the + /// @c databaseConfigApply function. This method is invoked in two cases: + /// when the server starts up and fetches the entire configuration available + /// for it and when it should fetch the updates to the existing configuration. + /// In the former case, the collection of audit entries is always empty. + /// In the latter case it contains audit entries indicating the updates + /// to be fetched. This method checks if the implementation of the + /// @c databaseConfigApply should fetch updated configuration of the + /// configuration elements of the specific type. Therefore, it returns true + /// if the audit entries collection is empty (the former case described + /// above) or the audit entries collection contains CREATE or UPDATE + /// entries of the specific type. + /// + /// @return true if there are new or updated configuration elements to + /// be fetched from the database or the audit entries collection is empty. + bool fetchConfigElement(const db::AuditEntryCollection& audit_entries, + const std::string& object_type) const { + if (!audit_entries.empty()) { + const auto& index = audit_entries.get(); + auto range = index.equal_range(object_type); + for (auto it = range.first; it != range.second; ++it) { + if ((*it)->getModificationType() != db::AuditEntry::ModificationType::DELETE) { + return (true); + } + } + return (false); + } + + return (true); + } + /// @brief Server specific method to apply fetched configuration into /// the local configuration. /// @@ -227,12 +265,15 @@ protected: /// @pararm srv_cfg Pointer to the local server configuration. /// @param backend_selector Backend selector. /// @param server_selector Server selector. + /// @param lb_modification_time Lower bound modification time for the + /// configuration elements to be fetched. /// @param audit_entries Audit entries fetched from the database since /// the last configuration update. This collection is empty if there /// were no updates. virtual void databaseConfigApply(const ConfigPtr& srv_cfg, const db::BackendSelector& backend_selector, const db::ServerSelector& server_selector, + const boost::posix_time::ptime& lb_modification_time, const db::AuditEntryCollection& audit_entries) = 0; /// @brief Returns the instance of the Config Backend Manager used by diff --git a/src/lib/process/tests/cb_ctl_base_unittests.cc b/src/lib/process/tests/cb_ctl_base_unittests.cc index 9abc1a7d16..19a07a879c 100644 --- a/src/lib/process/tests/cb_ctl_base_unittests.cc +++ b/src/lib/process/tests/cb_ctl_base_unittests.cc @@ -222,6 +222,7 @@ public: class CBControl : public CBControlBase { public: + using CBControlBase::fetchConfigElement; using CBControlBase::getMgr; using CBControlBase::getInitialAuditEntryTime; @@ -246,6 +247,7 @@ public: virtual void databaseConfigApply(const ConfigPtr& srv_cfg, const BackendSelector& backend_selector, const ServerSelector& server_selector, + const boost::posix_time::ptime&, const AuditEntryCollection& audit_entries) { ++merges_num_; backend_selector_ = backend_selector; @@ -379,6 +381,42 @@ TEST_F(CBControlBaseTest, getMgr) { EXPECT_EQ(TEST_INSTANCE_ID, mgr.getInstanceId()); } +// This test verifies that it is correctly determined whether the +// server should fetch the particular configuration element. +TEST_F(CBControlBaseTest, fetchConfigElement) { + db::AuditEntryCollection audit_entries; + // When audit entries collection is empty it indicates that this + // is the case of the full server reconfiguration. Always indicate + // that the configuration elements must be fetched. + EXPECT_TRUE(cb_ctl_.fetchConfigElement(audit_entries, "my_object_type")); + + // Now test the case that there is a DELETE audit entry. In this case + // our function should indicate that the configuration should not be + // fetched for the given object type. Note that when the configuration + // element is deleted, it no longer exists in database so there is + // no reason to fetch the data from the database. + AuditEntryPtr audit_entry(new AuditEntry("dhcp4_subnet", 1234 , + AuditEntry::ModificationType::DELETE, + "added audit entry")); + audit_entries.insert(audit_entry); + EXPECT_FALSE(cb_ctl_.fetchConfigElement(audit_entries, "my_object_type")); + + // Add another audit entry which indicates creation of the configuration element. + // This time we should get 'true'. + audit_entry.reset(new AuditEntry("my_object_type", 5678, + AuditEntry::ModificationType::CREATE, + "added audit entry")); + audit_entries.insert(audit_entry); + EXPECT_TRUE(cb_ctl_.fetchConfigElement(audit_entries, "my_object_type")); + + // Also we should get 'true' for the UPDATE case. + audit_entry.reset(new AuditEntry("another_object_type", + 5678, AuditEntry::ModificationType::UPDATE, + "added audit entry")); + audit_entries.insert(audit_entry); + EXPECT_TRUE(cb_ctl_.fetchConfigElement(audit_entries, "another_object_type")); +} + // This test verifies that true is return when the server successfully // connects to the backend and false if there are no backends to connect // to. -- 2.47.2