Added more logging and temp files for file linked
This commit is contained in:
parent
ec54efe8be
commit
7b11578f7a
6 changed files with 142 additions and 38 deletions
|
@ -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
17
file_linked/src/error.rs
Normal 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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
})
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue