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