WAL Recovery

DBX는 Write-Ahead Log (WAL)를 사용하여 크래시 복구와 데이터 무결성을 보장합니다.

Overview

WAL의 주요 특징:

  • 크래시 복구: 시스템 장애 시 자동으로 데이터 복구
  • 원자성 보장: 트랜잭션의 All-or-Nothing 보장
  • 순차 쓰기: 디스크 I/O 최적화
  • 체크포인트: 주기적으로 WAL을 WOS에 반영

How WAL Works

1. 쓰기 요청
   ↓
2. WAL에 기록 (순차 쓰기)
   ↓
3. 메모리에 반영
   ↓
4. 주기적으로 WOS에 플러시
   ↓
5. WAL 정리

Quick Start

use dbx_core::Database;

// WAL은 자동으로 활성화됨
let db = Database::open("./db".as_ref())?;

// 데이터 삽입 (자동으로 WAL에 기록)
db.insert("users", b"user:1", b"Alice")?;

// 크래시 시뮬레이션
drop(db);

// 재시작 시 자동 복구
let db = Database::open("./db".as_ref())?;
let value = db.get("users", b"user:1")?;
assert_eq!(value, Some(b"Alice".to_vec()));

Step-by-Step Guide

1. 기본 WAL 사용

WAL은 기본적으로 활성화되어 있습니다:

use dbx_core::Database;

// WAL이 자동으로 생성됨
let db = Database::open("./my_db".as_ref())?;

println!("✓ Database opened with WAL enabled");

// 데이터 삽입 (WAL에 기록)
db.insert("users", b"user:1", b"Alice")?;
db.insert("users", b"user:2", b"Bob")?;

println!("✓ Data written to WAL");

2. 크래시 복구 시뮬레이션

시스템 장애를 시뮬레이션하고 복구합니다:

use dbx_core::Database;

// 1. 데이터 삽입
{
    let db = Database::open("./crash_test".as_ref())?;
    
    for i in 0..100 {
        let key = format!("key:{}", i).into_bytes();
        let value = format!("value:{}", i).into_bytes();
        db.insert("data", &key, &value)?;
    }
    
    println!("✓ Inserted 100 rows");
    
    // 2. 크래시 시뮬레이션 (flush 없이 종료)
    // drop(db) - WAL에만 기록되고 WOS에는 미반영
}

// 3. 재시작 및 자동 복구
{
    let db = Database::open("./crash_test".as_ref())?;
    
    // WAL 재생으로 데이터 복구
    let count = db.count("data")?;
    println!("✓ Recovered {} rows from WAL", count);
    
    // 데이터 검증
    let value = db.get("data", b"key:50")?;
    assert_eq!(value, Some(b"value:50".to_vec()));
    println!("✓ Data integrity verified");
}

3. 수동 플러시

WAL을 WOS에 수동으로 반영합니다:

use dbx_core::Database;

let db = Database::open("./db".as_ref())?;

// 데이터 삽입
for i in 0..1000 {
    let key = format!("key:{}", i).into_bytes();
    db.insert("data", &key, b"value")?;
}

println!("✓ Data in WAL");

// 수동 플러시
db.flush()?;

println!("✓ WAL flushed to WOS");

4. Durability 레벨 조정

데이터 안전성과 성능 간 트레이드오프를 조정합니다:

use dbx_core::{Database, DurabilityLevel};

// 최대 안전성 (모든 쓰기마다 fsync)
let db = Database::open_safe("./critical_db")?;

// 최고 성능 (WAL 없음, 크래시 시 데이터 손실 가능)
let db = Database::open_fast("./cache_db")?;

// 균형 (기본값, 주기적 fsync)
let db = Database::open_with_durability(
    "./balanced_db",
    DurabilityLevel::Lazy
)?;

Complete Example

use dbx_core::{Database, DbxResult};

