idb/innodb/
compression.rs1use flate2::read::ZlibDecoder;
7use std::io::Read;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum CompressionAlgorithm {
12 None,
13 Zlib,
14 Lz4,
15}
16
17pub fn detect_compression(fsp_flags: u32) -> CompressionAlgorithm {
24 let comp_bits = (fsp_flags >> 11) & 0x03;
25 match comp_bits {
26 1 => CompressionAlgorithm::Zlib,
27 2 => CompressionAlgorithm::Lz4,
28 _ => CompressionAlgorithm::None,
29 }
30}
31
32pub fn decompress_zlib(compressed: &[u8]) -> Option<Vec<u8>> {
36 let mut decoder = ZlibDecoder::new(compressed);
37 let mut decompressed = Vec::new();
38 decoder.read_to_end(&mut decompressed).ok()?;
39 Some(decompressed)
40}
41
42pub fn decompress_lz4(compressed: &[u8], uncompressed_len: usize) -> Option<Vec<u8>> {
47 lz4_flex::decompress(compressed, uncompressed_len).ok()
48}
49
50pub fn is_hole_punched(page_data: &[u8], page_size: u32) -> bool {
55 if page_data.len() < page_size as usize {
56 return false;
57 }
58
59 let check_start = (page_size as usize * 3) / 4;
61 page_data[check_start..page_size as usize]
62 .iter()
63 .all(|&b| b == 0)
64}
65
66impl std::fmt::Display for CompressionAlgorithm {
67 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68 match self {
69 CompressionAlgorithm::None => write!(f, "None"),
70 CompressionAlgorithm::Zlib => write!(f, "Zlib"),
71 CompressionAlgorithm::Lz4 => write!(f, "LZ4"),
72 }
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn test_detect_compression() {
82 assert_eq!(detect_compression(0), CompressionAlgorithm::None);
83 assert_eq!(detect_compression(1 << 11), CompressionAlgorithm::Zlib);
84 assert_eq!(detect_compression(2 << 11), CompressionAlgorithm::Lz4);
85 assert_eq!(detect_compression(3 << 11), CompressionAlgorithm::None);
86 assert_eq!(detect_compression(0xFF | (1 << 11)), CompressionAlgorithm::Zlib);
88 }
89
90 #[test]
91 fn test_decompress_zlib() {
92 use flate2::write::ZlibEncoder;
93 use flate2::Compression;
94 use std::io::Write;
95
96 let original = b"Hello, InnoDB compression test data!";
97 let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
98 encoder.write_all(original).unwrap();
99 let compressed = encoder.finish().unwrap();
100
101 let result = decompress_zlib(&compressed).unwrap();
102 assert_eq!(result, original);
103 }
104
105 #[test]
106 fn test_decompress_lz4() {
107 let original = b"Hello, LZ4 compression test data for InnoDB!";
108 let compressed = lz4_flex::compress_prepend_size(original);
109 let result = lz4_flex::decompress(&compressed[4..], original.len());
112 assert!(result.is_ok());
113 assert_eq!(result.unwrap(), original);
114 }
115
116 #[test]
117 fn test_is_hole_punched() {
118 let page_size = 16384u32;
119 let mut page = vec![0u8; page_size as usize];
120 assert!(is_hole_punched(&page, page_size));
122
123 page[0] = 0xFF;
125 page[100] = 0xAB;
126 assert!(is_hole_punched(&page, page_size));
127
128 page[page_size as usize - 10] = 0x01;
130 assert!(!is_hole_punched(&page, page_size));
131 }
132}