Skip to content

Commit e1ed755

Browse files
committed
skip copy paste if the content is same
Signed-off-by: kerthcet <kerthcet@gmail.com>
1 parent 507fe14 commit e1ed755

1 file changed

Lines changed: 72 additions & 2 deletions

File tree

sandd/src/snapshot/manager.rs

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,32 @@ impl SnapshotManager {
160160

161161
match entry.entry_type {
162162
EntryType::Blob => {
163-
// Restore file from blob object
164-
self.store.copy_file(&entry.hash, &entry_path).await?;
163+
// Check if file already exists with same content
164+
let should_copy = if entry_path.exists() {
165+
// Compare metadata first (fast check)
166+
if let Ok(metadata) = fs::metadata(&entry_path).await {
167+
if metadata.len() == entry.size
168+
&& metadata.modified().ok() == Some(entry.modified) {
169+
// Size and mtime match - likely unchanged, skip copy
170+
false
171+
} else {
172+
// Metadata differs - need to verify with hash
173+
let file_hash = self.store.put_file(&entry_path).await?;
174+
file_hash != entry.hash
175+
}
176+
} else {
177+
true
178+
}
179+
} else {
180+
true
181+
};
182+
183+
if should_copy {
184+
// Restore file from blob object
185+
self.store.copy_file(&entry.hash, &entry_path).await?;
186+
}
187+
188+
// Always update metadata (cheap operation)
165189
set_mode(&entry_path, entry.mode)?;
166190
set_mtime(&entry_path, entry.modified)?;
167191
}
@@ -575,6 +599,52 @@ mod tests {
575599
);
576600
}
577601

602+
#[tokio::test]
603+
async fn test_restore_skip_unchanged() {
604+
use std::time::Duration;
605+
606+
let temp_dir = TempDir::new().unwrap();
607+
let store_dir = temp_dir.path().join("store");
608+
let workspace = temp_dir.path().join("workspace");
609+
let restore_dir = temp_dir.path().join("restored");
610+
611+
fs::create_dir_all(&workspace).await.unwrap();
612+
fs::write(workspace.join("file.txt"), "content").await.unwrap();
613+
614+
let manager = SnapshotManager::new(store_dir.clone()).unwrap();
615+
let snapshot_id = manager
616+
.create_snapshot(&workspace, Some("Test".to_string()), None)
617+
.await
618+
.unwrap();
619+
620+
// First restore
621+
manager.restore_snapshot(&snapshot_id, &restore_dir).await.unwrap();
622+
623+
// Get file timestamp after first restore
624+
let first_timestamp = std::fs::metadata(restore_dir.join("file.txt"))
625+
.unwrap()
626+
.modified()
627+
.unwrap();
628+
629+
// Wait to ensure timestamp would differ if file was rewritten
630+
tokio::time::sleep(Duration::from_millis(100)).await;
631+
632+
// Second restore to same location
633+
manager.restore_snapshot(&snapshot_id, &restore_dir).await.unwrap();
634+
635+
// File should NOT be rewritten (timestamp unchanged)
636+
let second_timestamp = std::fs::metadata(restore_dir.join("file.txt"))
637+
.unwrap()
638+
.modified()
639+
.unwrap();
640+
641+
// Timestamps should match (file was not recopied)
642+
assert_eq!(
643+
first_timestamp, second_timestamp,
644+
"File should not be recopied if unchanged"
645+
);
646+
}
647+
578648
#[tokio::test]
579649
#[cfg(unix)]
580650
async fn test_symlinks() {

0 commit comments

Comments
 (0)