fn main() -> DbxResult<()> {
    println!("=== DBX WAL Recovery Example ===\n");
    
    // 1. 초기 데이터 삽입
    println!("--- Initial Write ---");
    {
        let db = Database::open("./wal_demo".as_ref())?;
        
        for i in 0..50 {
            let key = format!("user:{}", i).into_bytes();
            let value = format!("User {}", i).into_bytes();
            db.insert("users", &key, &value)?;
        }
        
        println!("✓ Inserted 50 users");
        println!("✓ Data in WAL (not yet flushed)\n");
        
        // 크래시 시뮬레이션 (drop without flush)
    }
    
    // 2. 재시작 및 복구
    println!("--- Recovery After Crash ---");
    {
        let db = Database::open("./wal_demo".as_ref())?;
        
        // WAL 자동 재생
        let count = db.count("users")?;
        println!("✓ Recovered {} users from WAL", count);
        
        // 데이터 검증
        let value = db.get("users", b"user:25")?;
        match value {
            Some(v) => println!("✓ Data verified: {}", String::from_utf8_lossy(&v)),
            None => println!("✗ Data lost!"),
        }
        
        println!();
    }
    
    // 3. 추가 데이터 및 플러시
    println!("--- Additional Write + Flush ---");
    {
        let db = Database::open("./wal_demo".as_ref())?;
        
        for i in 50..100 {
            let key = format!("user:{}", i).into_bytes();
            let value = format!("User {}", i).into_bytes();
            db.insert("users", &key, &value)?;
        }
        
        println!("✓ Inserted 50 more users");
        
        // 명시적 플러시
        db.flush()?;
        println!("✓ Flushed to WOS\n");
    }
    
    // 4. 최종 검증
    println!("--- Final Verification ---");
    {
        let db = Database::open("./wal_demo".as_ref())?;
        let count = db.count("users")?;
        println!("✓ Total users: {}", count);
        assert_eq!(count, 100);
    }
    
    println!("\n=== Example Complete ===");
    Ok(())
}

Running the Example

cargo run --example simple_crud

Expected Output

=== DBX WAL Recovery Example ===

--- Initial Write ---
✓ Inserted 50 users
✓ Data in WAL (not yet flushed)

--- Recovery After Crash ---
✓ Recovered 50 users from WAL
✓ Data verified: User 25

--- Additional Write + Flush ---
✓ Inserted 50 more users
✓ Flushed to WOS

--- Final Verification ---
✓ Total users: 100

=== Example Complete ===

WAL Architecture

파일 구조

db/
├── wos/           # Write-Optimized Store
│   ├── conf
│   └── db
└── wal.log        # Write-Ahead Log

WAL 레코드 타입

enum WalRecord {
    Insert { table, key, value, ts },
    Delete { table, key, ts },
    Batch { table, rows, ts },
    Checkpoint { ts },
}

Durability Levels

레벨 fsync 빈도 성능 안전성 권장 용도
None 없음 ★★★★★ ★☆☆☆☆ 캐시, 임시 데이터
Lazy 주기적 ★★★★☆ ★★★★☆ 기본값, 일반 용도
Full 매 쓰기 ★★☆☆☆ ★★★★★ 금융, 의료 데이터

Best Practices

1. Durability 레벨 선택

// 중요한 데이터: Full
let db = Database::open_safe("./financial.db")?;

// 일반 데이터: Lazy (기본값)
let db = Database::open("./app.db".as_ref())?;

// 캐시: None
let db = Database::open_fast("./cache.db")?;

2. 주기적 플러시

use std::time::Duration;
use std::thread;

// 백그라운드 플러시 스레드
thread::spawn(move || {
    loop {
        thread::sleep(Duration::from_secs(60));
        let _ = db.flush();
    }
});

3. 체크포인트 관리

// 대량 삽입 후 체크포인트
for i in 0..1000000 {
    db.insert("data", &key, &value)?;
}
db.flush()?;  // WAL을 WOS에 반영

Troubleshooting

WAL 파일이 계속 커지는 경우

// 주기적으로 플러시하여 WAL 정리
db.flush()?;

복구 시간이 오래 걸리는 경우

// 더 자주 플러시하여 WAL 크기 감소
db.set_flush_interval(Duration::from_secs(30))?;

Next Steps


Copyright © 2026 ByteLogicCore. MIT OR Apache-2.0 License.

This site uses Just the Docs, a documentation theme for Jekyll.