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

Improve adjust_balance performance #1083 #1099

Closed
wants to merge 10 commits into from
Closed

Conversation

abitmore
Copy link
Member

@abitmore abitmore commented Jun 26, 2018

PR for #1083.

In this PR we added a new compile-time option: ASSET_BALANCE_SORTING, enabled by default.

  • when the option is enabled, witness_node will effectively keep the old behavior, which means nothing will change;
  • when the option is disabled,
    • witness_node will have better performance:
    • A side effect is that asset_api::get_asset_holders(...) and asset_api::get_all_asset_holders() will return unordered results.

To disable the new compile-time option (before compiling):

cmake -DCMAKE_BUILD_TYPE=Release -DASSET_BALANCE_SORTING=OFF ..

Note: asset_api::get_asset_holders(...)
  and asset_api::get_all_asset_holders()
  will return unordered results after this change.
@abitmore
Copy link
Member Author

abitmore commented Jun 27, 2018

I'm thinking about adding a compile-time option, e.g. name it ENABLE_ASSET_BALANCE_SORTING, disabled by default for better performance. API nodes that want to enable asset::api can be compiled with that option enabled. Or enable it by default?

Looks like this approach can please both parties. Also not too hard to code (although the code would be uglier).

Thoughts?

@oxarbitrage
Copy link
Member

oxarbitrage commented Jun 27, 2018 via email

@oxarbitrage oxarbitrage mentioned this pull request Jun 27, 2018
17 tasks
@abitmore
Copy link
Member Author

Added new compile-option ASSET_BALANCE_SORTING.

OP updated accordingly.

@abitmore
Copy link
Member Author

Changed the new option to ON by default to keep old behavior, which would be more convenient for Docker users, API nodes and ignorant node operators. It's easier to contact witnesses and seed node operators and suggest them to disable it. OP updated.

// From next maintenance interval, need to stop updating this account's active/owner.
// Here we check if each asset is added earlier in this maintenance interval,
// if yes, remove it from "added"; otherwise, add it to "removed".
d.modify( special_meta, [&assets_before](special_assets_meta_object& p) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Here we are modifying a persisted data object. Could this cause problems if you run witness_node with ASSET_BALANCE_SORTED and later without (or vice-versa, or yes-no-yes, or no-yes-no)? I have not tested these situations, just typing out loud.

If it does cause problems, it seems the use of this feature will be rare. So are the symptoms easily detectable? If so, we could [log a message | force a replay]. We should also document the consequences.

Copy link
Member Author

@abitmore abitmore Jul 16, 2018

Choose a reason for hiding this comment

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

Good questions.

  1. when to replay

Currently only DB_VERSION is used to detect whether need a replay.

Ideally the node should automatically detect a) whether db schema changed E.G. caused by code changes or compile-time option changes and b) whether certain options in config.ini changed. But probably need too much work to make it perfect.

For this issue, a quick solution is to define DB_VERSION to different values when using different compile-time options.

  1. automatically replay or not

The main concern is that replay takes long time. In case when a node operator accidentally ran a node with an incompatible data directory, being forced to replay is painful. So it makes some sense if the node refuses to start and shows an error message when incompatible db schema is detected.

IMHO these questions worth a new issue, or perhaps two issues.

@pmconrad @oxarbitrage your opinion?

Copy link
Member Author

Choose a reason for hiding this comment

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

For this issue, a quick solution is to define DB_VERSION to different values when using different compile-time options.

Done.

Copy link
Contributor

Choose a reason for hiding this comment

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

IMO the quick solution is good enough.

@oxarbitrage
Copy link
Member

please note that each time the flag is changed you need to run cmake again with the flag on or off. then at make the entire project will be compiled thus making the process of testing/developing painful.

mentioning this as i think it is not a solution to abuse.

@abitmore
Copy link
Member Author

Usually I use two build directories or more to test different values. Don't know if there is a better way.

Copy link
Contributor

@jmjatlanta jmjatlanta left a comment

Choose a reason for hiding this comment

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

Small fix to CMakeLists.txt

@@ -69,6 +69,13 @@ IF(NOT "${Boost_VERSION}" MATCHES "1.53(.*)")
SET(Boost_LIBRARIES ${BOOST_LIBRARIES_TEMP} ${Boost_LIBRARIES})
ENDIF()

OPTION( ASSET_BALANCE_SORTING "Keep account_balance objects sorted by asset and amount, to be used in asset_api (ON OR OFF)" ON )
Copy link
Contributor

Choose a reason for hiding this comment

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

All code other than CMAKE uses ASSET_BALANCE_SORTED, but CMAKE is looking for ASSET_BALANCE_SORTING. The easier fix is to change it in CMakeLists.txt.

