Skip to main content

kaya_wal/
inspect.rs

1use std::fs;
2use std::path::Path;
3
4use kaya_core::Result;
5
6use crate::{decode_record, DecodeRecordResult, WalRecordType, WalWarning};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct WalInspectionRow {
10    pub offset: u64,
11    pub lsn: u64,
12    pub sequence: u64,
13    pub record_type: WalRecordType,
14    pub key_len: Option<usize>,
15    pub value_len: Option<usize>,
16}
17
18#[derive(Debug, Clone, Default, PartialEq, Eq)]
19pub struct WalInspection {
20    pub segment: String,
21    pub rows: Vec<WalInspectionRow>,
22    pub warnings: Vec<WalWarning>,
23}
24
25pub fn inspect_wal_path(path: impl AsRef<Path>, max_record_bytes: u32) -> Result<WalInspection> {
26    let path = path.as_ref();
27    let bytes = fs::read(path)?;
28    let segment = path
29        .file_name()
30        .map(|name| name.to_string_lossy().into_owned())
31        .unwrap_or_else(|| path.display().to_string());
32    let mut offset = 0_usize;
33    let mut rows = Vec::new();
34    let mut warnings = Vec::new();
35
36    while offset < bytes.len() {
37        match decode_record(&bytes[offset..], offset as u64, max_record_bytes) {
38            DecodeRecordResult::Complete { record, bytes_read } => {
39                rows.push(WalInspectionRow {
40                    offset: offset as u64,
41                    lsn: record.lsn.get(),
42                    sequence: record.sequence.get(),
43                    record_type: record.record_type(),
44                    key_len: record.payload.key_len(),
45                    value_len: record.payload.value_len(),
46                });
47                offset += bytes_read;
48            }
49            DecodeRecordResult::Incomplete { warning }
50            | DecodeRecordResult::Invalid { warning } => {
51                warnings.push(warning);
52                break;
53            }
54        }
55    }
56
57    Ok(WalInspection {
58        segment,
59        rows,
60        warnings,
61    })
62}