isolate root dependencies, avoid TFile
This commit is contained in:
parent
b0966401c4
commit
cc157c235c
10 changed files with 154 additions and 123 deletions
24
Makefile
24
Makefile
|
@ -6,24 +6,28 @@ ROOTFLAGS = -std=c++17 -m64 -I$(ROOT)/include
|
||||||
ROOTLIBS = -L$(ROOT)/lib -lCore -lRIO -lROOTNTuple -lxxhash -Wl,-rpath,$(ROOT)/lib -pthread
|
ROOTLIBS = -L$(ROOT)/lib -lCore -lRIO -lROOTNTuple -lxxhash -Wl,-rpath,$(ROOT)/lib -pthread
|
||||||
LIBS = -lglfw
|
LIBS = -lglfw
|
||||||
MOLD = mold -run
|
MOLD = mold -run
|
||||||
|
ROOT_IFACE = build/libroot_iface.so
|
||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
all: build/imgui.o build/root_stuff.o noasan
|
all: build/imgui.o $(ROOT_IFACE) noasan
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm build/*.o rntviewer
|
rm build/*.o rntviewer $(ROOT_IFACE)
|
||||||
|
|
||||||
build/imgui.o: src/imgui_inc.cpp third_party/imgui/imgui.h
|
build/imgui.o: src/imgui_inc.cpp third_party/imgui/imgui.h
|
||||||
$(CXX) -O3 -fPIC -c -Ithird_party/imgui $< -o $@
|
$(CXX) -O3 -fPIC -c -Ithird_party/imgui $< -o $@
|
||||||
|
|
||||||
build/root_stuff.o: src/PseudoMiniFile.cxx
|
# $(ROOT_IFACE): src/root/RMicroFileReader.cxx
|
||||||
$(CXX) -O3 -fPIC -c $(ROOTFLAGS) $< -o $@
|
# $(CXX) -O3 -fPIC -c $(ROOTFLAGS) $< -o $@
|
||||||
|
|
||||||
d: build/root_stuff.o build/imgui.o
|
$(ROOT_IFACE): src/root/RMicroFileReader.cxx
|
||||||
$(MOLD) $(CXX) -DDEBUG -g -O0 -DENABLE_ASAN $(CFLAGS) -fsanitize=undefined $(INC) $(ROOTFLAGS) -o rntviewer src/rntviewer.cpp build/imgui.o build/root_stuff.o -lasan $(ROOTLIBS) $(LIBS)
|
$(CXX) -O3 -fPIC -shared $(ROOTFLAGS) $< -o $@ $(ROOTLIBS)
|
||||||
|
|
||||||
noasan: build/root_stuff.o build/imgui.o
|
d: $(ROOT_IFACE) build/imgui.o
|
||||||
$(MOLD) $(CXX) -DDEBUG -g -O0 $(CFLAGS) -fsanitize=undefined $(INC) $(ROOTFLAGS) -o rntviewer src/rntviewer.cpp build/imgui.o build/root_stuff.o $(ROOTLIBS) $(LIBS)
|
$(MOLD) $(CXX) -DDEBUG -g -O0 -DENABLE_ASAN $(CFLAGS) -fsanitize=undefined $(INC) -o rntviewer src/rntviewer.cpp build/imgui.o $(ROOT_IFACE) -lasan $(LIBS)
|
||||||
|
|
||||||
r: build/root_stuff.o build/imgui.o
|
noasan: $(ROOT_IFACE) build/imgui.o
|
||||||
$(MOLD) $(CXX) -O2 $(CFLAGS) $(INC) $(ROOTFLAGS) -o rntviewer src/rntviewer.cpp build/imgui.o build/root_stuff.o $(ROOTLIBS) $(LIBS)
|
$(MOLD) $(CXX) -DDEBUG -g -O0 $(CFLAGS) -fsanitize=undefined $(INC) -o rntviewer src/rntviewer.cpp build/imgui.o $(ROOT_IFACE) $(LIBS)
|
||||||
|
|
||||||
|
r: $(ROOT_IFACE) build/imgui.o
|
||||||
|
$(MOLD) $(CXX) -O2 $(CFLAGS) $(INC) -o rntviewer src/rntviewer.cpp build/imgui.o $(ROOT_IFACE) $(LIBS)
|
||||||
|
|
|
@ -8,7 +8,7 @@ Size=1152,1414
|
||||||
|
|
||||||
[Window][main]
|
[Window][main]
|
||||||
Pos=0,0
|
Pos=0,0
|
||||||
Size=1777,680
|
Size=3440,1440
|
||||||
|
|
||||||
[Window][Hex View]
|
[Window][Hex View]
|
||||||
Pos=91,62
|
Pos=91,62
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <ROOT/RError.hxx>
|
|
||||||
#include <ROOT/RNTuple.hxx>
|
|
||||||
#include <ROOT/RRawFile.hxx>
|
|
||||||
#include <string_view>
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
struct RNTuple_FileInfo {
|
|
||||||
std::uint64_t anchor_seek;
|
|
||||||
std::uint64_t anchor_nbytes;
|
|
||||||
std::uint64_t anchor_key_seek;
|
|
||||||
std::uint64_t anchor_key_nbytes;
|
|
||||||
std::uint64_t rblob_key_header_nbytes;
|
|
||||||
std::uint64_t tfile_header_nbytes;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PseudoMiniFileReader final {
|
|
||||||
public:
|
|
||||||
explicit PseudoMiniFileReader(ROOT::Internal::RRawFile *rawFile);
|
|
||||||
|
|
||||||
// ROOT::Experimental::RResult<ROOT::Experimental::RNTuple>
|
|
||||||
ROOT::Experimental::RResult<RNTuple_FileInfo>
|
|
||||||
GetNTupleProper(std::string_view ntupleName);
|
|
||||||
|
|
||||||
void
|
|
||||||
ReadBuffer(void *buffer, size_t nbytes, std::uint64_t offset);
|
|
||||||
|
|
||||||
// ROOT::Experimental::RNTuple
|
|
||||||
// CreateAnchor(
|
|
||||||
// std::uint16_t versionEpoch, std::uint16_t versionMajor, std::uint16_t versionMinor, std::uint16_t versionPatch,
|
|
||||||
// std::uint64_t seekHeader, std::uint64_t nbytesHeader, std::uint64_t lenHeader, std::uint64_t seekFooter,
|
|
||||||
// std::uint64_t nbytesFooter, std::uint64_t lenFooter, std::uint64_t maxKeySize);
|
|
||||||
|
|
||||||
ROOT::Internal::RRawFile *fRawFile;
|
|
||||||
std::uint64_t fMaxBlobSize;
|
|
||||||
};
|
|
|
@ -1,17 +1,12 @@
|
||||||
#pragma once
|
template <typename F>
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
struct Defer_Guard {
|
struct Defer_Guard {
|
||||||
template <typename F>
|
|
||||||
Defer_Guard(F && f) : _f(f) {}
|
Defer_Guard(F && f) : _f(f) {}
|
||||||
~Defer_Guard() { _f(); }
|
~Defer_Guard() { _f(); }
|
||||||
std::function<void()> _f;
|
F _f;
|
||||||
};
|
};
|
||||||
struct Defer_Guard_Helper {
|
struct Defer_Guard_Helper {
|
||||||
template <typename F>
|
template <typename F>
|
||||||
Defer_Guard operator+(F&& f) { return Defer_Guard(std::forward<F>(f)); }
|
Defer_Guard<F> operator+(F&& f) { return Defer_Guard<F>(std::forward<F>(f)); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CONCAT_STR_INTERNAL(A, B) A##B
|
#define CONCAT_STR_INTERNAL(A, B) A##B
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/inotify.h>
|
#include <sys/inotify.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <limits.h> // for NAME_MAX
|
#include <limits.h> // for NAME_MAX
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
internal
|
internal
|
||||||
String8 rntuple_description(Arena *arena, const RNTuple &anchor)
|
String8 rntuple_description(Arena *arena, const RNTuple_Anchor &anchor)
|
||||||
{
|
{
|
||||||
String8 desc = push_str8f(arena, "version %u.%u.%u.%u",
|
String8 desc = push_str8f(arena, "version %u.%u.%u.%u",
|
||||||
anchor.GetVersionEpoch(),
|
anchor.fVersionEpoch,
|
||||||
anchor.GetVersionMajor(),
|
anchor.fVersionMajor,
|
||||||
anchor.GetVersionMinor(),
|
anchor.fVersionMinor,
|
||||||
anchor.GetVersionPatch());
|
anchor.fVersionPatch);
|
||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,31 +14,14 @@ RNTuple_Info get_rntuple_info(const char *fname, const char *ntpl_name)
|
||||||
{
|
{
|
||||||
RNTuple_Info info = {};
|
RNTuple_Info info = {};
|
||||||
|
|
||||||
// Open the TFile
|
|
||||||
TFile *tfile = TFile::Open(fname, "READ");
|
|
||||||
if (!tfile) {
|
|
||||||
fprintf(stderr, "Failed to open TFile.\n");
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
defer { delete tfile; };
|
|
||||||
|
|
||||||
// Get the RNTuple information
|
|
||||||
const RNTuple *anchor = tfile->Get<RNTuple>(ntpl_name);
|
|
||||||
if (anchor) {
|
|
||||||
info.anchor = *anchor;
|
|
||||||
info.rng_header.start = anchor->GetSeekHeader();
|
|
||||||
info.rng_header.len = anchor->GetNBytesHeader();
|
|
||||||
info.rng_footer.start = anchor->GetSeekFooter();
|
|
||||||
info.rng_footer.len = anchor->GetNBytesFooter();
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "RNTuple '%s' not found in %s.\n", ntpl_name, fname);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: proper error handling
|
// TODO: proper error handling
|
||||||
auto raw_file = ROOT::Internal::RRawFile::Create(fname);
|
RMicroFileReader file_reader { fname };
|
||||||
if (raw_file) {
|
RNTuple_File_Info file_info = file_reader.GetNTupleProper(ntpl_name);
|
||||||
PseudoMiniFileReader file_reader { raw_file.get() };
|
if (!file_info.failed) {
|
||||||
auto file_info = file_reader.GetNTupleProper(ntpl_name).Unwrap();
|
info.rng_header.start = file_info.anchor.fSeekHeader;
|
||||||
|
info.rng_header.len = file_info.anchor.fNBytesHeader;
|
||||||
|
info.rng_footer.start = file_info.anchor.fSeekFooter;
|
||||||
|
info.rng_footer.len = file_info.anchor.fNBytesFooter;
|
||||||
info.rng_anchor.start = file_info.anchor_seek;
|
info.rng_anchor.start = file_info.anchor_seek;
|
||||||
info.rng_anchor.len = file_info.anchor_nbytes;
|
info.rng_anchor.len = file_info.anchor_nbytes;
|
||||||
info.rng_anchor_key.start = file_info.anchor_key_seek;
|
info.rng_anchor_key.start = file_info.anchor_key_seek;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using RNTuple = ROOT::Experimental::RNTuple;
|
// using RNTuple = ROOT::Experimental::RNTuple;
|
||||||
|
|
||||||
struct Byte_Range {
|
struct Byte_Range {
|
||||||
u64 start, len;
|
u64 start, len;
|
||||||
|
@ -6,7 +6,7 @@ struct Byte_Range {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RNTuple_Info {
|
struct RNTuple_Info {
|
||||||
RNTuple anchor;
|
RNTuple_Anchor anchor;
|
||||||
|
|
||||||
u64 root_file_header_size;
|
u64 root_file_header_size;
|
||||||
u64 rblob_header_size;
|
u64 rblob_header_size;
|
||||||
|
|
|
@ -1,9 +1,19 @@
|
||||||
#include <ROOT/RNTupleReader.hxx>
|
// ************************************
|
||||||
#include <ROOT/RNTuple.hxx>
|
// *
|
||||||
#include <TFile.h>
|
// * rntviewer
|
||||||
|
// *
|
||||||
|
// * A graphical RNTuple visualizer
|
||||||
|
// *
|
||||||
|
// * @author silverweed, 2024
|
||||||
|
// *
|
||||||
|
// ***********************************
|
||||||
|
// #include <ROOT/RNTupleReader.hxx>
|
||||||
|
// #include <ROOT/RNTuple.hxx>
|
||||||
|
// #include <TFile.h>
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <utility> // for std::forward
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -18,7 +28,7 @@
|
||||||
#define GLFW_INCLUDE_NONE
|
#define GLFW_INCLUDE_NONE
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
#include "PseudoMiniFile.hxx"
|
#include "root/RMicroFileReader.hxx"
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "defer.hpp"
|
#include "defer.hpp"
|
||||||
|
@ -40,8 +50,6 @@ namespace chr = std::chrono;
|
||||||
#include "render.cpp"
|
#include "render.cpp"
|
||||||
#include "mainloop.cpp"
|
#include "mainloop.cpp"
|
||||||
|
|
||||||
using namespace ROOT::Experimental;
|
|
||||||
|
|
||||||
internal
|
internal
|
||||||
b8 init_imgui(GLFWwindow* window) {
|
b8 init_imgui(GLFWwindow* window) {
|
||||||
IMGUI_CHECKVERSION();
|
IMGUI_CHECKVERSION();
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/// Stripped-down version of RMiniFile.cxx, only used to read RNTuples from TFiles.
|
/// Stripped-down version of RMiniFile.cxx, only used to read RNTuples from TFiles.
|
||||||
|
|
||||||
#include "PseudoMiniFile.hxx"
|
#include "RMicroFileReader.hxx"
|
||||||
|
|
||||||
#include "Rtypes.h"
|
#include "Rtypes.h"
|
||||||
#include <ROOT/RConfig.hxx>
|
#include <ROOT/RConfig.hxx>
|
||||||
#include <ROOT/RError.hxx>
|
#include <ROOT/RError.hxx>
|
||||||
|
#include <ROOT/RNTuple.hxx>
|
||||||
#include <ROOT/RRawFile.hxx>
|
#include <ROOT/RRawFile.hxx>
|
||||||
#include <ROOT/RNTupleZip.hxx>
|
#include <ROOT/RNTupleZip.hxx>
|
||||||
#include <ROOT/RNTupleSerialize.hxx>
|
#include <ROOT/RNTupleSerialize.hxx>
|
||||||
|
@ -1064,9 +1064,21 @@ static size_t ComputeNumChunks(size_t nbytes, size_t maxChunkSize)
|
||||||
return nChunks;
|
return nChunks;
|
||||||
}
|
}
|
||||||
|
|
||||||
PseudoMiniFileReader::PseudoMiniFileReader(ROOT::Internal::RRawFile *rawFile) : fRawFile(rawFile) {}
|
struct RMicroFileReader::Impl {
|
||||||
|
std::unique_ptr<ROOT::Internal::RRawFile> fRawFile;
|
||||||
|
std::uint64_t fMaxBlobSize;
|
||||||
|
};
|
||||||
|
|
||||||
// ROOT::Experimental::RNTuple PseudoMiniFileReader::CreateAnchor(
|
RMicroFileReader::RMicroFileReader(const char *fname) {
|
||||||
|
impl = new Impl;
|
||||||
|
impl->fRawFile = ROOT::Internal::RRawFile::Create(fname);
|
||||||
|
}
|
||||||
|
|
||||||
|
RMicroFileReader::~RMicroFileReader() {
|
||||||
|
delete impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ROOT::Experimental::RNTuple RMicroFileReader::CreateAnchor(
|
||||||
// std::uint16_t versionEpoch, std::uint16_t versionMajor, std::uint16_t versionMinor, std::uint16_t versionPatch,
|
// std::uint16_t versionEpoch, std::uint16_t versionMajor, std::uint16_t versionMinor, std::uint16_t versionPatch,
|
||||||
// std::uint64_t seekHeader, std::uint64_t nbytesHeader, std::uint64_t lenHeader, std::uint64_t seekFooter,
|
// std::uint64_t seekHeader, std::uint64_t nbytesHeader, std::uint64_t lenHeader, std::uint64_t seekFooter,
|
||||||
// std::uint64_t nbytesFooter, std::uint64_t lenFooter, std::uint64_t maxKeySize)
|
// std::uint64_t nbytesFooter, std::uint64_t lenFooter, std::uint64_t maxKeySize)
|
||||||
|
@ -1087,10 +1099,15 @@ PseudoMiniFileReader::PseudoMiniFileReader(ROOT::Internal::RRawFile *rawFile) :
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// ROOT::Experimental::RResult<ROOT::Experimental::RNTuple>
|
// ROOT::Experimental::RResult<ROOT::Experimental::RNTuple>
|
||||||
ROOT::Experimental::RResult<RNTuple_FileInfo>
|
RNTuple_File_Info
|
||||||
PseudoMiniFileReader::GetNTupleProper(std::string_view ntupleName)
|
RMicroFileReader::GetNTupleProper(const char *ntupleName)
|
||||||
{
|
{
|
||||||
RNTuple_FileInfo fileInfo {};
|
RNTuple_File_Info fileInfo {};
|
||||||
|
|
||||||
|
#define FAIL(msg) \
|
||||||
|
fprintf(stderr, "%s", std::string(msg).c_str()); \
|
||||||
|
fileInfo.failed = true; \
|
||||||
|
return fileInfo
|
||||||
|
|
||||||
RTFHeader fileHeader;
|
RTFHeader fileHeader;
|
||||||
ReadBuffer(&fileHeader, sizeof(fileHeader), 0);
|
ReadBuffer(&fileHeader, sizeof(fileHeader), 0);
|
||||||
|
@ -1129,21 +1146,21 @@ PseudoMiniFileReader::GetNTupleProper(std::string_view ntupleName)
|
||||||
offset += name.GetSize();
|
offset += name.GetSize();
|
||||||
ReadBuffer(&name, 1, offset);
|
ReadBuffer(&name, 1, offset);
|
||||||
ReadBuffer(&name, name.GetSize(), offset);
|
ReadBuffer(&name, name.GetSize(), offset);
|
||||||
if (std::string_view(name.fData, name.fLName) == ntupleName) {
|
if (std::string_view(name.fData, name.fLName) == std::string_view(ntupleName)) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
offset = offsetNextKey;
|
offset = offsetNextKey;
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
return R__FAIL("no RNTuple named '" + std::string(ntupleName) + "' in file '" + fRawFile->GetUrl() + "'");
|
FAIL("no RNTuple named '" + std::string(ntupleName) + "' in file '" + impl->fRawFile->GetUrl() + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
offset = key.GetSeekKey() + key.fKeyLen;
|
offset = key.GetSeekKey() + key.fKeyLen;
|
||||||
|
|
||||||
constexpr size_t kMinNTupleSize = 70; // size of a RTFNTuple version 4 (min supported version)
|
constexpr size_t kMinNTupleSize = 70; // size of a RTFNTuple version 4 (min supported version)
|
||||||
if (key.fObjLen < kMinNTupleSize) {
|
if (key.fObjLen < kMinNTupleSize) {
|
||||||
return R__FAIL("invalid anchor size: " + std::to_string(key.fObjLen) + " < " + std::to_string(sizeof(RTFNTuple)));
|
FAIL("invalid anchor size: " + std::to_string(key.fObjLen) + " < " + std::to_string(sizeof(RTFNTuple)));
|
||||||
}
|
}
|
||||||
// The object length can be smaller than the size of RTFNTuple if it comes from a past RNTuple class version,
|
// The object length can be smaller than the size of RTFNTuple if it comes from a past RNTuple class version,
|
||||||
// or larger than it if it comes from a future RNTuple class version.
|
// or larger than it if it comes from a future RNTuple class version.
|
||||||
|
@ -1166,7 +1183,7 @@ PseudoMiniFileReader::GetNTupleProper(std::string_view ntupleName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ntuple->fVersionClass < 4) {
|
if (ntuple->fVersionClass < 4) {
|
||||||
return R__FAIL("invalid anchor, unsupported pre-release of RNTuple");
|
FAIL("invalid anchor, unsupported pre-release of RNTuple");
|
||||||
}
|
}
|
||||||
|
|
||||||
// We require that future class versions only append members and store the checksum in the last 8 bytes
|
// We require that future class versions only append members and store the checksum in the last 8 bytes
|
||||||
|
@ -1184,34 +1201,35 @@ PseudoMiniFileReader::GetNTupleProper(std::string_view ntupleName)
|
||||||
ckOnDisk = static_cast<uint64_t>(*ckOnDiskPtr);
|
ckOnDisk = static_cast<uint64_t>(*ckOnDiskPtr);
|
||||||
}
|
}
|
||||||
if (ckCalc != ckOnDisk) {
|
if (ckCalc != ckOnDisk) {
|
||||||
return R__FAIL("RNTuple anchor checksum mismatch");
|
FAIL("RNTuple anchor checksum mismatch");
|
||||||
}
|
}
|
||||||
|
|
||||||
fMaxBlobSize = ntuple->fMaxKeySize;
|
impl->fMaxBlobSize = ntuple->fMaxKeySize;
|
||||||
|
|
||||||
// return CreateAnchor(ntuple->fVersionEpoch, ntuple->fVersionMajor, ntuple->fVersionMinor, ntuple->fVersionPatch,
|
fileInfo.anchor = {ntuple->fVersionEpoch, ntuple->fVersionMajor, ntuple->fVersionMinor, ntuple->fVersionPatch,
|
||||||
// ntuple->fSeekHeader, ntuple->fNBytesHeader, ntuple->fLenHeader, ntuple->fSeekFooter,
|
ntuple->fSeekHeader, ntuple->fNBytesHeader, ntuple->fLenHeader, ntuple->fSeekFooter,
|
||||||
// ntuple->fNBytesFooter, ntuple->fLenFooter, ntuple->fMaxKeySize);
|
ntuple->fNBytesFooter, ntuple->fLenFooter, ntuple->fMaxKeySize};
|
||||||
|
|
||||||
return fileInfo;
|
return fileInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PseudoMiniFileReader::ReadBuffer(void *buffer, size_t nbytes, std::uint64_t offset)
|
void RMicroFileReader::ReadBuffer(void *buffer, size_t nbytes, std::uint64_t offset)
|
||||||
{
|
{
|
||||||
size_t nread;
|
size_t nread;
|
||||||
if (fMaxBlobSize == 0 || nbytes <= fMaxBlobSize) {
|
uint64_t maxBlobSize = impl->fMaxBlobSize;
|
||||||
|
if (maxBlobSize == 0 || nbytes <= maxBlobSize) {
|
||||||
// Fast path: read single blob
|
// Fast path: read single blob
|
||||||
nread = fRawFile->ReadAt(buffer, nbytes, offset);
|
nread = impl->fRawFile->ReadAt(buffer, nbytes, offset);
|
||||||
} else {
|
} else {
|
||||||
// Read chunked blob. See RNTupleFileWriter::WriteBlob() for details.
|
// Read chunked blob. See RNTupleFileWriter::WriteBlob() for details.
|
||||||
const size_t nChunks = ComputeNumChunks(nbytes, fMaxBlobSize);
|
const size_t nChunks = ComputeNumChunks(nbytes, maxBlobSize);
|
||||||
const size_t nbytesChunkOffsets = (nChunks - 1) * sizeof(std::uint64_t);
|
const size_t nbytesChunkOffsets = (nChunks - 1) * sizeof(std::uint64_t);
|
||||||
const size_t nbytesFirstChunk = fMaxBlobSize - nbytesChunkOffsets;
|
const size_t nbytesFirstChunk = maxBlobSize - nbytesChunkOffsets;
|
||||||
uint8_t *bufCur = reinterpret_cast<uint8_t *>(buffer);
|
uint8_t *bufCur = reinterpret_cast<uint8_t *>(buffer);
|
||||||
|
|
||||||
// Read first chunk
|
// Read first chunk
|
||||||
nread = fRawFile->ReadAt(bufCur, fMaxBlobSize, offset);
|
nread = impl->fRawFile->ReadAt(bufCur, maxBlobSize, offset);
|
||||||
R__ASSERT(nread == fMaxBlobSize);
|
R__ASSERT(nread == maxBlobSize);
|
||||||
// NOTE: we read the entire chunk in `bufCur`, but we only advance the pointer by `nbytesFirstChunk`,
|
// NOTE: we read the entire chunk in `bufCur`, but we only advance the pointer by `nbytesFirstChunk`,
|
||||||
// since the last part of `bufCur` will later be overwritten by the next chunk's payload.
|
// since the last part of `bufCur` will later be overwritten by the next chunk's payload.
|
||||||
// We do this to avoid a second ReadAt to read in the chunk offsets.
|
// We do this to avoid a second ReadAt to read in the chunk offsets.
|
||||||
|
@ -1229,11 +1247,11 @@ void PseudoMiniFileReader::ReadBuffer(void *buffer, size_t nbytes, std::uint64_t
|
||||||
ROOT::Experimental::Internal::RNTupleSerializer::DeserializeUInt64(curChunkOffset, chunkOffset);
|
ROOT::Experimental::Internal::RNTupleSerializer::DeserializeUInt64(curChunkOffset, chunkOffset);
|
||||||
++curChunkOffset;
|
++curChunkOffset;
|
||||||
|
|
||||||
const size_t bytesToRead = std::min<size_t>(fMaxBlobSize, remainingBytes);
|
const size_t bytesToRead = std::min<size_t>(maxBlobSize, remainingBytes);
|
||||||
// Ensure we don't read outside of the buffer
|
// Ensure we don't read outside of the buffer
|
||||||
R__ASSERT(static_cast<size_t>(bufCur - reinterpret_cast<uint8_t *>(buffer)) <= nbytes - bytesToRead);
|
R__ASSERT(static_cast<size_t>(bufCur - reinterpret_cast<uint8_t *>(buffer)) <= nbytes - bytesToRead);
|
||||||
|
|
||||||
auto nbytesRead = fRawFile->ReadAt(bufCur, bytesToRead, chunkOffset);
|
auto nbytesRead = impl->fRawFile->ReadAt(bufCur, bytesToRead, chunkOffset);
|
||||||
R__ASSERT(nbytesRead == bytesToRead);
|
R__ASSERT(nbytesRead == bytesToRead);
|
||||||
|
|
||||||
nread += bytesToRead;
|
nread += bytesToRead;
|
63
src/root/RMicroFileReader.hxx
Normal file
63
src/root/RMicroFileReader.hxx
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
struct RNTuple_Anchor {
|
||||||
|
/// Version of the RNTuple binary format that the writer supports (see specification).
|
||||||
|
/// Changing the epoch indicates backward-incompatible changes
|
||||||
|
std::uint16_t fVersionEpoch;
|
||||||
|
/// Changing the major version indicates forward incompatible changes; such changes should correspond to a new
|
||||||
|
/// bit in the feature flag of the RNTuple header.
|
||||||
|
/// For the pre-release epoch 0, indicates the release candidate number
|
||||||
|
std::uint16_t fVersionMajor;
|
||||||
|
/// Changing the minor version indicates new optional fields added to the RNTuple meta-data
|
||||||
|
std::uint16_t fVersionMinor;
|
||||||
|
/// Changing the patch version indicates new backported features from newer binary format versions
|
||||||
|
std::uint16_t fVersionPatch;
|
||||||
|
/// The file offset of the header excluding the TKey part
|
||||||
|
std::uint64_t fSeekHeader;
|
||||||
|
/// The size of the compressed ntuple header
|
||||||
|
std::uint64_t fNBytesHeader;
|
||||||
|
/// The size of the uncompressed ntuple header
|
||||||
|
std::uint64_t fLenHeader;
|
||||||
|
/// The file offset of the footer excluding the TKey part
|
||||||
|
std::uint64_t fSeekFooter;
|
||||||
|
/// The size of the compressed ntuple footer
|
||||||
|
std::uint64_t fNBytesFooter;
|
||||||
|
/// The size of the uncompressed ntuple footer
|
||||||
|
std::uint64_t fLenFooter;
|
||||||
|
/// The maximum size for a TKey payload. Payloads bigger than this size will be written as multiple blobs.
|
||||||
|
std::uint64_t fMaxKeySize;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RNTuple_File_Info {
|
||||||
|
bool failed;
|
||||||
|
RNTuple_Anchor anchor;
|
||||||
|
std::uint64_t anchor_seek;
|
||||||
|
std::uint64_t anchor_nbytes;
|
||||||
|
std::uint64_t anchor_key_seek;
|
||||||
|
std::uint64_t anchor_key_nbytes;
|
||||||
|
std::uint64_t rblob_key_header_nbytes;
|
||||||
|
std::uint64_t tfile_header_nbytes;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RMicroFileReader final {
|
||||||
|
public:
|
||||||
|
explicit RMicroFileReader(const char *fname);
|
||||||
|
~RMicroFileReader();
|
||||||
|
|
||||||
|
RNTuple_File_Info
|
||||||
|
GetNTupleProper(const char *ntupleName);
|
||||||
|
|
||||||
|
void
|
||||||
|
ReadBuffer(void *buffer, std::size_t nbytes, std::uint64_t offset);
|
||||||
|
|
||||||
|
// ROOT::Experimental::RNTuple
|
||||||
|
// CreateAnchor(
|
||||||
|
// std::uint16_t versionEpoch, std::uint16_t versionMajor, std::uint16_t versionMinor, std::uint16_t versionPatch,
|
||||||
|
// std::uint64_t seekHeader, std::uint64_t nbytesHeader, std::uint64_t lenHeader, std::uint64_t seekFooter,
|
||||||
|
// std::uint64_t nbytesFooter, std::uint64_t lenFooter, std::uint64_t maxKeySize);
|
||||||
|
|
||||||
|
struct Impl;
|
||||||
|
Impl *impl;
|
||||||
|
};
|
Loading…
Reference in a new issue