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

wip: limit use of self ref struct in accounts index #34918

Closed
wants to merge 12 commits into from

Conversation

jeffwashington
Copy link
Contributor

@jeffwashington jeffwashington commented Jan 23, 2024

Problem

self-ref in accounts index is non-ideal.

Confirmed this gets rid of all but the rare, contentious creation of the self referencing struct.

Note the need to be removed.

Summary of Changes

Fixes #
#34786

}
};

let slot_list = lock.slot_list();
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice catch! We should avoid the clone as much as possible!

@Lichtso
Copy link
Contributor

Lichtso commented Jan 24, 2024

Can confirm that this PR eliminates all allocations through ouroboros in my small test ledger.

@HaoranYi
Copy link
Contributor

HaoranYi commented Jan 24, 2024

There are two other places that will cause the self-ref Arc to be cloned.

  • AccountsDb::calculate_accounts_hash_from_index
  • AccountsDb::get_append_vec_id

pub fn get_append_vec_id(&self, pubkey: &Pubkey, slot: Slot) -> Option<AppendVecId> {

.calculate_accounts_hash_from_index(slot, &calculate_accounts_hash_config);

But one of them, AccountsDb::get_append_vec_id seems to be deadcode.
And the other one AccountsDb::calculate_accounts_hash_from_index is only used in hash verification.

Both of them are not big deal.

But we may want to add a comment for fn AccountsIndex::get() to warn the caller that this fn makes a copy of the self-ref Arc.

@HaoranYi
Copy link
Contributor

HaoranYi commented Jan 24, 2024

Another place that we will clone the Arc unnecessarily, which can be optimized too!

  • AccountsIndex::get_account_read_entry_with_lock
    • AccountsIndex::get_account_read_entry
      • AccountsDb::do_shrink_slot_store
       for pubkey in shrink_collect.unrefed_pubkeys {
                if let Some(locked_entry) = self.accounts_index.get_account_read_entry(pubkey) {
                    // pubkeys in `unrefed_pubkeys` were unref'd in `shrink_collect` above under the assumption that we would shrink everything.
                    // Since shrink is not occurring, we need to addref the pubkeys to get the system back to the prior state since the account still exists at this slot.
                    locked_entry.addref();
                }
            }

@HaoranYi
Copy link
Contributor

Three more places that can be optimized too!

  • accounts_db::retry_to_get_account_accessor
  • snapshot_minimizer::get_minimized_slot_set
  • snapshot_minimizer::filter_storage

@HaoranYi
Copy link
Contributor

HaoranYi commented Jan 24, 2024

Maybe we should audit all the places this in_mem_accoutns_index::get fn is called too. This fn also clone the Arc.

pub fn get(&self, pubkey: &K) -> Option<AccountMapEntry<T>> {

@HaoranYi
Copy link
Contributor

HaoranYi commented Jan 24, 2024

Another idea is that we can change ReadAccountMapEntry to not hold Arc but hold &Arc, then we don't need to call Arc::clone when we get AccountMapEntry from the index.

#[self_referencing]
pub struct ReadAccountMapEntryRef<'a, T: IndexValue> {
    owned_entry: &'a AccountMapEntry<T>,
    #[borrows(owned_entry)]
    #[covariant]
    slot_list_guard: RwLockReadGuard<'this, SlotList<T>>,
}

A quick prototype and a simple test shows that this approach , i.e. ReadAccountMapEntryRef is
https://github.com/solana-labs/solana/compare/master...HaoranYi:jan_24_2024_self_ref_ref?expand=1

[Update]
However, it doesn't work.

   /// lookup 'pubkey' in index (in mem or on disk)
    pub fn get_ref<'a, 'b>(&'a self, pubkey: &K) -> Option<&'b AccountMapEntry<T>>
    where
        'a: 'b,
    {
        self.get_internal(pubkey, |entry| (true, entry))
    }

It looks like that we can't return entry, Option<&Arc<..>> out of get_ref. entry lifetime is not long enough to cover the return value.

@github-actions github-actions bot added the stale [bot only] Added to stale content; results in auto-close after a week. label Feb 13, 2024
@github-actions github-actions bot closed this Feb 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stale [bot only] Added to stale content; results in auto-close after a week.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants