Skip to content

第一步:创建项目

bash
cargo new kv-store
cd kv-store

Cargo.toml

toml
[package]
name = "kv-store"
version = "0.1.0"
edition = "2021"

[dependencies]
tokio = { version = "1", features = ["full"] }
dashmap = "5"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
chrono = { version = "0.4", features = ["serde"] }
anyhow = "1"
thiserror = "1"
bytes = "1"
tracing = "0.1"
tracing-subscriber = "0.3"

第二步:数据类型

src/store/types.rs

rust
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

/// 存储值类型
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Value {
    /// 字符串
    String(String),
    /// 列表
    List(Vec<String>),
    /// 哈希表
    Hash(std::collections::HashMap<String, String>),
}

/// 存储条目
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Entry {
    /// 值
    pub value: Value,
    /// 过期时间(可选)
    pub expires_at: Option<DateTime<Utc>>,
    /// 创建时间
    pub created_at: DateTime<Utc>,
}

impl Entry {
    /// 创建新条目
    pub fn new(value: Value) -> Self {
        Self {
            value,
            expires_at: None,
            created_at: Utc::now(),
        }
    }
    
    /// 设置过期时间
    pub fn with_expire(mut self, seconds: u64) -> Self {
        self.expires_at = Some(Utc::now() + chrono::Duration::seconds(seconds as i64));
        self
    }
    
    /// 检查是否过期
    pub fn is_expired(&self) -> bool {
        if let Some(expires_at) = self.expires_at {
            Utc::now() > expires_at
        } else {
            false
        }
    }
}

impl Value {
    /// 创建字符串值
    pub fn string(s: impl Into<String>) -> Self {
        Value::String(s.into())
    }
    
    /// 创建列表值
    pub fn list(items: Vec<String>) -> Self {
        Value::List(items)
    }
    
    /// 创建哈希值
    pub fn hash(fields: std::collections::HashMap<String, String>) -> Self {
        Value::Hash(fields)
    }
    
    /// 获取字符串值
    pub fn as_string(&self) -> Option<&String> {
        match self {
            Value::String(s) => Some(s),
            _ => None,
        }
    }
    
    /// 获取列表值
    pub fn as_list(&self) -> Option<&Vec<String>> {
        match self {
            Value::List(l) => Some(l),
            _ => None,
        }
    }
    
    /// 获取哈希值
    pub fn as_hash(&self) -> Option<&std::collections::HashMap<String, String>> {
        match self {
            Value::Hash(h) => Some(h),
            _ => None,
        }
    }
}
▶ Run

第三步:存储引擎

src/store/engine.rs

rust
use dashmap::DashMap;
use std::sync::Arc;
use crate::store::types::{Entry, Value};

/// 存储引擎
pub struct Store {
    /// 数据存储
    data: DashMap<String, Entry>,
}

impl Store {
    /// 创建新存储
    pub fn new() -> Self {
        Self {
            data: DashMap::new(),
        }
    }
    
    /// 设置键值
    pub fn set(&self, key: String, value: Value) {
        let entry = Entry::new(value);
        self.data.insert(key, entry);
    }
    
    /// 设置键值带过期时间
    pub fn setex(&self, key: String, value: Value, seconds: u64) {
        let entry = Entry::new(value).with_expire(seconds);
        self.data.insert(key, entry);
    }
    
    /// 获取值
    pub fn get(&self, key: &str) -> Option<Value> {
        self.data.get(key).and_then(|entry| {
            if entry.is_expired() {
                // 过期则删除
                self.data.remove(key);
                None
            } else {
                Some(entry.value.clone())
            }
        })
    }
    
    /// 删除键
    pub fn del(&self, key: &str) -> bool {
        self.data.remove(key).is_some()
    }
    
    /// 检查键是否存在
    pub fn exists(&self, key: &str) -> bool {
        self.data.get(key).map(|e| !e.is_expired()).unwrap_or(false)
    }
    
    /// 获取所有键
    pub fn keys(&self) -> Vec<String> {
        self.data
            .iter()
            .filter(|entry| !entry.is_expired())
            .map(|entry| entry.key().clone())
            .collect()
    }
    
    /// 清空所有数据
    pub fn flush(&self) {
        self.data.clear();
    }
    
    /// 获取数据数量
    pub fn size(&self) -> usize {
        self.data.len()
    }
    
    // === List 操作 ===
    
    /// 列表左推入
    pub fn lpush(&self, key: String, value: String) -> anyhow::Result<usize> {
        let entry = self.data.get_mut(&key);
        
        match entry {
            Some(mut e) => {
                match &mut e.value {
                    Value::List(list) => {
                        list.insert(0, value);
                        Ok(list.len())
                    }
                    _ => anyhow::bail!("键类型不是列表"),
                }
            }
            None => {
                let list = Value::list(vec![value]);
                self.set(key, list);
                Ok(1)
            }
        }
    }
    
    /// 列表右推入
    pub fn rpush(&self, key: String, value: String) -> anyhow::Result<usize> {
        let entry = self.data.get_mut(&key);
        
        match entry {
            Some(mut e) => {
                match &mut e.value {
                    Value::List(list) => {
                        list.push(value);
                        Ok(list.len())
                    }
                    _ => anyhow::bail!("键类型不是列表"),
                }
            }
            None => {
                let list = Value::list(vec![value]);
                self.set(key, list);
                Ok(1)
            }
        }
    }
    
    /// 列表左弹出
    pub fn lpop(&self, key: &str) -> Option<String> {
        self.data.get_mut(key).and_then(|mut entry| {
            match &mut entry.value {
                Value::List(list) if !list.is_empty() => Some(list.remove(0)),
                _ => None,
            }
        })
    }
    
