mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
Feat bulk locking (#1422)
* Feat: Multi-lock capabilities add to config * wip: RPC.rs fixes, new combinatoric * wip: changes * chore: More things that are bulk * fix: Saving * chore: Remove a dyn object * chore: Add tests + remove unused * Fix/feat bulk locking (#1427) * fix: health check * fix: start/stop service * fix: install/uninstall services * chore: Fix the notifications * fix: Version * fix: Version as serde * chore: Update to latest patch db * chore: Change the htLock to something that makes more sense * chore: Fix the rest of the ht * "chore: More ht_lock":
This commit is contained in:
@@ -1,11 +1,10 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use color_eyre::eyre::eyre;
|
||||
use patch_db::{DbHandle, LockType};
|
||||
use patch_db::{DbHandle, LockReceipt, LockType};
|
||||
use rpc_toolkit::command;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::context::RpcContext;
|
||||
use crate::db::util::WithRevision;
|
||||
use crate::dependencies::{
|
||||
break_all_dependents_transitive, heal_all_dependents_transitive, BreakageRes, DependencyError,
|
||||
@@ -15,8 +14,53 @@ use crate::s9pk::manifest::PackageId;
|
||||
use crate::status::MainStatus;
|
||||
use crate::util::display_none;
|
||||
use crate::util::serde::display_serializable;
|
||||
use crate::{context::RpcContext, dependencies::DependencyReceipt};
|
||||
use crate::{Error, ResultExt};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StartReceipts {
|
||||
dependency_receipt: DependencyReceipt,
|
||||
status: LockReceipt<MainStatus, ()>,
|
||||
version: LockReceipt<crate::util::Version, ()>,
|
||||
}
|
||||
|
||||
impl StartReceipts {
|
||||
pub async fn new<'a>(db: &'a mut impl DbHandle, id: &PackageId) -> Result<Self, Error> {
|
||||
let mut locks = Vec::new();
|
||||
|
||||
let setup = Self::setup(&mut locks, id);
|
||||
Ok(setup(&db.lock_all(locks).await?)?)
|
||||
}
|
||||
|
||||
pub fn setup(
|
||||
locks: &mut Vec<patch_db::LockTargetId>,
|
||||
id: &PackageId,
|
||||
) -> impl FnOnce(&patch_db::Verifier) -> Result<Self, Error> {
|
||||
let dependency_receipt = DependencyReceipt::setup(locks);
|
||||
let status = crate::db::DatabaseModel::new()
|
||||
.package_data()
|
||||
.idx_model(id)
|
||||
.and_then(|x| x.installed())
|
||||
.map(|x| x.status().main())
|
||||
.make_locker(LockType::Write)
|
||||
.add_to_keys(locks);
|
||||
let version = crate::db::DatabaseModel::new()
|
||||
.package_data()
|
||||
.idx_model(id)
|
||||
.and_then(|x| x.installed())
|
||||
.map(|x| x.manifest().version())
|
||||
.make_locker(LockType::Read)
|
||||
.add_to_keys(locks);
|
||||
move |skeleton_key| {
|
||||
Ok(Self {
|
||||
dependency_receipt: dependency_receipt(skeleton_key)?,
|
||||
status: status.verify(skeleton_key)?,
|
||||
version: version.verify(skeleton_key)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[command(display(display_none))]
|
||||
#[instrument(skip(ctx))]
|
||||
pub async fn start(
|
||||
@@ -25,37 +69,13 @@ pub async fn start(
|
||||
) -> Result<WithRevision<()>, Error> {
|
||||
let mut db = ctx.db.handle();
|
||||
let mut tx = db.begin().await?;
|
||||
crate::db::DatabaseModel::new()
|
||||
.package_data()
|
||||
.lock(&mut tx, LockType::Write)
|
||||
.await?;
|
||||
let installed = crate::db::DatabaseModel::new()
|
||||
.package_data()
|
||||
.idx_model(&id)
|
||||
.and_then(|pkg| pkg.installed())
|
||||
.expect(&mut tx)
|
||||
.await
|
||||
.with_ctx(|_| {
|
||||
(
|
||||
crate::ErrorKind::NotFound,
|
||||
format!("{} is not installed", id),
|
||||
)
|
||||
})?;
|
||||
installed.lock(&mut tx, LockType::Read).await?;
|
||||
let version = installed
|
||||
.clone()
|
||||
.manifest()
|
||||
.version()
|
||||
.get(&mut tx, true)
|
||||
.await?
|
||||
.to_owned();
|
||||
let mut status = installed.status().main().get_mut(&mut tx).await?;
|
||||
|
||||
*status = MainStatus::Starting;
|
||||
status.save(&mut tx).await?;
|
||||
heal_all_dependents_transitive(&ctx, &mut tx, &id).await?;
|
||||
let receipts = StartReceipts::new(&mut tx, &id).await?;
|
||||
let version = receipts.version.get(&mut tx).await?;
|
||||
receipts.status.set(&mut tx, MainStatus::Starting).await?;
|
||||
heal_all_dependents_transitive(&ctx, &mut tx, &id, &receipts.dependency_receipt).await?;
|
||||
|
||||
let revision = tx.commit(None).await?;
|
||||
drop(receipts);
|
||||
|
||||
ctx.managers
|
||||
.get(&(id, version))
|
||||
@@ -69,6 +89,40 @@ pub async fn start(
|
||||
response: (),
|
||||
})
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub struct StopReceipts {
|
||||
breaks: crate::dependencies::BreakTransitiveReceipts,
|
||||
status: LockReceipt<MainStatus, ()>,
|
||||
}
|
||||
|
||||
impl StopReceipts {
|
||||
pub async fn new<'a>(db: &'a mut impl DbHandle, id: &PackageId) -> Result<Self, Error> {
|
||||
let mut locks = Vec::new();
|
||||
|
||||
let setup = Self::setup(&mut locks, id);
|
||||
Ok(setup(&db.lock_all(locks).await?)?)
|
||||
}
|
||||
|
||||
pub fn setup(
|
||||
locks: &mut Vec<patch_db::LockTargetId>,
|
||||
id: &PackageId,
|
||||
) -> impl FnOnce(&patch_db::Verifier) -> Result<Self, Error> {
|
||||
let breaks = crate::dependencies::BreakTransitiveReceipts::setup(locks);
|
||||
let status = crate::db::DatabaseModel::new()
|
||||
.package_data()
|
||||
.idx_model(id)
|
||||
.and_then(|x| x.installed())
|
||||
.map(|x| x.status().main())
|
||||
.make_locker(LockType::Write)
|
||||
.add_to_keys(locks);
|
||||
move |skeleton_key| {
|
||||
Ok(Self {
|
||||
breaks: breaks(skeleton_key)?,
|
||||
status: status.verify(skeleton_key)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(db))]
|
||||
async fn stop_common<Db: DbHandle>(
|
||||
@@ -77,27 +131,18 @@ async fn stop_common<Db: DbHandle>(
|
||||
breakages: &mut BTreeMap<PackageId, TaggedDependencyError>,
|
||||
) -> Result<(), Error> {
|
||||
let mut tx = db.begin().await?;
|
||||
let mut status = crate::db::DatabaseModel::new()
|
||||
.package_data()
|
||||
.idx_model(&id)
|
||||
.and_then(|pkg| pkg.installed())
|
||||
.expect(&mut tx)
|
||||
.await
|
||||
.with_ctx(|_| {
|
||||
(
|
||||
crate::ErrorKind::NotFound,
|
||||
format!("{} is not installed", id),
|
||||
)
|
||||
})?
|
||||
.status()
|
||||
.main()
|
||||
.get_mut(&mut tx)
|
||||
.await?;
|
||||
let receipts = StopReceipts::new(&mut tx, id).await?;
|
||||
receipts.status.set(&mut tx, MainStatus::Stopping).await?;
|
||||
|
||||
*status = MainStatus::Stopping;
|
||||
status.save(&mut tx).await?;
|
||||
tx.save().await?;
|
||||
break_all_dependents_transitive(db, &id, DependencyError::NotRunning, breakages).await?;
|
||||
break_all_dependents_transitive(
|
||||
db,
|
||||
id,
|
||||
DependencyError::NotRunning,
|
||||
breakages,
|
||||
&receipts.breaks,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user