45std::string FormatBinarySize(std::uint64_t nbytes)
47 const char *suffix =
"B";
48 double v =
static_cast<double>(nbytes);
49 if (
v >= 1024.0 * 1024.0 * 1024.0) {
50 v /= 1024.0 * 1024.0 * 1024.0;
52 }
else if (
v >= 1024.0 * 1024.0) {
55 }
else if (
v >= 1024.0) {
59 std::ostringstream os;
60 os.setf(std::ios::fixed);
61 os.precision(
v >= 100.0 ? 0 : (
v >= 10.0 ? 1 : 2));
62 os <<
v <<
' ' << suffix;
68 static constexpr std::uint64_t gUpdateFrequencyBytes = 100 * 1000 * 1000;
69 std::uint64_t fNbytesNext = gUpdateFrequencyBytes;
72 ~RDefaultProgressCallback()
override {}
73 void Call(std::uint64_t nbytesWritten, std::uint64_t neventsWritten)
final
76 if (nbytesWritten < fNbytesNext)
78 std::cout <<
"Wrote " << nbytesWritten / 1000 / 1000 <<
"MB payload, " << neventsWritten <<
" entries\n";
79 fNbytesNext += gUpdateFrequencyBytes;
80 if (nbytesWritten > fNbytesNext) {
82 fNbytesNext = nbytesWritten + gUpdateFrequencyBytes;
88 std::cout <<
"Done: " << report.fEntries <<
" entries\n";
89 std::cout <<
" compressed page payload: " << FormatBinarySize(report.fCompressedPayloadBytes) <<
'\n';
90 std::cout <<
" on disk: " << FormatBinarySize(report.fFileBytesOnDisk) <<
'\n';
91 if (report.fFileBytesOnDisk > report.fCompressedPayloadBytes) {
92 const auto overhead = report.fFileBytesOnDisk - report.fCompressedPayloadBytes;
93 std::cout <<
" file overhead (approx): " << FormatBinarySize(overhead)
94 <<
" (page lists, footer, streamer info, ROOT keys)\n";
96 if (report.fUncompressedPageBytes > 0 && report.fCompressedPayloadBytes > 0) {
98 static_cast<double>(report.fCompressedPayloadBytes) /
static_cast<double>(report.fUncompressedPageBytes);
99 std::cout <<
" page compression ratio: " << std::fixed << std::setprecision(3) <<
ratio
100 <<
" (payload / uncompressed pages)\n";
114std::unique_ptr<ROOT::Experimental::RNTupleImporter>
116 std::string_view destFileName)
118 auto importer = std::unique_ptr<RNTupleImporter>(
new RNTupleImporter());
119 importer->fNTupleName = treeName;
120 importer->fSourceFile = std::unique_ptr<TFile>(
TFile::Open(std::string(sourceFileName).c_str()));
121 if (!importer->fSourceFile || importer->fSourceFile->IsZombie()) {
122 throw RException(
R__FAIL(
"cannot open source file " + std::string(sourceFileName)));
125 importer->fSourceTree = importer->fSourceFile->Get<
TTree>(std::string(treeName).c_str());
126 if (!importer->fSourceTree) {
127 throw RException(
R__FAIL(
"cannot read TTree " + std::string(treeName) +
" from " + std::string(sourceFileName)));
131 importer->fSourceTree->SetImplicitMT(
false);
132 auto result = importer->InitDestination(destFileName);
140std::unique_ptr<ROOT::Experimental::RNTupleImporter>
143 auto importer = std::unique_ptr<RNTupleImporter>(
new RNTupleImporter());
150 importer->fNTupleName = sourceTree->
GetName();
153 importer->fSourceTree = sourceTree;
157 auto result = importer->InitDestination(destFileName);
179 std::cout <<
"Importing '" <<
f.fField->GetFieldName() <<
"' [" <<
f.fField->GetTypeName() <<
"]\n";
182 std::cout <<
"Importing (projected) '" <<
f->GetFieldName() <<
"' [" <<
f->GetTypeName() <<
"]\n";
205 const auto firstLeaf =
static_cast<TLeaf *
>(
b->GetListOfLeaves()->First());
208 const bool isLeafList =
b->GetNleaves() > 1;
209 const bool isCountLeaf = firstLeaf->IsRange();
211 if (isLeafList && isClass)
212 return R__FAIL(
"unsupported: classes in leaf list, branch " + std::string(
b->GetName()));
213 if (isLeafList && isCountLeaf)
214 return R__FAIL(
"unsupported: count leaf arrays in leaf list, branch " + std::string(
b->GetName()));
219 Int_t firstLeafCountval;
220 const bool isCString = !isLeafList && (firstLeaf->IsA() ==
TLeafC::Class()) &&
221 (!firstLeaf->GetLeafCounter(firstLeafCountval)) && (firstLeafCountval == 1);
230 c.fCountVal = std::make_unique<Int_t>();
237 std::size_t branchBufferSize = 0;
239 std::vector<std::unique_ptr<ROOT::RFieldBase>> recordItems;
242 bool isLeafCountArray =
false;
245 return R__FAIL(
"unsupported: TObject branches, branch: " + std::string(
b->GetName()));
250 Int_t countval =
l->GetLenStatic();
251 auto *countleaf =
l->GetLeafCount();
252 const bool isFixedSizeArray = !isCString && (countleaf ==
nullptr) && (countval > 1);
253 isLeafCountArray = (countleaf !=
nullptr);
258 std::string fieldName =
b->GetName();
259 std::string fieldType =
l->GetTypeName();
265 fieldType =
"std::string";
268 fieldType =
b->GetClassName();
270 if (isFixedSizeArray)
271 fieldType =
"std::array<" + fieldType +
"," + std::to_string(countval) +
">";
275 std::replace(fieldName.begin(), fieldName.end(),
'.',
'_');
282 auto field = fieldOrError.Unwrap();
284 branchBufferSize =
l->GetMaximum();
285 f.fValue = std::make_unique<ROOT::RFieldBase::RValue>(field->CreateValue());
286 f.fFieldBuffer =
f.fValue->GetPtr<
void>().get();
293 branchBufferSize =
sizeof(
void *) * countval;
294 }
else if (isLeafCountArray) {
297 branchBufferSize =
l->GetOffset() + field->GetValueSize();
300 f.fField = field.get();
303 recordItems.emplace_back(std::move(field));
304 }
else if (isLeafCountArray) {
305 const std::string countleafName = countleaf->GetName();
308 R__ASSERT(
b->GetListOfLeaves()->GetEntries() == 1);
311 fModel->AddField(std::move(field));
315 if (!recordItems.empty()) {
316 auto recordField = std::make_unique<ROOT::RRecordField>(
b->GetName(), std::move(recordItems));
320 fModel->AddField(std::move(recordField));
325 ib.
fBranchBuffer = std::make_unique<unsigned char[]>(branchBufferSize);
329 return R__FAIL(
"unable to load class " + std::string(
b->GetClassName()) +
" for branch " +
330 std::string(
b->GetName()));
332 auto ptrBuf =
reinterpret_cast<void **
>(ib.
fBranchBuffer.get());
339 if (!isLeafCountArray && !
fImportFields.back().fFieldBuffer) {
347 int iLeafCountCollection = 0;
351 auto countLeafName =
p.first;
354 c.fFieldName =
"_collection" + std::to_string(iLeafCountCollection);
355 auto recordField = std::make_unique<ROOT::RRecordField>(
"_0", std::move(
c.fLeafFields));
357 c.fRecordField =
static_cast<RRecordField *
>(collectionField->GetMutableSubfields()[0]);
358 fModel->AddField(std::move(collectionField));
361 for (
const auto leaf :
c.fRecordField->GetConstSubfields()) {
362 const auto name = leaf->GetFieldName();
363 auto projectedField =
365 fModel->AddProjectedField(std::move(projectedField), [&
name, &
c](
const std::string &fieldName) {
366 if (fieldName ==
name)
369 return c.fFieldName +
"._0." +
name;
375 std::replace(countLeafName.begin(), countLeafName.end(),
'.',
'_');
380 fModel->AddProjectedField(std::move(projectedField), [&
c](
const std::string &) {
return c.fFieldName; });
382 iLeafCountCollection++;
386 for (
auto &field :
fModel->GetMutableFieldZero()) {
395 fEntry->BindRawPtr(
f.fField->GetFieldName(),
f.fFieldBuffer);
398 fEntry->BindRawPtr<
void>(
c.fFieldName, &
c.fFieldBuffer);
399 c.fSizeOfRecord =
c.fRecordField->GetValueSize();
400 const auto subfields =
c.fRecordField->GetConstSubfields();
401 const auto &offsets =
c.fRecordField->GetOffsets();
402 R__ASSERT(subfields.size() ==
c.fLeafBranchIndexes.size());
403 assert(
c.fPackedLeaves.empty());
404 c.fPackedLeaves.reserve(subfields.size());
405 for (std::size_t
l = 0;
l < subfields.size(); ++
l) {
410 c.fPackedLeaves.push_back(packed);
412 c.fFieldBuffer.reserve(
static_cast<std::size_t
>(
c.fMaxLength) *
c.fSizeOfRecord);
427 if (lastSlash != std::string::npos) {
431 targetDir =
fDestFile->mkdir(dirName.c_str(),
"",
true);
437 if (targetDir->
FindKey(ntupleName.c_str()) !=
nullptr) {
443 std::unique_ptr<ROOT::Internal::RPageSink> sink =
444 std::make_unique<ROOT::Internal::RPageSinkFile>(ntupleName, *targetDir,
fWriteOptions);
445 sink->GetMetrics().Enable();
446 auto ctrZippedBytes = sink->GetMetrics().GetCounter(
"RPageSinkFile.szWritePayload");
447 auto ctrUnzipBytes = sink->GetMetrics().GetCounter(
"RPageSinkFile.szZip");
450 sink = std::make_unique<ROOT::Internal::RPageSinkBuf>(std::move(sink));
461 std::uint64_t payloadBytes = 0;
462 std::uint64_t unzipBytes = 0;
468 for (
decltype(nEntries) i = 0; i < nEntries; ++i) {
472 const auto nItems =
static_cast<std::size_t
>(*
c.fCountVal);
473 const auto sizeOfRecord =
c.fSizeOfRecord;
474 c.fFieldBuffer.resize(sizeOfRecord * nItems);
476 for (
const auto &leaf :
c.fPackedLeaves) {
478 auto *
dst =
c.fFieldBuffer.data() + leaf.fOffset;
479 for (std::size_t j = 0; j < nItems; ++j) {
480 memcpy(
dst + j * sizeOfRecord,
src + j * leaf.fValueSize, leaf.fValueSize);
491 ntplWriter->Fill(*
fEntry);
497 payloadBytes = ctrZippedBytes->GetValueAsInt();
499 unzipBytes = ctrUnzipBytes->GetValueAsInt();
#define R__FORWARD_ERROR(res)
Short-hand to return an RResult<T> in an error state (i.e. after checking)
#define R__FAIL(msg)
Short-hand to return an RResult<T> in an error state; the RError is implicitly converted into RResult...
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t src
Used to report every ~100 MB of compressed page payload, and at the end about the status of the impor...
bool fConvertDotsInBranchNames
Whether or not dot characters in branch names should be converted to underscores.
std::unique_ptr< ROOT::REntry > fEntry
std::unique_ptr< TFile > fDestFile
std::int64_t fMaxEntries
The maximum number of entries to import. When this value is -1 (default), import all entries.
std::map< std::string, RImportLeafCountCollection > fLeafCountCollections
Maps the count leaf to the information about the corresponding untyped collection.
RNTupleImporter()=default
std::unique_ptr< ROOT::RNTupleModel > fModel
std::vector< RImportBranch > fImportBranches
ROOT::RResult< void > InitDestination(std::string_view destFileName)
RImportReport fLastImportReport
static std::unique_ptr< RNTupleImporter > Create(std::string_view sourceFileName, std::string_view treeName, std::string_view destFileName)
Opens the input file for reading and the output file for writing (update).
std::unique_ptr< RProgressCallback > fProgressCallback
void Import()
Import works in two steps:
ROOT::RNTupleWriteOptions fWriteOptions
std::string fDestFileName
bool fIsQuiet
No standard output, conversely if set to false, schema information and progress is printed.
std::vector< RImportField > fImportFields
FieldModifier_t fFieldModifier
std::vector< std::unique_ptr< RImportTransformation > > fImportTransformations
The list of transformations to be performed for every entry.
ROOT::RResult< void > PrepareSchema()
Sets up the connection from TTree branches to RNTuple fields, including initialization of the memory ...
ROOT::RFieldZero & GetFieldZero()
Base class for all ROOT issued exceptions.
std::vector< const RFieldBase * > GetConstSubfields() const
static RResult< std::unique_ptr< RFieldBase > > Create(const std::string &fieldName, const std::string &typeName, const ROOT::RCreateFieldOptions &options, const ROOT::RNTupleDescriptor *desc, ROOT::DescriptorId_t fieldId)
Factory method to resurrect a field from the stored on-disk type information.
static std::unique_ptr< RNTupleModel > CreateBare()
Creates a "bare model", i.e. an RNTupleModel with no default entry.
bool GetUseBufferedWrite() const
The field for an untyped record.
The class is used as a return type for operations that can fail; wraps a value of type T or an RError...
static std::unique_ptr< RVectorField > CreateUntyped(std::string_view fieldName, std::unique_ptr< RFieldBase > itemField)
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Describe directory structure in memory.
virtual TKey * FindKey(const char *) const
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
TClass * IsA() const override
const char * GetName() const override
Returns name of object.
virtual const char * GetName() const
Returns name of object.
A TTree represents a columnar dataset.
virtual Int_t SetBranchAddress(const char *bname, void *add, TBranch **ptr, TClass *realClass, EDataType datatype, bool isptr, bool suppressMissingBranchError)
virtual Int_t GetEntry(Long64_t entry, Int_t getall=0)
Read all branches of entry and return total number of bytes read.
virtual Long64_t GetEntries() const
virtual void SetImplicitMT(bool enabled)
virtual TObjArray * GetListOfBranches()
virtual TTree * GetTree() const
virtual Long64_t LoadTree(Long64_t entry)
Set current entry.
TClass * IsA() const override
std::unique_ptr< RNTupleWriter > CreateRNTupleWriter(std::unique_ptr< ROOT::RNTupleModel > model, std::unique_ptr< Internal::RPageSink > sink)
RProjectedFields & GetProjectedFieldsOfModel(RNTupleModel &model)
double ratio(double numerator, double denominator)
std::string fBranchName
Top-level branch name from the input TTree.
std::unique_ptr< unsigned char[]> fBranchBuffer
The destination of SetBranchAddress() for fBranchName
void * fFieldBuffer
Usually points to the corresponding RImportBranch::fBranchBuffer but not always.
ROOT::RFieldBase * fField
The field is kept during schema preparation and transferred to the fModel before the writing starts.
When the schema is set up and the import started, it needs to be reset before the next Import() call ...
std::size_t fImportBranchIdx
Leaf count arrays require special treatment.
Int_t fMaxLength
Stores count leaf GetMaximum() to create large enough buffers for the array leafs.
Summary printed after the RNTuple writer commits (footer, streamer info, last cluster).
std::uint64_t fCompressedPayloadBytes
Sealed column page blobs (RPageSinkFile.szWritePayload)
std::uint64_t fUncompressedPageBytes
Logical page bytes before compression (RPageSinkFile.szZip)
std::uint64_t fFileBytesOnDisk
Destination TFile size after commit (matches ls -lh)