Added more logging and temp files for file linked

This commit is contained in:
vandomej 2021-10-11 23:43:36 -07:00
parent ec54efe8be
commit 7b11578f7a
6 changed files with 142 additions and 38 deletions

View file

@ -19,3 +19,4 @@ serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0" thiserror = "1.0"
anyhow = "1.0" anyhow = "1.0"
bincode = "1.3.3" bincode = "1.3.3"
log = "0.4.14"

17
file_linked/src/error.rs Normal file
View file

@ -0,0 +1,17 @@
use thiserror::Error;
#[derive(Error, Debug)]
pub enum Error {
#[error(transparent)]
Serialization(bincode::Error),
#[error(transparent)]
IO(std::io::Error),
#[error(transparent)]
Other(#[from] anyhow::Error),
}
impl From<std::io::Error> for Error {
fn from(error: std::io::Error) -> Error {
Error::IO(error)
}
}

View file

@ -1,23 +1,15 @@
//! A wrapper around an object that ties it to a physical file //! A wrapper around an object that ties it to a physical file
extern crate serde; pub mod error;
use anyhow::Context; use anyhow::{anyhow, Context};
use error::Error;
use log::info;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde::Serialize; use serde::Serialize;
use std::fs::File; use std::fs::{copy, remove_file, File};
use std::io::ErrorKind;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum Error {
#[error(transparent)]
Serialization(bincode::Error),
#[error(transparent)]
IO(std::io::Error),
#[error(transparent)]
Other(#[from] anyhow::Error),
}
/// A wrapper around an object `T` that ties the object to a physical file /// A wrapper around an object `T` that ties the object to a physical file
#[derive(Debug)] #[derive(Debug)]
@ -27,6 +19,7 @@ where
{ {
val: T, val: T,
path: PathBuf, path: PathBuf,
temp_file_path: PathBuf,
} }
impl<T> FileLinked<T> impl<T> FileLinked<T>
@ -106,21 +99,57 @@ where
/// # } /// # }
/// ``` /// ```
pub fn new(val: T, path: &Path) -> Result<FileLinked<T>, Error> { pub fn new(val: T, path: &Path) -> Result<FileLinked<T>, Error> {
let mut temp_file_path = path.to_path_buf();
temp_file_path.set_file_name(format!(
".temp{}",
path.file_name()
.ok_or_else(|| anyhow!("Unable to get filename for tempfile {}", path.display()))?
.to_str()
.ok_or_else(|| anyhow!("Unable to get filename for tempfile {}", path.display()))?
));
let result = FileLinked { let result = FileLinked {
val, val,
path: path.to_path_buf(), path: path.to_path_buf(),
temp_file_path,
}; };
result.write_data()?; result.write_data()?;
Ok(result) Ok(result)
} }
fn write_data(&self) -> Result<(), Error> { fn write_data(&self) -> Result<(), Error> {
let file = File::create(&self.path) match File::open(&self.path) {
.with_context(|| format!("Unable to open path {}", self.path.display()))?; Ok(_) => {
copy(&self.path, &self.temp_file_path).with_context(|| {
format!(
"Unable to copy temp file from {} to {}",
self.path.display(),
self.temp_file_path.display()
)
})?;
let file = File::create(&self.path)?;
bincode::serialize_into(file, &self.val) bincode::serialize_into(file, &self.val)
.with_context(|| format!("Unable to write to file {}", self.path.display()))?; .with_context(|| format!("Unable to write to file {}", self.path.display()))?;
remove_file(&self.temp_file_path).with_context(|| {
format!(
"Unable to remove temp file {}",
self.temp_file_path.display()
)
})?;
}
Err(error) if error.kind() == ErrorKind::NotFound => {
let file = File::create(&self.path)?;
bincode::serialize_into(file, &self.val)
.with_context(|| format!("Unable to write to file {}", self.path.display()))?;
}
Err(error) => return Err(Error::IO(error)),
}
Ok(()) Ok(())
} }
@ -130,6 +159,7 @@ where
/// # Examples /// # Examples
/// ``` /// ```
/// # use file_linked::*; /// # use file_linked::*;
/// # use file_linked::error::Error;
/// # use serde::{Deserialize, Serialize}; /// # use serde::{Deserialize, Serialize};
/// # use std::fmt; /// # use std::fmt;
/// # use std::string::ToString; /// # use std::string::ToString;
@ -176,6 +206,7 @@ where
/// # Examples /// # Examples
/// ``` /// ```
/// # use file_linked::*; /// # use file_linked::*;
/// # use file_linked::error::Error;
/// # use serde::{Deserialize, Serialize}; /// # use serde::{Deserialize, Serialize};
/// # use std::fmt; /// # use std::fmt;
/// # use std::string::ToString; /// # use std::string::ToString;
@ -229,6 +260,7 @@ where
/// # Examples /// # Examples
/// ``` /// ```
/// # use file_linked::*; /// # use file_linked::*;
/// # use file_linked::error::Error;
/// # use serde::{Deserialize, Serialize}; /// # use serde::{Deserialize, Serialize};
/// # use std::fmt; /// # use std::fmt;
/// # use std::string::ToString; /// # use std::string::ToString;
@ -274,18 +306,66 @@ where
/// # } /// # }
/// ``` /// ```
pub fn from_file(path: &Path) -> Result<FileLinked<T>, Error> { pub fn from_file(path: &Path) -> Result<FileLinked<T>, Error> {
let file = let mut temp_file_path = path.to_path_buf();
File::open(path).with_context(|| format!("Unable to open file {}", path.display()))?; temp_file_path.set_file_name(format!(
".temp{}",
path.file_name()
.ok_or_else(|| anyhow!("Unable to get filename for tempfile {}", path.display()))?
.to_str()
.ok_or_else(|| anyhow!("Unable to get filename for tempfile {}", path.display()))?
));
let val = bincode::deserialize_from(file) match File::open(path).map_err(Error::from).and_then(|file| {
.with_context(|| String::from("Unable to parse value from file."))?; bincode::deserialize_from::<std::fs::File, T>(file)
.with_context(|| format!("Unable to deserialize file {}", path.display()))
.map_err(Error::from)
}) {
Ok(val) => Ok(FileLinked {
val,
path: path.to_path_buf(),
temp_file_path,
}),
Err(err) => {
info!(
"Unable to read/deserialize file {} attempting to open temp file {}",
path.display(),
temp_file_path.display()
);
// Try to use temp file instead and see if that file exists and is serializable
let val = FileLinked::from_temp_file(&temp_file_path, path)
.map_err(|_| err)
.with_context(|| format!("Failed to read/deserialize the object from the file {} and temp file {}", path.display(), temp_file_path.display()))?;
Ok(FileLinked { Ok(FileLinked {
val, val,
path: path.to_path_buf(), path: path.to_path_buf(),
temp_file_path,
}) })
} }
} }
}
fn from_temp_file(temp_file_path: &Path, path: &Path) -> Result<T, Error> {
let file = File::open(temp_file_path)
.with_context(|| format!("Unable to open file {}", temp_file_path.display()))?;
let val = bincode::deserialize_from(file).with_context(|| {
format!(
"Could not deserialize from temp file {}",
temp_file_path.display()
)
})?;
info!("Successfully deserialized value from temp file");
copy(temp_file_path, path)?;
remove_file(temp_file_path)
.with_context(|| format!("Unable to remove temp file {}", temp_file_path.display()))?;
Ok(val)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View file

@ -10,8 +10,8 @@ use clap::App;
use gemla::core::{Gemla, GemlaConfig}; use gemla::core::{Gemla, GemlaConfig};
use gemla::error::log_error; use gemla::error::log_error;
use std::path::PathBuf; use std::path::PathBuf;
use test_state::TestState;
use std::time::Instant; use std::time::Instant;
use test_state::TestState;
// use std::io::Write; // use std::io::Write;
/// Runs a simluation of a genetic algorithm against a dataset. /// Runs a simluation of a genetic algorithm against a dataset.

View file

@ -8,9 +8,9 @@ use crate::tree::Tree;
use anyhow::anyhow; use anyhow::anyhow;
use file_linked::FileLinked; use file_linked::FileLinked;
use genetic_node::{GeneticNode, GeneticNodeWrapper, GeneticState}; use genetic_node::{GeneticNode, GeneticNodeWrapper, GeneticState};
use log::{info, trace};
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use log::{info, trace};
use std::fmt::Debug; use std::fmt::Debug;
use std::fs::File; use std::fs::File;
use std::io::ErrorKind; use std::io::ErrorKind;
@ -67,7 +67,10 @@ where
self.data self.data
.mutate(|(d, c)| Gemla::increase_height(d, c, steps))??; .mutate(|(d, c)| Gemla::increase_height(d, c, steps))??;
info!("Height of simulation tree increased to {}", self.data.readonly().0.as_ref().unwrap().height()); info!(
"Height of simulation tree increased to {}",
self.data.readonly().0.as_ref().unwrap().height()
);
self.data self.data
.mutate(|(d, _c)| Gemla::process_tree(d.as_mut().unwrap()))??; .mutate(|(d, _c)| Gemla::process_tree(d.as_mut().unwrap()))??;
@ -146,7 +149,11 @@ where
break; break;
} }
trace!("{:?} completed in {:?}", node_state, node_state_time.elapsed()); trace!(
"{:?} completed in {:?}",
node_state,
node_state_time.elapsed()
);
} }
info!("Processed node in {:?}", node_time.elapsed()); info!("Processed node in {:?}", node_time.elapsed());

View file

@ -1,20 +1,20 @@
use thiserror::Error;
use log::error; use log::error;
use thiserror::Error;
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum Error { pub enum Error {
#[error(transparent)] #[error(transparent)]
FileLinked(file_linked::Error), FileLinked(file_linked::error::Error),
#[error(transparent)] #[error(transparent)]
IO(std::io::Error), IO(std::io::Error),
#[error(transparent)] #[error(transparent)]
Other(#[from] anyhow::Error), Other(#[from] anyhow::Error),
} }
impl From<file_linked::Error> for Error { impl From<file_linked::error::Error> for Error {
fn from(error: file_linked::Error) -> Error { fn from(error: file_linked::error::Error) -> Error {
match error { match error {
file_linked::Error::Other(e) => Error::Other(e), file_linked::error::Error::Other(e) => Error::Other(e),
_ => Error::FileLinked(error), _ => Error::FileLinked(error),
} }
} }
@ -32,4 +32,3 @@ pub fn log_error<T>(result: Result<T, Error>) -> Result<T, Error> {
e e
}) })
} }