wedb_embed 0.1.1

Embedded database engine providing Redis-like APIs, built on fjall / 嵌入式数据库引擎,提供类似 Redis 的接口,底层基于 fjall 开发
Documentation
use wedb_embed::{Conf, ScopeId, WeDb, decode_u64_varint, encode_u64_varint};

#[test]
fn test_keyspace_isolated_keyspaces() {
    let dir = tempfile::tempdir().expect("create tempdir failed");
    let conf = Conf::new(dir.path().to_str().unwrap());
    let db = WeDb::open_with_conf(&conf).expect("open db failed");

    db.data.insert(b"k1", b"v1").expect("data insert failed");
    assert_eq!(db.data.get(b"k1").unwrap().unwrap().as_ref(), b"v1");

    db.meta
        .insert(b"meta:1", b"m1")
        .expect("meta insert failed");
    assert_eq!(db.meta.get(b"meta:1").unwrap().unwrap().as_ref(), b"m1");

    assert!(db.data.get(b"meta:1").unwrap().is_none());
}
#[test]
fn test_oppv_monotonic_and_boundaries() {
    let test_cases = [
        0u64,
        1,
        127,
        128,
        1000,
        16511,
        16512,
        100_000,
        2113663,
        2113664,
        10_000_000,
        270549119,
        270549120,
        1_000_000_000,
        u32::MAX as u64,
        (u32::MAX as u64) + 1,
        1_000_000_000_000,
        1_000_000_000_000_000,
        u64::MAX - 100,
        u64::MAX,
    ];

    let mut prev_encoded = Vec::new();
    let mut prev_val = 0u64;

    for (idx, &val) in test_cases.iter().enumerate() {
        let mut encoded = Vec::new();
        encode_u64_varint(val, &mut encoded);

        // 验证解码
        let (decoded, len) = decode_u64_varint(&encoded).expect("decode failed");
        assert_eq!(decoded, val);
        assert_eq!(len, encoded.len());

        // 验证保序性
        if idx > 0 {
            assert!(prev_val < val, "test values must be strictly increasing");
            assert!(
                prev_encoded < encoded,
                "encoded bytes must preserve order: {:?} < {:?}",
                prev_encoded,
                encoded
            );
        }

        prev_val = val;
        prev_encoded = encoded;
    }
}

#[test]
fn test_scope_and_binary_keys_non_penetration() {
    // 测试多种作用域组合:默认库 (0,0)、常规租户与库 (1001, 88)、百万租户与大库 (1_000_000, 999_999_999)
    let scopes = [
        ScopeId::DEFAULT,
        ScopeId::new(1001, 88),
        ScopeId::new(1_000_000, 999_999_999),
    ];

    // 包含各种极端二进制、空字节、伪造内部编码前缀的 Key
    let binary_keys: Vec<&[u8]> = vec![
        b"",
        b"\x00",
        b"\x00\x00",
        b"\x00\x00\x01\x02kmalicious_key",
        b"\x00\x00\xff\xff\xfe\xfd",
        b"user\x00profile\x00data",
        b"\xff\xfe\xfd\xfc\xfb\xfa",
        b"colon:separated:key:with:\x00:binary",
        &[0x00, 0x00, 0x80, 0x01, 0x6b, 0x74, 0x65, 0x73, 0x74],
    ];

    for &scope in &scopes {
        for &raw_k in &binary_keys {
            // 1. String 键编码与零内存分配提取
            let encoded_key = scope.encode_key(raw_k);
            assert_eq!(
                ScopeId::extract_user_key(&encoded_key),
                Some(raw_k),
                "Failed for scope {scope:?}, key: {raw_k:?}"
            );
            if !scope.is_default() {
                assert_eq!(ScopeId::parse_scope(&encoded_key), Some(scope));
            }

            // 2. Meta 键编码与提取
            let meta_k = scope.encode_meta_key(b'h', raw_k);
            assert_eq!(
                ScopeId::extract_user_key(&meta_k),
                Some(raw_k),
                "Failed for meta key: {raw_k:?}"
            );

            // 3. SubKey 编码与定界:任意二进制 field 和版本号绝对不能穿透主键
            let binary_fields: Vec<&[u8]> = vec![
                b"",
                b"\x00",
                b"\x00\x00\x00\x00",
                b"normal_field",
                b"field\x00with\x00nulls",
                b"\xff\xff\xff\xff",
            ];

            for &field in &binary_fields {
                let version = 0x123456789ABCDEF0u64;
                let sub_k = scope.encode_sub_key(b'h', raw_k, version, field);

                let extracted = ScopeId::extract_user_key(&sub_k);
                assert_eq!(
                    extracted,
                    Some(raw_k),
                    "SubKey extraction penetrated into subkey/version! key={raw_k:?}, field={field:?}"
                );
            }
        }
    }

    // 4. 租户与数据库相互隔离性验证(互不穿透)
    let s1_0 = ScopeId::new(1, 0);
    let s1_1 = ScopeId::new(1, 1);
    let s2_0 = ScopeId::new(2, 0);
    let s2_1 = ScopeId::new(2, 1);

    let k_s1_0 = s1_0.encode_key(b"shared_key");
    let k_s1_1 = s1_1.encode_key(b"shared_key");
    let k_s2_0 = s2_0.encode_key(b"shared_key");
    let k_s2_1 = s2_1.encode_key(b"shared_key");

    // 彼此二进制编码必须全不相同
    assert_ne!(k_s1_0, k_s1_1);
    assert_ne!(k_s1_0, k_s2_0);
    assert_ne!(k_s1_1, k_s2_1);
    assert_ne!(k_s2_0, k_s2_1);

    // 作用域前缀相互独立
    assert!(!k_s1_0.starts_with(&s1_1.flush_db_prefix()));
    assert!(!k_s1_0.starts_with(&s2_0.flush_db_prefix()));
    assert!(!k_s1_1.starts_with(&s1_0.flush_db_prefix()));
    assert!(!k_s2_0.starts_with(&s1_0.tenant_prefix()));
}

