diff --git a/README.md b/README.md index 32948c1d..4f7e4d9a 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ a low-latency, memory-efficient, distributed cache written in Rust. designed to - **lru eviction** — approximate LRU via random sampling when memory pressure hits - **persistence** — append-only file (AOF) and point-in-time snapshots - **pipelining** — multiple commands per read for high throughput -- **interactive CLI** — `ember-cli` with REPL, tab-completion, inline help, and one-shot mode +- **interactive CLI** — `ember-cli` with REPL, syntax highlighting, tab-completion, inline hints, cluster subcommands, and built-in benchmark - **graceful shutdown** — drains active connections on SIGINT/SIGTERM before exiting ## quickstart @@ -61,7 +61,7 @@ cargo build --release --tls-cert-file cert.pem --tls-key-file key.pem ``` -ember speaks RESP3, so `redis-cli` works as a drop-in replacement — but `ember-cli` adds tab-completion, inline help, and auto-reconnect. +ember speaks RESP3, so `redis-cli` works as a drop-in replacement — but `ember-cli` adds syntax highlighting, tab-completion, inline hints, and auto-reconnect. ```bash # ember-cli: interactive REPL with autocomplete and help @@ -73,6 +73,14 @@ ember-cli -a mypassword # authenticate ember-cli SET hello world # => OK ember-cli GET hello # => "hello" +# cluster management subcommands +ember-cli cluster info # cluster state +ember-cli cluster nodes # list nodes +ember-cli cluster meet 10.0.0.1 6379 + +# built-in benchmark +ember-cli benchmark -n 100000 -c 50 -P 16 + # redis-cli works too — same protocol, same port redis-cli SET hello world # => OK redis-cli GET hello # => "world" @@ -172,7 +180,7 @@ crates/ ember-protocol/ RESP3 wire protocol ember-persistence/ AOF and snapshot durability ember-cluster/ raft consensus, gossip, slot management, migration - ember-cli/ interactive CLI client (REPL, one-shot, autocomplete) + ember-cli/ interactive CLI client (REPL, cluster subcommands, benchmark) ``` ## architecture @@ -227,7 +235,7 @@ contributions welcome — see [CONTRIBUTING.md](CONTRIBUTING.md). | 4 | clustering (raft, gossip, slots, migration) | ✅ complete | | 5 | developer experience (observability, CLI, clients) | 🚧 in progress | -**current**: 85 commands, 753 tests, ~14k lines of code (excluding tests) +**current**: 85 commands, 861 tests, ~18k lines of code (excluding tests) ## security diff --git a/bench/README.md b/bench/README.md index 074d1150..713b11de 100644 --- a/bench/README.md +++ b/bench/README.md @@ -212,6 +212,23 @@ KEY_COUNT=5000000 VALUE_SIZE=128 ./bench/bench-memory.sh | `MEMTIER_REQUESTS` | 10000 | requests per client (480k total) | | `MEMTIER_PIPELINE` | 16 | pipeline depth | +## built-in benchmark + +ember also ships a built-in benchmark tool that doesn't require external dependencies: + +```bash +# basic benchmark (100k requests, 50 clients) +ember-cli benchmark + +# high-throughput with pipelining +ember-cli benchmark -n 1000000 -c 50 -P 16 + +# specific workloads +ember-cli benchmark -t set,get,ping -d 128 +``` + +see `ember-cli benchmark --help` for all options. + ## micro-benchmarks for criterion micro-benchmarks: diff --git a/crates/ember-cli/README.md b/crates/ember-cli/README.md index 75c45b64..3029ac14 100644 --- a/crates/ember-cli/README.md +++ b/crates/ember-cli/README.md @@ -34,13 +34,85 @@ ember-cli SET msg "hello world" ## repl features -- **tab completion** — press tab to autocomplete command names +- **tab completion** — press tab to autocomplete command names and subcommands +- **syntax highlighting** — known commands in cyan, unknown in red, quoted strings in green +- **inline hints** — shows argument synopsis and subcommand options as you type - **history** — command history persisted to `~/.emberkv_history` - **inline help** — type `help` for all commands, `help SET` for details - **reconnection** — automatically reconnects if the server disconnects - **quoted strings** — double and single quoted arguments with backslash escapes - **timeouts** — 5s connect timeout, 10s read timeout to avoid hanging +## cluster subcommands + +manage a cluster directly from the CLI without manually typing `CLUSTER` commands: + +```bash +ember-cli cluster info +ember-cli cluster nodes +ember-cli cluster slots +ember-cli cluster keyslot mykey +ember-cli cluster myid +ember-cli cluster meet 10.0.0.1 6379 +ember-cli cluster forget +ember-cli cluster addslots 0 1 2 3 +ember-cli cluster delslots 100 200 +ember-cli cluster setslot 42 importing +ember-cli cluster setslot 42 migrating +ember-cli cluster setslot 42 node +ember-cli cluster setslot 42 stable +ember-cli cluster replicate +ember-cli cluster failover --force +ember-cli cluster failover --takeover +ember-cli cluster countkeysinslot 42 +ember-cli cluster getkeysinslot 42 10 +``` + +## built-in benchmark + +run a built-in benchmark with pipelining support and latency percentile reporting: + +```bash +# basic benchmark (100k requests, 50 clients) +ember-cli benchmark + +# high-throughput test with pipelining +ember-cli benchmark -n 1000000 -c 50 -P 16 + +# test specific workloads +ember-cli benchmark -t set,get,ping + +# customize data size and keyspace +ember-cli benchmark -d 128 --keyspace 1000000 + +# quiet mode — summary lines only +ember-cli benchmark -q +``` + +| flag | default | description | +|------|---------|-------------| +| `-n`, `--requests` | 100,000 | total number of requests | +| `-c`, `--clients` | 50 | concurrent client connections | +| `-P`, `--pipeline` | 1 | commands per pipeline batch | +| `-d`, `--data-size` | 64 | value payload size in bytes | +| `-t`, `--tests` | set,get | comma-separated workloads (`set`, `get`, `ping`) | +| `--keyspace` | 100,000 | number of unique keys | +| `-q`, `--quiet` | — | only print summary lines | + +output: + +``` +=== ember benchmark === +server: 127.0.0.1:6379 +requests: 100,000 +clients: 50 +pipeline: 16 +data size: 64 bytes + +SET: 523,809 rps p50: 120us p99: 410us p99.9: 1.23ms max: 4.56ms +GET: 612,345 rps p50: 100us p99: 380us p99.9: 1.01ms max: 3.21ms +``` + ## local commands these are handled by the client and not sent to the server: diff --git a/crates/ember-cluster/README.md b/crates/ember-cluster/README.md index e887b57b..64f5e4cf 100644 --- a/crates/ember-cluster/README.md +++ b/crates/ember-cluster/README.md @@ -74,4 +74,4 @@ the following CLUSTER commands are supported at the protocol layer: | [ember-protocol](../ember-protocol) | RESP3 parsing and command dispatch | | [ember-persistence](../ember-persistence) | AOF, snapshots, and crash recovery | | [ember-server](../ember-server) | TCP server and connection handling | -| [ember-cli](../ember-cli) | interactive command-line client (planned) | +| [ember-cli](../ember-cli) | interactive CLI client (REPL, cluster subcommands, benchmark) | diff --git a/crates/ember-core/README.md b/crates/ember-core/README.md index c5949fc7..debcc06d 100644 --- a/crates/ember-core/README.md +++ b/crates/ember-core/README.md @@ -35,4 +35,4 @@ let response = engine.route("mykey", ShardRequest::Get { | [ember-persistence](../ember-persistence) | AOF, snapshots, and crash recovery | | [ember-server](../ember-server) | TCP server and connection handling | | [ember-cluster](../ember-cluster) | distributed coordination | -| [ember-cli](../ember-cli) | interactive command-line client (planned) | +| [ember-cli](../ember-cli) | interactive CLI client (REPL, cluster subcommands, benchmark) | diff --git a/crates/ember-persistence/README.md b/crates/ember-persistence/README.md index ebf81f93..d9706ad5 100644 --- a/crates/ember-persistence/README.md +++ b/crates/ember-persistence/README.md @@ -41,4 +41,4 @@ for entry in result.entries { | [ember-protocol](../ember-protocol) | RESP3 parsing and command dispatch | | [ember-server](../ember-server) | TCP server and connection handling | | [ember-cluster](../ember-cluster) | distributed coordination | -| [ember-cli](../ember-cli) | interactive command-line client (planned) | +| [ember-cli](../ember-cli) | interactive CLI client (REPL, cluster subcommands, benchmark) | diff --git a/crates/ember-protocol/README.md b/crates/ember-protocol/README.md index db8d384e..56e46655 100644 --- a/crates/ember-protocol/README.md +++ b/crates/ember-protocol/README.md @@ -60,4 +60,4 @@ let cmd = Command::from_frame(frame).unwrap(); | [ember-persistence](../ember-persistence) | AOF, snapshots, and crash recovery | | [ember-server](../ember-server) | TCP server and connection handling | | [ember-cluster](../ember-cluster) | distributed coordination | -| [ember-cli](../ember-cli) | interactive command-line client (planned) | +| [ember-cli](../ember-cli) | interactive CLI client (REPL, cluster subcommands, benchmark) | diff --git a/crates/ember-server/README.md b/crates/ember-server/README.md index ae301d88..e4a84b98 100644 --- a/crates/ember-server/README.md +++ b/crates/ember-server/README.md @@ -37,4 +37,4 @@ compatible with `redis-cli` and any RESP3 client. | [ember-protocol](../ember-protocol) | RESP3 parsing and command dispatch | | [ember-persistence](../ember-persistence) | AOF, snapshots, and crash recovery | | [ember-cluster](../ember-cluster) | distributed coordination | -| [ember-cli](../ember-cli) | interactive command-line client (planned) | +| [ember-cli](../ember-cli) | interactive CLI client (REPL, cluster subcommands, benchmark) |