Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CCDB/src/CcdbApi.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@
#include <string_view>
#include <utility>
#include <TAlienUserAgent.h>
#if defined(_LIBCPP_VERSION)
#include "Framework/DataRefUtils.h"
#endif
#include <unordered_set>
#include "rapidjson/document.h"
#include "rapidjson/writer.h"
Expand Down Expand Up @@ -986,6 +989,9 @@ void* CcdbApi::extractFromTFile(TFile& file, TClass const* cl, const char* what)
if (!cl) {
return nullptr;
}
#if defined(_LIBCPP_VERSION)
o2::framework::DataRefUtils::registerLibstdcxxStdArray(file, cl);
#endif
auto object = file.GetObjectChecked(what, cl);
if (!object) {
// it could be that object was stored with previous convention
Expand Down
8 changes: 8 additions & 0 deletions Framework/Core/include/Framework/DataRefUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ namespace o2::conf
{
class ConfigurableParam;
}
#if defined(_LIBCPP_VERSION)
class TClass;
class TFile;
#endif

namespace o2::framework
{
Expand Down Expand Up @@ -185,6 +189,10 @@ struct DataRefUtils {
// Decode a CCDB object using the CcdbApi.
static void* decodeCCDB(DataRef const& ref, std::type_info const& info);
static std::map<std::string, std::string> extractCCDBHeaders(DataRef const& ref);
#if defined(_LIBCPP_VERSION)
/// Make a std::array<T,N> written with libstdc++ readable from file by this libc++ build.
static void registerLibstdcxxStdArray(TFile& file, TClass const* cl);
#endif
/// Return a span over the raw CCDB payload bytes, stripping the flattened HTTP
/// headers footer that CCDBFetcherHelper appends. Use this when the CCDB entry is
/// a binary blob rather than a ROOT-serialised object.
Expand Down
39 changes: 39 additions & 0 deletions Framework/Core/src/DataRefUtils.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
#include <TH1.h>
#include <TError.h>
#include <algorithm>
#if defined(_LIBCPP_VERSION)
#include <TList.h>
#include <TStreamerElement.h>
#include <TStreamerInfo.h>
#endif

namespace o2::framework
{
Expand All @@ -31,6 +36,9 @@ void* extractFromTFile(TFile& file, TClass const* cl, const char* what)
if (!cl) {
return nullptr;
}
#if defined(_LIBCPP_VERSION)
DataRefUtils::registerLibstdcxxStdArray(file, cl);
#endif
auto object = file.GetObjectChecked(what, cl);
if (!object) {
// it could be that object was stored with previous convention
Expand Down Expand Up @@ -73,6 +81,37 @@ void* extractFromTFile(TFile& file, TClass const* cl, const char* what)
return result;
}
} // namespace

#if defined(_LIBCPP_VERSION)
// The only member of std::array<T,N> is T _M_elems[N] in libstdc++, T __elems_[N] in libc++, so
// objects written on Linux carry a StreamerInfo with a checksum the libc++ class does not have.
// When opening the file, ROOT drops that StreamerInfo as an alias of the in-memory one
// (TStreamerInfo::BuildCheck), and the read fails with "Could not find the StreamerInfo with a
// checksum", leaving the array zero-filled. Register the on-file layout as a version of its own,
// under the in-memory member name, so that the payload, T[N] for both, is read as usual.
void DataRefUtils::registerLibstdcxxStdArray(TFile& file, TClass const* cl)
{
auto* infos = std::strncmp(cl->GetName(), "array<", 6) == 0 ? file.GetStreamerInfoCache() : nullptr;
auto* onfile = infos ? dynamic_cast<TStreamerInfo*>(infos->FindObject(cl->GetName())) : nullptr;
if (!onfile || onfile->GetNelement() != 1 || std::strcmp(onfile->GetElement(0)->GetName(), "_M_elems") != 0) {
return;
}
// Exists before BuildCheck, so that the on-file layout gets a version of its own
auto* current = static_cast<TStreamerInfo*>(const_cast<TClass*>(cl)->GetStreamerInfo());
auto* info = static_cast<TStreamerInfo*>(cl->FindStreamerInfo(onfile->GetCheckSum()));
if (!info) {
info = static_cast<TStreamerInfo*>(onfile->Clone());
info->BuildCheck(&file);
}
// Also when ROOT registered it itself: it then reads nothing, without any error
if (std::strcmp(info->GetElement(0)->GetName(), current->GetElement(0)->GetName()) != 0) {
info->GetElement(0)->SetName(current->GetElement(0)->GetName());
info->Clear("build");
info->BuildOld();
}
}
#endif

// Adapted from CcdbApi private method interpretAsTMemFileAndExtract
// If the former is moved to public, throws on error and could be changed to
// not require a mutex we could use it.
Expand Down
Loading