jdb_log

Crates.iojdb_log
lib.rsjdb_log
version0.1.6
created_at2025-12-23 20:07:38.417969+00
updated_at2025-12-23 20:07:38.417969+00
descriptionHigh-performance Write-Ahead Log / 高性能预写日志
homepagehttps://github.com/js0/jdb/tree/main/jdb_log
repositoryhttps://github.com/js0/jdb.git
max_upload_size
id2002222
size86,708
i18n.site (i18nsite)

documentation

README

English | 中文


jdb_log: High-Performance Write-Ahead Log

Fast, reliable, and crash-proof logging system for persistent storage.

目录

项目功能

jdb_log 是一个专为高性能数据库设计的预写日志(WAL)实现。它提供快速、可靠的日志记录功能,支持崩溃恢复和数据持久化。

核心功能包括:

  • 追加写入的日志记录
  • 支持跨页的大记录
  • CRC32 校验确保数据完整性
  • 顺序读取和随机访问两种读取模式
  • Direct I/O 优化,减少缓存开销

使用演示

基本写入和读取

use jdb_buf::LocalPool;
use jdb_log::{Writer, Reader};
use jdb_proto::Req;
use bytes::Bytes;

// 创建写入器
let mut pool = LocalPool::new(PAGE_SIZE, 16);
let mut writer = Writer::new("test.wal", 1, &mut pool).await?;

// 准备写入数据
let batch = vec![
  Req::Set {
    key: Bytes::from("key1"),
    val: Bytes::from("value1"),
    resp: tx,
  },
  Req::Del {
    key: Bytes::from("key2"),
    resp: tx,
  },
];

// 写入日志
let ptrs = writer.append(&batch, &mut pool).await?;
writer.sync(&mut pool).await?;

// 读取日志
let mut reader = Reader::open("test.wal", 1, &mut pool).await?;
let records = reader.read_all(&mut pool).await?;

随机访问读取

use jdb_log::RandomReader;

// 创建随机访问读取器
let reader = RandomReader::new(file);

// 使用 ValPtr 读取特定值
let val = reader.read_val(&val_ptr, &mut pool).await?;

特性介绍

  • 高性能写入:使用 Direct I/O 和页对齐缓冲区,最小化系统调用开销
  • 跨页支持:自动处理跨越页面边界的大记录
  • 数据完整性:每条记录包含 CRC32 校验,检测损坏
  • 零拷贝读取:在可能的情况下避免数据拷贝,提升性能
  • 批量操作:支持批量写入,提高吞吐量
  • 崩溃恢复:通过顺序读取恢复所有未丢失的记录

设计思路

graph TD
    A[Req Batch] --> B[Writer]
    B --> C[Build Headers]
    C --> D[Calculate CRC]
    D --> E[Write to Buffer]
    E --> F{Buffer Full?}
    F -->|Yes| G[Flush to Disk]
    F -->|No| E
    G --> H[Sync if Needed]
    
    I[WAL File] --> J[Reader]
    J --> K[Parse Header]
    K --> L[Verify CRC]
    L --> M[Extract Record]
    M --> N[Return Record]
    
    I --> O[RandomReader]
    O --> P[Read by ValPtr]
    P --> Q[Extract Value]
    Q --> R[Return Value]

系统采用经典的 WAL 架构,写入端将记录顺序追加到日志文件,读取端支持两种模式:

  1. 顺序读取:用于崩溃恢复,从头到尾读取所有有效记录
  2. 随机访问:通过 ValPtr 直接定位并读取特定记录的值

写入器使用页对齐的缓冲区,当缓冲区满时自动刷盘。所有记录都包含 CRC32 校验,确保数据完整性。

技术堆栈

  • Rust 2024 Edition:现代 Rust 特性
  • Direct I/O:绕过页缓存,直接访问存储
  • CRC32fast:硬件加速的 CRC32 计算
  • Compio:基于 io_uring 的高性能异步运行时
  • Bytes/BytesMut:零拷贝字节缓冲区管理

目录结构

src/
├── lib.rs      # 公共 API 导出
├── error.rs    # 错误类型定义
├── format.rs   # 记录格式定义
├── reader.rs   # 读取器实现
└── writer.rs   # 写入器实现

API 参考

数据结构

RecordType

记录类型枚举:

  • Zero:填充记录
  • Set:写入操作
  • Del:删除操作

Record

解码后的日志记录:

pub struct Record {
    pub rtype: RecordType,  // 记录类型
    pub key: Bytes,         // 键
    pub val: Bytes,         // 值
    pub ptr: ValPtr,        // 位置指针
}

核心函数

Writer::new()

创建新的 WAL 写入器。

Writer::append()

批量追加记录到日志。

Reader::open()

打开 WAL 文件用于顺序读取。

Reader::next()

读取下一条记录。

RandomReader::read_val()

通过 ValPtr 随机读取值。

历史小故事

预写日志(Write-Ahead Log)的概念可以追溯到 1976 年,IBM 的 System R 项目首次引入了这个概念。当时的研究者面临一个核心问题:如何在系统崩溃后保证数据的一致性?

答案是:在修改实际数据前,先记录将要执行的操作。这样即使崩溃,也可以通过重放日志来恢复状态。这个简单的思想成为了现代数据库系统的基石。

jdb_log 在这个经典概念的基础上,结合了现代 Rust 语言的内存安全和零拷贝特性,以及 Direct I/O 等现代存储技术,为高性能存储系统提供了可靠的基础组件。


