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

don't return zero lamport accounts from 'load' with feature #27793

Merged
merged 3 commits into from
Sep 15, 2022

Conversation

jeffwashington
Copy link
Contributor

@jeffwashington jeffwashington commented Sep 15, 2022

Problem

Seems like a better api to not return zero lamport accounts as Some(zero_lamport_account).

Summary of Changes

AccountsDb::load() returns None if account has zero lamports.

#27800

Fixes #

@jeffwashington jeffwashington changed the title Sep0 6 61 don't return zero lamport accounts from 'load' with feature Sep 15, 2022
@@ -4586,8 +4597,15 @@ impl AccountsDb {
&self,
ancestors: &Ancestors,
pubkey: &Pubkey,
ignore_zero_lamports: LoadZeroLamports,
Copy link
Member

Choose a reason for hiding this comment

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

nit: load_zero_lamports.

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 4602 to 4608
self.load(ancestors, pubkey, LoadHint::FixedMaxRoot)
.filter(|(account, _)| {
matches!(
ignore_zero_lamports,
LoadZeroLamports::SomeWithZeroLamportAccount
) || !account.is_zero_lamport()
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Why filter here and not deeper in call-stack in AccountsDb::load or in AccountsDb::do_load, or AccountsDb::do_load_with_populate_read_cache?

AccountsDb::load at least is a public function and this is potentially is adding a backdoor to bypass this filtering.

Also even though this function is returning None, seems like they are still wastefully stored in cache.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also even though this function is returning None, seems like they are still wastefully stored in cache.

If someone wrote a zero lamport account, it is stored in the write cache. Then it is flushed to an append vec.

Later, if someone uses the index to load the account, load goes to the append vec and reads the account data. Whether it is zero lamport or not, this hits the disk. Currently, anything we load is put in the read cache, under the observation that it will likely be read again. Getting the answer that the account DOES exist in accounts db, but is zero lamport could be a useful answer. Possibly getting it more quickly by having the zero lamport account stored in the read cache is also potentially useful for performance.

Whatever the case, it seems to me that choosing to not put zero lamport accounts in the read cache is a tuning/optimization concern. It is likely of minimal impact and is correct either way.

Incidentally, I think the accounts index also stores a bit that indicates that an entry is zero lamport. We could use that on load, but we are not today. I'll make a note of that. Again, likely minimal impact.

Copy link
Contributor

Choose a reason for hiding this comment

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

The main issue here is

Why filter here and not deeper in call-stack in AccountsDb::load or in AccountsDb::do_load, or AccountsDb::do_load_with_populate_read_cache?
AccountsDb::load at least is a public function and this is potentially is adding a backdoor to bypass this filtering.

But also I believe what is stored in the cache should be consistent with what api returns. That inconsistently can potentially manifest somewhere else as a bug. So it is not a purely performance issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is potentially is adding a backdoor to bypass this filtering.

This parameterization is required until the feature activates, which is a required parameter by the bank. So, I think the backdoor has to exist.

Copy link
Contributor

Choose a reason for hiding this comment

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

The parametrization is not the issue.
The issue are the other api which by pass the filtering.
In particular AccountsDb::load which is public.

and I don't see why AccountsDb::do_load, or AccountsDb::do_load_with_populate_read_cache should not do the filtering. Either of these can be used to bypass the filtering.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But also I believe what is stored in the cache should be consistent with what api returns. That inconsistently can potentially manifest somewhere else as a bug. So it is not a purely performance issue.

Another perspective is what is stored in the cache matches what is stored in the underlying thing being cached. In this case, the cache matches the appendvec it is caching. As a result, I have higher confidence we'll get the right answer, whether the item is in the read cache, the write cache, or the append vec - all contain the zero lamport account today. However, as usual, you are very insightful. I had noted in my personal notes the same question - of why we would read cache zero lamport accounts. It is a grey area with some tradeoffs, but I landed on the side of keeping the cache consistent with what it is caching.

I am attempting to keep this change as localized, well understood, and simple as possible.

Copy link
Contributor

Choose a reason for hiding this comment

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

Please stop focusing on the cache issue.
As I mentioned the issue here is that you are adding the filtering at a wrong place in the call stack.
do_load_with_populate_read_cache is invoked from load_account_into_read_cache which is public function.
So that is another possible route which will bypass the filtering.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The main issue here is

Why filter here and not deeper in call-stack in AccountsDb::load or in AccountsDb::do_load, or AccountsDb::do_load_with_populate_read_cache?

I was getting to replying to this main issue ;-), I was just responding to your other items first.

First, I am attempting to keep this change as localized, well understood, and simple as possible in order to limit unknown unknowns.
Each time we go deeper in the callstack for load, we likely have more fanout client calls to consider whether they would tolerate Some/None in all cases in a well understood way. I have not gone deeper yet in my investigation. I'm not philosophically opposed. I practically drew a line at load_with_fixed_root. I can accept that further investigation and pushing the api change deeper could have value in consistency. I can investigate that. If it does not require a feature change, I'd practically prefer to move this pr along as it is to minimize the unknowns.

Comment on lines +152 to +153
/// return None if loaded account has zero lamports
None,
Copy link
Contributor

Choose a reason for hiding this comment

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

None is in rust prelude. Redefining it to mean something else can be confusing.

This whole enum LoadZeroLamports imo is unnecessary and more confusing than just passing around:

return_none_for_zero_lamport_accounts: bool,

across the callstack.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

None is in rust prelude.

I acknowledge your concern about None. But it will always be prefixed like LoadZeroLamports::None. Feel free to suggest an alternative.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This whole enum LoadZeroLamports imo is unnecessary

Passing an additional true/false I consider to be potentially confusing in this case. The intention here is to make this explicit until the feature activation occurs. Then, this enum and the parameters will all disappear.

Copy link
Member

@jstarry jstarry 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, nit picks can be hashed out later IMO

Copy link
Member

@sakridge sakridge left a comment

Choose a reason for hiding this comment

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

lgtm

@jeffwashington jeffwashington merged commit 138d5ed into solana-labs:master Sep 15, 2022
mergify bot pushed a commit that referenced this pull request Sep 15, 2022
* don't return zero lamport accounts from 'load'

* add feature

* rename

(cherry picked from commit 138d5ed)

# Conflicts:
#	runtime/src/accounts.rs
#	sdk/src/feature_set.rs
jeffwashington added a commit to jeffwashington/solana that referenced this pull request Sep 15, 2022
…labs#27793)

    * don't return zero lamport accounts from 'load'

    * add feature

    * rename

    (cherry picked from commit 138d5ed)

manually merged
jeffwashington added a commit that referenced this pull request Sep 15, 2022
…27793) (#27803)

* don't return zero lamport accounts from 'load' with feature (#27793)

* don't return zero lamport accounts from 'load'

* add feature

* rename

(cherry picked from commit 138d5ed)

# Conflicts:
#	runtime/src/accounts.rs
#	sdk/src/feature_set.rs

* fix merge errors

Co-authored-by: Jeff Washington (jwash) <jeff.washington@solana.com>
mergify bot added a commit that referenced this pull request Sep 15, 2022
…27793) (#27803)

* don't return zero lamport accounts from 'load' with feature (#27793)

* don't return zero lamport accounts from 'load'

* add feature

* rename

(cherry picked from commit 138d5ed)

# Conflicts:
#	runtime/src/accounts.rs
#	sdk/src/feature_set.rs

* fix merge errors

Co-authored-by: Jeff Washington (jwash) <jeff.washington@solana.com>
(cherry picked from commit 0dda25f)

# Conflicts:
#	runtime/src/accounts.rs
#	runtime/src/accounts_db.rs
#	sdk/src/feature_set.rs
jeffwashington added a commit that referenced this pull request Sep 15, 2022
…#27793) (#27811)

don't return zero lamport accounts from 'load' with feature (#27793)

    * don't return zero lamport accounts from 'load'

    * add feature

    * rename

    (cherry picked from commit 138d5ed)

manually merged
jeffwashington added a commit that referenced this pull request Sep 15, 2022
…27793) (backport #27803) (#27818)

* don't return zero lamport accounts from 'load' with feature (backport #27793) (#27803)

* don't return zero lamport accounts from 'load' with feature (#27793)

* don't return zero lamport accounts from 'load'

* add feature

* rename

(cherry picked from commit 138d5ed)

# Conflicts:
#	runtime/src/accounts.rs
#	sdk/src/feature_set.rs

* fix merge errors

Co-authored-by: Jeff Washington (jwash) <jeff.washington@solana.com>
(cherry picked from commit 0dda25f)

# Conflicts:
#	runtime/src/accounts.rs
#	runtime/src/accounts_db.rs
#	sdk/src/feature_set.rs

* fix merge errors

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Co-authored-by: jeff washington <jeff.washington@solana.com>
behzadnouri added a commit to behzadnouri/solana that referenced this pull request Sep 20, 2022
behzadnouri added a commit to behzadnouri/solana that referenced this pull request Sep 20, 2022
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.

None yet

5 participants