Skip to content

Commit c61b005

Browse files
authored
Merge pull request #634 from Ivanbeethoven/main
[scorpio]: Pack and Push in scorpio.
2 parents 0ac175d + ce14200 commit c61b005

File tree

13 files changed

+425
-189
lines changed

13 files changed

+425
-189
lines changed

docs/images/scorpio.drawio

+1-94
Large diffs are not rendered by default.

docs/images/scorpio2.drawio

+111
Large diffs are not rendered by default.

docs/images/scorpio2.png

69.3 KB
Loading

mercury/src/internal/object/tree.rs

+9
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,15 @@ impl Tree {
262262
tree_items,
263263
})
264264
}
265+
266+
/// After the subdirectory is changed, the hash value of the tree is recalculated.
267+
pub fn rehash(&mut self){
268+
let mut data = Vec::new();
269+
for item in &self.tree_items {
270+
data.extend_from_slice(item.to_data().as_slice());
271+
}
272+
self.id = SHA1::from_type_and_data(ObjectType::Tree, &data);
273+
}
265274
}
266275
impl TryFrom<&[u8]> for Tree{
267276
type Error = GitError;

scorpio/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ edition = "2021"
66
[dependencies]
77
libra = { path = "../libra" }
88
mercury = { path = "../mercury" }
9-
9+
ceres = { path = "../ceres" }
1010
toml = "0.8.19"
1111
fuser = "0.14.0"
1212
libc = "0.2.158"
@@ -26,6 +26,7 @@ env_logger = "0.11.5"
2626
sled = "0.34.7"
2727
bincode = "1.3.3"
2828
async-recursion = "1.1.1"
29+
bytes = "1.7.2"
2930

3031
[features]
3132
async-io = []

scorpio/README.md

+6
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,9 @@ The structure of Sapling is achieved through a multi-layered architecture, with
6464
[6] [fuser](https://github.com/cberner/fuser.git) : A Rust library crate for easy implementation of FUSE filesystems in userspace.
6565

6666
[7] [Scalar](https://github.com/microsoft/git/blob/HEAD/contrib/scalar/docs/index.md) : Scalar is a tool that helps Git scale to some of the largest Git repositories. Initially, it was a single standalone git plugin based on Vfs for git, inheriting GVFS. No longer using FUSE. It implements aware partial directory management. Users need to manage and register the required workspace directory on their own. Ease of use can be improved through the fuse mechanism.
67+
68+
69+
# TODO
70+
1. * BUILD : monorepo build , which dictionary ?
71+
2. *** API list... for add mount point .
72+
3. - .https://opentitan.org/

scorpio/config.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ store_path = "/home/luxian/megadir/store"
55
[[works]]
66
path = "third-part/mega/libra"
77
node = 26
8-
hash = "4a3bec47e31fc5442b9f9c42f519788e565ea485"
8+
hash = "47a90e9262bcd023bbff32f9f4c328b43b62813a"
99

1010
[[works]]
1111
path = "third-part/mega/scorpio"
1212
node = 17
13-
hash = "1b70e8bf4d39d6f5e9dd1637aaa2c221e2d00a27"
13+
hash = "76d6dbd014dee9a78497ea61d1ee923e8b0f9387"

scorpio/src/manager/diff.rs

+150-46
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::collections::HashMap;
2-
use std::{ffi::CString, fs};
2+
use std::vec;
3+
use std::ffi::CString;
34
use std::path::{Path, PathBuf};
45
use libc::{self, stat};
56
use mercury::hash::SHA1;
@@ -8,12 +9,12 @@ use mercury::internal::object::tree::{Tree, TreeItem, TreeItemMode};
89
use mercury::internal::object::types::ObjectType;
910

1011
use crate::manager::store::TreeStore;
11-
use crate::util::GPath;
12+
1213

1314
fn collect_paths<P: AsRef<Path>>(path: P) -> Vec<PathBuf> {
1415
let mut paths = Vec::new();
1516

16-
if let Ok(entries) = fs::read_dir(path) {
17+
if let Ok(entries) = std::fs::read_dir(path) {
1718
for entry in entries.filter_map(Result::ok) {
1819
let path = entry.path();
1920
if path.is_dir() {
@@ -43,74 +44,177 @@ fn is_whiteout_inode<P: AsRef<Path>>(path: P)-> bool {
4344

4445
false
4546
}
47+
/// the output tree in hashmap , which hash value is not computed.
4648
#[allow(unused)]
47-
fn diff(lower: PathBuf, upper:PathBuf,dbpath:&str)->(HashMap<PathBuf,Tree>,Vec<Blob>){
49+
pub fn diff(lower: PathBuf, upper:PathBuf,dbpath:&str,monopath:PathBuf)->(HashMap<PathBuf,Tree>,Vec<Blob>){
4850
let db = sled::open(dbpath).unwrap();
4951
let upper_changes = collect_paths(&lower);
5052
let _root_len = lower.clone();
5153
let mut map = HashMap::<PathBuf,Tree>::new();
52-
let root_tree = db.get_bypath(GPath::from(String::from(lower.to_str().unwrap()))).unwrap();
54+
let root_tree = db.get_bypath(monopath.clone()).unwrap();// BUG: wrong path :"lower". the store in db is not real path .
55+
// dont forget get tree below
5356
map.insert(lower.clone(), root_tree);
5457
let mut blobs=Vec::<Blob>::new();
58+
5559
for node in upper_changes {
56-
let p = node.parent().unwrap().to_path_buf();
57-
let t = map.get_mut(&p).unwrap();
58-
59-
let mut is_new_file = true;
60-
// look up the older version to delete/change .
61-
let mut i =0;
62-
while i<t.tree_items.len() {
63-
let item = &mut t.tree_items[i];
64-
if item.name.eq(node.file_name().unwrap().to_string_lossy().as_ref()){
65-
is_new_file = false;
66-
//delete .
67-
if is_whiteout_inode(&node){
68-
t.tree_items.remove(i);
69-
}else{
70-
// changed
71-
// node is a changed ()blob.
72-
// just compute the NEW hash first.
73-
let content = std::fs::read(&node).unwrap();
74-
item.id= SHA1::from_type_and_data(ObjectType::Blob, &content);
75-
blobs.push(Blob { id: item.id, data: content });
60+
if node.is_dir(){
61+
let new_path = monopath.clone().join(node.strip_prefix(&lower).unwrap());
62+
let node_tree = db.get_bypath(new_path).unwrap();
63+
map.insert(node.clone(), node_tree);
64+
//db.get_bypath(path);
65+
//ap.insert(node.clone(), node_tree);
66+
}
67+
let p = node.parent().unwrap().to_path_buf();
68+
let t = map.get_mut(&p).unwrap();
69+
70+
let mut is_new_file = true;
71+
// look up the parent tree node to delete/change .
72+
let mut i =0;
73+
while i<t.tree_items.len() {
74+
let item = &mut t.tree_items[i];
75+
if item.name.eq(node.file_name().unwrap().to_string_lossy().as_ref()){
76+
is_new_file = false;
77+
//delete .
78+
if is_whiteout_inode(&node){
79+
t.tree_items.remove(i);
80+
}
81+
else if node.is_dir(){
82+
//pass
83+
}
84+
else{
85+
// changed
86+
// node is a changed ()blob.
87+
// just compute the NEW hash first.
88+
let content = std::fs::read(&node).unwrap();
89+
item.id= SHA1::from_type_and_data(ObjectType::Blob, &content);
90+
blobs.push(Blob { id: item.id, data: content });
91+
}
92+
break;
93+
}
94+
i+=1;
95+
}
96+
// if new file add item.
97+
let new_name =node.file_name().unwrap().to_string_lossy().as_ref().to_owned();
98+
if is_new_file{
99+
//is a fiel or a dictionary?
100+
if node.is_dir(){
101+
// is dictionary.
102+
t.tree_items.push(TreeItem {
103+
mode: TreeItemMode::Tree,
104+
id: SHA1::default(),
105+
name: new_name,
106+
});
107+
}else {
108+
//is a file.
109+
let content = std::fs::read(&node).unwrap();
110+
let hash = SHA1::from_type_and_data(ObjectType::Blob, &content);
111+
blobs.push(Blob { id: hash, data: content });
112+
t.tree_items.push(TreeItem {
113+
mode: TreeItemMode::Blob,
114+
id: hash,
115+
name: new_name,
116+
});
117+
}
118+
119+
}
120+
}
121+
(map,blobs)
122+
}
123+
124+
pub fn change(
125+
real_path:PathBuf,
126+
tree_path:PathBuf,
127+
trees:&mut Vec<Tree>,
128+
blobs:&mut Vec<Blob>,
129+
db:&sled::Db) -> Tree{
130+
let mut tree;
131+
let root_tree = db.get_bypath(tree_path.clone());
132+
if let Ok(root_tree) = root_tree{// exit dictionry
133+
println!("exit tree:{:?}",tree_path);
134+
tree = root_tree;
135+
}else {// there is a new dictionary.
136+
println!("new tree:{:?}",tree_path);
137+
tree = Tree{ id: SHA1::default(), tree_items: vec![] };
138+
}
139+
140+
let entries = std::fs::read_dir(real_path).unwrap();
141+
for entry in entries {
142+
let entry = entry.unwrap();
143+
let path = entry.path();
144+
let name = path.file_name().unwrap().to_string_lossy().into_owned().to_string();
145+
let mut new = true;
146+
let mut i =0 ;
147+
while i<tree.tree_items.len() {
148+
let item: &mut TreeItem = tree.tree_items.get_mut(i).unwrap();
149+
if item.name.eq(&name) {
150+
if is_whiteout_inode(&path){
151+
println!("change: delete {}",item.name);
152+
// delete..
153+
let _ = item;//drop
154+
tree.tree_items.remove(i);
155+
}
156+
else if path.is_dir() {
157+
let new_tree_path = tree_path.join(path.file_name().unwrap());
158+
let new_tree = change(path.clone(), new_tree_path, trees, blobs, db);
159+
160+
// change the hash value & push tree .
161+
item.id = new_tree.id;
162+
trees.push(new_tree);
163+
println!("change: changed tree {}",item.name);
164+
} else {
165+
println!("change: changed file {}",item.name);
166+
let content = std::fs::read(&path).unwrap();
167+
let hash = SHA1::from_type_and_data(ObjectType::Blob, &content);
168+
blobs.push(Blob { id: hash, data: content });
169+
item.id = hash;// change fiel hash .
76170
}
171+
new = false;
77172
break;
78173
}
79174
i+=1;
80175
}
81-
// if new file add item.
82-
let new_name =node.file_name().unwrap().to_string_lossy().as_ref().to_owned();
83-
if is_new_file{
84-
//is a fiel or a dictionary?
85-
if node.is_dir(){
86-
// is dictionary.
87-
t.tree_items.push(TreeItem {
88-
mode: TreeItemMode::Tree,
89-
id: SHA1::default(),
90-
name: new_name,
176+
if new{// a new file or dictionary
177+
if path.is_dir() {
178+
println!("change: new tree {:?}",name);
179+
let new_tree_path = tree_path.join(path.file_name().unwrap());
180+
let new_tree = change(path.clone(), new_tree_path, trees, blobs, db);
181+
182+
//add a new item for this tree. and push tree.
183+
tree.tree_items.push(TreeItem {
184+
mode: TreeItemMode::Tree,
185+
id: new_tree.id,
186+
name ,
91187
});
92-
}else {
93-
//is a file.
94-
let content = std::fs::read(&node).unwrap();
188+
trees.push(new_tree);
189+
} else {
190+
println!("change: new file {}",name);
191+
let content = std::fs::read(&path).unwrap();
95192
let hash = SHA1::from_type_and_data(ObjectType::Blob, &content);
96193
blobs.push(Blob { id: hash, data: content });
97-
t.tree_items.push(TreeItem {
98-
mode: TreeItemMode::Blob,
99-
id: hash,
100-
name: new_name,
194+
tree.tree_items.push(TreeItem {
195+
mode: TreeItemMode::Blob,
196+
id: hash,
197+
name ,
101198
});
102199
}
103-
104200
}
105-
}
106-
(map,blobs)
201+
202+
203+
204+
}
205+
tree.rehash();//Re compute the hash value .
206+
tree
207+
107208
}
209+
108210
#[cfg(test)]
109211
mod tests {
110-
use fs::File;
212+
213+
use std::fs::File;
111214

112215
use super::*;
113216

217+
114218
#[test]
115219
fn test_collect_paths_nested_directories() {
116220
let temp_dir = "/home/luxian/code/mega/scorpio/src";

scorpio/src/manager/fetch.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
use std::path::{Path, PathBuf};
32
use std::{collections::VecDeque, sync::Arc, time::Duration};
43
use mercury::hash::SHA1;
@@ -61,7 +60,7 @@ async fn worker_thread(
6160
send_tree :Sender<Tree>,
6261
) {
6362
let client = Client::new();
64-
let mut interval = time::interval(Duration::from_millis(50)); // 设定检查间隔时间
63+
let mut interval = time::interval(Duration::from_millis(50));
6564
let timeout_duration = Duration::from_millis(300);
6665
loop {
6766
let path = tokio::select! {
@@ -165,7 +164,6 @@ async fn worker_ro_thread(
165164
tokio::fs::create_dir_all(real_path).await.unwrap();
166165
} else {
167166

168-
// TODO: fetch file and save to target path. about file fetch api, refer to test_fetch_octet_stream() test func.
169167
let e = fetch_and_save_file(&item.id,real_path).await;
170168
println!("{:?}",e);
171169
}
@@ -175,6 +173,11 @@ async fn worker_ro_thread(
175173
}
176174

177175
}
176+
177+
///
178+
/// the tree info is store in k-v database.
179+
/// monorepo path -> Tree
180+
///
178181
async fn fetch_code(path:&GPath, save_path : impl AsRef<Path>){
179182

180183
let target_path: Arc<PathBuf> = Arc::new(save_path.as_ref().to_path_buf());
@@ -342,7 +345,6 @@ mod tests {
342345

343346
// Use the URL from environment variables or local test URL
344347
let url = "http://localhost:8000/api/v1/file/blob/d12d12579799a658b29808fe695abd919a033ac9";
345-
346348
// Send a GET request
347349
let response = client.get(url).send().await.unwrap();
348350

scorpio/src/manager/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use serde::{Deserialize, Serialize};
22
use std::fs;
33

4-
mod diff;
4+
pub mod diff;
5+
pub mod push;
56
pub mod fetch;
67
pub mod store;
78

0 commit comments

Comments
 (0)