grumpydb 0.2.0

A disk-based object storage engine with B+Tree indexing and page-based storage
Documentation
<p align="center">
  <img src="docs/grumpy-logo.png" alt="GrumpyDB logo" width="200">
</p>

# GrumpyDB

A disk-based object storage engine written in Rust. GrumpyDB stores schema-less documents (JSON-like) with B+Tree indexing, page-based storage, WAL for durability, and SWMR concurrency.

## Features

| Feature | Status |
|---------|--------|
| Page-based storage (8 KiB pages, slotted layout, overflow) | βœ… Implemented |
| B+Tree index (search, insert, delete, range scan) | βœ… Implemented |
| Document model (JSON-like Value type, binary codec) | βœ… Implemented |
| Storage engine (CRUD API) | βœ… Implemented |
| Write-Ahead Log (crash recovery) | πŸ”² Phase 5 |
| Buffer pool (LRU cache) | πŸ”² Phase 6 |
| SWMR concurrency | πŸ”² Phase 7 |

## Getting started

### Prerequisites

- Rust (edition 2024)

### Build

```bash
cargo build
```

### Test

```bash
cargo test
```

### Lint

```bash
cargo clippy -- -D warnings
```

## Usage

```rust
use grumpydb::{GrumpyDb, Value};
use uuid::Uuid;
use std::collections::BTreeMap;

let mut db = GrumpyDb::open(std::path::Path::new("./my_database")).unwrap();

let key = Uuid::new_v4();
let value = Value::Object(BTreeMap::from([
    ("name".into(), Value::String("GrumpyDB".into())),
    ("version".into(), Value::Integer(1)),
]));

db.insert(key, value).unwrap();

let doc = db.get(&key).unwrap();
assert!(doc.is_some());

db.close().unwrap();
```

> **Note**: The full CRUD API (`insert`, `get`, `update`, `delete`, `scan`) is now wired and functional. WAL durability is coming in Phase 5.

## Architecture

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         API publique (lib.rs)        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚         Engine (engine.rs)           β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Document  β”‚  Concurrencyβ”‚  Buffer   β”‚
β”‚  Model     β”‚  (SWMR)     β”‚  Pool     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  B+Tree    β”‚     WAL     β”‚  Page     β”‚
β”‚  Index     β”‚             β”‚  Manager  β”‚
β”‚ (index.db) β”‚  (wal.log)  β”‚ (data.db) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

Voir [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) pour les dΓ©tails techniques.

## Project structure

```
src/
β”œβ”€β”€ lib.rs              # Public API, re-exports
β”œβ”€β”€ error.rs            # GrumpyError, Result type
β”œβ”€β”€ engine.rs           # GrumpyDb β€” CRUD orchestrator
β”œβ”€β”€ page/               # 8 KiB page management
β”‚   β”œβ”€β”€ mod.rs          # Constants, PageHeader, PageType
β”‚   β”œβ”€β”€ manager.rs      # PageManager (I/O, free-list)
β”‚   β”œβ”€β”€ slotted.rs      # SlottedPage (variable-length tuples)
β”‚   └── overflow.rs     # Overflow page chains
β”œβ”€β”€ btree/              # B+Tree index
β”‚   β”œβ”€β”€ mod.rs          # BTree struct, metadata
β”‚   β”œβ”€β”€ node.rs         # InternalNode, LeafNode
β”‚   β”œβ”€β”€ ops.rs          # search, insert, delete
β”‚   └── cursor.rs       # BTreeCursor, range scans
β”œβ”€β”€ document/           # Document model
β”‚   β”œβ”€β”€ mod.rs          # Document struct
β”‚   β”œβ”€β”€ value.rs        # Value enum (JSON-like)
β”‚   └── codec.rs        # Binary encode/decode
β”œβ”€β”€ wal/                # Write-Ahead Log (Phase 5)
β”œβ”€β”€ buffer/             # Buffer pool LRU (Phase 6)
└── concurrency/        # SWMR locks (Phase 7)
```

## License

MIT