blkar_lib/
log.rs

1use file_reader::{FileReader,
2                  FileReaderParam};
3use file_writer::{FileWriter,
4                  FileWriterParam};
5use general_error::Error;
6use std::fmt;
7
8use std::time::Duration;
9
10use std::sync::atomic::AtomicBool;
11use std::sync::atomic::Ordering;
12
13use std::sync::Arc;
14use std::sync::Mutex;
15
16use std::thread;
17
18const LOG_MAX_SIZE : usize = 1024;
19
20const LOG_WRITE_INTERVAL_IN_MILLISEC : u64 = 1000;
21
22pub struct LogHandler<T : 'static + Log + Send> {
23    log_file   : Option<String>,
24    stats      : Arc<Mutex<T>>,
25    write_flag : Arc<AtomicBool>,
26}
27
28#[derive(Clone, Copy, PartialEq)]
29pub enum ErrorKind {
30    ParseError,
31}
32
33#[derive(Clone)]
34pub struct LogError {
35    kind : ErrorKind,
36    path : String,
37}
38
39impl fmt::Display for LogError {
40    fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result {
41        use self::ErrorKind::*;
42        match self.kind {
43            ParseError => write!(f, "failed to parse log file \"{}\"", self.path),
44        }
45    }
46}
47
48impl LogError {
49    pub fn new(kind : ErrorKind, path : &str) -> LogError {
50        LogError {
51            kind,
52            path : String::from(path),
53        }
54    }
55}
56
57pub fn to_err(e : LogError) -> super::Error {
58    use super::{Error, ErrorKind};
59    Error::new(ErrorKind::LogError(e))
60}
61
62pub trait Log {
63    fn serialize(&self) -> String;
64
65    fn deserialize(&mut self, &[u8]) -> Result<(), ()>;
66
67    fn read_from_file(&mut self, log_file : &str) -> Result<(), Error> {
68        let mut reader = FileReader::new(log_file,
69                                         FileReaderParam { write    : false,
70                                                           buffered : false  })?;
71        let mut buffer : [u8; LOG_MAX_SIZE] = [0; LOG_MAX_SIZE];
72        let _len_read = reader.read(&mut buffer)?;
73
74        match self.deserialize(&buffer) {
75            Ok(())  => Ok(()),
76            Err(()) => Err(to_err(LogError::new(ErrorKind::ParseError, log_file))),
77        }
78    }
79
80    fn write_to_file(&self, log_file : &str) -> Result<(), Error> {
81        let mut writer = FileWriter::new(log_file,
82                                         FileWriterParam { read     : false,
83                                                           append   : false,
84                                                           buffered : false  })?;
85        let output = self.serialize();
86
87        let _len_written = writer.write(output.as_bytes())?;
88
89        Ok(())
90    }
91}
92
93impl<T : 'static + Log + Send> LogHandler<T> {
94    pub fn new(log_file : Option<&str>,
95               stats    : &Arc<Mutex<T>>) -> LogHandler<T> {
96        let log_file = match log_file {
97            None         => None,
98            Some(ref lg) => Some(lg.to_string()),
99        };
100        let write_flag = Arc::new(AtomicBool::new(true));
101        let runner_write_flag = Arc::clone(&write_flag);
102        thread::spawn(move || {
103            loop {
104                runner_write_flag.store(true, Ordering::Relaxed);
105
106                thread::sleep(Duration::from_millis(LOG_WRITE_INTERVAL_IN_MILLISEC));
107            }
108        });
109        LogHandler {
110            log_file,
111            stats    : Arc::clone(stats),
112            write_flag,
113        }
114    }
115
116    pub fn read_from_file(&self) -> Result<(), Error> {
117        use super::ErrorKind;
118        use super::file_error;
119
120        match self.log_file {
121            None         => Ok(()),
122            Some(ref lg) => {
123                let res = self.stats.lock().unwrap().read_from_file(lg);
124
125                if let Err(ref e) = res {
126                    if let ErrorKind::FileError(ref fe) = e.kind {
127                        if let file_error::ErrorKind::NotFound = fe.kind {
128                            return Ok(());
129                        }
130                    }
131                }
132                res
133            }
134        }
135    }
136
137    pub fn write_to_file(&self, force_write : bool) -> Result<(), Error> {
138        if force_write || self.write_flag.swap(false, Ordering::SeqCst) {
139            match self.log_file {
140                None        => {},
141                Some(ref x) => self.stats.lock().unwrap().write_to_file(x)?,
142            }
143        }
144
145        Ok(())
146    }
147}