From f071837487e8ea3fc7d80f39cc8239c452006071 Mon Sep 17 00:00:00 2001 From: Elio Neto Date: Fri, 6 Mar 2026 18:09:03 -0300 Subject: [PATCH 1/7] feat: add CLI binary to enable cargo run --bin cli Adds dedicated binary for CLI REPL interface. Users can now run: cargo run --bin cli --- src/bin/cli.rs | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/bin/cli.rs diff --git a/src/bin/cli.rs b/src/bin/cli.rs new file mode 100644 index 0000000..fee0766 --- /dev/null +++ b/src/bin/cli.rs @@ -0,0 +1,5 @@ +use apexstore::cli; + +fn main() -> Result<(), Box> { + cli::main() +} From 63cb0113c27b9bbef58a41d7d75f5d3fb2773cf3 Mon Sep 17 00:00:00 2001 From: Elio Neto Date: Fri, 6 Mar 2026 18:09:22 -0300 Subject: [PATCH 2/7] feat: register CLI binary in Cargo.toml Adds CLI binary configuration enabling: - cargo run --bin cli (for REPL interface) - cargo run --bin apexstore-server (for API server) --- Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 2d70743..c25eea9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,10 @@ description = "A high-performance LSM-tree storage engine with SSTable V2 format name = "apexstore-server" path = "src/bin/server.rs" +[[bin]] +name = "cli" +path = "src/bin/cli.rs" + [lib] name = "apexstore" path = "src/lib.rs" From 45b099047fde515add78fd612534d52c0c29fa8b Mon Sep 17 00:00:00 2001 From: Elio Neto Date: Fri, 6 Mar 2026 18:09:43 -0300 Subject: [PATCH 3/7] feat: export cli module in lib.rs Makes CLI module accessible to the cli binary --- src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 1c57ec1..b5f364e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,6 +69,7 @@ //! - [`infra`] - Infrastructure (config, error handling, codec) //! - [`features`] - Feature flags system //! - [`api`] - REST API server (optional, requires "api" feature) +//! - [`cli`] - Interactive CLI REPL interface //! //! ## Feature Flags //! @@ -87,6 +88,7 @@ //! - [Configuration Guide](https://github.com/ElioNeto/ApexStore/blob/main/docs/CONFIGURATION.md) //! - [API Documentation](https://github.com/ElioNeto/ApexStore/blob/main/docs/API.md) +pub mod cli; pub mod core; pub mod features; pub mod infra; From c846e540190ac4d7e5f2206ef69fc37e44ca7727 Mon Sep 17 00:00:00 2001 From: Elio Neto Date: Fri, 6 Mar 2026 18:10:25 -0300 Subject: [PATCH 4/7] docs: add quick start guide for running CLI and server Explains the different ways to run ApexStore: - CLI REPL interface - API server - Common issues and solutions --- QUICKSTART.md | 305 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 QUICKSTART.md diff --git a/QUICKSTART.md b/QUICKSTART.md new file mode 100644 index 0000000..5b4160c --- /dev/null +++ b/QUICKSTART.md @@ -0,0 +1,305 @@ +# ApexStore Quick Start Guide + +## πŸš€ Running ApexStore + +ApexStore provides two main interfaces: + +### 1. πŸ–₯️ CLI REPL Interface (Interactive) + +For development, testing, and interactive data exploration. + +```bash +# Start the interactive CLI +cargo run --bin cli + +# Or in release mode (faster) +cargo run --release --bin cli +``` + +**Features:** +- Interactive REPL (Read-Eval-Print Loop) +- All commands: SET, GET, DELETE, SEARCH, STATS, BATCH, etc. +- Perfect for testing and debugging +- See [CLI Guide](docs/CLI_GUIDE.md) for all commands + +**Example Session:** +```bash +lsm> SET user:alice Alice Silva +βœ“ SET 'user:alice' executado com sucesso + +lsm> GET user:alice +βœ“ 'user:alice' = 'Alice Silva' + +lsm> SEARCH user: --prefix +βœ“ 1 registro(s) encontrado(s): + user:alice = Alice Silva + +lsm> STATS ALL +{ + "mem_records": 1, + "mem_kb": 0, + ... +} + +lsm> exit +πŸ‘‹ Encerrando LSM-Tree CLI... +``` + +### 2. 🌐 API Server (Production) + +For production deployments with REST API access. + +```bash +# Start the API server +cargo run --bin apexstore-server + +# Or in release mode (recommended for production) +cargo run --release --bin apexstore-server + +# With custom configuration +DATA_DIR=./data MEMTABLE_MAX_SIZE=16777216 cargo run --bin apexstore-server +``` + +**Features:** +- REST API with JSON payloads +- Actix-Web server (high performance) +- Environment-based configuration +- Production-ready with error handling + +**Default Server:** +- URL: `http://0.0.0.0:8080` +- Health Check: `curl http://localhost:8080/health` + +**Example API Calls:** +```bash +# Insert data +curl -X POST http://localhost:8080/keys \ + -H "Content-Type: application/json" \ + -d '{"key": "user:1", "value": "Alice"}' + +# Get data +curl http://localhost:8080/keys/user:1 + +# Search +curl "http://localhost:8080/keys/search?q=user:&prefix=true" + +# Stats +curl http://localhost:8080/stats/all +``` + +## πŸ“¦ Build Commands + +### Development Builds (Faster compilation) + +```bash +# Build CLI +cargo build --bin cli + +# Build server +cargo build --bin apexstore-server + +# Build both +cargo build --bins +``` + +### Release Builds (Optimized performance) + +```bash +# Build CLI (optimized) +cargo build --release --bin cli + +# Build server (optimized) +cargo build --release --bin apexstore-server + +# Run directly after building +./target/release/cli +./target/release/apexstore-server +``` + +## 🐳 Docker Deployment + +### Quick Start with Docker Compose + +```bash +# Start server +docker-compose up -d + +# View logs +docker-compose logs -f apexstore + +# Stop server +docker-compose down +``` + +### Standalone Docker + +```bash +# Build image +docker build -t apexstore:latest . + +# Run server +docker run -d \ + --name apexstore-server \ + -p 8080:8080 \ + -v apexstore-data:/data \ + apexstore:latest +``` + +## βš™οΈ Configuration + +### CLI Configuration + +The CLI uses default settings optimized for development: +- **Data Directory**: `./.lsm_data` +- **MemTable Size**: 4KB (for quick flushes during testing) + +You can modify these in `src/cli/mod.rs` or pass environment variables. + +### Server Configuration + +The server reads configuration from environment variables: + +```bash +# Create .env file +cp .env.example .env + +# Edit configuration +nano .env + +# Start with custom config +source .env +cargo run --bin apexstore-server +``` + +**Key Variables:** +```bash +DATA_DIR=./.lsm_data +MEMTABLE_MAX_SIZE=16777216 # 16MB +BLOCK_CACHE_SIZE_MB=64 +BLOCK_SIZE=4096 +HOST=0.0.0.0 +PORT=8080 +``` + +See [Configuration Guide](docs/CONFIGURATION.md) for all options. + +## πŸ” Testing + +```bash +# Run all tests +cargo test + +# Run specific test +cargo test test_builder_basic + +# Run with output +cargo test -- --nocapture + +# Check code quality +cargo clippy -- -D warnings + +# Format code +cargo fmt +``` + +## ❓ Common Issues + +### Issue: `cargo run` doesn't start server + +**Problem:** Running `cargo run` without `--bin` uses the default binary which just exits. + +**Solution:** +```bash +# ❌ Wrong (uses default binary) +cargo run + +# βœ… Correct (specify binary) +cargo run --bin apexstore-server # For API server +cargo run --bin cli # For CLI REPL +``` + +### Issue: "Address already in use" + +**Problem:** Port 8080 is already occupied. + +**Solution 1:** Stop the other process using port 8080 +```bash +# Find process +lsof -i :8080 + +# Kill process +kill +``` + +**Solution 2:** Use a different port +```bash +PORT=8081 cargo run --bin apexstore-server +``` + +### Issue: "Failed to load SSTable" or "Corrupted data" + +**Problem:** Incompatible SSTable format from previous version or corrupted data. + +**Solution:** Remove old data files +```bash +# Backup first (optional) +cp -r .lsm_data .lsm_data.backup + +# Remove old data +rm -rf .lsm_data/*.sst +rm -rf .lsm_data/wal.log + +# Restart server/CLI +cargo run --bin apexstore-server +``` + +### Issue: CLI commands not recognized + +**Problem:** Typo or incorrect command syntax. + +**Solution:** Use `HELP` command +```bash +lsm> HELP +# Shows all available commands with syntax +``` + +## πŸ“š Documentation + +- [README.md](README.md) - Project overview and architecture +- [CLI Guide](docs/CLI_GUIDE.md) - Complete CLI reference +- [Configuration Guide](docs/CONFIGURATION.md) - All configuration options +- [API Documentation](docs/API.md) - REST API endpoints +- [Contributing Guide](docs/CONTRIBUTING.md) - Development guidelines + +## 🎯 Next Steps + +### For Development: +1. Start CLI: `cargo run --bin cli` +2. Try commands: `SET`, `GET`, `SEARCH`, `STATS ALL` +3. Import sample data: `BATCH SET examples/batch_data.txt` +4. Explore: See [CLI Guide](docs/CLI_GUIDE.md) + +### For Production: +1. Configure: Copy and edit `.env.example` +2. Build: `cargo build --release --bin apexstore-server` +3. Deploy: Use Docker or systemd service +4. Monitor: Check `/stats/all` endpoint + +## πŸ’‘ Tips + +- **Use release builds** for production (10x faster) +- **Monitor with `STATS ALL`** in CLI or `/stats/all` in API +- **Use prefix-based keys** (e.g., `user:123`, `product:456`) for efficient searches +- **BATCH SET** for bulk imports (faster than individual SETs) +- **Docker** recommended for production deployments + +## πŸ†˜ Need Help? + +- πŸ“– Check the [CLI Guide](docs/CLI_GUIDE.md) for command syntax +- πŸ› [Open an issue](https://github.com/ElioNeto/ApexStore/issues) for bugs +- πŸ’¬ [Discussions](https://github.com/ElioNeto/ApexStore/discussions) for questions +- πŸ“§ Email: netoo.elio@hotmail.com + +--- + +**Built with πŸ¦€ Rust and ❀️** From c5c1fd8cfdae615aa8c967823bd6bc167ebf7a98 Mon Sep 17 00:00:00 2001 From: Elio Neto Date: Fri, 6 Mar 2026 18:12:50 -0300 Subject: [PATCH 5/7] fix: resolve CLI compilation errors Fixes: - Use crate:: instead of apexstore:: for internal imports - Fix Vec type annotations for engine return values - Add proper type handling for all search/scan operations --- src/cli/mod.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index d0c1457..99199fd 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,4 +1,4 @@ -use apexstore::{LsmConfig, LsmEngine}; +use crate::{LsmConfig, LsmEngine}; use std::io::{self, Write}; use std::path::PathBuf; @@ -15,18 +15,17 @@ pub fn main() -> Result<(), Box> { println!("β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\n"); // ConfiguraΓ§Γ£o - let config = LsmConfig { - memtable_max_size: 4 * 1024, // 4KB para testes - data_dir: PathBuf::from("./.lsm_data"), - }; + let config = LsmConfig::builder() + .dir_path(PathBuf::from("./.lsm_data")) + .memtable_max_size(4 * 1024) // 4KB para testes + .build()?; - // ADICIONAR ESTA LINHA: println!( "πŸ“‚ DiretΓ³rio de dados: {}", - config.data_dir.canonicalize()?.display() + config.core.data_dir.display() ); - println!("Inicializando engine em: {}", config.data_dir.display()); + println!("Inicializando engine..."); let engine = LsmEngine::new(config)?; println!("βœ“ Engine inicializado com sucesso!\n"); @@ -270,7 +269,7 @@ pub fn main() -> Result<(), Box> { let key_display = if key.len() > 20 { format!("{}...", &key[..17]) } else { - key + key.clone() }; let value_display = if value_str.len() > 20 { format!("{}...", &value_str[..17]) From 2968b4efbc0ad4d70aaa3d49b6d3bb1248f02f9f Mon Sep 17 00:00:00 2001 From: Elio Neto Date: Fri, 6 Mar 2026 18:38:57 -0300 Subject: [PATCH 6/7] fix: correct field name from data_dir to dir_path Fixes compilation error by using the correct field name from CoreConfig struct. --- src/cli/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 99199fd..157688a 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -22,7 +22,7 @@ pub fn main() -> Result<(), Box> { println!( "πŸ“‚ DiretΓ³rio de dados: {}", - config.core.data_dir.display() + config.core.dir_path.display() ); println!("Inicializando engine..."); From c5edbd0b09d3a52a73cd4aba331b6ad976277f57 Mon Sep 17 00:00:00 2001 From: Elio Neto Date: Fri, 6 Mar 2026 19:53:17 -0300 Subject: [PATCH 7/7] style: apply cargo fmt formatting to CLI - Fix println! multiline formatting - Fix match expression indentation - Remove trailing whitespace - Improve code readability per rustfmt rules --- src/cli/mod.rs | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 157688a..4cf24d3 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -20,10 +20,7 @@ pub fn main() -> Result<(), Box> { .memtable_max_size(4 * 1024) // 4KB para testes .build()?; - println!( - "πŸ“‚ DiretΓ³rio de dados: {}", - config.core.dir_path.display() - ); + println!("πŸ“‚ DiretΓ³rio de dados: {}", config.core.dir_path.display()); println!("Inicializando engine..."); let engine = LsmEngine::new(config)?; @@ -97,12 +94,10 @@ pub fn main() -> Result<(), Box> { // Check if "ALL" parameter is provided if parts.len() > 1 && parts[1].to_uppercase() == "ALL" { match engine.stats_all() { - Ok(stats) => { - match serde_json::to_string_pretty(&stats) { - Ok(json) => println!("{}", json), - Err(e) => println!("❌ Erro ao serializar JSON: {}", e), - } - } + Ok(stats) => match serde_json::to_string_pretty(&stats) { + Ok(json) => println!("{}", json), + Err(e) => println!("❌ Erro ao serializar JSON: {}", e), + }, Err(e) => println!("❌ Erro: {}", e), } } else { @@ -115,16 +110,16 @@ pub fn main() -> Result<(), Box> { println!("❌ Uso: SEARCH [--prefix]"); continue; } - + let query = parts[1]; let prefix_mode = parts.len() > 2 && parts[2] == "--prefix"; - + let results = if prefix_mode { engine.search_prefix(query) } else { engine.search(query) }; - + match results { Ok(records) => { if records.is_empty() { @@ -166,22 +161,22 @@ pub fn main() -> Result<(), Box> { // BATCH SET let file_path = parts[2]; println!("Importando de {}...", file_path); - + match std::fs::read_to_string(file_path) { Ok(content) => { let mut count = 0; let mut errors = 0; - + for (line_num, line) in content.lines().enumerate() { let line = line.trim(); if line.is_empty() || line.starts_with('#') { continue; // Skip empty lines and comments } - + if let Some((key, value)) = line.split_once('=') { let key = key.trim(); let value = value.trim(); - + match engine.set(key.to_string(), value.as_bytes().to_vec()) { Ok(_) => count += 1, Err(e) => { @@ -190,11 +185,14 @@ pub fn main() -> Result<(), Box> { } } } else { - println!("⚠ Linha {} invΓ‘lida (formato esperado: key=value)", line_num + 1); + println!( + "⚠ Linha {} invΓ‘lida (formato esperado: key=value)", + line_num + 1 + ); errors += 1; } } - + println!("βœ“ {} registro(s) importado(s)", count); if errors > 0 { println!("⚠ {} erro(s) encontrado(s)", errors); @@ -235,14 +233,18 @@ pub fn main() -> Result<(), Box> { continue; } let prefix = parts[1]; - + // Use the search_prefix method now available match engine.search_prefix(prefix) { Ok(records) => { if records.is_empty() { println!("⚠ Nenhum registro encontrado com prefixo '{}'", prefix); } else { - println!("βœ“ {} registro(s) com prefixo '{}':\n", records.len(), prefix); + println!( + "βœ“ {} registro(s) com prefixo '{}':\n", + records.len(), + prefix + ); for (key, value) in records { let value_str = String::from_utf8_lossy(&value); println!(" {} = {}", key, value_str); @@ -391,7 +393,7 @@ fn run_demo(engine: &LsmEngine) -> Result<(), Box> { Ok(results) => println!(" Encontrados {} registros", results.len()), Err(e) => println!(" Erro: {}", e), } - + println!(" - SEARCH user: --prefix"); match engine.search_prefix("user:") { Ok(results) => println!(" Encontrados {} registros", results.len()), @@ -401,7 +403,7 @@ fn run_demo(engine: &LsmEngine) -> Result<(), Box> { println!("7. EstatΓ­sticas finais (bΓ‘sicas):"); println!("{}", engine.stats()); - + println!("\n8. EstatΓ­sticas detalhadas:"); match engine.stats_all() { Ok(stats) => {