Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.

Re-use accounts stores#12885

Merged
sakridge merged 5 commits intosolana-labs:masterfrom
sakridge:re-use-account-stores
Nov 4, 2020
Merged

Re-use accounts stores#12885
sakridge merged 5 commits intosolana-labs:masterfrom
sakridge:re-use-account-stores

Conversation

@sakridge
Copy link
Copy Markdown
Contributor

Problem

File/mmap creation can be expensive (100s of ms) and mmap deletion causes a flush to disk which increases unnecessary writes to disk when that data is not actually needed.

Summary of Changes

Save stores for re-use later.

Fixes #

@sakridge sakridge marked this pull request as draft October 14, 2020 21:51
@sakridge sakridge force-pushed the re-use-account-stores branch 2 times, most recently from b464577 to c0d7a73 Compare October 14, 2020 23:34

pub fn slot(&self) -> Slot {
self.slot
self.slot.load(Ordering::Acquire)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

👀

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Our first acquire-release semantics! To celebrate maybe we should include a comment about why it's necessary here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think we use it in gossip as well. Most of our atomics are not critical for functionality like perf counters which are fine if they are incremented or loaded out of order. I thought it would be bad if the load/store is re-ordered for the slot value, a thread could see a stale slot value.

Copy link
Copy Markdown
Contributor

@carllin carllin Nov 3, 2020

Choose a reason for hiding this comment

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

Just to clarify my understanding and future reference about the interaction between the atomics slot and id fields in AccountStorageEntry:

A recycle scenario can be summarized with something like the following:

Initial state:

self.slot = 0
self.id = 0

Thread A grabs and holds a copy of the storage entry Arc and reads
Thread A

let ref_count = storage.lookup(store_id_x);  // lookup in the storage for some store_id_x, may be the old store id, or the new recycled id
ref_count.store(2, Ordering::SeqCst);      // storage clone bumps the Arc refcount, Arc uses `SeqCst`   
slot.load(Ordering::Acquire);                             
id.load(Ordering::Relaxed);
ref_count.store(1, Ordering::SeqCst);

Thread B performing the recycle:
Thread B

// do the recycle
if refcount.load(Ordering::SeqCst) == 1 {    // Arc `strong_count()` uses `SeqCst`   
    slot.store(5, Ordering::Release);                             
    id.store(5, Ordering::Relaxed);
}
// Insert the store
storage.lock().insert(store_id_y);   // insert recycled store into storage with new store id

So now looking at possible combinations of (slot, id) that thread A can see:

  1. If Thread A is reading directly grabbing and holding copy of the Arc for the storage entry from the recycled_stores, then it can see any combination of (0, 0), (0, 5), (5, 5) (5, 0), because the loads can interleave with the recycle logic in B that starts at if Arc::strong_count(store) == 1 {

  2. If Thread A is finding the storage entry through a read on self.storages:
    Can thread A still see a mixed combination like (0, 5), or (5, 0)? I think the storage lock and the strong_count() == 1 check prevent this from happening?
    For example for (5, 0), this means A must have seen B's store to slot, which means store_id_x == store_id_y,
    so the loads in thread A must have occurred after the new storage with store_id_y was inserted into the store at storage.lock().insert(store_id_y);. And because locks have full fences, both loads in thread A cannot be ordered before the storage.lock().insert(store_id_y);, and must see both stores from thread B.
    (0, 5) follows a similar reasoning.

@sakridge sakridge force-pushed the re-use-account-stores branch 4 times, most recently from 33fbd71 to 52ea4ac Compare October 22, 2020 16:03
@sakridge sakridge force-pushed the re-use-account-stores branch 5 times, most recently from c6eb905 to 9204156 Compare October 27, 2020 19:10
@sakridge sakridge added the CI Pull Request is ready to enter CI label Oct 27, 2020
@solana-grimes solana-grimes removed the CI Pull Request is ready to enter CI label Oct 27, 2020
@sakridge
Copy link
Copy Markdown
Contributor Author

Comparison of find storage time, new is on left. After warmup, it's improved from 10-15ms to 2-4ms.

find-storage

@sakridge sakridge force-pushed the re-use-account-stores branch from 9204156 to fd5e992 Compare October 27, 2020 23:29
@codecov
Copy link
Copy Markdown

codecov Bot commented Oct 28, 2020

Codecov Report

Merging #12885 into master will increase coverage by 0.0%.
The diff coverage is 93.7%.

@@           Coverage Diff            @@
##           master   #12885    +/-   ##
========================================
  Coverage    82.0%    82.0%            
========================================
  Files         376      376            
  Lines       87885    88114   +229     
========================================
+ Hits        72117    72322   +205     
- Misses      15768    15792    +24     

@sakridge sakridge force-pushed the re-use-account-stores branch from fd5e992 to 8a3e92d Compare October 28, 2020 17:05
@sakridge sakridge marked this pull request as ready for review October 28, 2020 17:12
@sakridge sakridge requested review from carllin and ryoqun October 28, 2020 17:12
Comment thread runtime/src/accounts_db.rs Outdated
Comment thread runtime/src/accounts_db.rs
Comment thread runtime/src/accounts_db.rs Outdated
Comment thread runtime/src/accounts_db.rs
Comment thread runtime/src/accounts_db.rs
Comment thread runtime/src/accounts_db.rs
Comment thread runtime/src/accounts_db.rs
Comment thread runtime/src/accounts_db.rs Outdated
Comment thread runtime/src/accounts_db.rs
Creating files and dropping mmap areas can be expensive
Can encounter an infinite loop when the store is too small, but
smaller than the normal store size.
@sakridge sakridge force-pushed the re-use-account-stores branch from 8a3e92d to c1b9f1f Compare November 1, 2020 18:27
@sakridge sakridge requested a review from carllin November 2, 2020 19:20
if !self.has_space_available(slot, data_len) {
let special_store_size = std::cmp::max(data_len * 2, self.file_size);
if self
.try_recycle_and_insert_store(slot, special_store_size, std::u64::MAX)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: Should we wrap this call to try_recycle_and_insert_store in a Measure and be add it to the self.stats.store_find_store timing metric?

Copy link
Copy Markdown
Contributor

@carllin carllin left a comment

Choose a reason for hiding this comment

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

Great stuff!

@sakridge sakridge merged commit 43053dc into solana-labs:master Nov 4, 2020
@sakridge sakridge deleted the re-use-account-stores branch November 4, 2020 17:17
dadamu pushed a commit to forbole/solana that referenced this pull request Nov 9, 2020
* Re-use accounts_db stores

Creating files and dropping mmap areas can be expensive

* Add test for storage finder

Can encounter an infinite loop when the store is too small, but
smaller than the normal store size.

* Fix storage finding

* Check for strong_count == 1

* try_recycle helper
sakridge added a commit to sakridge/solana that referenced this pull request Dec 17, 2020
* Re-use accounts_db stores

Creating files and dropping mmap areas can be expensive

* Add test for storage finder

Can encounter an infinite loop when the store is too small, but
smaller than the normal store size.

* Fix storage finding

* Check for strong_count == 1

* try_recycle helper
behzadnouri added a commit to behzadnouri/solana that referenced this pull request Jan 5, 2021
carllin pushed a commit to carllin/solana that referenced this pull request Jan 8, 2021
* Re-use accounts_db stores

Creating files and dropping mmap areas can be expensive

* Add test for storage finder

Can encounter an infinite loop when the store is too small, but
smaller than the normal store size.

* Fix storage finding

* Check for strong_count == 1

* try_recycle helper
carllin pushed a commit to carllin/solana that referenced this pull request Jan 13, 2021
* Re-use accounts_db stores

Creating files and dropping mmap areas can be expensive

* Add test for storage finder

Can encounter an infinite loop when the store is too small, but
smaller than the normal store size.

* Fix storage finding

* Check for strong_count == 1

* try_recycle helper
carllin pushed a commit to carllin/solana that referenced this pull request Jan 18, 2021
* Re-use accounts_db stores

Creating files and dropping mmap areas can be expensive

* Add test for storage finder

Can encounter an infinite loop when the store is too small, but
smaller than the normal store size.

* Fix storage finding

* Check for strong_count == 1

* try_recycle helper
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants