Skip to content

Conversation

@PeterChen13579
Copy link
Collaborator

Support AWS Keyspace queries

@codecov
Copy link

codecov bot commented Aug 19, 2025

Codecov Report

❌ Patch coverage is 1.23457% with 80 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.55%. Comparing base (2b937bf) to head (6bf8b14).
⚠️ Report is 1 commits behind head on develop.

Files with missing lines Patch % Lines
src/data/KeyspaceBackend.hpp 0.00% 80 Missing ⚠️

❌ Your patch status has failed because the patch coverage (1.23%) is below the target coverage (20.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #2454      +/-   ##
===========================================
- Coverage    79.95%   79.55%   -0.41%     
===========================================
  Files          384      385       +1     
  Lines        16037    16118      +81     
  Branches      8387     8438      +51     
===========================================
- Hits         12823    12822       -1     
- Misses        1925     2006      +81     
- Partials      1289     1290       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Collaborator

@kuznetsss kuznetsss left a comment

Choose a reason for hiding this comment

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

LGTM, but let's wait for an approval from @godexsoft

Copy link
Collaborator

@godexsoft godexsoft left a comment

Choose a reason for hiding this comment

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

I have not thoroughly reviewed the code because i don't yet understand why we need so many changes if keyspaces is supposed to be compatible with cassandra?
In general i'm not a fan of adding custom stuff to the cassandra backend.. if we need to have custom behaviour maybe we should create a separate backend and inherit where we can, modify where we need.

@PeterChen13579
Copy link
Collaborator Author

PeterChen13579 commented Aug 27, 2025

@godexsoft For some context, Keyspace is compatible with Cassandra but there's a few limitations. Specifically the places where we had:

IF ... IN clause 
PER PARTITION LIMIT 1 
Tuple comparisons, e.g.  (taxon, token_id) > ? 

To tackle this, I split the queries that contains the above into 2 queries. ie, 2 queries will be equivalent to the 1 from before.

The goal of this PR is to get Clio to run with Keyspace while those running cassandra/scylladb would work the exact same.
Also, keyspace is trying to support the above statements that they don't support right now. Hopefully once they get it supported, I'm happy to revert this PR.

Copy link
Collaborator

@mathbunnyru mathbunnyru left a comment

Choose a reason for hiding this comment

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

Left some comments to mostly make the code more readable and less error-prone

Copy link
Collaborator

@godexsoft godexsoft left a comment

Choose a reason for hiding this comment

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

I left a few comments, nothing major, should be easy enough to fix.
For the Schema inheritance idea let's discuss. I think we can still do slightly better than having two copies of the schema with modifications

godexsoft
godexsoft previously approved these changes Oct 3, 2025
Copy link
Collaborator

@godexsoft godexsoft left a comment

Choose a reason for hiding this comment

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

Looks good 👍

@PeterChen13579 PeterChen13579 enabled auto-merge (squash) October 3, 2025 15:28
@PeterChen13579 PeterChen13579 merged commit 1cfa06c into XRPLF:develop Oct 3, 2025
13 checks passed
backend = std::make_shared<data::cassandra::CassandraBackend>(
data::cassandra::SettingsProvider{cfg}, cache, readOnly
);
if (cfg.getValueView("provider").asString() == toString(cassandra::impl::Provider::Keyspace)) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

It's better to do it vice-versa, have a function to convert string to a enum, and then compare enum values

Comment on lines +60 to +62
* @tparam SettingsProviderType The settings provider type to use
* @tparam ExecutionStrategyType The execution strategy type to use
* @tparam FetchLedgerCacheType The ledger header cache type to use
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's remove to use in the end, it's not helpful

// !range_.has_value() means the table 'ledger_range' is not populated;
// This would be the first write to the table.
// In this case, insert both min_sequence/max_sequence range into the table.
if (not(range_.has_value())) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Well, using not this way ( not(x) instead of not x ) is something new, let's not do it 😆

Comment on lines +105 to +109
executor_.writeSync(schema_->insertLedgerRange, false, ledgerSequence_);
executor_.writeSync(schema_->insertLedgerRange, true, ledgerSequence_);
}

if (not this->executeSyncUpdate(schema_->updateLedgerRange.bind(ledgerSequence_, true, ledgerSequence_ - 1))) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would probably add inline comments to a boolean variable like executor_.writeSync(schema_->insertLedgerRange, /* some_opt_name = */ false, ledgerSequence_);

// Keyspace and ScyllaDB uses the same logic for taxon-filtered queries
nftIDs = fetchNFTIDsByTaxon(issuer, *taxon, limit, cursorIn, yield);
} else {
// --- Amazon Keyspaces Workflow for non-taxon queries ---
Copy link
Collaborator

Choose a reason for hiding this comment

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

No need for --- in the comment, I don't think we do that

Comment on lines +114 to +118
if (auto const res = handle_.connect(); not res)
throw std::runtime_error("Could not connect to database: " + res.error());

if (not readOnly) {
if (auto const res = handle_.execute(schema_.createKeyspace); not res) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

same as above

throw std::runtime_error("Could not create keyspace: " + res.error());
}

if (auto const res = handle_.executeEach(schema_.createSchema); not res)
Copy link
Collaborator

Choose a reason for hiding this comment

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

same as above

Comment on lines +248 to +251
if (auto const res = executor_.read(yield, schema_->selectLatestLedger); res) {
if (auto const& result = res.value(); result) {
if (auto const maybeValue = result.template get<uint32_t>(); maybeValue)
return maybeValue;
Copy link
Collaborator

Choose a reason for hiding this comment

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

same as above

{"database.cassandra.port", ConfigValue{ConfigType::Integer}.optional()},
{"database.cassandra.keyspace",
ConfigValue{ConfigType::String}.defaultValue(TestGlobals::instance().backendKeyspace)},
{"database.cassandra.provider", ConfigValue{ConfigType::String}.defaultValue("cassandra")},
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's move it to a variable (and in places below as well)

enum class Provider { Cassandra, Keyspace };

inline std::string
toString(Provider provider)
Copy link
Collaborator

Choose a reason for hiding this comment

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

You will have a function providerFromString instead, and this function could be removed

@mathbunnyru
Copy link
Collaborator

Left some comments, mostly about style

When you use optional/expected, I suggest using this pattern (has_value() + *):

if (my_opt.has_value()) {
  use_it(*my_opt);
}

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants