Make machine correctly load state and set previous/current use in API

This commit is contained in:
Nadja Reitzenstein 2021-12-01 15:46:52 +01:00
parent 9fcb7664aa
commit 47781b445e
7 changed files with 131 additions and 34 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "diflouroborane" name = "diflouroborane"
version = "0.3.0" version = "0.3.1"
authors = [ "dequbed <me@dequbed.space>" authors = [ "dequbed <me@dequbed.space>"
, "Kai Jan Kriegel <kai@kjkriegel.de>" , "Kai Jan Kriegel <kai@kjkriegel.de>"
, "Joseph Langosch <thejoklla@gmail.com>" , "Joseph Langosch <thejoklla@gmail.com>"

View File

@ -65,13 +65,52 @@ impl info::Server for Machine {
_: info::GetMachineInfoExtendedParams, _: info::GetMachineInfoExtendedParams,
mut results: info::GetMachineInfoExtendedResults, mut results: info::GetMachineInfoExtendedResults,
) -> Promise<(), capnp::Error> { ) -> Promise<(), capnp::Error> {
if self.perms.manage { let machine = self.machine.get_inner();
let mut builder = results.get(); let perms = self.perms.clone();
let mut extinfo = builder.init_machine_info_extended(); let f = async move {
let mut current = extinfo.init_current_user(); if perms.manage {
current.set_username(&self.userid.uid); let mut builder = results.get();
} let mut extinfo = builder.init_machine_info_extended();
Promise::ok(()) 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( fn get_reservation_list(

View File

@ -24,10 +24,12 @@ pub mod access;
/// Stores&Retrieves Machines /// Stores&Retrieves Machines
pub mod machine; pub mod machine;
pub type MachineDB = machine::internal::Internal;
#[derive(Clone)] #[derive(Clone)]
pub struct Databases { pub struct Databases {
pub access: Arc<access::AccessControl>, pub access: Arc<access::AccessControl>,
pub machine: Arc<machine::internal::Internal>, pub machine: Arc<MachineDB>,
pub userdb: Arc<user::Internal>, pub userdb: Arc<user::Internal>,
} }

View File

@ -75,7 +75,7 @@ impl MachineState {
pub fn init(log: Logger, _config: &Config, env: Arc<lmdb::Environment>) -> Result<Internal> { pub fn init(log: Logger, _config: &Config, env: Arc<lmdb::Environment>) -> Result<Internal> {
let mut flags = lmdb::DatabaseFlags::empty(); 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)?; let machdb = env.create_db(Some("machines"), flags)?;
debug!(&log, "Opened machine db successfully."); debug!(&log, "Opened machine db successfully.");

View File

@ -2,7 +2,7 @@ use std::sync::Arc;
use slog::Logger; use slog::Logger;
use lmdb::{Environment, Transaction, RwTransaction, Cursor}; use lmdb::{Environment, Transaction, RwTransaction, Cursor, RoTransaction};
use super::{MachineIdentifier, MachineState}; use super::{MachineIdentifier, MachineState};
use crate::error::Result; use crate::error::Result;
@ -37,11 +37,11 @@ impl Internal {
self.get_with_txn(&txn, id) 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<()> -> Result<()>
{ {
let bytes = flexbuffers::to_vec(status)?; 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(()) Ok(())
} }
@ -52,11 +52,20 @@ impl Internal {
txn.commit().map_err(Into::into) txn.commit().map_err(Into::into)
} }
pub fn iter<T: Transaction>(&self, txn: &T) -> Result<impl Iterator<Item=MachineState>> { pub fn iter<'txn, T: Transaction>(&self, txn: &'txn T)
-> Result<impl Iterator<Item=(&'txn str, MachineState)>>
{
let mut cursor = txn.open_ro_cursor(self.db)?; let mut cursor = txn.open_ro_cursor(self.db)?;
Ok(cursor.iter_start().map(|buf| { Ok(cursor.iter_start().map(|buf| {
let (_kbuf, vbuf) = buf.unwrap(); let (kbuf, vbuf) = buf.unwrap();
flexbuffers::from_slice(vbuf).unwrap() let id = unsafe { std::str::from_utf8_unchecked(kbuf) };
let state = flexbuffers::from_slice(vbuf).unwrap();
(id, state)
})) }))
} }
pub fn txn(&self) -> Result<RoTransaction> {
let txn = self.env.begin_ro_txn()?;
Ok(txn)
}
} }

View File

@ -19,12 +19,13 @@ use futures::channel::{mpsc, oneshot};
use futures_signals::signal::Signal; use futures_signals::signal::Signal;
use futures_signals::signal::SignalExt; use futures_signals::signal::SignalExt;
use futures_signals::signal::{Mutable, ReadOnlyMutable}; use futures_signals::signal::{Mutable, ReadOnlyMutable};
use slog::Logger;
use crate::error::{Result, Error}; 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::machine::{MachineIdentifier, MachineState, Status};
use crate::db::user::{User, UserData}; use crate::db::user::{User, UserData, UserId};
use crate::network::MachineMap; use crate::network::MachineMap;
use crate::space; use crate::space;
@ -73,13 +74,14 @@ impl Machine {
} }
} }
pub fn construct pub fn construct(
( id: MachineIdentifier id: MachineIdentifier,
, desc: MachineDescription desc: MachineDescription,
, state: MachineState state: MachineState,
) -> Machine db: Arc<MachineDB>,
) -> 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) 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 /// case of an actor it should then make sure that the real world matches up with the set state
state: Mutable<MachineState>, state: Mutable<MachineState>,
reset: Option<MachineState>, reset: Option<MachineState>,
previous: Option<UserId>,
db: Arc<MachineDB>,
} }
impl Inner { impl Inner {
pub fn new ( id: MachineIdentifier pub fn new(id: MachineIdentifier, state: MachineState, db: Arc<MachineDB>) -> Inner {
, state: MachineState
) -> Inner
{
Inner { Inner {
id, id,
state: Mutable::new(state), state: Mutable::new(state),
reset: None, reset: None,
previous: None,
db,
} }
} }
@ -162,8 +167,13 @@ impl Inner {
Box::pin(self.state.signal_cloned().dedupe_cloned()) 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) { 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); self.reset.replace(old_state);
} }
@ -176,9 +186,30 @@ impl Inner {
} }
pub fn reset_state(&mut self) { pub fn reset_state(&mut self) {
if let Some(state) = self.reset.take() { let previous_state = self.read_state();
self.state.replace(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<UserId> {
&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<MachineMap> -> Result<MachineMap>
{ {
let mut map = config.machines.clone(); let mut map = config.machines.clone();
let db = db.machine;
let it = map.drain() let it = map.drain()
.map(|(k,v)| { .map(|(k,v)| {
// TODO: Read state from the state db // 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()))
}
}); });

View File

@ -167,7 +167,16 @@ fn maybe(matches: clap::ArgMatches, log: Arc<Logger>) -> Result<(), Error> {
let ex = Executor::new(); let ex = Executor::new();
let db = db::Databases::new(&log, &config)?; 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 (actor_map, actors) = actor::load(&log, &config)?;
let (init_map, initiators) = initiator::load(&log, &config)?; let (init_map, initiators) = initiator::load(&log, &config)?;