From 47781b445e474ebd3ab45754aab2713cfaaed297 Mon Sep 17 00:00:00 2001 From: Nadja Reitzenstein Date: Wed, 1 Dec 2021 15:46:52 +0100 Subject: [PATCH] Make machine correctly load state and set previous/current use in API --- Cargo.toml | 2 +- src/api/machine.rs | 53 ++++++++++++++++++++++++---- src/db.rs | 4 ++- src/db/machine.rs | 2 +- src/db/machine/internal.rs | 21 +++++++---- src/machine.rs | 72 +++++++++++++++++++++++++++++--------- src/main.rs | 11 +++++- 7 files changed, 131 insertions(+), 34 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a2747b1..c588f69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "diflouroborane" -version = "0.3.0" +version = "0.3.1" authors = [ "dequbed " , "Kai Jan Kriegel " , "Joseph Langosch " diff --git a/src/api/machine.rs b/src/api/machine.rs index d0a8e72..65eb8d0 100644 --- a/src/api/machine.rs +++ b/src/api/machine.rs @@ -65,13 +65,52 @@ impl info::Server for Machine { _: info::GetMachineInfoExtendedParams, mut results: info::GetMachineInfoExtendedResults, ) -> Promise<(), capnp::Error> { - if self.perms.manage { - let mut builder = results.get(); - let mut extinfo = builder.init_machine_info_extended(); - let mut current = extinfo.init_current_user(); - current.set_username(&self.userid.uid); - } - Promise::ok(()) + let machine = self.machine.get_inner(); + let perms = self.perms.clone(); + let f = async move { + if perms.manage { + let mut builder = results.get(); + let mut extinfo = builder.init_machine_info_extended(); + let guard = machine.lock().await; + + // "previous" user + if let Some(user) = guard.get_previous() { + let mut previous = extinfo.reborrow().init_transfer_user(); + previous.set_username(&user.uid); + } + + let state = guard.read_state(); + let state_lock = state.lock_ref(); + match state_lock.state { + Status::Free => {} + Status::InUse(ref user) => if user.is_some() { + let user = user.as_ref().unwrap(); + let mut current = extinfo.init_current_user(); + current.set_username(&user.uid); + } + Status::ToCheck(ref user) => { + let mut current = extinfo.init_current_user(); + current.set_username(&user.uid); + } + Status::Blocked(ref user) => { + let mut current = extinfo.init_current_user(); + current.set_username(&user.uid); + } + Status::Disabled => {} + Status::Reserved(ref user) => { + let mut current = extinfo.init_current_user(); + current.set_username(&user.uid); + } + } + } + + Ok(()) + }; + + let g = smol::future::race(f, smol::Timer::after(Duration::from_secs(4)) + .map(|_| Err(capnp::Error::failed("Waiting for machine lock timed out!".to_string())))); + + Promise::from_future(g) } fn get_reservation_list( diff --git a/src/db.rs b/src/db.rs index d4c1305..be802e6 100644 --- a/src/db.rs +++ b/src/db.rs @@ -24,10 +24,12 @@ pub mod access; /// Stores&Retrieves Machines pub mod machine; +pub type MachineDB = machine::internal::Internal; + #[derive(Clone)] pub struct Databases { pub access: Arc, - pub machine: Arc, + pub machine: Arc, pub userdb: Arc, } diff --git a/src/db/machine.rs b/src/db/machine.rs index 01b8002..7e371c4 100644 --- a/src/db/machine.rs +++ b/src/db/machine.rs @@ -75,7 +75,7 @@ impl MachineState { pub fn init(log: Logger, _config: &Config, env: Arc) -> Result { let mut flags = lmdb::DatabaseFlags::empty(); - flags.set(lmdb::DatabaseFlags::INTEGER_KEY, true); + //flags.set(lmdb::DatabaseFlags::INTEGER_KEY, true); let machdb = env.create_db(Some("machines"), flags)?; debug!(&log, "Opened machine db successfully."); diff --git a/src/db/machine/internal.rs b/src/db/machine/internal.rs index 9ae80be..99f36fa 100644 --- a/src/db/machine/internal.rs +++ b/src/db/machine/internal.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use slog::Logger; -use lmdb::{Environment, Transaction, RwTransaction, Cursor}; +use lmdb::{Environment, Transaction, RwTransaction, Cursor, RoTransaction}; use super::{MachineIdentifier, MachineState}; use crate::error::Result; @@ -37,11 +37,11 @@ impl Internal { self.get_with_txn(&txn, id) } - pub fn put_with_txn(&self, txn: &mut RwTransaction, uuid: &String, status: &MachineState) + pub fn put_with_txn(&self, txn: &mut RwTransaction, id: &String, status: &MachineState) -> Result<()> { let bytes = flexbuffers::to_vec(status)?; - txn.put(self.db, &uuid.as_bytes(), &bytes, lmdb::WriteFlags::empty())?; + txn.put(self.db, &id.as_bytes(), &bytes, lmdb::WriteFlags::empty())?; Ok(()) } @@ -52,11 +52,20 @@ impl Internal { txn.commit().map_err(Into::into) } - pub fn iter(&self, txn: &T) -> Result> { + pub fn iter<'txn, T: Transaction>(&self, txn: &'txn T) + -> Result> + { let mut cursor = txn.open_ro_cursor(self.db)?; Ok(cursor.iter_start().map(|buf| { - let (_kbuf, vbuf) = buf.unwrap(); - flexbuffers::from_slice(vbuf).unwrap() + let (kbuf, vbuf) = buf.unwrap(); + let id = unsafe { std::str::from_utf8_unchecked(kbuf) }; + let state = flexbuffers::from_slice(vbuf).unwrap(); + (id, state) })) } + + pub fn txn(&self) -> Result { + let txn = self.env.begin_ro_txn()?; + Ok(txn) + } } diff --git a/src/machine.rs b/src/machine.rs index 6c7b004..18f9afe 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -19,12 +19,13 @@ use futures::channel::{mpsc, oneshot}; use futures_signals::signal::Signal; use futures_signals::signal::SignalExt; use futures_signals::signal::{Mutable, ReadOnlyMutable}; +use slog::Logger; use crate::error::{Result, Error}; -use crate::db::access; +use crate::db::{access, Databases, MachineDB}; use crate::db::machine::{MachineIdentifier, MachineState, Status}; -use crate::db::user::{User, UserData}; +use crate::db::user::{User, UserData, UserId}; use crate::network::MachineMap; use crate::space; @@ -73,13 +74,14 @@ impl Machine { } } - pub fn construct - ( id: MachineIdentifier - , desc: MachineDescription - , state: MachineState - ) -> Machine + pub fn construct( + id: MachineIdentifier, + desc: MachineDescription, + state: MachineState, + db: Arc, + ) -> Machine { - Self::new(Inner::new(id, state), desc) + Self::new(Inner::new(id, state, db), desc) } pub fn do_state_change(&self, new_state: MachineState) @@ -136,17 +138,20 @@ pub struct Inner { /// case of an actor it should then make sure that the real world matches up with the set state state: Mutable, reset: Option, + + previous: Option, + + db: Arc, } impl Inner { - pub fn new ( id: MachineIdentifier - , state: MachineState - ) -> Inner - { + pub fn new(id: MachineIdentifier, state: MachineState, db: Arc) -> Inner { Inner { id, state: Mutable::new(state), reset: None, + previous: None, + db, } } @@ -162,8 +167,13 @@ impl Inner { Box::pin(self.state.signal_cloned().dedupe_cloned()) } + fn replace_state(&mut self, new_state: MachineState) -> MachineState { + self.db.put(&self.id, &new_state); + self.state.replace(new_state) + } + pub fn do_state_change(&mut self, new_state: MachineState) { - let old_state = self.state.replace(new_state); + let old_state = self.replace_state(new_state); self.reset.replace(old_state); } @@ -176,9 +186,30 @@ impl Inner { } pub fn reset_state(&mut self) { - if let Some(state) = self.reset.take() { - self.state.replace(state); + let previous_state = self.read_state(); + let state_lock = previous_state.lock_ref(); + // Only update previous user if state changed from InUse or ToCheck to whatever. + match state_lock.state { + Status::InUse(ref user) => { + self.previous = user.clone(); + }, + Status::ToCheck(ref user) => { + self.previous = Some(user.clone()); + }, + _ => {}, } + drop(state_lock); + + if let Some(state) = self.reset.take() { + self.replace_state(state); + } else { + // Default to Free + self.replace_state(MachineState::free()); + } + } + + pub fn get_previous(&self) -> &Option { + &self.previous } } @@ -242,15 +273,22 @@ impl MachineDescription { } } -pub fn load(config: &crate::config::Config) +pub fn load(config: &crate::config::Config, db: Databases, log: &Logger) -> Result { let mut map = config.machines.clone(); + let db = db.machine; let it = map.drain() .map(|(k,v)| { // TODO: Read state from the state db - (v.name.clone(), Machine::construct(k, v, MachineState::new())) + if let Some(state) = db.get(&k).unwrap() { + debug!(log, "Loading old state from db for {}: {:?}", &k, &state); + (v.name.clone(), Machine::construct(k, v, state, db.clone())) + } else { + debug!(log, "No old state found in db for {}, creating new.", &k); + (v.name.clone(), Machine::construct(k, v, MachineState::new(), db.clone())) + } }); diff --git a/src/main.rs b/src/main.rs index 5d73524..5543f88 100644 --- a/src/main.rs +++ b/src/main.rs @@ -167,7 +167,16 @@ fn maybe(matches: clap::ArgMatches, log: Arc) -> Result<(), Error> { let ex = Executor::new(); let db = db::Databases::new(&log, &config)?; - let machines = machine::load(&config)?; + { + info!(log, "Loaded DB state:"); + let txn = db.machine.txn()?; + for (id, state) in db.machine.iter(&txn)? { + info!(log, "- {}: {:?}", id, state); + } + info!(log, "Loaded DB state END."); + } + + let machines = machine::load(&config, db.clone(), &log)?; let (actor_map, actors) = actor::load(&log, &config)?; let (init_map, initiators) = initiator::load(&log, &config)?;