Check for package upgrades in parallel; Search in packages in parallel;

This commit is contained in:
Nathan Fisher 2023-04-01 02:01:53 -04:00
parent 26be99f408
commit a1843cac33
4 changed files with 75 additions and 39 deletions

View File

@ -2,8 +2,16 @@ use ron::ser::PrettyConfig;
use { use {
crate::{Package, Repository, Version}, crate::{Package, Repository, Version},
rayon::prelude::*,
serde::{Deserialize, Serialize}, serde::{Deserialize, Serialize},
std::{collections::HashMap, error::Error, fmt, fs::{self, File}, path::PathBuf}, std::{
collections::HashMap,
error::Error,
fmt,
fs::{self, File},
path::PathBuf,
sync::Mutex,
},
url::Url, url::Url,
zstd::{Decoder, Encoder}, zstd::{Decoder, Encoder},
}; };
@ -50,17 +58,17 @@ impl Database {
pub fn get_upgradable(&mut self) -> Result<HashMap<String, Update>, Box<dyn Error>> { pub fn get_upgradable(&mut self) -> Result<HashMap<String, Update>, Box<dyn Error>> {
self.update()?; self.update()?;
let mut updates = HashMap::<String, Update>::new(); let updates = Mutex::new(HashMap::<String, Update>::new());
for local_package in self.packages.values() { self.packages.par_iter().for_each(|(key, local_package)| {
let name = local_package.name.clone();
for repo in self.available.values() { for repo in self.available.values() {
// Check if the remote has a package by this name // Check if the remote has a package by this name
if let Some(remote_package) = repo.packages.get(&name) { if let Some(remote_package) = repo.packages.get(key) {
// Check if the remote package is an update // Check if the remote package is an update
if remote_package.is_upgrade(&local_package) { if remote_package.is_upgrade(&local_package) {
if let Ok(mut updates) = updates.lock() {
// Check if we've already pulled in an update from another repo, // Check if we've already pulled in an update from another repo,
// and if so compare versions // and if so compare versions
if let Some(other_update) = updates.get(&name) { if let Some(other_update) = updates.get(key) {
if remote_package.version > other_update.version if remote_package.version > other_update.version
|| (remote_package.version == other_update.version || (remote_package.version == other_update.version
&& remote_package.release > other_update.release) && remote_package.release > other_update.release)
@ -68,28 +76,30 @@ impl Database {
// The remote version is an update to the already // The remote version is an update to the already
// pulled in update, so swap it out // pulled in update, so swap it out
let update = Update { let update = Update {
name: name.clone(), name: key.to_string(),
version: remote_package.version.clone(), version: remote_package.version.clone(),
release: remote_package.release, release: remote_package.release,
url: repo.base_url.clone(), url: repo.base_url.clone(),
}; };
updates.insert(name.clone(), update); updates.insert(key.to_string(), update);
} }
} else { } else {
// First time we've seen this update, so insert it // First time we've seen this update, so insert it
// into our hashmap // into our hashmap
let update = Update { let update = Update {
name: name.clone(), name: key.to_string(),
version: remote_package.version.clone(), version: remote_package.version.clone(),
release: remote_package.release, release: remote_package.release,
url: repo.base_url.clone(), url: repo.base_url.clone(),
}; };
updates.insert(name.clone(), update); updates.insert(key.to_string(), update);
} }
} }
} }
} }
} }
});
let updates = updates.into_inner()?;
Ok(updates) Ok(updates)
} }
@ -125,3 +135,20 @@ impl Database {
unimplemented!(); unimplemented!();
} }
} }
#[cfg(test)]
mod test {
use super::*;
#[test]
fn update_to_string() {
let up = Update {
name: "hpk".to_string(),
version: Version::Number(42),
release: 1,
url: Url::parse("https://hitchhiker-linux.org/pub/packages/").unwrap(),
}
.to_string();
assert_eq!("hpk-42_1".to_string(), up);
}
}

View File

@ -68,7 +68,6 @@ pub fn get_dbdir(prefix: Option<PathBuf>) -> PathBuf {
path path
} }
/// Gets the cache directory path. Takes an optional prefix variable for working /// Gets the cache directory path. Takes an optional prefix variable for working
/// with an alternate filesystem root. /// with an alternate filesystem root.
/// ## Examples /// ## Examples
@ -120,4 +119,3 @@ mod test {
assert_eq!(cache, PathBuf::from("/mnt/aarch64/var/cache/hpk")); assert_eq!(cache, PathBuf::from("/mnt/aarch64/var/cache/hpk"));
} }
} }

View File

@ -6,8 +6,8 @@ use {
ron::ser::{to_string_pretty, PrettyConfig}, ron::ser::{to_string_pretty, PrettyConfig},
serde::{Deserialize, Serialize}, serde::{Deserialize, Serialize},
std::{ std::{
fs,
error::Error, error::Error,
fs,
fs::File, fs::File,
io::{BufWriter, Write}, io::{BufWriter, Write},
path::Path, path::Path,

View File

@ -1,7 +1,10 @@
use std::sync::PoisonError;
use { use {
crate::Package, crate::Package,
rayon::prelude::*,
serde::{Deserialize, Serialize}, serde::{Deserialize, Serialize},
std::collections::HashMap, std::{collections::HashMap, sync::Mutex},
url::Url, url::Url,
}; };
@ -13,32 +16,40 @@ pub struct Repository {
} }
impl Repository { impl Repository {
pub fn search_names(&self, query: &str) -> Vec<&Package> { pub fn search_names(&self, query: &str) -> Result<Vec<&Package>, PoisonError<Vec<&Package>>> {
let mut results = vec![]; let mut results = vec![];
if let Some(p) = self.packages.get(query) { if let Some(p) = self.packages.get(query) {
results.push(p) results.push(p)
} }
self.packages.iter().for_each(|(k, v)| { let results = Mutex::new(results);
self.packages.par_iter().for_each(|(k, v)| {
if k.contains(query) { if k.contains(query) {
results.push(v); if let Ok(mut r) = results.lock() {
r.push(v);
}
} }
}); });
results let results = results.into_inner()?;
Ok(results)
} }
pub fn search_all(&self, query: &str) -> Vec<&Package> { pub fn search_all(&self, query: &str) -> Result<Vec<&Package>, PoisonError<Vec<&Package>>> {
let mut results = vec![]; let mut results = vec![];
if let Some(p) = self.packages.get(query) { if let Some(p) = self.packages.get(query) {
results.push(p) results.push(p)
} }
self.packages.iter().for_each(|(k, v)| { let results = Mutex::new(results);
self.packages.par_iter().for_each(|(k, v)| {
if k.contains(query) if k.contains(query)
|| v.description.contains(query) || v.description.contains(query)
|| v.long_description.contains(query) || v.long_description.contains(query)
{ {
results.push(v); if let Ok(mut r) = results.lock() {
r.push(v);
}
} }
}); });
results let results = results.into_inner()?;
Ok(results)
} }
} }