-
Notifications
You must be signed in to change notification settings - Fork 0
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
Analyzing progress notifications #44
base: main
Are you sure you want to change the base?
Conversation
ae728b8
to
bcd6a77
Compare
@@ -26,7 +26,7 @@ pub struct Client<'s> { | |||
pub(super) requester: Requester<'s>, | |||
} | |||
|
|||
#[derive(Clone)] | |||
#[derive(Clone, Debug)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why?
#[derive(Clone, Debug)] | |
#[derive(Clone)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's included in the new Controller which needs to be Debug
as well because of ProcMacroClient
being Debug
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe custom impl on ProcMacroClient
would be better in this case? This does not make sense to debug this struct
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not done
src/state.rs
Outdated
); | ||
|
||
let diagnostics_controller = | ||
DiagnosticsController::new(notifier.clone(), analysis_progress_controller.clone()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please dont pass AnalysisProgressController
everywhere, split it into 2 parts where one lives on the main thread/special thread and second can be used in other places, this will also help splitting its interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done - pls let me know if that's what you meant
/// Uses information provided from other controllers (diagnostics controller, procmacro controller) | ||
/// to assess if diagnostics are in fact calculated. | ||
#[derive(Debug, Clone)] | ||
pub struct AnalysisProgressController { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we get flow explanation here? like in ProcMacroController
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can do although i think it's nicely explained here in the docstrings
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TBD Still - i would like to finalize business logic first if that's OK so i don't have to update this flowchart
bcd6a77
to
2a2bc04
Compare
Co-authored-by: Piotr Figiela <77412592+Draggu@users.noreply.github.com> Signed-off-by: Tomasz Rejowski <34059895+Arcticae@users.noreply.github.com>
@@ -26,7 +26,7 @@ pub struct Client<'s> { | |||
pub(super) requester: Requester<'s>, | |||
} | |||
|
|||
#[derive(Clone)] | |||
#[derive(Clone, Debug)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not done
} | ||
} | ||
/// Struct which allows setting a callback - which can be triggered afterward | ||
/// by the function which has the reference. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reference to what?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reference to the thing that i'm talking about - the struct
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we state that explicitly in the comment? It can be figured out, but it is not immediately obvious on the (English) language level
/// Struct which allows setting a callback - which can be triggered afterward | ||
/// by the function which has the reference. | ||
#[derive(Default)] | ||
pub struct Beacon { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a standard name for this pattern? Isn't Callback
with set
and execute
methods better?
|
||
pub fn signal(&mut self) { | ||
if let Some(hook) = self.signal_hook.take() { | ||
hook(); // call the hook |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is useless
self.signal_hook = Some(Box::new(drop_hook)); | ||
} | ||
|
||
pub fn signal(&mut self) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
signal_and_clear_hook
?
/// Notifies about diagnostics generation which is beginning to calculate | ||
#[derive(Debug)] | ||
pub struct DiagnosticsCalculationStart; | ||
|
||
impl Notification for DiagnosticsCalculationStart { | ||
type Params = (); | ||
const METHOD: &'static str = "cairo/diagnosticsCalculationStart"; | ||
} | ||
|
||
/// Notifies about diagnostics generation which ended calculating | ||
#[derive(Debug)] | ||
pub struct DiagnosticsCalculationFinish; | ||
|
||
impl Notification for DiagnosticsCalculationFinish { | ||
type Params = (); | ||
const METHOD: &'static str = "cairo/diagnosticsCalculationFinish"; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Idk if it shouldn't go to lsp/ext.rs
for consistency
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know why not place it near the usage tbh
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both are fine for me tbh, I guess we should get rid of lsp/ext.rs
altogether #130
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's place it in lsp/ext.rs
as discussed on meeting
} | ||
|
||
impl Beacon { | ||
// Set the drop hook |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dot.
Btw it doesn't set the drop hook, it is not done on Drop
.
.field("id_generator", &self.id_generator) | ||
.field("requests_params", &self.requests_params) | ||
.field("error_channel", &self.error_channel) | ||
.finish() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.finish() | |
.finish_non_exhaustive() |
} | ||
|
||
impl Beacon { | ||
// Set the drop hook |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe note here that it is disposable?
controller: AnalysisProgressController, | ||
} | ||
|
||
impl AnalysisProgressTracker { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can split it for proc macros / diagnostics so interface is clear there, also it does not have to store whole controller (and should not if it possible, if not then maybe controller itself is ok).
} | ||
|
||
/// Allows to set the procmacro configuration to whatever is in the config, upon loading it. | ||
pub fn set_procmacros_enabled(&self, value: bool) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub fn set_procmacros_enabled(&self, value: bool) { | |
pub fn on_config_change(&self, config: &Config) { |
More future proof and it is clear where this info is coming from.
let id_generator = Arc::new(IdGenerator::default()); | ||
Self { | ||
notifier, | ||
id_generator: id_generator.clone(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why clone here, just generate unique_id before the struct constructor expr
pub fn get_generation_id(&self) -> u64 { | ||
self.generation_id.load(Ordering::SeqCst) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Used in one place, just inline it imo
} | ||
|
||
pub fn clear_active_snapshots(&self) { | ||
let active_snapshots_ref = self.active_snapshots.clone(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you need to clone here?
@@ -142,6 +150,7 @@ impl ProcMacroClient { | |||
match self.send_request_untracked::<M>(id, ¶ms) { | |||
Ok(()) => { | |||
requests_params.insert(id, map(params)); | |||
self.analysis_progress_tracker.register_procmacro_request(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that there is a small chance that a yet alive snapshot from previous diagnostics calculation was already in db.get_attribute_expansion
before its cancellation. It will still call this method and possibly register proc macro request in analysis tracker AFTER track_analysis
is called to start tracking the new diagnostics batch. It can cause us to never finish waiting for diagnostics in tests, since:
- the next batch won't be scheduled
- we will always think there is some proc macro yet to resolve while it may not be
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logic wise seems good besides what I wrote before
|
||
pub fn remove_active_snapshot(&self, snapshot_id: usize) { | ||
let mut active_snapshots = self.active_snapshots.lock().unwrap(); | ||
active_snapshots.remove(&snapshot_id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An assertion could be made here to make sure sth was removed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A lot of pubs are unnecessary here, some methods could be inlined
} | ||
/// Struct which allows setting a callback - which can be triggered afterward |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | |
/// Struct which allows setting a callback - which can be triggered afterward | |
} | |
/// Struct which allows setting a callback - which can be triggered afterward |
/// Struct which allows setting a callback - which can be triggered afterward | ||
/// by the function which has the reference. | ||
#[derive(Default)] | ||
pub struct Beacon { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TBH you have simplified this so much that I would probably drop this type entirely and just stick that Option<Box<dyn FnOnce() + Send>>
.
/// The beacons are wrapping snapshots, which are signalling when diagnostics finished | ||
/// calculating for a given snapshot (used for calculating files diagnostics or removing | ||
/// stale ones) | ||
pub fn track_analysis<'a>(&self, beacons: impl Iterator<Item = &'a mut Beacon>) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't this just take a mutable reference to StateSnapshots?
/// Sequential IDs of state snapshots from the current generation, used to track their status | ||
/// (present meaning it's still being used) | ||
active_snapshots: Arc<Mutex<HashSet<usize>>>, | ||
id_generator: Arc<IdGenerator>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TBH you'd be better off not touching the IdGenerator here and just peeing that AtomicU64 in generation_id and incrementing it directly. you're just doing this in a fancy way now
#[derive(Debug, Clone)] | ||
pub struct AnalysisProgressController { | ||
notifier: Notifier, | ||
/// ID of the diagnostics "generation" - the scheduled diagnostics jobs set. | ||
/// Used to filter out stale threads finishing when new ones (from newer "generation") | ||
/// are already in progress and being tracked by the controller. | ||
generation_id: Arc<AtomicU64>, | ||
/// Sequential IDs of state snapshots from the current generation, used to track their status | ||
/// (present meaning it's still being used) | ||
active_snapshots: Arc<Mutex<HashSet<usize>>>, | ||
id_generator: Arc<IdGenerator>, | ||
/// If `true` - a request to procmacro server was submitted, meaning that analysis will extend | ||
/// beyond the current generation of diagnostics. | ||
did_submit_procmacro_request: Arc<AtomicBool>, | ||
/// Indicates that a notification was sent and analysis (i.e. macro expansion) is taking place. | ||
analysis_in_progress: Arc<AtomicBool>, | ||
/// Loaded asynchronously from config - unset if config was not loaded yet. | ||
/// Has to be set in order for analysis to finish. | ||
procmacros_enabled: Arc<Mutex<Option<bool>>>, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
consider just using a mutex for everything. I don't believe you benefit from atomics here over mutexes, and I'm not sure all methods here guarantee consistency in case of races.
struct AnalysisProgressController(Arc<Mutex<AnalysisProgressControllerState>>);
struct AnalysisProgressControllerState {
generation_id: u64,
// ...
}
/// Notifies about diagnostics generation which is beginning to calculate | ||
#[derive(Debug)] | ||
pub struct DiagnosticsCalculationStart; | ||
|
||
impl Notification for DiagnosticsCalculationStart { | ||
type Params = (); | ||
const METHOD: &'static str = "cairo/diagnosticsCalculationStart"; | ||
} | ||
|
||
/// Notifies about diagnostics generation which ended calculating | ||
#[derive(Debug)] | ||
pub struct DiagnosticsCalculationFinish; | ||
|
||
impl Notification for DiagnosticsCalculationFinish { | ||
type Params = (); | ||
const METHOD: &'static str = "cairo/diagnosticsCalculationFinish"; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's place it in lsp/ext.rs
as discussed on meeting
Based off this PR we can start implementing tests (like currently we can wait for project update + the diagnostics finish and it should work fine)