I got an deadlock on index building using python bindings on pytest.
This reproduced only with specific test order (that's wired).
I can't share full tests (sorry for that), but can mention important parts
Granne version: 0.5.2
Python version: 3.8
Code called in both tests looks like
import granne
index_builder = granne.GranneBuilder('angular', 500)
for v in vectors: # no matters how much `vectors` or dimensions
index_builder.append(v)
index_builder.build() # < - deadlock happens here
I traced them using py-spy
and got stack that looks like
Thread 73895 (idle): "MainThread"
pthread_cond_wait@@GLIBC_2.3.2 (libpthread-2.31.so)
core::sync::atomic::atomic_load::h40d363a33a87228c (atomic.rs:2353)
core::sync::atomic::AtomicBool::load::h98755e393c876abe (atomic.rs:378)
std::sys_common::poison::Flag::get::hf277343eec2966e7 (poison.rs:44)
std::sync::condvar::Condvar::wait::h14c20325128edf7e (condvar.rs:189)
rayon_core::latch::LockLatch::wait_and_reset::h1c8244bf740f09b9 (latch.rs:240)
rayon_core::registry::Registry::in_worker_cold::_$u7b$$u7b$closure$u7d$$u7d$::hc01231cc1f5776b3 (registry.rs:475)
std::thread::local::LocalKey$LT$T$GT$::try_with::hcb9dc379c39268fa (local.rs:272)
std::thread::local::LocalKey$LT$T$GT$::with::h340944f8b882cf1f (local.rs:248)
rayon_core::registry::Registry::in_worker_cold::hd65bc2a269d982ed (registry.rs:458)
rayon_core::registry::in_worker::ha625d863b1ab5202 (registry.rs:877)
rayon::iter::plumbing::bridge_producer_consumer::helper::h161e56cd8915cee0 (mod.rs:436)
_$LT$$LT$rayon..iter..skip..Skip$LT$I$GT$$u20$as$u20$rayon..iter..IndexedParallelIterator$GT$..with_producer..Callback$LT$CB$GT$$u20$as$u20$rayon..iter..plumbing..ProducerCallback$LT$T$GT$$GT$::callback::hbff8b682fd113b73 (skip.rs:85)
_$LT$$LT$rayon..iter..enumerate..Enumerate$LT$I$GT$$u20$as$u20$rayon..iter..IndexedParallelIterator$GT$..with_producer..Callback$LT$CB$GT$$u20$as$u20$rayon..iter..plumbing..ProducerCallback$LT$I$GT$$GT$::callback::h12880f40ae46697b (enumerate.rs:79)
_$LT$alloc..raw_vec..RawVec$LT$T$C$A$GT$$u20$as$u20$core..ops..drop..Drop$GT$::drop::h3a55feac6c8e7771 (raw_vec.rs:498)
core::ptr::drop_in_place$LT$alloc..raw_vec..RawVec$LT$lock_api..rwlock..RwLock$LT$parking_lot..raw_rwlock..RawRwLock$C$$RF$mut$u20$$u5b$u32$u5d$$GT$$GT$$GT$::hc1e4faf2b4194c14 (mod.rs:179)
core::ptr::drop_in_place$LT$alloc..vec..Vec$LT$lock_api..rwlock..RwLock$LT$parking_lot..raw_rwlock..RawRwLock$C$$RF$mut$u20$$u5b$u32$u5d$$GT$$GT$$GT$::hb58aa88a82306982 (mod.rs:179)
granne::index::GranneBuilder$LT$Elements$GT$::index_elements::h00507be69e0b3db2 (mod.rs:783)
granne::index::GranneBuilder$LT$Elements$GT$::index_elements_in_last_layer::h0c3bc587b9a5cb50 (mod.rs:693)
_$LT$granne..index..GranneBuilder$LT$Elements$GT$$u20$as$u20$granne..index..Builder$GT$::build_partial::hd77479376bbc9da5 (mod.rs:392)
granne::GranneBuilder::build::ha4747e7418026a87 (lib.rs)
granne::GranneBuilder::create_instance::init::wrap_instance_method::_$u7b$$u7b$closure$u7d$$u7d$::h5afe2b0665ab803c (members.rs:99)
cpython::function::handle_callback::_$u7b$$u7b$closure$u7d$$u7d$::h403681d837d8438a (function.rs:218)
std::panicking::try::do_call::h62939ca7a79bd0c1 (panicking.rs:379)
std::panicking::try::h38c9f96318d0de5c (panicking.rs:343)
std::panic::catch_unwind::h814cfa00d891a4c7 (panic.rs:431)
cpython::function::handle_callback::hc27b96a79fdcc7de (function.rs:215)
granne::GranneBuilder::create_instance::init::wrap_instance_method::hcadb94cd6edba93c (members.rs:103)
...
<..... HIDDEN ........>
...
_process_worker (concurrent/futures/process.py:239)
run (multiprocessing/process.py:108)
_bootstrap (multiprocessing/process.py:315)
_launch (multiprocessing/popen_fork.py:75)
__init__ (multiprocessing/popen_fork.py:19)
_Popen (multiprocessing/context.py:277)
start (multiprocessing/process.py:121)
_adjust_process_count (concurrent/futures/process.py:608)
_start_queue_management_thread (concurrent/futures/process.py:584)
submit (concurrent/futures/process.py:645)
...
<..... HIDDEN ........>
...
call_fixture_func (_pytest/fixtures.py:791)
pytest_fixture_setup (_pytest/fixtures.py:936)
_multicall (pluggy/callers.py:187)
<lambda> (pluggy/manager.py:84)
_hookexec (pluggy/manager.py:93)
__call__ (pluggy/hooks.py:286)
execute (_pytest/fixtures.py:894)
_compute_fixture_value (_pytest/fixtures.py:587)
_get_active_fixturedef (_pytest/fixtures.py:502)
getfixturevalue (_pytest/fixtures.py:479)
_fillfixtures (_pytest/fixtures.py:469)
fillfixtures (_pytest/fixtures.py:296)
setup (_pytest/python.py:1468)
prepare (_pytest/runner.py:362)
pytest_runtest_setup (_pytest/runner.py:116)
_multicall (pluggy/callers.py:187)
<lambda> (pluggy/manager.py:84)
_hookexec (pluggy/manager.py:93)
__call__ (pluggy/hooks.py:286)
<lambda> (_pytest/runner.py:198)
from_call (_pytest/runner.py:226)
call_runtest_hook (_pytest/runner.py:197)
call_and_report (_pytest/runner.py:173)
runtestprotocol (_pytest/runner.py:87)
pytest_runtest_protocol (_pytest/runner.py:78)
_multicall (pluggy/callers.py:187)
<lambda> (pluggy/manager.py:84)
_hookexec (pluggy/manager.py:93)
__call__ (pluggy/hooks.py:286)
pytest_runtestloop (_pytest/main.py:271)
_multicall (pluggy/callers.py:187)
<lambda> (pluggy/manager.py:84)
_hookexec (pluggy/manager.py:93)
__call__ (pluggy/hooks.py:286)
_main (_pytest/main.py:250)
wrap_session (_pytest/main.py:206)
pytest_cmdline_main (_pytest/main.py:243)
_multicall (pluggy/callers.py:187)
<lambda> (pluggy/manager.py:84)
_hookexec (pluggy/manager.py:93)
__call__ (pluggy/hooks.py:286)
main (_pytest/config/__init__.py:82)
<module> (pytest:8)
Deadlock related to https://github.com/granne/granne/blob/fe2fe5aca4be879be8cbaf4fc34a5abf6ed2593d/src/index/mod.rs#L774 par_iter
call (not itself call, but rayon
usage) and most probably related to https://github.com/rayon-rs/rayon/issues/592.
After I set default = ["singlethreaded"]
in https://github.com/granne/granne/blob/master/Cargo.toml#L26, deadlock goes away
Unfortunately, I can't provide fully reproducible code sample for that, but will be glad to answer to any question.