    /// 列表右弹出
    pub fn rpop(&self, key: &str) -> Option<String> {
        self.data.get_mut(key).and_then(|mut entry| {
            match &mut entry.value {
                Value::List(list) if !list.is_empty() => Some(list.pop()),
                _ => None,
            }
        })
    }
    
    /// 获取列表长度
    pub fn llen(&self, key: &str) -> usize {
        self.get(key)
            .and_then(|v| v.as_list().map(|l| l.len()))
            .unwrap_or(0)
    }
    
    /// 获取列表范围
    pub fn lrange(&self, key: &str, start: usize, end: usize) -> Option<Vec<String>> {
        self.get(key).and_then(|v| {
            v.as_list().map(|list| {
                let end = end.min(list.len());
                if start < end {
                    list[start..end].to_vec()
                } else {
                    vec![]
                }
            })
        })
    }
    
    // === Hash 操作 ===
    
    /// 设置哈希字段
    pub fn hset(&self, key: String, field: String, value: String) -> anyhow::Result<bool> {
        let entry = self.data.get_mut(&key);
        
        match entry {
            Some(mut e) => {
                match &mut e.value {
                    Value::Hash(hash) => {
                        let is_new = !hash.contains_key(&field);
                        hash.insert(field, value);
                        Ok(is_new)
                    }
                    _ => anyhow::bail!("键类型不是哈希"),
                }
            }
            None => {
                let mut hash = std::collections::HashMap::new();
                hash.insert(field, value);
                self.set(key, Value::hash(hash));
                Ok(true)
            }
        }
    }
    
    /// 获取哈希字段
    pub fn hget(&self, key: &str, field: &str) -> Option<String> {
        self.get(key).and_then(|v| {
            v.as_hash().and_then(|h| h.get(field).cloned())
        })
    }
    
    /// 获取所有哈希字段
    pub fn hgetall(&self, key: &str) -> Option<std::collections::HashMap<String, String>> {
        self.get(key).and_then(|v| v.as_hash().cloned())
    }
    
    /// 删除哈希字段
    pub fn hdel(&self, key: &str, field: &str) -> bool {
        self.data.get_mut(key).and_then(|mut entry| {
            match &mut entry.value {
                Value::Hash(hash) => hash.remove(field).is_some(),
                _ => false,
            }
        }).unwrap_or(false)
    }
}

impl Default for Store {
    fn default() -> Self {
        Self::new()
    }
}
▶ Run

第四步:命令协议

src/command/protocol.rs

rust
use serde::{Deserialize, Serialize};

/// 响应结果
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Response {
    /// 成功(简单字符串)
    Ok(String),
    /// 错误
    Error(String),
    /// 整数
    Integer(i64),
    /// 批量字符串
    Bulk(String),
    /// 数组
    Array(Vec<Response>),
    /// 空
    Nil,
}

impl Response {
    /// 成功响应
    pub fn ok() -> Self {
        Response::Ok("OK".to_string())
    }
    
    /// 错误响应
    pub fn error(msg: impl Into<String>) -> Self {
        Response::Error(msg.into())
    }
    
    /// 整数响应
    pub fn integer(n: i64) -> Self {
        Response::Integer(n)
    }
    
    /// 批量字符串响应
    pub fn bulk(s: impl Into<String>) -> Self {
        Response::Bulk(s.into())
    }
    
    /// 空响应
    pub fn nil() -> Self {
        Response::Nil
    }
    
    /// 数组响应
    pub fn array(items: Vec<Response>) -> Self {
        Response::Array(items)
    }
    
    /// 序列化为字符串
    pub fn to_string(&self) -> String {
        match self {
            Response::Ok(s) => format!("+{}\r\n", s),
            Response::Error(e) => format!("-{}\r\n", e),
            Response::Integer(n) => format!(":{}\r\n", n),
            Response::Bulk(s) => format!("${}\r\n{}\r\n", s.len(), s),
            Response::Nil => "$-1\r\n".to_string(),
            Response::Array(items) => {
                let mut result = format!("*{}\r\n", items.len());
                for item in items {
                    result.push_str(&item.to_string());
                }
                result
            }
        }
    }
}
▶ Run

第五步:命令解析

src/command/parser.rs

rust
use bytes::Bytes;

/// 命令解析器
pub struct CommandParser;

impl CommandParser {
    /// 解析命令
    pub fn parse(input: &[u8]) -> Option<Vec<String>> {
        let input = std::str::from_utf8(input).ok()?;
        
        // 简单协议:命令用空格分隔
        // 例如:SET key value
        let parts: Vec<String> = input
            .trim()
            .split_whitespace()
            .map(|s| s.to_string())
            .collect();
        
        if parts.is_empty() {
            None
        } else {
            Some(parts)
        }
    }
    
    /// 解析 RESP 协议(Redis 协议)
    pub fn parse_resp(input: &[u8]) -> Option<Vec<String>> {
        let input = std::str::from_utf8(input).ok()?;
        let lines: Vec<&str> = input.lines().collect();
        
        if lines.is_empty() {
            return None;
        }
        
        // 检查数组标记
        if !lines[0].starts_with('*') {
            return Self::parse(input);
        }
        
        let count: usize = lines[0][1..].parse().ok()?;
        let mut result = Vec::with_capacity(count);
        
        let mut i = 1;
        while i < lines.len() && result.len() < count {
            if lines[i].starts_with('$') {
                let len: usize = lines[i][1..].parse().ok()?;
                i += 1;
                if i < lines.len() {
                    result.push(lines[i].to_string());
                }
            }
            i += 1;
        }
        
        Some(result)
    }
}
▶ Run