From 4494d6f283ff74ff1bd7a1fdb02cb1277ca7503c Mon Sep 17 00:00:00 2001 From: Barthelemy Date: Thu, 18 Nov 2021 13:44:31 +0100 Subject: [PATCH 1/3] [QC-652] Add a method to update the metadata of an object. --- CCDB/include/CCDB/CcdbApi.h | 2 ++ CCDB/src/CcdbApi.cxx | 39 ++++++++++++++++++++ CCDB/test/testCcdbApi.cxx | 71 ++++++++++++++++++++++++++++++++----- 3 files changed, 104 insertions(+), 8 deletions(-) diff --git a/CCDB/include/CCDB/CcdbApi.h b/CCDB/include/CCDB/CcdbApi.h index 207644bd1b8f9..498387444db40 100644 --- a/CCDB/include/CCDB/CcdbApi.h +++ b/CCDB/include/CCDB/CcdbApi.h @@ -180,6 +180,8 @@ class CcdbApi //: public DatabaseInterface */ void deleteObject(std::string const& path, long timestamp = -1) const; + void updateMetadata(std::string const& path, std::map const& metadata, long timestamp, std::string const& id = ""); + /** * Return the listing of objects, and in some cases subfolders, matching this path. * The path can contain sql patterns (correctly encoded) or regexps. diff --git a/CCDB/src/CcdbApi.cxx b/CCDB/src/CcdbApi.cxx index 14a1924769f5e..b344991f4ee8b 100644 --- a/CCDB/src/CcdbApi.cxx +++ b/CCDB/src/CcdbApi.cxx @@ -1339,5 +1339,44 @@ TClass* CcdbApi::tinfo2TClass(std::type_info const& tinfo) return cl; } +void CcdbApi::updateMetadata(std::string const& path, std::map const& metadata, long timestamp, std::string const& id) +{ + CURL* curl; + CURLcode res; + stringstream fullUrl; + fullUrl << mUrl << "/" << path << "/" << timestamp; + if(!id.empty()) { + fullUrl << "/" << id; + } + fullUrl << "?"; + + curl = curl_easy_init(); + + for (auto& kv : metadata) { + string mfirst = kv.first; + string msecond = kv.second; + // same trick for the metadata as for the object type + char* mfirstEncoded = curl_easy_escape(curl, mfirst.c_str(), mfirst.size()); + char* msecondEncoded = curl_easy_escape(curl, msecond.c_str(), msecond.size()); + fullUrl << string(mfirstEncoded) + "=" + string(msecondEncoded) + "&"; + curl_free(mfirstEncoded); + curl_free(msecondEncoded); + } + + if (curl != nullptr) { + curl_easy_setopt(curl, CURLOPT_URL, fullUrl.str().c_str()); + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT"); // make sure we use PUT + + curlSetSSLOptions(curl); + + // Perform the request, res will get the return code + res = curl_easy_perform(curl); + if (res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + } + curl_easy_cleanup(curl); + } +} + } // namespace ccdb } // namespace o2 diff --git a/CCDB/test/testCcdbApi.cxx b/CCDB/test/testCcdbApi.cxx index b9ffe59c19500..fa3f839281f6c 100644 --- a/CCDB/test/testCcdbApi.cxx +++ b/CCDB/test/testCcdbApi.cxx @@ -24,22 +24,14 @@ #include "CCDB/CCDBTimeStampUtils.h" #include #include -#include -#include #include -#include -#include -#include -#include #include #include #include -#include #include #include #include #include -#include #include #include @@ -479,3 +471,66 @@ BOOST_AUTO_TEST_CASE(TestRetrieveHeaders, *utf::precondition(if_reachable())) } BOOST_CHECK_EQUAL(headers.size(), 0); } + +BOOST_AUTO_TEST_CASE(TestUpdateMetadata, *utf::precondition(if_reachable())) +{ + test_fixture f; + + // upload an object + TH1F h1("object1", "object1", 100, 0, 99); + cout << "storing object 1 in " << basePath << "Test" << endl; + map metadata; + metadata["custom"] = "whatever"; + metadata["id"] = "first"; + f.api.storeAsTFile(&h1, basePath + "Test", metadata); + + // retrieve the headers just to be sure + std::map headers = f.api.retrieveHeaders(basePath + "Test", metadata); + BOOST_CHECK(headers.count("custom") > 0); + BOOST_CHECK(headers.at("custom") == "whatever"); + string firstID = headers.at("ETag"); + firstID.erase(std::remove(firstID.begin(), firstID.end(), '"'), firstID.end()); + + map newMetadata; + newMetadata["custom"] = "somethingelse"; + + // update the metadata and check + f.api.updateMetadata(basePath + "Test", newMetadata, o2::ccdb::getCurrentTimestamp()); + headers = f.api.retrieveHeaders(basePath + "Test", newMetadata); + BOOST_CHECK(headers.count("custom") > 0); + BOOST_CHECK(headers.at("custom") == "somethingelse"); + + // add a second object + cout << "storing object 2 in " << basePath << "Test" << endl; + metadata.clear(); + metadata["custom"] = "whatever"; + metadata["id"] = "second"; + f.api.storeAsTFile(&h1, basePath + "Test", metadata); + + // get id + cout << "get id" << endl; + headers = f.api.retrieveHeaders(basePath + "Test", metadata); + string secondID = headers.at("ETag"); + secondID.erase(std::remove(secondID.begin(), secondID.end(), '"'), secondID.end()); + + // update the metadata by id + cout << "update the metadata by id" << endl; + newMetadata.clear(); + newMetadata["custom"] = "first"; + f.api.updateMetadata(basePath + "Test", newMetadata, o2::ccdb::getCurrentTimestamp(), firstID); + newMetadata.clear(); + newMetadata["custom"] = "second"; + f.api.updateMetadata(basePath + "Test", newMetadata, o2::ccdb::getCurrentTimestamp(), secondID); + + // check + metadata.clear(); + metadata["id"] = "first"; + headers = f.api.retrieveHeaders(basePath + "Test", metadata); + BOOST_CHECK(headers.count("custom") > 0); + BOOST_CHECK(headers.at("custom") == "first"); + metadata.clear(); + metadata["id"] = "second"; + headers = f.api.retrieveHeaders(basePath + "Test", metadata); + BOOST_CHECK(headers.count("custom") > 0); + BOOST_CHECK(headers.at("custom") == "second"); +} From 1860355b1d05a3d6f40d8322bd6ac35c953b9e11 Mon Sep 17 00:00:00 2001 From: Barthelemy Date: Thu, 18 Nov 2021 13:46:29 +0100 Subject: [PATCH 2/3] Add missing doxy --- CCDB/include/CCDB/CcdbApi.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CCDB/include/CCDB/CcdbApi.h b/CCDB/include/CCDB/CcdbApi.h index 498387444db40..3586003822849 100644 --- a/CCDB/include/CCDB/CcdbApi.h +++ b/CCDB/include/CCDB/CcdbApi.h @@ -180,6 +180,13 @@ class CcdbApi //: public DatabaseInterface */ void deleteObject(std::string const& path, long timestamp = -1) const; + /** + * Update the metadata of the object defined by the provided timestamp, and id if provided. + * @param path Path to the object to update + * @param metadata The metadata to update + * @param timestamp The timestamp to select the object + * @param id The id, if any, to select the object + */ void updateMetadata(std::string const& path, std::map const& metadata, long timestamp, std::string const& id = ""); /** From 2d457e373e380a4708d77f5c796eb979865eb82c Mon Sep 17 00:00:00 2001 From: Barthelemy Date: Thu, 18 Nov 2021 13:47:05 +0100 Subject: [PATCH 3/3] format --- CCDB/src/CcdbApi.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CCDB/src/CcdbApi.cxx b/CCDB/src/CcdbApi.cxx index b344991f4ee8b..fe47eb968684e 100644 --- a/CCDB/src/CcdbApi.cxx +++ b/CCDB/src/CcdbApi.cxx @@ -1345,7 +1345,7 @@ void CcdbApi::updateMetadata(std::string const& path, std::map