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

fix: properly stop prefetching background threads #7712

Merged
merged 3 commits into from
Sep 29, 2022

Conversation

jakmeier
Copy link
Contributor

Explicitly stop and wait for prefetching background threads to terminate when the ShardTriesInner is dropped.

This avoids that estimations are influenced by background threads left
over from previous estimations, which we have observed since merging
#7661.

Explicitly stop and wait for prefetching background threads to terminate
when the `ShardTriesInner` is dropped.

 This avoids that estimations are influenced by background threads left
 over from previous estimations, which we have observed since merging
 near#7661.
@jakmeier jakmeier requested a review from a team as a code owner September 28, 2022 12:57
@jakmeier jakmeier requested review from akhi3030 and matklad and removed request for akhi3030 September 28, 2022 12:57
@jakmeier
Copy link
Contributor Author

replaces #7689

@@ -334,7 +337,7 @@ impl PrefetchStagingArea {
Some(_) => (),
None => return None,
}
std::thread::sleep(std::time::Duration::from_micros(1));
Copy link
Contributor

Choose a reason for hiding this comment

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

unreleated to the PR, but this one here looks quite suspect. Should this have a Condvar instead of a busy-wait here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah from a logical point it almost certainly should. But I suspect it would also make code quite a bit more complex.

To elaborate a bit, we are waiting for one of two events to happen here:

  1. An IO background thread puts the value into the staging area.
  2. A main thread puts the value in the shard cache.

Both these options are possible regardless of whether blocking_get got called from a main thread or from a background thread.

The case where we are a main thread and another main thread puts it in the shard cache is also not handled properly, yet. Let me create an issue for cleaning that up...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

#[must_use = "When dropping this handle, the IO threads will be aborted immediately."]
pub(crate) struct PrefetchingThreadsHandle {
/// Shutdown channels to all spawned threads.
shutdown_channels: Vec<crossbeam::channel::Sender<()>>,
Copy link
Contributor

Choose a reason for hiding this comment

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

One channel should be enough here, Receiver: Clone

Comment on lines 501 to 509
for tx in &self.shutdown_channels {
let e = tx.send(());
if e.is_err() {
// Usually senders are dropped after joining all background threads.
// But if this order is reversed, this send here will fail. This
// is perfectly valid behavior and should not be treated as error.
debug!("IO thread already hung up when trying to shut it down.");
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
for tx in &self.shutdown_channels {
let e = tx.send(());
if e.is_err() {
// Usually senders are dropped after joining all background threads.
// But if this order is reversed, this send here will fail. This
// is perfectly valid behavior and should not be treated as error.
debug!("IO thread already hung up when trying to shut it down.");
}
}
self.shutdown_channels.clear()

Copy link
Contributor

Choose a reason for hiding this comment

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

That is, closing a channel gives the signal we want here, we don't need special code to handle this.

let (shutdown_tx, shutdown_rx) = crossbeam::channel::bounded(1);
let handle = thread::spawn(move || {
loop {
select! {
Copy link
Contributor

Choose a reason for hiding this comment

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

Not a huge fan of putting ladge chunks of code into a select. I'd write htis as

loop {
    let next_item = select! {}
    match next_item { None => return, Some(it) => process }
}

@near-bulldozer near-bulldozer bot merged commit cd7217b into near:master Sep 29, 2022
@jakmeier jakmeier deleted the stop-prefetch-threads branch September 29, 2022 12:19
nikurt pushed a commit that referenced this pull request Nov 9, 2022
Explicitly stop and wait for prefetching background threads to terminate when the `ShardTriesInner` is dropped.

 This avoids that estimations are influenced by background threads left
 over from previous estimations, which we have observed since merging
 #7661.
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.

2 participants