Skip to content

Commit 80f2bea

Browse files
authored
Extending the CCDB API to optionally get the headers from first HTTP request (#14709)
* Extend CCDB functions with optional headers * Remove the header filtering & add more tests * Fix code snippets and enhance metadata retrieval documentation Updated code snippets in README for header retrieval and added optional parameter documentation details. Also fixed some CI formatting errors. * Change unit test with to have correct includes
1 parent 8e0e840 commit 80f2bea

File tree

6 files changed

+466
-21
lines changed

6 files changed

+466
-21
lines changed

CCDB/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ o2_add_test(CcdbDownloader
9292
PUBLIC_LINK_LIBRARIES O2::CCDB
9393
LABELS ccdb)
9494

95+
o2_add_test(CcdbApi-Headers
96+
SOURCES test/testCcdbApiHeaders.cxx
97+
COMPONENT_NAME ccdb
98+
PUBLIC_LINK_LIBRARIES O2::CCDB
99+
LABELS ccdb)
100+
95101
# extra CcdbApi test which dispatches to CCDBDownloader (tmp until full move done)
96102
#o2_add_test_command(NAME CcdbApi-MultiHandle
97103
# WORKING_DIRECTORY ${SIMTESTDIR}

CCDB/README.md

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ in circumstances of reduced or no network connectivity.
1313

1414
There are currently 2 different kinds of store/retrieve functions, which we expect to unify in the immediate future:
1515
2. `storeAsTFile/retrieveFromTFile` API serializing a `TObject` in a ROOT `TFile`.
16-
3. A strongly-typed `storeAsTFileAny<T>/retrieveFromTFileAny<T>` API allowing to handle any type T
16+
3. A strongly-typed `storeAsTFileAny<T>/retrieveFromTFileAny<T>` API allowing to handle any type T
1717
having a ROOT dictionary. We encourage to use this API by default.
1818

1919
## Central and local instances of the CCDB
@@ -37,12 +37,12 @@ api.init("http://ccdb-test.cern.ch:8080"); // or http://localhost:8080 for a loc
3737
auto deadpixels = new o2::FOO::DeadPixelMap();
3838
api.storeAsTFileAny(deadpixels, "FOO/DeadPixels", metadata);
3939
// read like this (you have to specify the type)
40-
auto deadpixelsback = api.retrieveFromTFileAny<o2::FOO::DeadPixelMap>("FOO/DeadPixels", metadata);
41-
// read like this to get the headers as well, and thus the metadata attached to the object
40+
auto deadpixelsback = api.retrieveFromTFileAny<o2::FOO::DeadPixelMap>("FOO/DeadPixels", metadata);
41+
// read like this to get the headers as well, and thus the metadata attached to the object
4242
std::map<std::string, std::string> headers;
43-
auto deadpixelsback = api.retrieveFromTFileAny<o2::FOO::DeadPixelMap>("FOO/DeadPixels", metadata /* constraint the objects retrieved to those matching the metadata */, -1 /* timestamp */, &headers /* the headers attached to the returned object */);
43+
auto deadpixelsback = api.retrieveFromTFileAny<o2::FOO::DeadPixelMap>("FOO/DeadPixels", metadata /* constraint the objects retrieved to those matching the metadata */, -1 /* timestamp */, &headers /* the headers attached to the returned object */);
4444
// finally, use this method to retrieve only the headers (and thus the metadata)
45-
std::map<std::string, std::string> headers = f.api.retrieveHeaders("FOO/DeadPixels", f.metadata);
45+
std::map<std::string, std::string> headers = api.retrieveHeaders("FOO/DeadPixels", metadata);
4646
```
4747

4848
* creating a local snapshot and fetching objects therefrom
@@ -85,7 +85,7 @@ user code. This class
8585
The class was written for the use-case of transport MC simulation. Typical usage should be like
8686

8787
```c++
88-
// setup manager once (at start of processing)
88+
// setup manager once (at start of processing)
8989
auto& mgr = o2::ccdb::BasicCCDBManager::instance();
9090
mgr.setURL("http://ourccdbserverver.cern.ch");
9191
mgr.setTimestamp(timestamp_which_we_want_to_anchor_to);
@@ -111,6 +111,12 @@ This feature is useful to avoid using newer objects if the CCDB is updated in pa
111111

112112
In cached mode, the manager can check that local objects are still valid by requiring `mgr.setLocalObjectValidityChecking(true)`, in this case a CCDB query is performed only if the cached object is no longer valid.
113113

114+
If you want the headers/metadata for the object retrieved from the CCDB there is an optional paramater to `BasicCCDBManager::getForTimeStamp`. These headers are also cached (when caching is enabled) and is updated when a CCDB query is sent.
115+
```c++
116+
std::map<std::string,std::string> headers;
117+
mgr.getForTimeStamp(path, timstamp, metadata, &headers);
118+
```
119+
114120
## Future ideas / todo:
115121

116122
- [ ] offer improved error handling / exceptions
@@ -129,26 +135,26 @@ A few prototypic command line tools are offered. These can be used in scriptable
129135
and facilitate the following tasks:
130136

131137
1. Upload and annotate a generic C++ object serialized in a ROOT file
132-
138+
133139
```bash
134140
o2-ccdb-upload -f myRootFile.root --key histogram1 --path /Detector1/QA/ --meta "Description=Foo;Author=Person1;Uploader=Person2"
135141
```
136142
This will upload the object serialized in `myRootFile.root` under the key `histogram1`. Object will be put to the CCDB path `/Detector1/QA`.
137143
For full list of options see `o2-ccdb-upload --help`.
138-
144+
139145
2. Download a CCDB object to a local ROOT file (including its meta information)
140-
146+
141147
```bash
142148
o2-ccdb-downloadccdbfile --path /Detector1/QA/ --dest /tmp/CCDB --timestamp xxx
143149
```
144150
This will download the CCDB object under path given by `--path` to a directory given by `--dest` on the disc.
145151
(The final filename will be `/tmp/CCDB/Detector1/QA/snapshot.root` for the moment).
146152
All meta-information as well as the information associated to this query will be appended to the file.
147-
153+
148154
For full list of options see `o2-ccdb-downloadccdbfile --help`.
149-
155+
150156
3. Inspect the content of a ROOT file and print summary about type of contained (CCDB) objects and its meta information
151-
157+
152158
```bash
153159
o2-ccdb-inspectccdbfile filename
154160
```

CCDB/include/CCDB/BasicCCDBManager.h

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <string>
2424
#include <chrono>
2525
#include <map>
26+
#include <string_view>
2627
#include <unordered_map>
2728
#include <memory>
2829
#include <cstdlib>
@@ -57,6 +58,7 @@ class CCDBManagerInstance
5758
int queries = 0;
5859
int fetches = 0;
5960
int failures = 0;
61+
std::map<std::string, std::string> cacheOfHeaders;
6062
bool isValid(long ts) { return ts < endvalidity && ts >= startvalidity; }
6163
bool isCacheValid(long ts)
6264
{
@@ -70,6 +72,7 @@ class CCDBManagerInstance
7072
uuid = "";
7173
startvalidity = 0;
7274
endvalidity = -1;
75+
cacheOfHeaders.clear();
7376
}
7477
};
7578