#[test]
fn test_fjall_scope_prefix_scan_isolation() {
    let dir = tempfile::tempdir().expect("create tempdir failed");
    let conf = Conf::new(dir.path().to_str().unwrap());
    let db = WeDb::open_with_conf(&conf).expect("open db failed");

    // 构造多个租户、多个 DB 的数据集
    // 租户 1: DB 0, DB 1, DB 2
    // 租户 2: DB 0, DB 1
    // 租户 100: DB 0
    let s1_0 = ScopeId::new(1, 0);
    let s1_1 = ScopeId::new(1, 1);
    let s1_2 = ScopeId::new(1, 2);
    let s2_0 = ScopeId::new(2, 0);
    let s2_1 = ScopeId::new(2, 1);
    let s100_0 = ScopeId::new(100, 0);

    // 写入 Tenant 1, DB 0 (包含二进制 Key、Meta Key、SubKey)
    let s1_0_keys = [
        s1_0.encode_key(b"key1"),
        s1_0.encode_key(b"key2"),
        s1_0.encode_key(b"binary\x00key\x00test"),
        s1_0.encode_key(b"\x00\x00fake_escape"),
    ];
    for (i, k) in s1_0_keys.iter().enumerate() {
        db.data
            .insert(k.as_ref(), format!("val_1_0_{i}").as_bytes())
            .unwrap();
    }
    // Meta & Subkeys for Tenant 1, DB 0
    let meta_1_0 = s1_0.encode_meta_key(b'h', b"hash_1_0");
    db.meta.insert(&meta_1_0, b"hash_meta_data").unwrap();
    let sub1_1_0 = s1_0.encode_sub_key(b'h', b"hash_1_0", 1, b"f1");
    let sub2_1_0 = s1_0.encode_sub_key(b'h', b"hash_1_0", 1, b"f2\x00null");
    db.data.insert(&sub1_1_0, b"v1").unwrap();
    db.data.insert(&sub2_1_0, b"v2").unwrap();

    // 写入 Tenant 1, DB 1
    let s1_1_keys = [
        s1_1.encode_key(b"key1"),
        s1_1.encode_key(b"another_key"),
        s1_1.encode_key(b"\xff\xfe_max_key"),
    ];
    for (i, k) in s1_1_keys.iter().enumerate() {
        db.data
            .insert(k.as_ref(), format!("val_1_1_{i}").as_bytes())
            .unwrap();
    }

    // 写入 Tenant 1, DB 2
    let s1_2_k = s1_2.encode_key(b"only_db2_key");
    db.data.insert(s1_2_k.as_ref(), b"val_db2").unwrap();

    // 写入 Tenant 2, DB 0
    let s2_0_keys = [s2_0.encode_key(b"key1"), s2_0.encode_key(b"t2_key")];
    for (i, k) in s2_0_keys.iter().enumerate() {
        db.data
            .insert(k.as_ref(), format!("val_2_0_{i}").as_bytes())
            .unwrap();
    }

    // 写入 Tenant 2, DB 1
    let s2_1_k = s2_1.encode_key(b"key1");
    db.data.insert(s2_1_k.as_ref(), b"val_2_1").unwrap();

    // 写入 Tenant 100, DB 0
    let s100_0_k = s100_0.encode_key(b"key1");
    db.data.insert(s100_0_k.as_ref(), b"val_100_0").unwrap();

    // ================= 验证 1: 单库扫描范围 (FLUSHDB) =================
    // 扫描 Tenant 1, DB 0:必须精确匹配 4 个 String + 2 个 SubKey = 6 个 data 项,1 个 meta 项
    let flush_prefix_1_0 = s1_0.flush_db_prefix();
    let scanned_data_1_0: Vec<Vec<u8>> = db
        .data
        .prefix(&flush_prefix_1_0)
        .map(|item| item.key().unwrap().to_vec())
        .collect();
    assert_eq!(
        scanned_data_1_0.len(),
        6,
        "Tenant 1 DB 0 data items mismatch"
    );
    for k in &scanned_data_1_0 {
        assert_eq!(ScopeId::parse_scope(k), Some(s1_0));
    }

    let scanned_meta_1_0: Vec<Vec<u8>> = db
        .meta
        .prefix(&flush_prefix_1_0)
        .map(|item| item.key().unwrap().to_vec())
        .collect();
    assert_eq!(
        scanned_meta_1_0.len(),
        1,
        "Tenant 1 DB 0 meta items mismatch"
    );
    assert_eq!(ScopeId::parse_scope(&scanned_meta_1_0[0]), Some(s1_0));

    // 扫描 Tenant 1, DB 1:必须精确匹配 3 个 data 项
    let flush_prefix_1_1 = s1_1.flush_db_prefix();
    let scanned_data_1_1: Vec<Vec<u8>> = db
        .data
        .prefix(&flush_prefix_1_1)
        .map(|item| item.key().unwrap().to_vec())
        .collect();
    assert_eq!(
        scanned_data_1_1.len(),
        3,
        "Tenant 1 DB 1 data items mismatch"
    );
    for k in &scanned_data_1_1 {
        assert_eq!(ScopeId::parse_scope(k), Some(s1_1));
    }

    // ================= 验证 2: 租户级扫描范围 (FLUSHALL / 删除租户) =================
    // 扫描 Tenant 1:必须精确覆盖 DB 0 (6) + DB 1 (3) + DB 2 (1) = 10 个 data 项,1 个 meta 项
    let tenant_prefix_1 = s1_0.tenant_prefix();
    let scanned_tenant_1: Vec<Vec<u8>> = db
        .data
        .prefix(&tenant_prefix_1)
        .map(|item| item.key().unwrap().to_vec())
        .collect();
    assert_eq!(
        scanned_tenant_1.len(),
        10,
        "Tenant 1 total items across all DBs mismatch"
    );
    for k in &scanned_tenant_1 {
        let sc = ScopeId::parse_scope(k).unwrap();
        assert_eq!(sc.tenant_id, 1, "Leaked into another tenant!");
    }

    // 扫描 Tenant 2:精确覆盖 DB 0 (2) + DB 1 (1) = 3 个 data 项
    let tenant_prefix_2 = s2_0.tenant_prefix();
    let scanned_tenant_2: Vec<Vec<u8>> = db
        .data
        .prefix(&tenant_prefix_2)
        .map(|item| item.key().unwrap().to_vec())
        .collect();
    assert_eq!(scanned_tenant_2.len(), 3, "Tenant 2 items mismatch");
    for k in &scanned_tenant_2 {
        let sc = ScopeId::parse_scope(k).unwrap();
        assert_eq!(sc.tenant_id, 2);
    }

    // ================= 验证 3: 模拟清理 DB 0,验证相邻 DB 与租户不受影响 =================
    let mut batch = db.db.batch();
    for k in &scanned_data_1_0 {
        batch.remove(&db.data, k);
    }
    for k in &scanned_meta_1_0 {
        batch.remove(&db.meta, k);
    }
    batch.commit().unwrap();

    // 验证 Tenant 1, DB 0 已空
    assert_eq!(db.data.prefix(&flush_prefix_1_0).count(), 0);
    assert_eq!(db.meta.prefix(&flush_prefix_1_0).count(), 0);

    // 验证 Tenant 1 DB 1 依然完整 (3 个项)
    assert_eq!(db.data.prefix(&flush_prefix_1_1).count(), 3);
    // 验证 Tenant 1 DB 2 依然完整 (1 个项)
    assert_eq!(db.data.prefix(s1_2.flush_db_prefix()).count(), 1);
    // 验证 Tenant 2 DB 0 依然完整 (2 个项)
    assert_eq!(db.data.prefix(s2_0.flush_db_prefix()).count(), 2);
    // 验证 Tenant 100 DB 0 依然完整 (1 个项)
    assert_eq!(db.data.prefix(s100_0.flush_db_prefix()).count(), 1);
}

#[test]
fn test_oppv_lexicographical_range_ordering() {
    // 验证跨越不同字节长度边界时,字典序仍然严格递增
    let scopes = [
        ScopeId::new(1, 0),
        ScopeId::new(1, 1),
        ScopeId::new(1, 127),
        ScopeId::new(1, 128),
        ScopeId::new(1, 16511),
        ScopeId::new(1, 16512),
        ScopeId::new(1, 2113663),
        ScopeId::new(1, 2113664),
        ScopeId::new(1, u64::MAX),
        ScopeId::new(2, 0),
        ScopeId::new(127, 0),
        ScopeId::new(128, 0),
        ScopeId::new(16511, 0),
        ScopeId::new(16512, 0),
        ScopeId::new(1_000_000, 0),
        ScopeId::new(u64::MAX, u64::MAX),
    ];

    for i in 0..scopes.len() - 1 {
        let p1 = scopes[i].flush_db_prefix();
        let p2 = scopes[i + 1].flush_db_prefix();
        assert!(
            p1 < p2,
            "Lexicographical ordering violation: {:?} ({:?}) vs {:?} ({:?})",
            scopes[i],
            p1,
            scopes[i + 1],
            p2
        );
    }
}