From a5231e08baa22a7c0145333c10395f825213da28 Mon Sep 17 00:00:00 2001 From: Sandro Wenzel Date: Tue, 18 Nov 2025 15:27:41 +0100 Subject: [PATCH] Custom member streamer for CalArray::mData This commit expands on https://github.com/AliceO2Group/AliceO2/pull/14427 and fixes the issue brought up in https://its.cern.ch/jira/browse/O2-4671. After debugging/testing it turns out that the approach taken via a customer streamer for std::vector does not take effect in the ROOT/IO because apparently ROOT still prefers to use the CollectionProxy for std::vector and does not employ the custom streamer. Instead, after discussion with @pcanal, this commit proposes to implement a custom stream just for the mData data member of CalArray. This is the only place where we use o2::tpc::PadFlags in IO and it fixes the problem when reading CCDB objects containing such data. I have verified that the following code ``` o2-ccdb-downloadccdbfile -p TPC/Calib/IDC_PadStatusMap_A -t 1731274461770 -d ./ -o tpc_idc.root --no-preserve-path root tpc_idc.root gFile->Get>("ccdb_object") ``` correctly executes the custom streamer function. Note that there is also no need to make the code ROOT version dependent. We need to fix the reading in any case and the writing will just stay the same. Concerning situations, where future classes will write data containing std::vector we should be protected by the fact that this bug has been fixed >= ROOT 6.36 in any case. This commit relates also to https://github.com/root-project/root/pull/17009 The commit also re-enables dictionary creation of related classes and adds a dictionary for CalArray previously missing. --- DataFormats/Detectors/TPC/CMakeLists.txt | 1 - .../Detectors/TPC/src/DataFormatsTPCLinkDef.h | 4 +- .../TPC/src/VectorPadflagsCustomStreamer.cxx | 56 ------------- Detectors/TPC/base/CMakeLists.txt | 1 + Detectors/TPC/base/src/TPCBaseLinkDef.h | 1 + .../base/src/TPCFlagsMemberCustomStreamer.cxx | 79 +++++++++++++++++++ 6 files changed, 83 insertions(+), 59 deletions(-) delete mode 100644 DataFormats/Detectors/TPC/src/VectorPadflagsCustomStreamer.cxx create mode 100644 Detectors/TPC/base/src/TPCFlagsMemberCustomStreamer.cxx diff --git a/DataFormats/Detectors/TPC/CMakeLists.txt b/DataFormats/Detectors/TPC/CMakeLists.txt index 5aed01a9772c1..2cc69e16001a6 100644 --- a/DataFormats/Detectors/TPC/CMakeLists.txt +++ b/DataFormats/Detectors/TPC/CMakeLists.txt @@ -40,7 +40,6 @@ o2_add_library( o2_target_root_dictionary( DataFormatsTPC - EXTRA_PATCH src/VectorPadflagsCustomStreamer.cxx HEADERS include/DataFormatsTPC/ClusterGroupAttribute.h include/DataFormatsTPC/ClusterNative.h include/DataFormatsTPC/ClusterNativeHelper.h diff --git a/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h b/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h index 8659e6a2e43eb..f463e9011c935 100644 --- a/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h +++ b/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h @@ -22,7 +22,7 @@ #pragma link C++ class o2::tpc::ClusterHardwareContainerFixedSize < 8192> + ; #pragma link C++ class o2::tpc::ClusterNativeContainer + ; #pragma link C++ class o2::tpc::Digit + ; -// pragma link C++ enum o2::tpc::PadFlags +; // enum itself +#pragma link C++ enum o2::tpc::PadFlags + ; // enum itself #pragma link C++ class o2::tpc::ZeroSuppressedContainer8kb + ; #pragma link C++ class std::vector < o2::tpc::ClusterNative> + ; #pragma link C++ class std::vector < o2::tpc::ClusterNativeContainer> + ; @@ -30,7 +30,7 @@ #pragma link C++ class std::vector < o2::tpc::ClusterHardwareContainerFixedSize < 8192>> + ; #pragma link C++ class std::vector < o2::tpc::ClusterHardwareContainer8kb> + ; #pragma link C++ class std::vector < o2::tpc::Digit> + ; -// pragma link C++ class std::vector < o2::tpc::PadFlags> + ; +#pragma link C++ class std::vector < o2::tpc::PadFlags> + ; #pragma link C++ class std::vector < o2::tpc::ZeroSuppressedContainer8kb> + ; #pragma link C++ class o2::tpc::TrackTPC + ; #pragma link C++ class o2::tpc::LaserTrack + ; diff --git a/DataFormats/Detectors/TPC/src/VectorPadflagsCustomStreamer.cxx b/DataFormats/Detectors/TPC/src/VectorPadflagsCustomStreamer.cxx deleted file mode 100644 index f7cb9285b8884..0000000000000 --- a/DataFormats/Detectors/TPC/src/VectorPadflagsCustomStreamer.cxx +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2019-2025 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -using std::vector; - -void VectorPadFlagsStreamer(TBuffer& R__b, void* objp) -{ - std::vector* obj = static_cast*>(objp); - if (R__b.IsReading()) { - std::vector R__stl; - R__stl.clear(); - int R__n; - R__b >> R__n; - R__stl.reserve(R__n); - for (int R__i = 0; R__i < R__n; R__i++) { - Int_t readtemp; - R__b >> readtemp; - R__stl.push_back(readtemp); - } - auto data = reinterpret_cast(R__stl.data()); - for (int i = 0; i < R__n; ++i) { - obj->push_back(static_cast(data[i])); - } - } else { - // We always save things with the old format. - R__b << (int)obj->size() / 2; - for (size_t i = 0; i < obj->size(); i++) { - R__b << (short)obj->at(i); - } - } -} - -#define RootStreamerLocal(name, STREAMER) \ - namespace ROOT \ - { \ - \ - /** \cond HIDDEN_SYMBOLS */ \ - static auto _R__UNIQUE_(R__dummyStreamer) = \ - []() { TClass::GetClass()->SetStreamerFunc(STREAMER); return 0; }(); \ - /** \endcond */ \ - R__UseDummy(_R__UNIQUE_(R__dummyStreamer)); \ - } - -// Let's not try to fix the old ROOT version, so that we can build -// the new ROOT with the patched code in the CI. -#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 33, 00) -RootStreamerLocal(vector, VectorPadFlagsStreamer); -#endif diff --git a/Detectors/TPC/base/CMakeLists.txt b/Detectors/TPC/base/CMakeLists.txt index d4c1bc4602d54..8c796d7e4ff13 100644 --- a/Detectors/TPC/base/CMakeLists.txt +++ b/Detectors/TPC/base/CMakeLists.txt @@ -43,6 +43,7 @@ o2_add_library(TPCBase O2::DetectorsRaw O2::CCDB FairRoot::Base) o2_target_root_dictionary(TPCBase + EXTRA_PATCH src/TPCFlagsMemberCustomStreamer.cxx HEADERS include/TPCBase/CalArray.h include/TPCBase/CalDet.h include/TPCBase/CDBInterface.h diff --git a/Detectors/TPC/base/src/TPCBaseLinkDef.h b/Detectors/TPC/base/src/TPCBaseLinkDef.h index 60924db3953e2..4fdde1ca55518 100644 --- a/Detectors/TPC/base/src/TPCBaseLinkDef.h +++ b/Detectors/TPC/base/src/TPCBaseLinkDef.h @@ -21,6 +21,7 @@ #pragma link C++ class o2::tpc::CalArray < unsigned> + ; #pragma link C++ class o2::tpc::CalArray < short> + ; #pragma link C++ class o2::tpc::CalArray < bool> + ; +#pragma link C++ class o2::tpc::CalArray < o2::tpc::PadFlags> + ; #pragma link C++ class o2::tpc::CalDet < float> + ; #pragma link C++ class o2::tpc::CalDet < double> + ; #pragma link C++ class o2::tpc::CalDet < int> + ; diff --git a/Detectors/TPC/base/src/TPCFlagsMemberCustomStreamer.cxx b/Detectors/TPC/base/src/TPCFlagsMemberCustomStreamer.cxx new file mode 100644 index 0000000000000..1dfb775a14aaa --- /dev/null +++ b/Detectors/TPC/base/src/TPCFlagsMemberCustomStreamer.cxx @@ -0,0 +1,79 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TPCBase/CalArray.h" +#include +#include +#include +#include + +// to enable assert statements +#ifdef NDEBUG +#undef NDEBUG +#include +#endif + +// The following code provides a specific ROOT I/O streaming method +// for the mData member of CalArray +// This member was written incorrectly to the TFile in ROOT versions < 6.36, causing +// segfaults when reading on ARM64 (occassionally). +// We continue to write it in the incorrect format and fix the reading back. + +// See also: +// - https://github.com/root-project/root/pull/17009 +// - https://its.cern.ch/jira/browse/O2-4671 + +void MemberVectorPadFlagsStreamer(TBuffer& R__b, void* objp, int n) +{ + if (n != 1) { + std::cerr << "Error in MemberVectorPadFlagsStreamer : Unexpected n " << n << std::endl; + return; + } + std::vector* obj = static_cast*>(objp); + if (R__b.IsReading()) { + std::vector R__stl; + R__stl.clear(); + int R__n; + R__b >> R__n; + R__stl.reserve(R__n); + for (int R__i = 0; R__i < R__n; R__i++) { + Int_t readtemp; + R__b >> readtemp; + R__stl.push_back(readtemp); + } + auto data = reinterpret_cast(R__stl.data()); + for (int i = 0; i < R__n; ++i) { + obj->push_back(static_cast(data[i])); + } + } else { + // We always save things with the old format. + R__b << (int)obj->size() / 2; + for (size_t i = 0; i < obj->size(); i++) { + R__b << (short)obj->at(i); + } + } +} + +// register the streamer via static global initialization (on library load) +namespace ROOT +{ +static __attribute__((used)) int _R__dummyStreamer_3 = + ([]() { + auto cl = TClass::GetClass>(); + if (cl) { + cl->AdoptMemberStreamer("mData", new TMemberStreamer(MemberVectorPadFlagsStreamer)); + } else { + // we should never come here ... and if we do we should assert/fail + assert(false); + } + return 0; + })(); +} // namespace ROOT