forked from mirrors/jj
index: make segment-level lookup return neighbor commit ids instead of positions
Both readonly and mutable segments know the commit ids to return, and the caller only needs the ids. Since segment_commit_id(local_pos) scans the graph entries, doing that would increase the chance of cache miss.
This commit is contained in:
parent
0e7834feb9
commit
ee8d5e279a
4 changed files with 41 additions and 50 deletions
|
@ -41,12 +41,12 @@ pub(super) trait IndexSegment: Send + Sync {
|
||||||
|
|
||||||
fn segment_commit_id_to_pos(&self, commit_id: &CommitId) -> Option<IndexPosition>;
|
fn segment_commit_id_to_pos(&self, commit_id: &CommitId) -> Option<IndexPosition>;
|
||||||
|
|
||||||
/// Suppose the given `commit_id` exists, returns the positions of the
|
/// Suppose the given `commit_id` exists, returns the previous and next
|
||||||
/// previous and next commit ids in lexicographical order.
|
/// commit ids in lexicographical order.
|
||||||
fn segment_commit_id_to_neighbor_positions(
|
fn segment_resolve_neighbor_commit_ids(
|
||||||
&self,
|
&self,
|
||||||
commit_id: &CommitId,
|
commit_id: &CommitId,
|
||||||
) -> (Option<IndexPosition>, Option<IndexPosition>);
|
) -> (Option<CommitId>, Option<CommitId>);
|
||||||
|
|
||||||
fn segment_resolve_prefix(&self, prefix: &HexPrefix) -> PrefixResolution<CommitId>;
|
fn segment_resolve_prefix(&self, prefix: &HexPrefix) -> PrefixResolution<CommitId>;
|
||||||
|
|
||||||
|
@ -168,16 +168,7 @@ impl<'a> CompositeIndex<'a> {
|
||||||
commit_id: &CommitId,
|
commit_id: &CommitId,
|
||||||
) -> (Option<CommitId>, Option<CommitId>) {
|
) -> (Option<CommitId>, Option<CommitId>) {
|
||||||
self.ancestor_index_segments()
|
self.ancestor_index_segments()
|
||||||
.map(|segment| {
|
.map(|segment| segment.segment_resolve_neighbor_commit_ids(commit_id))
|
||||||
let num_parent_commits = segment.segment_num_parent_commits();
|
|
||||||
let to_local_pos = |pos: IndexPosition| pos.0 - num_parent_commits;
|
|
||||||
let (prev_pos, next_pos) =
|
|
||||||
segment.segment_commit_id_to_neighbor_positions(commit_id);
|
|
||||||
(
|
|
||||||
prev_pos.map(|p| segment.segment_commit_id(to_local_pos(p))),
|
|
||||||
next_pos.map(|p| segment.segment_commit_id(to_local_pos(p))),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.reduce(|(acc_prev_id, acc_next_id), (prev_id, next_id)| {
|
.reduce(|(acc_prev_id, acc_next_id), (prev_id, next_id)| {
|
||||||
(
|
(
|
||||||
acc_prev_id.into_iter().chain(prev_id).max(),
|
acc_prev_id.into_iter().chain(prev_id).max(),
|
||||||
|
|
|
@ -423,58 +423,58 @@ mod tests {
|
||||||
|
|
||||||
// Local lookup in readonly index, commit_id exists.
|
// Local lookup in readonly index, commit_id exists.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
initial_file.segment_commit_id_to_neighbor_positions(&id_0),
|
initial_file.segment_resolve_neighbor_commit_ids(&id_0),
|
||||||
(None, Some(IndexPosition(1))),
|
(None, Some(id_1.clone())),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
initial_file.segment_commit_id_to_neighbor_positions(&id_1),
|
initial_file.segment_resolve_neighbor_commit_ids(&id_1),
|
||||||
(Some(IndexPosition(0)), Some(IndexPosition(2))),
|
(Some(id_0.clone()), Some(id_2.clone())),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
initial_file.segment_commit_id_to_neighbor_positions(&id_2),
|
initial_file.segment_resolve_neighbor_commit_ids(&id_2),
|
||||||
(Some(IndexPosition(1)), None),
|
(Some(id_1.clone()), None),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Local lookup in readonly index, commit_id does not exist.
|
// Local lookup in readonly index, commit_id does not exist.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
initial_file.segment_commit_id_to_neighbor_positions(&CommitId::from_hex("000000")),
|
initial_file.segment_resolve_neighbor_commit_ids(&CommitId::from_hex("000000")),
|
||||||
(None, Some(IndexPosition(0))),
|
(None, Some(id_0.clone())),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
initial_file.segment_commit_id_to_neighbor_positions(&CommitId::from_hex("000002")),
|
initial_file.segment_resolve_neighbor_commit_ids(&CommitId::from_hex("000002")),
|
||||||
(Some(IndexPosition(0)), Some(IndexPosition(1))),
|
(Some(id_0.clone()), Some(id_1.clone())),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
initial_file.segment_commit_id_to_neighbor_positions(&CommitId::from_hex("ffffff")),
|
initial_file.segment_resolve_neighbor_commit_ids(&CommitId::from_hex("ffffff")),
|
||||||
(Some(IndexPosition(2)), None),
|
(Some(id_2.clone()), None),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Local lookup in mutable index, commit_id exists. id_5 < id_3 < id_4
|
// Local lookup in mutable index, commit_id exists. id_5 < id_3 < id_4
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mutable_segment.segment_commit_id_to_neighbor_positions(&id_5),
|
mutable_segment.segment_resolve_neighbor_commit_ids(&id_5),
|
||||||
(None, Some(IndexPosition(3))),
|
(None, Some(id_3.clone())),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mutable_segment.segment_commit_id_to_neighbor_positions(&id_3),
|
mutable_segment.segment_resolve_neighbor_commit_ids(&id_3),
|
||||||
(Some(IndexPosition(5)), Some(IndexPosition(4))),
|
(Some(id_5.clone()), Some(id_4.clone())),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mutable_segment.segment_commit_id_to_neighbor_positions(&id_4),
|
mutable_segment.segment_resolve_neighbor_commit_ids(&id_4),
|
||||||
(Some(IndexPosition(3)), None),
|
(Some(id_3.clone()), None),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Local lookup in mutable index, commit_id does not exist. id_5 < id_3 < id_4
|
// Local lookup in mutable index, commit_id does not exist. id_5 < id_3 < id_4
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mutable_segment.segment_commit_id_to_neighbor_positions(&CommitId::from_hex("033332")),
|
mutable_segment.segment_resolve_neighbor_commit_ids(&CommitId::from_hex("033332")),
|
||||||
(None, Some(IndexPosition(5))),
|
(None, Some(id_5.clone())),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mutable_segment.segment_commit_id_to_neighbor_positions(&CommitId::from_hex("033334")),
|
mutable_segment.segment_resolve_neighbor_commit_ids(&CommitId::from_hex("033334")),
|
||||||
(Some(IndexPosition(5)), Some(IndexPosition(3))),
|
(Some(id_5.clone()), Some(id_3.clone())),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mutable_segment.segment_commit_id_to_neighbor_positions(&CommitId::from_hex("ffffff")),
|
mutable_segment.segment_resolve_neighbor_commit_ids(&CommitId::from_hex("ffffff")),
|
||||||
(Some(IndexPosition(4)), None),
|
(Some(id_4.clone()), None),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Global lookup, commit_id exists. id_0 < id_1 < id_5 < id_3 < id_2 < id_4
|
// Global lookup, commit_id exists. id_0 < id_1 < id_5 < id_3 < id_2 < id_4
|
||||||
|
|
|
@ -319,21 +319,21 @@ impl IndexSegment for MutableIndexSegment {
|
||||||
self.lookup.get(commit_id).cloned()
|
self.lookup.get(commit_id).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn segment_commit_id_to_neighbor_positions(
|
fn segment_resolve_neighbor_commit_ids(
|
||||||
&self,
|
&self,
|
||||||
commit_id: &CommitId,
|
commit_id: &CommitId,
|
||||||
) -> (Option<IndexPosition>, Option<IndexPosition>) {
|
) -> (Option<CommitId>, Option<CommitId>) {
|
||||||
let prev_pos = self
|
let prev_id = self
|
||||||
.lookup
|
.lookup
|
||||||
.range((Bound::Unbounded, Bound::Excluded(commit_id)))
|
.range((Bound::Unbounded, Bound::Excluded(commit_id)))
|
||||||
.next_back()
|
.next_back()
|
||||||
.map(|(_, &pos)| pos);
|
.map(|(id, _)| id.clone());
|
||||||
let next_pos = self
|
let next_id = self
|
||||||
.lookup
|
.lookup
|
||||||
.range((Bound::Excluded(commit_id), Bound::Unbounded))
|
.range((Bound::Excluded(commit_id), Bound::Unbounded))
|
||||||
.next()
|
.next()
|
||||||
.map(|(_, &pos)| pos);
|
.map(|(id, _)| id.clone());
|
||||||
(prev_pos, next_pos)
|
(prev_id, next_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn segment_resolve_prefix(&self, prefix: &HexPrefix) -> PrefixResolution<CommitId> {
|
fn segment_resolve_prefix(&self, prefix: &HexPrefix) -> PrefixResolution<CommitId> {
|
||||||
|
|
|
@ -385,10 +385,10 @@ impl IndexSegment for ReadonlyIndexSegment {
|
||||||
(&entry.commit_id() == commit_id).then(|| entry.pos())
|
(&entry.commit_id() == commit_id).then(|| entry.pos())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn segment_commit_id_to_neighbor_positions(
|
fn segment_resolve_neighbor_commit_ids(
|
||||||
&self,
|
&self,
|
||||||
commit_id: &CommitId,
|
commit_id: &CommitId,
|
||||||
) -> (Option<IndexPosition>, Option<IndexPosition>) {
|
) -> (Option<CommitId>, Option<CommitId>) {
|
||||||
if let Some(lookup_pos) = self.commit_id_byte_prefix_to_lookup_pos(commit_id) {
|
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 entry_commit_id = self.lookup_entry(lookup_pos).commit_id();
|
||||||
let (prev_lookup_pos, next_lookup_pos) = match entry_commit_id.cmp(commit_id) {
|
let (prev_lookup_pos, next_lookup_pos) = match entry_commit_id.cmp(commit_id) {
|
||||||
|
@ -402,9 +402,9 @@ impl IndexSegment for ReadonlyIndexSegment {
|
||||||
}
|
}
|
||||||
Ordering::Greater => (lookup_pos.checked_sub(1), Some(lookup_pos)),
|
Ordering::Greater => (lookup_pos.checked_sub(1), Some(lookup_pos)),
|
||||||
};
|
};
|
||||||
let prev_pos = prev_lookup_pos.map(|p| self.lookup_entry(p).pos());
|
let prev_id = prev_lookup_pos.map(|p| self.lookup_entry(p).commit_id());
|
||||||
let next_pos = next_lookup_pos.map(|p| self.lookup_entry(p).pos());
|
let next_id = next_lookup_pos.map(|p| self.lookup_entry(p).commit_id());
|
||||||
(prev_pos, next_pos)
|
(prev_id, next_id)
|
||||||
} else {
|
} else {
|
||||||
(None, None)
|
(None, None)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue