Skip to content

Commit d63176f

Browse files
committed
First basic validation of all packs within an odb store (#287)
1 parent 6c06659 commit d63176f

File tree

3 files changed

+106
-10
lines changed

3 files changed

+106
-10
lines changed

git-odb/src/store_impls/dynamic/types.rs

+3
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ pub(crate) enum OnDiskFileState<T: Clone> {
147147
}
148148

149149
impl<T: Clone> OnDiskFile<T> {
150+
pub fn path(&self) -> &Path {
151+
&*self.path
152+
}
150153
/// Return true if we hold a memory map of the file already.
151154
pub fn is_loaded(&self) -> bool {
152155
matches!(self.state, OnDiskFileState::Loaded(_) | OnDiskFileState::Garbage(_))

git-odb/src/store_impls/dynamic/verify.rs

+102-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crate::pack;
2+
use crate::types::IndexAndPacks;
23
use git_features::progress::Progress;
3-
use std::sync::atomic::AtomicBool;
4+
use std::ops::Deref;
5+
use std::sync::atomic::{AtomicBool, Ordering};
46

57
#[allow(missing_docs, unused)]
68

@@ -13,9 +15,19 @@ pub mod integrity {
1315
#[allow(missing_docs)]
1416
pub enum Error {
1517
#[error(transparent)]
16-
MultiIndex(#[from] pack::index::traverse::Error<pack::multi_index::verify::integrity::Error>),
18+
MultiIndexIntegrity(#[from] pack::index::traverse::Error<pack::multi_index::verify::integrity::Error>),
1719
#[error(transparent)]
18-
Index(#[from] pack::index::traverse::Error<pack::index::verify::integrity::Error>),
20+
IndexIntegrity(#[from] pack::index::traverse::Error<pack::index::verify::integrity::Error>),
21+
#[error(transparent)]
22+
IndexOpen(#[from] pack::index::init::Error),
23+
#[error(transparent)]
24+
MultiIndexOpen(#[from] pack::multi_index::init::Error),
25+
#[error(transparent)]
26+
PackOpen(#[from] pack::data::init::Error),
27+
#[error(transparent)]
28+
InitializeODB(#[from] crate::store::load_index::Error),
29+
#[error("The disk on state changed while performing the operation, and we observed the change.")]
30+
NeedsRetryDueToChangeOnDisk,
1931
}
2032

2133
/// Returned by [`Store::verify_integrity()`][crate::Store::verify_integrity()].
@@ -34,15 +46,97 @@ impl super::Store {
3446
/// This does, however, include all alternates.
3547
pub fn verify_integrity<C, P, F>(
3648
&self,
37-
_progress: P,
38-
_should_interrupt: &AtomicBool,
39-
_options: pack::index::verify::integrity::Options<F>,
40-
) -> Result<integrity::Outcome<P>, pack::index::traverse::Error<integrity::Error>>
49+
mut progress: P,
50+
should_interrupt: &AtomicBool,
51+
options: pack::index::verify::integrity::Options<F>,
52+
) -> Result<integrity::Outcome<P>, integrity::Error>
4153
where
4254
P: Progress,
4355
C: pack::cache::DecodeEntry,
4456
F: Fn() -> C + Send + Clone,
4557
{
46-
todo!()
58+
let mut index = self.index.load();
59+
if !index.is_initialized() {
60+
self.consolidate_with_disk_state(false)?;
61+
index = self.index.load();
62+
assert!(
63+
index.is_initialized(),
64+
"BUG: after consolidating successfully, we have an initialized index"
65+
)
66+
}
67+
68+
progress.init(
69+
Some(index.slot_indices.len()),
70+
git_features::progress::count("pack indices"),
71+
);
72+
let mut statistics = Vec::new();
73+
for slot_index in &index.slot_indices {
74+
let slot = &self.files[*slot_index];
75+
if slot.generation.load(Ordering::SeqCst) != index.generation {
76+
return Err(integrity::Error::NeedsRetryDueToChangeOnDisk);
77+
}
78+
let files = slot.files.load();
79+
let files = Option::as_ref(&files).ok_or(integrity::Error::NeedsRetryDueToChangeOnDisk)?;
80+
81+
match files {
82+
IndexAndPacks::Index(bundle) => {
83+
let index;
84+
let index = match bundle.index.loaded() {
85+
Some(index) => index.deref(),
86+
None => {
87+
index = pack::index::File::at(bundle.index.path(), self.object_hash)?;
88+
&index
89+
}
90+
};
91+
let pack;
92+
let data = match bundle.data.loaded() {
93+
Some(pack) => pack.deref(),
94+
None => {
95+
pack = pack::data::File::at(bundle.data.path(), self.object_hash)?;
96+
&pack
97+
}
98+
};
99+
let outcome = index.verify_integrity(
100+
Some(pack::index::verify::PackContext {
101+
data,
102+
options: options.clone(),
103+
}),
104+
progress.add_child("Checking integrity"),
105+
should_interrupt,
106+
)?;
107+
statistics.push(
108+
outcome
109+
.pack_traverse_statistics
110+
.expect("pack provided so there are stats"),
111+
);
112+
}
113+
IndexAndPacks::MultiIndex(bundle) => {
114+
let index;
115+
let index = match bundle.multi_index.loaded() {
116+
Some(index) => index.deref(),
117+
None => {
118+
index = pack::multi_index::File::at(bundle.multi_index.path())?;
119+
&index
120+
}
121+
};
122+
let outcome = index.verify_integrity(
123+
progress.add_child("Checking integrity"),
124+
should_interrupt,
125+
options.clone(),
126+
)?;
127+
statistics.extend(outcome.pack_traverse_statistics);
128+
}
129+
}
130+
progress.inc();
131+
}
132+
133+
for _loose_db in &*index.loose_dbs {
134+
// TODO: impl verify integrity for loose object databases
135+
}
136+
137+
Ok(integrity::Outcome {
138+
pack_traverse_statistics: statistics,
139+
progress,
140+
})
47141
}
48142
}

git-odb/tests/odb/store/dynamic.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -574,8 +574,7 @@ mod verify {
574574
use std::sync::atomic::AtomicBool;
575575

576576
#[test]
577-
#[ignore]
578-
fn verify_integrity() {
577+
fn integrity() {
579578
let handle = db();
580579
let outcome = handle
581580
.store_ref()

0 commit comments

Comments
 (0)