0281-KVS-启动时加载文件内容

环境

  • Time 2022-12-11
  • WSL-Ubuntu 22.04
  • Rust 1.65.0

前言

说明

参考:https://github.com/pingcap/talent-plan

目标

在上一节的基础上,启动时将文件的内容加载到内存,实现读取操作。

Cargo.toml

[package]
edition = "2021"
name = "kvs"
version = "1.0.0"

[dependencies]
clap = {version = "4", features = ["derive"]}
serde = {version = "1", features = ["derive"]}
serde_json = "1"

lib.rs

use cmd::Command;
use log::CommandLog;

mod cmd;
mod log;

#[derive(Default)]
pub struct KvStore {
    log: CommandLog,
}

impl KvStore {
    pub fn get(&mut self, key: &str) -> Option<String> {
        self.log.get(key)
    }

    pub fn set(&mut self, key: String, value: String) -> Option<String> {
        let command = Command::Set { key, value };
        self.log.set(command)
    }

    pub fn remove(&mut self, key: String) -> Option<String> {
        let command = Command::Remove { key };
        self.log.remove(command)
    }
}

log.rs

use std::collections::HashMap;
use std::fs::{File, OpenOptions};
use std::io::{BufReader, BufWriter, Write};

use serde_json::Deserializer;

use crate::cmd::Command;

pub struct CommandLog {
    writer: BufWriter<File>,
    map: HashMap<String, String>,
}

impl Default for CommandLog {
    fn default() -> Self {
        let path = "/root/log/1.log";
        let writer = new_writer(path);
        let mut map = HashMap::default();
        load(path, &mut map);
        Self { writer, map }
    }
}

impl CommandLog {
    pub fn get(&mut self, key: &str) -> Option<String> {
        self.map.get(key).map(String::from)
    }

    pub fn set(&mut self, command: Command) -> Option<String> {
        let json = serde_json::to_string(&command).unwrap();
        self.writer.write_all(json.as_bytes()).unwrap();
        None
    }

    pub fn remove(&mut self, command: Command) -> Option<String> {
        let json = serde_json::to_string(&command).unwrap();
        self.writer.write_all(json.as_bytes()).unwrap();
        None
    }
}

fn new_writer(path: &str) -> BufWriter<File> {
    let file = OpenOptions::new()
        .append(true)
        .create(true)
        .open(path)
        .unwrap();
    BufWriter::new(file)
}

fn load(path: &str, map: &mut HashMap<String, String>) {
    let stream = Deserializer::from_reader(new_reader(path)).into_iter();
    for cmd in stream {
        match cmd.unwrap() {
            Command::Set { key, value } => map.insert(key, value),
            Command::Remove { key } => map.remove(&key),
        };
    }
}

fn new_reader(path: &str) -> BufReader<File> {
    let file = OpenOptions::new().read(true).open(path).unwrap();
    BufReader::new(file)
}

运行

使用 cargo build --release 构建后运行。

root@jiangbo12490:~/git/game/target/release# ./kvs set name JiangBo
SET KEY: name, VALUE: None
root@jiangbo12490:~/git/game/target/release# ./kvs set age 44
SET KEY: age, VALUE: None
root@jiangbo12490:~/git/game/target/release# ./kvs get name
GET KEY: name, VALUE: JiangBo
root@jiangbo12490:~/git/game/target/release# ./kvs rm name
REM KEY: name, VALUE: None

查看文件

root@jiangbo12490:~/log# cat /root/log/1.log
{"Set":{"key":"name","value":"JiangBo"}}{"Set":{"key":"age","value":"44"}}{"Remove":{"key":"name"}}

总结

在启动时,将文件加载到内存,实现了持久化的功能。

附录

posted @ 2025-10-27 10:33  jiangbo4444  阅读(2)  评论(0)    收藏  举报