mirror of
https://github.com/martinvonz/jj.git
synced 2024-12-04 05:28:02 +00:00
operation: iterate ancestors incrementally with timestamp-based heuristic
Suppose the operation log is mostly linear, this means "jj op log" iterator won't look ahead more than one entry. Another idea is to either add a "generation" number to operation data, or build index of operations. Since we'll eventually add GC command, I don't think op index would be required. I think readdir() is good enough to resolve hex prefix against ~10k entries. For now, walk_ancestors() is a free function. If we add Repo-like abstraction over OpStore + OpHeadsStore, this function will probably be migrated there.
This commit is contained in:
parent
5cecdb54ce
commit
7a6f832e14
2 changed files with 34 additions and 8 deletions
|
@ -19,8 +19,8 @@ use std::hash::{Hash, Hasher};
|
|||
use std::sync::Arc;
|
||||
|
||||
use crate::backend::CommitId;
|
||||
use crate::op_store;
|
||||
use crate::op_store::{OpStore, OperationId, ViewId};
|
||||
use crate::{dag_walk, op_store};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Operation {
|
||||
|
@ -165,3 +165,34 @@ impl View {
|
|||
&self.data.head_ids
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
struct OperationByEndTime(Operation);
|
||||
|
||||
impl Ord for OperationByEndTime {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
let self_end_time = &self.0.store_operation().metadata.end_time;
|
||||
let other_end_time = &other.0.store_operation().metadata.end_time;
|
||||
self_end_time
|
||||
.cmp(other_end_time)
|
||||
.then_with(|| self.0.cmp(&other.0)) // to comply with Eq
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for OperationByEndTime {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
/// Walks `head_op` and its ancestors in reverse topological order.
|
||||
pub fn walk_ancestors(head_op: &Operation) -> impl Iterator<Item = Operation> {
|
||||
// Lazily load operations based on timestamp-based heuristic. This works so long
|
||||
// as the operation history is mostly linear.
|
||||
dag_walk::topo_order_reverse_lazy(
|
||||
vec![OperationByEndTime(head_op.clone())],
|
||||
|OperationByEndTime(op)| op.id().clone(),
|
||||
|OperationByEndTime(op)| op.parents().into_iter().map(OperationByEndTime),
|
||||
)
|
||||
.map(|OperationByEndTime(op)| op)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use clap::Subcommand;
|
||||
use jujutsu_lib::dag_walk::topo_order_reverse;
|
||||
use jujutsu_lib::operation::Operation;
|
||||
use jujutsu_lib::operation;
|
||||
|
||||
use crate::cli_util::{user_error, CommandError, CommandHelper, LogContentFormat};
|
||||
use crate::graphlog::{get_graphlog, Edge};
|
||||
|
@ -82,11 +81,7 @@ fn cmd_op_log(
|
|||
let formatter = formatter.as_mut();
|
||||
let mut graph = get_graphlog(command.settings(), formatter.raw());
|
||||
let default_node_symbol = graph.default_node_symbol().to_owned();
|
||||
for op in topo_order_reverse(
|
||||
vec![head_op],
|
||||
|op: &Operation| op.id().clone(),
|
||||
|op: &Operation| op.parents(),
|
||||
) {
|
||||
for op in operation::walk_ancestors(&head_op) {
|
||||
let mut edges = vec![];
|
||||
for parent in op.parents() {
|
||||
edges.push(Edge::direct(parent.id().clone()));
|
||||
|
|
Loading…
Reference in a new issue