Skip to main content

worktable/table/
system_info.rs

1use indexset::core::node::NodeLike;
2use indexset::core::pair::Pair;
3use prettytable::{Table, format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR, row};
4use std::fmt::{self, Debug, Display, Formatter};
5
6use crate::in_memory::{RowWrapper, StorableRow};
7use crate::mem_stat::MemStat;
8use crate::util::OffsetEqLink;
9use crate::{TableSecondaryIndexInfo, WorkTable};
10
11#[derive(Debug)]
12pub struct SystemInfo {
13    pub table_name: &'static str,
14    pub page_count: usize,
15    pub row_count: usize,
16    pub empty_slots: u64,
17    pub memory_usage_bytes: u64,
18    pub idx_size: usize,
19    pub indexes_info: Vec<IndexInfo>,
20}
21
22#[derive(Debug)]
23pub struct IndexInfo {
24    pub name: String,
25    pub index_type: IndexKind,
26    pub key_count: usize,
27    pub capacity: usize,
28    pub heap_size: usize,
29    pub used_size: usize,
30    pub node_count: usize,
31}
32
33#[derive(Debug)]
34pub enum IndexKind {
35    Unique,
36    NonUnique,
37}
38
39impl Display for IndexKind {
40    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
41        match self {
42            Self::Unique => write!(f, "unique"),
43            Self::NonUnique => write!(f, "non unique"),
44        }
45    }
46}
47
48impl<
49    Row,
50    PrimaryKey,
51    AvailableTypes,
52    AvailableIndexes,
53    SecondaryIndexes,
54    LockType,
55    PkGen,
56    const DATA_LENGTH: usize,
57    NodeType,
58>
59    WorkTable<
60        Row,
61        PrimaryKey,
62        AvailableTypes,
63        AvailableIndexes,
64        SecondaryIndexes,
65        LockType,
66        PkGen,
67        DATA_LENGTH,
68        NodeType,
69    >
70where
71    PrimaryKey: Debug + Clone + Ord + Send + 'static + std::hash::Hash,
72    Row: StorableRow + Send + Clone + 'static,
73    <Row as StorableRow>::WrappedRow: RowWrapper<Row>,
74    NodeType: NodeLike<Pair<PrimaryKey, OffsetEqLink<DATA_LENGTH>>> + Send + 'static,
75    SecondaryIndexes: MemStat + TableSecondaryIndexInfo,
76{
77    pub fn system_info(&self) -> SystemInfo {
78        let page_count = self.data.get_page_count();
79        let row_count = self.primary_index.pk_map.len();
80
81        let empty_links = self.data.get_empty_links().len();
82
83        let bytes = self.data.get_bytes();
84
85        let memory_usage_bytes = bytes
86            .iter()
87            .map(|(_buf, free_offset)| *free_offset as u64)
88            .sum();
89
90        let idx_size = self.indexes.heap_size();
91
92        SystemInfo {
93            table_name: self.table_name,
94            page_count,
95            row_count,
96            empty_slots: empty_links as u64,
97            memory_usage_bytes,
98            idx_size,
99            indexes_info: self.indexes.index_info(),
100        }
101    }
102}
103
104impl Display for SystemInfo {
105    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
106        let mem_fmt = fmt_bytes(self.memory_usage_bytes as usize);
107        let idx_fmt = fmt_bytes(self.idx_size);
108        let total_fmt = fmt_bytes(self.memory_usage_bytes as usize + self.idx_size);
109
110        writeln!(f, "┌──────────────────────────────┐")?;
111        writeln!(f, " \t Table Name: {:<5}", self.table_name)?;
112        writeln!(f, "└──────────────────────────────┘")?;
113        writeln!(
114            f,
115            "Rows: {}   Pages: {}   Empty slots: {}",
116            self.row_count, self.page_count, self.empty_slots
117        )?;
118        writeln!(
119            f,
120            "Allocated Memory: {mem_fmt} (data) + {idx_fmt} (indexes) = {total_fmt} total\n"
121        )?;
122
123        let mut table = Table::new();
124        table.set_format(*FORMAT_NO_BORDER_LINE_SEPARATOR);
125        table.add_row(row![
126            "Index",
127            "Type",
128            "Keys",
129            "Capacity",
130            "Node Count",
131            "Heap",
132            "Used"
133        ]);
134
135        for idx in &self.indexes_info {
136            table.add_row(row![
137                idx.name,
138                idx.index_type.to_string(),
139                idx.key_count,
140                idx.capacity,
141                idx.node_count,
142                fmt_bytes(idx.heap_size),
143                fmt_bytes(idx.used_size),
144            ]);
145        }
146
147        let mut buffer = Vec::new();
148        table.print(&mut buffer).unwrap();
149        let table_str = String::from_utf8(buffer).unwrap();
150        writeln!(f, "{}", table_str.trim_end())?;
151
152        Ok(())
153    }
154}
155
156fn fmt_bytes(bytes: usize) -> String {
157    const KB: f64 = 1024.0;
158    const MB: f64 = 1024.0 * KB;
159    const GB: f64 = 1024.0 * MB;
160
161    let b = bytes as f64;
162
163    let (value, unit) = if b >= GB {
164        (b / GB, "GB")
165    } else if b >= MB {
166        (b / MB, "MB")
167    } else if b >= KB {
168        (b / KB, "KB")
169    } else {
170        return format!("{bytes} B");
171    };
172
173    if (value.fract() * 100.0).round() == 0.0 {
174        format!("{value:.0} {unit}")
175    } else {
176        format!("{value:.2} {unit}")
177    }
178}