wedb_embed 0.1.1

Embedded database engine providing Redis-like APIs, built on fjall / 嵌入式数据库引擎,提供类似 Redis 的接口,底层基于 fjall 开发
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
[English]#en | [中文]#zh

[![crates.io]https://img.shields.io/crates/v/wedb_embed.svg]https://crates.io/crates/wedb_embed
[![docs.rs]https://docs.rs/wedb_embed/badge.svg]https://docs.rs/wedb_embed

---

<a id="en"></a>
# wedb_embed : Embedded database engine providing Redis-like APIs, built on [fjall]https://github.com/fjall-rs/fjall

- [wedb_embed : Embedded database engine providing Redis-like APIs, built on [fjall](https://github.com/fjall-rs/fjall)]#wedb_embed-embedded-database-engine-providing-redis-like-apis-built-on-fjallhttpsgithubcomfjall-rsfjall
  - [Motivation]#motivation
  - [Core Architecture & Encoding Design]#core-architecture-encoding-design
    - [1. Default DB Prefix Optimization & 1-Byte Tag]#1-default-db-prefix-optimization-1-byte-tag
    - [2. OPPV Order-Preserving Prefix Varint (`oppv_u64`)]#2-oppv-order-preserving-prefix-varint-oppv_u64
    - [3. Numerical Tenant ID Mapping & Renaming]#3-numerical-tenant-id-mapping-renaming
    - [4. Streaming Iterators]#4-streaming-iterators
  - [Usage]#usage
    - [1. Database Initialization & Configuration (`WeDb` & `Conf`)]#1-database-initialization-configuration-wedb-conf
    - [2. Multi-Tenant & Multi-DB Isolation (`Namespace`)]#2-multi-tenant-multi-db-isolation-namespace
    - [3. Key-Value & String Operations (`KvOps`)]#3-key-value-string-operations-kvops
    - [4. Hash Map (`HashOps`)]#4-hash-map-hashops
    - [5. List (`ListOps`)]#5-list-listops
    - [6. Set (`SetOps`)]#6-set-setops
    - [7. Sorted Set (`ZSetOps`)]#7-sorted-set-zsetops
    - [8. Bitmap, Bloom Filter, TimeSeries & Geo (`BitmapOps`, `BloomOps`, `TsOps`, `GeoOps`)]#8-bitmap-bloom-filter-timeseries-geo-bitmapops-bloomops-tsops-geoops
  - [Tech Stack]#tech-stack
  - [Benchmark & Performance]#benchmark-performance
    - [Environment: Ubuntu CI (GitHub Actions Runner)]#environment-ubuntu-ci-github-actions-runner
      - [WeDb (Embedded Engine) vs Redis (v8.10.1 Standalone Server) Performance Comparison]#wedb-embedded-engine-vs-redis-v8101-standalone-server-performance-comparison
      - [Regression Benchmark]#regression-benchmark
    - [Environment: macOS (Apple M2 Max)]#environment-macos-apple-m2-max
      - [WeDb (Embedded Engine) vs Redis (v8.10.1 Standalone Server) Performance Comparison]#wedb-embedded-engine-vs-redis-v8101-standalone-server-performance-comparison
      - [Regression Benchmark]#regression-benchmark

Embedded multi-model database engine in Rust, providing Redis-compatible data structures and APIs, built on [fjall](https://github.com/fjall-rs/fjall) LSM-Tree for disk-backed persistence.

---

## Motivation

In standalone services and embedded application scenarios, running an external Redis daemon introduces process management overhead and IPC / socket communication round trips.

`wedb_embed` provides rich Redis-compatible APIs directly as an in-process Rust library:
- **In-Process Direct Calls**: Eliminates network and IPC latency by reading and writing within the host application process.
- **Rich Redis Data Models**: Supports String, Hash, List, Set, ZSet, Bitmap, JSON, Bloom/Cuckoo Filter, TimeSeries, Geo, HyperLogLog, TDigest, SortedInt, Stream (all 15 composite types).
- **Multi-Tenant & Multi-DB Isolation**: Full $2^{64}$ tenant and $2^{64}$ database capacity with atomic renaming and physical isolation.
- **Compact Binary Encoding**: Default namespace 0-byte prefix bypass, composite types encoded with 1-Byte `KeyTag` and OPPV order-preserving varints.
- **Disk Persistence & Crash Consistency**: Built on [fjall]https://github.com/fjall-rs/fjall LSM-Tree and cross-keyspace atomic write batches for crash-safe operations.

---

## Core Architecture & Encoding Design

```mermaid
graph TD
  Client["Application Code"] --> WeDb["WeDb Instance"]
  WeDb --> NS["Namespace Handle<br/>(Zero-Heap Struct)"]

  subgraph KeyComposer["Key Composer & Fast Encoding"]
    Tag["1-Byte Fast KeyTag (#[repr(u8)])"]
    OPPV["OPPV Order-Preserving Varint (1~9B)"]
    DefaultBypass["Default NS 0-Prefix Bypass"]
    Slot["CRC16 Slot & {hashtag}"]
  end

  subgraph Engine["Storage Engine Layer"]
    Batch["Atomic WriteBatch (Cross-Keyspace WAL)"]
    Catalog["Catalog Compact Index"]
  end

  subgraph Storage["Fjall LSM Partitions"]
    DataKS["Data Keyspace<br/>(Payloads & Subkeys / 64KB Blocks)"]
    MetaKS["Meta Keyspace<br/>(Indices, TTL & Metadata / 4KB Blocks)"]
  end

  WeDb --> KeyComposer
  NS --> KeyComposer
  KeyComposer --> Engine
  Engine --> DataKS
  Engine --> MetaKS
```

### 1. Default DB Prefix Optimization & 1-Byte Tag
- **Default Namespace**: Keys are stored as raw bytes `user_key` with 0-byte prefix overhead.
- **1-Byte Fast Tag (`KeyTag`)**: Composite metadata and subkey prefixes use `#[repr(u8)] KeyTag` encoding (`\x00\x01:key`), avoiding redundant string prefixes.

### 2. OPPV Order-Preserving Prefix Varint (`oppv_u64`)
- Database index and tenant numerical IDs use **OPPV (Order-Preserving Prefix Varint)** encoding:
  - Databases $0 \sim 127$: Encoded in 1 byte.
  - Preserves lexicographical byte order equal to numeric value order: $\forall a < b \implies \text{encode}(a) < \text{encode}(b)$.

### 3. Numerical Tenant ID Mapping & Renaming
- Tenant names map to `ns_id: u64` via global metadata.
- **Tenant Renaming (`rename_namespace`)**: Metadata mapping updated without rewriting underlying data.

### 4. Streaming Iterators
- **`WeDb::iter(&self) -> Namespaces`**: Iterates distinct tenants via Jump-Seek.
- **`Namespace::iter(&self) -> Dbs`**: Decodes OPPV catalog entries.

---

## Usage

### 1. Database Initialization & Configuration (`WeDb` & `Conf`)

```rust
use wedb_embed::{Conf, PersistMode, Result, WeDb};

fn main() -> Result<()> {
    // 1. Open with custom configuration
    let mut conf = Conf::new("./data/db_demo");
    conf.db.flush_workers = 2; // Background flush worker threads
    let db = WeDb::open_with_conf(&conf)?;

    // 2. Persistence and active expiration tasks
    db.persist(PersistMode::SyncAll)?; // Synchronously persist WAL and dirty pages
    db.active_expire_cycle(100)?;       // Trigger active key expiration sampling

    Ok(())
}
```

### 2. Multi-Tenant & Multi-DB Isolation (`Namespace`)

```rust
use wedb_embed::{KvOps, Result, WeDb};

fn main() -> Result<()> {
    let db = WeDb::open("./data/multitenant_demo")?;

    // Tenant-isolated handle (lightweight zero-copy struct)
    let ns_apple = db.namespace("tenant_apple");
    let ns_google = db.namespace("tenant_google");

    ns_apple.set(b"config:theme", b"dark", &[])?;
    ns_google.set(b"config:theme", b"light", &[])?;

    // Physically isolated lookups
    assert_eq!(ns_apple.get(b"config:theme")?.unwrap(), b"dark");
    assert_eq!(ns_google.get(b"config:theme")?.unwrap(), b"light");

    // Multi-DB selection (e.g. SELECT 1)
    let db1 = db.select_db(1);
    db1.set(b"db1_key", b"value1", &[])?;

    // Iterate active databases under tenant
    for db_idx in &ns_apple {
        println!("Active DB: {}", db_idx);
    }

    // Tenant renaming
    db.rename_namespace("tenant_apple", "tenant_apple_v2")?;

    // Keyspace management
    let key_count = ns_apple.key_count()?;
    let keys = ns_apple.keys(b"config:*")?;
    let exists_count = ns_apple.exists(&[b"config:theme".as_slice()])?;
    ns_apple.del(&[b"config:theme".as_slice()])?;
    ns_apple.clear()?; // Cascade clear all tenant data

    Ok(())
}
```

### 3. Key-Value & String Operations (`KvOps`)

```rust
use wedb_embed::{KvOps, Result, WeDb, string::Set};

fn main() -> Result<()> {
    let db = WeDb::open("./data/kv_demo")?;

    // Basic read, write, and TTL expiration
    db.set(b"site", b"webc.site", &[])?;
    let val = db.get(b"site")?;
    db.set_ex(b"temp_token", b"xyz", 3600)?;

    // Conditional write (NX / XX)
    db.set(b"lock", b"1", &[Set::Nx])?;

    // Numerical increment & decrement
    db.incr(b"counter")?;
    db.incrby(b"counter", 10)?;
    db.decrby(b"counter", 5)?;

    // Batch & string operations
    db.mset(&[(b"k1", b"v1"), (b"k2", b"v2")])?;
    let values = db.mget(&[b"k1".as_slice(), b"k2".as_slice()])?;
    let len = db.strlen(b"site")?;
    let old_val = db.getset(b"site", b"new_site")?;
    let del_val = db.getdel(b"site")?;

    Ok(())
}
```

### 4. Hash Map (`HashOps`)

```rust
use wedb_embed::{HashOps, Result, WeDb};

fn main() -> Result<()> {
    let db = WeDb::open("./data/hash_demo")?;

    // Field set & get
    db.hset(b"user:100", b"name", b"Alice")?;
    db.hset(b"user:100", b"age", b"20")?;
    let name = db.hget(b"user:100", b"name")?;

    // Batch field operations
    db.hmset(b"user:100", &[(b"city", b"Beijing"), (b"role", b"Admin")])?;
    let fields = db.hmget(b"user:100", &[b"name".as_slice(), b"city".as_slice()])?;

    // Counter increment and introspection
    db.hincrby(b"user:100", b"age", 1)?;
    let exists = db.hexists(b"user:100", b"name")?;
    let len = db.hlen(b"user:100")?;
    let all = db.hgetall(b"user:100")?;
    let keys = db.hkeys(b"user:100")?;
    let vals = db.hvals(b"user:100")?;
    db.hdel(b"user:100", &[b"role".as_slice()])?;

    Ok(())
}
```

### 5. List (`ListOps`)

```rust
use wedb_embed::{ListOps, Result, WeDb};

fn main() -> Result<()> {
    let db = WeDb::open("./data/list_demo")?;

    // Push and pop
    db.lpush(b"tasks", &[b"task1".as_slice(), b"task2".as_slice()])?;
    db.rpush(b"tasks", &[b"task3".as_slice()])?;
    let first = db.lpop(b"tasks", 1)?;
    let last = db.rpop(b"tasks", 1)?;

    // Range query and trim
    let len = db.llen(b"tasks")?;
    let items = db.lrange(b"tasks", 0, -1)?;
    db.ltrim(b"tasks", 0, 10)?;
    db.lset(b"tasks", 0, b"updated_task")?;

    Ok(())
}
```

### 6. Set (`SetOps`)

```rust
use wedb_embed::{Result, SetOps, WeDb};

fn main() -> Result<()> {
    let db = WeDb::open("./data/set_demo")?;

    db.sadd(b"tags", &[b"rust".as_slice(), b"database".as_slice(), b"lsm".as_slice()])?;
    let is_member = db.sismember(b"tags", b"rust")?;
    let count = db.scard(b"tags")?;
    let members = db.smembers(b"tags")?;
    db.srem(b"tags", &[b"lsm".as_slice()])?;
    let popped = db.spop(b"tags", 1)?;

    Ok(())
}
```

### 7. Sorted Set (`ZSetOps`)

```rust
use wedb_embed::{Result, WeDb, ZSetOps};

fn main() -> Result<()> {
    let db = WeDb::open("./data/zset_demo")?;

    // Add members with scores
    db.zadd(b"leaderboard", &[(100.0, b"player1".as_slice()), (200.0, b"player2".as_slice())], &[])?;
    db.zincrby(b"leaderboard", 50.0, b"player1")?;

    // Rank and score lookups
    let score = db.zscore(b"leaderboard", b"player1")?;
    let rank = db.zrank(b"leaderboard", b"player1")?;
    let rev_rank = db.zrevrank(b"leaderboard", b"player1")?;

    // Range queries
    let top = db.zrange(b"leaderboard", 0, 10, &[])?;
    let count = db.zcount(b"leaderboard", 100.0, 300.0)?;
    let card = db.zcard(b"leaderboard")?;
    db.zrem(b"leaderboard", &[b"player1".as_slice()])?;

    Ok(())
}
```

### 8. Bitmap, Bloom Filter, TimeSeries & Geo (`BitmapOps`, `BloomOps`, `TsOps`, `GeoOps`)

```rust
use wedb_embed::{BitmapOps, BloomOps, GeoOps, Result, TsOps, WeDb};

fn main() -> Result<()> {
    let db = WeDb::open("./data/advanced_demo")?;

    // Bitmap
    db.setbit(b"online_users", 1001, true)?;
    let is_online = db.getbit(b"online_users", 1001)?;
    let online_count = db.bitcount(b"online_users", 0, -1)?;

    // Bloom Filter
    db.bf_add(b"filter", b"item_1")?;
    let exists = db.bf_exists(b"filter", b"item_1")?;

    // TimeSeries
    db.ts_add(b"metrics:cpu", 1700000000000, 42.5, &[])?;
    let latest = db.ts_get(b"metrics:cpu")?;

    // Geo
    db.geoadd(b"cities", &[(116.4074, 39.9042, b"Beijing".as_slice()), (121.4737, 31.2304, b"Shanghai".as_slice())])?;
    let dist = db.geodist(b"cities", b"Beijing", b"Shanghai", None)?;

    Ok(())
}
```

---

## Tech Stack

- **Core Language**: Rust Edition 2024
- **Storage Engine**: `fjall` (LSM-Tree Engine)
- **JSON Engine**: `sonic-rs` (SIMD JSON Parser)
- **Hash Algorithm**: `rapidhash` (Non-Cryptographic Hash)
- **Serialization**: `bitcode` (Binary Codec)
- **Compact String**: `hipstr`
- **Time Utilities**: `coarsetime`, `ts_`
- **Error Handling**: `thiserror`

---

## Benchmark & Performance

### Environment: Ubuntu CI (GitHub Actions Runner)

- **CPU**: `Intel(R) Xeon(R) 6973P-C (4 Cores)`
- **Memory**: `15.6 GB`
- **Platform**: `Ubuntu 24.04.4 LTS (Linux 6.17.0-1022-azure) (x86_64)`
- **Compiler**: `rustc 1.98.0 (88d9e12ae 2026-08-18)`

#### WeDb (Embedded Engine) vs Redis (v8.10.1 Standalone Server) Performance Comparison

> **Benchmark Notes**:
> - WeDb: In-process direct call, LSM disk persistence (WAL journal)
> - Redis: Standalone service, AOF persistence enabled (appendfsync everysec), Unix Domain Socket

**Composite Performance**: WeDb Weighted Throughput **1.689 M ops/s** | Redis Weighted Throughput **0.024 M ops/s** | WeDb Overall Speedup **$\color{#1a7f37}\text{70.1x}$**

| Command | WeDb P95 Latency | WeDb Est. Throughput | Redis P95 Latency | Redis Est. Throughput | WeDb Speedup |
| :--- | :--- | :--- | :--- | :--- | :--- |
| SET | 6.009 µs | 1.197 M ops/s | 63.3 µs | 0.021 M ops/s | $\color{#1a7f37}\text{57.7x}$ |
| GET | 267.8 ns | 4.013 M ops/s | 55.29 µs | 0.021 M ops/s | $\color{#1a7f37}\text{192.5x}$ |
| MSET | 12.44 µs | 0.249 M ops/s | 69.21 µs | 0.031 M ops/s | $\color{#1a7f37}\text{8.0x}$ |
| MGET | 3.295 µs | 0.527 M ops/s | 49.88 µs | 0.021 M ops/s | $\color{#1a7f37}\text{25.1x}$ |
| INCRBY | 8.867 µs | 0.987 M ops/s | 79.99 µs | 0.021 M ops/s | $\color{#1a7f37}\text{47.9x}$ |
| HSET | 11.27 µs | 0.663 M ops/s | 55.14 µs | 0.021 M ops/s | $\color{#1a7f37}\text{32.3x}$ |
| HGET | 1.425 µs | 1.767 M ops/s | 63.48 µs | 0.021 M ops/s | $\color{#1a7f37}\text{84.8x}$ |
| LPUSH | 12.19 µs | 0.316 M ops/s | 81.02 µs | 0.020 M ops/s | $\color{#1a7f37}\text{15.5x}$ |
| LPOP | 3.307 µs | 0.509 M ops/s | 51.65 µs | 0.020 M ops/s | $\color{#1a7f37}\text{25.0x}$ |
| SADD | 9.665 µs | 0.682 M ops/s | 69.82 µs | 0.039 M ops/s | $\color{#1a7f37}\text{17.4x}$ |
| SISMEMBER | 579.3 ns | 1.865 M ops/s | 33.42 µs | 0.052 M ops/s | $\color{#1a7f37}\text{35.6x}$ |
| ZADD | 12.26 µs | 0.527 M ops/s | 95.59 µs | 0.021 M ops/s | $\color{#1a7f37}\text{25.2x}$ |
| ZRANGE | 9.29 µs | 0.375 M ops/s | 34.76 µs | 0.043 M ops/s | $\color{#1a7f37}\text{8.8x}$ |
| DEL | 8.569 µs | 0.737 M ops/s | 56.91 µs | 0.021 M ops/s | $\color{#1a7f37}\text{35.9x}$ |
| EXISTS | 3.642 µs | 2.391 M ops/s | 53.85 µs | 0.020 M ops/s | $\color{#1a7f37}\text{117.8x}$ |

#### Regression Benchmark

**Composite Weighted Performance**: Weighted Throughput **1.243 M ops/s** | Weighted Latency Diff **$\color{#0969da}\text{-25%}$**

| Command | P95 Latency | Est. Throughput | vs Baseline (%) |
| :--- | :--- | :--- | :--- |
| BITCOUNT | 2.912 µs | 2.100 M ops/s | $\color{#0969da}\text{-10%}$ |
| BITPOS | 763.5 ns | 3.066 M ops/s | $\color{#1a7f37}\text{+2%}$ |
| GETBIT | 1.908 µs | 2.270 M ops/s | $\color{#0969da}\text{-11%}$ |
| SETBIT | 11.4 µs | 0.657 M ops/s | $\color{#0969da}\text{-41%}$ |
| BF.ADD | 106.3 µs | 0.021 M ops/s | $\color{#0969da}\text{-27%}$ |
| BF.EXISTS | 563.1 ns | 2.372 M ops/s | $\color{#0969da}\text{-19%}$ |
| BF.INFO | 186 ns | 5.659 M ops/s | $\color{#1a7f37}\text{-4%}$ |
| CF.ADD | 21.1 µs | 0.303 M ops/s | $\color{#0969da}\text{-42%}$ |
| CF.DEL | 19.47 µs | 0.159 M ops/s | $\color{#0969da}\text{-35%}$ |
| CF.EXISTS | 665.8 ns | 1.694 M ops/s | $\color{#0969da}\text{-20%}$ |
| BATCH_COMMIT | 9.836 µs | 0.265 M ops/s | $\color{#0969da}\text{-30%}$ |
| DEL | 18.39 µs | 0.507 M ops/s | $\color{#0969da}\text{-48%}$ |
| EXISTS | 2.533 µs | 3.549 M ops/s | $\color{#0969da}\text{-22%}$ |
| NAMESPACE | 7.039 µs | 0.983 M ops/s | $\color{#0969da}\text{-48%}$ |
| GEOADD | 13.16 µs | 0.532 M ops/s | $\color{#0969da}\text{-37%}$ |
| GEODIST | 3.196 µs | 1.977 M ops/s | $\color{#1a7f37}\text{-1%}$ |
| GEOHASH | 1.26 µs | 2.851 M ops/s | $\color{#1a7f37}\text{+1%}$ |
| GEOPOS | 1.728 µs | 3.425 M ops/s | $\color{#1a7f37}\text{+6%}$ |
| HDEL | 35 µs | 0.084 M ops/s | $\color{#0969da}\text{-20%}$ |
| HEXISTS | 420.3 ns | 2.495 M ops/s | $\color{#1a7f37}\text{+2%}$ |
| HGET | 1.56 µs | 1.480 M ops/s | $\color{#0969da}\text{-12%}$ |
| HGETALL | 30.8 µs | 0.044 M ops/s | $\color{#1a7f37}\text{-9%}$ |
| HINCRBY | 10.64 µs | 0.861 M ops/s | $\color{#0969da}\text{-44%}$ |
| HKEYS | 25.58 µs | 0.054 M ops/s | $\color{#0969da}\text{-14%}$ |
| HLEN | 1.96 µs | 3.364 M ops/s | $\color{#0969da}\text{-11%}$ |
| HMGET | 3.538 µs | 0.515 M ops/s | $\color{#1a7f37}\text{-5%}$ |
| HSET | 9.949 µs | 0.613 M ops/s | $\color{#0969da}\text{-41%}$ |
| HVALS | 27.25 µs | 0.054 M ops/s | $\color{#0969da}\text{-24%}$ |
| PFADD | 28.24 µs | 0.129 M ops/s | $\color{#0969da}\text{-41%}$ |
| PFCOUNT | 45.74 µs | 0.036 M ops/s | $\color{#0969da}\text{-20%}$ |
| PFMERGE | 34.24 µs | 0.071 M ops/s | $\color{#0969da}\text{-35%}$ |
| JSON.ARRLEN | 4.744 µs | 2.376 M ops/s | $\color{#0969da}\text{-29%}$ |
| JSON.DEL | 13.38 µs | 0.441 M ops/s | $\color{#0969da}\text{-47%}$ |
| JSON.GET | 5.82 µs | 2.071 M ops/s | $\color{#0969da}\text{-33%}$ |
| JSON.NUMINCRBY | 14.19 µs | 0.756 M ops/s | $\color{#0969da}\text{-48%}$ |
| JSON.SET | 7.076 µs | 0.625 M ops/s | $\color{#0969da}\text{-45%}$ |
| JSON.TYPE | 3.341 µs | 2.795 M ops/s | $\color{#0969da}\text{-29%}$ |
| LINDEX | 1.531 µs | 2.005 M ops/s | $\color{#1a7f37}\text{-3%}$ |
| LLEN | 695.5 ns | 3.602 M ops/s | $\color{#1a7f37}\text{-8%}$ |
| LPOP | 4.442 µs | 0.496 M ops/s | $\color{#0969da}\text{-39%}$ |
| LPUSH | 26.37 µs | 0.733 M ops/s | $\color{#0969da}\text{-43%}$ |
| LRANGE | 36.37 µs | 0.046 M ops/s | $\color{#0969da}\text{-16%}$ |
| LREM | 32.33 µs | 0.086 M ops/s | $\color{#0969da}\text{-19%}$ |
| LSET | 4.271 µs | 0.770 M ops/s | $\color{#0969da}\text{-45%}$ |
| LTRIM | 116.4 µs | 0.010 M ops/s | $\color{#0969da}\text{-42%}$ |
| RPOP | 4.115 µs | 0.515 M ops/s | $\color{#0969da}\text{-39%}$ |
| RPUSH | 10.63 µs | 0.728 M ops/s | $\color{#0969da}\text{-42%}$ |
| SADD | 12.4 µs | 0.647 M ops/s | $\color{#0969da}\text{-42%}$ |
| SCARD | 786 ns | 3.723 M ops/s | $\color{#1a7f37}\text{-10%}$ |
| SISMEMBER | 1.603 µs | 1.558 M ops/s | $\color{#0969da}\text{-16%}$ |
| SMEMBERS | 31.29 µs | 0.053 M ops/s | $\color{#0969da}\text{-16%}$ |
| SPOP | 1.877 ms | 0.001 M ops/s | $\color{#0969da}\text{-15%}$ |
| SRANDMEMBER | 32.24 µs | 0.053 M ops/s | $\color{#0969da}\text{-18%}$ |
| SREM | 24.01 µs | 0.083 M ops/s | $\color{#0969da}\text{-19%}$ |
| SI.ADD | 10.56 µs | 0.672 M ops/s | $\color{#0969da}\text{-41%}$ |
| SI.CARD | 1.556 µs | 3.609 M ops/s | $\color{#1a7f37}\text{-2%}$ |
| SI.EXISTS | 1.658 µs | 1.913 M ops/s | $\color{#1a7f37}\text{-9%}$ |
| SI.RANGE | 17.17 µs | 0.118 M ops/s | $\color{#0969da}\text{-16%}$ |
| SI.REM | 27.07 µs | 0.081 M ops/s | $\color{#0969da}\text{-19%}$ |
| APPEND | 20.18 µs | 0.567 M ops/s | $\color{#0969da}\text{-51%}$ |
| DECRBY | 3.075 µs | 1.141 M ops/s | $\color{#0969da}\text{-53%}$ |
| GET | 1.396 µs | 1.900 M ops/s | $\color{#0969da}\text{-11%}$ |
| GETDEL | 8.726 µs | 0.573 M ops/s | $\color{#0969da}\text{-52%}$ |
| GETRANGE | 190.8 ns | 5.488 M ops/s | $\color{#1a7f37}\text{-6%}$ |
| INCRBY | 8.12 µs | 1.163 M ops/s | $\color{#0969da}\text{-52%}$ |
| MGET | 10.18 µs | 0.523 M ops/s | $\color{#0969da}\text{-13%}$ |
| MSET | 25.02 µs | 0.229 M ops/s | $\color{#0969da}\text{-28%}$ |
| SET | 8.494 µs | 1.239 M ops/s | $\color{#0969da}\text{-53%}$ |
| SETRANGE | 9.97 µs | 0.560 M ops/s | $\color{#0969da}\text{-51%}$ |
| STRLEN | 334.8 ns | 6.112 M ops/s | $\color{#1a7f37}\text{+1%}$ |
| XADD | 21.5 µs | 0.699 M ops/s | $\color{#0969da}\text{-43%}$ |
| XDEL | 28.17 µs | 0.311 M ops/s | $\color{#0969da}\text{-40%}$ |
| XLEN | 212.2 ns | 4.914 M ops/s | $\color{#1a7f37}\text{-5%}$ |
| XRANGE | 22.76 µs | 0.078 M ops/s | $\color{#0969da}\text{-19%}$ |
| XREAD | 21.6 µs | 0.078 M ops/s | $\color{#0969da}\text{-18%}$ |
| TDIGEST.ADD | 6.174 µs | 0.534 M ops/s | $\color{#0969da}\text{-42%}$ |
| TDIGEST.BYRANK | 8.605 µs | 2.104 M ops/s | $\color{#0969da}\text{-32%}$ |
| TDIGEST.CDF | 10.59 µs | 1.067 M ops/s | $\color{#0969da}\text{-30%}$ |
| TDIGEST.QUANTILE | 9.608 µs | 2.562 M ops/s | $\color{#0969da}\text{-31%}$ |
| TS.ADD | 45.21 µs | 0.120 M ops/s | $\color{#0969da}\text{-20%}$ |
| TS.GET | 3.319 µs | 1.648 M ops/s | $\color{#0969da}\text{-23%}$ |
| TS.INCRBY | 42.69 µs | 0.063 M ops/s | $\color{#0969da}\text{-24%}$ |
| TS.RANGE | 52.34 µs | 0.023 M ops/s | $\color{#0969da}\text{-11%}$ |
| ZADD | 16.56 µs | 0.508 M ops/s | $\color{#0969da}\text{-37%}$ |
| ZCARD | 1.098 µs | 6.536 M ops/s | $\color{#1a7f37}\text{-10%}$ |
| ZCOUNT | 77.73 µs | 0.016 M ops/s | $\color{#0969da}\text{-24%}$ |
| ZINCRBY | 13.43 µs | 0.117 M ops/s | $\color{#1a7f37}\text{-9%}$ |
| ZPOPMIN | 28.23 µs | 0.071 M ops/s | $\color{#1a7f37}\text{-7%}$ |
| ZRANGE | 9.684 µs | 0.346 M ops/s | $\color{#0969da}\text{-19%}$ |
| ZRANK | 31.76 µs | 0.094 M ops/s | $\color{#1a7f37}\text{-7%}$ |
| ZREM | 42.02 µs | 0.065 M ops/s | $\color{#1a7f37}\text{+1%}$ |
| ZREVRANGE | 9.264 µs | 0.241 M ops/s | $\color{#0969da}\text{-20%}$ |
| ZSCORE | 590.1 ns | 2.031 M ops/s | $\color{#0969da}\text{-16%}$ |

---

### Environment: macOS (Apple M2 Max)

- **CPU**: `Apple M2 Max (12 Cores)`
- **Memory**: `64.0 GB`
- **Platform**: `macOS 26.5.1 (Darwin 25.5.0) (aarch64)`
- **Compiler**: `rustc 1.98.0 (88d9e12ae 2026-08-18)`

#### WeDb (Embedded Engine) vs Redis (v8.10.1 Standalone Server) Performance Comparison

> **Benchmark Notes**:
> - WeDb: In-process direct call, LSM disk persistence (WAL journal)
> - Redis: Standalone service, AOF persistence enabled (appendfsync everysec), Unix Domain Socket

**Composite Performance**: WeDb Weighted Throughput **0.383 M ops/s** | Redis Weighted Throughput **0.012 M ops/s** | WeDb Overall Speedup **$\color{#1a7f37}\text{31.2x}$**

| Command | WeDb P95 Latency | WeDb Est. Throughput | Redis P95 Latency | Redis Est. Throughput | WeDb Speedup |
| :--- | :--- | :--- | :--- | :--- | :--- |
| SET | 29.66 µs | 0.500 M ops/s | 531.2 µs | 0.008 M ops/s | $\color{#1a7f37}\text{61.9x}$ |
| GET | 6.999 µs | 0.632 M ops/s | 76.74 µs | 0.016 M ops/s | $\color{#1a7f37}\text{39.8x}$ |
| MSET | 152.2 µs | 0.052 M ops/s | 561.2 µs | 0.008 M ops/s | $\color{#1a7f37}\text{6.8x}$ |
| MGET | 22.37 µs | 0.286 M ops/s | 328.5 µs | 0.008 M ops/s | $\color{#1a7f37}\text{34.6x}$ |
| INCRBY | 136.6 µs | 0.251 M ops/s | 1.354 ms | 0.005 M ops/s | $\color{#1a7f37}\text{50.0x}$ |
| HSET | 48.29 µs | 0.255 M ops/s | 535.7 µs | 0.009 M ops/s | $\color{#1a7f37}\text{27.9x}$ |
| HGET | 8.04 µs | 0.414 M ops/s | 89.16 µs | 0.016 M ops/s | $\color{#1a7f37}\text{25.6x}$ |
| LPUSH | 141.9 µs | 0.053 M ops/s | 464.4 µs | 0.008 M ops/s | $\color{#1a7f37}\text{6.6x}$ |
| LPOP | 40.24 µs | 0.073 M ops/s | 153.5 µs | 0.014 M ops/s | $\color{#1a7f37}\text{5.0x}$ |
| SADD | 37.58 µs | 0.304 M ops/s | 544.4 µs | 0.009 M ops/s | $\color{#1a7f37}\text{34.2x}$ |
| SISMEMBER | 4.583 µs | 0.775 M ops/s | 85.2 µs | 0.013 M ops/s | $\color{#1a7f37}\text{60.4x}$ |
| ZADD | 52.37 µs | 0.289 M ops/s | 241.8 µs | 0.015 M ops/s | $\color{#1a7f37}\text{19.0x}$ |
| ZRANGE | 33.37 µs | 0.262 M ops/s | 113.1 µs | 0.013 M ops/s | $\color{#1a7f37}\text{20.9x}$ |
| DEL | 16.33 µs | 0.429 M ops/s | 164.2 µs | 0.019 M ops/s | $\color{#1a7f37}\text{22.4x}$ |
| EXISTS | 12.33 µs | 1.171 M ops/s | 50.87 µs | 0.023 M ops/s | $\color{#1a7f37}\text{51.2x}$ |

#### Regression Benchmark

**Composite Weighted Performance**: Weighted Throughput **1.292 M ops/s** | Weighted Latency Diff **$\color{#1a7f37}\text{+12%}$**

| Command | P95 Latency | Est. Throughput | vs Baseline (%) |
| :--- | :--- | :--- | :--- |
| BITCOUNT | 8.083 µs | 2.181 M ops/s | $\color{#cf222e}\text{+22%}$ |
| BITPOS | 397.9 ns | 3.102 M ops/s | $\color{#0969da}\text{-48%}$ |
| GETBIT | 1.187 µs | 1.951 M ops/s | $\color{#cf222e}\text{+32%}$ |
| SETBIT | 79.33 µs | 0.436 M ops/s | $\color{#cf222e}\text{+34%}$ |
| BF.ADD | 433.3 µs | 0.011 M ops/s | $\color{#cf222e}\text{+88%}$ |
| BF.EXISTS | 845.8 ns | 2.261 M ops/s | $\color{#1a7f37}\text{+10%}$ |
| BF.INFO | 340.6 ns | 3.887 M ops/s | $\color{#cf222e}\text{+80%}$ |
| CF.ADD | 65.49 µs | 0.107 M ops/s | $\color{#cf222e}\text{+145%}$ |
| CF.DEL | 67.79 µs | 0.123 M ops/s | $\color{#1a7f37}\text{+13%}$ |
| CF.EXISTS | 869.4 ns | 1.456 M ops/s | $\color{#cf222e}\text{+25%}$ |
| BATCH_COMMIT | 67.24 µs | 0.222 M ops/s | $\color{#cf222e}\text{+20%}$ |
| DEL | 85.12 µs | 0.304 M ops/s | $\color{#1a7f37}\text{+8%}$ |
| EXISTS | 5.666 µs | 2.999 M ops/s | $\color{#1a7f37}\text{-0%}$ |
| NAMESPACE | 69.91 µs | 0.522 M ops/s | $\color{#cf222e}\text{+35%}$ |
| GEOADD | 77.12 µs | 0.421 M ops/s | $\color{#1a7f37}\text{+12%}$ |
| GEODIST | 559.4 ns | 2.222 M ops/s | $\color{#cf222e}\text{+16%}$ |
| GEOHASH | 413.6 ns | 2.766 M ops/s | $\color{#0969da}\text{-57%}$ |
| GEOPOS | 366.7 ns | 3.344 M ops/s | $\color{#cf222e}\text{+25%}$ |
| HDEL | 80.33 µs | 0.100 M ops/s | $\color{#1a7f37}\text{+8%}$ |
| HEXISTS | 411 ns | 2.936 M ops/s | $\color{#1a7f37}\text{-3%}$ |
| HGET | 817.2 ns | 1.392 M ops/s | $\color{#1a7f37}\text{+15%}$ |
| HGETALL | 37.58 µs | 0.076 M ops/s | $\color{#1a7f37}\text{-8%}$ |
| HINCRBY | 68.16 µs | 0.649 M ops/s | $\color{#1a7f37}\text{-5%}$ |
| HKEYS | 20.74 µs | 0.080 M ops/s | $\color{#1a7f37}\text{+8%}$ |
| HLEN | 317.2 ns | 3.967 M ops/s | $\color{#1a7f37}\text{-7%}$ |
| HMGET | 10.79 µs | 0.471 M ops/s | $\color{#1a7f37}\text{+15%}$ |
| HSET | 56.91 µs | 0.453 M ops/s | $\color{#1a7f37}\text{0%}$ |
| HVALS | 22.16 µs | 0.074 M ops/s | $\color{#0969da}\text{-11%}$ |
| PFADD | 68.2 µs | 0.097 M ops/s | $\color{#cf222e}\text{+16%}$ |
| PFCOUNT | 41.79 µs | 0.030 M ops/s | $\color{#1a7f37}\text{-8%}$ |
| PFMERGE | 51.37 µs | 0.059 M ops/s | $\color{#1a7f37}\text{+2%}$ |
| JSON.ARRLEN | 17.91 µs | 0.924 M ops/s | $\color{#cf222e}\text{+100%}$ |
| JSON.DEL | 93.7 µs | 0.267 M ops/s | $\color{#1a7f37}\text{+5%}$ |
| JSON.GET | 15.66 µs | 1.503 M ops/s | $\color{#cf222e}\text{+23%}$ |
| JSON.NUMINCRBY | 17.79 µs | 0.558 M ops/s | $\color{#1a7f37}\text{0%}$ |
| JSON.SET | 56.29 µs | 0.407 M ops/s | $\color{#cf222e}\text{+20%}$ |
| JSON.TYPE | 5.208 µs | 2.002 M ops/s | $\color{#cf222e}\text{+20%}$ |
| LINDEX | 533.3 ns | 2.302 M ops/s | $\color{#1a7f37}\text{+8%}$ |
| LLEN | 237.8 ns | 4.398 M ops/s | $\color{#1a7f37}\text{+13%}$ |
| LPOP | 6.457 µs | 0.429 M ops/s | $\color{#1a7f37}\text{-3%}$ |
| LPUSH | 55.37 µs | 0.632 M ops/s | $\color{#1a7f37}\text{-0%}$ |
| LRANGE | 31.2 µs | 0.043 M ops/s | $\color{#cf222e}\text{+22%}$ |
| LREM | 129.3 µs | 0.109 M ops/s | $\color{#1a7f37}\text{+2%}$ |
| LSET | 4.541 µs | 0.546 M ops/s | $\color{#cf222e}\text{+300%}$ |
| LTRIM | 194.2 µs | 0.007 M ops/s | $\color{#1a7f37}\text{+4%}$ |
| RPOP | 5.29 µs | 0.471 M ops/s | $\color{#1a7f37}\text{+2%}$ |
| RPUSH | 75.45 µs | 0.522 M ops/s | $\color{#0969da}\text{-51%}$ |
| SADD | 76.66 µs | 0.453 M ops/s | $\color{#cf222e}\text{+20%}$ |
| SCARD | 353.7 ns | 3.434 M ops/s | $\color{#cf222e}\text{+29%}$ |
| SISMEMBER | 666.2 ns | 1.657 M ops/s | $\color{#0969da}\text{-15%}$ |
| SMEMBERS | 20.83 µs | 0.084 M ops/s | $\color{#1a7f37}\text{-0%}$ |
| SPOP | 1.262 ms | 0.001 M ops/s | $\color{#1a7f37}\text{-0%}$ |
| SRANDMEMBER | 115.5 µs | 0.078 M ops/s | $\color{#1a7f37}\text{+8%}$ |
| SREM | 121.5 µs | 0.111 M ops/s | $\color{#1a7f37}\text{-1%}$ |
| SI.ADD | 142.5 µs | 0.534 M ops/s | $\color{#1a7f37}\text{+12%}$ |
| SI.CARD | 236.5 ns | 5.621 M ops/s | $\color{#1a7f37}\text{+1%}$ |
| SI.EXISTS | 647.9 ns | 2.095 M ops/s | $\color{#1a7f37}\text{-3%}$ |
| SI.RANGE | 15.91 µs | 0.182 M ops/s | $\color{#1a7f37}\text{-3%}$ |
| SI.REM | 91.49 µs | 0.101 M ops/s | $\color{#1a7f37}\text{+8%}$ |
| APPEND | 88.83 µs | 0.400 M ops/s | $\color{#0969da}\text{-56%}$ |
| DECRBY | 62.74 µs | 0.858 M ops/s | $\color{#1a7f37}\text{-10%}$ |
| GET | 666.1 ns | 2.344 M ops/s | $\color{#1a7f37}\text{+6%}$ |
| GETDEL | 442.2 µs | 0.173 M ops/s | $\color{#cf222e}\text{+128%}$ |
| GETRANGE | 114.1 ns | 9.891 M ops/s | $\color{#1a7f37}\text{+4%}$ |
| INCRBY | 97.58 µs | 0.829 M ops/s | $\color{#1a7f37}\text{-3%}$ |
| MGET | 4.874 µs | 0.600 M ops/s | $\color{#1a7f37}\text{+11%}$ |
| MSET | 139.3 µs | 0.202 M ops/s | $\color{#1a7f37}\text{+15%}$ |
| SET | 116.7 µs | 0.751 M ops/s | $\color{#1a7f37}\text{+14%}$ |
| SETRANGE | 158.5 µs | 0.358 M ops/s | $\color{#0969da}\text{-51%}$ |
| STRLEN | 96.56 ns | 11.972 M ops/s | $\color{#1a7f37}\text{-1%}$ |
| XADD | 49.99 µs | 0.572 M ops/s | $\color{#1a7f37}\text{+2%}$ |
| XDEL | 55.87 µs | 0.229 M ops/s | $\color{#cf222e}\text{+23%}$ |
| XLEN | 163.6 ns | 6.262 M ops/s | $\color{#1a7f37}\text{+12%}$ |
| XRANGE | 34.04 µs | 0.091 M ops/s | $\color{#1a7f37}\text{+9%}$ |
| XREAD | 28.37 µs | 0.086 M ops/s | $\color{#1a7f37}\text{+12%}$ |
| TDIGEST.ADD | 17.54 µs | 0.308 M ops/s | $\color{#1a7f37}\text{+7%}$ |
| TDIGEST.BYRANK | 11.83 µs | 1.413 M ops/s | $\color{#1a7f37}\text{+13%}$ |
| TDIGEST.CDF | 17.91 µs | 0.961 M ops/s | $\color{#cf222e}\text{+19%}$ |
| TDIGEST.QUANTILE | 16.08 µs | 1.847 M ops/s | $\color{#1a7f37}\text{-7%}$ |
| TS.ADD | 165 µs | 0.142 M ops/s | $\color{#1a7f37}\text{+1%}$ |
| TS.GET | 697.5 ns | 1.763 M ops/s | $\color{#1a7f37}\text{+7%}$ |
| TS.INCRBY | 27.2 µs | 0.069 M ops/s | $\color{#1a7f37}\text{+7%}$ |
| TS.RANGE | 28.58 µs | 0.038 M ops/s | $\color{#1a7f37}\text{+13%}$ |
| ZADD | 141.1 µs | 0.381 M ops/s | $\color{#cf222e}\text{+19%}$ |
| ZCARD | 174 ns | 7.485 M ops/s | $\color{#cf222e}\text{+24%}$ |
| ZCOUNT | 60.24 µs | 0.021 M ops/s | $\color{#cf222e}\text{+21%}$ |
| ZINCRBY | 106.8 µs | 0.125 M ops/s | $\color{#cf222e}\text{+22%}$ |
| ZPOPMIN | 14.83 µs | 0.109 M ops/s | $\color{#1a7f37}\text{+7%}$ |
| ZRANGE | 11.29 µs | 0.375 M ops/s | $\color{#cf222e}\text{+20%}$ |
| ZRANK | 10.29 µs | 0.155 M ops/s | $\color{#1a7f37}\text{+5%}$ |
| ZREM | 172.6 µs | 0.113 M ops/s | $\color{#1a7f37}\text{+3%}$ |
| ZREVRANGE | 12.49 µs | 0.253 M ops/s | $\color{#1a7f37}\text{+10%}$ |
| ZSCORE | 765.1 ns | 1.568 M ops/s | $\color{#cf222e}\text{+29%}$ |



---

<a id="zh"></a>
# wedb_embed : 嵌入式数据库引擎,提供类似 Redis 的接口,底层基于 [fjall]https://github.com/fjall-rs/fjall 开发

- [wedb_embed : 嵌入式数据库引擎,提供类似 Redis 的接口,底层基于 [fjall](https://github.com/fjall-rs/fjall) 开发]#wedb_embed-嵌入式数据库引擎提供类似-redis-的接口底层基于-fjallhttpsgithubcomfjall-rsfjall-开发
  - [项目初衷]#项目初衷
  - [核心架构与编码设计]#核心架构与编码设计
    - [1. 默认库前缀优化与 1-Byte 标签]#1-默认库前缀优化与-1-byte-标签
    - [2. OPPV 保序变长整型编码 (`oppv_u64`)]#2-oppv-保序变长整型编码-oppv_u64
    - [3. 多租户数字 ID 映射与重命名]#3-多租户数字-id-映射与重命名
    - [4. 流式迭代器]#4-流式迭代器
  - [使用演示]#使用演示
    - [1. 数据库打开与配置 (`WeDb` & `Conf`)]#1-数据库打开与配置-wedb-conf
    - [2. 多租户与分库隔离 (`Namespace`)]#2-多租户与分库隔离-namespace
    - [3. 键值与字符串 (`KvOps`)]#3-键值与字符串-kvops
    - [4. 哈希字典 (`HashOps`)]#4-哈希字典-hashops
    - [5. 列表 (`ListOps`)]#5-列表-listops
    - [6. 集合 (`SetOps`)]#6-集合-setops
    - [7. 有序集合 (`ZSetOps`)]#7-有序集合-zsetops
    - [8. 位图、布隆过滤、时序与地理位置 (`BitmapOps`, `BloomOps`, `TsOps`, `GeoOps`)]#8-位图布隆过滤时序与地理位置-bitmapops-bloomops-tsops-geoops
  - [技术堆栈]#技术堆栈
  - [性能基准与回归测试]#性能基准与回归测试
    - [运行环境:Ubuntu CI (GitHub Actions Runner)]#运行环境ubuntu-ci-github-actions-runner
      - [WeDb (嵌入式引擎) vs Redis (v8.10.1 独立服务) 性能对比]#wedb-嵌入式引擎-vs-redis-v8101-独立服务-性能对比
      - [性能回归测试]#性能回归测试
    - [运行环境:macOS (Apple M2 Max)]#运行环境macos-apple-m2-max
      - [WeDb (嵌入式引擎) vs Redis (v8.10.1 独立服务) 性能对比]#wedb-嵌入式引擎-vs-redis-v8101-独立服务-性能对比
      - [性能回归测试]#性能回归测试

基于 Rust 开发的嵌入式多模型数据库引擎,提供与 Redis 兼容的数据结构与操作接口,底层采用 [fjall](https://github.com/fjall-rs/fjall) LSM-Tree 进行磁盘持久化存储。

---

## 项目初衷

在许多单机服务或嵌入式应用场景中,部署和维护独立的 Redis 守护进程会增加运维复杂度,并且跨进程通信(IPC / Socket 网络与 RESP 编解码)会带来额外的延迟开销。
在单机或嵌入式应用中,部署独立 Redis 进程会增加运维复杂度,且跨进程通信(IPC/Socket 与 RESP 编解码)会引入额外延迟。

`wedb_embed` 作为 Rust 原生库嵌入应用程序:
- **进程内调用**:无网络与 IPC 开销,直接在内存与磁盘间进行读写。
- **丰富的数据模型**:支持 String、Hash、List、Set、ZSet、Bitmap、JSON、Bloom/Cuckoo Filter、TimeSeries、Geo、HyperLogLog、TDigest、SortedInt、Stream 等 15 种数据结构。
- **多租户与分库隔离**:原生支持 $2^{64}$ 租户与 $2^{64}$ 分库,具备原子改名与物理隔离能力。
- **紧凑二进制编码**:默认库采用 0 字节前缀,复合结构使用 1-Byte `KeyTag` 与 OPPV 变长保序编码。
- **持久化一致性**:基于 [fjall]https://github.com/fjall-rs/fjall LSM-Tree 存储引擎与跨 Keyspace 原子 WriteBatch,保障数据安全。

---

## 核心架构与编码设计

```mermaid
graph TD
  Client["Application Code"] --> WeDb["WeDb Instance"]
  WeDb --> NS["Namespace Handle<br/>(Zero-Heap Struct)"]

  subgraph KeyComposer["Key Composer & Fast Encoding"]
    Tag["1-Byte Fast KeyTag (#[repr(u8)])"]
    OPPV["OPPV Order-Preserving Varint (1~9B)"]
    DefaultBypass["Default NS 0-Prefix Bypass"]
    Slot["CRC16 Slot & {hashtag}"]
  end

  subgraph Engine["Storage Engine Layer"]
    Batch["Atomic WriteBatch (Cross-Keyspace WAL)"]
    Catalog["Catalog Compact Index"]
  end

  subgraph Storage["Fjall LSM Partitions"]
    DataKS["Data Keyspace<br/>(业务载荷与子键 / 64KB 块)"]
    MetaKS["Meta Keyspace<br/>(常驻索引、TTL 与元数据 / 4KB 块)"]
  end

  WeDb --> KeyComposer
  NS --> KeyComposer
  KeyComposer --> Engine
  Engine --> DataKS
  Engine --> MetaKS
```

### 1. 默认库前缀优化与 1-Byte 标签
- **默认命名空间**:键直接为原始字节 `user_key`,物理前缀占用 0 字节。
- **1-Byte Fast Tag (`KeyTag`)**:复合结构元数据与子键前缀采用 `#[repr(u8)] KeyTag` 编码(`\x00\x01:key` 等),消除冗余字符串标签。

### 2. OPPV 保序变长整型编码 (`oppv_u64`)
- 数据库编号与租户数字 ID 采用 **OPPV(Order-Preserving Prefix Varint)** 编码:
  - 分库 $0 \sim 127$:占用 1 字节(相比固定 8 字节大端序节约空间)。
  - 全范围保持字节字典序与数值顺序等价:$\forall a < b \implies \text{encode}(a) < \text{encode}(b)$。

### 3. 多租户数字 ID 映射与重命名
- 租户名称与 `ns_id: u64` 采用全局元数据原子映射。
- **租户改名 (`rename_namespace`)**:更新元数据映射即可完成重命名,无需重写底层业务键。

### 4. 流式迭代器
- **`WeDb::iter(&self) -> Namespaces`**:基于字典序跳跃二分(Prefix Jump-Seek)定位租户。
- **`Namespace::iter(&self) -> Dbs`**:直接流式解包底层 OPPV 变长 Catalog 目录。

---

## 使用演示

### 1. 数据库打开与配置 (`WeDb` & `Conf`)

```rust
use wedb_embed::{Conf, PersistMode, Result, WeDb};

fn main() -> Result<()> {
    // 1. 自定义配置打开
    let mut conf = Conf::new("./data/db_demo");
    conf.db.flush_workers = 2; // 后台刷盘线程数
    let db = WeDb::open_with_conf(&conf)?;

    // 2. 刷盘与周期任务
    db.persist(PersistMode::SyncAll)?; // 手动同步持久化 WAL 与脏页
    db.active_expire_cycle(100)?;       // 触发主动过期采样清理

    Ok(())
}
```

### 2. 多租户与分库隔离 (`Namespace`)

```rust
use wedb_embed::{KvOps, Result, WeDb};

fn main() -> Result<()> {
    let db = WeDb::open("./data/multitenant_demo")?;

    // 租户隔离句柄(轻量句柄,零拷贝)
    let ns_apple = db.namespace("tenant_apple");
    let ns_google = db.namespace("tenant_google");

    ns_apple.set(b"config:theme", b"dark", &[])?;
    ns_google.set(b"config:theme", b"light", &[])?;

    // 物理隔离读取
    assert_eq!(ns_apple.get(b"config:theme")?.unwrap(), b"dark");
    assert_eq!(ns_google.get(b"config:theme")?.unwrap(), b"light");

    // 多 DB 选择 (如 SELECT 1)
    let db1 = db.select_db(1);
    db1.set(b"db1_key", b"value1", &[])?;

    // 遍历租户下已激活的 DB(流式迭代)
    for db_idx in &ns_apple {
        println!("Active DB: {}", db_idx);
    }

    // 租户重命名
    db.rename_namespace("tenant_apple", "tenant_apple_v2")?;

    // 键空间管理
    let key_count = ns_apple.key_count()?;
    let keys = ns_apple.keys(b"config:*")?;
    let exists_count = ns_apple.exists(&[b"config:theme".as_slice()])?;
    ns_apple.del(&[b"config:theme".as_slice()])?;
    ns_apple.clear()?; // 级联清空整个命名空间

    Ok(())
}
```

### 3. 键值与字符串 (`KvOps`)

```rust
use wedb_embed::{KvOps, Result, WeDb, string::Set};

fn main() -> Result<()> {
    let db = WeDb::open("./data/kv_demo")?;

    // 基础读写与过期设置 (set_ex)
    db.set(b"site", b"webc.site", &[])?;
    let val = db.get(b"site")?;
    db.set_ex(b"temp_token", b"xyz", 3600)?;

    // 条件写入 (NX / XX)
    db.set(b"lock", b"1", &[Set::Nx])?;

    // 数值增减
    db.incr(b"counter")?;
    db.incrby(b"counter", 10)?;
    db.decrby(b"counter", 5)?;

    // 批量与字符串操作
    db.mset(&[(b"k1", b"v1"), (b"k2", b"v2")])?;
    let values = db.mget(&[b"k1".as_slice(), b"k2".as_slice()])?;
    let len = db.strlen(b"site")?;
    let old_val = db.getset(b"site", b"new_site")?;
    let del_val = db.getdel(b"site")?;

    Ok(())
}
```

### 4. 哈希字典 (`HashOps`)

```rust
use wedb_embed::{HashOps, Result, WeDb};

fn main() -> Result<()> {
    let db = WeDb::open("./data/hash_demo")?;

    // 字段写入与读取
    db.hset(b"user:100", b"name", b"Alice")?;
    db.hset(b"user:100", b"age", b"20")?;
    let name = db.hget(b"user:100", b"name")?;

    // 批量写入与获取
    db.hmset(b"user:100", &[(b"city", b"Beijing"), (b"role", b"Admin")])?;
    let fields = db.hmget(b"user:100", &[b"name".as_slice(), b"city".as_slice()])?;

    // 数值自增与元数据
    db.hincrby(b"user:100", b"age", 1)?;
    let exists = db.hexists(b"user:100", b"name")?;
    let len = db.hlen(b"user:100")?;
    let all = db.hgetall(b"user:100")?;
    let keys = db.hkeys(b"user:100")?;
    let vals = db.hvals(b"user:100")?;
    db.hdel(b"user:100", &[b"role".as_slice()])?;

    Ok(())
}
```

### 5. 列表 (`ListOps`)

```rust
use wedb_embed::{ListOps, Result, WeDb};

fn main() -> Result<()> {
    let db = WeDb::open("./data/list_demo")?;

    // 双端推入与弹出
    db.lpush(b"tasks", &[b"task1".as_slice(), b"task2".as_slice()])?;
    db.rpush(b"tasks", &[b"task3".as_slice()])?;
    let first = db.lpop(b"tasks", 1)?;
    let last = db.rpop(b"tasks", 1)?;

    // 范围查询与修剪
    let len = db.llen(b"tasks")?;
    let items = db.lrange(b"tasks", 0, -1)?;
    db.ltrim(b"tasks", 0, 10)?;
    db.lset(b"tasks", 0, b"updated_task")?;

    Ok(())
}
```

### 6. 集合 (`SetOps`)

```rust
use wedb_embed::{Result, SetOps, WeDb};

fn main() -> Result<()> {
    let db = WeDb::open("./data/set_demo")?;

    db.sadd(b"tags", &[b"rust".as_slice(), b"database".as_slice(), b"lsm".as_slice()])?;
    let is_member = db.sismember(b"tags", b"rust")?;
    let count = db.scard(b"tags")?;
    let members = db.smembers(b"tags")?;
    db.srem(b"tags", &[b"lsm".as_slice()])?;
    let popped = db.spop(b"tags", 1)?;

    Ok(())
}
```

### 7. 有序集合 (`ZSetOps`)

```rust
use wedb_embed::{Result, WeDb, ZSetOps};

fn main() -> Result<()> {
    let db = WeDb::open("./data/zset_demo")?;

    // 添加成员与分数
    db.zadd(b"leaderboard", &[(100.0, b"player1".as_slice()), (200.0, b"player2".as_slice())], &[])?;
    db.zincrby(b"leaderboard", 50.0, b"player1")?;

    // 排名与分数
    let score = db.zscore(b"leaderboard", b"player1")?;
    let rank = db.zrank(b"leaderboard", b"player1")?;
    let rev_rank = db.zrevrank(b"leaderboard", b"player1")?;

    // 范围查询
    let top = db.zrange(b"leaderboard", 0, 10, &[])?;
    let count = db.zcount(b"leaderboard", 100.0, 300.0)?;
    let card = db.zcard(b"leaderboard")?;
    db.zrem(b"leaderboard", &[b"player1".as_slice()])?;

    Ok(())
}
```

### 8. 位图、布隆过滤、时序与地理位置 (`BitmapOps`, `BloomOps`, `TsOps`, `GeoOps`)

```rust
use wedb_embed::{BitmapOps, BloomOps, GeoOps, Result, TsOps, WeDb};

fn main() -> Result<()> {
    let db = WeDb::open("./data/advanced_demo")?;

    // 位图 (Bitmap)
    db.setbit(b"online_users", 1001, true)?;
    let is_online = db.getbit(b"online_users", 1001)?;
    let online_count = db.bitcount(b"online_users", 0, -1)?;

    // 布隆过滤器 (Bloom Filter)
    db.bf_add(b"filter", b"item_1")?;
    let exists = db.bf_exists(b"filter", b"item_1")?;

    // 时序数据 (TimeSeries)
    db.ts_add(b"metrics:cpu", 1700000000000, 42.5, &[])?;
    let latest = db.ts_get(b"metrics:cpu")?;

    // 地理位置 (Geo)
    db.geoadd(b"cities", &[(116.4074, 39.9042, b"Beijing".as_slice()), (121.4737, 31.2304, b"Shanghai".as_slice())])?;
    let dist = db.geodist(b"cities", b"Beijing", b"Shanghai", None)?;

    Ok(())
}
```

---

## 技术堆栈

- **核心语言**:Rust Edition 2024
- **底层存储**`fjall` (LSM-Tree 持久化引擎)
- **JSON 解析**`sonic-rs` (SIMD 指令集加速 JSON 引擎)
- **哈希算法**`rapidhash` (非加密哈希算法)
- **二进制编解码**`bitcode` (二进制序列化)
- **字符串存储**`hipstr` (紧凑字符串存储)
- **时间库**`coarsetime``ts_` (时间戳)
- **错误定义**`thiserror`

---

## 性能基准与回归测试

### 运行环境:Ubuntu CI (GitHub Actions Runner)

- **CPU**`Intel(R) Xeon(R) 6973P-C (4 核)`
- **内存**`15.6 GB`
- **系统**`Ubuntu 24.04.4 LTS (Linux 6.17.0-1022-azure) (x86_64)`
- **编译器**`rustc 1.98.0 (88d9e12ae 2026-08-18)`

#### WeDb (嵌入式引擎) vs Redis (v8.10.1 独立服务) 性能对比

> **测试说明**> - WeDb:进程内直接调用,基于 LSM 磁盘持久化(WAL 日志)
> - Redis:独立服务,开启 AOF 持久化(appendfsync everysec),通过本地 Unix Domain Socket 通信

**综合性能对比**:WeDb 加权吞吐量 **168.915 万次/秒** | Redis 加权吞吐量 **2.408 万次/秒** | WeDb 综合性能倍数 **$\color{#1a7f37}\text{70.1x}$**

| 命令 | WeDb P95延时 | WeDb 估算吞吐量 | Redis P95延时 | Redis 估算吞吐量 | WeDb 性能倍数 |
| :--- | :--- | :--- | :--- | :--- | :--- |
| SET | 6.009 µs | 119.717 万次/秒 | 63.3 µs | 2.074 万次/秒 | $\color{#1a7f37}\text{57.7x}$ |
| GET | 267.8 ns | 401.284 万次/秒 | 55.29 µs | 2.084 万次/秒 | $\color{#1a7f37}\text{192.5x}$ |
| MSET | 12.44 µs | 24.857 万次/秒 | 69.21 µs | 3.122 万次/秒 | $\color{#1a7f37}\text{8.0x}$ |
| MGET | 3.295 µs | 52.743 万次/秒 | 49.88 µs | 2.103 万次/秒 | $\color{#1a7f37}\text{25.1x}$ |
| INCRBY | 8.867 µs | 98.717 万次/秒 | 79.99 µs | 2.063 万次/秒 | $\color{#1a7f37}\text{47.9x}$ |
| HSET | 11.27 µs | 66.313 万次/秒 | 55.14 µs | 2.053 万次/秒 | $\color{#1a7f37}\text{32.3x}$ |
| HGET | 1.425 µs | 176.741 万次/秒 | 63.48 µs | 2.085 万次/秒 | $\color{#1a7f37}\text{84.8x}$ |
| LPUSH | 12.19 µs | 31.586 万次/秒 | 81.02 µs | 2.037 万次/秒 | $\color{#1a7f37}\text{15.5x}$ |
| LPOP | 3.307 µs | 50.942 万次/秒 | 51.65 µs | 2.035 万次/秒 | $\color{#1a7f37}\text{25.0x}$ |
| SADD | 9.665 µs | 68.166 万次/秒 | 69.82 µs | 3.917 万次/秒 | $\color{#1a7f37}\text{17.4x}$ |
| SISMEMBER | 579.3 ns | 186.463 万次/秒 | 33.42 µs | 5.244 万次/秒 | $\color{#1a7f37}\text{35.6x}$ |
| ZADD | 12.26 µs | 52.715 万次/秒 | 95.59 µs | 2.094 万次/秒 | $\color{#1a7f37}\text{25.2x}$ |
| ZRANGE | 9.29 µs | 37.495 万次/秒 | 34.76 µs | 4.279 万次/秒 | $\color{#1a7f37}\text{8.8x}$ |
| DEL | 8.569 µs | 73.746 万次/秒 | 56.91 µs | 2.053 万次/秒 | $\color{#1a7f37}\text{35.9x}$ |
| EXISTS | 3.642 µs | 239.063 万次/秒 | 53.85 µs | 2.029 万次/秒 | $\color{#1a7f37}\text{117.8x}$ |

#### 性能回归测试

**综合加权性能**:加权估算吞吐量 **124.290 万次/秒** | 加权延迟变动 **$\color{#0969da}\text{-25%}$**

| 命令 | P95延时 | 估算吞吐量 | 较基线变化 (%) |
| :--- | :--- | :--- | :--- |
| BITCOUNT | 2.912 µs | 210.040 万次/秒 | $\color{#0969da}\text{-10%}$ |
| BITPOS | 763.5 ns | 306.560 万次/秒 | $\color{#1a7f37}\text{+2%}$ |
| GETBIT | 1.908 µs | 226.963 万次/秒 | $\color{#0969da}\text{-11%}$ |
| SETBIT | 11.4 µs | 65.703 万次/秒 | $\color{#0969da}\text{-41%}$ |
| BF.ADD | 106.3 µs | 2.080 万次/秒 | $\color{#0969da}\text{-27%}$ |
| BF.EXISTS | 563.1 ns | 237.192 万次/秒 | $\color{#0969da}\text{-19%}$ |
| BF.INFO | 186 ns | 565.931 万次/秒 | $\color{#1a7f37}\text{-4%}$ |
| CF.ADD | 21.1 µs | 30.285 万次/秒 | $\color{#0969da}\text{-42%}$ |
| CF.DEL | 19.47 µs | 15.941 万次/秒 | $\color{#0969da}\text{-35%}$ |
| CF.EXISTS | 665.8 ns | 169.405 万次/秒 | $\color{#0969da}\text{-20%}$ |
| BATCH_COMMIT | 9.836 µs | 26.476 万次/秒 | $\color{#0969da}\text{-30%}$ |
| DEL | 18.39 µs | 50.736 万次/秒 | $\color{#0969da}\text{-48%}$ |
| EXISTS | 2.533 µs | 354.862 万次/秒 | $\color{#0969da}\text{-22%}$ |
| NAMESPACE | 7.039 µs | 98.328 万次/秒 | $\color{#0969da}\text{-48%}$ |
| GEOADD | 13.16 µs | 53.248 万次/秒 | $\color{#0969da}\text{-37%}$ |
| GEODIST | 3.196 µs | 197.707 万次/秒 | $\color{#1a7f37}\text{-1%}$ |
| GEOHASH | 1.26 µs | 285.144 万次/秒 | $\color{#1a7f37}\text{+1%}$ |
| GEOPOS | 1.728 µs | 342.466 万次/秒 | $\color{#1a7f37}\text{+6%}$ |
| HDEL | 35 µs | 8.389 万次/秒 | $\color{#0969da}\text{-20%}$ |
| HEXISTS | 420.3 ns | 249.501 万次/秒 | $\color{#1a7f37}\text{+2%}$ |
| HGET | 1.56 µs | 147.973 万次/秒 | $\color{#0969da}\text{-12%}$ |
| HGETALL | 30.8 µs | 4.442 万次/秒 | $\color{#1a7f37}\text{-9%}$ |
| HINCRBY | 10.64 µs | 86.059 万次/秒 | $\color{#0969da}\text{-44%}$ |
| HKEYS | 25.58 µs | 5.397 万次/秒 | $\color{#0969da}\text{-14%}$ |
| HLEN | 1.96 µs | 336.361 万次/秒 | $\color{#0969da}\text{-11%}$ |
| HMGET | 3.538 µs | 51.546 万次/秒 | $\color{#1a7f37}\text{-5%}$ |
| HSET | 9.949 µs | 61.312 万次/秒 | $\color{#0969da}\text{-41%}$ |
| HVALS | 27.25 µs | 5.382 万次/秒 | $\color{#0969da}\text{-24%}$ |
| PFADD | 28.24 µs | 12.857 万次/秒 | $\color{#0969da}\text{-41%}$ |
| PFCOUNT | 45.74 µs | 3.602 万次/秒 | $\color{#0969da}\text{-20%}$ |
| PFMERGE | 34.24 µs | 7.123 万次/秒 | $\color{#0969da}\text{-35%}$ |
| JSON.ARRLEN | 4.744 µs | 237.643 万次/秒 | $\color{#0969da}\text{-29%}$ |
| JSON.DEL | 13.38 µs | 44.053 万次/秒 | $\color{#0969da}\text{-47%}$ |
| JSON.GET | 5.82 µs | 207.125 万次/秒 | $\color{#0969da}\text{-33%}$ |
| JSON.NUMINCRBY | 14.19 µs | 75.643 万次/秒 | $\color{#0969da}\text{-48%}$ |
| JSON.SET | 7.076 µs | 62.539 万次/秒 | $\color{#0969da}\text{-45%}$ |
| JSON.TYPE | 3.341 µs | 279.486 万次/秒 | $\color{#0969da}\text{-29%}$ |
| LINDEX | 1.531 µs | 200.481 万次/秒 | $\color{#1a7f37}\text{-3%}$ |
| LLEN | 695.5 ns | 360.231 万次/秒 | $\color{#1a7f37}\text{-8%}$ |
| LPOP | 4.442 µs | 49.579 万次/秒 | $\color{#0969da}\text{-39%}$ |
| LPUSH | 26.37 µs | 73.260 万次/秒 | $\color{#0969da}\text{-43%}$ |
| LRANGE | 36.37 µs | 4.587 万次/秒 | $\color{#0969da}\text{-16%}$ |
| LREM | 32.33 µs | 8.628 万次/秒 | $\color{#0969da}\text{-19%}$ |
| LSET | 4.271 µs | 77.042 万次/秒 | $\color{#0969da}\text{-45%}$ |
| LTRIM | 116.4 µs | 0.983 万次/秒 | $\color{#0969da}\text{-42%}$ |
| RPOP | 4.115 µs | 51.520 万次/秒 | $\color{#0969da}\text{-39%}$ |
| RPUSH | 10.63 µs | 72.780 万次/秒 | $\color{#0969da}\text{-42%}$ |
| SADD | 12.4 µs | 64.725 万次/秒 | $\color{#0969da}\text{-42%}$ |
| SCARD | 786 ns | 372.301 万次/秒 | $\color{#1a7f37}\text{-10%}$ |
| SISMEMBER | 1.603 µs | 155.812 万次/秒 | $\color{#0969da}\text{-16%}$ |
| SMEMBERS | 31.29 µs | 5.288 万次/秒 | $\color{#0969da}\text{-16%}$ |
| SPOP | 1.877 ms | 0.055 万次/秒 | $\color{#0969da}\text{-15%}$ |
| SRANDMEMBER | 32.24 µs | 5.294 万次/秒 | $\color{#0969da}\text{-18%}$ |
| SREM | 24.01 µs | 8.340 万次/秒 | $\color{#0969da}\text{-19%}$ |
| SI.ADD | 10.56 µs | 67.159 万次/秒 | $\color{#0969da}\text{-41%}$ |
| SI.CARD | 1.556 µs | 360.881 万次/秒 | $\color{#1a7f37}\text{-2%}$ |
| SI.EXISTS | 1.658 µs | 191.278 万次/秒 | $\color{#1a7f37}\text{-9%}$ |
| SI.RANGE | 17.17 µs | 11.806 万次/秒 | $\color{#0969da}\text{-16%}$ |
| SI.REM | 27.07 µs | 8.110 万次/秒 | $\color{#0969da}\text{-19%}$ |
| APPEND | 20.18 µs | 56.689 万次/秒 | $\color{#0969da}\text{-51%}$ |
| DECRBY | 3.075 µs | 114.116 万次/秒 | $\color{#0969da}\text{-53%}$ |
| GET | 1.396 µs | 190.006 万次/秒 | $\color{#0969da}\text{-11%}$ |
| GETDEL | 8.726 µs | 57.339 万次/秒 | $\color{#0969da}\text{-52%}$ |
| GETRANGE | 190.8 ns | 548.847 万次/秒 | $\color{#1a7f37}\text{-6%}$ |
| INCRBY | 8.12 µs | 116.306 万次/秒 | $\color{#0969da}\text{-52%}$ |
| MGET | 10.18 µs | 52.274 万次/秒 | $\color{#0969da}\text{-13%}$ |
| MSET | 25.02 µs | 22.925 万次/秒 | $\color{#0969da}\text{-28%}$ |
| SET | 8.494 µs | 123.870 万次/秒 | $\color{#0969da}\text{-53%}$ |
| SETRANGE | 9.97 µs | 55.991 万次/秒 | $\color{#0969da}\text{-51%}$ |
| STRLEN | 334.8 ns | 611.247 万次/秒 | $\color{#1a7f37}\text{+1%}$ |
| XADD | 21.5 µs | 69.930 万次/秒 | $\color{#0969da}\text{-43%}$ |
| XDEL | 28.17 µs | 31.066 万次/秒 | $\color{#0969da}\text{-40%}$ |
| XLEN | 212.2 ns | 491.400 万次/秒 | $\color{#1a7f37}\text{-5%}$ |
| XRANGE | 22.76 µs | 7.770 万次/秒 | $\color{#0969da}\text{-19%}$ |
| XREAD | 21.6 µs | 7.770 万次/秒 | $\color{#0969da}\text{-18%}$ |
| TDIGEST.ADD | 6.174 µs | 53.362 万次/秒 | $\color{#0969da}\text{-42%}$ |
| TDIGEST.BYRANK | 8.605 µs | 210.393 万次/秒 | $\color{#0969da}\text{-32%}$ |
| TDIGEST.CDF | 10.59 µs | 106.689 万次/秒 | $\color{#0969da}\text{-30%}$ |
| TDIGEST.QUANTILE | 9.608 µs | 256.213 万次/秒 | $\color{#0969da}\text{-31%}$ |
| TS.ADD | 45.21 µs | 11.967 万次/秒 | $\color{#0969da}\text{-20%}$ |
| TS.GET | 3.319 µs | 164.799 万次/秒 | $\color{#0969da}\text{-23%}$ |
| TS.INCRBY | 42.69 µs | 6.349 万次/秒 | $\color{#0969da}\text{-24%}$ |
| TS.RANGE | 52.34 µs | 2.300 万次/秒 | $\color{#0969da}\text{-11%}$ |
| ZADD | 16.56 µs | 50.813 万次/秒 | $\color{#0969da}\text{-37%}$ |
| ZCARD | 1.098 µs | 653.595 万次/秒 | $\color{#1a7f37}\text{-10%}$ |
| ZCOUNT | 77.73 µs | 1.563 万次/秒 | $\color{#0969da}\text{-24%}$ |
| ZINCRBY | 13.43 µs | 11.692 万次/秒 | $\color{#1a7f37}\text{-9%}$ |
| ZPOPMIN | 28.23 µs | 7.082 万次/秒 | $\color{#1a7f37}\text{-7%}$ |
| ZRANGE | 9.684 µs | 34.590 万次/秒 | $\color{#0969da}\text{-19%}$ |
| ZRANK | 31.76 µs | 9.390 万次/秒 | $\color{#1a7f37}\text{-7%}$ |
| ZREM | 42.02 µs | 6.464 万次/秒 | $\color{#1a7f37}\text{+1%}$ |
| ZREVRANGE | 9.264 µs | 24.096 万次/秒 | $\color{#0969da}\text{-20%}$ |
| ZSCORE | 590.1 ns | 203.128 万次/秒 | $\color{#0969da}\text{-16%}$ |

---

### 运行环境:macOS (Apple M2 Max)

- **CPU**`Apple M2 Max (12 核)`
- **内存**`64.0 GB`
- **系统**`macOS 26.5.1 (Darwin 25.5.0) (aarch64)`
- **编译器**`rustc 1.98.0 (88d9e12ae 2026-08-18)`

#### WeDb (嵌入式引擎) vs Redis (v8.10.1 独立服务) 性能对比

> **测试说明**> - WeDb:进程内直接调用,基于 LSM 磁盘持久化(WAL 日志)
> - Redis:独立服务,开启 AOF 持久化(appendfsync everysec),通过本地 Unix Domain Socket 通信

**综合性能对比**:WeDb 加权吞吐量 **38.314 万次/秒** | Redis 加权吞吐量 **1.228 万次/秒** | WeDb 综合性能倍数 **$\color{#1a7f37}\text{31.2x}$**

| 命令 | WeDb P95延时 | WeDb 估算吞吐量 | Redis P95延时 | Redis 估算吞吐量 | WeDb 性能倍数 |
| :--- | :--- | :--- | :--- | :--- | :--- |
| SET | 29.66 µs | 50.025 万次/秒 | 531.2 µs | 0.808 万次/秒 | $\color{#1a7f37}\text{61.9x}$ |
| GET | 6.999 µs | 63.211 万次/秒 | 76.74 µs | 1.587 万次/秒 | $\color{#1a7f37}\text{39.8x}$ |
| MSET | 152.2 µs | 5.247 万次/秒 | 561.2 µs | 0.770 万次/秒 | $\color{#1a7f37}\text{6.8x}$ |
| MGET | 22.37 µs | 28.580 万次/秒 | 328.5 µs | 0.825 万次/秒 | $\color{#1a7f37}\text{34.6x}$ |
| INCRBY | 136.6 µs | 25.138 万次/秒 | 1.354 ms | 0.503 万次/秒 | $\color{#1a7f37}\text{50.0x}$ |
| HSET | 48.29 µs | 25.536 万次/秒 | 535.7 µs | 0.915 万次/秒 | $\color{#1a7f37}\text{27.9x}$ |
| HGET | 8.04 µs | 41.391 万次/秒 | 89.16 µs | 1.614 万次/秒 | $\color{#1a7f37}\text{25.6x}$ |
| LPUSH | 141.9 µs | 5.299 万次/秒 | 464.4 µs | 0.800 万次/秒 | $\color{#1a7f37}\text{6.6x}$ |
| LPOP | 40.24 µs | 7.262 万次/秒 | 153.5 µs | 1.446 万次/秒 | $\color{#1a7f37}\text{5.0x}$ |
| SADD | 37.58 µs | 30.386 万次/秒 | 544.4 µs | 0.888 万次/秒 | $\color{#1a7f37}\text{34.2x}$ |
| SISMEMBER | 4.583 µs | 77.519 万次/秒 | 85.2 µs | 1.284 万次/秒 | $\color{#1a7f37}\text{60.4x}$ |
| ZADD | 52.37 µs | 28.927 万次/秒 | 241.8 µs | 1.519 万次/秒 | $\color{#1a7f37}\text{19.0x}$ |
| ZRANGE | 33.37 µs | 26.233 万次/秒 | 113.1 µs | 1.256 万次/秒 | $\color{#1a7f37}\text{20.9x}$ |
| DEL | 16.33 µs | 42.882 万次/秒 | 164.2 µs | 1.916 万次/秒 | $\color{#1a7f37}\text{22.4x}$ |
| EXISTS | 12.33 µs | 117.069 万次/秒 | 50.87 µs | 2.287 万次/秒 | $\color{#1a7f37}\text{51.2x}$ |

#### 性能回归测试

**综合加权性能**:加权估算吞吐量 **129.193 万次/秒** | 加权延迟变动 **$\color{#1a7f37}\text{+12%}$**

| 命令 | P95延时 | 估算吞吐量 | 较基线变化 (%) |
| :--- | :--- | :--- | :--- |
| BITCOUNT | 8.083 µs | 218.103 万次/秒 | $\color{#cf222e}\text{+22%}$ |
| BITPOS | 397.9 ns | 310.174 万次/秒 | $\color{#0969da}\text{-48%}$ |
| GETBIT | 1.187 µs | 195.122 万次/秒 | $\color{#cf222e}\text{+32%}$ |
| SETBIT | 79.33 µs | 43.649 万次/秒 | $\color{#cf222e}\text{+34%}$ |
| BF.ADD | 433.3 µs | 1.130 万次/秒 | $\color{#cf222e}\text{+88%}$ |
| BF.EXISTS | 845.8 ns | 226.142 万次/秒 | $\color{#1a7f37}\text{+10%}$ |
| BF.INFO | 340.6 ns | 388.651 万次/秒 | $\color{#cf222e}\text{+80%}$ |
| CF.ADD | 65.49 µs | 10.668 万次/秒 | $\color{#cf222e}\text{+145%}$ |
| CF.DEL | 67.79 µs | 12.309 万次/秒 | $\color{#1a7f37}\text{+13%}$ |
| CF.EXISTS | 869.4 ns | 145.560 万次/秒 | $\color{#cf222e}\text{+25%}$ |
| BATCH_COMMIT | 67.24 µs | 22.227 万次/秒 | $\color{#cf222e}\text{+20%}$ |
| DEL | 85.12 µs | 30.386 万次/秒 | $\color{#1a7f37}\text{+8%}$ |
| EXISTS | 5.666 µs | 299.850 万次/秒 | $\color{#1a7f37}\text{-0%}$ |
| NAMESPACE | 69.91 µs | 52.192 万次/秒 | $\color{#cf222e}\text{+35%}$ |
| GEOADD | 77.12 µs | 42.123 万次/秒 | $\color{#1a7f37}\text{+12%}$ |
| GEODIST | 559.4 ns | 222.222 万次/秒 | $\color{#cf222e}\text{+16%}$ |
| GEOHASH | 413.6 ns | 276.625 万次/秒 | $\color{#0969da}\text{-57%}$ |
| GEOPOS | 366.7 ns | 334.448 万次/秒 | $\color{#cf222e}\text{+25%}$ |
| HDEL | 80.33 µs | 10.022 万次/秒 | $\color{#1a7f37}\text{+8%}$ |
| HEXISTS | 411 ns | 293.600 万次/秒 | $\color{#1a7f37}\text{-3%}$ |
| HGET | 817.2 ns | 139.237 万次/秒 | $\color{#1a7f37}\text{+15%}$ |
| HGETALL | 37.58 µs | 7.553 万次/秒 | $\color{#1a7f37}\text{-8%}$ |
| HINCRBY | 68.16 µs | 64.893 万次/秒 | $\color{#1a7f37}\text{-5%}$ |
| HKEYS | 20.74 µs | 8.006 万次/秒 | $\color{#1a7f37}\text{+8%}$ |
| HLEN | 317.2 ns | 396.668 万次/秒 | $\color{#1a7f37}\text{-7%}$ |
| HMGET | 10.79 µs | 47.081 万次/秒 | $\color{#1a7f37}\text{+15%}$ |
| HSET | 56.91 µs | 45.310 万次/秒 | $\color{#1a7f37}\text{0%}$ |
| HVALS | 22.16 µs | 7.435 万次/秒 | $\color{#0969da}\text{-11%}$ |
| PFADD | 68.2 µs | 9.718 万次/秒 | $\color{#cf222e}\text{+16%}$ |
| PFCOUNT | 41.79 µs | 2.978 万次/秒 | $\color{#1a7f37}\text{-8%}$ |
| PFMERGE | 51.37 µs | 5.921 万次/秒 | $\color{#1a7f37}\text{+2%}$ |
| JSON.ARRLEN | 17.91 µs | 92.421 万次/秒 | $\color{#cf222e}\text{+100%}$ |
| JSON.DEL | 93.7 µs | 26.674 万次/秒 | $\color{#1a7f37}\text{+5%}$ |
| JSON.GET | 15.66 µs | 150.263 万次/秒 | $\color{#cf222e}\text{+23%}$ |
| JSON.NUMINCRBY | 17.79 µs | 55.835 万次/秒 | $\color{#1a7f37}\text{0%}$ |
| JSON.SET | 56.29 µs | 40.683 万次/秒 | $\color{#cf222e}\text{+20%}$ |
| JSON.TYPE | 5.208 µs | 200.200 万次/秒 | $\color{#cf222e}\text{+20%}$ |
| LINDEX | 533.3 ns | 230.203 万次/秒 | $\color{#1a7f37}\text{+8%}$ |
| LLEN | 237.8 ns | 439.754 万次/秒 | $\color{#1a7f37}\text{+13%}$ |
| LPOP | 6.457 µs | 42.863 万次/秒 | $\color{#1a7f37}\text{-3%}$ |
| LPUSH | 55.37 µs | 63.211 万次/秒 | $\color{#1a7f37}\text{-0%}$ |
| LRANGE | 31.2 µs | 4.318 万次/秒 | $\color{#cf222e}\text{+22%}$ |
| LREM | 129.3 µs | 10.910 万次/秒 | $\color{#1a7f37}\text{+2%}$ |
| LSET | 4.541 µs | 54.585 万次/秒 | $\color{#cf222e}\text{+300%}$ |
| LTRIM | 194.2 µs | 0.706 万次/秒 | $\color{#1a7f37}\text{+4%}$ |
| RPOP | 5.29 µs | 47.081 万次/秒 | $\color{#1a7f37}\text{+2%}$ |
| RPUSH | 75.45 µs | 52.219 万次/秒 | $\color{#0969da}\text{-51%}$ |
| SADD | 76.66 µs | 45.310 万次/秒 | $\color{#cf222e}\text{+20%}$ |
| SCARD | 353.7 ns | 343.407 万次/秒 | $\color{#cf222e}\text{+29%}$ |
| SISMEMBER | 666.2 ns | 165.673 万次/秒 | $\color{#0969da}\text{-15%}$ |
| SMEMBERS | 20.83 µs | 8.368 万次/秒 | $\color{#1a7f37}\text{-0%}$ |
| SPOP | 1.262 ms | 0.093 万次/秒 | $\color{#1a7f37}\text{-0%}$ |
| SRANDMEMBER | 115.5 µs | 7.794 万次/秒 | $\color{#1a7f37}\text{+8%}$ |
| SREM | 121.5 µs | 11.112 万次/秒 | $\color{#1a7f37}\text{-1%}$ |
| SI.ADD | 142.5 µs | 53.362 万次/秒 | $\color{#1a7f37}\text{+12%}$ |
| SI.CARD | 236.5 ns | 562.114 万次/秒 | $\color{#1a7f37}\text{+1%}$ |
| SI.EXISTS | 647.9 ns | 209.512 万次/秒 | $\color{#1a7f37}\text{-3%}$ |
| SI.RANGE | 15.91 µs | 18.185 万次/秒 | $\color{#1a7f37}\text{-3%}$ |
| SI.REM | 91.49 µs | 10.106 万次/秒 | $\color{#1a7f37}\text{+8%}$ |
| APPEND | 88.83 µs | 40.016 万次/秒 | $\color{#0969da}\text{-56%}$ |
| DECRBY | 62.74 µs | 85.763 万次/秒 | $\color{#1a7f37}\text{-10%}$ |
| GET | 666.1 ns | 234.412 万次/秒 | $\color{#1a7f37}\text{+6%}$ |
| GETDEL | 442.2 µs | 17.268 万次/秒 | $\color{#cf222e}\text{+128%}$ |
| GETRANGE | 114.1 ns | 989.120 万次/秒 | $\color{#1a7f37}\text{+4%}$ |
| INCRBY | 97.58 µs | 82.850 万次/秒 | $\color{#1a7f37}\text{-3%}$ |
| MGET | 4.874 µs | 60.024 万次/秒 | $\color{#1a7f37}\text{+11%}$ |
| MSET | 139.3 µs | 20.169 万次/秒 | $\color{#1a7f37}\text{+15%}$ |
| SET | 116.7 µs | 75.075 万次/秒 | $\color{#1a7f37}\text{+14%}$ |
| SETRANGE | 158.5 µs | 35.829 万次/秒 | $\color{#0969da}\text{-51%}$ |
| STRLEN | 96.56 ns | 1197.175 万次/秒 | $\color{#1a7f37}\text{-1%}$ |
| XADD | 49.99 µs | 57.176 万次/秒 | $\color{#1a7f37}\text{+2%}$ |
| XDEL | 55.87 µs | 22.862 万次/秒 | $\color{#cf222e}\text{+23%}$ |
| XLEN | 163.6 ns | 626.174 万次/秒 | $\color{#1a7f37}\text{+12%}$ |
| XRANGE | 34.04 µs | 9.099 万次/秒 | $\color{#1a7f37}\text{+9%}$ |
| XREAD | 28.37 µs | 8.636 万次/秒 | $\color{#1a7f37}\text{+12%}$ |
| TDIGEST.ADD | 17.54 µs | 30.779 万次/秒 | $\color{#1a7f37}\text{+7%}$ |
| TDIGEST.BYRANK | 11.83 µs | 141.343 万次/秒 | $\color{#1a7f37}\text{+13%}$ |
| TDIGEST.CDF | 17.91 µs | 96.061 万次/秒 | $\color{#cf222e}\text{+19%}$ |
| TDIGEST.QUANTILE | 16.08 µs | 184.672 万次/秒 | $\color{#1a7f37}\text{-7%}$ |
| TS.ADD | 165 µs | 14.203 万次/秒 | $\color{#1a7f37}\text{+1%}$ |
| TS.GET | 697.5 ns | 176.305 万次/秒 | $\color{#1a7f37}\text{+7%}$ |
| TS.INCRBY | 27.2 µs | 6.878 万次/秒 | $\color{#1a7f37}\text{+7%}$ |
| TS.RANGE | 28.58 µs | 3.804 万次/秒 | $\color{#1a7f37}\text{+13%}$ |
| ZADD | 141.1 µs | 38.110 万次/秒 | $\color{#cf222e}\text{+19%}$ |
| ZCARD | 174 ns | 748.503 万次/秒 | $\color{#cf222e}\text{+24%}$ |
| ZCOUNT | 60.24 µs | 2.077 万次/秒 | $\color{#cf222e}\text{+21%}$ |
| ZINCRBY | 106.8 µs | 12.534 万次/秒 | $\color{#cf222e}\text{+22%}$ |
| ZPOPMIN | 14.83 µs | 10.885 万次/秒 | $\color{#1a7f37}\text{+7%}$ |
| ZRANGE | 11.29 µs | 37.523 万次/秒 | $\color{#cf222e}\text{+20%}$ |
| ZRANK | 10.29 µs | 15.535 万次/秒 | $\color{#1a7f37}\text{+5%}$ |
| ZREM | 172.6 µs | 11.348 万次/秒 | $\color{#1a7f37}\text{+3%}$ |
| ZREVRANGE | 12.49 µs | 25.265 万次/秒 | $\color{#1a7f37}\text{+10%}$ |
| ZSCORE | 765.1 ns | 156.838 万次/秒 | $\color{#cf222e}\text{+29%}$ |