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

@ -18,4 +18,5 @@ categories = ["filesystem", "data-structures"]
serde = { version = "1.0", features = ["derive"] }
thiserror = "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
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::Serialize;
use std::fs::File;
use std::fs::{copy, remove_file, File};
use std::io::ErrorKind;
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
#[derive(Debug)]
@ -27,6 +19,7 @@ where
{
val: T,
path: PathBuf,
temp_file_path: PathBuf,
}
impl<T> FileLinked<T>
@ -106,20 +99,56 @@ where
/// # }
/// ```
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 {
val,
path: path.to_path_buf(),
temp_file_path,
};
result.write_data()?;
Ok(result)
}
fn write_data(&self) -> Result<(), Error> {
let file = File::create(&self.path)
.with_context(|| format!("Unable to open path {}", self.path.display()))?;
match File::open(&self.path) {
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()
)
})?;
bincode::serialize_into(file, &self.val)
.with_context(|| format!("Unable to write to file {}", self.path.display()))?;
let file = File::create(&self.path)?;
bincode::serialize_into(file, &self.val)
.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(())
}
@ -130,6 +159,7 @@ where
/// # Examples
/// ```
/// # use file_linked::*;
/// # use file_linked::error::Error;
/// # use serde::{Deserialize, Serialize};
/// # use std::fmt;
/// # use std::string::ToString;
@ -176,6 +206,7 @@ where
/// # Examples
/// ```
/// # use file_linked::*;
/// # use file_linked::error::Error;
/// # use serde::{Deserialize, Serialize};
/// # use std::fmt;
/// # use std::string::ToString;
@ -229,6 +260,7 @@ where
/// # Examples
/// ```
/// # use file_linked::*;
/// # use file_linked::error::Error;
/// # use serde::{Deserialize, Serialize};
/// # use std::fmt;
/// # use std::string::ToString;
@ -274,16 +306,64 @@ where
/// # }
/// ```
pub fn from_file(path: &Path) -> Result<FileLinked<T>, Error> {
let file =
File::open(path).with_context(|| format!("Unable to open file {}", path.display()))?;
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 val = bincode::deserialize_from(file)
.with_context(|| String::from("Unable to parse value from file."))?;
match File::open(path).map_err(Error::from).and_then(|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()
);
Ok(FileLinked {
val,
path: path.to_path_buf(),
})
// 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 {
val,
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)
}
}

View file

@ -10,8 +10,8 @@ use clap::App;
use gemla::core::{Gemla, GemlaConfig};
use gemla::error::log_error;
use std::path::PathBuf;
use test_state::TestState;
use std::time::Instant;
use test_state::TestState;
// use std::io::Write;
/// Runs a simluation of a genetic algorithm against a dataset.
@ -21,7 +21,7 @@ use std::time::Instant;
fn main() -> anyhow::Result<()> {
env_logger::init();
info!("Starting");
let now = Instant::now();
// Command line arguments are parsed with the clap crate. And this program uses

View file

@ -8,9 +8,9 @@ use crate::tree::Tree;
use anyhow::anyhow;
use file_linked::FileLinked;
use genetic_node::{GeneticNode, GeneticNodeWrapper, GeneticState};
use log::{info, trace};
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use log::{info, trace};
use std::fmt::Debug;
use std::fs::File;
use std::io::ErrorKind;
@ -67,7 +67,10 @@ where
self.data
.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
.mutate(|(d, _c)| Gemla::process_tree(d.as_mut().unwrap()))??;
@ -146,7 +149,11 @@ where
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());

View file

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