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(tarball): use rwlock instead of dashmap to avoid potential deadlock #200

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

await-ovo
Copy link
Member

Let's say we have a project that has express in dependencies and devDependencies:

// package.json
  "dependencies": {
    "express": "^4.18.2"
  },
  "devDependencies": {
    "express": "^4.18.2"
  }

Running pacquet/target/debug/pacquet install over and over again under this project sometimes hangs forever.

Inspect thread's backtrace using rust-lldb you can see that there seems to be a deadlock in the dashmap:

(lldb) thread list
Process 19187 stopped
* thread #1: tid = 0x1c7fe, 0x00007ff80c7670ee libsystem_kernel.dylib`__psynch_cvwait + 10, name = 'main', queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  thread #2: tid = 0x1c80b, 0x00007ff80c7670ee libsystem_kernel.dylib`__psynch_cvwait + 10, name = 'tokio-runtime-worker'
  thread #3: tid = 0x1c80c, 0x00007ff80c7670ee libsystem_kernel.dylib`__psynch_cvwait + 10, name = 'tokio-runtime-worker'
  thread #4: tid = 0x1c80d, 0x00007ff80c7670ee libsystem_kernel.dylib`__psynch_cvwait + 10, name = 'tokio-runtime-worker'
  thread #5: tid = 0x1c80e, 0x00007ff80c7670ee libsystem_kernel.dylib`__psynch_cvwait + 10, name = 'tokio-runtime-worker'
  thread #6: tid = 0x1c80f, 0x00007ff80c7670ee libsystem_kernel.dylib`__psynch_cvwait + 10, name = 'tokio-runtime-worker'
  thread #7: tid = 0x1c810, 0x00007ff80c7670ee libsystem_kernel.dylib`__psynch_cvwait + 10, name = 'tokio-runtime-worker'
  thread #8: tid = 0x1c811, 0x00007ff80c7670ee libsystem_kernel.dylib`__psynch_cvwait + 10, name = 'tokio-runtime-worker'
  thread #9: tid = 0x1c812, 0x00007ff80c7670ee libsystem_kernel.dylib`__psynch_cvwait + 10, name = 'tokio-runtime-worker'
  thread #10: tid = 0x1c813, 0x00007ff80c7670ee libsystem_kernel.dylib`__psynch_cvwait + 10, name = 'tokio-runtime-worker'
  thread #11: tid = 0x1c814, 0x00007ff80c7691ee libsystem_kernel.dylib`kevent + 10, name = 'tokio-runtime-worker'
  thread #12: tid = 0x1c815, 0x00007ff80c7670ee libsystem_kernel.dylib`__psynch_cvwait + 10, name = 'tokio-runtime-worker'
  thread #13: tid = 0x1c816, 0x00007ff80c7670ee libsystem_kernel.dylib`__psynch_cvwait + 10, name = 'tokio-runtime-worker'
  thread #14: tid = 0x1c8c7, 0x0000000000000000
