Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Advance ripple.app.rdb #3965

Closed
wants to merge 12 commits into from
Closed

Conversation

undertome
Copy link
Contributor

@undertome undertome commented Oct 23, 2021

High Level Overview of Change

This pull request refactors the ripple.app.rdb module (the Relational Database Interface) with the goal of making it easier to use, read, and maintain, and also features updated documentation.

Context of Change

This refactor improves Doxygen comments, documentation, naming, and the organization of the files in the rdb directory by increasing modularity.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactor (non-breaking change that only restructures code)
  • Tests (You added tests for code that already exists, or your new feature included in this PR)
  • Documentation Updates
  • Release

Test Plan

Since there aren't any substantial changes to the logic, only unit tests were conducted.

Future Tasks

This is likely the first of several iterative improvements to this module.

@undertome undertome added Tech Debt Non-urgent improvements Documentation README changes, code comments, etc. labels Oct 23, 2021
@cjcobb23
Copy link
Contributor

@manojsdoshi Let's run CI on this after the review has wrapped up but before merge, because a lot of this Postgres code is not unit tested. Need to make sure we didn't break anything.

Copy link
Collaborator

@ximinez ximinez 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. I left a couple of minor comments, but I won't need to re-review once they're addressed.

src/ripple/app/rdb/backend/detail/impl/Shard.cpp Outdated Show resolved Hide resolved
src/ripple/app/rdb/backend/detail/impl/Shard.cpp Outdated Show resolved Hide resolved
src/ripple/app/rdb/impl/Vacuum.cpp Outdated Show resolved Hide resolved
Copy link
Collaborator

@scottschurr scottschurr left a comment

Choose a reason for hiding this comment

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

Sorry I took so long getting through this code review.

The changes look good. I pointed out a number of things that, in my opinion, could be improved. But I think most of the issues I've pointed out were already in the various files.

I'm open to discussing any of the suggestions I made.

In total this looks like a substantial improvement on the current situation. Thanks.

@@ -927,8 +927,7 @@ saveValidatedLedger(
return true;
}

auto res = dynamic_cast<RelationalDBInterfaceSqlite*>(
&app.getRelationalDBInterface())
auto res = dynamic_cast<SQLiteDatabase*>(&app.getRelationalDatabase())
Copy link
Collaborator

Choose a reason for hiding this comment

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

You have a couple of choices here. A failed dynamic_cast returns a nullptr. But you're not checking for a nullptr, and indirecting through a nullptr will immediately crash the server.

A dynamic_cast is expensive. So if you're not going to take advantage of the returned nullptr it makes more sense to use a static_cast, which is cheaper and will also work in the successful case. A failed static_cast will certainly blow up as spectacularly in the failing case, but not in as predictable a fashion.

Personally, I'd be inclined to stick with the dynamic_cast, but check the return value for nullptr before proceeding. However if there's some way that you can guarantee to me that an SQLiteDatabase is the only possible return value forever and for always, then the static_cast could make sense. But in that case you should leave a comment about why the static_cast is always safe.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment on lines 1165 to 1167
auto nodestoreHashes =
dynamic_cast<PostgresDatabase*>(&app.getRelationalDatabase())
->getTxHashes(ledger.info().seq);
Copy link
Collaborator

Choose a reason for hiding this comment

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

See earlier comment about checking the return value of a dynamic_cast for nullptr.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@@ -1021,8 +1021,7 @@ class ApplicationImp : public Application, public BasicApp
ledgerCleaner_->stop();
if (reportingETL_)
reportingETL_->stop();
if (auto pg = dynamic_cast<RelationalDBInterfacePostgres*>(
&*mRelationalDBInterface))
if (auto pg = dynamic_cast<PostgresDatabase*>(&*mRelationalDatabase))
Copy link
Collaborator

Choose a reason for hiding this comment

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

FWIW, here's an example of properly checking the return value of a dynamic_cast.

