No longer refcount rodeo to avoid redundant serialization

This commit is contained in:
Antoine Gersant 2024-08-09 08:00:24 -07:00
parent f0fa985f8a
commit 2f2fdf9056
2 changed files with 47 additions and 54 deletions

View file

@ -84,7 +84,7 @@ impl Manager {
let index_manager = self.clone(); let index_manager = self.clone();
move || { move || {
let index = index_manager.index.read().unwrap(); let index = index_manager.index.read().unwrap();
index.browser.browse(virtual_path) index.browser.browse(&index.strings, virtual_path)
} }
}) })
.await .await
@ -96,7 +96,7 @@ impl Manager {
let index_manager = self.clone(); let index_manager = self.clone();
move || { move || {
let index = index_manager.index.read().unwrap(); let index = index_manager.index.read().unwrap();
index.browser.flatten(virtual_path) index.browser.flatten(&index.strings, virtual_path)
} }
}) })
.await .await
@ -180,48 +180,43 @@ impl Manager {
} }
} }
#[derive(Serialize, Deserialize)] #[derive(Default, Serialize, Deserialize)]
pub struct Index { pub struct Index {
pub strings: ThreadedRodeo,
pub browser: browser::Browser, pub browser: browser::Browser,
pub collection: collection::Collection, pub collection: collection::Collection,
} }
impl Default for Index {
fn default() -> Self {
Self {
browser: browser::Browser::new(Arc::default()),
collection: Default::default(),
}
}
}
pub struct Builder { pub struct Builder {
strings: ThreadedRodeo,
browser_builder: browser::Builder, browser_builder: browser::Builder,
collection_builder: collection::Builder, collection_builder: collection::Builder,
} }
impl Builder { impl Builder {
pub fn new() -> Self { pub fn new() -> Self {
let strings = Arc::new(ThreadedRodeo::new());
Self { Self {
browser_builder: browser::Builder::new(strings), strings: ThreadedRodeo::new(),
browser_builder: browser::Builder::default(),
collection_builder: collection::Builder::default(), collection_builder: collection::Builder::default(),
} }
} }
pub fn add_directory(&mut self, directory: scanner::Directory) { pub fn add_directory(&mut self, directory: scanner::Directory) {
self.browser_builder.add_directory(directory); self.browser_builder
.add_directory(&mut self.strings, directory);
} }
pub fn add_song(&mut self, song: scanner::Song) { pub fn add_song(&mut self, song: scanner::Song) {
self.browser_builder.add_song(&song); self.browser_builder.add_song(&mut self.strings, &song);
self.collection_builder.add_song(song); self.collection_builder.add_song(song);
} }
pub fn build(self) -> Index { pub fn build(mut self) -> Index {
Index { Index {
browser: self.browser_builder.build(), browser: self.browser_builder.build(&mut self.strings),
collection: self.collection_builder.build(), collection: self.collection_builder.build(),
strings: self.strings,
} }
} }
} }
@ -236,12 +231,12 @@ impl Default for Builder {
pub(self) struct PathID(lasso2::Spur); pub(self) struct PathID(lasso2::Spur);
pub(self) trait InternPath { pub(self) trait InternPath {
fn get_or_intern(self, strings: &mut Arc<ThreadedRodeo>) -> Option<PathID>; fn get_or_intern(self, strings: &mut ThreadedRodeo) -> Option<PathID>;
fn get(self, strings: &Arc<ThreadedRodeo>) -> Option<PathID>; fn get(self, strings: &ThreadedRodeo) -> Option<PathID>;
} }
impl<P: AsRef<Path>> InternPath for P { impl<P: AsRef<Path>> InternPath for P {
fn get_or_intern(self, strings: &mut Arc<ThreadedRodeo>) -> Option<PathID> { fn get_or_intern(self, strings: &mut ThreadedRodeo) -> Option<PathID> {
let id = self let id = self
.as_ref() .as_ref()
.as_os_str() .as_os_str()
@ -254,7 +249,7 @@ impl<P: AsRef<Path>> InternPath for P {
id id
} }
fn get(self, strings: &Arc<ThreadedRodeo>) -> Option<PathID> { fn get(self, strings: &ThreadedRodeo) -> Option<PathID> {
let id = self let id = self
.as_ref() .as_ref()
.as_os_str() .as_os_str()

View file

@ -3,7 +3,6 @@ use std::{
ffi::OsStr, ffi::OsStr,
hash::Hash, hash::Hash,
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::Arc,
}; };
use lasso2::ThreadedRodeo; use lasso2::ThreadedRodeo;
@ -21,24 +20,28 @@ pub enum File {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct Browser { pub struct Browser {
strings: Arc<ThreadedRodeo>,
directories: HashMap<PathID, Vec<storage::File>>, directories: HashMap<PathID, Vec<storage::File>>,
flattened: Trie<lasso2::Spur>, flattened: Trie<lasso2::Spur>,
} }
impl Browser { impl Default for Browser {
pub fn new(strings: Arc<ThreadedRodeo>) -> Self { fn default() -> Self {
Self { Self {
strings, directories: HashMap::default(),
directories: HashMap::new(),
flattened: TrieBuilder::new().build(), flattened: TrieBuilder::new().build(),
} }
} }
}
pub fn browse<P: AsRef<Path>>(&self, virtual_path: P) -> Result<Vec<File>, Error> { impl Browser {
pub fn browse<P: AsRef<Path>>(
&self,
strings: &ThreadedRodeo,
virtual_path: P,
) -> Result<Vec<File>, Error> {
let path_id = virtual_path let path_id = virtual_path
.as_ref() .as_ref()
.get(&self.strings) .get(strings)
.ok_or_else(|| Error::DirectoryNotFound(virtual_path.as_ref().to_owned()))?; .ok_or_else(|| Error::DirectoryNotFound(virtual_path.as_ref().to_owned()))?;
let Some(files) = self.directories.get(&path_id) else { let Some(files) = self.directories.get(&path_id) else {
@ -52,7 +55,7 @@ impl Browser {
storage::File::Directory(p) => p, storage::File::Directory(p) => p,
storage::File::Song(p) => p, storage::File::Song(p) => p,
}; };
let path = Path::new(OsStr::new(self.strings.resolve(&path_id.0))).to_owned(); let path = Path::new(OsStr::new(strings.resolve(&path_id.0))).to_owned();
match f { match f {
storage::File::Directory(_) => File::Directory(path), storage::File::Directory(_) => File::Directory(path),
storage::File::Song(_) => File::Song(path), storage::File::Song(_) => File::Song(path),
@ -61,12 +64,16 @@ impl Browser {
.collect()) .collect())
} }
pub fn flatten<P: AsRef<Path>>(&self, virtual_path: P) -> Result<Vec<PathBuf>, Error> { pub fn flatten<P: AsRef<Path>>(
&self,
strings: &ThreadedRodeo,
virtual_path: P,
) -> Result<Vec<PathBuf>, Error> {
let path_components = virtual_path let path_components = virtual_path
.as_ref() .as_ref()
.components() .components()
.map(|c| c.as_os_str().to_str().unwrap_or_default()) .map(|c| c.as_os_str().to_str().unwrap_or_default())
.filter_map(|c| self.strings.get(c)) .filter_map(|c| strings.get(c))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
if !self.flattened.is_prefix(&path_components) { if !self.flattened.is_prefix(&path_components) {
@ -78,7 +85,7 @@ impl Browser {
.predictive_search(path_components) .predictive_search(path_components)
.map(|c: Vec<_>| -> PathBuf { .map(|c: Vec<_>| -> PathBuf {
c.into_iter() c.into_iter()
.map(|s| self.strings.resolve(&s)) .map(|s| strings.resolve(&s))
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(std::path::MAIN_SEPARATOR_STR) .join(std::path::MAIN_SEPARATOR_STR)
.into() .into()
@ -87,29 +94,21 @@ impl Browser {
} }
} }
#[derive(Default)]
pub struct Builder { pub struct Builder {
strings: Arc<ThreadedRodeo>,
directories: HashMap<PathID, Vec<storage::File>>, directories: HashMap<PathID, Vec<storage::File>>,
flattened: TrieBuilder<lasso2::Spur>, flattened: TrieBuilder<lasso2::Spur>,
} }
impl Builder { impl Builder {
pub fn new(strings: Arc<ThreadedRodeo>) -> Self { pub fn add_directory(&mut self, strings: &mut ThreadedRodeo, directory: scanner::Directory) {
Self { let Some(path_id) = directory.virtual_path.get_or_intern(strings) else {
strings,
directories: HashMap::default(),
flattened: TrieBuilder::default(),
}
}
pub fn add_directory(&mut self, directory: scanner::Directory) {
let Some(path_id) = directory.virtual_path.get_or_intern(&mut self.strings) else {
return; return;
}; };
let Some(parent_id) = directory let Some(parent_id) = directory
.virtual_parent .virtual_parent
.and_then(|p| p.get_or_intern(&mut self.strings)) .and_then(|p| p.get_or_intern(strings))
else { else {
return; return;
}; };
@ -122,12 +121,12 @@ impl Builder {
.push(storage::File::Directory(path_id)); .push(storage::File::Directory(path_id));
} }
pub fn add_song(&mut self, song: &scanner::Song) { pub fn add_song(&mut self, strings: &mut ThreadedRodeo, song: &scanner::Song) {
let Some(path_id) = (&song.virtual_path).get_or_intern(&mut self.strings) else { let Some(path_id) = (&song.virtual_path).get_or_intern(strings) else {
return; return;
}; };
let Some(parent_id) = (&song.virtual_parent).get_or_intern(&mut self.strings) else { let Some(parent_id) = (&song.virtual_parent).get_or_intern(strings) else {
return; return;
}; };
@ -139,20 +138,19 @@ impl Builder {
self.flattened.push( self.flattened.push(
song.virtual_path song.virtual_path
.components() .components()
.map(|c| self.strings.get_or_intern(c.as_os_str().to_str().unwrap())) .map(|c| strings.get_or_intern(c.as_os_str().to_str().unwrap()))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
); );
} }
pub fn build(mut self) -> Browser { pub fn build(mut self, strings: &mut ThreadedRodeo) -> Browser {
for directory in self.directories.values_mut() { for directory in self.directories.values_mut() {
directory.sort_by_key(|f| match f { directory.sort_by_key(|f| match f {
storage::File::Directory(p) => self.strings.resolve(&p.0), storage::File::Directory(p) => strings.resolve(&p.0),
storage::File::Song(p) => self.strings.resolve(&p.0), storage::File::Song(p) => strings.resolve(&p.0),
}); });
} }
Browser { Browser {
strings: self.strings,
directories: self.directories, directories: self.directories,
flattened: self.flattened.build(), flattened: self.flattened.build(),
} }