Skip to main content

mysql_handler/hton/
cost_constants.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-specific optimizer cost constants.
24
25/// Engine-specific cost constants the handlerton returns from
26/// [`get_cost_constants`](crate::hton::Handlerton::get_cost_constants).
27///
28/// Both fields mirror the per-storage-engine values MySQL stores in the
29/// `mysql.engine_cost` table; the defaults match what
30/// `SE_cost_constants(Optimizer::kOriginal)` would have produced on the
31/// C++ side, so an engine that supplies only one field starts from a sane
32/// fallback for the other.
33#[derive(Debug, Clone, Copy, PartialEq)]
34#[non_exhaustive]
35pub struct CostConstants {
36    memory_block_read_cost: f64,
37    io_block_read_cost: f64,
38}
39
40impl CostConstants {
41    /// Construct a cost-constants tuple with the given per-block read
42    /// costs. Both values must be positive; MySQL's
43    /// `SE_cost_constants::set` rejects zero or negative values with
44    /// `INVALID_COST_VALUE`, so the shim does the same and an engine
45    /// returning either value reverts to the defaults.
46    #[must_use]
47    pub const fn new(memory_block_read_cost: f64, io_block_read_cost: f64) -> Self {
48        Self {
49            memory_block_read_cost,
50            io_block_read_cost,
51        }
52    }
53
54    /// The defaults `SE_cost_constants(Optimizer::kOriginal)` initialises
55    /// — `memory_block_read_cost = 0.25`, `io_block_read_cost = 1.0`.
56    /// Engines that want to override one field commonly start from these.
57    #[must_use]
58    pub const fn defaults() -> Self {
59        Self::new(0.25, 1.0)
60    }
61
62    /// Cost of reading one random block from an in-memory buffer.
63    #[must_use]
64    pub const fn memory_block_read_cost(&self) -> f64 {
65        self.memory_block_read_cost
66    }
67
68    /// Cost of reading one random block from disk.
69    #[must_use]
70    pub const fn io_block_read_cost(&self) -> f64 {
71        self.io_block_read_cost
72    }
73}
74
75impl Default for CostConstants {
76    fn default() -> Self {
77        Self::defaults()
78    }
79}
80
81#[cfg(test)]
82mod tests {
83    use super::*;
84
85    #[test]
86    fn defaults_match_se_cost_constants_original() {
87        // Values pinned to mysql-server's
88        // `SE_cost_constants(Optimizer::kOriginal)` initialiser.
89        let c = CostConstants::defaults();
90        assert!((c.memory_block_read_cost() - 0.25).abs() < f64::EPSILON);
91        assert!((c.io_block_read_cost() - 1.0).abs() < f64::EPSILON);
92    }
93
94    #[test]
95    fn new_preserves_values() {
96        let c = CostConstants::new(0.5, 2.5);
97        assert!((c.memory_block_read_cost() - 0.5).abs() < f64::EPSILON);
98        assert!((c.io_block_read_cost() - 2.5).abs() < f64::EPSILON);
99    }
100}