16#include <TBufferFile.h>
18#include <arrow/buffer.h>
19#include <arrow/dataset/file_base.h>
20#include <arrow/extension_type.h>
21#include <arrow/memory_pool.h>
22#include <arrow/status.h>
23#include <arrow/type.h>
24#include <arrow/type_fwd.h>
25#include <arrow/util/key_value_metadata.h>
26#include <arrow/array/array_nested.h>
27#include <arrow/array/array_primitive.h>
28#include <arrow/array/builder_nested.h>
29#include <arrow/array/builder_primitive.h>
30#include <arrow/array/util.h>
31#include <arrow/record_batch.h>
74 const std::shared_ptr<arrow::ResizableBuffer>&
buffer);
82 static arrow::Result<std::shared_ptr<TTreeDeferredReadOutputStream>>
Create(
83 std::vector<ReadOps>& ops,
84 int64_t initial_capacity = 4096,
85 arrow::MemoryPool* pool = arrow::default_memory_pool());
95 arrow::Status
Close()
override;
96 [[nodiscard]]
bool closed()
const override;
97 [[nodiscard]] arrow::Result<int64_t>
Tell()
const override;
98 arrow::Status
Write(
const void*
data, int64_t nbytes)
override;
101 using OutputStream::Write;
105 arrow::Result<std::shared_ptr<arrow::Buffer>>
Finish();
112 arrow::Status
Reset(std::vector<ReadOps> ops,
113 int64_t initial_capacity, arrow::MemoryPool* pool);
115 [[nodiscard]] int64_t
capacity()
const {
return capacity_; }
119 std::vector<ReadOps> ops_;
122 arrow::Status Reserve(int64_t nbytes);
124 std::shared_ptr<arrow::ResizableBuffer> buffer_;
131static constexpr int64_t kBufferMinimumSize = 256;
133TTreeDeferredReadOutputStream::TTreeDeferredReadOutputStream()
134 : is_open_(
false), capacity_(0), position_(0), mutable_data_(nullptr) {}
136TTreeDeferredReadOutputStream::TTreeDeferredReadOutputStream(std::vector<ReadOps>& ops,
137 const std::shared_ptr<arrow::ResizableBuffer>&
buffer)
143 mutable_data_(
buffer->mutable_data()) {}
146 std::vector<ReadOps>& ops,
147 int64_t initial_capacity, arrow::MemoryPool* pool)
151 RETURN_NOT_OK(
ptr->Reset(ops, initial_capacity, pool));
156 int64_t initial_capacity, arrow::MemoryPool* pool)
158 ARROW_ASSIGN_OR_RAISE(buffer_, AllocateResizableBuffer(initial_capacity, pool));
161 capacity_ = initial_capacity;
163 mutable_data_ = buffer_->mutable_data();
164 return arrow::Status::OK();
171 if (position_ < capacity_) {
172 RETURN_NOT_OK(buffer_->Resize(position_,
false));
175 return arrow::Status::OK();
182 RETURN_NOT_OK(
Close());
183 buffer_->ZeroPadding();
185 return std::move(buffer_);
193 throw runtime_error_f(
"Error while reading branch %s starting from %d: got %d entries.",
op.branch->GetName(), readEntries, readLast);
195 if (
static_cast<int64_t
>(readEntries) + readLast >
op.rootBranchEntries) {
196 throw runtime_error_f(
"Invalid read range for branch %s: starting from %d, read %d entries, total entries %lld.",
197 op.branch->GetName(), readEntries, readLast,
static_cast<long long>(
op.rootBranchEntries));
203 if (bytesNeeded < 0 || bytesNeeded > available) {
204 throw runtime_error_f(
"Basket of branch %s starting from %d holds %lld bytes, but %lld are needed.",
205 op.branch->GetName(), readEntries,
static_cast<long long>(available),
static_cast<long long>(bytesNeeded));
212 while (readEntries <
op.rootBranchEntries) {
213 auto readLast =
op.branch->GetBulkRead().GetEntriesSerialized(readEntries,
rootBuffer);
215 int size = readLast *
op.listSize;
217 readEntries += readLast;
227 memset(
target, 0,
op.targetBuffer->size());
229 while (readEntries <
op.rootBranchEntries) {
230 auto beginValue = readEntries;
231 readLast =
op.branch->GetBulkRead().GetBulkEntries(readEntries,
rootBuffer);
233 int size = readLast *
op.listSize;
235 readEntries += readLast;
236 for (
int i = beginValue;
i < beginValue +
size; ++
i) {
246 if (
op.rootBranchEntries != offsetOp.rootBranchEntries) {
247 throw runtime_error_f(
"Branch %s has %lld entries, but its size branch %s has %lld.",
248 op.branch->GetName(),
static_cast<long long>(
op.rootBranchEntries),
249 offsetOp.branch->GetName(),
static_cast<long long>(offsetOp.rootBranchEntries));
251 auto* tPtrOffset =
reinterpret_cast<const int*
>(offsetOp.targetBuffer->data());
252 std::span<int const>
const offsets{tPtrOffset, tPtrOffset + offsetOp.rootBranchEntries + 1};
255 while (readEntries <
op.rootBranchEntries) {
256 auto readLast =
op.branch->GetBulkRead().GetEntriesSerialized(readEntries,
rootBuffer);
260 throw runtime_error_f(
"Invalid offset range for branch %s: offsets[%d]=%d, offsets[%d]=%d.",
261 op.branch->GetName(), readEntries,
offsets[readEntries], readEntries + readLast,
offsets[readEntries + readLast]);
264 readEntries += readLast;
279 if (ARROW_PREDICT_FALSE(!is_open_)) {
280 return arrow::Status::IOError(
"OutputStream is closed");
282 if (ARROW_PREDICT_TRUE(nbytes == 0)) {
283 return arrow::Status::OK();
285 if (ARROW_PREDICT_FALSE(position_ + nbytes >= capacity_)) {
286 RETURN_NOT_OK(Reserve(nbytes));
290 if (
ref >= ops_.size()) {
291 memcpy(mutable_data_ + position_,
data, nbytes);
293 return arrow::Status::OK();
295 auto&
op = ops_[
ref];
314 op.branch->SetStatus(
false);
315 op.branch->DropBaskets(
"all");
317 op.branch->GetTransientBuffer(0)->Expand(0);
320 return arrow::Status::OK();
323arrow::Status TTreeDeferredReadOutputStream::Reserve(int64_t nbytes)
329 int64_t new_capacity = std::max(kBufferMinimumSize, capacity_);
330 new_capacity = position_ + nbytes;
331 if (new_capacity > capacity_) {
332 RETURN_NOT_OK(buffer_->Resize(new_capacity));
333 capacity_ = new_capacity;
334 mutable_data_ = buffer_->mutable_data();
336 return arrow::Status::OK();
343 : FileWriteOptions(
format)
355 const std::string&
path,
356 const std::shared_ptr<const arrow::KeyValueMetadata>& metadata)
override;
358 virtual std::unique_ptr<TTree>&
GetTree(arrow::dataset::FileSource
source) = 0;
363 size_t& mTotCompressedSize;
364 size_t& mTotUncompressedSize;
369 mTotCompressedSize(totalCompressedSize),
370 mTotUncompressedSize(totalUncompressedSize)
388 auto fs = std::dynamic_pointer_cast<VirtualRootFileSystemBase>(
source.filesystem());
392 return fs->CheckSupport(
source);
395 arrow::Result<std::shared_ptr<arrow::Schema>>
Inspect(
const arrow::dataset::FileSource&
source)
const override;
397 arrow::Result<std::shared_ptr<arrow::dataset::FileFragment>>
MakeFragment(
398 arrow::dataset::FileSource
source, arrow::compute::Expression partition_expression,
399 std::shared_ptr<arrow::Schema> physical_schema)
override;
401 arrow::Result<std::shared_ptr<arrow::dataset::FileWriter>>
MakeWriter(std::shared_ptr<arrow::io::OutputStream> destination, std::shared_ptr<arrow::Schema>
schema, std::shared_ptr<arrow::dataset::FileWriteOptions> options, arrow::fs::FileLocator destination_locator)
const override;
406 const std::shared_ptr<arrow::dataset::ScanOptions>& options,
407 const std::shared_ptr<arrow::dataset::FileFragment>& fragment)
const override;
415 mTotUncompressedSize(totalUncompressedSize),
416 mTotCompressedSize(totalCompressedSize),
421 arrow::Result<arrow::fs::FileInfo>
GetFileInfo(std::string
const&
path)
override;
430 return std::make_shared<RootObjectHandler>((
void*)mTree.get(), std::make_shared<TTreeFileFormat>(mTotCompressedSize, mTotUncompressedSize));
433 std::unique_ptr<TTree>&
GetTree(arrow::dataset::FileSource)
override
443 size_t& mTotUncompressedSize;
444 size_t& mTotCompressedSize;
445 std::unique_ptr<TTree> mTree;
450 arrow::dataset::FileSource
source(
path, shared_from_this());
451 arrow::fs::FileInfo
result;
453 result.set_type(arrow::fs::FileType::File);
462 std::shared_ptr<arrow::dataset::FileFormat>
format,
463 arrow::compute::Expression partition_expression,
464 std::shared_ptr<arrow::Schema> physical_schema)
465 : FileFragment(
source,
format,
std::move(partition_expression), physical_schema)
467 auto rootFS = std::dynamic_pointer_cast<VirtualRootFileSystemBase>(this->
source().filesystem());
468 if (rootFS.get() ==
nullptr) {
470 source.filesystem()->type_name().c_str(),
source.path().c_str());
472 auto objectHandler = rootFS->GetObjectHandler(
source);
473 if (!objectHandler->format->Equals(*
format)) {
474 throw runtime_error_f(
"Cannot read source %s with format %s to pupulate a TTreeFileFragment.",
475 source.path().c_str(), objectHandler->format->type_name().c_str());
477 mTree = objectHandler->GetObjectAsOwner<TTree>();
485 std::vector<ReadOps>&
ops()
494 return std::make_shared<arrow::Buffer>((
uint8_t*)(mOps.size() - 1),
size);
498 std::unique_ptr<TTree> mTree;
499 std::vector<ReadOps> mOps;
511 arrow::Status
Close()
override;
513 arrow::Result<int64_t>
Tell()
const override;
515 arrow::Status
Write(
const void*
data, int64_t nbytes)
override;
517 bool closed()
const override;
519 TBranch*
CreateBranch(
char const* branchName,
char const* sizeBranch);
528 std::string mBranchPrefix;
536 mBranchPrefix(
std::move(branchPrefix))
542 if (mTree->GetCurrentFile() ==
nullptr) {
543 return arrow::Status::Invalid(
"Cannot close a tree not attached to a file");
545 mTree->GetCurrentFile()->Close();
546 return arrow::Status::OK();
551 return arrow::Result<int64_t>(arrow::Status::NotImplemented(
"Cannot move"));
556 return arrow::Status::NotImplemented(
"Cannot write raw bytes to a TTree");
562 if (mTree->GetCurrentFile() ==
nullptr) {
565 return mTree->GetCurrentFile()->IsOpen() ==
false;
570 if (mBranchPrefix.empty() ==
true) {
571 return mTree->Branch(branchName, (
char*)
nullptr, sizeBranch);
573 return mTree->Branch((mBranchPrefix +
"/" + branchName).c_str(), (
char*)
nullptr, (mBranchPrefix + sizeBranch).c_str());
579 std::shared_ptr<o2::framework::TTreeFileFormat>
format =
nullptr;
586 context->
format = std::make_shared<o2::framework::TTreeFileFormat>(context->totalCompressedSize, context->totalUncompressedSize);
588 .
options = [context]() {
return context->format->DefaultWriteOptions(); },
589 .format = [context]() {
return context->format; },
590 .deferredOutputStreamer = [](std::shared_ptr<arrow::dataset::FileFragment> fragment,
const std::shared_ptr<arrow::ResizableBuffer>&
buffer) -> std::shared_ptr<arrow::io::OutputStream> {
591 auto treeFragment = std::dynamic_pointer_cast<TTreeFileFragment>(fragment);
592 return std::make_shared<TTreeDeferredReadOutputStream>(treeFragment->ops(),
buffer);
608 auto* tPtrOffset =
reinterpret_cast<int*
>(
op.targetBuffer->mutable_data());
609 offsets = std::span<int>{tPtrOffset, tPtrOffset +
op.rootBranchEntries + 1};
613 while (readEntries <
op.rootBranchEntries) {
614 auto readLast =
op.branch->GetBulkRead().GetEntriesSerialized(readEntries,
rootBuffer);
617 readEntries += readLast;
618 for (
auto i = 0;
i < readLast; ++
i) {
621 offset += (std::endian::native == std::endian::little) ? __builtin_bswap32(
raw) :
raw;
624 throw runtime_error_f(
"Invalid sizes for branch %s: offsets overflow at entry %d.",
op.branch->GetName(),
count - 1);
633 const std::shared_ptr<arrow::dataset::ScanOptions>& options,
634 const std::shared_ptr<arrow::dataset::FileFragment>& fragment)
const
636 assert(options->dataset_schema !=
nullptr);
638 auto dataset_schema = options->dataset_schema;
639 auto treeFragment = std::dynamic_pointer_cast<TTreeFileFragment>(fragment);
640 if (treeFragment.get() ==
nullptr) {
641 return {arrow::Status::NotImplemented(
"Not a ttree fragment")};
644 auto generator = [pool = options->pool, treeFragment, dataset_schema, &totalCompressedSize = mTotCompressedSize,
645 &totalUncompressedSize = mTotUncompressedSize]() -> arrow::Future<std::shared_ptr<arrow::RecordBatch>> {
647 O2_SIGNPOST_START(root_arrow_fs, tid,
"Generator",
"Creating batch for tree %{public}s", treeFragment->GetTree()->GetName());
648 std::vector<std::shared_ptr<arrow::Array>> columns;
649 std::vector<std::shared_ptr<arrow::Field>>
fields = dataset_schema->fields();
650 auto physical_schema = *treeFragment->ReadPhysicalSchema();
652 if (dataset_schema->num_fields() > physical_schema->num_fields()) {
653 throw runtime_error_f(
"One TTree must have all the fields requested in a table");
657 std::vector<BranchFieldMapping> mappings;
661 for (
int fi = 0; fi < dataset_schema->num_fields(); ++fi) {
662 auto dataset_field = dataset_schema->field(fi);
665 O2_SIGNPOST_EVENT_EMIT(root_arrow_fs, tid,
"Generator",
"Processing dataset field %{public}s.", dataset_field->name().c_str());
666 int physicalFieldIdx = physical_schema->GetFieldIndex(dataset_field->name());
668 if (physicalFieldIdx < 0) {
669 throw runtime_error_f(
"Cannot find physical field associated to %s. Possible fields: %s",
670 dataset_field->name().c_str(), physical_schema->ToString().c_str());
672 if (physicalFieldIdx > 0 && physical_schema->field(physicalFieldIdx - 1)->name().ends_with(
"_size")) {
673 O2_SIGNPOST_EVENT_EMIT(root_arrow_fs, tid,
"Generator",
"Field %{public}s has sizes in %{public}s.", dataset_field->name().c_str(),
674 physical_schema->field(physicalFieldIdx - 1)->name().c_str());
675 mappings.push_back({physicalFieldIdx, physicalFieldIdx - 1, fi});
678 if (physicalFieldIdx > 0) {
679 O2_SIGNPOST_EVENT_EMIT(root_arrow_fs, tid,
"Generator",
"Field %{public}s previous field is %{public}s.", dataset_field->name().c_str(),
680 physical_schema->field(physicalFieldIdx - 1)->name().c_str());
682 mappings.push_back({physicalFieldIdx, -1, fi});
687 auto*
tree = treeFragment->GetTree();
688 auto branches =
tree->GetListOfBranches();
689 size_t totalTreeSize = 0;
690 std::vector<TBranch*> selectedBranches;
691 for (
auto& mapping : mappings) {
692 selectedBranches.push_back((TBranch*)branches->At(mapping.mainBranchIdx));
693 O2_SIGNPOST_EVENT_EMIT(root_arrow_fs, tid,
"Generator",
"Adding branch %{public}s to stream.", selectedBranches.back()->GetName());
694 totalTreeSize += selectedBranches.back()->GetTotalSize();
695 if (mapping.vlaIdx != -1) {
696 selectedBranches.push_back((TBranch*)branches->At(mapping.vlaIdx));
697 O2_SIGNPOST_EVENT_EMIT(root_arrow_fs, tid,
"Generator",
"Adding branch %{public}s to stream.", selectedBranches.back()->GetName());
698 totalTreeSize += selectedBranches.back()->GetTotalSize();
702 size_t cacheSize = std::max(std::min(totalTreeSize, 25000000UL), 1000000UL);
704 tree->SetCacheSize(cacheSize);
705 for (
auto* branch : selectedBranches) {
706 tree->AddBranchToCache(branch,
false);
708 tree->StopCacheLearningPhase();
711 std::vector<ReadOps>& ops = treeFragment->ops();
713 ops.reserve(opsCount);
714 for (
size_t mi = 0; mi < mappings.size(); ++mi) {
717 auto datasetField = dataset_schema->field(mapping.datasetFieldIdx);
718 auto physicalField = physical_schema->field(mapping.mainBranchIdx);
720 if (mapping.vlaIdx != -1) {
721 auto* branch = (TBranch*)branches->At(mapping.vlaIdx);
724 .rootBranchEntries = branch->GetEntries(),
729 auto&
op = ops.back();
730 ARROW_ASSIGN_OR_RAISE(
op.targetBuffer, arrow::AllocateBuffer((
op.rootBranchEntries + 1) *
op.typeSize, pool));
735 auto& valueOp = ops.back();
736 valueOp.branch = (TBranch*)branches->At(mapping.mainBranchIdx);
737 valueOp.rootBranchEntries = valueOp.branch->GetEntries();
740 auto listType = std::dynamic_pointer_cast<arrow::FixedSizeListType>(datasetField->type());
741 valueOp.typeSize = physicalField->type()->byte_width();
744 if ((datasetField->type() == arrow::boolean())) {
746 valueOp.listSize = 1;
747 valueOp.targetBuffer = treeFragment->GetPlaceholderForOp((valueOp.rootBranchEntries + 7) / 8);
748 }
else if (listType && datasetField->type()->field(0)->type() == arrow::boolean()) {
749 valueOp.typeSize = physicalField->type()->field(0)->type()->byte_width();
750 valueOp.listSize = listType->list_size();
752 valueOp.targetBuffer = treeFragment->GetPlaceholderForOp((valueOp.rootBranchEntries * valueOp.listSize) / 8 + 1);
753 }
else if (mapping.vlaIdx != -1) {
754 valueOp.typeSize = physicalField->type()->field(0)->type()->byte_width();
755 valueOp.listSize = -1;
758 valueOp.targetBuffer = treeFragment->GetPlaceholderForOp(ops[ops.size() - 2].offsetCount * valueOp.typeSize);
759 }
else if (listType) {
761 valueOp.listSize = listType->list_size();
762 valueOp.typeSize = physicalField->type()->field(0)->type()->byte_width();
763 valueOp.targetBuffer = treeFragment->GetPlaceholderForOp(valueOp.rootBranchEntries * valueOp.typeSize * valueOp.listSize);
765 valueOp.typeSize = physicalField->type()->byte_width();
767 valueOp.listSize = 1;
768 valueOp.targetBuffer = treeFragment->GetPlaceholderForOp(valueOp.rootBranchEntries * valueOp.typeSize);
770 arrow::Status status;
771 std::shared_ptr<arrow::Array>
array;
774 auto vdata = std::make_shared<arrow::ArrayData>(datasetField->type()->field(0)->type(), valueOp.rootBranchEntries * valueOp.listSize,
775 std::vector<std::shared_ptr<arrow::Buffer>>{nullptr, valueOp.targetBuffer});
776 array = std::make_shared<arrow::FixedSizeListArray>(datasetField->type(), valueOp.rootBranchEntries, arrow::MakeArray(vdata));
778 O2_SIGNPOST_EVENT_EMIT(root_arrow_fs, tid,
"Op",
"Created op for branch %{public}s with %lli entries, size of the buffer %lli.",
779 valueOp.branch->GetName(),
780 valueOp.rootBranchEntries,
781 valueOp.targetBuffer->size());
782 }
else if (mapping.vlaIdx != -1) {
783 auto& offsetOp = ops[ops.size() - 2];
784 auto vdata = std::make_shared<arrow::ArrayData>(datasetField->type()->field(0)->type(), offsetOp.offsetCount,
785 std::vector<std::shared_ptr<arrow::Buffer>>{nullptr, valueOp.targetBuffer});
787 array = std::make_shared<arrow::ListArray>(datasetField->type(), offsetOp.rootBranchEntries, offsetOp.targetBuffer, arrow::MakeArray(vdata));
788 O2_SIGNPOST_EVENT_EMIT(root_arrow_fs, tid,
"Op",
"Created op for branch %{public}s with %lli entries, size of the buffer %lli.",
789 offsetOp.branch->GetName(), offsetOp.rootBranchEntries, offsetOp.targetBuffer->size());
790 O2_SIGNPOST_EVENT_EMIT(root_arrow_fs, tid,
"Op",
"Created op for branch %{public}s with %lli entries, size of the buffer %lli.",
791 valueOp.branch->GetName(),
792 offsetOp.offsetCount,
793 valueOp.targetBuffer->size());
795 auto data = std::make_shared<arrow::ArrayData>(datasetField->type(), valueOp.rootBranchEntries,
796 std::vector<std::shared_ptr<arrow::Buffer>>{nullptr, valueOp.targetBuffer});
798 O2_SIGNPOST_EVENT_EMIT(root_arrow_fs, tid,
"Op",
"Created op for branch %{public}s with %lli entries, size of the buffer %lli.",
799 valueOp.branch->GetName(),
800 valueOp.rootBranchEntries,
801 valueOp.targetBuffer->size());
804 columns.push_back(
array);
810 for (
size_t i = 0;
i < ops.size(); ++
i) {
813 rows =
op.rootBranchEntries;
816 auto& offsetOp = ops[
i - 1];
817 rows = offsetOp.rootBranchEntries;
820 throw runtime_error_f(
"Unmatching number of rows for branch %s. Expected %lli, found %lli",
op.branch->GetName(),
rows,
op.rootBranchEntries);
823 throw runtime_error_f(
"Unmatching number of rows for branch %s. Expected %lli, found %lli",
op.branch->GetName(),
rows, ops[
i - 1].offsetCount);
827 auto batch = arrow::RecordBatch::Make(dataset_schema,
rows, columns);
828 totalCompressedSize +=
tree->GetZipBytes();
829 totalUncompressedSize +=
tree->GetTotBytes();
830 O2_SIGNPOST_END(root_arrow_fs, tid,
"Generator",
"Done creating batch compressed:%zu uncompressed:%zu", totalCompressedSize, totalUncompressedSize);
839 case arrow::Type::BOOL:
841 case arrow::Type::UINT8:
843 case arrow::Type::UINT16:
845 case arrow::Type::UINT32:
847 case arrow::Type::UINT64:
849 case arrow::Type::INT8:
851 case arrow::Type::INT16:
853 case arrow::Type::INT32:
855 case arrow::Type::INT64:
857 case arrow::Type::FLOAT:
859 case arrow::Type::DOUBLE:
867 const std::string&
path,
868 const std::shared_ptr<const arrow::KeyValueMetadata>& metadata)
870 arrow::dataset::FileSource
source{
path, shared_from_this()};
871 auto prefix = metadata->Get(
"branch_prefix");
873 return std::make_shared<TTreeOutputStream>(
GetTree(
source).get(), *prefix);
875 return std::make_shared<TTreeOutputStream>(
GetTree(
source).get(),
"");
889 auto typeGenerator = [](std::shared_ptr<arrow::DataType>
const&
type,
int size) -> std::shared_ptr<arrow::DataType> {
892 return arrow::list(
type);
894 return std::move(
type);
896 return arrow::fixed_size_list(
type,
size);
901 case EDataType::kBool_t:
902 return typeGenerator(arrow::boolean(),
size);
903 case EDataType::kUChar_t:
904 return typeGenerator(arrow::uint8(),
size);
905 case EDataType::kUShort_t:
906 return typeGenerator(arrow::uint16(),
size);
907 case EDataType::kUInt_t:
908 return typeGenerator(arrow::uint32(),
size);
909 case EDataType::kULong64_t:
910 return typeGenerator(arrow::uint64(),
size);
911 case EDataType::kChar_t:
912 return typeGenerator(arrow::int8(),
size);
913 case EDataType::kShort_t:
914 return typeGenerator(arrow::int16(),
size);
915 case EDataType::kInt_t:
916 return typeGenerator(arrow::int32(),
size);
917 case EDataType::kLong64_t:
918 return typeGenerator(arrow::int64(),
size);
919 case EDataType::kFloat_t:
920 return typeGenerator(arrow::float32(),
size);
921 case EDataType::kDouble_t:
922 return typeGenerator(arrow::float64(),
size);
934 auto fs = std::dynamic_pointer_cast<VirtualRootFileSystemBase>(
source.filesystem());
939 auto objectHandler = fs->GetObjectHandler(
source);
941 if (!objectHandler->format->Equals(*
this)) {
947 auto tree = objectHandler->GetObjectAsOwner<TTree>().release();
948 if (
tree ==
nullptr) {
949 return arrow::Status::IOError(
"Unable to read tree ",
source.path());
952 auto branches =
tree->GetListOfBranches();
953 auto n = branches->GetEntries();
955 std::vector<std::shared_ptr<arrow::Field>>
fields;
957 bool prevIsSize =
false;
958 for (
auto i = 0;
i <
n; ++
i) {
959 auto branch =
static_cast<TBranch*
>(branches->At(
i));
960 if (branch ==
nullptr || branch->GetListOfLeaves()->At(0) ==
nullptr) {
961 return arrow::Status::IOError(
"Invalid branch ",
i,
" in tree ",
source.path());
963 std::string
name = branch->GetName();
964 if (prevIsSize &&
fields.back()->name() !=
name +
"_size") {
965 throw runtime_error_f(
"Unexpected layout for VLA container %s.", branch->GetName());
968 if (
name.ends_with(
"_size")) {
969 fields.emplace_back(std::make_shared<arrow::Field>(
name, arrow::int32()));
974 branch->GetExpectedType(cls,
type);
979 auto listSize =
static_cast<TLeaf*
>(branch->GetListOfLeaves()->At(0))->GetLenStatic();
986 if (!
fields.empty() &&
fields.back()->name().ends_with(
"_size")) {
989 return std::make_shared<arrow::Schema>(
fields);
994 arrow::dataset::FileSource
source, arrow::compute::Expression partition_expression,
995 std::shared_ptr<arrow::Schema> physical_schema)
998 return std::make_shared<TTreeFileFragment>(
source, std::dynamic_pointer_cast<arrow::dataset::FileFormat>(shared_from_this()),
999 std::move(partition_expression),
1005 std::vector<TBranch*> branches;
1006 std::vector<TBranch*> sizesBranches;
1007 std::vector<std::shared_ptr<arrow::Array>> valueArrays;
1008 std::vector<std::shared_ptr<arrow::Array>> sizeArrays;
1009 std::vector<std::shared_ptr<arrow::DataType>> valueTypes;
1011 std::vector<int64_t> valuesIdealBasketSize;
1012 std::vector<int64_t> sizeIdealBasketSize;
1014 std::vector<int64_t> typeSizes;
1015 std::vector<int64_t> listSizes;
1016 bool firstBasket =
true;
1019 void finaliseBasketSize(std::shared_ptr<arrow::RecordBatch> firstBatch)
1022 O2_SIGNPOST_START(root_arrow_fs, sid,
"finaliseBasketSize",
"First batch with %lli rows received and %zu columns",
1023 firstBatch->num_rows(), firstBatch->columns().size());
1024 for (
size_t i = 0;
i < branches.size();
i++) {
1025 auto* branch = branches[
i];
1026 auto* sizeBranch = sizesBranches[
i];
1028 int valueSize = valueTypes[
i]->byte_width();
1029 if (listSizes[
i] == 1) {
1030 O2_SIGNPOST_EVENT_EMIT(root_arrow_fs, sid,
"finaliseBasketSize",
"Branch %s exists and uses %d bytes per entry for %lli entries.",
1031 branch->GetName(), valueSize, firstBatch->num_rows());
1032 assert(sizeBranch ==
nullptr);
1033 branch->SetBasketSize(1024 + firstBatch->num_rows() * valueSize);
1034 }
else if (listSizes[
i] == -1) {
1035 O2_SIGNPOST_EVENT_EMIT(root_arrow_fs, sid,
"finaliseBasketSize",
"Branch %s exists and uses %d bytes per entry.",
1036 branch->GetName(), valueSize);
1038 auto column = firstBatch->GetColumnByName(schema_->field(
i)->name());
1039 auto list = std::static_pointer_cast<arrow::ListArray>(column);
1040 O2_SIGNPOST_EVENT_EMIT(root_arrow_fs, sid,
"finaliseBasketSize",
"Branch %s needed. Associated size branch %s and there are %lli entries of size %d in that list.",
1041 branch->GetName(), sizeBranch->GetName(), list->length(), valueSize);
1042 branch->SetBasketSize(1024 + firstBatch->num_rows() * valueSize * list->length());
1043 sizeBranch->SetBasketSize(1024 + firstBatch->num_rows() * 4);
1045 O2_SIGNPOST_EVENT_EMIT(root_arrow_fs, sid,
"finaliseBasketSize",
"Branch %s needed. There are %lli entries per array of size %d in that list.",
1046 branch->GetName(), listSizes[
i], valueSize);
1047 assert(sizeBranch ==
nullptr);
1048 branch->SetBasketSize(1024 + firstBatch->num_rows() * valueSize * listSizes[
i]);
1051 auto field = firstBatch->schema()->field(
i);
1052 if (field->name().starts_with(
"fIndexArray")) {
1054 int idealBasketSize = 4 * firstBatch->num_rows() + 1024 + field->type()->byte_width() * firstBatch->num_rows();
1055 int basketSize = std::max(32000, idealBasketSize);
1056 sizeBranch->SetBasketSize(basketSize);
1057 branch->SetBasketSize(basketSize);
1067 std::shared_ptr<arrow::io::OutputStream> destination,
1068 arrow::fs::FileLocator destination_locator)
1069 : FileWriter(
schema, options, destination, destination_locator)
1072 auto directoryStream = std::dynamic_pointer_cast<TDirectoryFileOutputStream>(destination_);
1073 auto treeStream = std::dynamic_pointer_cast<TTreeOutputStream>(destination_);
1075 if (directoryStream.get()) {
1076 TDirectoryFile* dir = directoryStream->GetDirectory();
1078 auto*
tree =
new TTree(destination_locator_.path.c_str(),
"");
1079 treeStream = std::make_shared<TTreeOutputStream>(
tree,
"");
1080 }
else if (treeStream.get()) {
1084 auto*
tree = treeStream->GetTree();
1085 treeStream = std::make_shared<TTreeOutputStream>(
tree, destination_locator_.path);
1088 throw std::runtime_error(
"Unsupported backend.");
1092 auto& field =
schema->field(
i);
1093 listSizes.push_back(1);
1095 int valuesIdealBasketSize = 0;
1097 switch (field->type()->id()) {
1098 case arrow::Type::FIXED_SIZE_LIST: {
1099 listSizes.back() = std::static_pointer_cast<arrow::FixedSizeListType>(field->type())->list_size();
1100 valuesIdealBasketSize = 1024 + valueTypes.back()->byte_width() * listSizes.back();
1101 valueTypes.push_back(field->type()->field(0)->type());
1102 sizesBranches.push_back(
nullptr);
1103 std::string leafList = fmt::format(
"{}[{}]{}", field->name(), listSizes.back(),
rootSuffixFromArrow(valueTypes.back()->id()));
1104 branches.push_back(treeStream->CreateBranch(field->name().c_str(), leafList.c_str()));
1106 case arrow::Type::LIST: {
1107 valueTypes.push_back(field->type()->field(0)->type());
1108 std::string leafList = fmt::format(
"{}[{}_size]{}", field->name(), field->name(),
rootSuffixFromArrow(valueTypes.back()->id()));
1109 listSizes.back() = -1;
1110 std::string sizeLeafList = field->name() +
"_size/I";
1111 sizesBranches.push_back(treeStream->CreateBranch((field->name() +
"_size").c_str(), sizeLeafList.c_str()));
1112 branches.push_back(treeStream->CreateBranch(field->name().c_str(), leafList.c_str()));
1117 valueTypes.push_back(field->type());
1119 sizesBranches.push_back(
nullptr);
1120 branches.push_back(treeStream->CreateBranch(field->name().c_str(), leafList.c_str()));
1127 arrow::Status
Write(
const std::shared_ptr<arrow::RecordBatch>& batch)
override
1130 firstBasket =
false;
1131 finaliseBasketSize(batch);
1135 if (batch->columns().empty() || batch->num_rows() == 0) {
1136 return arrow::Status::OK();
1140 auto directoryStream = std::dynamic_pointer_cast<TDirectoryFileOutputStream>(destination_);
1141 TTree*
tree =
nullptr;
1142 if (directoryStream.get()) {
1143 TDirectoryFile* dir = directoryStream->GetDirectory();
1144 tree = (TTree*)dir->Get(destination_locator_.path.c_str());
1146 auto treeStream = std::dynamic_pointer_cast<TTreeOutputStream>(destination_);
1150 throw std::runtime_error(
"Unsupported backend.");
1153 for (
auto i = 0u;
i < batch->columns().
size(); ++
i) {
1154 auto column = batch->column(
i);
1155 auto& field = batch->schema()->field(
i);
1157 valueArrays.push_back(
nullptr);
1159 switch (field->type()->id()) {
1160 case arrow::Type::FIXED_SIZE_LIST: {
1161 auto list = std::static_pointer_cast<arrow::FixedSizeListArray>(column);
1162 if (list->list_type()->field(0)->type()->id() == arrow::Type::BOOL) {
1163 int64_t
length = list->length() * list->list_type()->list_size();
1164 arrow::UInt8Builder builder;
1165 auto ok = builder.Reserve(
length);
1168 auto boolArray = std::static_pointer_cast<arrow::BooleanArray>(list->values());
1170 if (boolArray->IsValid(
i)) {
1173 auto ok = builder.Append(
value);
1176 auto ok = builder.AppendNull();
1179 valueArrays.back() = *builder.Finish();
1181 valueArrays.back() = list->values();
1184 case arrow::Type::LIST: {
1185 auto list = std::static_pointer_cast<arrow::ListArray>(column);
1186 valueArrays.back() = list->values();
1188 case arrow::Type::BOOL: {
1191 auto boolArray = std::static_pointer_cast<arrow::BooleanArray>(column);
1193 int64_t
length = boolArray->length();
1194 arrow::UInt8Builder builder;
1195 auto ok = builder.Reserve(
length);
1198 if (boolArray->IsValid(
i)) {
1201 auto ok = builder.Append(
value);
1204 auto ok = builder.AppendNull();
1207 valueArrays.back() = *builder.Finish();
1210 valueArrays.back() = column;
1215 while (pos < batch->num_rows()) {
1216 for (
size_t bi = 0; bi < branches.size(); ++bi) {
1217 auto* branch = branches[bi];
1218 auto* sizeBranch = sizesBranches[bi];
1219 auto array = batch->column(bi);
1220 auto& field = batch->schema()->field(bi);
1221 auto& listSize = listSizes[bi];
1222 auto valueType = valueTypes[bi];
1223 auto valueArray = valueArrays[bi];
1225 switch (field->type()->id()) {
1226 case arrow::Type::LIST: {
1227 auto list = std::static_pointer_cast<arrow::ListArray>(
array);
1228 listSize = list->value_length(
pos);
1229 uint8_t const*
buffer = std::static_pointer_cast<arrow::PrimitiveArray>(valueArray)->values()->data() +
array->offset() + list->value_offset(
pos) * valueType->byte_width();
1230 branch->SetAddress((
void*)
buffer);
1231 sizeBranch->SetAddress(&listSize);
1233 case arrow::Type::FIXED_SIZE_LIST:
1236 auto byteWidth = valueType->byte_width() ? valueType->byte_width() : 1;
1237 uint8_t const*
buffer = std::static_pointer_cast<arrow::PrimitiveArray>(valueArray)->values()->data() +
array->offset() +
pos * listSize * byteWidth;
1238 branch->SetAddress((
void*)
buffer);
1245 return arrow::Status::OK();
1250 auto treeStream = std::dynamic_pointer_cast<TTreeOutputStream>(destination_);
1251 auto*
tree = treeStream->GetTree();
1252 tree->Write(
"", TObject::kOverwrite);
1253 tree->SetDirectory(
nullptr);
1258arrow::Result<std::shared_ptr<arrow::dataset::FileWriter>>
TTreeFileFormat::MakeWriter(std::shared_ptr<arrow::io::OutputStream> destination, std::shared_ptr<arrow::Schema>
schema, std::shared_ptr<arrow::dataset::FileWriteOptions> options, arrow::fs::FileLocator destination_locator)
const
1260 auto writer = std::make_shared<TTreeFileWriter>(
schema, options, destination, destination_locator);
1261 return std::dynamic_pointer_cast<arrow::dataset::FileWriter>(writer);
1266 std::shared_ptr<TTreeFileWriteOptions> options(
std::shared_ptr< arrow::Schema > schema
std::vector< std::shared_ptr< arrow::Field > > fields
o2::raw::RawFileWriter * raw
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered disabling the noisy pad check for that pad Treat signal above this minimum as saturated Smoothing factor for the exponential Highly Ionising Particle tail filter Number of timebins to use for the averaging Add additional custom track errors when crossing relative as fraction of Do N fit passes in final fit of< 0:reject at max -n hits") AddOptionRTC(rejectIFCLowRadiusCluster, uint8_t, 1, "", 0, "Reject clusters that get the IFC mask error during refit") AddOptionRTC(dEdxTruncLow, uint8_t, 2, "", 0, "Low truncation threshold, fraction of 128") AddOptionRTC(dEdxTruncHigh, uint8_t, 77, "", 0, "High truncation threshold, fraction of 128") AddOptionRTC(extrapolationTracking, int8_t, 1, "", 0, "Enable Extrapolation Tracking(prolong tracks to adjacent sectors to find short segments)") AddOptionRTC(disableRefitAttachment, uint8_t, 0, "", 0, "Bitmask to disable certain attachment steps during refit(1:attachment, 2:propagation, 4:loop following, 8:mirroring)") AddOptionRTC(rejectionStrategy, uint8_t, o2::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression(0=no, 1=strategy A, 2=strategy B)") AddOptionRTC(mergeLoopersAfterburner, uint8_t, 1, "", 0, "Run afterburner for additional looper merging") AddOptionRTC(compressionTypeMask, uint8_t, o2::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits(1=truncate charge/width LSB, 2=differences, 4=track-model)") AddOptionRTC(compressionSortOrder, uint8_t, o2::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression(0=time, 1=pad, 2=Z-time-pad, 3=Z-pad-time, 4=no sorting(use incoming order))") AddOptionRTC(sigBitsCharge, uint8_t, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") AddOptionRTC(sigBitsWidth, uint8_t, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") AddOptionRTC(dropLoopers, uint8_t, 0, "", 0, "Drop looping tracks starting from second loop") AddOptionRTC(mergerInterpolateErrors, uint8_t, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergerInterpolateRejectAlsoOnCurrentPosition, uint8_t, 1, "", 0, "When using mergerInterpolateErrors, reject based on chi2 twice computed with interpolated and current track position starting from NDF > mergerNonInterpolateRejectMinNDF Merge tracks accross the central electrode Enable PID response Add sub threshold clusters in TPC dEdx computation OR mask of TPC flags that will reject the cluster in alternative dEdx Reject edge clusters based on uncorrected track Y during track fit Increase decrease removal by when on this number of pads from the edge h configStandalone Reconstruction rec_trd Max chi2 for TRD tracklets to be matched to a track Chi2 cut for strict matching mode Number of sigmas for ITS TPC track time error estimate Addition to search road around track prolongation along Y in cm Optimal tracklet rphi resolution in maximum chi2 per attached tracklet for TRD tracks take into account the full likelihood of the slope including exponential tails Tracks with less attached tracklets are discarded after the tracking Post trigger Pile up integration time in BCs fits all iterations but the last one in projections Use material lookup table for TPC refit Apply workarounds to avoid cyclic merge should not be needed tpc dyn configStandalone Processing proc_rtc Replace constant variables static by constexpr expressions false
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered disabling the noisy pad check for that pad Treat signal above this minimum as saturated Smoothing factor for the exponential Highly Ionising Particle tail filter Number of timebins to use for the averaging Add additional custom track errors when crossing relative as fraction of Do N fit passes in final fit of< 0:reject at max -n hits") AddOptionRTC(rejectIFCLowRadiusCluster, uint8_t, 1, "", 0, "Reject clusters that get the IFC mask error during refit") AddOptionRTC(dEdxTruncLow, uint8_t, 2, "", 0, "Low truncation threshold, fraction of 128") AddOptionRTC(dEdxTruncHigh, uint8_t, 77, "", 0, "High truncation threshold, fraction of 128") AddOptionRTC(extrapolationTracking, int8_t, 1, "", 0, "Enable Extrapolation Tracking(prolong tracks to adjacent sectors to find short segments)") AddOptionRTC(disableRefitAttachment, uint8_t, 0, "", 0, "Bitmask to disable certain attachment steps during refit(1:attachment, 2:propagation, 4:loop following, 8:mirroring)") AddOptionRTC(rejectionStrategy, uint8_t, o2::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression(0=no, 1=strategy A, 2=strategy B)") AddOptionRTC(mergeLoopersAfterburner, uint8_t, 1, "", 0, "Run afterburner for additional looper merging") AddOptionRTC(compressionTypeMask, uint8_t, o2::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits(1=truncate charge/width LSB, 2=differences, 4=track-model)") AddOptionRTC(compressionSortOrder, uint8_t, o2::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression(0=time, 1=pad, 2=Z-time-pad, 3=Z-pad-time, 4=no sorting(use incoming order))") AddOptionRTC(sigBitsCharge, uint8_t, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") AddOptionRTC(sigBitsWidth, uint8_t, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") AddOptionRTC(dropLoopers, uint8_t, 0, "", 0, "Drop looping tracks starting from second loop") AddOptionRTC(mergerInterpolateErrors, uint8_t, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergerInterpolateRejectAlsoOnCurrentPosition, uint8_t, 1, "", 0, "When using mergerInterpolateErrors, reject based on chi2 twice computed with interpolated and current track position starting from NDF > mergerNonInterpolateRejectMinNDF Merge tracks accross the central electrode Enable PID response Add sub threshold clusters in TPC dEdx computation OR mask of TPC flags that will reject the cluster in alternative dEdx Reject edge clusters based on uncorrected track Y during track fit Increase decrease removal by when on this number of pads from the edge h configStandalone Reconstruction rec_trd Max chi2 for TRD tracklets to be matched to a track Chi2 cut for strict matching mode Number of sigmas for ITS TPC track time error estimate Addition to search road around track prolongation along Y in cm Optimal tracklet rphi resolution in maximum chi2 per attached tracklet for TRD tracks take into account the full likelihood of the slope including exponential tails Tracks with less attached tracklets are discarded after the tracking Post trigger Pile up integration time in BCs fits all iterations but the last one in projections Use material lookup table for TPC refit Apply workarounds to avoid cyclic merge should not be needed tpc dyn configStandalone Processing proc_rtc true
#define DEFINE_DPL_PLUGIN_INSTANCE(NAME, KIND)
#define DEFINE_DPL_PLUGINS_END
#define DEFINE_DPL_PLUGINS_BEGIN
#define O2_DECLARE_DYNAMIC_LOG(name)
#define O2_SIGNPOST_ID_FROM_POINTER(name, log, pointer)
#define O2_SIGNPOST_END(log, id, name, format,...)
#define O2_SIGNPOST_EVENT_EMIT(log, id, name, format,...)
#define O2_SIGNPOST_START(log, id, name, format,...)
std::string type_name() const override
SingleTreeFileSystem(TTree *tree, size_t &totalCompressedSize, size_t &totalUncompressedSize)
arrow::Result< arrow::fs::FileInfo > GetFileInfo(std::string const &path) override
std::shared_ptr< RootObjectHandler > GetObjectHandler(arrow::dataset::FileSource source) override
std::unique_ptr< TTree > & GetTree(arrow::dataset::FileSource) override
~TTreeDeferredReadOutputStream() override=default
arrow::Status Reset(std::vector< ReadOps > ops, int64_t initial_capacity, arrow::MemoryPool *pool)
Initialize state of OutputStream with newly allocated memory and set position to 0.
arrow::Status Write(const void *data, int64_t nbytes) override
arrow::Result< std::shared_ptr< arrow::Buffer > > Finish()
Close the stream and return the buffer.
arrow::Result< int64_t > Tell() const override
static arrow::Result< std::shared_ptr< TTreeDeferredReadOutputStream > > Create(std::vector< ReadOps > &ops, int64_t initial_capacity=4096, arrow::MemoryPool *pool=arrow::default_memory_pool())
Create in-memory output stream with indicated capacity using a memory pool.
arrow::Status Close() override
Close the stream, preserving the buffer (retrieve it with Finish()).
bool closed() const override
TTreeFileFragment(arrow::dataset::FileSource source, std::shared_ptr< arrow::dataset::FileFormat > format, arrow::compute::Expression partition_expression, std::shared_ptr< arrow::Schema > physical_schema)
std::vector< ReadOps > & ops()
std::shared_ptr< arrow::Buffer > GetPlaceholderForOp(size_t size)
arrow::Result< std::shared_ptr< arrow::io::OutputStream > > OpenOutputStream(const std::string &path, const std::shared_ptr< const arrow::KeyValueMetadata > &metadata) override
~TTreeFileSystem() override
virtual std::unique_ptr< TTree > & GetTree(arrow::dataset::FileSource source)=0
TTreeFileWriteOptions(std::shared_ptr< arrow::dataset::FileFormat > format)
arrow::Status Write(const std::shared_ptr< arrow::RecordBatch > &batch) override
arrow::Future FinishInternal() override
TTreeFileWriter(std::shared_ptr< arrow::Schema > schema, std::shared_ptr< arrow::dataset::FileWriteOptions > options, std::shared_ptr< arrow::io::OutputStream > destination, arrow::fs::FileLocator destination_locator)
arrow::Status Write(const void *data, int64_t nbytes) override
arrow::Result< int64_t > Tell() const override
arrow::Status Close() override
bool closed() const override
TBranch * CreateBranch(char const *branchName, char const *sizeBranch)
TTreeOutputStream(TTree *, std::string branchPrefix)
GLuint GLsizei const GLuint const GLintptr * offsets
GLuint const GLchar * name
GLsizei GLsizei GLchar * source
GLsizei const GLfloat * value
GLint GLint GLsizei GLint GLenum GLenum type
GLuint GLsizei GLsizei * length
GLsizei const GLchar *const * path
GLint GLint GLsizei GLint GLenum format
Defining ITS Vertex explicitly as messageable.
RuntimeErrorRef runtime_error(const char *)
TBufferFile & rootBuffer()
@ RootObjectReadingImplementation
char const * rootSuffixFromArrow(arrow::Type::type id)
auto arrowTypeFromROOT(EDataType type, int size)
void bigEndianCopy(void *dest, const void *src, int count, size_t typeSize)
RuntimeErrorRef runtime_error_f(const char *,...)
int64_t rootBranchEntries
std::shared_ptr< arrow::Buffer > targetBuffer
std::function< std::shared_ptr< arrow::dataset::FileWriteOptions >()> options
RootArrowFactory * create() override
std::shared_ptr< o2::framework::TTreeFileFormat > format
size_t totalCompressedSize
size_t totalUncompressedSize
VectorOfTObjectPtrs other
std::unique_ptr< TTree > tree((TTree *) flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str()))
std::vector< ReadoutWindowData > rows