@@ -72,12 +72,22 @@ inline constexpr std::array<char const*, 5> LgrDBInit{
// Transaction database holds transactions and public keys
inline constexpr auto TxDBName{"transaction.db"};

inline constexpr std::array TxDBPragma
// Omitting the explicit template parameters
// seemed to caused undefined behaviour
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd change this comment to "In C++17 omitting the explicit template parameters caused a crash."

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@@ -117,12 +127,22 @@ inline constexpr std::array<char const*, 8> TxDBInit{
// The Ledger Meta database maps ledger hashes to shard indexes
inline constexpr auto LgrMetaDBName{"ledger_meta.db"};

inline constexpr std::array LgrMetaDBPragma
// Omitting the explicit template parameters
// seemed to caused undefined behaviour
Copy link
Collaborator

Choose a reason for hiding this comment

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

See the above comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@@ -305,16 +305,16 @@ doAccountTxHelp(RPC::Context& context, AccountTxArgs const& args)
{
if (args.forward)
{
auto [tx, marker] = dynamic_cast<RelationalDBInterfaceSqlite*>(
&context.app.getRelationalDBInterface())
auto [tx, marker] = dynamic_cast<SQLiteDatabase*>(
Copy link
Collaborator

Choose a reason for hiding this comment

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

See earlier comment about checking the return value of a dynamic_cast for nullptr.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

->oldestAccountTxPage(options);
result.transactions = tx;
result.marker = marker;
}
else
{
auto [tx, marker] = dynamic_cast<RelationalDBInterfaceSqlite*>(
&context.app.getRelationalDBInterface())
auto [tx, marker] = dynamic_cast<SQLiteDatabase*>(
Copy link
Collaborator

Choose a reason for hiding this comment

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

See earlier comment about checking the return value of a dynamic_cast for nullptr.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@@ -75,22 +75,19 @@ getCountsJson(Application& app, int minObjectCount)

if (!app.config().reporting() && app.config().useTxTables())
{
auto dbKB = dynamic_cast<RelationalDBInterfaceSqlite*>(
&app.getRelationalDBInterface())
auto dbKB = dynamic_cast<SQLiteDatabase*>(&app.getRelationalDatabase())
Copy link
Collaborator

Choose a reason for hiding this comment

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

See earlier comment about checking the return value of a dynamic_cast for nullptr.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

->getKBUsedAll();

if (dbKB > 0)
ret[jss::dbKBTotal] = dbKB;

dbKB = dynamic_cast<RelationalDBInterfaceSqlite*>(
&app.getRelationalDBInterface())
dbKB = dynamic_cast<SQLiteDatabase*>(&app.getRelationalDatabase())
Copy link
Collaborator

Choose a reason for hiding this comment

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

See earlier comment about checking the return value of a dynamic_cast for nullptr.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

Copy link
Collaborator

Choose a reason for hiding this comment

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

Nice job getting rid of the dynamic_cast altogether!

->getKBUsedLedger();

if (dbKB > 0)
ret[jss::dbKBLedger] = dbKB;

dbKB = dynamic_cast<RelationalDBInterfaceSqlite*>(
&app.getRelationalDBInterface())
dbKB = dynamic_cast<SQLiteDatabase*>(&app.getRelationalDatabase())
Copy link
Collaborator

Choose a reason for hiding this comment

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

See earlier comment about checking the return value of a dynamic_cast for nullptr.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

Copy link
Collaborator

@scottschurr scottschurr left a comment

Choose a reason for hiding this comment

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

👍 Changes look good to me. You should consider removing the unused method either in this pull request or a future pull request. But that change is not worth holding up this pull request.

@undertome
Copy link
Contributor Author

Rebased to HEAD of develop

Comment on lines 930 to 935
auto const res = dynamic_cast<SQLiteDatabase*>(&app.getRelationalDatabase())
->saveValidatedLedger(ledger, current);

if (!res)
Throw<std::runtime_error>("Failed to get relational database");
Copy link
Collaborator

Choose a reason for hiding this comment

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

This doesn't look right. You're checking the result of saveValidatedLedger, which would not justify a throw with this message. I think what you're going for is:

    auto const db = dynamic_cast<SQLiteDatabase*>(&app.getRelationalDatabase());
    if (!db)
        Throw<std::runtime_error>("Failed to get relational database");

    auto const res = db->saveValidatedLedger(ledger, current);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch. Done

Copy link
Collaborator

@ximinez ximinez left a comment

Choose a reason for hiding this comment

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

Nicely done!

nbougalis and others added 11 commits May 2, 2022 22:16
This commit addresses minor bugs introduced with commit
6faaa91:

- The number of threads used by the database engine was
  incorrectly clamped to the lower possible value, such
  that the database was effectively operating in single
  threaded mode.

- The number of requests to extract at once was so high
  that it could result in increased latency. The bundle
  size is now limited to 4 and can be adjusted by a new
  configuration option `rq_bundle` in the `[node_db]`
  stanza. This is an advanced tunable and adjusting it
  should not be needed.
Several hard-coded parameters control the behavior of the ledger
acquisition engine. The values of many of these parameters where
set by intuition and have complex and non-intuitive interactions
with each other and other parts of the code.

An earlier commit attempted to adjust several of these parameters
to improve syncing performance; initial testing was promising but
a number of operators reported experiencing syncing and stability
issues with their servers. As a result, this commit reverts parts
of commit 1823506.

This commit further adjusts some tunables so as to increase the
aggressiveness of the ledger acquisition engine.
* "A path is considered invalid if and only if it enters and exits an
  address node through trust lines where No Ripple has been enabled for
  that address." (https://xrpl.org/rippling.html#specifics)
* When loading trust lines for an account "Alice" which was reached
  via a trust line that has the No Ripple flag set on Alice's side, do
  not use or cache any of Alice's trust lines which have the No Ripple
  flag set on Alice's side. For typical "end-user" accounts, this will
  return no trust lines.
* Also remove an unused variable that's giving VS a problem
@undertome undertome force-pushed the relational-database branch 2 times, most recently from ba27cde to 5dd35e5 Compare May 4, 2022 20:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Documentation README changes, code comments, etc. Tech Debt Non-urgent improvements
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants