Skip to content

Commit

Permalink
Add a metadata service and a test (#215)
Browse files Browse the repository at this point in the history
  • Loading branch information
jmcarcell committed Aug 8, 2024
1 parent 9548b64 commit bcb3f15
Show file tree
Hide file tree
Showing 16 changed files with 579 additions and 15 deletions.
15 changes: 15 additions & 0 deletions k4FWCore/components/IOSvc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "GaudiKernel/AnyDataWrapper.h"
#include "GaudiKernel/IEventProcessor.h"

#include <algorithm>
#include <mutex>
#include <tuple>

Expand Down Expand Up @@ -63,6 +64,20 @@ StatusCode IOSvc::initialize() {
return StatusCode::FAILURE;
}

m_metadataSvc = service("MetadataSvc");
if (!m_metadataSvc) {
error() << "Unable to locate the MetadataSvc" << endmsg;
return StatusCode::FAILURE;
}
if (m_reader) {
auto categories = m_reader->getAvailableCategories();
if (std::find(categories.begin(), categories.end(), podio::Category::Metadata) != categories.end() &&
m_reader->getEntries(podio::Category::Metadata) > 0) {
info() << "Setting metadata frame" << endmsg;
m_metadataSvc->setFrame(m_reader->readEntry(podio::Category::Metadata, 0));
}
}

m_hiveWhiteBoard = service("EventDataSvc");

return StatusCode::SUCCESS;
Expand Down
2 changes: 2 additions & 0 deletions k4FWCore/components/IOSvc.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "podio/ROOTWriter.h"

#include "IIOSvc.h"
#include "k4FWCore/IMetadataSvc.h"
#include "k4FWCore/KeepDropSwitch.h"

#include <string>
Expand Down Expand Up @@ -85,6 +86,7 @@ class IOSvc : public extends<Service, IIOSvc, IIncidentListener> {
SmartIF<IDataProviderSvc> m_dataSvc;
SmartIF<IIncidentSvc> m_incidentSvc;
SmartIF<IHiveWhiteBoard> m_hiveWhiteBoard;
SmartIF<IMetadataSvc> m_metadataSvc;
void handle(const Incident& incident) override;

int m_entries{0};
Expand Down
49 changes: 49 additions & 0 deletions k4FWCore/components/MetadataSvc.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2014-2024 Key4hep-Project.
*
* This file is part of Key4hep.
* See https://key4hep.github.io/key4hep-doc/ for further info.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "MetadataSvc.h"

#include "podio/Frame.h"

#include <GaudiKernel/AnyDataWrapper.h>
#include <GaudiKernel/IDataProviderSvc.h>
#include <GaudiKernel/Service.h>

StatusCode MetadataSvc::initialize() {
StatusCode sc = Service::initialize();
if (sc.isFailure()) {
error() << "Unable to initialize base class Service." << endmsg;
return sc;
}
m_dataSvc = service("EventDataSvc");
if (!m_dataSvc) {
error() << "Unable to locate the EventDataSvc" << endmsg;
return StatusCode::FAILURE;
}

m_frame.reset(new podio::Frame());

return StatusCode::SUCCESS;
}

StatusCode MetadataSvc::finalize() { return Service::finalize(); }

void MetadataSvc::setFrame(podio::Frame&& fr) { m_frame.reset(new podio::Frame(std::move(fr))); }

DECLARE_COMPONENT(MetadataSvc)
46 changes: 46 additions & 0 deletions k4FWCore/components/MetadataSvc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2014-2024 Key4hep-Project.
*
* This file is part of Key4hep.
* See https://key4hep.github.io/key4hep-doc/ for further info.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FWCORE_METADATASVC_H
#define FWCORE_METADATASVC_H

#include "GaudiKernel/IDataProviderSvc.h"
#include "GaudiKernel/Service.h"

#include "podio/Frame.h"

#include "k4FWCore/IMetadataSvc.h"

class MetadataSvc : public extends<Service, IMetadataSvc> {
using extends::extends;

public:
~MetadataSvc() override = default;

StatusCode initialize() override;
StatusCode finalize() override;

protected:
SmartIF<IDataProviderSvc> m_dataSvc;

std::unique_ptr<podio::Frame> m_frame;

void setFrame(podio::Frame&& frame) override;
};

#endif
13 changes: 13 additions & 0 deletions k4FWCore/components/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include "k4FWCore/DataWrapper.h"
#include "k4FWCore/FunctionalUtils.h"
#include "k4FWCore/IMetadataSvc.h"

#include <GaudiKernel/IHiveWhiteBoard.h>
#include <memory>
Expand All @@ -53,6 +54,7 @@ class Writer final : public Gaudi::Functional::Consumer<void(const EventContext&
ServiceHandle<IIOSvc> iosvc{this, "IOSvc", "IOSvc"};
SmartIF<IHiveWhiteBoard> m_hiveWhiteBoard;
SmartIF<IDataProviderSvc> m_dataSvc;
SmartIF<IMetadataSvc> m_metadataSvc;
mutable bool m_first{true};

StatusCode initialize() override {
Expand All @@ -74,6 +76,12 @@ class Writer final : public Gaudi::Functional::Consumer<void(const EventContext&
<< endmsg;
}

m_metadataSvc = service("MetadataSvc", false);
if (!m_metadataSvc) {
error() << "Unable to locate MetadataSvc service" << endmsg;
return StatusCode::FAILURE;
}

return StatusCode::SUCCESS;
}

Expand Down Expand Up @@ -113,7 +121,12 @@ class Writer final : public Gaudi::Functional::Consumer<void(const EventContext&
}
iosvc->getWriter()->writeFrame(config_metadata_frame, "configuration_metadata");

if (m_metadataSvc->m_frame) {
iosvc->getWriter()->writeFrame(*std::move(m_metadataSvc->m_frame), podio::Category::Metadata);
}

iosvc->deleteWriter();

return StatusCode::SUCCESS;
}

Expand Down
42 changes: 42 additions & 0 deletions k4FWCore/include/k4FWCore/IMetadataSvc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2014-2024 Key4hep-Project.
*
* This file is part of Key4hep.
* See https://key4hep.github.io/key4hep-doc/ for further info.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FWCORE_IMETADATASERVICE_H
#define FWCORE_IMETADATASERVICE_H

#include "GaudiKernel/IInterface.h"

#include "podio/Frame.h"

class IMetadataSvc : virtual public IInterface {
public:
DeclareInterfaceID(IMetadataSvc, 1, 0);

std::unique_ptr<podio::Frame> m_frame;

virtual void setFrame(podio::Frame&& fr) = 0;
template <typename T> void put(const std::string& name, const T& obj) {
if (!m_frame) {
m_frame.reset(new podio::Frame());
}
m_frame->putParameter(name, obj);
}
template <typename T> std::optional<T> get(const std::string& name) { return m_frame->getParameter<T>(name); }
};

#endif
45 changes: 33 additions & 12 deletions k4FWCore/include/k4FWCore/MetaDataHandle.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
#ifndef K4FWCORE_METADATAHANDLE_H
#define K4FWCORE_METADATAHANDLE_H

#include <GaudiKernel/DataHandle.h>

#include "k4FWCore/MetadataUtils.h"
#include "k4FWCore/PodioDataSvc.h"

template <typename T> class MetaDataHandle {
Expand Down Expand Up @@ -95,10 +98,17 @@ template <typename T> std::optional<T> MetaDataHandle<T>::get_optional() const {

//---------------------------------------------------------------------------
template <typename T> const T MetaDataHandle<T>::get() const {
const auto maybeVal = get_optional();
if (!maybeVal.has_value()) {
throw GaudiException("MetaDataHandle empty handle access",
"MetaDataHandle " + fullDescriptor() + " not (yet?) available", StatusCode::FAILURE);
std::optional<T> maybeVal;
// DataHandle based algorithms
if (m_podio_data_service) {
maybeVal = get_optional();
if (!maybeVal.has_value()) {
throw GaudiException("MetaDataHandle empty handle access",
"MetaDataHandle " + fullDescriptor() + " not (yet?) available", StatusCode::FAILURE);
}
// Functional algorithms
} else {
maybeVal = k4FWCore::getParameter<T>(fullDescriptor());
}
return maybeVal.value();
}
Expand All @@ -115,13 +125,20 @@ template <typename T> void MetaDataHandle<T>::put(T value) {
StatusCode::FAILURE);
// check whether we are in the proper State
// put is only allowed in the initalization
if (m_podio_data_service->targetFSMState() == Gaudi::StateMachine::RUNNING) {
throw GaudiException("MetaDataHandle policy violation", "Put cannot be used during the event loop",
StatusCode::FAILURE);

std::string full_descriptor = fullDescriptor();
// DataHandle based algorithms
if (m_podio_data_service) {
if (m_podio_data_service->targetFSMState() == Gaudi::StateMachine::RUNNING) {
throw GaudiException("MetaDataHandle policy violation", "Put cannot be used during the event loop",
StatusCode::FAILURE);
}
podio::Frame& frame = m_podio_data_service->getMetaDataFrame();
frame.putParameter(full_descriptor, value);
// Functional algorithms
} else {
k4FWCore::putParameter(full_descriptor, value);
}
std::string full_descriptor = fullDescriptor();
podio::Frame& frame = m_podio_data_service->getMetaDataFrame();
frame.putParameter(full_descriptor, value);
}

//---------------------------------------------------------------------------
Expand All @@ -145,8 +162,12 @@ template <typename T> void MetaDataHandle<T>::checkPodioDataSvc() {
if (cmd.find("genconf") != std::string::npos)
return;

if (nullptr == m_podio_data_service) {
std::cout << "ERROR: MetaDataHandles require the PodioDataSvc" << std::endl;
// The proper check would be the following:
// if (!m_podio_data_service && !Gaudi::svcLocator()->service<IMetadataSvc>("MetadataSvc")) {
// However, it seems there is always a service called "MetadataSvc" from Gaudi,
// so the check will always pass
if (!m_podio_data_service) {
std::cout << "Warning: MetaDataHandles require the PodioDataSvc (ignore if using IOSvc)" << std::endl;
}
}

Expand Down
74 changes: 74 additions & 0 deletions k4FWCore/include/k4FWCore/MetadataUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright (c) 2014-2024 Key4hep-Project.
*
* This file is part of Key4hep.
* See https://key4hep.github.io/key4hep-doc/ for further info.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FWCORE_METADATAUTILS_H
#define FWCORE_METADATAUTILS_H

#include <GaudiKernel/Service.h>
#include "Gaudi/Algorithm.h"

#include "k4FWCore/IMetadataSvc.h"

namespace k4FWCore {

/// @brief Save a metadata parameter in the metadata frame
/// @param name The name of the parameter
/// @param value The value of the parameter
/// @param alg The algorithm that is saving the parameter, typically "this"
template <typename T> void putParameter(const std::string& name, const T& value, const Gaudi::Algorithm* alg) {
auto metadataSvc = alg->service<IMetadataSvc>("MetadataSvc", false);
if (!metadataSvc) {
alg->error() << "MetadataSvc not found" << endmsg;
return;
}
metadataSvc->put<T>(name, value);
}
/// @brief Save a metadata parameter in the metadata frame. Overload for compatibility
/// with the MetadataHandle, don't use!
template <typename T> void putParameter(const std::string& name, const T& value) {
auto metadataSvc = Gaudi::svcLocator()->service<IMetadataSvc>("MetadataSvc", false);
if (!metadataSvc) {
std::cout << "MetadataSvc not found" << std::endl;
return;
}
return metadataSvc->put<T>(name, value);
}
/// @brief Get a metadata parameter from the metadata frame
/// @param name The name of the parameter
/// @param alg The algorithm that is saving the parameter, typically "this"
/// @return std::optional<T> The value of the parameter, if it exists or std::nullopt
template <typename T> std::optional<T> getParameter(const std::string& name, const Gaudi::Algorithm* alg) {
auto metadataSvc = alg->service<IMetadataSvc>("MetadataSvc", false);
if (!metadataSvc) {
alg->error() << "MetadataSvc not found" << endmsg;
return std::nullopt;
}
return metadataSvc->get<T>(name);
}
/// @brief Get a metadata parameter from the metadata frame. Overload for compatibility
/// with the MetadataHandle, don't use!
template <typename T> std::optional<T> getParameter(const std::string& name) {
auto metadataSvc = Gaudi::svcLocator()->service<IMetadataSvc>("MetadataSvc", false);
if (!metadataSvc) {
return std::nullopt;
}
return metadataSvc->get<T>(name);
}
} // namespace k4FWCore

#endif // FWCORE_METADATAUTILS_H
4 changes: 3 additions & 1 deletion python/k4FWCore/ApplicationMgr.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# limitations under the License.
#
from Configurables import ApplicationMgr as AppMgr
from Configurables import Reader, Writer, IOSvc, Gaudi__Sequencer
from Configurables import Reader, Writer, IOSvc, MetadataSvc, Gaudi__Sequencer
import os
from podio.root_io import Reader as PodioReader

Expand All @@ -39,6 +39,8 @@ def __init__(self, **kwargs):
self._mgr = AppMgr(**kwargs)

for conf in frozenset(self._mgr.allConfigurables.values()):
if isinstance(conf, MetadataSvc):
self._mgr.ExtSvc.append(conf)
if not isinstance(conf, IOSvc):
continue
props = conf.getPropertiesWithDescription()
Expand Down
Loading

0 comments on commit bcb3f15

Please sign in to comment.