mirror of
https://github.com/martinvonz/jj.git
synced 2025-01-17 17:55:29 +00:00
index: add neighbor commit_id lookup to IndexSegment
ReadonlyIndex implementation leverages the existing binary search function. MutableIndex one is basically the same as repo::IdIndex. Shortest prefix length could be calculated for each segment, but I think returning neighbors is better for testing.
This commit is contained in:
parent
e46cbfc9d0
commit
e71e9c99b2
1 changed files with 133 additions and 0 deletions
133
lib/src/index.rs
133
lib/src/index.rs
|
@ -672,6 +672,13 @@ trait IndexSegment {
|
|||
|
||||
fn segment_commit_id_to_pos(&self, commit_id: &CommitId) -> Option<IndexPosition>;
|
||||
|
||||
/// Suppose the given `commit_id` exists, returns the positions of the
|
||||
/// previous and next commit ids in lexicographical order.
|
||||
fn segment_commit_id_to_neighbor_positions(
|
||||
&self,
|
||||
commit_id: &CommitId,
|
||||
) -> (Option<IndexPosition>, Option<IndexPosition>);
|
||||
|
||||
fn segment_resolve_prefix(&self, prefix: &HexPrefix) -> PrefixResolution<CommitId>;
|
||||
|
||||
fn segment_generation_number(&self, local_pos: u32) -> u32;
|
||||
|
@ -1243,6 +1250,31 @@ impl IndexSegment for ReadonlyIndex {
|
|||
(&entry.commit_id() == commit_id).then(|| entry.pos())
|
||||
}
|
||||
|
||||
fn segment_commit_id_to_neighbor_positions(
|
||||
&self,
|
||||
commit_id: &CommitId,
|
||||
) -> (Option<IndexPosition>, Option<IndexPosition>) {
|
||||
if let Some(lookup_pos) = self.commit_id_byte_prefix_to_lookup_pos(commit_id) {
|
||||
let entry_commit_id = self.lookup_entry(lookup_pos).commit_id();
|
||||
let (prev_lookup_pos, next_lookup_pos) = match entry_commit_id.cmp(commit_id) {
|
||||
Ordering::Less => {
|
||||
assert_eq!(lookup_pos + 1, self.num_local_commits);
|
||||
(Some(lookup_pos), None)
|
||||
}
|
||||
Ordering::Equal => {
|
||||
let succ = ((lookup_pos + 1)..self.num_local_commits).next();
|
||||
(lookup_pos.checked_sub(1), succ)
|
||||
}
|
||||
Ordering::Greater => (lookup_pos.checked_sub(1), Some(lookup_pos)),
|
||||
};
|
||||
let prev_pos = prev_lookup_pos.map(|p| self.lookup_entry(p).pos());
|
||||
let next_pos = next_lookup_pos.map(|p| self.lookup_entry(p).pos());
|
||||
(prev_pos, next_pos)
|
||||
} else {
|
||||
(None, None)
|
||||
}
|
||||
}
|
||||
|
||||
fn segment_resolve_prefix(&self, prefix: &HexPrefix) -> PrefixResolution<CommitId> {
|
||||
let (bytes_prefix, min_bytes_prefix) = prefix.bytes_prefixes();
|
||||
match self.commit_id_byte_prefix_to_lookup_pos(&min_bytes_prefix) {
|
||||
|
@ -1332,6 +1364,23 @@ impl IndexSegment for MutableIndex {
|
|||
self.lookup.get(commit_id).cloned()
|
||||
}
|
||||
|
||||
fn segment_commit_id_to_neighbor_positions(
|
||||
&self,
|
||||
commit_id: &CommitId,
|
||||
) -> (Option<IndexPosition>, Option<IndexPosition>) {
|
||||
let prev_pos = self
|
||||
.lookup
|
||||
.range((Bound::Unbounded, Bound::Excluded(commit_id)))
|
||||
.next_back()
|
||||
.map(|(_, &pos)| pos);
|
||||
let next_pos = self
|
||||
.lookup
|
||||
.range((Bound::Excluded(commit_id), Bound::Unbounded))
|
||||
.next()
|
||||
.map(|(_, &pos)| pos);
|
||||
(prev_pos, next_pos)
|
||||
}
|
||||
|
||||
fn segment_resolve_prefix(&self, prefix: &HexPrefix) -> PrefixResolution<CommitId> {
|
||||
let (bytes_prefix, min_bytes_prefix) = prefix.bytes_prefixes();
|
||||
let mut potential_range = self
|
||||
|
@ -1955,6 +2004,90 @@ mod tests {
|
|||
PrefixResolution::AmbiguousMatch
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::redundant_clone)] // allow id_n.clone()
|
||||
fn neighbor_commit_ids() {
|
||||
let temp_dir = testutils::new_temp_dir();
|
||||
let mut new_change_id = change_id_generator();
|
||||
let mut index = MutableIndex::full(3);
|
||||
|
||||
// Create some commits with different various common prefixes.
|
||||
let id_0 = CommitId::from_hex("000001");
|
||||
let id_1 = CommitId::from_hex("009999");
|
||||
let id_2 = CommitId::from_hex("055488");
|
||||
index.add_commit_data(id_0.clone(), new_change_id(), &[]);
|
||||
index.add_commit_data(id_1.clone(), new_change_id(), &[]);
|
||||
index.add_commit_data(id_2.clone(), new_change_id(), &[]);
|
||||
|
||||
// Write the first three commits to one file and build the remainder on top.
|
||||
let initial_file = index.save_in(temp_dir.path().to_owned()).unwrap();
|
||||
index = MutableIndex::incremental(initial_file.clone());
|
||||
|
||||
let id_3 = CommitId::from_hex("055444");
|
||||
let id_4 = CommitId::from_hex("055555");
|
||||
let id_5 = CommitId::from_hex("033333");
|
||||
index.add_commit_data(id_3.clone(), new_change_id(), &[]);
|
||||
index.add_commit_data(id_4.clone(), new_change_id(), &[]);
|
||||
index.add_commit_data(id_5.clone(), new_change_id(), &[]);
|
||||
|
||||
// Local lookup in readonly index, commit_id exists.
|
||||
assert_eq!(
|
||||
initial_file.segment_commit_id_to_neighbor_positions(&id_0),
|
||||
(None, Some(IndexPosition(1))),
|
||||
);
|
||||
assert_eq!(
|
||||
initial_file.segment_commit_id_to_neighbor_positions(&id_1),
|
||||
(Some(IndexPosition(0)), Some(IndexPosition(2))),
|
||||
);
|
||||
assert_eq!(
|
||||
initial_file.segment_commit_id_to_neighbor_positions(&id_2),
|
||||
(Some(IndexPosition(1)), None),
|
||||
);
|
||||
|
||||
// Local lookup in readonly index, commit_id does not exist.
|
||||
assert_eq!(
|
||||
initial_file.segment_commit_id_to_neighbor_positions(&CommitId::from_hex("000000")),
|
||||
(None, Some(IndexPosition(0))),
|
||||
);
|
||||
assert_eq!(
|
||||
initial_file.segment_commit_id_to_neighbor_positions(&CommitId::from_hex("000002")),
|
||||
(Some(IndexPosition(0)), Some(IndexPosition(1))),
|
||||
);
|
||||
assert_eq!(
|
||||
initial_file.segment_commit_id_to_neighbor_positions(&CommitId::from_hex("ffffff")),
|
||||
(Some(IndexPosition(2)), None),
|
||||
);
|
||||
|
||||
// Local lookup in mutable index, commit_id exists. id_5 < id_3 < id_4
|
||||
assert_eq!(
|
||||
index.segment_commit_id_to_neighbor_positions(&id_5),
|
||||
(None, Some(IndexPosition(3))),
|
||||
);
|
||||
assert_eq!(
|
||||
index.segment_commit_id_to_neighbor_positions(&id_3),
|
||||
(Some(IndexPosition(5)), Some(IndexPosition(4))),
|
||||
);
|
||||
assert_eq!(
|
||||
index.segment_commit_id_to_neighbor_positions(&id_4),
|
||||
(Some(IndexPosition(3)), None),
|
||||
);
|
||||
|
||||
// Local lookup in mutable index, commit_id does not exist. id_5 < id_3 < id_4
|
||||
assert_eq!(
|
||||
index.segment_commit_id_to_neighbor_positions(&CommitId::from_hex("033332")),
|
||||
(None, Some(IndexPosition(5))),
|
||||
);
|
||||
assert_eq!(
|
||||
index.segment_commit_id_to_neighbor_positions(&CommitId::from_hex("033334")),
|
||||
(Some(IndexPosition(5)), Some(IndexPosition(3))),
|
||||
);
|
||||
assert_eq!(
|
||||
index.segment_commit_id_to_neighbor_positions(&CommitId::from_hex("ffffff")),
|
||||
(Some(IndexPosition(4)), None),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_ancestor() {
|
||||
let mut new_change_id = change_id_generator();
|
||||
|
|
Loading…
Reference in a new issue