为Blob增加压缩支持,IO优化放置到Store中

This commit is contained in:
HouXiaoxuan
2023-12-28 22:02:02 +08:00
parent cdc289b3bb
commit b3aea1d0d1
4 changed files with 51 additions and 69 deletions

View File

@@ -16,4 +16,6 @@ colored = "2.1.0"
rand = "0.8.5"
color-backtrace = "0.6.1"
once_cell = "1.19.0"
backtrace = "0.3.69"
backtrace = "0.3.69"
flate2 = "1.0.28"
base64 = "0.21.5"

View File

@@ -1,3 +1,7 @@
use base64::Engine;
use flate2::{read::GzDecoder, write::GzEncoder, Compression};
use std::io::{Read, Write};
use crate::{
models::Hash,
utils::{store, util},
@@ -17,28 +21,53 @@ impl Blob {
/// 从源文件新建blob对象并直接保存到/objects/中
pub fn new(file: &Path) -> Blob {
let data = fs::read_to_string(file).expect(format!("无法读取文件:{:?}", file).as_str());
let hash = util::calc_hash(&data);
let blob = Blob { hash, data };
let mut blob = Blob { hash: "".to_string(), data };
blob.save();
blob
}
pub fn load(hash: &String) -> Blob {
let s = store::Store::new();
let data = s.load(hash);
let encoded = s.load(hash);
let compressed_data = base64::engine::general_purpose::STANDARD_NO_PAD.decode(&encoded).unwrap();
let mut decompress_decoder = GzDecoder::new(&compressed_data[..]);
let mut data = String::new();
decompress_decoder.read_to_string(&mut data).unwrap();
Blob { hash: hash.clone(), data }
}
/// 写入文件;优化:文件已存在时不做操作
pub fn save(&self) {
/// 写入文件
pub fn save(&mut self) -> Hash {
let s = store::Store::new();
if !s.contains(&self.hash) {
let hash = s.save(&self.data);
assert_eq!(hash, self.hash);
}
let mut cmopress_encoder = GzEncoder::new(Vec::new(), Compression::default());
cmopress_encoder.write_all(self.data.as_bytes()).unwrap();
let compressed_data = cmopress_encoder.finish().unwrap();
let encoded_data = base64::engine::general_purpose::STANDARD_NO_PAD.encode(&compressed_data);
let hash: String = s.save(&encoded_data);
self.hash = hash;
self.hash.clone()
}
pub fn get_hash(&self) -> String {
self.hash.clone()
}
}
#[cfg(test)]
mod test {
use std::path::PathBuf;
use crate::utils::test_util;
#[test]
fn test_save_and_load() {
test_util::setup_test_with_clean_mit();
let test_data = "hello world";
test_util::ensure_test_file(&PathBuf::from("a.txt"), Some(test_data));
let blob = super::Blob::new(&PathBuf::from("a.txt"));
let blob2 = super::Blob::load(&blob.hash);
assert_eq!(blob2.get_hash(), blob.get_hash());
assert_eq!(blob2.data, test_data);
}
}

View File

@@ -99,7 +99,7 @@ impl Tree {
tree
}
pub fn save(&mut self) -> String {
pub fn save(&mut self) -> Hash {
let s = store::Store::new();
let tree_data = serde_json::to_string_pretty(&self).unwrap();
let hash = s.save(&tree_data);
@@ -107,28 +107,6 @@ impl Tree {
hash
}
/**递归获取Tree对应的所有文件 */
pub fn get_recursive_file_entries(&self) -> Vec<PathBuf> {
let mut files = Vec::new();
for entry in self.entries.iter() {
if entry.filemode.0 == "blob" {
files.push(PathBuf::from(entry.name.clone()));
} else {
let sub_tree = Tree::load(&entry.object_hash);
let sub_files = sub_tree.get_recursive_file_entries();
files.append(
sub_files
.iter()
.map(|file| PathBuf::from(entry.name.clone()).join(file))
.collect::<Vec<PathBuf>>()
.as_mut(),
);
}
}
files
}
///注:相对路径(to workdir)
pub fn get_recursive_blobs(&self) -> Vec<(PathBuf, Hash)> {
//TODO 返回HashMap
@@ -159,7 +137,7 @@ mod test {
use crate::{
models::*,
utils::{util, test_util},
utils::test_util,
};
#[test]
@@ -198,34 +176,6 @@ mod test {
assert!(tree.entries[1].name == loaded_tree.entries[1].name);
}
#[test]
fn test_get_recursive_file_entries() {
test_util::setup_test_with_clean_mit();
let index = Index::get_instance();
let mut test_files = vec![PathBuf::from("b.txt"), PathBuf::from("mit_src/a.txt")];
for test_file in test_files.clone() {
test_util::ensure_test_file(&test_file, None);
index.add(test_file.clone(), FileMetaData::new(&Blob::new(&test_file), &test_file));
}
let tree = Tree::new(&index);
let tree_hash = tree.get_hash();
let loaded_tree = Tree::load(&tree_hash);
let mut files = loaded_tree.get_recursive_file_entries();
files.sort();
test_files.sort();
assert_eq!(files.len(), test_files.len());
assert_eq!(
util::to_workdir_absolute_path(&files[0]).to_str().unwrap(), //TODO 罪大恶极的路径问题
util::get_absolute_path(&test_files[0]).to_str().unwrap()
);
assert_eq!(
util::to_workdir_absolute_path(&files[1]).to_str().unwrap(),
util::get_absolute_path(&test_files[1]).to_str().unwrap()
);
}
#[test]
fn test_get_recursive_blobs() {
test_util::setup_test_with_clean_mit();

View File

@@ -9,6 +9,9 @@ pub struct Store {
store_path: PathBuf,
}
/**Store负责管理objects
* 每一个object文件名与内容的hash值相同
*/
impl Store {
pub fn new() -> Store {
util::check_repo_exist();
@@ -26,13 +29,6 @@ impl Store {
}
}
pub fn contains(&self, hash: &String) -> bool {
let mut path = self.store_path.clone();
path.push("objects");
path.push(hash);
path.exists()
}
/// 将hash对应的文件内容(主要是blob)还原到file
pub fn restore_to_file(&self, hash: &Hash, file: &PathBuf) {
let content = self.load(hash);
@@ -69,6 +65,7 @@ impl Store {
}
}
pub fn save(&self, content: &String) -> String {
/* 保存文件内容 */
let hash = util::calc_hash(content);
@@ -76,6 +73,10 @@ impl Store {
path.push("objects");
path.push(&hash);
// println!("Saved to: [{}]", path.display());
if path.exists() {
// IO优化文件已存在不再写入
return hash;
}
match std::fs::write(path, content) {
Ok(_) => hash,
Err(_) => panic!("储存库疑似损坏,无法写入文件"),