дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 11:15:40 +02:00
fix(plugins): soft deadlines hold under load, unique cache writes, CI on every platform
- A provider result produced after its soft deadline is dropped even when it is already waiting (the caller was scheduled late or waited on another plugin first), so the deadline holds on a busy machine. The result is timestamped when the plugin's thread produces it, so a result that came in time is still used when it is read late. - Each precompiled-component write uses its own temporary file: two threads storing the same component could rename a half-written file into place. - Tests: the cache-corruption case replaces the file instead of overwriting the one a running component maps; the yield test no longer counts on a tick rate; a test that runs a shell script is Unix-only like its neighbours. - Plugin web pages declare `@types/node` for their Vite configs instead of finding the repository's.
Цей коміт міститься в:
1 джерело
9cc83c77b8
коміт
20960c1d96
10 files changed
+84
-34
No files matched your search
@@ -527,10 +527,9 @@ fn edit_path_calls_have_soft_and_hard_deadlines() {
|
||||
let tokens = provider.highlights(&mis, "fast").unwrap();
|
||||
assert_eq!((tokens[0].start, tokens[0].end, tokens[0].kind.as_str()), (0, 4, "keyword"));
|
||||
|
||||
// Slower than the soft deadline: dropped, but the instance lives on.
|
||||
let started = Instant::now();
|
||||
// Slower than the soft deadline: dropped (however late this thread gets
|
||||
// to look), but the instance lives on.
|
||||
assert!(provider.highlights(&mis, "sleep:150").is_none());
|
||||
assert!(started.elapsed() < Duration::from_millis(120), "{:?}", started.elapsed());
|
||||
std::thread::sleep(Duration::from_millis(150));
|
||||
assert!(provider.highlights(&mis, "fast").is_some());
|
||||
let info = host.info_of("misbehave").unwrap();
|
||||
@@ -1165,9 +1164,12 @@ fn precompiled_components_make_cold_activation_cheap() {
|
||||
std::fs::write(cache.join("0000-stale.cwasm"), b"junk").unwrap();
|
||||
again.warm_component_cache();
|
||||
assert_eq!(cached(), 1);
|
||||
// A corrupt entry is discarded and recompiled.
|
||||
// A corrupt entry is discarded and recompiled. Replaced, not overwritten:
|
||||
// the running component maps the file it was loaded from.
|
||||
for e in std::fs::read_dir(&cache).unwrap().flatten() {
|
||||
std::fs::write(e.path(), b"junk").unwrap();
|
||||
let junk = e.path().with_extension("junk");
|
||||
std::fs::write(&junk, b"junk").unwrap();
|
||||
std::fs::rename(&junk, e.path()).unwrap();
|
||||
}
|
||||
again.reload("hello").unwrap();
|
||||
assert!(
|
||||
@@ -1949,6 +1951,7 @@ fn official_regex_tester_answers_its_page() {
|
||||
/// A tree filled from a pinned program's output, and a terminal for the
|
||||
/// activated entry in the invoking window, titled and sized by the plugin's
|
||||
/// settings (the `jobs` fixture).
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn pinned_programs_fill_views_and_open_terminals() {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
@@ -35,17 +35,23 @@ pub enum ActorError {
|
||||
|
||||
/// A call queued with [`Actor::submit`].
|
||||
pub struct Pending<R> {
|
||||
result: mpsc::Receiver<Result<R, CallError>>,
|
||||
/// The outcome and when the plugin's thread produced it.
|
||||
result: mpsc::Receiver<(Result<R, CallError>, Instant)>,
|
||||
give_up: Option<Instant>,
|
||||
alive: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl<R> Pending<R> {
|
||||
/// Waits for the outcome, until the call's soft deadline if it has one.
|
||||
/// Waits for the outcome, until the call's soft deadline if it has one. A
|
||||
/// result produced after that deadline is dropped even when it is already
|
||||
/// there (the caller was not scheduled in time, or waited on another call
|
||||
/// first), so the deadline holds however busy the machine is; a failure is
|
||||
/// still reported.
|
||||
pub fn wait(self) -> Result<R, ActorError> {
|
||||
let outcome = match self.give_up {
|
||||
Some(t) => match self.result.recv_timeout(t.saturating_duration_since(Instant::now())) {
|
||||
Ok(r) => r,
|
||||
Ok((Ok(_), done)) if done > t => return Err(ActorError::SoftTimeout),
|
||||
Ok((r, _)) => r,
|
||||
Err(mpsc::RecvTimeoutError::Timeout) => return Err(ActorError::SoftTimeout),
|
||||
Err(mpsc::RecvTimeoutError::Disconnected) => {
|
||||
// Skipped as too late, or the actor ended.
|
||||
@@ -53,7 +59,7 @@ impl<R> Pending<R> {
|
||||
return Err(if alive { ActorError::SoftTimeout } else { ActorError::Stopped });
|
||||
}
|
||||
},
|
||||
None => self.result.recv().map_err(|_| ActorError::Stopped)?,
|
||||
None => self.result.recv().map_err(|_| ActorError::Stopped)?.0,
|
||||
};
|
||||
outcome.map_err(ActorError::Call)
|
||||
}
|
||||
@@ -149,7 +155,7 @@ impl Actor {
|
||||
alive.store(false, Ordering::Release);
|
||||
*slot = None;
|
||||
}
|
||||
let _ = reply.send(outcome);
|
||||
let _ = reply.send((outcome, Instant::now()));
|
||||
});
|
||||
{
|
||||
let tx = self.tx.lock().unwrap_or_else(|e| e.into_inner());
|
||||
|
||||
@@ -17,7 +17,7 @@ use ide_extension::Capability;
|
||||
use parking_lot::Mutex;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
|
||||
use std::time::{Duration, Instant};
|
||||
use wasmtime::component::{Component, HasSelf, Linker, ResourceTable};
|
||||
use wasmtime::{Config, Engine, Store, StoreLimits, StoreLimitsBuilder, UpdateDeadline};
|
||||
@@ -271,7 +271,10 @@ fn store_precompiled(component: &Component, file: &Path) {
|
||||
if let Some(dir) = file.parent() {
|
||||
let _ = std::fs::create_dir_all(dir);
|
||||
}
|
||||
let tmp = file.with_extension(format!("tmp{}", std::process::id()));
|
||||
// Unique per write: two threads may store the same component at once, and a
|
||||
// shared temporary file could be renamed into place half written.
|
||||
static WRITES: AtomicU64 = AtomicU64::new(0);
|
||||
let tmp = file.with_extension(format!("tmp{}-{}", std::process::id(), WRITES.fetch_add(1, Ordering::Relaxed)));
|
||||
if std::fs::write(&tmp, bytes).and_then(|()| std::fs::rename(&tmp, file)).is_err() {
|
||||
let _ = std::fs::remove_file(&tmp);
|
||||
}
|
||||
|
||||
@@ -236,7 +236,8 @@ async fn spinning_guest_yields_to_the_executor() {
|
||||
let spin = base.call_run(&mut s, "spin", "");
|
||||
assert!(tokio::time::timeout(Duration::from_millis(200), spin).await.is_err(), "spin never returns");
|
||||
ticker.abort();
|
||||
assert!(ticks.load(Ordering::Relaxed) > 10, "the executor kept running other tasks while the guest spun");
|
||||
// How often depends on how busy the machine is; that it ran at all shows the guest yielded.
|
||||
assert!(ticks.load(Ordering::Relaxed) > 0, "the executor kept running other tasks while the guest spun");
|
||||
}
|
||||
|
||||
/// P0-2b: dropping the call future cancels the call — and poisons the instance:
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
"react-dom": "^19.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^26.6.6",
|
||||
"@types/react": "^19.1.0",
|
||||
"@types/react-dom": "^19.1.0",
|
||||
"@vitejs/plugin-react": "^6.0.2",
|
||||
|
||||
+28
-11
@@ -18,6 +18,9 @@ importers:
|
||||
specifier: ^19.1.0
|
||||
version: 19.3.1([email protected])
|
||||
devDependencies:
|
||||
'@types/node':
|
||||
specifier: ^26.6.6
|
||||
version: 26.6.6
|
||||
'@types/react':
|
||||
specifier: ^19.1.0
|
||||
version: 19.3.0
|
||||
@@ -26,7 +29,7 @@ importers:
|
||||
version: 19.3.0(@types/[email protected])
|
||||
'@vitejs/plugin-react':
|
||||
specifier: ^6.0.2
|
||||
version: 6.1.2([email protected])
|
||||
version: 6.1.2([email protected](@types/[email protected]))
|
||||
jsdom:
|
||||
specifier: ^30.1.3
|
||||
version: 30.1.3
|
||||
@@ -35,10 +38,10 @@ importers:
|
||||
version: 6.0.3
|
||||
vite:
|
||||
specifier: ^8.0.16
|
||||
version: 8.3.5
|
||||
version: 8.3.5(@types/[email protected])
|
||||
vitest:
|
||||
specifier: ^5.0.5
|
||||
version: 5.0.5([email protected])([email protected])
|
||||
version: 5.0.5(@types/[email protected])([email protected])([email protected](@types/[email protected]))
|
||||
|
||||
packages:
|
||||
|
||||
@@ -675,6 +678,9 @@ packages:
|
||||
'@types/[email protected]':
|
||||
resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==}
|
||||
|
||||
'@types/[email protected]':
|
||||
resolution: {integrity: sha512-MzQj+8Kx3XI40OmUAE6Qoh58ZMNstNNMwn2nfd3qWsfe7nDNSqJNzes4njhz6AHwrSHOffSLwXU6yb474Q4aog==}
|
||||
|
||||
'@types/[email protected]':
|
||||
resolution: {integrity: sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==}
|
||||
peerDependencies:
|
||||
@@ -1487,6 +1493,9 @@ packages:
|
||||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-+fdndUTwBP86cVjihTp21hZHo7d6oj1c/47XPA3lL8mM0XHs+C4EkcjmgRsFnFk2f/UONGDy9ItBItmXsLOQHw==}
|
||||
engines: {node: '>=22.19.0'}
|
||||
@@ -2304,6 +2313,10 @@ snapshots:
|
||||
|
||||
'@types/[email protected]': {}
|
||||
|
||||
'@types/[email protected]':
|
||||
dependencies:
|
||||
undici-types: 8.9.0
|
||||
|
||||
'@types/[email protected](@types/[email protected])':
|
||||
dependencies:
|
||||
'@types/react': 19.3.0
|
||||
@@ -2320,19 +2333,19 @@ snapshots:
|
||||
d3-selection: 3.0.0
|
||||
d3-transition: 3.0.1([email protected])
|
||||
|
||||
'@vitejs/[email protected]([email protected])':
|
||||
'@vitejs/[email protected]([email protected](@types/[email protected]))':
|
||||
dependencies:
|
||||
'@rolldown/pluginutils': 1.0.1
|
||||
vite: 8.3.5
|
||||
vite: 8.3.5(@types/[email protected])
|
||||
|
||||
'@vitest/[email protected]([email protected])':
|
||||
'@vitest/[email protected]([email protected](@types/[email protected]))':
|
||||
dependencies:
|
||||
'@jridgewell/trace-mapping': 0.3.31
|
||||
'@vitest/spy': 5.0.5
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 1.4.5
|
||||
optionalDependencies:
|
||||
vite: 8.3.5
|
||||
vite: 8.3.5(@types/[email protected])
|
||||
|
||||
'@vitest/[email protected]': {}
|
||||
|
||||
@@ -3084,6 +3097,8 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected](@types/[email protected])([email protected]):
|
||||
@@ -3107,7 +3122,7 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]:
|
||||
[email protected](@types/[email protected]):
|
||||
dependencies:
|
||||
lightningcss: 1.33.0
|
||||
picomatch: 4.0.7
|
||||
@@ -3115,12 +3130,13 @@ snapshots:
|
||||
rolldown: 1.2.16
|
||||
tinyglobby: 0.2.17
|
||||
optionalDependencies:
|
||||
'@types/node': 26.6.6
|
||||
fsevents: 2.3.3
|
||||
|
||||
[email protected]([email protected])([email protected]):
|
||||
[email protected](@types/[email protected])([email protected])([email protected](@types/[email protected])):
|
||||
dependencies:
|
||||
'@types/chai': 5.2.3
|
||||
'@vitest/mocker': 5.0.5([email protected])
|
||||
'@vitest/mocker': 5.0.5([email protected](@types/[email protected]))
|
||||
chai: 6.3.0
|
||||
es-module-lexer: 2.3.2
|
||||
expect-type: 1.4.0
|
||||
@@ -3131,9 +3147,10 @@ snapshots:
|
||||
tinybench: 6.2.3
|
||||
tinyexec: 1.3.1
|
||||
tinyglobby: 0.2.17
|
||||
vite: 8.3.5
|
||||
vite: 8.3.5(@types/[email protected])
|
||||
why-is-node-running: 3.2.1
|
||||
optionalDependencies:
|
||||
'@types/node': 26.6.6
|
||||
jsdom: 30.1.3
|
||||
transitivePeerDependencies:
|
||||
- msw
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"isolatedModules": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"types": ["vite/client"]
|
||||
"types": ["vite/client", "node"]
|
||||
},
|
||||
"include": ["src", "vite.config.ts"]
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
"@viz-js/viz": "3.31.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^26.6.6",
|
||||
"typescript": "~6.0.3",
|
||||
"vite": "^8.0.16",
|
||||
"vitest": "^5.0.5"
|
||||
|
||||
+26
-8
@@ -12,15 +12,18 @@ importers:
|
||||
specifier: 3.31.0
|
||||
version: 3.31.0
|
||||
devDependencies:
|
||||
'@types/node':
|
||||
specifier: ^26.6.6
|
||||
version: 26.6.6
|
||||
typescript:
|
||||
specifier: ~6.0.3
|
||||
version: 6.0.3
|
||||
vite:
|
||||
specifier: ^8.0.16
|
||||
version: 8.3.5
|
||||
version: 8.3.5(@types/[email protected])
|
||||
vitest:
|
||||
specifier: ^5.0.5
|
||||
version: 5.0.5([email protected])
|
||||
version: 5.0.5(@types/[email protected])([email protected](@types/[email protected]))
|
||||
|
||||
packages:
|
||||
|
||||
@@ -145,6 +148,9 @@ packages:
|
||||
'@types/[email protected]':
|
||||
resolution: {integrity: sha512-lTyOMnOcmRBzdCv6/4zUZCrEhV0xrqQiUZBZtVcbmLHBXKLnN8q89v/wKRF/Q0HbwVsqbIG3o5HDoFl9sduM+g==}
|
||||
|
||||
'@types/[email protected]':
|
||||
resolution: {integrity: sha512-MzQj+8Kx3XI40OmUAE6Qoh58ZMNstNNMwn2nfd3qWsfe7nDNSqJNzes4njhz6AHwrSHOffSLwXU6yb474Q4aog==}
|
||||
|
||||
'@vitest/[email protected]':
|
||||
resolution: {integrity: sha512-xLL3lkDegJZw+MGoGaCCsFayDZthGgpAtr3Vziyfc4p7xH89K7KRPcRBBh/kEYm0Aqkt5DtTmkYpBtRV/FrHZg==}
|
||||
peerDependencies:
|
||||
@@ -324,6 +330,9 @@ packages:
|
||||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-z1YpjieJ9g0ebTmQpLBv/oq9E3F9EIlOe+7LahW8SrE3LTiG3udBRUXQOlYXP9b+IC2q2phHeVxj9xGlw34OEQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -482,14 +491,18 @@ snapshots:
|
||||
|
||||
'@types/[email protected]': {}
|
||||
|
||||
'@vitest/[email protected]([email protected])':
|
||||
'@types/[email protected]':
|
||||
dependencies:
|
||||
undici-types: 8.9.0
|
||||
|
||||
'@vitest/[email protected]([email protected](@types/[email protected]))':
|
||||
dependencies:
|
||||
'@jridgewell/trace-mapping': 0.3.31
|
||||
'@vitest/spy': 5.0.5
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 1.4.5
|
||||
optionalDependencies:
|
||||
vite: 8.3.5
|
||||
vite: 8.3.5(@types/[email protected])
|
||||
|
||||
'@vitest/[email protected]': {}
|
||||
|
||||
@@ -619,7 +632,9 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]:
|
||||
[email protected]: {}
|
||||
|
||||
[email protected](@types/[email protected]):
|
||||
dependencies:
|
||||
lightningcss: 1.33.0
|
||||
picomatch: 4.0.7
|
||||
@@ -627,12 +642,13 @@ snapshots:
|
||||
rolldown: 1.2.16
|
||||
tinyglobby: 0.2.17
|
||||
optionalDependencies:
|
||||
'@types/node': 26.6.6
|
||||
fsevents: 2.3.3
|
||||
|
||||
[email protected]([email protected]):
|
||||
[email protected](@types/[email protected])([email protected](@types/[email protected])):
|
||||
dependencies:
|
||||
'@types/chai': 5.2.3
|
||||
'@vitest/mocker': 5.0.5([email protected])
|
||||
'@vitest/mocker': 5.0.5([email protected](@types/[email protected]))
|
||||
chai: 6.3.0
|
||||
es-module-lexer: 2.3.2
|
||||
expect-type: 1.4.0
|
||||
@@ -643,8 +659,10 @@ snapshots:
|
||||
tinybench: 6.2.3
|
||||
tinyexec: 1.3.1
|
||||
tinyglobby: 0.2.17
|
||||
vite: 8.3.5
|
||||
vite: 8.3.5(@types/[email protected])
|
||||
why-is-node-running: 3.2.1
|
||||
optionalDependencies:
|
||||
'@types/node': 26.6.6
|
||||
transitivePeerDependencies:
|
||||
- msw
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"isolatedModules": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"types": ["vite/client"]
|
||||
"types": ["vite/client", "node"]
|
||||
},
|
||||
"include": ["src", "vite.config.ts"]
|
||||
}
|
||||
Reference in new issue
Заблокувати користувача