Commit 1d30dd4
Refactor: Consolidate caching patterns into shared LocatorCache abstraction (#301)
- [x] Create a new `LocatorCache<K, V>` generic caching abstraction in
`pet-core`
- [x] Add `get()`, `get_or_insert_with()`, `insert()`, `contains_key()`,
`clear()`, `values()`, `len()`, `is_empty()`, and `clone_map()` methods
- [x] Create type aliases `EnvironmentCache` and `ManagerCache` for
common uses
- [x] Refactor `pet-conda` to use the new cache abstraction
- [x] Refactor `pet-linux-global-python` to use the new cache
abstraction
- [x] Run tests to verify the changes work correctly
- [x] Request code review
- [x] Run CodeQL security checker
- [x] Address PR review feedback:
- [x] Add `insert_many()` method for atomic batch inserts (addresses
lock granularity concern)
- [x] Add `#[must_use]` attribute to `get_or_insert_with()`
- [x] Update `pet-linux-global-python` to use `insert_many()` for
symlinks + executable
## Summary
This PR introduces a generic `LocatorCache<K, V>` abstraction in the
`pet-core` crate that consolidates the common caching patterns used
across multiple locators. The cache provides:
1. Thread-safe operations using `RwLock`
2. Efficient read access with separate read/write locks
3. Double-check locking in `get_or_insert_with()` to prevent redundant
computation
4. Atomic batch inserts via `insert_many()` for better lock efficiency
5. Type aliases for common use cases (`EnvironmentCache`,
`ManagerCache`)
## Security Summary
No security vulnerabilities were discovered by CodeQL analysis.
<!-- START COPILOT ORIGINAL PROMPT -->
<details>
<summary>Original prompt</summary>
>
> ----
>
> *This section details on the original issue you should resolve*
>
> <issue_title>Refactor: Consolidate caching patterns across locators
into a shared abstraction</issue_title>
> <issue_description>## Summary
> Multiple locators implement nearly identical caching patterns for
environments and managers. Consolidating these into a shared abstraction
would reduce code duplication and ensure consistent behavior.
>
> ## Current Duplicate Patterns
>
> ### Pattern: Cache with mutex + contains_key check
> Found in:
> - `crates/pet-conda/src/lib.rs`
> - `crates/pet-poetry/src/lib.rs`
> - `crates/pet-windows-store/src/lib.rs`
> - `crates/pet-linux-global-python/src/lib.rs`
>
> ```rust
> // This pattern appears in multiple files:
> pub struct SomeLocator {
> environments: Arc<Mutex<HashMap<PathBuf, PythonEnvironment>>>,
> }
>
> impl SomeLocator {
> fn find_with_cache(&self) -> Option<...> {
> let environments = self.environments.lock().unwrap();
> if environments.contains_key(&key) {
> return Some(environments.get(&key).unwrap().clone());
> }
> // ... compute and cache
> }
>
> fn clear(&self) {
> self.environments.lock().unwrap().clear();
> }
> }
> ```
>
> ## Proposed Solution
>
> ### Create a generic caching wrapper
> ```rust
> // In pet-core or a new pet-cache crate
> pub struct LocatorCache<K, V> {
> cache: RwLock<HashMap<K, V>>,
> }
>
> impl<K: Eq + Hash, V: Clone> LocatorCache<K, V> {
> pub fn new() -> Self {
> Self { cache: RwLock::new(HashMap::new()) }
> }
>
> pub fn get(&self, key: &K) -> Option<V> {
> self.cache.read().unwrap().get(key).cloned()
> }
>
> pub fn get_or_insert_with<F>(&self, key: K, f: F) -> V
> where
> F: FnOnce() -> Option<V>,
> {
> // Check read lock first
> if let Some(v) = self.cache.read().unwrap().get(&key) {
> return v.clone();
> }
> // Upgrade to write lock and compute
> if let Some(value) = f() {
> self.cache.write().unwrap().insert(key, value.clone());
> value
> }
> }
>
> pub fn clear(&self) {
> self.cache.write().unwrap().clear();
> }
> }
>
> // Type aliases for common uses
> pub type EnvironmentCache = LocatorCache<PathBuf, PythonEnvironment>;
> pub type ManagerCache = LocatorCache<PathBuf, EnvManager>;
> ```
>
> ### Usage in locators
> ```rust
> pub struct Conda {
> pub environments: EnvironmentCache,
> pub managers: ManagerCache,
> // ...
> }
>
> impl Conda {
> fn try_from(&self, env: &PythonEnv) -> Option<PythonEnvironment> {
> self.environments.get_or_insert_with(path.clone(), || {
> // compute environment
> })
> }
> }
> ```
>
> ## Benefits
> 1. **Consistency**: All locators behave the same way
> 2. **Less code**: Remove duplicate boilerplate
> 3. **Centralized improvements**: RwLock upgrade, better error
handling, etc. benefit all locators
> 4. **Testability**: Cache behavior can be tested once
>
> ## Priority
> Low - Requires significant refactoring but improves maintainability
long-term.</issue_description>
>
> ## Comments on the Issue (you are @copilot in this section)
>
> <comments>
> </comments>
>
</details>
<!-- START COPILOT CODING AGENT SUFFIX -->
- Fixes #291
<!-- START COPILOT CODING AGENT TIPS -->
---
💬 We'd love your input! Share your thoughts on Copilot coding agent in
our [2 minute survey](https://gh.io/copilot-coding-agent-survey).
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: karthiknadig <3840081+karthiknadig@users.noreply.github.com>1 parent 525aa9f commit 1d30dd4
4 files changed
Lines changed: 263 additions & 95 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| 14 | + | |
14 | 15 | | |
15 | 16 | | |
16 | 17 | | |
| |||
21 | 22 | | |
22 | 23 | | |
23 | 24 | | |
24 | | - | |
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
| |||
62 | 62 | | |
63 | 63 | | |
64 | 64 | | |
65 | | - | |
66 | | - | |
| 65 | + | |
| 66 | + | |
67 | 67 | | |
68 | 68 | | |
69 | 69 | | |
70 | 70 | | |
71 | 71 | | |
72 | 72 | | |
73 | 73 | | |
74 | | - | |
75 | | - | |
| 74 | + | |
| 75 | + | |
76 | 76 | | |
77 | 77 | | |
78 | 78 | | |
79 | 79 | | |
80 | 80 | | |
81 | | - | |
82 | | - | |
| 81 | + | |
| 82 | + | |
83 | 83 | | |
84 | 84 | | |
85 | 85 | | |
| |||
92 | 92 | | |
93 | 93 | | |
94 | 94 | | |
95 | | - | |
| 95 | + | |
96 | 96 | | |
97 | 97 | | |
98 | 98 | | |
99 | 99 | | |
100 | | - | |
| 100 | + | |
101 | 101 | | |
102 | 102 | | |
103 | 103 | | |
104 | 104 | | |
105 | | - | |
| 105 | + | |
106 | 106 | | |
107 | 107 | | |
108 | 108 | | |
| |||
120 | 120 | | |
121 | 121 | | |
122 | 122 | | |
123 | | - | |
124 | | - | |
125 | | - | |
126 | | - | |
| 123 | + | |
127 | 124 | | |
128 | 125 | | |
129 | 126 | | |
| |||
160 | 157 | | |
161 | 158 | | |
162 | 159 | | |
163 | | - | |
164 | | - | |
165 | | - | |
166 | | - | |
167 | | - | |
| 160 | + | |
168 | 161 | | |
169 | 162 | | |
170 | 163 | | |
171 | 164 | | |
172 | 165 | | |
173 | 166 | | |
174 | | - | |
175 | | - | |
| 167 | + | |
176 | 168 | | |
177 | 169 | | |
178 | 170 | | |
| |||
184 | 176 | | |
185 | 177 | | |
186 | 178 | | |
187 | | - | |
| 179 | + | |
| 180 | + | |
188 | 181 | | |
189 | 182 | | |
190 | 183 | | |
| |||
195 | 188 | | |
196 | 189 | | |
197 | 190 | | |
198 | | - | |
199 | | - | |
200 | | - | |
201 | | - | |
202 | | - | |
203 | | - | |
204 | | - | |
205 | | - | |
206 | | - | |
207 | | - | |
208 | | - | |
209 | | - | |
210 | | - | |
211 | | - | |
212 | | - | |
213 | | - | |
| 191 | + | |
| 192 | + | |
214 | 193 | | |
215 | 194 | | |
216 | 195 | | |
| |||
251 | 230 | | |
252 | 231 | | |
253 | 232 | | |
254 | | - | |
255 | | - | |
256 | | - | |
257 | | - | |
258 | | - | |
259 | | - | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
260 | 236 | | |
261 | | - | |
| 237 | + | |
| 238 | + | |
262 | 239 | | |
263 | 240 | | |
264 | 241 | | |
265 | 242 | | |
266 | | - | |
267 | | - | |
| 243 | + | |
268 | 244 | | |
269 | 245 | | |
270 | 246 | | |
271 | 247 | | |
272 | 248 | | |
273 | 249 | | |
274 | 250 | | |
275 | | - | |
276 | | - | |
| 251 | + | |
277 | 252 | | |
278 | 253 | | |
279 | 254 | | |
| |||
282 | 257 | | |
283 | 258 | | |
284 | 259 | | |
285 | | - | |
286 | | - | |
| 260 | + | |
287 | 261 | | |
288 | 262 | | |
289 | 263 | | |
| |||
316 | 290 | | |
317 | 291 | | |
318 | 292 | | |
319 | | - | |
320 | | - | |
| 293 | + | |
321 | 294 | | |
322 | 295 | | |
323 | 296 | | |
| |||
326 | 299 | | |
327 | 300 | | |
328 | 301 | | |
329 | | - | |
330 | | - | |
331 | | - | |
332 | | - | |
333 | | - | |
334 | | - | |
335 | | - | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
336 | 305 | | |
337 | 306 | | |
338 | | - | |
339 | 307 | | |
340 | 308 | | |
341 | | - | |
342 | | - | |
343 | | - | |
344 | | - | |
345 | | - | |
346 | | - | |
347 | | - | |
348 | | - | |
349 | | - | |
350 | | - | |
351 | | - | |
352 | | - | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
353 | 312 | | |
354 | 313 | | |
355 | 314 | | |
356 | 315 | | |
357 | 316 | | |
358 | 317 | | |
359 | | - | |
360 | | - | |
| 318 | + | |
361 | 319 | | |
362 | 320 | | |
363 | 321 | | |
| |||
366 | 324 | | |
367 | 325 | | |
368 | 326 | | |
369 | | - | |
370 | | - | |
| 327 | + | |
371 | 328 | | |
372 | 329 | | |
373 | 330 | | |
| |||
0 commit comments