-
Notifications
You must be signed in to change notification settings - Fork 521
feat: Use channels to maintain job tokens & reuse the implicit token without dropping it first #878
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
Merged
NobodyXu
merged 12 commits into
rust-lang:main
from
osiewicz:no_drops_on_implicit_job_token
Oct 19, 2023
Merged
Changes from 5 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
0c87751
feat: Do not preemptively drop implicit job token.
osiewicz d0a8a49
Move implementation to a separate module and document a bunch
osiewicz ee5dee7
Readd reusable global jobserver connection
osiewicz 3637127
Fix up a comment
osiewicz 4ca7808
Further documentation refinements
osiewicz 1b025d8
Move jobserver func into job_token module
osiewicz 52afaf1
Remove should_return_to_queue member in favor of wrapping pool in an …
osiewicz 3d45841
Make jobserver initialization private in job_token mod
osiewicz 280c673
Remove unnecessary mut on acquire fn
osiewicz d55c382
Use shared global JobTokenServer
osiewicz 985dbae
Change Option to MaybeUninit
osiewicz 65ab371
Convert internal channel to use Result and do not panic in helper thread
osiewicz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
use jobserver::{Acquired, Client, HelperThread}; | ||
use std::sync::mpsc::{self, Receiver, Sender}; | ||
|
||
pub(crate) struct JobToken { | ||
/// The token can either be a fresh token obtained from the jobserver or - if `token` is None - an implicit token for this process. | ||
/// Both are valid values to put into queue. | ||
token: Option<Acquired>, | ||
pool: Sender<Option<Acquired>>, | ||
should_return_to_queue: bool, | ||
} | ||
|
||
impl Drop for JobToken { | ||
fn drop(&mut self) { | ||
if self.should_return_to_queue { | ||
let _ = self.pool.send(self.token.take()); | ||
} | ||
} | ||
} | ||
|
||
impl JobToken { | ||
/// Ensure that this token is not put back into queue once it's dropped. | ||
/// This also leads to releasing it sooner for other processes to use, | ||
/// which is a correct thing to do once it is known that there won't be | ||
/// any more token acquisitions. | ||
pub(crate) fn forget(&mut self) { | ||
self.should_return_to_queue = false; | ||
} | ||
} | ||
|
||
/// A thin wrapper around jobserver's Client. | ||
/// It would be perfectly fine to just use jobserver's Client, but we also want to reuse | ||
/// our own implicit token assigned for this build script. This struct manages that and | ||
/// gives out tokens without exposing whether they're implicit tokens or tokens from jobserver. | ||
/// Furthermore, instead of giving up job tokens, it keeps them around | ||
/// for reuse if we know we're going to request another token after freeing the current one. | ||
pub(crate) struct JobTokenServer { | ||
helper: HelperThread, | ||
tx: Sender<Option<Acquired>>, | ||
rx: Receiver<Option<Acquired>>, | ||
} | ||
|
||
impl JobTokenServer { | ||
pub(crate) fn new(client: Client) -> Result<Self, crate::Error> { | ||
let (tx, rx) = mpsc::channel(); | ||
// Push the implicit token. Since JobTokens only give back what they got, | ||
// there should be at most one global implicit token in the wild. | ||
tx.send(None).unwrap(); | ||
let pool = tx.clone(); | ||
let helper = client.into_helper_thread(move |acq| { | ||
let _ = pool.send(Some(acq.unwrap())); | ||
osiewicz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
})?; | ||
Ok(Self { helper, tx, rx }) | ||
} | ||
|
||
pub(crate) fn acquire(&mut self) -> JobToken { | ||
let token = if let Ok(token) = self.rx.try_recv() { | ||
// Opportunistically check if there's a token that can be reused. | ||
token | ||
} else { | ||
// Cold path, request a token and block | ||
self.helper.request_token(); | ||
osiewicz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
self.rx.recv().unwrap() | ||
}; | ||
JobToken { | ||
token, | ||
pool: self.tx.clone(), | ||
should_return_to_queue: true, | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.