Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:10:45

0001 /// \file ROOT/RMiniFile.hxx
0002 /// \ingroup NTuple ROOT7
0003 /// \author Jakob Blomer <jblomer@cern.ch>
0004 /// \date 2019-12-22
0005 /// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
0006 /// is welcome!
0007 
0008 /*************************************************************************
0009  * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers.               *
0010  * All rights reserved.                                                  *
0011  *                                                                       *
0012  * For the licensing terms see $ROOTSYS/LICENSE.                         *
0013  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
0014  *************************************************************************/
0015 
0016 #ifndef ROOT7_RMiniFile
0017 #define ROOT7_RMiniFile
0018 
0019 #include <ROOT/RError.hxx>
0020 #include <ROOT/RNTuple.hxx>
0021 #include <string_view>
0022 
0023 #include <cstdint>
0024 #include <cstdio>
0025 #include <memory>
0026 #include <string>
0027 
0028 class TCollection;
0029 class TFile;
0030 class TFileMergeInfo;
0031 
0032 namespace ROOT {
0033 
0034 namespace Internal {
0035 class RRawFile;
0036 }
0037 
0038 namespace Experimental {
0039 
0040 namespace Internal {
0041 /// Holds status information of an open ROOT file during writing
0042 struct RTFileControlBlock;
0043 
0044 // clang-format off
0045 /**
0046 \class ROOT::Experimental::Internal::RMiniFileReader
0047 \ingroup NTuple
0048 \brief Read RNTuple data blocks from a TFile container, provided by a RRawFile
0049 
0050 A RRawFile is used for the byte access.  The class implements a minimal subset of TFile, enough to extract
0051 RNTuple data keys.
0052 */
0053 // clang-format on
0054 class RMiniFileReader {
0055 private:
0056    /// The raw file used to read byte ranges
0057    ROOT::Internal::RRawFile *fRawFile = nullptr;
0058    /// Indicates whether the file is a TFile container or an RNTuple bare file
0059    bool fIsBare = false;
0060    /// Used when the file container turns out to be a bare file
0061    RResult<RNTuple> GetNTupleBare(std::string_view ntupleName);
0062    /// Used when the file turns out to be a TFile container
0063    RResult<RNTuple> GetNTupleProper(std::string_view ntupleName);
0064 
0065    RNTuple CreateAnchor(std::uint16_t versionEpoch, std::uint16_t versionMajor, std::uint16_t versionMinor,
0066                         std::uint16_t versionPatch, std::uint64_t seekHeader, std::uint64_t nbytesHeader,
0067                         std::uint64_t lenHeader, std::uint64_t seekFooter, std::uint64_t nbytesFooter,
0068                         std::uint64_t lenFooter, std::uint64_t checksum);
0069 
0070 public:
0071    RMiniFileReader() = default;
0072    /// Uses the given raw file to read byte ranges
0073    explicit RMiniFileReader(ROOT::Internal::RRawFile *rawFile);
0074    /// Extracts header and footer location for the RNTuple identified by ntupleName
0075    RResult<RNTuple> GetNTuple(std::string_view ntupleName);
0076    /// Reads a given byte range from the file into the provided memory buffer
0077    void ReadBuffer(void *buffer, size_t nbytes, std::uint64_t offset);
0078 };
0079 
0080 
0081 // clang-format off
0082 /**
0083 \class ROOT::Experimental::Internal::RNTupleFileWriter
0084 \ingroup NTuple
0085 \brief Write RNTuple data blocks in a TFile or a bare file container
0086 
0087 The writer can create a new TFile container for an RNTuple or add an RNTuple to an existing TFile.
0088 Creating a single RNTuple in a new TFile container can be done with a C file stream without a TFile class.
0089 Updating an existing TFile requires a proper TFile object.  Also, writing a remote file requires a proper TFile object.
0090 A stand-alone version of RNTuple can remove the TFile based writer.
0091 */
0092 // clang-format on
0093 class RNTupleFileWriter {
0094 private:
0095    struct RFileProper {
0096       TFile *fFile = nullptr;
0097       /// Low-level writing using a TFile
0098       void Write(const void *buffer, size_t nbytes, std::int64_t offset);
0099       /// Writes an RBlob opaque key with the provided buffer as data record and returns the offset of the record
0100       std::uint64_t WriteKey(const void *buffer, size_t nbytes, size_t len);
0101       operator bool() const { return fFile; }
0102    };
0103 
0104    struct RFileSimple {
0105       /// For the simplest cases, a C file stream can be used for writing
0106       FILE *fFile = nullptr;
0107       /// Keeps track of the seek offset
0108       std::uint64_t fFilePos = 0;
0109       /// Keeps track of the next key offset
0110       std::uint64_t fKeyOffset = 0;
0111       /// Keeps track of TFile control structures, which need to be updated on committing the data set
0112       std::unique_ptr<ROOT::Experimental::Internal::RTFileControlBlock> fControlBlock;
0113 
0114       RFileSimple() = default;
0115       RFileSimple(const RFileSimple &other) = delete;
0116       RFileSimple(RFileSimple &&other) = delete;
0117       RFileSimple &operator =(const RFileSimple &other) = delete;
0118       RFileSimple &operator =(RFileSimple &&other) = delete;
0119       ~RFileSimple();
0120 
0121       /// Writes bytes in the open stream, either at fFilePos or at the given offset
0122       void Write(const void *buffer, size_t nbytes, std::int64_t offset = -1);
0123       /// Writes a TKey including the data record, given by buffer, into fFile; returns the file offset to the payload.
0124       /// The payload is already compressed
0125       std::uint64_t WriteKey(const void *buffer, std::size_t nbytes, std::size_t len, std::int64_t offset = -1,
0126                              std::uint64_t directoryOffset = 100,
0127                              const std::string &className = "",
0128                              const std::string &objectName = "",
0129                              const std::string &title = "");
0130       operator bool() const { return fFile; }
0131    };
0132 
0133    // TODO(jblomer): wrap in an std::variant with C++17
0134    /// For updating existing files and for storing more than just an RNTuple in the file
0135    RFileProper fFileProper;
0136    /// For simple use cases, survives without libRIO dependency
0137    RFileSimple fFileSimple;
0138    /// A simple file can either be written as TFile container or as NTuple bare file
0139    bool fIsBare = false;
0140    /// The identifier of the RNTuple; A single writer object can only write a single RNTuple but multiple
0141    /// writers can operate on the same file if (and only if) they use a proper TFile object for writing.
0142    std::string fNTupleName;
0143    /// The file name without parent directory; only required when writing with a C file stream
0144    std::string fFileName;
0145    /// Header and footer location of the ntuple, written on Commit()
0146    RNTuple fNTupleAnchor;
0147 
0148    explicit RNTupleFileWriter(std::string_view name);
0149 
0150    /// For a TFile container written by a C file stream, write the header and TFile object
0151    void WriteTFileSkeleton(int defaultCompression);
0152    /// The only key that will be visible in file->ls()
0153    void WriteTFileNTupleKey();
0154    /// Write the TList with the RNTuple key
0155    void WriteTFileKeysList();
0156    /// Write the compressed streamer info record with the description of the RNTuple class
0157    void WriteTFileStreamerInfo();
0158    /// Last record in the file
0159    void WriteTFileFreeList();
0160    /// For a bare file, which is necessarily written by a C file stream, write file header
0161    void WriteBareFileSkeleton(int defaultCompression);
0162 
0163 public:
0164    /// For testing purposes, RNTuple data can be written into a bare file container instead of a ROOT file
0165    enum class EContainerFormat {
0166       kTFile, // ROOT TFile
0167       kBare,  // A thin envelope supporting a single RNTuple only
0168    };
0169 
0170    /// Create or truncate the local file given by path with the new empty RNTuple identified by ntupleName.
0171    /// Uses a C stream for writing
0172    static RNTupleFileWriter *Recreate(std::string_view ntupleName, std::string_view path, int defaultCompression,
0173                                       EContainerFormat containerFormat);
0174    /// Add a new RNTuple identified by ntupleName to the existing TFile.
0175    static RNTupleFileWriter *Append(std::string_view ntupleName, TFile &file);
0176 
0177    RNTupleFileWriter(const RNTupleFileWriter &other) = delete;
0178    RNTupleFileWriter(RNTupleFileWriter &&other) = delete;
0179    RNTupleFileWriter &operator =(const RNTupleFileWriter &other) = delete;
0180    RNTupleFileWriter &operator =(RNTupleFileWriter &&other) = delete;
0181    ~RNTupleFileWriter();
0182 
0183    /// Writes the compressed header and registeres its location; lenHeader is the size of the uncompressed header.
0184    std::uint64_t WriteNTupleHeader(const void *data, size_t nbytes, size_t lenHeader);
0185    /// Writes the compressed footer and registeres its location; lenFooter is the size of the uncompressed footer.
0186    std::uint64_t WriteNTupleFooter(const void *data, size_t nbytes, size_t lenFooter);
0187    /// Writes a new record as an RBlob key into the file
0188    std::uint64_t WriteBlob(const void *data, size_t nbytes, size_t len);
0189    /// Reserves a new record as an RBlob key in the file.
0190    std::uint64_t ReserveBlob(size_t nbytes, size_t len);
0191    /// Write into a reserved record; the caller is responsible for making sure that the written byte range is in the
0192    /// previously reserved key.
0193    void WriteIntoReservedBlob(const void *buffer, size_t nbytes, std::int64_t offset);
0194    /// Writes the RNTuple key to the file so that the header and footer keys can be found
0195    void Commit();
0196 };
0197 
0198 } // namespace Internal
0199 } // namespace Experimental
0200 } // namespace ROOT
0201 
0202 #endif