parent
5ba82a6cf0
commit
be540a7ded
@ -1,150 +0,0 @@
|
||||
/*
|
||||
* Created on Mon May 29 2023
|
||||
*
|
||||
* This file is a part of Skytable
|
||||
* Skytable (formerly known as TerrabaseDB or Skybase) is a free and open-source
|
||||
* NoSQL database written by Sayan Nandan ("the Author") with the
|
||||
* vision to provide flexibility in data modelling without compromising
|
||||
* on performance, queryability or scalability.
|
||||
*
|
||||
* Copyright (c) 2023, Sayan Nandan <ohsayan@outlook.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
use {
|
||||
super::{SDSSError, SDSSErrorContext, SDSSResult},
|
||||
crate::util::os,
|
||||
std::{
|
||||
fs::File,
|
||||
io::{ErrorKind, Read, Write},
|
||||
},
|
||||
};
|
||||
|
||||
#[cfg(not(test))]
|
||||
const START_FILE: &'static str = ".start";
|
||||
#[cfg(test)]
|
||||
const START_FILE: &'static str = ".start_testmode";
|
||||
#[cfg(not(test))]
|
||||
const STOP_FILE: &'static str = ".stop";
|
||||
#[cfg(test)]
|
||||
const STOP_FILE: &'static str = ".stop_testmode";
|
||||
|
||||
const EMSG_FAILED_WRITE_START_FILE: &str =
|
||||
concat_str_to_str!("failed to write to `", START_FILE, "` file");
|
||||
const EMSG_FAILED_WRITE_STOP_FILE: &str =
|
||||
concat_str_to_str!("failed to write to `", STOP_FILE, "` file");
|
||||
const EMSG_FAILED_OPEN_START_FILE: &str =
|
||||
concat_str_to_str!("failed to open `", START_FILE, "` file");
|
||||
const EMSG_FAILED_OPEN_STOP_FILE: &str =
|
||||
concat_str_to_str!("failed to open `", STOP_FILE, "` file");
|
||||
const EMSG_FAILED_VERIFY: &str = concat_str_to_str!(
|
||||
"failed to verify `",
|
||||
START_FILE,
|
||||
concat_str_to_str!("` and `", STOP_FILE, "` timestamps")
|
||||
);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StartStop {
|
||||
begin: u128,
|
||||
stop_file: File,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ReadNX {
|
||||
Created(File),
|
||||
Read(File, u128),
|
||||
}
|
||||
|
||||
impl ReadNX {
|
||||
const fn created(&self) -> bool {
|
||||
matches!(self, Self::Created(_))
|
||||
}
|
||||
fn file_mut(&mut self) -> &mut File {
|
||||
match self {
|
||||
Self::Created(ref mut f) => f,
|
||||
Self::Read(ref mut f, _) => f,
|
||||
}
|
||||
}
|
||||
fn into_file(self) -> File {
|
||||
match self {
|
||||
Self::Created(f) => f,
|
||||
Self::Read(f, _) => f,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StartStop {
|
||||
fn read_time_file(f: &str, create_new_if_nx: bool) -> SDSSResult<ReadNX> {
|
||||
let mut f = match File::options().write(true).read(true).open(f) {
|
||||
Ok(f) => f,
|
||||
Err(e) if e.kind() == ErrorKind::NotFound && create_new_if_nx => {
|
||||
let f = File::create(f)?;
|
||||
return Ok(ReadNX::Created(f));
|
||||
}
|
||||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
let len = f.metadata().map(|m| m.len())?;
|
||||
if len != sizeof!(u128) as u64 {
|
||||
return Err(SDSSError::corrupted_file(START_FILE));
|
||||
}
|
||||
let mut buf = [0u8; sizeof!(u128)];
|
||||
f.read_exact(&mut buf)?;
|
||||
Ok(ReadNX::Read(f, u128::from_le_bytes(buf)))
|
||||
}
|
||||
pub fn terminate(mut self) -> SDSSResult<()> {
|
||||
self.stop_file
|
||||
.write_all(self.begin.to_le_bytes().as_ref())
|
||||
.map_err(|e| e.with_extra(EMSG_FAILED_WRITE_STOP_FILE))
|
||||
}
|
||||
pub fn verify_and_start() -> SDSSResult<Self> {
|
||||
// read start file
|
||||
let mut start_file = Self::read_time_file(START_FILE, true)
|
||||
.map_err(|e| e.with_ioerror_extra(EMSG_FAILED_OPEN_START_FILE))?;
|
||||
// read stop file
|
||||
let stop_file = Self::read_time_file(STOP_FILE, start_file.created())
|
||||
.map_err(|e| e.with_ioerror_extra(EMSG_FAILED_OPEN_STOP_FILE))?;
|
||||
// read current time
|
||||
let ctime = os::get_epoch_time();
|
||||
match (&start_file, &stop_file) {
|
||||
(ReadNX::Read(_, time_start), ReadNX::Read(_, time_stop))
|
||||
if time_start == time_stop => {}
|
||||
(ReadNX::Created(_), ReadNX::Created(_)) => {}
|
||||
_ => return Err(SDSSError::OtherError(EMSG_FAILED_VERIFY)),
|
||||
}
|
||||
start_file
|
||||
.file_mut()
|
||||
.write_all(&ctime.to_le_bytes())
|
||||
.map_err(|e| e.with_extra(EMSG_FAILED_WRITE_START_FILE))?;
|
||||
Ok(Self {
|
||||
stop_file: stop_file.into_file(),
|
||||
begin: ctime,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_test() {
|
||||
let x = || -> SDSSResult<()> {
|
||||
let ss = StartStop::verify_and_start()?;
|
||||
ss.terminate()?;
|
||||
let ss = StartStop::verify_and_start()?;
|
||||
ss.terminate()?;
|
||||
std::fs::remove_file(START_FILE)?;
|
||||
std::fs::remove_file(STOP_FILE)?;
|
||||
Ok(())
|
||||
};
|
||||
x().unwrap();
|
||||
}
|
Loading…
Reference in New Issue