Skip to content

[ntuple] Add RPageSinkS3 for the basic S3 write path (Mode B)#22653

Open
JasMehta08 wants to merge 1 commit into
root-project:masterfrom
JasMehta08:ntuple-s3-sink
Open

[ntuple] Add RPageSinkS3 for the basic S3 write path (Mode B)#22653
JasMehta08 wants to merge 1 commit into
root-project:masterfrom
JasMehta08:ntuple-s3-sink

Conversation

@JasMehta08

Copy link
Copy Markdown
Contributor

This Pull request:

(Is a part of the GSoC 2026 project S3 Backend for RNTuple.)

Adds RPageSinkS3, the write path of the experimental S3 storage backend for RNTuple.

Changes or fixes:

  • RPageSinkS3 (Mode B full write path): InitImpl (header), CommitPageImpl/CommitSealedPageImpl (one S3 object per sealed page, kTypeObject64 locator), StageClusterImpl, CommitClusterGroupImpl (page list), and CommitDatasetImpl (footer, then the JSON anchor written last for atomicity).

Checklist:

  • tested changes locally

@jblomer jblomer left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Very nice! Some discussion points.

Comment thread tree/ntuple/CMakeLists.txt Outdated
Comment thread tree/ntuple/inc/ROOT/RPageStorageS3.hxx Outdated
Comment thread tree/ntuple/inc/ROOT/RPageStorageS3.hxx Outdated
Comment thread tree/ntuple/src/RPageStorage.cxx Outdated
Comment on lines +196 to +197
if (location.find("s3://") == 0 || location.find("s3+http://") == 0 || location.find("s3+https://") == 0)
throw RException(R__FAIL("S3 read support is not yet implemented."));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I realize that we have a problem here: we cannot distinguish between an RNTuple natively stored on S3 and a ROOT file on S3. I think we have to come up with a special scheme for the first case. E.g. ntpl+s3:// (or something else if you have a better suggestion). The advantage is that we then only need to check for one scheme.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I used ntpl+s3:// as it is simple and makes sense

Comment thread tree/ntuple/src/RPageStorageS3.cxx Outdated
Comment thread tree/ntuple/src/RPageStorageS3.cxx Outdated
Comment on lines +196 to +198
// one PUT per object on a fresh connection.
ROOT::Internal::RCurlConnection conn(url);
conn.SetCredentialsFromEnvironment();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we should already now reuse the connection, i.e. make the connection a class member

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Since the URL changes per object but RCurlConnection fixes its URL at construction. I think it would be better to overload SendPutReq so that it first sets the URL and then sends the PUT request. Or should I implement it in some other way?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I have made the changes for now, let me know if I should have it as a separate commit or do something else

fAnchor.fLenHeader = length;
}

ROOT::RNTupleLocator ROOT::Experimental::Internal::RPageSinkS3::CommitPageImpl(ColumnHandle_t columnHandle,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think this is exactly the same code for file, DAOS, and S3. I suggest to make a first, preparatory commit that moves this logic to RPagePersistentSink::CommitPage() (the only place where it is used) and to remove CommitPageImpl() altogether.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Should I create a separate PR or just a commit in this PR before the S3 sink commit

Comment thread tree/ntuple/inc/ROOT/RPageStorageS3.hxx Outdated
std::string fBaseUrl;
/// Object ID counter; incremented for each object written. Atomic to match the DAOS pattern and
/// prepare for a future parallel CommitSealedPageVImpl.
std::atomic<std::uint64_t> fObjectId{0};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actually, I don't think we would parallelize (as in: run in multiple threads) the creation of object IDs. Let's keep this a standard integer for the time being.

// Upload the anchor LAST: once it exists at the base URL, a reader can assume the whole ntuple
// is complete. Never upload it before all other objects are in place.
const auto anchorJson = fAnchor.ToJSON();
PutObject(fBaseUrl, reinterpret_cast<const unsigned char *>(anchorJson.data()), anchorJson.size());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One thing I forgot (not for this PR): we should checksum the anchor. E.g., using some canonical json normalization. Let's discuss this in the next meeting.

}

std::unique_ptr<ROOT::Internal::RPageSink>
ROOT::Experimental::Internal::RPageSinkS3::CloneAsHidden(std::string_view /*name*/,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That should be relatively simple to add. E.g., name could be added to the baseurl as $baseurl/name and then we return a new S3 page sink with this extended base url. @silverweed what do you think?

@JasMehta08 JasMehta08 Jun 24, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

would it be better to do $baseurl/_clone/name to make sure it does not end up colliding.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You mean $baseurl/name could potentially collide if name is the same as another object's id? Then yes, I think the _clone/ solution is a good idea 👍

@github-actions

Copy link
Copy Markdown

Test Results

    19 files      19 suites   2d 23h 36m 2s ⏱️
 3 847 tests  3 847 ✅ 0 💤 0 ❌
66 578 runs  66 578 ✅ 0 💤 0 ❌

Results for commit 55e94d8.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants