diff --git a/lib/src/operation.rs b/lib/src/operation.rs index 6d7d763cd..990090d68 100644 --- a/lib/src/operation.rs +++ b/lib/src/operation.rs @@ -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 { + Some(self.cmp(other)) + } +} + +/// Walks `head_op` and its ancestors in reverse topological order. +pub fn walk_ancestors(head_op: &Operation) -> impl Iterator { + // 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) +} diff --git a/src/commands/operation.rs b/src/commands/operation.rs index 7c679757e..49fe8dd19 100644 --- a/src/commands/operation.rs +++ b/src/commands/operation.rs @@ -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()));