Skip to content
This repository was archived by the owner on Nov 1, 2023. It is now read-only.

Commit 62c4194

Browse files
authored
Ensure loads are not duplicated
1 parent 432de2a commit 62c4194

File tree

1 file changed

+36
-4
lines changed

1 file changed

+36
-4
lines changed
Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,59 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4+
use std::sync::{Mutex, MutexGuard};
5+
46
use anyhow::Result;
7+
use thiserror::Error;
58

69
use crate::path::FilePath;
710

811
pub struct Loader {
912
loaded: elsa::sync::FrozenMap<FilePath, Box<[u8]>>,
13+
loading: Mutex<()>,
1014
}
1115

12-
impl Loader {
13-
pub fn new() -> Self {
14-
Loader {
16+
impl Default for Loader {
17+
fn default() -> Self {
18+
Self {
19+
// sync version doesn't have a Default impl
1520
loaded: elsa::sync::FrozenMap::new(),
21+
loading: Default::default(),
1622
}
1723
}
24+
}
25+
26+
impl Loader {
27+
pub fn new() -> Self {
28+
Self::default()
29+
}
1830

1931
pub fn load(&self, path: &FilePath) -> Result<&[u8]> {
2032
if let Some(data) = self.loaded.get(path) {
2133
return Ok(data);
2234
}
2335

36+
// claim the lock to ensure we don't duplicate loads
37+
let loading_lock: MutexGuard<()> = self
38+
.loading
39+
.lock()
40+
.map_err(|_| LoaderError::PoisonedMutex)?;
41+
42+
// re-check after claiming "loading" mutex,
43+
// since the data might have been loaded by someone else
44+
if let Some(data) = self.loaded.get(path) {
45+
return Ok(data);
46+
}
47+
2448
let data: Box<[u8]> = std::fs::read(path)?.into();
25-
Ok(self.loaded.insert(path.clone(), data))
49+
let result = self.loaded.insert(path.clone(), data);
50+
drop(loading_lock);
51+
Ok(result)
2652
}
2753
}
54+
55+
#[derive(Error, Debug)]
56+
pub enum LoaderError {
57+
#[error("internal mutex poisoned")]
58+
PoisonedMutex,
59+
}

0 commit comments

Comments
 (0)