Lazily load channel state instead of storing in memory
Dependencies
- [2]
WFWTKCJNCreate initial Visual Studio Code extension - [3]
72K45XKDRefactor inline credit to improve hover messages - [4]
TIPGJCUWConsistently use `EditorWorkingCopy` in `pijul-extension` - [5]
DUZBRB3URender correspoding hunk on inline credit hover
Change contents
- file deletion: channel_state.rs
use std::cell::OnceCell;use std::collections::HashMap;use libpijul::changestore::ChangeStore;use libpijul::pristine::TxnErr;use libpijul::pristine::sanakirja::{MutTxn, SanakirjaError};#[derive(Debug, thiserror::Error)]pub enum ChannelStateError<C: std::error::Error + 'static> {#[error("unable to iterate changes: {0:#?}")]ReverseLog(SanakirjaError),#[error("encountered error while iterating log: {0:#?}")]Item(SanakirjaError),#[error("unable to get external hash: {0:#?}")]InternalHash(TxnErr<SanakirjaError>),#[error("unable to read changes: {0:#?}")]ChangeStore(C),}pub struct ChannelState {root_change: ChangeId,}impl ChannelState {pub fn new<C>(transaction: &ArcTxn<MutTxn<()>>,channel: &ChannelRef<MutTxn<()>>,change_store: &C,) -> Result<Self, ChannelStateError<C::Error>>whereC: ChangeStore + Clone + Send + 'static,{let mut changes = HashMap::new();let mut root_change = OnceCell::new();// TODO: authors// let mut authors = HashSet::new();let read_transaction = transaction.read();let mut reverse_log = read_transaction.reverse_log(&*channel.read(), None).map_err(ChannelStateError::ReverseLog)?.peekable();while let Some(log_result) = reverse_log.next() {// TODO: merklelet (_, (hash, merkle)) = log_result.map_err(ChannelStateError::Item)?;let change_id = *read_transaction.get_internal(hash).map_err(ChannelStateError::InternalHash)?.unwrap();// TODO: `change_id.is_root()` is broken?if reverse_log.peek().is_none() {root_change.set(change_id).unwrap();} else {let change_header = change_store.map_err(ChannelStateError::ChangeStore)?;changes.try_insert(change_id, change_header).unwrap();}}Ok(ChannelState {root_change: root_change.take().unwrap(),changes,})}self.changes.get(change_id)}pub fn iter_change_headers(&self) -> impl Iterator<Item = &ChangeHeader> {}}self.changes.values().map(|change| &change.header)pub fn find_vertex_hunk(&self,vertex: Vertex<ChangeId>,) -> Option<(usize, &BaseHunk<Atom<Option<Hash>>, Local>)> {let change = self.changes.get(&vertex.change)?;change.changes.iter().enumerate().find_map(|(index, hunk)| {if hunk.iter().any(|atom| match atom {Atom::NewVertex(new_vertex) => {// Changes that depend on this one may later fragment the original contents,// so the current vertex may be a subset of the original contents.new_vertex.start <= vertex.start && new_vertex.end >= vertex.end}Atom::EdgeMap(_edge_map) => false,}) {// Hunks are 1-indexedSome((index + 1, hunk))} else {None}})}pub fn get_change(&self, change_id: &ChangeId) -> Option<&Change> {.get_change(&hash.into())// TODO: lazy access from ChangeStore?changes: HashMap<ChangeId, Change>,use libpijul::{ArcTxn, ChangeId, ChannelRef, GraphTxnT, Hash, TxnTExt, Vertex};use libpijul::change::{Atom, BaseHunk, Change, ChangeHeader, Local}; - edit in pijul-extension/src/lib.rs at line 14
use std::borrow::Cow; - replacement in pijul-extension/src/lib.rs at line 24
use libpijul::{ArcTxn, ChangeId, ChannelRef, TxnT, Vertex};use libpijul::{ArcTxn, Base32, ChangeId, ChannelRef, GraphTxnT, TxnT, Vertex}; - replacement in pijul-extension/src/lib.rs at line 27
use crate::author::{AuthorSource, Authors};use crate::channel_state::{ChannelState, ChannelStateError};use crate::author::{AuthorSource, Authors, GetAuthorsError}; - edit in pijul-extension/src/lib.rs at line 39
pub mod channel_state; - replacement in pijul-extension/src/lib.rs at line 51
#[error("failed to log changes: {0:#?}")]Changes(#[from] ChannelStateError<C>),#[error("failed to get local authors: {0:#?}")]Changes(#[from] GetAuthorsError<C>), - edit in pijul-extension/src/lib.rs at line 66
pub enum GetChangeError<C: std::error::Error + 'static> {#[error("Unable to begin transaction: {0}")]Transaction(#[from] SanakirjaError),#[error("Unable to get external hash: {0}")]Hash(#[from] TxnErr<SanakirjaError>),#[error("Failed to get change: {0}")]Change(C),#[error("No matching change for {change_id:?}")]NoMatchingChange { change_id: ChangeId },}#[derive(Debug, thiserror::Error)]pub enum FindVertexHunkError<C: std::error::Error + 'static> {#[error("Unable to get change: {0}")]Change(#[from] GetChangeError<C>),#[error("No hunk found for vertex: {vertex:?}")]NoHunkForVertex { vertex: Vertex<ChangeId> },}#[derive(Debug, thiserror::Error)] - replacement in pijul-extension/src/lib.rs at line 104
#[error("Change not found: {change_id:?}")]ChangeNotFound { change_id: ChangeId },#[error("No hunk found for vertex: {vertex:?}")]NoHunkForVertex { vertex: Vertex<ChangeId> },#[error("Failed to get change for {change_id:?}: {error}")]Change {change_id: ChangeId,error: GetChangeError<C>,},#[error("Unable to find hunk for vertex: {0}")]FindVertexHunk(#[from] FindVertexHunkError<C>), - edit in pijul-extension/src/lib.rs at line 165
pub channel_state: ChannelState, - edit in pijul-extension/src/lib.rs at line 186
- edit in pijul-extension/src/lib.rs at line 187
let authors = Authors::new(&dot_directory, &transaction, &channel, &change_store)?; - edit in pijul-extension/src/lib.rs at line 189
let channel_state = ChannelState::new(&transaction, &channel, &change_store)?;let authors = Authors::new(&channel_state, &dot_directory); - edit in pijul-extension/src/lib.rs at line 200
channel_state, - replacement in pijul-extension/src/lib.rs at line 214
pub fn get_change(&self, change_id: &ChangeId) -> Option<&Change> {self.channel_state.get_change(change_id)pub fn get_change(&self, change_id: ChangeId) -> Result<Change, GetChangeError<C::Error>> {let transaction = self.pristine.arc_txn_begin()?;let read_transaction = transaction.read();let external_hash = read_transaction.get_external(&change_id)?.ok_or(GetChangeError::NoMatchingChange { change_id })?;self.change_store.get_change(&external_hash.into()).map_err(GetChangeError::Change)}pub fn find_vertex_hunk(&self,vertex: Vertex<ChangeId>,) -> Result<(usize,BaseHunk<Atom<Option<libpijul::Hash>>, libpijul::change::Local>,),FindVertexHunkError<C::Error>,> {let change = self.get_change(vertex.change)?;change.hashed.changes.into_iter().enumerate().find_map(|(index, hunk)| {hunk.iter().any(|atom| match atom {Atom::NewVertex(new_vertex) => {// Changes that depend on this one may later fragment the original contents,// so the current vertex may be a subset of the original contents.new_vertex.start <= vertex.start && new_vertex.end >= vertex.end}Atom::EdgeMap(_edge_map) => false,})// Hunks are 1-indexed.then_some((index + 1, hunk))}).ok_or(FindVertexHunkError::NoHunkForVertex { vertex }) - replacement in pijul-extension/src/lib.rs at line 271
let Some(change) = self.channel_state.get_change(&vertex.change) else {return Err(ActiveHunkError::ChangeNotFound {change_id: vertex.change,});};let change =self.get_change(vertex.change).map_err(|error| ActiveHunkError::Change {change_id: vertex.change,error,})?; - replacement in pijul-extension/src/lib.rs at line 278
&change.contentsCow::Owned(change.contents)}CreditSource::Untracked { hunk_index: _ } => {Cow::Borrowed(&credits.unrecorded_state.change_contents) - edit in pijul-extension/src/lib.rs at line 283
CreditSource::Untracked { hunk_index: _ } => &credits.unrecorded_state.change_contents, - replacement in pijul-extension/src/lib.rs at line 286
CreditSource::Tracked { vertex } => self.channel_state.find_vertex_hunk(vertex).ok_or_else(|| ActiveHunkError::NoHunkForVertex { vertex })?,CreditSource::Tracked { vertex } => {let (index, hunk) = self.find_vertex_hunk(vertex)?;(index, Cow::Owned(hunk))} - replacement in pijul-extension/src/lib.rs at line 292
(hunk_index + 1, &credits.unrecorded_state.hunks[hunk_index])(hunk_index + 1,Cow::Borrowed(&credits.unrecorded_state.hunks[hunk_index]),) - replacement in pijul-extension/src/lib.rs at line 300
let hunk_diff = match hunk {let hunk_diff = match hunk.as_ref() { - replacement in pijul-extension/src/lib.rs at line 310
hunk: Box::new(hunk.clone()),hunk: Box::new(hunk.into_owned()), - replacement in pijul-extension/src/lib.rs at line 317
change_contents,&change_contents, - replacement in pijul-extension/src/lib.rs at line 335
change_contents,&change_contents, - replacement in pijul-extension/src/lib.rs at line 340
change_contents,&change_contents, - replacement in pijul-extension/src/lib.rs at line 359
change_contents,&change_contents, - replacement in pijul-extension/src/lib.rs at line 380
hunk: Box::new(hunk.clone()),hunk: Box::new(hunk.into_owned()), - replacement in pijul-extension/src/author.rs at line 7
use crate::channel_state::ChannelState;use libpijul::changestore::ChangeStore;use libpijul::pristine::SerializedHash;use libpijul::pristine::sanakirja::{MutTxn, SanakirjaError};use libpijul::{ArcTxn, ChannelRef, TxnTExt}; - edit in pijul-extension/src/author.rs at line 17
}#[derive(Debug, thiserror::Error)]pub enum GetAuthorsError<C: std::error::Error + 'static> {#[error("Unable to get log of changes: {0}")]Log(SanakirjaError),#[error("Error while iterating log: {0}")]LogEntry(SanakirjaError),#[error("Failed to get change header for {hash:?}: {error}")]ChangeHeader { hash: SerializedHash, error: C }, - replacement in pijul-extension/src/author.rs at line 34
pub fn new(channel_state: &ChannelState, dot_directory: &Utf8Path) -> Self {let mut authors = HashMap::new();let repository_identities_path = dot_directory.join("identities");pub fn new<C>(dot_directory: &Utf8Path,transaction: &ArcTxn<MutTxn<()>>,channel: &ChannelRef<MutTxn<()>>,change_store: &C,) -> Result<Self, GetAuthorsError<C::Error>>whereC: ChangeStore + Clone + Send + 'static,{let mut authors = Self {authors: HashMap::new(),};// Get local identitiesauthors.insert_local_identities();// Get identities stored in the repositoryauthors.insert_repository_identities(dot_directory, transaction, channel, change_store)?;Ok(authors)} - edit in pijul-extension/src/author.rs at line 56
fn insert_local_identities(&mut self) { - replacement in pijul-extension/src/author.rs at line 62
match authors.entry(public_key_signature.clone()) {match self.authors.entry(public_key_signature.clone()) { - edit in pijul-extension/src/author.rs at line 78
} - replacement in pijul-extension/src/author.rs at line 80
for change_header in channel_state.iter_change_headers() {fn insert_repository_identities<C>(&mut self,dot_directory: &Utf8Path,transaction: &ArcTxn<MutTxn<()>>,channel: &ChannelRef<MutTxn<()>>,change_store: &C,) -> Result<(), GetAuthorsError<C::Error>>whereC: ChangeStore + Clone + Send + 'static,{let repository_identities_path = dot_directory.join("identities");let read_transaction = transaction.read();let log_entries = read_transaction.log(&*channel.read(), 0).map_err(GetAuthorsError::Log)?;for log_entry in log_entries {let (_index, (serialized_hash, _merkle)) =log_entry.map_err(GetAuthorsError::LogEntry)?;let change_header =change_store.get_header(&serialized_hash.into()).map_err(|error| GetAuthorsError::ChangeHeader {hash: *serialized_hash,error,})?; - replacement in pijul-extension/src/author.rs at line 112
authors.entry(public_key_signature.to_owned())self.authors.entry(public_key_signature.to_owned()) - replacement in pijul-extension/src/author.rs at line 152
Self { authors }Ok(()) - replacement in extensions/vscode/src/inline_credit/line_annotation.rs at line 28
message: &'change_header str,message: String, - replacement in extensions/vscode/src/inline_credit/line_annotation.rs at line 62
let change = repository.get_change(&vertex.change).ok_or_else(|| {napi::Error::from_reason(format!("Unable to get change for verte {vertex:#?}"))let change = repository.get_change(vertex.change).map_err(|error| {napi::Error::from_reason(format!("Unable to get change for vertex {vertex:#?}: {error}")) - replacement in extensions/vscode/src/inline_credit/line_annotation.rs at line 87
message: &change.header.message,message: change.hashed.header.message, - replacement in extensions/vscode/src/inline_credit/hover.rs at line 87
let change = repository.get_change(&vertex.change).ok_or_else(|| {napi::Error::from_reason(format!("Unable to get change for vertex: {vertex:#?}"))let change = repository.get_change(vertex.change).map_err(|error| {napi::Error::from_reason(format!("Unable to get change for vertex {vertex:#?}: {error}"))