(lldb) thread backtrace
* thread #1, name = 'main', queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  * frame #0: 0x00007ff80c7670ee libsystem_kernel.dylib`__psynch_cvwait + 10
    frame #1: 0x00007ff80c7a3758 libsystem_pthread.dylib`_pthread_cond_wait + 1242
    frame #2: 0x0000000101f8885a pacquet`_$LT$parking_lot_core..thread_parker..imp..ThreadParker$u20$as$u20$parking_lot_core..thread_parker..ThreadParkerT$GT$::park::h901dec8d6c82d511(self=0x00007fd753904620) at unix.rs:77:21
    frame #3: 0x0000000101f8681d pacquet`parking_lot_core::parking_lot::park::_$u7b$$u7b$closure$u7d$$u7d$::hf6f0000f30670c25(thread_data=0x00007fd753904620) at parking_lot.rs:635:17
    frame #4: 0x0000000101f85a7a pacquet`parking_lot_core::parking_lot::park::h7573f0f4d6138281 at parking_lot.rs:207:5
    frame #5: 0x0000000101f8599f pacquet`parking_lot_core::parking_lot::park::h7573f0f4d6138281(key=140562837595088, validate={closure_env#0} @ 0x00007ff7be08f878, before_sleep={closure_env#1} @ 0x00007ff7be08f886, timed_out={closure_env#2} @ 0x00007ff7be08f887, park_token=ParkToken @ 0x00007ff7be08f840, timeout=Option<std::time::Instant> @ 0x00007ff7be08f848) at parking_lot.rs:600:5
    frame #6: 0x0000000102b04394 pacquet`dashmap::lock::RawRwLock::lock_exclusive_slow::hf285450ddd71acbc(self=0x00007fd75600e3d0) at lock.rs:127:21
    frame #7: 0x0000000101ee3ce5 pacquet`_$LT$dashmap..lock..RawRwLock$u20$as$u20$lock_api..rwlock..RawRwLock$GT$::lock_exclusive::h759a7154a4d567da(self=0x00007fd75600e3d0) at lock.rs:39:13
    frame #8: 0x0000000101ee3ae5 pacquet`lock_api::rwlock::RwLock$LT$R$C$T$GT$::write::h815e856b6c8b2ff2(self=0x00007fd75600e3d0) at rwlock.rs:480:9
    frame #9: 0x0000000101ecbcb5 pacquet`_$LT$dashmap..DashMap$LT$K$C$V$C$S$GT$$u20$as$u20$dashmap..t..Map$LT$K$C$V$C$S$GT$$GT$::_yield_write_shard::hc66de80739a70aa5(self=0x00007ff7be0a0c18, i=54) at lib.rs:897:9
    frame #10: 0x0000000101ecbf0f pacquet`_$LT$dashmap..DashMap$LT$K$C$V$C$S$GT$$u20$as$u20$dashmap..t..Map$LT$K$C$V$C$S$GT$$GT$::_insert::h00b54d0a5a90f554(self=0x00007ff7be0a0c18, key="https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", value=strong=2, weak=0) at lib.rs:923:34
    frame #11: 0x0000000101ecbb05 pacquet`dashmap::DashMap$LT$K$C$V$C$S$GT$::insert::h1a302dff1cb874ef(self=0x00007ff7be0a0c18, key=<unavailable>, value=strong=2, weak=0) at lib.rs:459:9
    frame #12: 0x0000000101f0a0b9 pacquet`pacquet_tarball::DownloadTarballToStore::run_with_mem_cache::_$u7b$$u7b$closure$u7d$$u7d$::h3f64b7dfdb11ee17((null)=0x00007ff7be096750) at lib.rs:155:16
    frame #13: 0x0000000101f06eb0 pacquet`pacquet_package_manager::install_package_from_registry::InstallPackageFromRegistry::install_package_version::_$u7b$$u7b$closure$u7d$$u7d$::h39469df5cf1dd94c((null)=0x00007ff7be096750) at install_package_from_registry.rs:93:10
    frame #14: 0x0000000101f068d8 pacquet`pacquet_package_manager::install_package_from_registry::InstallPackageFromRegistry::run::_$u7b$$u7b$closure$u7d$$u7d$::h353ed9cd774f2404((null)=0x00007ff7be096750) at install_package_from_registry.rs:61:59
    frame #15: 0x0000000101f28c03 pacquet`pacquet_package_manager::install_without_lockfile::InstallWithoutLockfile$LT$$LP$$RP$$GT$::install_dependencies_from_registry::_$u7b$$u7b$closure$u7d$$u7d$::_$u7b$$u7b$closure$u7d$$u7d$::_$u7b$$u7b$closure$u7d$$u7d$::h80c7f76aaa118353((null)=0x00007ff7be096750) at install_without_lockfile.rs:100:18
    frame #16: 0x0000000101efef7d pacquet`_$LT$futures_util..stream..futures_ordered..OrderWrapper$LT$T$GT$$u20$as$u20$core..future..future..Future$GT$::poll::h331dc0890632c4ce(self=Pin<&mut futures_util::stream::futures_ordered::OrderWrapper<pacquet_package_manager::install_without_lockfile::{impl#1}::install_dependencies_from_registry::{async_block#0}::{closure#0}::{async_block_env#0}>> @ 0x00007ff7be096510, cx=0x00007ff7be096750) at futures_ordered.rs:55:9
    frame #17: 0x0000000101ed3fc5 pacquet`_$LT$futures_util..stream..futures_unordered..FuturesUnordered$LT$Fut$GT$$u20$as$u20$futures_core..stream..Stream$GT$::poll_next::hbe129c38375cab09(self=Pin<&mut futures_util::stream::futures_unordered::FuturesUnordered<futures_util::stream::futures_ordered::OrderWrapper<pacquet_package_manager::install_without_lockfile::{impl#1}::install_dependencies_from_registry::{async_block#0}::{closure#0}::{async_block_env#0}>>> @ 0x00007ff7be096650, cx=0x00007ff7be098970) at mod.rs:518:17
    frame #18: 0x0000000101ed5c01 pacquet`futures_util::stream::stream::StreamExt::poll_next_unpin::hc09dfe6a154413a8(self=0x0000600002ab8778, cx=0x00007ff7be098970) at mod.rs:1632:9
    frame #19: 0x0000000101eff183 pacquet`_$LT$futures_util..stream..futures_ordered..FuturesOrdered$LT$Fut$GT$$u20$as$u20$futures_core..stream..Stream$GT$::poll_next::hb951f6867c98c605(self=Pin<&mut futures_util::stream::futures_ordered::FuturesOrdered<pacquet_package_manager::install_without_lockfile::{impl#1}::install_dependencies_from_registry::{async_block#0}::{closure#0}::{async_block_env#0}>> @ 0x00007ff7be096868, cx=0x00007ff7be098970) at futures_ordered.rs:190:26
    frame #20: 0x0000000101f29604 pacquet`_$LT$futures_util..stream..stream..collect..Collect$LT$St$C$C$GT$$u20$as$u20$core..future..future..Future$GT$::poll::hb5fafae2ec03e571(self=Pin<&mut futures_util::stream::stream::collect::Collect<futures_util::stream::futures_ordered::FuturesOrdered<pacquet_package_manager::install_without_lockfile::{impl#1}::install_dependencies_from_registry::{async_block#0}::{closure#0}::{async_block_env#0}>, alloc::vec::Vec<(), alloc::alloc::Global>>> @ 0x00007ff7be096918, cx=0x00007ff7be098970) at collect.rs:50:26
    frame #21: 0x0000000101ef7657 pacquet`_$LT$futures_util..future..join_all..JoinAll$LT$F$GT$$u20$as$u20$core..future..future..Future$GT$::poll::h039afb5b7efc154e(self=Pin<&mut futures_util::future::join_all::JoinAll<pacquet_package_manager::install_without_lockfile::{impl#1}::install_dependencies_from_registry::{async_block#0}::{closure#0}::{async_block_env#0}>> @ 0x00007ff7be096a20, cx=0x00007ff7be098970) at join_all.rs:157:41
    frame #22: 0x0000000101f2822e pacquet`pacquet_package_manager::install_without_lockfile::InstallWithoutLockfile$LT$$LP$$RP$$GT$::install_dependencies_from_registry::_$u7b$$u7b$closure$u7d$$u7d$::hbffb66c18bd4a4e7((null)=0x00007ff7be098970) at install_without_lockfile.rs:105:14
    frame #23: 0x0000000101ed6f20 pacquet`_$LT$core..pin..Pin$LT$P$GT$$u20$as$u20$core..future..future..Future$GT$::poll::h59adedcf45602e2c(self=Pin<&mut core::pin::Pin<alloc::boxed::Box<(dyn core::future::future::Future<Output=()> + core::marker::Send), alloc::alloc::Global>>> @ 0x00007ff7be0975f8, cx=0x00007ff7be098970) at future.rs:125:9
    frame #24: 0x0000000101ea906d pacquet`pacquet_package_manager::install_without_lockfile::InstallWithoutLockfile$LT$DependencyGroupList$GT$::run::_$u7b$$u7b$closure$u7d$$u7d$::_$u7b$$u7b$closure$u7d$$u7d$::_$u7b$$u7b$closure$u7d$$u7d$::h764f14b1de4dc53d((null)=0x00007ff7be098970) at install_without_lockfile.rs:67:18
    frame #25: 0x0000000101ea24ad pacquet`_$LT$futures_util..stream..futures_ordered..OrderWrapper$LT$T$GT$$u20$as$u20$core..future..future..Future$GT$::poll::h15ec92cc022ac7e1(self=Pin<&mut futures_util::stream::futures_ordered::OrderWrapper<pacquet_package_manager::install_without_lockfile::{impl#0}::run::{async_fn#0}::{closure#0}::{async_block_env#0}<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::sources::empty::Empty<pacquet_package_manifest::DependencyGroup>, core::option::IntoIter<pacquet_package_manifest::DependencyGroup>>, core::option::IntoIter<pacquet_package_manifest::DependencyGroup>>, core::option::IntoIter<pacquet_package_manifest::DependencyGroup>>>>> @ 0x00007ff7be098730, cx=0x00007ff7be098970) at futures_ordered.rs:55:9
    frame #26: 0x0000000101e74515 pacquet`_$LT$futures_util..stream..futures_unordered..FuturesUnordered$LT$Fut$GT$$u20$as$u20$futures_core..stream..Stream$GT$::poll_next::h1be25d9d3cf19b96(self=Pin<&mut futures_util::stream::futures_unordered::FuturesUnordered<futures_util::stream::futures_ordered::OrderWrapper<pacquet_package_manager::install_without_lockfile::{impl#0}::run::{async_fn#0}::{closure#0}::{async_block_env#0}<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::sources::empty::Empty<pacquet_package_manifest::DependencyGroup>, core::option::IntoIter<pacquet_package_manifest::DependencyGroup>>, core::option::IntoIter<pacquet_package_manifest::DependencyGroup>>, core::option::IntoIter<pacquet_package_manifest::DependencyGroup>>>>>> @ 0x00007ff7be098870, cx=0x00007ff7be0a07e8) at mod.rs:518:17
    frame #27: 0x0000000101e7a6f1 pacquet`futures_util::stream::stream::StreamExt::poll_next_unpin::h66befaa29111ca72(self=0x00007ff7be0a0b60, cx=0x00007ff7be0a07e8) at mod.rs:1632:9
    frame #28: 0x0000000101ea27b3 pacquet`_$LT$futures_util..stream..futures_ordered..FuturesOrdered$LT$Fut$GT$$u20$as$u20$futures_core..stream..Stream$GT$::poll_next::hb7e87eab8b6cc693(self=Pin<&mut futures_util::stream::futures_ordered::FuturesOrdered<pacquet_package_manager::install_without_lockfile::{impl#0}::run::{async_fn#0}::{closure#0}::{async_block_env#0}<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::sources::empty::Empty<pacquet_package_manifest::DependencyGroup>, core::option::IntoIter<pacquet_package_manifest::DependencyGroup>>, core::option::IntoIter<pacquet_package_manifest::DependencyGroup>>, core::option::IntoIter<pacquet_package_manifest::DependencyGroup>>>>> @ 0x00007ff7be098a88, cx=0x00007ff7be0a07e8) at futures_ordered.rs:190:26
    frame #29: 0x0000000101e97804 pacquet`_$LT$futures_util..stream..stream..collect..Collect$LT$St$C$C$GT$$u20$as$u20$core..future..future..Future$GT$::poll::h475c0329ed622f55(self=Pin<&mut futures_util::stream::stream::collect::Collect<futures_util::stream::futures_ordered::FuturesOrdered<pacquet_package_manager::install_without_lockfile::{impl#0}::run::{async_fn#0}::{closure#0}::{async_block_env#0}<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::sources::empty::Empty<pacquet_package_manifest::DependencyGroup>, core::option::IntoIter<pacquet_package_manifest::DependencyGroup>>, core::option::IntoIter<pacquet_package_manifest::DependencyGroup>>, core::option::IntoIter<pacquet_package_manifest::DependencyGroup>>>>, alloc::vec::Vec<(), alloc::alloc::Global>>> @ 0x00007ff7be098b38, cx=0x00007ff7be0a07e8) at collect.rs:50:26
    frame #30: 0x0000000101e5f347 pacquet`_$LT$futures_util..future..join_all..JoinAll$LT$F$GT$$u20$as$u20$core..future..future..Future$GT$::poll::h2004fdfddbbd37f7(self=Pin<&mut futures_util::future::join_all::JoinAll<pacquet_package_manager::install_without_lockfile::{impl#0}::run::{async_fn#0}::{closure#0}::{async_block_env#0}<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::sources::empty::Empty<pacquet_package_manifest::DependencyGroup>, core::option::IntoIter<pacquet_package_manifest::DependencyGroup>>, core::option::IntoIter<pacquet_package_manifest::DependencyGroup>>, core::option::IntoIter<pacquet_package_manifest::DependencyGroup>>>>> @ 0x00007ff7be098c40, cx=0x00007ff7be0a07e8) at join_all.rs:157:41
    frame #31: 0x0000000101ea8278 pacquet`pacquet_package_manager::install_without_lockfile::InstallWithoutLockfile$LT$DependencyGroupList$GT$::run::_$u7b$$u7b$closure$u7d$$u7d$::h5279e414d3ac9c8f((null)=0x00007ff7be0a07e8) at install_without_lockfile.rs:70:14
    frame #32: 0x0000000101e5d52c pacquet`pacquet_package_manager::install::Install$LT$DependencyGroupList$GT$::run::_$u7b$$u7b$closure$u7d$$u7d$::hdd263e747923347f((null)=0x00007ff7be0a07e8) at install.rs:51:18
    frame #33: 0x0000000101e5dffd pacquet`pacquet_cli::cli_args::install::InstallArgs::run::_$u7b$$u7b$closure$u7d$$u7d$::h1d5e5bc4af22f316((null)=0x00007ff7be0a07e8) at install.rs:65:10
    frame #34: 0x0000000101e611cc pacquet`pacquet_cli::cli_args::CliArgs::run::_$u7b$$u7b$closure$u7d$$u7d$::he0259bf7ff7d4fdb((null)=0x00007ff7be0a07e8) at cli_args.rs:65:61
    frame #35: 0x0000000101e822d6 pacquet`pacquet_cli::main::_$u7b$$u7b$closure$u7d$$u7d$::h72ed04d395be81e4((null)=0x00007ff7be0a07e8) at lib.rs:13:28
    frame #36: 0x0000000101e5b8a3 pacquet`pacquet::main::_$u7b$$u7b$closure$u7d$$u7d$::h5b27071a787da554((null)=0x00007ff7be0a07e8) at main.rs:3:25
    frame #37: 0x0000000101e83002 pacquet`tokio::runtime::park::CachedParkThread::block_on::_$u7b$$u7b$closure$u7d$$u7d$::hddb7a5e4f7256cf4 at park.rs:283:63
    frame #38: 0x0000000101e82e31 pacquet`tokio::runtime::park::CachedParkThread::block_on::h5ffbb6a446bf7df4 at coop.rs:107:5
    frame #39: 0x0000000101e82dc7 pacquet`tokio::runtime::park::CachedParkThread::block_on::h5ffbb6a446bf7df4 [inlined] tokio::runtime::coop::budget::heca54b564cf92ee2(f={closure_env#0}<pacquet::main::{async_block_env#0}> @ 0x00007ff7be0a1548) at coop.rs:73:5
    frame #40: 0x0000000101e82d43 pacquet`tokio::runtime::park::CachedParkThread::block_on::h5ffbb6a446bf7df4(self=0x00007ff7be0a15df, f={async_block_env#0} @ 0x00007ff7be0a15e0) at park.rs:283:31
    frame #41: 0x0000000101e7a8c1 pacquet`tokio::runtime::context::blocking::BlockingRegionGuard::block_on::h8c9921ac00e5e534(self=0x00007ff7be0a3048, f={async_block_env#0} @ 0x00007ff7be0a22f8) at blocking.rs:66:9
    frame #42: 0x0000000101e801f0 pacquet`tokio::runtime::scheduler::multi_thread::MultiThread::block_on::_$u7b$$u7b$closure$u7d$$u7d$::h1e04f13f5ef259a1(blocking=0x00007ff7be0a3048) at mod.rs:87:13
    frame #43: 0x0000000101e98a64 pacquet`tokio::runtime::context::runtime::enter_runtime::h633aa6f4b970d737(handle=0x00007ff7be0a7268, allow_block_in_place=true, f={closure_env#0}<pacquet::main::{async_block_env#0}> @ 0x00007ff7be0a3dc0) at runtime.rs:65:16
    frame #44: 0x0000000101e8019b pacquet`tokio::runtime::scheduler::multi_thread::MultiThread::block_on::h840ca0aa5089a8b0(self=0x00007ff7be0a7240, handle=0x00007ff7be0a7268, future=<unavailable>) at mod.rs:86:9
    frame #45: 0x0000000101e7fcde pacquet`tokio::runtime::runtime::Runtime::block_on::hef52f1f93b1039a7(self=0x00007ff7be0a7238, future={async_block_env#0} @ 0x00007ff7be0a7398) at runtime.rs:313:45
    frame #46: 0x0000000101e9e47f pacquet`pacquet::main::h75bb93d8b2c5adcc at main.rs:3:5
    frame #47: 0x0000000101e6db6e pacquet`core::ops::function::FnOnce::call_once::hc6ed0eaeaead1dbf((null)=(pacquet`pacquet::main::h75bb93d8b2c5adcc at main.rs:2), (null)=<unavailable>) at function.rs:250:5
    frame #48: 0x0000000101e7df91 pacquet`std::sys_common::backtrace::__rust_begin_short_backtrace::heeac9e61e07c83b4(f=(pacquet`pacquet::main::h75bb93d8b2c5adcc at main.rs:2)) at backtrace.rs:154:18
    frame #49: 0x0000000101e9e364 pacquet`std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::h85e885c88739b978 at rt.rs:166:18
    frame #50: 0x0000000102ac5a4a pacquet`std::rt::lang_start_internal::h54faea1e36783632 [inlined] core::ops::function::impls::_$LT$impl$u20$core..ops..function..FnOnce$LT$A$GT$$u20$for$u20$$RF$F$GT$::call_once::hcfff0e1d84ed81c5 at function.rs:284:13 [opt]
    frame #51: 0x0000000102ac5a3d pacquet`std::rt::lang_start_internal::h54faea1e36783632 [inlined] std::panicking::try::do_call::hbabf83ee9c686a7b at panicking.rs:502:40 [opt]
    frame #52: 0x0000000102ac5a3d pacquet`std::rt::lang_start_internal::h54faea1e36783632 [inlined] std::panicking::try::he3e9a1c93c50f591 at panicking.rs:466:19 [opt]
    frame #53: 0x0000000102ac5a3d pacquet`std::rt::lang_start_internal::h54faea1e36783632 [inlined] std::panic::catch_unwind::ha18733e497b82774 at panic.rs:142:14 [opt]
    frame #54: 0x0000000102ac5a3d pacquet`std::rt::lang_start_internal::h54faea1e36783632 [inlined] std::rt::lang_start_internal::_$u7b$$u7b$closure$u7d$$u7d$::hfb6977160fe64fc0 at rt.rs:148:48 [opt]
    frame #55: 0x0000000102ac5a3d pacquet`std::rt::lang_start_internal::h54faea1e36783632 [inlined] std::panicking::try::do_call::h385fcb260f1f324b at panicking.rs:502:40 [opt]
    frame #56: 0x0000000102ac5a3d pacquet`std::rt::lang_start_internal::h54faea1e36783632 [inlined] std::panicking::try::h3734e87bdbb1b067 at panicking.rs:466:19 [opt]
    frame #57: 0x0000000102ac5a3d pacquet`std::rt::lang_start_internal::h54faea1e36783632 [inlined] std::panic::catch_unwind::hc13dbc187cd64fe1 at panic.rs:142:14 [opt]
    frame #58: 0x0000000102ac5a3d pacquet`std::rt::lang_start_internal::h54faea1e36783632 at rt.rs:148:20 [opt]
    frame #59: 0x0000000101e9e337 pacquet`std::rt::lang_start::hd05a88e7ef5041fc(main=(pacquet`pacquet::main::h75bb93d8b2c5adcc at main.rs:2), argc=2, argv=0x00007ff7be0a84d0, sigpipe='\0') at rt.rs:165:17
    frame #60: 0x0000000101e9e518 pacquet`main + 24
    frame #61: 0x00007ff80c44941f dyld`start + 1903