@@ -98,9 +101,9 @@ class CCDBManagerInstance
98101
/// query timestamp
99102
long getTimestamp() const { return mTimestamp; }
100103

101-
/// retrieve an object of type T from CCDB as stored under path and timestamp
104+
/// retrieve an object of type T from CCDB as stored under path and timestamp. Optional to get the headers.
102105
template <typename T>
103-
T* getForTimeStamp(std::string const& path, long timestamp);
106+
T* getForTimeStamp(std::string const& path, long timestamp, std::map<std::string, std::string>* headers = nullptr);
104107

105108
/// retrieve an object of type T from CCDB as stored under path and using the timestamp in the middle of the run
106109
template <typename T>
@@ -112,10 +115,7 @@ class CCDBManagerInstance
112115
{
113116
// TODO: add some error info/handling when failing
114117
mMetaData = metaData;
115-
auto obj = getForTimeStamp<T>(path, timestamp);
116-
if (headers) {
117-
*headers = mHeaders;
118-
}
118+
auto obj = getForTimeStamp<T>(path, timestamp, headers);
119119
return obj;
120120
}
121121

@@ -235,7 +235,7 @@ class CCDBManagerInstance
235235
};
236236

237237
template <typename T>
238-
T* CCDBManagerInstance::getForTimeStamp(std::string const& path, long timestamp)
238+
T* CCDBManagerInstance::getForTimeStamp(std::string const& path, long timestamp, std::map<std::string, std::string>* headers)
239239
{
240240
mHeaders.clear(); // we clear at the beginning; to allow to retrieve the header information in a subsequent call
241241
T* ptr = nullptr;
@@ -258,15 +258,32 @@ T* CCDBManagerInstance::getForTimeStamp(std::string const& path, long timestamp)
258258
mFetchedSize += s;
259259
}
260260
}
261+
262+
if (headers) {
263+
*headers = mHeaders;
264+
}
261265
} else {
262266
auto& cached = mCache[path];
263267
cached.queries++;
264268
if ((!isOnline() && cached.isCacheValid(timestamp)) || (mCheckObjValidityEnabled && cached.isValid(timestamp))) {
269+
// Give back the cached/saved headers
270+
if (headers) {
271+
*headers = cached.cacheOfHeaders;
272+
}
265273
return reinterpret_cast<T*>(cached.noCleanupPtr ? cached.noCleanupPtr : cached.objPtr.get());
266274
}
267275
ptr = mCCDBAccessor.retrieveFromTFileAny<T>(path, mMetaData, timestamp, &mHeaders, cached.uuid,
268276
mCreatedNotAfter ? std::to_string(mCreatedNotAfter) : "",
269277
mCreatedNotBefore ? std::to_string(mCreatedNotBefore) : "");
278+
// update the cached headers
279+
for (auto const& h : mHeaders) {
280+
cached.cacheOfHeaders[h.first] = h.second;
281+
}
282+
// return the cached headers
283+
if (headers) {
284+
*headers = cached.cacheOfHeaders;
285+
}
286+
270287
if (ptr) { // new object was shipped, old one (if any) is not valid anymore
271288
cached.fetches++;
272289
mFetches++;

CCDB/include/CCDB/CcdbApi.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ class CcdbApi //: public DatabaseInterface
281281
* @return: True in case operation successful or false if there was a failure/problem.
282282
*/
283283
bool retrieveBlob(std::string const& path, std::string const& targetdir, std::map<std::string, std::string> const& metadata, long timestamp,
284-
bool preservePathStructure = true, std::string const& localFileName = "snapshot.root", std::string const& createdNotAfter = "", std::string const& createdNotBefore = "") const;
284+
bool preservePathStructure = true, std::string const& localFileName = "snapshot.root", std::string const& createdNotAfter = "", std::string const& createdNotBefore = "", std::map<std::string, std::string>* headers = nullptr) const;
285285

286286
/**
287287
* Retrieve the headers of a CCDB entry, if it exists.

CCDB/src/CcdbApi.cxx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,7 @@ TObject* CcdbApi::retrieveFromTFile(std::string const& path, std::map<std::strin
835835
}
836836

837837
bool CcdbApi::retrieveBlob(std::string const& path, std::string const& targetdir, std::map<std::string, std::string> const& metadata,
838-
long timestamp, bool preservePath, std::string const& localFileName, std::string const& createdNotAfter, std::string const& createdNotBefore) const
838+
long timestamp, bool preservePath, std::string const& localFileName, std::string const& createdNotAfter, std::string const& createdNotBefore, std::map<std::string, std::string>* outHeaders) const
839839
{
840840

841841
// we setup the target path for this blob
@@ -883,6 +883,9 @@ bool CcdbApi::retrieveBlob(std::string const& path, std::string const& targetdir
883883
CCDBQuery querysummary(path, metadata, timestamp);
884884

885885
updateMetaInformationInLocalFile(targetpath.c_str(), &headers, &querysummary);
886+
if (outHeaders) {
887+
*outHeaders = std::move(headers);
888+
}
886889
return true;
887890
}
888891

0 commit comments

Comments
 (0)