Skip to content

Commit

Permalink
Improve performance of MPR cache loading
Browse files Browse the repository at this point in the history
We no longer maintain 'CachePackage' structs, as these seemed to have slowed down our code a lot.
  • Loading branch information
hwittenborn committed Oct 10, 2022
1 parent 96e9fcc commit dd58ee2
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 256 deletions.
17 changes: 2 additions & 15 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@ name: Run unit tests
on: {"pull_request"}
env: {"DEBIAN_FRONTEND": "noninteractive"}
jobs:
build:
run-tests:
runs-on: ubuntu-latest
container:
image: proget.hunterwittenborn.com/docker/makedeb/makedeb-alpha:ubuntu-focal
options: --user root
steps:
- name: Install CI prerequisites
run: sudo -E apt-get install git -y
Expand All @@ -15,16 +12,6 @@ jobs:
uses: actions/checkout@v3

- name: Run unit tests
run: |
sudo chown 'makedeb:makedeb' ./ -R
.drone/scripts/setup-pbmpr.sh
sudo apt-get install rustup libssl-dev pkg-config libapt-pkg-dev -y
cargo fmt --check
cargo clippy -- -D warnings
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: stepchowfun/toast/.github/actions/toast@main
uses: stepchowfun/toast/.github/actions/toast@main

# vim: expandtab ts=2 sw=2
14 changes: 14 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env just --justfile
set positional-arguments

default:
@just --list

build *args:
cargo build "${@}"
sudo chown 'root:root' target/*/mist
sudo chmod a+s target/*/mist

run *args:
just build
target/debug/mist "${@}"
114 changes: 0 additions & 114 deletions src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,37 +232,11 @@ impl MprCache {
// Some of these fields only make sense to one type of package, but this kind of
// cache allows us to combine both types when needed, such as when providing
// search results.

#[derive(Clone, PartialEq, Eq)]
pub enum CachePackageSource {
Apt,
Mpr,
}

#[derive(Clone, PartialEq)]
pub struct CachePackage {
pub pkgname: String,
pub pkgbase: Option<String>,
pub version: String,
pub pkgdesc: Option<String>,
pub arch: Option<String>,
pub maintainer: Option<String>,
pub num_votes: Option<u32>,
pub popularity: Option<f32>,
pub ood: Option<u32>,
pub source: CachePackageSource,
}

pub struct Cache {
/// The underlying APT cache struct.
apt_cache: AptCache,
/// The underlying MPR cache struct.
mpr_cache: MprCache,
/// A combined list of all packages in the cache.
//pkglist: Vec<CachePackage>,
/// A map for getting all packages with a certain pkgname. Can be quicker
/// than looping over [`Self::pkglist`].
pkgmap: HashMap<String, Vec<CachePackage>>,
}

impl Cache {
Expand All @@ -286,60 +260,9 @@ impl Cache {

/// Create a new cache.
pub fn new(apt_cache: AptCache, mpr_cache: MprCache) -> Self {
// Package list.
let mut pkglist = Vec::new();

for pkg in Self::get_nonvirtual_packages(&apt_cache, &PackageSort::default()) {
let candidate = pkg.candidate().unwrap();

pkglist.push(CachePackage {
pkgname: pkg.name(),
pkgbase: None,
version: candidate.version(),
pkgdesc: candidate.summary(),
arch: Some(pkg.arch()),
maintainer: None,
num_votes: None,
popularity: None,
ood: None,
source: CachePackageSource::Apt,
});
}

for pkg in mpr_cache.packages().values() {
pkglist.push(CachePackage {
pkgname: pkg.pkgname.clone(),
pkgbase: Some(pkg.pkgbase.clone()),
version: pkg.version.clone(),
pkgdesc: pkg.pkgdesc.clone(),
arch: None,
maintainer: pkg.maintainer.clone(),
num_votes: Some(pkg.num_votes),
popularity: Some(pkg.popularity),
ood: pkg.ood,
source: CachePackageSource::Mpr,
});
}

// Package map.
let mut pkgmap: HashMap<String, Vec<CachePackage>> = HashMap::new();

for pkg in &pkglist {
let pkgname = pkg.pkgname.clone();

#[allow(clippy::map_entry)]
if pkgmap.contains_key(&pkgname) {
pkgmap.get_mut(&pkgname).unwrap().push(pkg.clone());
} else {
pkgmap.insert(pkgname, vec![pkg.clone()]);
}
}

Self {
apt_cache,
mpr_cache,
//pkglist,
pkgmap,
}
}

Expand Down Expand Up @@ -714,43 +637,6 @@ impl Cache {
}
}

/// Get a reference to the generated pkglist (contains a combined APT+MPR
/// cache).
/*pub fn pkglist(&self) -> &Vec<CachePackage> {
&self.pkglist
}*/

/// Get a reference to the generated pkgmap (a key-value pair with keys of
/// pkgnames and values of lists of packages). Can be quicker than
/// [`Cache::pkglist`] if you're trying to lookup a package.
pub fn pkgmap(&self) -> &HashMap<String, Vec<CachePackage>> {
&self.pkgmap
}

// Get the APT variant of a package.
pub fn get_apt_pkg(&self, pkgname: &str) -> Option<&CachePackage> {
if let Some(pkglist) = self.pkgmap().get(&pkgname.to_owned()) {
for pkg in pkglist {
if let CachePackageSource::Apt = pkg.source {
return Some(pkg);
}
}
}
None
}

// Get the MPR variant of a package.
pub fn get_mpr_pkg(&self, pkgname: &str) -> Option<&CachePackage> {
if let Some(pkglist) = self.pkgmap().get(&pkgname.to_owned()) {
for pkg in pkglist {
if let CachePackageSource::Mpr = pkg.source {
return Some(pkg);
}
}
}
None
}

// Find the pkgbase of a given MPR package's pkgname.
pub fn find_pkgbase(&self, pkgname: &str) -> Option<String> {
for pkg in self.mpr_cache().packages().values() {
Expand Down
7 changes: 4 additions & 3 deletions src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ pub fn install(args: &clap::ArgMatches) {
let mut unfindable = false;

for pkg in &pkglist {
if cache.get_apt_pkg(pkg).is_none() && cache.get_mpr_pkg(pkg).is_none() {
if cache.apt_cache().get(pkg).is_none() && !cache.mpr_cache().packages().contains_key(*pkg)
{
message::error(&format!(
"Unable to find package '{}'.\n",
pkg.green().bold()
Expand All @@ -35,8 +36,8 @@ pub fn install(args: &clap::ArgMatches) {
}

for pkg in &pkglist {
let apt_pkg = cache.get_apt_pkg(pkg);
let mpr_pkg = cache.get_mpr_pkg(pkg);
let apt_pkg = cache.apt_cache().get(pkg);
let mpr_pkg = cache.mpr_cache().packages().get(*pkg);

if apt_pkg.is_some() && mpr_pkg.is_some() {
let resp = util::ask_question(
Expand Down
25 changes: 18 additions & 7 deletions src/list.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::{
cache::{Cache, CachePackage, MprCache},
cache::{Cache, MprCache},
style,
};
use rust_apt::cache::Cache as AptCache;
use rust_apt::cache::{Cache as AptCache, PackageSort};

pub fn list(args: &clap::ArgMatches) {
let pkglist: Vec<&String> = match args.get_many("pkg") {
Expand All @@ -15,17 +15,28 @@ pub fn list(args: &clap::ArgMatches) {
let name_only = args.is_present("name-only");

let cache = Cache::new(AptCache::new(), MprCache::new());
let mut candidates: Vec<&Vec<CachePackage>> = Vec::new();
let mut candidates = Vec::new();

if !pkglist.is_empty() {
for pkg in pkglist {
if let Some(pkg_group) = cache.pkgmap().get(pkg) {
candidates.push(pkg_group);
if cache.apt_cache().get(pkg).is_some()
|| cache.mpr_cache().packages().get(pkg).is_some()
{
candidates.push(pkg.to_string());
}
}
} else {
for pkg_group in cache.pkgmap().values() {
candidates.push(pkg_group);
for pkg in Cache::get_nonvirtual_packages(cache.apt_cache(), &PackageSort::default()) {
let pkgname = pkg.name();
if !candidates.contains(&pkgname) {
candidates.push(pkgname);
}
}

for pkg in cache.mpr_cache().packages().values() {
if !candidates.contains(&pkg.pkgname) {
candidates.push(pkg.pkgname.to_string());
}
}
}

Expand Down
46 changes: 22 additions & 24 deletions src/search.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::{
cache::{Cache, CachePackage, MprCache},
cache::{Cache, MprCache},
style,
};
use rust_apt::cache::Cache as AptCache;
use rust_apt::cache::{Cache as AptCache, PackageSort};

pub fn search(args: &clap::ArgMatches) {
let query_list: Vec<&String> = args.get_many("query").unwrap().collect();
Expand All @@ -12,32 +12,30 @@ pub fn search(args: &clap::ArgMatches) {
let name_only = args.is_present("name-only");

let cache = Cache::new(AptCache::new(), MprCache::new());
let mut candidates: Vec<&Vec<CachePackage>> = Vec::new();
let mut candidates = Vec::new();

for query in query_list {
for (pkgname, pkg_group) in cache.pkgmap().iter() {
let mut pkgs = Vec::new();
let apt_pkg = cache.get_apt_pkg(pkgname);
let mpr_pkg = cache.get_mpr_pkg(pkgname);

if let Some(pkg) = apt_pkg {
pkgs.push(pkg);
}
if let Some(pkg) = mpr_pkg {
pkgs.push(pkg);
for pkg in Cache::get_nonvirtual_packages(cache.apt_cache(), &PackageSort::default()) {
let pkgname = pkg.name();
if (pkgname.contains(query)
|| pkg
.candidate()
.unwrap()
.description()
.unwrap_or_default()
.contains(query))
&& !candidates.contains(&pkgname)
{
candidates.push(pkgname);
}
}

for pkg in pkgs {
if (pkg.pkgname.contains(query)
|| pkg
.pkgdesc
.as_ref()
.unwrap_or(&"".to_owned())
.contains(query))
&& !candidates.contains(&pkg_group)
{
candidates.push(pkg_group);
}
for pkg in cache.mpr_cache().packages().values() {
if (pkg.pkgname.contains(query)
|| pkg.pkgdesc.clone().unwrap_or_default().contains(query))
&& !candidates.contains(&pkg.pkgname)
{
candidates.push(pkg.pkgname.to_string());
}
}
}
Expand Down
Loading

0 comments on commit dd58ee2

Please sign in to comment.