About

This project is an open-source component of js0.site ⋅ Refactoring the Internet Plan.

We are redefining the development paradigm of the Internet in a componentized way. Welcome to follow us:


jdb_log:高性能预写日志

快速、可靠且防崩溃的持久化存储日志系统。

目录

项目功能

jdb_log 是专为高性能数据库设计的预写日志(WAL)实现。它提供快速、可靠的日志记录功能,支持崩溃恢复和数据持久化。

核心功能包括:

  • 追加写入的日志记录
  • 支持跨页的大记录
  • CRC32 校验确保数据完整性
  • 顺序读取和随机访问两种读取模式
  • Direct I/O 优化,减少缓存开销

使用演示

基本写入和读取

use jdb_buf::LocalPool;
use jdb_log::{Writer, Reader};
use jdb_proto::Req;
use bytes::Bytes;

// 创建写入器
let mut pool = LocalPool::new(PAGE_SIZE, 16);
let mut writer = Writer::new("test.wal", 1, &mut pool).await?;

// 准备写入数据
let batch = vec![
  Req::Set {
    key: Bytes::from("key1"),
    val: Bytes::from("value1"),
    resp: tx,
  },
  Req::Del {
    key: Bytes::from("key2"),
    resp: tx,
  },
];

// 写入日志
let ptrs = writer.append(&batch, &mut pool).await?;
writer.sync(&mut pool).await?;

// 读取日志
let mut reader = Reader::open("test.wal", 1, &mut pool).await?;
let records = reader.read_all(&mut pool).await?;

随机访问读取

use jdb_log::RandomReader;

// 创建随机访问读取器
let reader = RandomReader::new(file);

// 使用 ValPtr 读取特定值
let val = reader.read_val(&val_ptr, &mut pool).await?;

特性介绍

  • 高性能写入:使用 Direct I/O 和页对齐缓冲区,最小化系统调用开销
  • 跨页支持:自动处理跨越页面边界的大记录
  • 数据完整性:每条记录包含 CRC32 校验,检测损坏
  • 零拷贝读取:在可能的情况下避免数据拷贝,提升性能
  • 批量操作:支持批量写入,提高吞吐量
  • 崩溃恢复:通过顺序读取恢复所有未丢失的记录

设计思路

graph TD
    A[Req Batch] --> B[Writer]
    B --> C[Build Headers]
    C --> D[Calculate CRC]
    D --> E[Write to Buffer]
    E --> F{Buffer Full?}
    F -->|Yes| G[Flush to Disk]
    F -->|No| E
    G --> H[Sync if Needed]
    
    I[WAL File] --> J[Reader]
    J --> K[Parse Header]
    K --> L[Verify CRC]
    L --> M[Extract Record]
    M --> N[Return Record]
    
    I --> O[RandomReader]
    O --> P[Read by ValPtr]
    P --> Q[Extract Value]
    Q --> R[Return Value]

系统采用经典的 WAL 架构,写入端将记录顺序追加到日志文件,读取端支持两种模式:

  1. 顺序读取:用于崩溃恢复,从头到尾读取所有有效记录
  2. 随机访问:通过 ValPtr 直接定位并读取特定记录的值

写入器使用页对齐的缓冲区,当缓冲区满时自动刷盘。所有记录都包含 CRC32 校验,确保数据完整性。

技术堆栈

  • Rust 2024 Edition:现代 Rust 特性
  • Direct I/O:绕过页缓存,直接访问存储
  • CRC32fast:硬件加速的 CRC32 计算
  • Compio:基于 io_uring 的高性能异步运行时
  • Bytes/BytesMut:零拷贝字节缓冲区管理

目录结构

src/
├── lib.rs      # 公共 API 导出
├── error.rs    # 错误类型定义
├── format.rs   # 记录格式定义
├── reader.rs   # 读取器实现
└── writer.rs   # 写入器实现

API 参考

数据结构

RecordType

记录类型枚举:

  • Zero:填充记录
  • Set:写入操作
  • Del:删除操作

Record

解码后的日志记录:

pub struct Record {
    pub rtype: RecordType,  // 记录类型
    pub key: Bytes,         // 键
    pub val: Bytes,         // 值
    pub ptr: ValPtr,        // 位置指针
}

核心函数

Writer::new()

创建新的 WAL 写入器。

Writer::append()

批量追加记录到日志。

Reader::open()

打开 WAL 文件用于顺序读取。

Reader::next()

读取下一条记录。

RandomReader::read_val()

通过 ValPtr 随机读取值。

历史小故事

预写日志(Write-Ahead Log)的概念可以追溯到 1976 年,IBM 的 System R 项目首次引入了这个概念。当时的研究者面临一个核心问题:如何在系统崩溃后保证数据的一致性?

答案是:在修改实际数据前,先记录将要执行的操作。这样即使崩溃,也可以通过重放日志来恢复状态。这个简单的思想成为了现代数据库系统的基石。

jdb_log 在这个经典概念的基础上,结合了现代 Rust 语言的内存安全和零拷贝特性,以及 Direct I/O 等现代存储技术,为高性能存储系统提供了可靠的基础组件。


关于

本项目为 js0.site ⋅ 重构互联网计划 的开源组件。

我们正在以组件化的方式重新定义互联网的开发范式,欢迎关注:

Commit count: 0

cargo fmt