It looks like dashmap doesn't recommend keeping references across .await, which should also be the cause of the deadlock here, if I understand correctly.

Since I'm new to Rust, I'm not sure if there's a better way to solve this problem, I tried replacing the dashmap with RwLock like in this PR and it seems to work fine.

Copy link
Member

@anonrig anonrig left a comment

Choose a reason for hiding this comment

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

Can you add a test?

@await-ovo
Copy link
Member Author

Can you add a test?

Yes, I'll try to add the related test ~

eprintln!("Creating package.json...");
let manifest_path = workspace.join("package.json");
let package_json_content = serde_json::json!({
"dependencies": {
Copy link
Member Author

Choose a reason for hiding this comment

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

Before rebase the branch main, i.e. without mock-registry, the test passed, but now it doesn't seem to be able to install express, so it will take a bit more time to see what's going on.

crates/cli/src/state.rs Outdated Show resolved Hide resolved
@KSXGitHub
Copy link
Contributor

I'm not sure how this will impact the performance of using pacquet without lockfile because the current algorithm in its current state is very bad. See: #133, #134.

@@ -88,7 +87,7 @@ pub enum CacheValue {
/// Internal in-memory cache of tarballs.
///
/// The key of this hashmap is the url of each tarball.
pub type MemCache = DashMap<String, Arc<RwLock<CacheValue>>>;
pub type MemCache = RwLock<HashMap<String, Arc<RwLock<CacheValue>>>>;
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if MemoMap can be sent across async? Since the cache is growth only.

Copy link
Member Author

@await-ovo await-ovo Nov 20, 2023

Choose a reason for hiding this comment

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

Looks like it is perfect for our scene. I just tried memo-map on this branch, and it works well.

I've also tried integrated-benchmark on the branch main, fix-mem-cache-deadlock, and refactor-use-memo-map, here is the result on my local machine:

  • fronzen-lockfile
$ just integrated-benchmark  fix-mem-cache-deadlock refactor-use-memo-map main -s=frozen-lockfile

Benchmark 1: pacquet@fix-mem-cache-deadlock
  Time (mean ± σ):     532.3 ms ± 189.3 ms    [User: 99.6 ms, System: 729.0 ms]
  Range (min … max):   390.8 ms … 1049.7 ms    10 runs

  Warning: The first benchmarking run for this command was significantly slower than the rest (1.050 s). This could be caused by (filesystem) caches that were not filled until after the first run. You are already using both the '--warmup' option as well as the '--prepare' option. Consider re-running the benchmark on a quiet system. Maybe it was a random outlier. Alternatively, consider increasing the warmup count.

Benchmark 2: pacquet@refactor-use-memo-map
  Time (mean ± σ):     517.7 ms ± 104.7 ms    [User: 110.5 ms, System: 764.0 ms]
  Range (min … max):   412.1 ms … 707.7 ms    10 runs

Benchmark 3: pacquet@main
  Time (mean ± σ):     517.9 ms ±  95.5 ms    [User: 113.1 ms, System: 801.1 ms]
  Range (min … max):   410.9 ms … 712.6 ms    10 runs

Summary
  pacquet@refactor-use-memo-map ran
    1.00 ± 0.27 times faster than pacquet@main
    1.03 ± 0.42 times faster than pacquet@fix-mem-cache-deadlock
  • clean-install
$ just integrated-benchmark  fix-mem-cache-deadlock refactor-use-memo-map main -s=clean-install

Benchmark 1: pacquet@fix-mem-cache-deadlock
  Time (mean ± σ):      7.350 s ±  0.156 s    [User: 0.587 s, System: 0.909 s]
  Range (min … max):    7.092 s …  7.603 s    10 runs

Benchmark 2: pacquet@refactor-use-memo-map
  Time (mean ± σ):      7.124 s ±  0.849 s    [User: 0.521 s, System: 0.868 s]
  Range (min … max):    6.713 s …  9.532 s    10 runs

  Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs.

Benchmark 3: pacquet@main
 ⠦ Initial time measurement       ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ETA 00:00:00^C%
$ just integrated-benchmark  fix-mem-cache-deadlock refactor-use-memo-map  -s=clean-install
Building "refactor-use-memo-map"...
    Finished release [optimized] target(s) in 0.57s
Benchmark 1: pacquet@fix-mem-cache-deadlock
  Time (mean ± σ):      7.400 s ±  0.157 s    [User: 0.578 s, System: 0.936 s]
  Range (min … max):    7.207 s …  7.761 s    10 runs

Benchmark 2: pacquet@refactor-use-memo-map
  Time (mean ± σ):      7.706 s ±  1.574 s    [User: 0.544 s, System: 0.910 s]
  Range (min … max):    6.906 s … 12.145 s    10 runs

  Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs.

Summary
  pacquet@fix-mem-cache-deadlock ran
    1.04 ± 0.21 times faster than pacquet@refactor-use-memo-map

It seems that integrated-benchmark on the branch main will get a deadlock currently, so there's no comparison to the main branch.

Overall, thanks for your suggestion, it would be better to use memo-map, If there's no problem on your end, I think we can just use it ~ I don't know if we should use memo-map here, it looks like RwLock for clean-install would be a little better?

Copy link
Contributor

Choose a reason for hiding this comment

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

Frozen lockfile doesn't use memory cache so it's irrelevant (It invokes run_without_mem_cache).

I don't know if we should use memo-map here, it looks like RwLock for clean-install would be a little better?

The integrated-benchmark script has a --fixture-dir/-D option, you may use it to specify a bigger package.json file.

Copy link
Member Author

Choose a reason for hiding this comment

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

for this package.json:

{
  "dependencies": {
    "nanoid": "^3.3.6",
    "picocolors": "^1.0.0",
    "source-map-js": "^1.0.2"
  },
  "devDependencies": {
    "@size-limit/preset-small-lib": "^9.0.0",
    "@types/node": "^20.8.3",
    "c8": "^8.0.1",
    "check-dts": "^0.7.2",
    "clean-publish": "^4.2.0",
    "concat-with-sourcemaps": "^1.1.0",
    "nanodelay": "^1.0.8",
    "nanospy": "^1.0.0",
    "postcss-parser-tests": "^8.8.0",
    "simple-git-hooks": "^2.9.0",
    "size-limit": "^9.0.0",
    "strip-ansi": "^6.0.1",
    "ts-node": "^10.9.1",
    "typescript": "^5.2.2",
    "uvu": "^0.5.6"
  }
}

Run just integrated-benchmark fix-mem-cache-deadlock refactor-use-memo-map -s=clean-install -D=/Users/await-ovo/Documents/test/test-pnpm/alotta-modules show that:

List of branches:
Building "refactor-use-memo-map"...
    Finished release [optimized] target(s) in 0.47s
Benchmark 1: pacquet@fix-mem-cache-deadlock
  Time (mean ± σ):      3.943 s ±  0.205 s    [User: 3.193 s, System: 2.717 s]
  Range (min … max):    3.618 s …  4.192 s    10 runs

Benchmark 2: pacquet@refactor-use-memo-map
  Time (mean ± σ):      4.041 s ±  0.184 s    [User: 3.328 s, System: 2.843 s]
  Range (min … max):    3.818 s …  4.355 s    10 runs

Summary
  pacquet@fix-mem-cache-deadlock ran
    1.02 ± 0.07 times faster than pacquet@refactor-use-memo-map

Copy link
Member Author

Choose a reason for hiding this comment

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

I want to use this package.json to do a benchmark, but there will be a Too many open files error during install.

Copy link
Contributor

Choose a reason for hiding this comment

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

Try a smaller one, for example:

{
  "dependencies": {
    "@babel/core": "^7.23.2",
    "@tsfun/all": "0.0.37",
    "@types/node": "16.18.39",
    "cross-env": "7.0.3",
    "glob-parent": "6.0.2",
    "husky": "8.0.3",
    "jest": "29.7.0",
    "json5": "2.2.3",
    "jsonwebtoken": "9.0.2",
    "keyv": "4.5.3",
    "react": "18.2.0",
    "rimraf": "3.0.2",
    "semver": "7.5.4",
    "shx": "0.3.4",
    "ts-jest": "29.1.1",
    "ts-node": "10.9.1",
    "typescript": "5.2.2",
    "verdaccio": "5.27.0",
    "yaml": "2.3.4"
  }
}

Copy link
Member Author

Choose a reason for hiding this comment

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

Unfortunately, this will get an error:

image

Maybe we should test the benchmark with a bigger repository after this is resolved.

Copy link
Contributor

Choose a reason for hiding this comment

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

Can you try combine your branches with #210 into 2 new branches and see if the "too many open files" error still exist? If the error disappear, can you try benchmark them?

Copy link
Member Author

Choose a reason for hiding this comment

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

I tried, but I still can't get the results of integrated-benchmark, it seems to be because of a circular dependency in alotta-files?

Copy link
Contributor

Choose a reason for hiding this comment

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

@zkochan It seems pacquet can't yet handle circular dependencies (without lockfile). Can you tell us which is the circular dependencies to remove?

Also, @await-ovo, another PR was just merged, you should pull from upstream or rebase.

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.

3 participants