Skip to main content

mysql_handler/hton/
table_statistics.rs

1// Copyright (C) 2026 ren-yamanashi
2//
3// This program is free software; you can redistribute it and/or modify
4// it under the terms of the GNU General Public License, version 2.0,
5// as published by the Free Software Foundation.
6//
7// This program is designed to work with certain software (including
8// but not limited to OpenSSL) that is licensed under separate terms,
9// as designated in a particular file or component or in included license
10// documentation. The authors of this program hereby grant you an additional
11// permission to link the program and your derivative works with the
12// separately licensed software that they have either included with
13// the program or referenced in the documentation.
14//
15// This program is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with this program; if not, see <https://www.gnu.org/licenses/>.
22
23//! Engine-published per-table statistics.
24
25/// Snapshot of the per-table statistics MySQL stores in `ha_statistics`.
26///
27/// Returned from
28/// [`Handlerton::get_table_statistics`](crate::hton::Handlerton::get_table_statistics);
29/// the shim copies each field into the matching `ha_statistics` slot
30/// before handing control back to the optimizer. Engines build instances
31/// through [`Self::new`] and the chained `with_*` setters; missing fields
32/// stay zero, which matches MySQL's `ha_statistics()` default constructor.
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34#[non_exhaustive]
35pub struct TableStatistics {
36    records: u64,
37    data_file_length: u64,
38    max_data_file_length: u64,
39    index_file_length: u64,
40    max_index_file_length: u64,
41    delete_length: u64,
42    auto_increment_value: u64,
43    deleted: u64,
44    mean_rec_length: u64,
45    create_time: i64,
46    check_time: u64,
47    update_time: u64,
48    block_size: u32,
49}
50
51impl TableStatistics {
52    /// Construct a statistics snapshot with every field zeroed — the same
53    /// initial state `ha_statistics()` produces on the C++ side.
54    #[must_use]
55    pub const fn new() -> Self {
56        Self {
57            records: 0,
58            data_file_length: 0,
59            max_data_file_length: 0,
60            index_file_length: 0,
61            max_index_file_length: 0,
62            delete_length: 0,
63            auto_increment_value: 0,
64            deleted: 0,
65            mean_rec_length: 0,
66            create_time: 0,
67            check_time: 0,
68            update_time: 0,
69            block_size: 0,
70        }
71    }
72
73    /// Number of live rows in the table.
74    #[must_use]
75    pub const fn with_records(mut self, value: u64) -> Self {
76        self.records = value;
77        self
78    }
79
80    /// Size of the data segment in bytes.
81    #[must_use]
82    pub const fn with_data_file_length(mut self, value: u64) -> Self {
83        self.data_file_length = value;
84        self
85    }
86
87    /// Hard cap MySQL should believe for `data_file_length`.
88    #[must_use]
89    pub const fn with_max_data_file_length(mut self, value: u64) -> Self {
90        self.max_data_file_length = value;
91        self
92    }
93
94    /// Size of the index segment in bytes.
95    #[must_use]
96    pub const fn with_index_file_length(mut self, value: u64) -> Self {
97        self.index_file_length = value;
98        self
99    }
100
101    /// Hard cap MySQL should believe for `index_file_length`.
102    #[must_use]
103    pub const fn with_max_index_file_length(mut self, value: u64) -> Self {
104        self.max_index_file_length = value;
105        self
106    }
107
108    /// Bytes reclaimable by compacting deleted rows.
109    #[must_use]
110    pub const fn with_delete_length(mut self, value: u64) -> Self {
111        self.delete_length = value;
112        self
113    }
114
115    /// Next auto-increment value the engine intends to hand out.
116    #[must_use]
117    pub const fn with_auto_increment_value(mut self, value: u64) -> Self {
118        self.auto_increment_value = value;
119        self
120    }
121
122    /// Number of tombstoned rows still occupying space.
123    #[must_use]
124    pub const fn with_deleted(mut self, value: u64) -> Self {
125        self.deleted = value;
126        self
127    }
128
129    /// Physical record length (`stats.mean_rec_length` on the C++ side).
130    #[must_use]
131    pub const fn with_mean_rec_length(mut self, value: u64) -> Self {
132        self.mean_rec_length = value;
133        self
134    }
135
136    /// UNIX timestamp the table was created at; mirrors C++ `time_t`.
137    #[must_use]
138    pub const fn with_create_time(mut self, value: i64) -> Self {
139        self.create_time = value;
140        self
141    }
142
143    /// UNIX timestamp of the last CHECK TABLE run.
144    #[must_use]
145    pub const fn with_check_time(mut self, value: u64) -> Self {
146        self.check_time = value;
147        self
148    }
149
150    /// UNIX timestamp of the last data modification.
151    #[must_use]
152    pub const fn with_update_time(mut self, value: u64) -> Self {
153        self.update_time = value;
154        self
155    }
156
157    /// Index block size in bytes.
158    #[must_use]
159    pub const fn with_block_size(mut self, value: u32) -> Self {
160        self.block_size = value;
161        self
162    }
163
164    /// Raw record count (read by the shim when copying into `ha_statistics`).
165    pub const fn records(&self) -> u64 {
166        self.records
167    }
168    /// Data segment length in bytes.
169    pub const fn data_file_length(&self) -> u64 {
170        self.data_file_length
171    }
172    /// Hard cap for `data_file_length`.
173    pub const fn max_data_file_length(&self) -> u64 {
174        self.max_data_file_length
175    }
176    /// Index segment length in bytes.
177    pub const fn index_file_length(&self) -> u64 {
178        self.index_file_length
179    }
180    /// Hard cap for `index_file_length`.
181    pub const fn max_index_file_length(&self) -> u64 {
182        self.max_index_file_length
183    }
184    /// Reclaimable byte count.
185    pub const fn delete_length(&self) -> u64 {
186        self.delete_length
187    }
188    /// Next auto-increment value.
189    pub const fn auto_increment_value(&self) -> u64 {
190        self.auto_increment_value
191    }
192    /// Tombstoned row count.
193    pub const fn deleted(&self) -> u64 {
194        self.deleted
195    }
196    /// Mean record length.
197    pub const fn mean_rec_length(&self) -> u64 {
198        self.mean_rec_length
199    }
200    /// Create-time UNIX timestamp.
201    pub const fn create_time(&self) -> i64 {
202        self.create_time
203    }
204    /// Last-check UNIX timestamp.
205    pub const fn check_time(&self) -> u64 {
206        self.check_time
207    }
208    /// Last-update UNIX timestamp.
209    pub const fn update_time(&self) -> u64 {
210        self.update_time
211    }
212    /// Index block size in bytes.
213    pub const fn block_size(&self) -> u32 {
214        self.block_size
215    }
216}
217
218impl Default for TableStatistics {
219    fn default() -> Self {
220        Self::new()
221    }
222}
223
224#[cfg(test)]
225mod tests {
226    use super::*;
227
228    #[test]
229    fn new_zeros_every_field() {
230        let s = TableStatistics::new();
231        assert_eq!(s.records(), 0);
232        assert_eq!(s.data_file_length(), 0);
233        assert_eq!(s.block_size(), 0);
234    }
235
236    #[test]
237    fn builder_preserves_each_setter() {
238        let s = TableStatistics::new()
239            .with_records(100)
240            .with_data_file_length(4096)
241            .with_block_size(16);
242        assert_eq!(s.records(), 100);
243        assert_eq!(s.data_file_length(), 4096);
244        assert_eq!(s.block_size(), 16);
245    }
246}