@@ -22,7 +22,7 @@ use serde::{Deserialize, Serialize};
2222use std:: {
2323 collections:: HashMap ,
2424 path:: { Path , PathBuf } ,
25- sync:: { Arc , Mutex } ,
25+ sync:: { Arc , RwLock } ,
2626 thread,
2727} ;
2828use telemetry:: { get_conda_rcs_and_env_dirs, report_missing_envs} ;
@@ -61,24 +61,24 @@ pub struct CondaTelemetryInfo {
6161}
6262
6363pub struct Conda {
64- pub environments : Arc < Mutex < HashMap < PathBuf , PythonEnvironment > > > ,
65- pub managers : Arc < Mutex < HashMap < PathBuf , CondaManager > > > ,
64+ pub environments : Arc < RwLock < HashMap < PathBuf , PythonEnvironment > > > ,
65+ pub managers : Arc < RwLock < HashMap < PathBuf , CondaManager > > > ,
6666 pub env_vars : EnvVariables ,
67- conda_executable : Arc < Mutex < Option < PathBuf > > > ,
67+ conda_executable : Arc < RwLock < Option < PathBuf > > > ,
6868}
6969
7070impl Conda {
7171 pub fn from ( env : & dyn Environment ) -> Conda {
7272 Conda {
73- environments : Arc :: new ( Mutex :: new ( HashMap :: new ( ) ) ) ,
74- managers : Arc :: new ( Mutex :: new ( HashMap :: new ( ) ) ) ,
73+ environments : Arc :: new ( RwLock :: new ( HashMap :: new ( ) ) ) ,
74+ managers : Arc :: new ( RwLock :: new ( HashMap :: new ( ) ) ) ,
7575 env_vars : EnvVariables :: from ( env) ,
76- conda_executable : Arc :: new ( Mutex :: new ( None ) ) ,
76+ conda_executable : Arc :: new ( RwLock :: new ( None ) ) ,
7777 }
7878 }
7979 fn clear ( & self ) {
80- self . environments . lock ( ) . unwrap ( ) . clear ( ) ;
81- self . managers . lock ( ) . unwrap ( ) . clear ( ) ;
80+ self . environments . write ( ) . unwrap ( ) . clear ( ) ;
81+ self . managers . write ( ) . unwrap ( ) . clear ( ) ;
8282 }
8383}
8484
@@ -91,7 +91,7 @@ impl CondaLocator for Conda {
9191 // Look for environments that we couldn't find without spawning conda.
9292 let user_provided_conda_exe = conda_executable. is_some ( ) ;
9393 let conda_info = CondaInfo :: from ( conda_executable) ?;
94- let environments = self . environments . lock ( ) . unwrap ( ) . clone ( ) ;
94+ let environments = self . environments . read ( ) . unwrap ( ) . clone ( ) ;
9595 let new_envs = conda_info
9696 . envs
9797 . clone ( )
@@ -119,7 +119,7 @@ impl CondaLocator for Conda {
119119
120120 fn get_info_for_telemetry ( & self , conda_executable : Option < PathBuf > ) -> CondaTelemetryInfo {
121121 let can_spawn_conda = CondaInfo :: from ( conda_executable) . is_some ( ) ;
122- let environments = self . environments . lock ( ) . unwrap ( ) . clone ( ) ;
122+ let environments = self . environments . read ( ) . unwrap ( ) . clone ( ) ;
123123 let environments = environments
124124 . into_values ( )
125125 . collect :: < Vec < PythonEnvironment > > ( ) ;
@@ -132,7 +132,7 @@ impl CondaLocator for Conda {
132132 environments_txt = Some ( file) ;
133133 }
134134
135- let conda_exe = & self . conda_executable . lock ( ) . unwrap ( ) . clone ( ) ;
135+ let conda_exe = & self . conda_executable . read ( ) . unwrap ( ) . clone ( ) ;
136136 let envs_found = get_conda_environment_paths ( & self . env_vars , conda_exe) ;
137137 let mut user_provided_env_found = None ;
138138 if let Some ( conda_dir) = get_conda_dir_from_exe ( conda_exe) {
@@ -159,7 +159,7 @@ impl CondaLocator for Conda {
159159 if let Some ( conda_dir) = manager. conda_dir . clone ( ) {
160160 // Keep track to search again later.
161161 // Possible we'll find environments in other directories created using this manager
162- let mut managers = self . managers . lock ( ) . unwrap ( ) ;
162+ let mut managers = self . managers . write ( ) . unwrap ( ) ;
163163 // Keep track to search again later.
164164 // Possible we'll find environments in other directories created using this manager
165165 managers. insert ( conda_dir. clone ( ) , manager. clone ( ) ) ;
@@ -170,7 +170,7 @@ impl CondaLocator for Conda {
170170 get_conda_environments ( & get_environments ( & conda_dir) , & manager. clone ( ) . into ( ) )
171171 {
172172 // If reported earlier, no point processing this again.
173- let mut environments = self . environments . lock ( ) . unwrap ( ) ;
173+ let mut environments = self . environments . write ( ) . unwrap ( ) ;
174174 if environments. contains_key ( & conda_env. prefix ) {
175175 continue ;
176176 }
@@ -194,13 +194,17 @@ impl CondaLocator for Conda {
194194
195195impl Conda {
196196 fn get_manager ( & self , conda_dir : & Path ) -> Option < CondaManager > {
197- let mut managers = self . managers . lock ( ) . unwrap ( ) ;
198- // If we have a conda install folder, then use that to get the manager.
199- if let Some ( mgr) = managers. get ( conda_dir) {
200- return Some ( mgr. clone ( ) ) ;
197+ // First try to read from cache
198+ {
199+ let managers = self . managers . read ( ) . unwrap ( ) ;
200+ if let Some ( mgr) = managers. get ( conda_dir) {
201+ return Some ( mgr. clone ( ) ) ;
202+ }
201203 }
202204
205+ // If not found, acquire write lock and insert
203206 if let Some ( manager) = CondaManager :: from ( conda_dir) {
207+ let mut managers = self . managers . write ( ) . unwrap ( ) ;
204208 managers. insert ( conda_dir. into ( ) , manager. clone ( ) ) ;
205209 Some ( manager)
206210 } else {
@@ -215,7 +219,7 @@ impl Locator for Conda {
215219 }
216220 fn configure ( & self , config : & pet_core:: Configuration ) {
217221 if let Some ( ref conda_exe) = config. conda_executable {
218- let mut conda_executable = self . conda_executable . lock ( ) . unwrap ( ) ;
222+ let mut conda_executable = self . conda_executable . write ( ) . unwrap ( ) ;
219223 conda_executable. replace ( conda_exe. clone ( ) ) ;
220224 }
221225 }
@@ -246,16 +250,19 @@ impl Locator for Conda {
246250 return None ;
247251 }
248252
249- let mut environments = self . environments . lock ( ) . unwrap ( ) ;
250-
251- // Do we already have an env for this.
252- if let Some ( env) = environments. get ( path) {
253- return Some ( env. clone ( ) ) ;
253+ // First check cache with read lock
254+ {
255+ let environments = self . environments . read ( ) . unwrap ( ) ;
256+ if let Some ( env) = environments. get ( path) {
257+ return Some ( env. clone ( ) ) ;
258+ }
254259 }
260+ // Not in cache, build the environment and insert with write lock
255261 if let Some ( env) = get_conda_environment_info ( path, & None ) {
256262 if let Some ( conda_dir) = & env. conda_dir {
257263 if let Some ( manager) = self . get_manager ( conda_dir) {
258264 let env = env. to_python_environment ( Some ( manager. to_manager ( ) ) ) ;
265+ let mut environments = self . environments . write ( ) . unwrap ( ) ;
259266 environments. insert ( path. clone ( ) , env. clone ( ) ) ;
260267 return Some ( env) ;
261268 } else {
@@ -264,6 +271,7 @@ impl Locator for Conda {
264271 // The client can activate this env either using another conda manager or using the activation scripts
265272 error ! ( "Unable to find Conda Manager for env (even though we have a conda_dir): {:?}" , env) ;
266273 let env = env. to_python_environment ( None ) ;
274+ let mut environments = self . environments . write ( ) . unwrap ( ) ;
267275 environments. insert ( path. clone ( ) , env. clone ( ) ) ;
268276 return Some ( env) ;
269277 }
@@ -273,6 +281,7 @@ impl Locator for Conda {
273281 // The client can activate this env either using another conda manager or using the activation scripts
274282 error ! ( "Unable to find Conda Manager for env: {:?}" , env) ;
275283 let env = env. to_python_environment ( None ) ;
284+ let mut environments = self . environments . write ( ) . unwrap ( ) ;
276285 environments. insert ( path. clone ( ) , env. clone ( ) ) ;
277286 return Some ( env) ;
278287 }
@@ -286,7 +295,7 @@ impl Locator for Conda {
286295 self . clear ( ) ;
287296
288297 let env_vars = self . env_vars . clone ( ) ;
289- let executable = self . conda_executable . lock ( ) . unwrap ( ) . clone ( ) ;
298+ let executable = self . conda_executable . read ( ) . unwrap ( ) . clone ( ) ;
290299 thread:: scope ( |s| {
291300 // 1. Get a list of all know conda environments file paths
292301 let possible_conda_envs = get_conda_environment_paths ( & env_vars, & executable) ;
@@ -306,7 +315,7 @@ impl Locator for Conda {
306315 error ! ( "Unable to find Conda Manager for the Conda env: {:?}" , env) ;
307316 let prefix = env. prefix . clone ( ) ;
308317 let env = env. to_python_environment ( None ) ;
309- let mut environments = self . environments . lock ( ) . unwrap ( ) ;
318+ let mut environments = self . environments . write ( ) . unwrap ( ) ;
310319 environments. insert ( prefix, env. clone ( ) ) ;
311320 reporter. report_environment ( & env) ;
312321 return None ;
@@ -319,7 +328,7 @@ impl Locator for Conda {
319328 {
320329 // 3.1 Check if we have already reported this environment.
321330 // Closure to quickly release lock
322- let environments = self . environments . lock ( ) . unwrap ( ) ;
331+ let environments = self . environments . read ( ) . unwrap ( ) ;
323332 if environments. contains_key ( & env. prefix ) {
324333 return None ;
325334 }
@@ -328,14 +337,14 @@ impl Locator for Conda {
328337
329338 // 4 Get the manager for this env.
330339 let conda_dir = & env. conda_dir . clone ( ) ?;
331- let managers = self . managers . lock ( ) . unwrap ( ) ;
340+ let managers = self . managers . read ( ) . unwrap ( ) ;
332341 let mut manager = managers. get ( conda_dir) . cloned ( ) ;
333342 drop ( managers) ;
334343
335344 if manager. is_none ( ) {
336345 // 4.1 Build the manager from the conda dir if we do not have it.
337346 if let Some ( conda_manager) = CondaManager :: from ( conda_dir) {
338- let mut managers = self . managers . lock ( ) . unwrap ( ) ;
347+ let mut managers = self . managers . write ( ) . unwrap ( ) ;
339348 managers. insert ( conda_dir. to_path_buf ( ) . clone ( ) , conda_manager. clone ( ) ) ;
340349 manager = Some ( conda_manager) ;
341350 }
@@ -346,7 +355,7 @@ impl Locator for Conda {
346355 let env = env. to_python_environment (
347356 Some ( manager. to_manager ( ) ) ,
348357 ) ;
349- let mut environments = self . environments . lock ( ) . unwrap ( ) ;
358+ let mut environments = self . environments . write ( ) . unwrap ( ) ;
350359 environments. insert ( prefix. clone ( ) , env. clone ( ) ) ;
351360 reporter. report_manager ( & manager. to_manager ( ) ) ;
352361 reporter. report_environment ( & env) ;
@@ -356,7 +365,7 @@ impl Locator for Conda {
356365 // The client can activate this env either using another conda manager or using the activation scripts
357366 error ! ( "Unable to find Conda Manager for Conda env (even though we have a conda_dir {:?}): Env Details = {:?}" , conda_dir, env) ;
358367 let env = env. to_python_environment ( None ) ;
359- let mut environments = self . environments . lock ( ) . unwrap ( ) ;
368+ let mut environments = self . environments . write ( ) . unwrap ( ) ;
360369 environments. insert ( prefix. clone ( ) , env. clone ( ) ) ;
361370 reporter. report_environment ( & env) ;
362371 }
0 commit comments