Skip to content

Conversation

silverweed
Copy link
Contributor

@silverweed silverweed commented Sep 23, 2025

This PR adds a first version of the new RFile prototype, implementing basic Open/Append/Recreate/Get/Put methods.

For a sneak peek of the final shape of the prototype, see here

Checklist:

  • tested changes locally
  • updated the docs (if necessary)

Copy link
Member

@hageboeck hageboeck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the work!

Seeing the code sparked a lot of questions. Many of those might be either addressed in later PRs and some might be irrelevant, so feel free to "Resolve" those.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After yesterday's discussion, is it wise to put this in io/v7? Version numbers in file names or configs will just create headaches. How about putting it in io/rfile, where it can remain also in the future?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the end I just put it in io/io to avoid CMake headaches. Since it's always built anyway it doesn't make much of a difference in my opinion.


} // namespace Internal

class RFile final {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

final will prevent users from inheriting and possibly overriding. Is this the intention?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A larger docstring for the class documentation would be desirable, but it

  • can be added later
  • and could be placed in the .cxx, so you don't have to recompile everything when updating the docs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

final will prevent users from inheriting and possibly overriding. Is this the intention?

Considering we're not defining any virtual method (including the destructor) I don't see how the user could effectively inherit this class anyway. If we change our mind later we can just remove the final, but I consider it a good default.

/// The caller should immediately wrap it into a unique_ptr of the type described by `type`.
[[nodiscard]] void *GetUntyped(std::string_view path, const TClass &type) const;

/// Writes `obj` to file, without taking its ownership.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this makes it clearer?

Suggested change
/// Writes `obj` to file, without taking its ownership.
/// Writes a copy of `obj` to file, without taking its ownership.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An explanation of type and flags would be great, too.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I see now that this is private, so the request has low priority.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about the "a copy of" part; the object is not really copied in memory, it's just serialized into the file. At least, that's the mental model that the both us and the user should have, regardless of how TFile actually implements it

return std::unique_ptr<T>(static_cast<T *>(obj));
}

/// Puts an object into the file.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Puts an object into the file.
/// Puts a copy of an object into the file.

@@ -0,0 +1,397 @@
#include "gtest/gtest.h"
#include "gmock/gmock.h"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it using gmock? I might have removed gmock from the automatically linked CMake targets, so you might have to add it if required.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is apparently needed by testing::HasSubstr

EXPECT_FALSE(file->Get<TH1F>("hist"));
EXPECT_TRUE(file->Get<TH1>("hist"));

// We do NOT want to globally register RFiles ever.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Maybe yes if the browser is supposed to show a list of open files. But if we decide that that's what it should do, one should maybe do this in a different list with weak pointers or so ...

auto hist = file->Get<TH1D>("hist");
ASSERT_TRUE(hist);
EXPECT_EQ(static_cast<int>(hist->GetEntries()), 10);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this hold?

Suggested change
EXPECT_EQ(*file->Get<TH1D>("hist;2"), *hist);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the equality operator is defined for TH1..

constexpr const char *kFileName = "http://root.cern/files/RNTuple.root";

auto file = RFile::Open(kFileName);
auto ntuple = file->Get<ROOT::RNTuple>("Contributors");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this gracefully fail with GTEST_SKIP() if one is offline?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know...how can we reliably detect whether we're offline? Do we do this in other tests?

TH1D hist(histName, histTitle, 100, -10 * (i + 1), 10 * (i + 1));
file->Put(histPath, hist);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this test increases coverage. Also, if it was covering a new case, wouldn't you at least have to check that the objects can be read / listed?

Copy link

github-actions bot commented Sep 23, 2025

Test Results

    21 files      21 suites   3d 17h 56m 43s ⏱️
 3 680 tests  3 679 ✅ 0 💤 1 ❌
75 460 runs  75 454 ✅ 5 💤 1 ❌

For more details on these failures, see this check.

Results for commit 6cbc229.

♻️ This comment has been updated with latest results.

@silverweed silverweed force-pushed the rfile_01_1 branch 3 times, most recently from 978733c to 7430133 Compare September 24, 2025 11:41
Copy link
Member

@hahnjo hahnjo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two small comments, but in general I'll leave review to others...

ROOT_ADD_GTEST(RIoUring RIoUring.cxx LIBRARIES RIO)
endif()

ROOT_ADD_GTEST(rfile rfile.cxx LIBRARIES RIO Hist ROOTNTuple)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In principle, ROOTNTuple is a higher level in terms of layering than RIO, not sure if it's a good idea to depend on it (even for a test)...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't that the case also for Hist?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants