From 1187974b7347e8e1620ef3e602095a895b25c5a7 Mon Sep 17 00:00:00 2001 From: Colin Woodbury Date: Tue, 19 Mar 2024 07:21:39 +0900 Subject: [PATCH] fix: reinstate connection pools --- rust/Cargo.lock | 35 +++++++++++++++++ rust/Cargo.toml | 2 +- rust/aura-core/Cargo.toml | 3 ++ rust/aura-core/src/aur/dependencies.rs | 54 +++++++++++++++++++++----- rust/aura-core/src/cache.rs | 4 +- rust/aura-core/src/lib.rs | 25 ------------ rust/aura-core/src/snapshot.rs | 3 +- rust/aura-pm/Cargo.toml | 2 + rust/aura-pm/i18n/en-US/aura_pm.ftl | 2 + rust/aura-pm/src/command/aur.rs | 11 +++--- rust/aura-pm/src/command/cache.rs | 2 +- rust/aura-pm/src/command/check.rs | 18 ++++++--- rust/aura-pm/src/command/deps.rs | 3 +- rust/aura-pm/src/command/orphans.rs | 3 +- rust/aura-pm/src/command/snapshot.rs | 2 +- rust/aura-pm/src/command/stats.rs | 2 +- rust/aura-pm/src/env.rs | 22 +++++++++-- rust/aura-pm/src/error.rs | 1 + rust/aura-pm/src/localization.rs | 1 + rust/r2d2-alpm/Cargo.toml | 6 +-- rust/r2d2-alpm/src/lib.rs | 34 +++++++++++++++- 21 files changed, 171 insertions(+), 64 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 3882fb3e5..11dfc8f6c 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -97,6 +97,8 @@ dependencies = [ "log", "nonempty-collections", "petgraph", + "r2d2", + "r2d2-alpm", "rayon", "serde", "serde_json", @@ -124,6 +126,8 @@ dependencies = [ "nonempty-collections", "num_cpus", "pacmanconf", + "r2d2", + "r2d2-alpm", "rayon", "rust-embed", "rustyline", @@ -1065,6 +1069,28 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r2d2" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" +dependencies = [ + "log", + "parking_lot", + "scheduled-thread-pool", +] + +[[package]] +name = "r2d2-alpm" +version = "0.2.0" +dependencies = [ + "alpm", + "alpm-utils", + "pacmanconf", + "r2d2", + "rayon", +] + [[package]] name = "radix_trie" version = "0.2.1" @@ -1210,6 +1236,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "scheduled-thread-pool" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" +dependencies = [ + "parking_lot", +] + [[package]] name = "scopeguard" version = "1.2.0" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 1d85bc919..9b0ba18ac 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -5,7 +5,7 @@ members = [ # Core libraries "aura-core", # Ecosystem libraries -# "r2d2-alpm", +"r2d2-alpm", # Documentation Generation # "doc-gen" ] diff --git a/rust/aura-core/Cargo.toml b/rust/aura-core/Cargo.toml index a1faa52ef..38e28dc98 100644 --- a/rust/aura-core/Cargo.toml +++ b/rust/aura-core/Cargo.toml @@ -10,6 +10,8 @@ license = "GPL-3.0-only" keywords = ["archlinux", "alpm", "aur", "pacman"] [dependencies] +r2d2-alpm = { version = "0.2", path = "../r2d2-alpm" } + alpm = "3.0" alpm-utils = "3.0" disown = "1.0" @@ -18,6 +20,7 @@ itertools = "0.12" log = "0.4" nonempty-collections = "0.1.4" petgraph = { version = "0.6", default-features = false } +r2d2 = "0.8" rayon = "1.8" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/rust/aura-core/src/aur/dependencies.rs b/rust/aura-core/src/aur/dependencies.rs index 7266e9514..fd04f5d69 100644 --- a/rust/aura-core/src/aur/dependencies.rs +++ b/rust/aura-core/src/aur/dependencies.rs @@ -1,11 +1,13 @@ //! AUR package dependency solving. -use crate::{Alpm, Apply}; +use crate::Apply; use disown::Disown; use log::{debug, info}; use nonempty_collections::NEVec; use petgraph::graph::NodeIndex; use petgraph::Graph; +use r2d2::{ManageConnection, Pool}; +use r2d2_alpm::Alpm; use rayon::iter::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator}; use srcinfo::Srcinfo; use std::borrow::Borrow; @@ -22,6 +24,8 @@ use validated::Validated; pub enum Error { /// A [`Mutex`] was poisoned and couldn't be unlocked. PoisonedMutex, + /// An error pulling from the resource pool. + R2D2(r2d2::Error), /// An error parsing a `.SRCINFO` file. Srcinfo(PathBuf, srcinfo::Error), /// An error cloning or pulling a repo. @@ -46,10 +50,17 @@ impl From for Error { } } +impl From for Error { + fn from(v: r2d2::Error) -> Self { + Self::R2D2(v) + } +} + impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Error::PoisonedMutex => write!(f, "Poisoned Mutex"), + Error::R2D2(e) => write!(f, "{}", e), Error::Resolutions(es) => { writeln!(f, "Errors during dependency resolution:")?; for e in (*es).iter() { @@ -159,14 +170,15 @@ impl Hash for Buildable { } /// Determine all packages to be built and installed. -pub fn resolve<'a, I, F, E>( - alpm: Alpm, +pub fn resolve<'a, I, M, F, E>( + pool: Pool, fetch: &F, clone_d: &Path, pkgs: I, ) -> Result> where I: IntoIterator, + M: ManageConnection, F: Fn(&str) -> Result, E> + Sync, E: Send, { @@ -179,7 +191,7 @@ where let start = OffsetDateTime::now_utc(); orig.par_iter() - .map(|pkg| resolve_one(alpm.clone(), arc.clone(), fetch, clone_d, &orig, None, pkg)) + .map(|pkg| resolve_one(pool.clone(), arc.clone(), fetch, clone_d, &orig, None, pkg)) .collect::>>() .ok() .map_err(|es| Error::Resolutions(Box::new(es)))?; @@ -196,8 +208,8 @@ where Ok(res) } -fn resolve_one( - alpm: Alpm, +fn resolve_one( + pool: Pool, mutx: Arc>, fetch: &F, clone_d: &Path, @@ -206,6 +218,7 @@ fn resolve_one( pkg_raw: &str, ) -> Result<(), Error> where + M: ManageConnection, F: Fn(&str) -> Result, E> + Sync, E: Send, { @@ -224,7 +237,14 @@ where // Checks if the current package is installed or otherwise satisfied by // some package, and then immediately drops the ALPM handle. let satisfied = { - let db = alpm.as_ref().localdb(); + let state = pool.state(); + debug!( + "Trying to get ALPM handle ({} idle connections)", + state.idle_connections + ); + let alpm = pool.get()?; + debug!("Got a handle."); + let db = alpm.alpm.localdb(); db.pkg(pr).is_ok() || db.pkgs().find_satisfier(pr).is_some() }; @@ -236,7 +256,9 @@ where .satisfied .insert(pkg); } else { - match alpm.as_ref().syncdbs().find_satisfier(pr) { + let alpm = pool.get()?; + + match alpm.alpm.syncdbs().find_satisfier(pr) { Some(official) => { debug!("{} is an official package.", pr); @@ -254,16 +276,28 @@ where .map(|d| d.name().to_string()) .collect(); + // FIXME Fri Feb 18 15:07:23 2022 + // + // Manual drops are a signal of bad design. For the moment + // these are necessary to avoid running out of ALPM handles + // when we recurse. + drop(alpm); + deps.into_par_iter() .map(|d| { let p = Some(prnt.as_str()); - resolve_one(alpm.clone(), mutx.clone(), fetch, clone_d, orig, p, &d) + resolve_one(pool.clone(), mutx.clone(), fetch, clone_d, orig, p, &d) }) .collect::>>() .ok() .map_err(|es| Error::Resolutions(Box::new(es)))?; } None => { + // FIXME Fri Feb 18 15:13:31 2022 + // + // Same here as above. + drop(alpm); + debug!("{} is an AUR package.", pr); let path = pull_or_clone(fetch, clone_d, parent, &pkg)?; debug!("Parsing .SRCINFO for {}", pkg); @@ -307,7 +341,7 @@ where .into_par_iter() .map(|p| { let prnt = Some(parent.as_str()); - resolve_one(alpm.clone(), mutx.clone(), fetch, clone_d, orig, prnt, &p) + resolve_one(pool.clone(), mutx.clone(), fetch, clone_d, orig, prnt, &p) }) .collect::>>() .ok() diff --git a/rust/aura-core/src/cache.rs b/rust/aura-core/src/cache.rs index 78fb3ee59..a682cd0d1 100644 --- a/rust/aura-core/src/cache.rs +++ b/rust/aura-core/src/cache.rs @@ -1,6 +1,8 @@ //! Cache manipulation internals. -use crate::{Alpm, Package}; +use r2d2_alpm::Alpm; + +use crate::Package; use std::collections::{HashMap, HashSet}; use std::ffi::OsString; use std::fs::Metadata; diff --git a/rust/aura-core/src/lib.rs b/rust/aura-core/src/lib.rs index 28ce66bdb..57b10ff9b 100644 --- a/rust/aura-core/src/lib.rs +++ b/rust/aura-core/src/lib.rs @@ -17,31 +17,6 @@ use std::borrow::Cow; use std::cmp::Ordering; use std::fs::DirEntry; use std::path::Path; -use std::sync::Arc; - -/// A thread-safe(?) wrapper around a raw [`alpm::Alpm`]. -#[derive(Clone)] -pub struct Alpm { - alpm: Arc, -} - -impl Alpm { - /// Construct a new `Alpm` wrapper from an open connection. - pub fn new(alpm: alpm::Alpm) -> Self { - Self { - alpm: Arc::new(alpm), - } - } -} - -impl AsRef for Alpm { - fn as_ref(&self) -> &alpm::Alpm { - self.alpm.as_ref() - } -} - -unsafe impl Send for Alpm {} -unsafe impl Sync for Alpm {} /// The simplest form a package. #[derive(Debug, PartialEq, Eq)] diff --git a/rust/aura-core/src/snapshot.rs b/rust/aura-core/src/snapshot.rs index ec070f2d0..7706127a8 100644 --- a/rust/aura-core/src/snapshot.rs +++ b/rust/aura-core/src/snapshot.rs @@ -1,5 +1,6 @@ //! Snapshot manipulation internals. +use r2d2_alpm::Alpm; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet}; use std::fs::File; @@ -7,8 +8,6 @@ use std::io::BufReader; use std::path::{Path, PathBuf}; use time::OffsetDateTime; -use crate::Alpm; - /// All packages installed at some specific [`DateTime`]. Any "pinned" snapshot /// should never be considered for deletion. #[derive(Serialize, Deserialize)] diff --git a/rust/aura-pm/Cargo.toml b/rust/aura-pm/Cargo.toml index 1001a1c8f..c304c5c09 100644 --- a/rust/aura-pm/Cargo.toml +++ b/rust/aura-pm/Cargo.toml @@ -15,6 +15,7 @@ path = "src/main.rs" [dependencies] aura-core = { version = "0.2", path = "../aura-core" } +r2d2-alpm = { version = "0.2", path = "../r2d2-alpm" } alpm = "3.0" alpm-utils = "3.0" @@ -30,6 +31,7 @@ log = "0.4" nonempty-collections = "0.1.4" num_cpus = "1.16" pacmanconf = "2.0" +r2d2 = "0.8" rayon = "1.8" rust-embed = "8.0" rustyline = "12" diff --git a/rust/aura-pm/i18n/en-US/aura_pm.ftl b/rust/aura-pm/i18n/en-US/aura_pm.ftl index dd9c5b444..e3672a174 100644 --- a/rust/aura-pm/i18n/en-US/aura_pm.ftl +++ b/rust/aura-pm/i18n/en-US/aura_pm.ftl @@ -202,6 +202,8 @@ err-json-decode = Failed to decode JSON from: { $url } err-json-write = Failed to write JSON to: { $file } err-mutex = A mutex was poisoned. err-none-exist = None of the specified packages exist. +err-pool-create = Failed to create an ALPM connection pool. +err-pool-get = Failed to get an ALPM handle from the connection pool. err-read-dir = Failed to read directory: { $dir } err-srcinfo = Failed to parse .SRCINFO: { $file } err-sudo = Failed to raise privileges. diff --git a/rust/aura-pm/src/command/aur.rs b/rust/aura-pm/src/command/aur.rs index 01cba3055..28c7b4ae7 100644 --- a/rust/aura-pm/src/command/aur.rs +++ b/rust/aura-pm/src/command/aur.rs @@ -7,13 +7,14 @@ use crate::error::Nested; use crate::localization::Localised; use crate::utils::{Finished, PathStr, ResultVoid, NOTHING}; use crate::{aura, green, proceed}; -use aura_core::{Alpm, Apply}; +use aura_core::Apply; use colored::{ColoredString, Colorize}; use from_variants::FromVariants; use i18n_embed::{fluent::FluentLanguageLoader, LanguageLoader}; use i18n_embed_fl::fl; use linya::Progress; use log::{debug, error, info}; +use r2d2_alpm::Alpm; use rayon::prelude::*; use srcinfo::Srcinfo; use std::collections::HashSet; @@ -194,7 +195,7 @@ pub(crate) fn search( ) -> Result<(), Error> { debug!("Searching for: {:?}", terms); - let db = alpm.as_ref().localdb(); + let db = alpm.alpm.localdb(); let rep = "aur/".magenta(); // Sanitize the input. @@ -376,10 +377,10 @@ fn install_work<'a, I>(fll: &FluentLanguageLoader, env: &Env, pkgs: I) -> Result where I: IntoIterator, { - let alpm = env.alpm()?; + let pool = env.alpm_pool()?; aura!(fll, "A-install-deps"); let rslv = aura_core::aur::dependencies::resolve( - alpm, + pool, &crate::fetch::fetch_json, &env.aur.clones, pkgs, @@ -510,7 +511,7 @@ pub(crate) fn upgrade<'a>( &crate::fetch::fetch_json, )?; debug!("Packages pulled: {}", from_api.len()); - let db = alpm.as_ref().localdb(); + let db = alpm.alpm.localdb(); let mut to_upgrade: Vec<(aura_core::Package<'_>, aura_core::Package<'_>)> = from_api .into_iter() .filter_map(|new| db.pkg(new.name.as_str()).ok().map(|old| (old, new))) diff --git a/rust/aura-pm/src/command/cache.rs b/rust/aura-pm/src/command/cache.rs index bddce20ef..bbf5e1bcc 100644 --- a/rust/aura-pm/src/command/cache.rs +++ b/rust/aura-pm/src/command/cache.rs @@ -7,7 +7,6 @@ use crate::localization::Localised; use crate::utils::{PathStr, NOTHING}; use crate::{aura, green, proceed, yellow}; use aura_core::cache::{CacheSize, PkgPath}; -use aura_core::Alpm; use colored::*; use from_variants::FromVariants; use i18n_embed::{fluent::FluentLanguageLoader, LanguageLoader}; @@ -15,6 +14,7 @@ use i18n_embed_fl::fl; use itertools::Itertools; use linya::Progress; use log::{debug, error}; +use r2d2_alpm::Alpm; use rayon::prelude::*; use std::collections::{HashMap, HashSet}; use std::ffi::OsString; diff --git a/rust/aura-pm/src/command/check.rs b/rust/aura-pm/src/command/check.rs index 324aadab8..f75e9f04a 100644 --- a/rust/aura-pm/src/command/check.rs +++ b/rust/aura-pm/src/command/check.rs @@ -5,11 +5,12 @@ use crate::error::Nested; use crate::localization::Localised; use crate::utils::PathStr; use crate::{aura, executable, green}; -use aura_core::Alpm; use colored::*; use from_variants::FromVariants; use i18n_embed::fluent::FluentLanguageLoader; use i18n_embed_fl::fl; +use r2d2::Pool; +use r2d2_alpm::{Alpm, AlpmManager}; use rayon::prelude::*; use std::collections::HashSet; use std::ops::Not; @@ -48,6 +49,7 @@ impl Localised for Error { pub(crate) fn check(fll: &FluentLanguageLoader, env: &Env) -> Result<(), Error> { let caches = env.caches(); let alpm = env.alpm()?; + let pool = env.alpm_pool()?; aura!(fll, "check-start"); environment(fll); @@ -55,7 +57,7 @@ pub(crate) fn check(fll: &FluentLanguageLoader, env: &Env) -> Result<(), Error> pacman_config(fll, &env.pacman, &env.aur); makepkg_config(fll); snapshots(fll, &env.backups.snapshots, &caches); - cache(fll, &alpm, &caches); + cache(fll, &alpm, pool, &caches); green!(fll, "common-done"); Ok(()) @@ -202,12 +204,12 @@ fn usable_snapshots(fll: &FluentLanguageLoader, s_path: &Path, t_path: &[&Path]) } } -fn cache(fll: &FluentLanguageLoader, alpm: &Alpm, caches: &[&Path]) { +fn cache(fll: &FluentLanguageLoader, alpm: &Alpm, pool: Pool, caches: &[&Path]) { aura!(fll, "check-cache"); caches_exist(fll, caches); official_packages_have_tarballs(fll, alpm, caches); foreign_packages_have_tarballs(fll, alpm, caches); - valid_tarballs(fll, alpm, caches); + valid_tarballs(fll, pool, caches); } fn caches_exist(fll: &FluentLanguageLoader, caches: &[&Path]) { @@ -230,10 +232,14 @@ fn caches_exist(fll: &FluentLanguageLoader, caches: &[&Path]) { } /// Is every tarball in the cache valid and loadable by ALPM? -fn valid_tarballs(fll: &FluentLanguageLoader, alpm: &Alpm, caches: &[&Path]) { +fn valid_tarballs(fll: &FluentLanguageLoader, pool: Pool, caches: &[&Path]) { let (goods, bads): (Vec<_>, Vec<_>) = aura_core::cache::package_paths(caches) .par_bridge() - .partition(|pp| aura_core::is_valid_package(&alpm, pp.as_path())); + .partition(|pp| { + pool.get() + .map(|alpm| aura_core::is_valid_package(&*alpm, pp.as_path())) + .unwrap_or(false) + }); let good = bads.is_empty(); let symbol = if good { GOOD.green() } else { BAD.red() }; println!( diff --git a/rust/aura-pm/src/command/deps.rs b/rust/aura-pm/src/command/deps.rs index 1dc345751..6353a51bb 100644 --- a/rust/aura-pm/src/command/deps.rs +++ b/rust/aura-pm/src/command/deps.rs @@ -1,6 +1,7 @@ //! Output a dependency graph in DOT format. -use aura_core::{deps, Alpm}; +use aura_core::deps; +use r2d2_alpm::Alpm; /// Given some packages to focus on, print their combined dependency graph in /// DOT format. diff --git a/rust/aura-pm/src/command/orphans.rs b/rust/aura-pm/src/command/orphans.rs index 701fba097..0d3ec48f4 100644 --- a/rust/aura-pm/src/command/orphans.rs +++ b/rust/aura-pm/src/command/orphans.rs @@ -5,12 +5,13 @@ use crate::green; use crate::localization::Localised; use crate::utils::NOTHING; use alpm::PackageReason; -use aura_core::{Alpm, Apply}; +use aura_core::Apply; use colored::*; use from_variants::FromVariants; use i18n_embed::fluent::FluentLanguageLoader; use i18n_embed_fl::fl; use log::error; +use r2d2_alpm::Alpm; use std::ops::Not; #[derive(FromVariants)] diff --git a/rust/aura-pm/src/command/snapshot.rs b/rust/aura-pm/src/command/snapshot.rs index c9b3ee684..c93300108 100644 --- a/rust/aura-pm/src/command/snapshot.rs +++ b/rust/aura-pm/src/command/snapshot.rs @@ -5,12 +5,12 @@ use crate::localization::Localised; use crate::utils::{PathStr, NOTHING}; use crate::{aura, green, proceed}; use aura_core::snapshot::Snapshot; -use aura_core::Alpm; use colored::*; use from_variants::FromVariants; use i18n_embed::fluent::FluentLanguageLoader; use i18n_embed_fl::fl; use log::error; +use r2d2_alpm::Alpm; use std::cmp::Ordering; use std::collections::{HashMap, HashSet}; use std::fs::File; diff --git a/rust/aura-pm/src/command/stats.rs b/rust/aura-pm/src/command/stats.rs index 3f94c5dfa..b35f575fd 100644 --- a/rust/aura-pm/src/command/stats.rs +++ b/rust/aura-pm/src/command/stats.rs @@ -2,12 +2,12 @@ use crate::error::Nested; use crate::localization::{self, Localised}; -use aura_core::Alpm; use colored::*; use from_variants::FromVariants; use i18n_embed::fluent::FluentLanguageLoader; use i18n_embed_fl::fl; use log::error; +use r2d2_alpm::Alpm; use std::collections::{HashMap, HashSet}; use ubyte::ToByteUnit; use unic_langid::{langid, LanguageIdentifier}; diff --git a/rust/aura-pm/src/env.rs b/rust/aura-pm/src/env.rs index 605ae18c5..b7734c050 100644 --- a/rust/aura-pm/src/env.rs +++ b/rust/aura-pm/src/env.rs @@ -3,10 +3,11 @@ use crate::dirs; use crate::error::Nested; use crate::localization::Localised; -use aura_core::Alpm; use from_variants::FromVariants; use i18n_embed_fl::fl; use log::error; +use r2d2::Pool; +use r2d2_alpm::{Alpm, AlpmManager}; use serde::{Deserialize, Serialize}; use std::collections::HashSet; use std::path::{Path, PathBuf}; @@ -18,6 +19,7 @@ pub(crate) enum Error { Dirs(crate::dirs::Error), PConf(pacmanconf::Error), Alpm(alpm::Error), + R2d2(r2d2::Error), MissingEditor, } @@ -28,6 +30,7 @@ impl Nested for Error { Error::PConf(e) => error!("{e}"), Error::MissingEditor => {} Error::Alpm(e) => error!("{e}"), + Error::R2d2(e) => error!("{e}"), } } } @@ -39,6 +42,7 @@ impl Localised for Error { Error::PConf(_) => fl!(fll, "env-pconf"), Error::MissingEditor => fl!(fll, "env-missing-editor"), Error::Alpm(_) => fl!(fll, "err-alpm"), + Error::R2d2(_) => fl!(fll, "err-pool-create"), } } } @@ -105,11 +109,21 @@ impl Env { Ok(e) } + /// Open a series of connections to ALPM handles. The quantity matches the + /// number of CPUs available on the machine. + pub(crate) fn alpm_pool(&self) -> Result, Error> { + // FIXME Thu Jun 9 13:53:49 2022 + // + // Unfortunate clone here. + let mngr = AlpmManager::new(self.pacman.clone()); + let pool = Pool::builder().max_size(self.general.cpus).build(mngr)?; + + Ok(pool) + } + /// Open a new connection to `alpm` instance. pub(crate) fn alpm(&self) -> Result { - alpm_utils::alpm_with_conf(&self.pacman) - .map_err(Error::Alpm) - .map(Alpm::new) + Alpm::from_config(&self.pacman).map_err(Error::Alpm) } /// All tarball caches across the various config sources. diff --git a/rust/aura-pm/src/error.rs b/rust/aura-pm/src/error.rs index 6f36a79bf..675aaf4b9 100644 --- a/rust/aura-pm/src/error.rs +++ b/rust/aura-pm/src/error.rs @@ -102,6 +102,7 @@ where fn nested(&self) { match self { deps::Error::PoisonedMutex => {} + deps::Error::R2D2(e) => error!("{e}"), deps::Error::Srcinfo(_, e) => error!("{e}"), deps::Error::Git(e) => e.nested(), deps::Error::Resolutions(es) => es.iter().into_iter().for_each(|e| e.nested()), diff --git a/rust/aura-pm/src/localization.rs b/rust/aura-pm/src/localization.rs index 938d87f1a..cb998c085 100644 --- a/rust/aura-pm/src/localization.rs +++ b/rust/aura-pm/src/localization.rs @@ -75,6 +75,7 @@ where fn localise(&self, fll: &FluentLanguageLoader) -> String { match self { deps::Error::PoisonedMutex => fl!(fll, "err-mutex"), + deps::Error::R2D2(_) => fl!(fll, "err-pool-get"), deps::Error::Srcinfo(p, _) => fl!(fll, "err-srcinfo", file = p.utf8()), deps::Error::Git(e) => e.localise(fll), deps::Error::Resolutions(es) => { diff --git a/rust/r2d2-alpm/Cargo.toml b/rust/r2d2-alpm/Cargo.toml index 984a5eb70..f790545fb 100644 --- a/rust/r2d2-alpm/Cargo.toml +++ b/rust/r2d2-alpm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "r2d2-alpm" -version = "0.1.0" +version = "0.2.0" authors = ["Colin Woodbury "] edition = "2021" description = "R2D2 resource pools for managing ALPM connections." @@ -10,8 +10,8 @@ license = "MIT" keywords = ["database", "pool", "archlinux", "alpm", "pacman"] [dependencies] -alpm = "2.2" -alpm-utils = "2.0" +alpm = "3.0" +alpm-utils = "3.0" pacmanconf = "2.0" r2d2 = "0.8" diff --git a/rust/r2d2-alpm/src/lib.rs b/rust/r2d2-alpm/src/lib.rs index f4f946ae3..83a13844e 100644 --- a/rust/r2d2-alpm/src/lib.rs +++ b/rust/r2d2-alpm/src/lib.rs @@ -28,11 +28,41 @@ #![warn(missing_docs)] -use alpm::Alpm; use pacmanconf::Config; use r2d2::ManageConnection; use std::ffi::OsStr; +/// A thread-safe wrapper around a raw [`alpm::Alpm`]. +pub struct Alpm { + /// A wrapper around an inner database handle. + /// + /// At the moment, this handle type isn't `Send`, so we have to trick the + /// compiler into allowing this, such that we can implement + /// [`ManageConnection`] for it. + pub alpm: alpm::Alpm, +} + +impl Alpm { + /// Attempt a database connection via some configuration. + pub fn from_config(config: &Config) -> Result { + alpm_utils::alpm_with_conf(&config).map(Alpm::from) + } +} + +impl From for Alpm { + fn from(alpm: alpm::Alpm) -> Self { + Alpm { alpm } + } +} + +impl AsRef for Alpm { + fn as_ref(&self) -> &alpm::Alpm { + &self.alpm + } +} + +unsafe impl Send for Alpm {} + /// Manage multiple [`Alpm`] handles. pub struct AlpmManager { /// The result of having parsed a `pacman.conf` file. @@ -68,7 +98,7 @@ impl ManageConnection for AlpmManager { type Error = alpm::Error; fn connect(&self) -> Result { - alpm_utils::alpm_with_conf(&self.config) + alpm_utils::alpm_with_conf(&self.config).map(Alpm::from) } fn is_valid(&self, _: &mut Self::Connection) -> Result<(), Self::Error> {