Skip to content

Commit da2d7e9

Browse files
markbtfacebook-github-bot
authored andcommitted
blame: make replacement parent lookup fallible
Summary: Blame derivation should arrange for all interesting commits to be available in the map of replacement parents. However, it seems this might not always be the case. Make the lookup fallible so that we fail derivation (rather than crashing) and allow us to find the cause more easily. Reviewed By: mzr Differential Revision: D75864222 fbshipit-source-id: a09a2749f5a24403c4b1861f1e4cb0de94c8d337
1 parent 10f9d86 commit da2d7e9

4 files changed

Lines changed: 109 additions & 68 deletions

File tree

eden/mononoke/mononoke_types/BUCK

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ rust_library(
3737
"fbsource//third-party/rust:derivative",
3838
"fbsource//third-party/rust:either",
3939
"fbsource//third-party/rust:faster-hex",
40+
"fbsource//third-party/rust:fn-error-context",
4041
"fbsource//third-party/rust:futures",
4142
"fbsource//third-party/rust:gix-date",
4243
"fbsource//third-party/rust:gix-hash",

eden/mononoke/mononoke_types/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ derived_data_type_if = { version = "0.1.0", path = "../derived_data/if" }
3030
either = "1.5"
3131
faster-hex = "0.6.1"
3232
fbthrift = { version = "0.0.1+unstable", git = "https://github.com/facebook/fbthrift.git", branch = "main" }
33+
fn-error-context = "0.2"
3334
futures = { version = "0.3.30", features = ["async-await", "compat"] }
3435
futures_watchdog = { version = "0.1.0", path = "../common/futures_watchdog" }
3536
gix-date = "0.10.1"

eden/mononoke/mononoke_types/src/blame_v2.rs

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use blobstore::Loadable;
2626
use blobstore::LoadableError;
2727
use context::CoreContext;
2828
use fbthrift::compact_protocol;
29+
use fn_error_context::context;
2930
use futures_watchdog::WatchdogExt;
3031
use sorted_vector_map::SortedVectorMap;
3132
use thiserror::Error;
@@ -321,19 +322,25 @@ pub enum BlameParentId<Id> {
321322
impl<Id: Eq + Hash> BlameParentId<Id> {
322323
/// Convert this blame parent into an indexed blame parent, using the provided
323324
/// mapping from changeset id to index.
324-
pub fn indexed<IdKey: Eq + Hash>(
325+
pub fn indexed<IdKey: Eq + Hash + std::fmt::Debug>(
325326
&self,
326327
replacement_parent_indexes: &HashMap<IdKey, u32>,
327-
) -> BlameParentIndex
328+
) -> Result<BlameParentIndex>
328329
where
329330
Id: Borrow<IdKey>,
330331
{
331332
match self {
332333
BlameParentId::ChangesetParent(index) => {
333-
BlameParentIndex::ChangesetParent(*index as u32)
334+
Ok(BlameParentIndex::ChangesetParent(*index as u32))
334335
}
335336
BlameParentId::ReplacementParent(csid) => {
336-
BlameParentIndex::ReplacementParent(replacement_parent_indexes[csid.borrow()])
337+
let csid = csid.borrow();
338+
Ok(BlameParentIndex::ReplacementParent(
339+
replacement_parent_indexes
340+
.get(csid)
341+
.copied()
342+
.ok_or_else(|| anyhow!("No replacement parent index for {csid:?}"))?,
343+
))
337344
}
338345
}
339346
}
@@ -626,6 +633,7 @@ impl BlameData {
626633
}
627634

628635
/// Merge other blame data into this blame for a merge changeset.
636+
#[context("Failed to merge blame data for {merge_csid}")]
629637
fn merge(&mut self, merge_csid: ChangesetId, others: &[BlameData]) -> Result<()> {
630638
// Remove the csid index for the merge changeset; we will re-assign it
631639
// once all other blames have been merged in.
@@ -708,7 +716,14 @@ impl BlameData {
708716
for blame_line in self.merge_lines(merge_csid, others) {
709717
let path_index = path_indexes[blame_line.path];
710718
let csid_index = csid_indexes[blame_line.changeset_id];
711-
let parent = blame_line.parent(&path_indexes, &replacement_parent_indexes);
719+
let parent = blame_line
720+
.parent(&path_indexes, &replacement_parent_indexes)
721+
.with_context(|| {
722+
format!(
723+
"Failed to get parent for blame range at offset {}",
724+
blame_line.offset
725+
)
726+
})?;
712727
match merged_ranges.last_mut() {
713728
None if blame_line.offset != 0 => {
714729
return Err(anyhow!(
@@ -962,6 +977,7 @@ impl BlameData {
962977
Ok(result)
963978
}
964979

980+
#[context("Failed to apply mutable change to blame")]
965981
fn apply_mutable_change(&mut self, original_blame: &Self, mutated_blame: &Self) -> Result<()> {
966982
// Sort order of changesets is not guaranteed to be the same, which rules out Iterator::eq
967983
let my_csids: HashSet<_> = self.csids.values().collect();
@@ -1116,10 +1132,18 @@ impl BlameData {
11161132
format!("Unknown path {} - should not be possible", line.path)
11171133
})?;
11181134
let offset = offset as u32;
1119-
let parent = line.parent.map(|parent| {
1120-
parent
1121-
.to_range_parent_index(&path_to_index, &replacement_parent_to_index)
1122-
});
1135+
let parent = line
1136+
.parent
1137+
.map(|parent| {
1138+
parent.to_range_parent_index(
1139+
&path_to_index,
1140+
&replacement_parent_to_index,
1141+
)
1142+
})
1143+
.transpose()
1144+
.with_context(|| {
1145+
format!("Failed to get parent index for range at offset {offset}")
1146+
})?;
11231147

11241148
let range = BlameRangeIndex {
11251149
offset,
@@ -1391,13 +1415,13 @@ impl<'a> BlameLineParent<'a> {
13911415
&self,
13921416
path_indexes: &HashMap<NonRootMPath, u32>,
13931417
replacement_parent_indexes: &HashMap<&ChangesetId, u32>,
1394-
) -> BlameRangeParentIndex {
1395-
BlameRangeParentIndex {
1396-
parent_index: self.parent.indexed(replacement_parent_indexes),
1418+
) -> Result<BlameRangeParentIndex> {
1419+
Ok(BlameRangeParentIndex {
1420+
parent_index: self.parent.indexed(replacement_parent_indexes)?,
13971421
offset: self.offset,
13981422
length: self.length,
13991423
renamed_from_path_index: self.renamed_from_path.map(|p| path_indexes[p]),
1400-
}
1424+
})
14011425
}
14021426

14031427
/// Returns true if this parent matches the parent of another range.
@@ -1464,15 +1488,25 @@ impl<'a> BlameLine<'a> {
14641488
&self,
14651489
path_indexes: &HashMap<NonRootMPath, u32>,
14661490
replacement_parent_indexes: &HashMap<&ChangesetId, u32>,
1467-
) -> Option<BlameRangeParentIndex> {
1491+
) -> Result<Option<BlameRangeParentIndex>> {
14681492
self.parent
14691493
.as_ref()
1470-
.map(|parent_range| BlameRangeParentIndex {
1471-
parent_index: parent_range.parent.indexed(replacement_parent_indexes),
1472-
offset: parent_range.offset,
1473-
length: parent_range.length,
1474-
renamed_from_path_index: parent_range.renamed_from_path.map(|p| path_indexes[p]),
1494+
.map(|parent_range| {
1495+
Ok(BlameRangeParentIndex {
1496+
parent_index: parent_range.parent.indexed(replacement_parent_indexes)?,
1497+
offset: parent_range.offset,
1498+
length: parent_range.length,
1499+
renamed_from_path_index: parent_range
1500+
.renamed_from_path
1501+
.map(|p| {
1502+
path_indexes.get(p).copied().ok_or_else(|| {
1503+
anyhow!("Failed to get path index for renamed-from path {p}")
1504+
})
1505+
})
1506+
.transpose()?,
1507+
})
14751508
})
1509+
.transpose()
14761510
}
14771511
}
14781512

eden/mononoke/scs/scs_methods/src/methods/commit_path.rs

Lines changed: 54 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -378,66 +378,71 @@ impl SourceControlServiceImpl {
378378
.map_err(|e| MononokeError::InvalidRequest(e.to_string()))?;
379379
let lines = stream::iter(lines.enumerate())
380380
.yield_periodically()
381-
.map(|(line, blame_line)| -> Result<_, thrift::RequestError> {
382-
let commit_id_index =
383-
commit_id_indexes
381+
.map(
382+
|(line, blame_line)| -> Result<_, scs_errors::ServiceError> {
383+
let commit_id_index = commit_id_indexes
384384
.get(blame_line.changeset_id)
385385
.ok_or_else(|| {
386386
scs_errors::commit_not_found(format!(
387387
"failed to resolve commit: {}",
388388
blame_line.changeset_id
389389
))
390390
})?;
391-
let (author, date, message, title) =
392-
info.get(blame_line.changeset_id).ok_or_else(|| {
393-
scs_errors::commit_not_found(format!(
394-
"failed to resolve commit: {}",
395-
blame_line.changeset_id
396-
))
397-
})?;
398-
let mut thrift_blame_line = thrift::BlameCompactLine {
399-
line: (line + 1) as i32,
400-
contents: None,
401-
commit_id_index: *commit_id_index as i32,
402-
path_index: paths.insert(&blame_line.path.to_string()) as i32,
403-
author_index: authors.insert(author) as i32,
404-
date_index: dates.insert(Cow::Borrowed(date)) as i32,
405-
origin_line: (blame_line.origin_offset + 1) as i32,
406-
title_index: None,
407-
message_index: None,
408-
..Default::default()
409-
};
410-
if option_include_contents {
411-
if let Some(content_line) = content_iter.next() {
412-
thrift_blame_line.contents =
413-
Some(String::from_utf8_lossy(content_line).into_owned());
391+
let (author, date, message, title) =
392+
info.get(blame_line.changeset_id).ok_or_else(|| {
393+
scs_errors::commit_not_found(format!(
394+
"failed to resolve commit: {}",
395+
blame_line.changeset_id
396+
))
397+
})?;
398+
let mut thrift_blame_line = thrift::BlameCompactLine {
399+
line: (line + 1) as i32,
400+
contents: None,
401+
commit_id_index: *commit_id_index as i32,
402+
path_index: paths.insert(&blame_line.path.to_string()) as i32,
403+
author_index: authors.insert(author) as i32,
404+
date_index: dates.insert(Cow::Borrowed(date)) as i32,
405+
origin_line: (blame_line.origin_offset + 1) as i32,
406+
title_index: None,
407+
message_index: None,
408+
..Default::default()
409+
};
410+
if option_include_contents {
411+
if let Some(content_line) = content_iter.next() {
412+
thrift_blame_line.contents =
413+
Some(String::from_utf8_lossy(content_line).into_owned());
414+
}
414415
}
415-
}
416-
if option_include_title {
417-
thrift_blame_line.title_index = Some(titles.insert(title) as i32);
418-
}
419-
if option_include_message {
420-
thrift_blame_line.message_index = Some(messages.insert(message) as i32);
421-
}
422-
if option_include_parent {
423-
if let Some(parent) = &blame_line.parent {
424-
match parent.parent.indexed(&replacement_parents) {
425-
BlameParentIndex::ChangesetParent(index) => {
426-
thrift_blame_line.parent_index = Some(index as i32);
427-
}
428-
BlameParentIndex::ReplacementParent(index) => {
429-
thrift_blame_line.replacement_parent_index = Some(index as i32);
416+
if option_include_title {
417+
thrift_blame_line.title_index = Some(titles.insert(title) as i32);
418+
}
419+
if option_include_message {
420+
thrift_blame_line.message_index = Some(messages.insert(message) as i32);
421+
}
422+
if option_include_parent {
423+
if let Some(parent) = &blame_line.parent {
424+
match parent
425+
.parent
426+
.indexed(&replacement_parents)
427+
.map_err(scs_errors::internal_error)?
428+
{
429+
BlameParentIndex::ChangesetParent(index) => {
430+
thrift_blame_line.parent_index = Some(index as i32);
431+
}
432+
BlameParentIndex::ReplacementParent(index) => {
433+
thrift_blame_line.replacement_parent_index = Some(index as i32);
434+
}
430435
}
436+
thrift_blame_line.parent_start_line = Some((parent.offset + 1) as i32);
437+
thrift_blame_line.parent_range_length = Some(parent.length as i32);
438+
thrift_blame_line.parent_path_index = parent
439+
.renamed_from_path
440+
.map(|path| paths.insert(&path.to_string()) as i32);
431441
}
432-
thrift_blame_line.parent_start_line = Some((parent.offset + 1) as i32);
433-
thrift_blame_line.parent_range_length = Some(parent.length as i32);
434-
thrift_blame_line.parent_path_index = parent
435-
.renamed_from_path
436-
.map(|path| paths.insert(&path.to_string()) as i32);
437442
}
438-
}
439-
Ok(thrift_blame_line)
440-
})
443+
Ok(thrift_blame_line)
444+
},
445+
)
441446
.try_collect::<Vec<_>>()
442447
.await?;
443448

0 commit comments

Comments
 (0)