libnsave/
chunkindex.rs

1use crate::common::*;
2use crate::configure::*;
3use crate::mmapbuf::*;
4use crate::packet::*;
5use bincode::deserialize_from;
6use serde::{Deserialize, Serialize};
7use std::borrow::Borrow;
8use std::fmt;
9use std::{
10    fs::OpenOptions,
11    path::{Path, PathBuf},
12};
13
14#[derive(Debug)]
15pub struct ChunkIndex {
16    configure: &'static Configure,
17    buf_writer: Option<MmapBufWriter>,
18}
19
20impl ChunkIndex {
21    pub fn new(configure: &'static Configure) -> Self {
22        ChunkIndex {
23            configure,
24            buf_writer: None,
25        }
26    }
27
28    pub fn init_dir(&mut self, dir: &Path) -> Result<(), StoreError> {
29        let mut path = PathBuf::new();
30        path.push(dir);
31        path.push("chunkindex.ci");
32        let result = OpenOptions::new()
33            .read(true)
34            .write(true)
35            .create(true)
36            .truncate(false)
37            .open(path);
38        match result {
39            Ok(fd) => {
40                let meta = fd.metadata()?;
41                self.buf_writer = Some(MmapBufWriter::with_arg(
42                    fd,
43                    meta.len(),
44                    self.configure.ci_buff_size,
45                ));
46            }
47            Err(e) => return Err(StoreError::IoError(e)),
48        }
49        Ok(())
50    }
51
52    pub fn change_dir(&mut self) -> Result<(), StoreError> {
53        self.buf_writer = None;
54        Ok(())
55    }
56
57    pub fn write(&mut self, record: ChunkIndexRd) -> Result<u64, StoreError> {
58        let ci_offset = self.buf_writer.borrow().as_ref().unwrap().next_offset();
59        if let Some(ref mut writer) = self.buf_writer {
60            if bincode::serialize_into(writer, &record).is_err() {
61                return Err(StoreError::WriteError(
62                    "chunk index write error".to_string(),
63                ));
64            }
65        }
66        Ok(ci_offset)
67    }
68
69    pub fn finish(&mut self) {
70        self.buf_writer = None;
71    }
72}
73
74#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Hash, Clone, Copy)]
75pub struct ChunkIndexRd {
76    pub start_time: u128,
77    pub end_time: u128,
78    pub chunk_id: u32,
79    pub chunk_offset: u32,
80    pub tuple5: PacketKey,
81}
82
83impl fmt::Display for ChunkIndexRd {
84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85        write!(
86            f,
87            "ChunkIndexRd {{ start_time: {}, end_time: {}, chunk_id: {}, chunk_offset: {}, tuple5: {:?} }}",
88            ts_date(self.start_time),
89            ts_date(self.end_time),
90            self.chunk_id,
91            self.chunk_offset,
92            self.tuple5,
93        )
94    }
95}
96
97pub fn dump_chunkindex_file(path: PathBuf) -> Result<(), StoreError> {
98    match path.extension() {
99        Some(ext) => {
100            if !ext.to_str().unwrap().eq("ci") {
101                return Err(StoreError::CliError("not chunkindex file".to_string()));
102            }
103        }
104        None => return Err(StoreError::CliError("not chunkindex file".to_string())),
105    };
106
107    let file = match OpenOptions::new()
108        .read(true)
109        .write(true)
110        .create(false)
111        .truncate(false)
112        .open(&path)
113    {
114        Ok(fd) => fd,
115        Err(e) => {
116            return Err(StoreError::CliError(format!("open file error: {}", e)));
117        }
118    };
119    let mut mmap_reader = MmapBufReader::new(file);
120    println!("dump chunkid file: {:?}", path);
121    while let Ok(record) = deserialize_from::<_, ChunkIndexRd>(&mut mmap_reader) {
122        println!("record: {}", record);
123    }
124    Ok(())
125}