My opinion: ASSET_BALANCE_SORTING is not as descriptive as ASSET_BALANCE_SORTED. ASSET_BALANCE_SORTING makes me think it is not an ON/OFF option, but perhaps an algorithm choice.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ahhh, Now I see why that was done. CMake doesn't like it when their variables are the same name as compile variables. I think there is a workaround for more recent versions of cmake, but I haven't explored it. I'm cancelling my request for changes.

Copy link
Member Author

Choose a reason for hiding this comment

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

Or change the CMAKE option to something else, e.g. SORT_ASSET_BALANCE (verb+object)? To be honest I'm not good at naming things. Actually, when the option is ON, we sort balances by asset + quantity; when it's OFF, we sort balances by asset only.

Copy link
Contributor

Choose a reason for hiding this comment

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

And I do not like haggling about variable names. Had we needed to chose one or the other, I was stating my opinion. But now we don't need to choose. I think your name is clear enough, especially with the option comment next to it.

@jmjatlanta jmjatlanta dismissed their stale review July 25, 2018 13:57

Wrong assumption

jmjatlanta
jmjatlanta previously approved these changes Jul 25, 2018
Copy link
Contributor

@jmjatlanta jmjatlanta left a comment

Choose a reason for hiding this comment

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

All looks good. I tested this along with the test created by @oxarbitrage in PR #1169 on Ubuntu 18.04, with ASSET_BALANCE_SORTING ON and OFF.

I am marking this approved, but perhaps merging PR 1169 into this branch before merging this into develop would be a good thing.

What should be the procedure in this case? Should I (a) "Request Changes" until 1169 is merged in here? Or (b) mark this "Approved" and keep 1169 independent?

Update: Merge happened while I was writing review. Thanks!

Copy link
Contributor

@pmconrad pmconrad left a comment

Choose a reason for hiding this comment

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

I think it might be a good idea (and simplify the code) if you switch the special authority logic to the separate account_special_balance index unconditionally, and have the ASSET_BALANCE_SORTED flag only affect the sorting of asset balances.

The great advantage I see there is that the chain logic does not depend on a compile-time flag.

b.balance = delta.amount.value;
if( b.asset_type == asset_id_type() ) // CORE asset
b.balance = delta.amount;
if( maint_flag )
b.maintenance_flag = true;
Copy link
Contributor

Choose a reason for hiding this comment

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

Use unconditional set: b.maintenance_flag = maint_flag;

flat_set<asset_id_type> account_object::get_top_n_control_assets() const
{
flat_set<asset_id_type> result;
if( owner_special_authority.which() == special_authority::tag< top_holders_special_authority >::value )
Copy link
Contributor

Choose a reason for hiding this comment

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

visitor pattern might look better here

p.special_assets_added_this_interval.insert( a );
}
});
#endif
}

return void_result();
Copy link
Contributor

Choose a reason for hiding this comment

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

IMO the handling of special_assets_meta_object is broken in several respects:

  • account_create_evaluator::do_apply can create special authorities, similar code needs to be added there as well
  • you don't handle the case if an account switches from one asset to another (i. e. both sa_before and sa_after are true)
  • you cannot remove an asset just because an account doesn't use it anymore - it could still be used by a different account

Please add unit tests for all of these.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks. My bad. Apparently the code is incomplete. I don't know why I didn't realize it. Perhaps I was thinking that it's updating an asset but not an account.

@abitmore
Copy link
Member Author

Still need much work to get this PR done, and it's possible that we won't merge it at all. I've removed it from this release, and will rebase other PR's which were based on it to be based on develop branch, hope that they can get merged for the coming release.

I think it might be a good idea (and simplify the code) if you switch the special authority logic to the separate account_special_balance index unconditionally, and have the ASSET_BALANCE_SORTED flag only affect the sorting of asset balances.

The great advantage I see there is that the chain logic does not depend on a compile-time flag.

If we switch the special authority logic to the separate account_special_balance index unconditionally, it will impact performance of nodes which have enabled the compile-time option, due to additional data copy and modification.

Actually, as mentioned in the in-code comments, if there are too many accounts with special authorities, or the configured assets have too many holders (E.G. BTS), the approach done in this PR (massive data copy on maintenance interval) can greatly impact performance, which can be considered as an attack factor.

I guess I'll abandon the whole idea and close this PR. Some code may still be usable, so I will cherry-pick them to a new branch and submit a new PR.

Hope that we can find a better solution.

@oxarbitrage oxarbitrage mentioned this pull request Jul 29, 2018
@abitmore abitmore closed this Aug 8, 2018
@abitmore abitmore deleted the 1083-adjust-balance branch August 8, 2018 16:23
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