|
16 | 16 | //! ```
|
17 | 17 |
|
18 | 18 | use anyhow::{bail, Context, Result};
|
19 |
| -use serde::{Serialize, Deserialize}; |
20 | 19 | use bytes::Bytes;
|
21 | 20 | use dashmap::DashMap;
|
22 | 21 | use memmap2::Mmap;
|
| 22 | +use serde::{Deserialize, Serialize}; |
23 | 23 | use std::{fs::File, ops::Range, sync::Arc};
|
24 | 24 |
|
25 | 25 | /***
|
@@ -178,24 +178,17 @@ mod tests {
|
178 | 178 | // use std::{sync::Arc, thread};
|
179 | 179 |
|
180 | 180 | fn unique_path() -> std::path::PathBuf {
|
181 |
| - let nanos = SystemTime::now() |
182 |
| - .duration_since(UNIX_EPOCH) |
183 |
| - .unwrap() |
184 |
| - .as_nanos(); |
| 181 | + let nanos = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_nanos(); |
185 | 182 | std::env::temp_dir().join(format!("acropolis_resolver_{nanos}.bin"))
|
186 | 183 | }
|
187 | 184 |
|
188 | 185 | fn create_file_with(bytes: &[u8]) -> Result<File> {
|
189 | 186 | let path = unique_path();
|
190 |
| - let mut f = OpenOptions::new() |
191 |
| - .read(true) |
192 |
| - .write(true) |
193 |
| - .create(true) |
194 |
| - .truncate(true) |
195 |
| - .open(&path)?; |
| 187 | + let mut f = |
| 188 | + OpenOptions::new().read(true).write(true).create(true).truncate(true).open(&path)?; |
196 | 189 | f.write_all(bytes)?;
|
197 | 190 | f.sync_all()?; // ensure size/content visible to mmap
|
198 |
| - // Reopen read-only (optional, but mirrors production “reader” role) |
| 191 | + // Reopen read-only (optional, but mirrors production “reader” role) |
199 | 192 | drop(f);
|
200 | 193 | let f = OpenOptions::new().read(true).open(&path)?;
|
201 | 194 | Ok(f)
|
@@ -244,7 +237,10 @@ mod tests {
|
244 | 237 | let loc = Loc {
|
245 | 238 | store,
|
246 | 239 | object: obj,
|
247 |
| - region: Region { offset: 100, len: 20 }, |
| 240 | + region: Region { |
| 241 | + offset: 100, |
| 242 | + len: 20, |
| 243 | + }, |
248 | 244 | inline: None,
|
249 | 245 | };
|
250 | 246 |
|
@@ -328,56 +324,57 @@ mod tests {
|
328 | 324 | }
|
329 | 325 |
|
330 | 326 | #[test]
|
331 |
| -fn concurrent_resolves_share_backing() -> Result<()> { |
332 |
| - use std::sync::Arc; |
| 327 | + fn concurrent_resolves_share_backing() -> Result<()> { |
| 328 | + use std::sync::Arc; |
333 | 329 |
|
334 |
| - // 1) Create file content. |
335 |
| - let mut bytes = Vec::with_capacity(1024); |
336 |
| - for i in 0..1024u32 { |
337 |
| - bytes.push((i % 251) as u8); |
338 |
| - } |
| 330 | + // 1) Create file content. |
| 331 | + let mut bytes = Vec::with_capacity(1024); |
| 332 | + for i in 0..1024u32 { |
| 333 | + bytes.push((i % 251) as u8); |
| 334 | + } |
339 | 335 |
|
340 |
| - // 2) Pre-compute the expected slice and share it via Arc. |
341 |
| - let expected: Arc<Vec<u8>> = Arc::new(bytes[128..384].to_vec()); |
342 |
| - |
343 |
| - // 3) Register the file once. |
344 |
| - let file = create_file_with(&bytes)?; |
345 |
| - let reg = Arc::new(Registry::default()); |
346 |
| - let store = StoreId(11); |
347 |
| - let obj = ObjectId(0xABCD); |
348 |
| - reg.register_file(store, obj, &file)?; |
349 |
| - |
350 |
| - let loc = Loc { |
351 |
| - store, |
352 |
| - object: obj, |
353 |
| - region: Region { offset: 128, len: 256 }, |
354 |
| - inline: None, |
355 |
| - }; |
356 |
| - |
357 |
| - |
358 |
| - // 4) Resolve in parallel without ever capturing `bytes`. |
359 |
| - let mut handles = Vec::new(); |
360 |
| - for _ in 0..8 { |
361 |
| - let reg_cloned = Arc::clone(®); |
362 |
| - let loc_cloned = loc.clone(); |
363 |
| - let expected_cloned = Arc::clone(&expected); |
364 |
| - |
365 |
| - handles.push(std::thread::spawn(move || { |
366 |
| - let resolver = Resolver::new(®_cloned); |
367 |
| - let r = resolver.resolve(&loc_cloned).expect("resolve"); |
368 |
| - assert_eq!(r.as_slice(), &expected_cloned[..]); |
369 |
| - })); |
370 |
| - } |
| 336 | + // 2) Pre-compute the expected slice and share it via Arc. |
| 337 | + let expected: Arc<Vec<u8>> = Arc::new(bytes[128..384].to_vec()); |
371 | 338 |
|
372 |
| - // 4) Concurrently, sanity check in the main thread. |
373 |
| - let resolver_main = Resolver::new(®); |
374 |
| - let r_main = resolver_main.resolve(&loc)?; |
375 |
| - assert_eq!(r_main.as_slice(), &expected[..]); |
| 339 | + // 3) Register the file once. |
| 340 | + let file = create_file_with(&bytes)?; |
| 341 | + let reg = Arc::new(Registry::default()); |
| 342 | + let store = StoreId(11); |
| 343 | + let obj = ObjectId(0xABCD); |
| 344 | + reg.register_file(store, obj, &file)?; |
376 | 345 |
|
377 |
| - for h in handles { |
378 |
| - h.join().expect("thread join ok"); |
379 |
| - } |
380 |
| - Ok(()) |
381 |
| -} |
| 346 | + let loc = Loc { |
| 347 | + store, |
| 348 | + object: obj, |
| 349 | + region: Region { |
| 350 | + offset: 128, |
| 351 | + len: 256, |
| 352 | + }, |
| 353 | + inline: None, |
| 354 | + }; |
382 | 355 |
|
| 356 | + // 4) Resolve in parallel without ever capturing `bytes`. |
| 357 | + let mut handles = Vec::new(); |
| 358 | + for _ in 0..8 { |
| 359 | + let reg_cloned = Arc::clone(®); |
| 360 | + let loc_cloned = loc.clone(); |
| 361 | + let expected_cloned = Arc::clone(&expected); |
| 362 | + |
| 363 | + handles.push(std::thread::spawn(move || { |
| 364 | + let resolver = Resolver::new(®_cloned); |
| 365 | + let r = resolver.resolve(&loc_cloned).expect("resolve"); |
| 366 | + assert_eq!(r.as_slice(), &expected_cloned[..]); |
| 367 | + })); |
| 368 | + } |
| 369 | + |
| 370 | + // 4) Concurrently, sanity check in the main thread. |
| 371 | + let resolver_main = Resolver::new(®); |
| 372 | + let r_main = resolver_main.resolve(&loc)?; |
| 373 | + assert_eq!(r_main.as_slice(), &expected[..]); |
| 374 | + |
| 375 | + for h in handles { |
| 376 | + h.join().expect("thread join ok"); |
| 377 | + } |
| 378 | + Ok(()) |
| 379 | + } |
383 | 380 | }
|
0 commit comments