0288-KVS-根据索引读取文件

环境

  • Time 2022-12-13
  • 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"

log.rs

use std::collections::BTreeMap;

use crate::cmd::{Command, CommandPosition};

use self::{reader::PosBufReader, writer::PosBufWriter};

mod reader;
mod writer;

pub struct CommandLog {
    reader: PosBufReader,
    writer: PosBufWriter,
    index: BTreeMap<String, CommandPosition>,
}

pub type KvResult = anyhow::Result<Option<String>>;

impl CommandLog {
    pub fn new() -> anyhow::Result<Self> {
        let path = "/root/log/1.log";
        let writer = PosBufWriter::new(path)?;
        let mut index = BTreeMap::default();
        let mut reader = PosBufReader::new(path)?;
        reader.load(&mut index)?;
        Ok(Self {
            reader,
            writer,
            index,
        })
    }

    pub fn get(&mut self, key: &str) -> KvResult {
        self.reader.read(self.index.get(key))
    }

    pub fn set(&mut self, key: String, value: String) -> KvResult {
        let result = self.reader.read(self.index.get(&key));
        let command = Command::Set {
            key: key.to_string(),
            value,
        };
        let json = serde_json::to_string(&command)?;
        let position = self.writer.write(json.as_bytes())?;
        self.index.insert(key, position);
        result
    }

    pub fn remove(&mut self, key: String) -> KvResult {
        let result = self.reader.read(self.index.get(&key));
        let command = Command::Remove {
            key: key.to_string(),
        };
        let json = serde_json::to_string(&command)?;
        self.writer.write(json.as_bytes())?;
        self.index.remove(&key);
        result
    }
}

reader.rs

use std::fs::{File, OpenOptions};
use std::io::{BufReader, Read, Seek, SeekFrom};

use serde_json::Deserializer;

use crate::cmd::{Command, CommandPosition, Index};

use super::KvResult;

pub struct PosBufReader {
    reader: BufReader<File>,
}

impl PosBufReader {
    pub fn new(path: &str) -> anyhow::Result<PosBufReader> {
        let file = OpenOptions::new().read(true).open(path)?;
        let reader = BufReader::new(file);
        Ok(Self { reader })
    }

    pub fn load(&mut self, map: &mut Index) -> anyhow::Result<()> {
        let reader = &mut self.reader;
        let mut old = reader.seek(SeekFrom::Start(0))? as usize;
        let mut stream = Deserializer::from_reader(reader).into_iter();
        while let Some(cmd) = stream.next() {
            let new = stream.byte_offset();
            match cmd? {
                Command::Set { key, .. } => {
                    let position = CommandPosition::new(old, new - old);
                    map.insert(key, position);
                }
                Command::Remove { .. } => (),
            };
            old = new;
        }
        Ok(())
    }

    pub fn read(&mut self, position: Option<&CommandPosition>) -> KvResult {
        let position = match position {
            Some(position) => position,
            None => return Ok(None),
        };

        self.reader.seek(SeekFrom::Start(position.pos as u64))?;
        let command = (&mut self.reader).take(position.len as u64);

        match serde_json::from_reader(command)? {
            Command::Set { value, .. } => Ok(Some(value)),
            _ => unreachable!(),
        }
    }
}

总结

读取值时,根据内存中保存的索引,到文件中获取真正的值。

附录

posted @ 2025-10-28 17:16  jiangbo4444  阅读(0)  评论(0)    收藏  举报