mirror of
https://github.com/gitui-org/gitui
synced 2026-05-23 17:08:21 +00:00
fix performance regression in revlog
This commit is contained in:
parent
df43ea03aa
commit
2497c4fe9e
3 changed files with 80 additions and 38 deletions
|
|
@ -12,7 +12,7 @@ pub mod sync;
|
|||
|
||||
pub use crate::{
|
||||
diff::{AsyncDiff, DiffParams},
|
||||
revlog::AsyncLog,
|
||||
revlog::{AsyncLog, FetchStatus},
|
||||
status::{AsyncStatus, StatusParams},
|
||||
sync::{
|
||||
diff::{DiffLine, DiffLineType, FileDiff},
|
||||
|
|
|
|||
|
|
@ -13,16 +13,32 @@ use std::{
|
|||
atomic::{AtomicBool, Ordering},
|
||||
Arc, Mutex,
|
||||
},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
///
|
||||
#[derive(PartialEq)]
|
||||
pub enum FetchStatus {
|
||||
/// previous fetch still running
|
||||
Pending,
|
||||
/// no change expected
|
||||
NoChange,
|
||||
/// new walk was started
|
||||
Started,
|
||||
}
|
||||
|
||||
///
|
||||
pub struct AsyncLog {
|
||||
current: Arc<Mutex<Vec<Oid>>>,
|
||||
sender: Sender<AsyncNotification>,
|
||||
pending: Arc<AtomicBool>,
|
||||
background: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
static LIMIT_COUNT: usize = 1000;
|
||||
static LIMIT_COUNT: usize = 3000;
|
||||
static SLEEP_FOREGROUND: Duration = Duration::from_millis(2);
|
||||
static SLEEP_BACKGROUND: Duration = Duration::from_millis(1000);
|
||||
|
||||
impl AsyncLog {
|
||||
///
|
||||
|
|
@ -31,6 +47,7 @@ impl AsyncLog {
|
|||
current: Arc::new(Mutex::new(Vec::new())),
|
||||
sender,
|
||||
pending: Arc::new(AtomicBool::new(false)),
|
||||
background: Arc::new(AtomicBool::new(false)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -58,6 +75,11 @@ impl AsyncLog {
|
|||
self.pending.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
///
|
||||
pub fn set_background(&mut self) {
|
||||
self.background.store(true, Ordering::Relaxed)
|
||||
}
|
||||
|
||||
///
|
||||
fn current_head(&self) -> Result<Oid> {
|
||||
Ok(self.current.lock()?.first().map_or(Oid::zero(), |f| *f))
|
||||
|
|
@ -79,29 +101,44 @@ impl AsyncLog {
|
|||
}
|
||||
|
||||
///
|
||||
pub fn fetch(&mut self) -> Result<()> {
|
||||
if !self.is_pending() && self.head_changed()? {
|
||||
self.clear()?;
|
||||
pub fn fetch(&mut self) -> Result<FetchStatus> {
|
||||
self.background.store(false, Ordering::Relaxed);
|
||||
|
||||
let arc_current = Arc::clone(&self.current);
|
||||
let sender = self.sender.clone();
|
||||
let arc_pending = Arc::clone(&self.pending);
|
||||
|
||||
rayon_core::spawn(move || {
|
||||
scope_time!("async::revlog");
|
||||
|
||||
arc_pending.store(true, Ordering::Relaxed);
|
||||
AsyncLog::fetch_helper(arc_current, &sender)
|
||||
.expect("failed to fetch");
|
||||
arc_pending.store(false, Ordering::Relaxed);
|
||||
Self::notify(&sender);
|
||||
});
|
||||
if self.is_pending() {
|
||||
return Ok(FetchStatus::Pending);
|
||||
}
|
||||
Ok(())
|
||||
|
||||
if !self.head_changed()? {
|
||||
return Ok(FetchStatus::NoChange);
|
||||
}
|
||||
|
||||
self.clear()?;
|
||||
|
||||
let arc_current = Arc::clone(&self.current);
|
||||
let sender = self.sender.clone();
|
||||
let arc_pending = Arc::clone(&self.pending);
|
||||
let arc_background = Arc::clone(&self.background);
|
||||
|
||||
rayon_core::spawn(move || {
|
||||
scope_time!("async::revlog");
|
||||
|
||||
arc_pending.store(true, Ordering::Relaxed);
|
||||
AsyncLog::fetch_helper(
|
||||
arc_current,
|
||||
arc_background,
|
||||
&sender,
|
||||
)
|
||||
.expect("failed to fetch");
|
||||
arc_pending.store(false, Ordering::Relaxed);
|
||||
Self::notify(&sender);
|
||||
});
|
||||
|
||||
Ok(FetchStatus::Started)
|
||||
}
|
||||
|
||||
fn fetch_helper(
|
||||
arc_current: Arc<Mutex<Vec<Oid>>>,
|
||||
arc_background: Arc<AtomicBool>,
|
||||
sender: &Sender<AsyncNotification>,
|
||||
) -> Result<()> {
|
||||
let mut entries = Vec::with_capacity(LIMIT_COUNT);
|
||||
|
|
@ -121,6 +158,14 @@ impl AsyncLog {
|
|||
break;
|
||||
} else {
|
||||
Self::notify(&sender);
|
||||
|
||||
let sleep_duration =
|
||||
if arc_background.load(Ordering::Relaxed) {
|
||||
SLEEP_BACKGROUND
|
||||
} else {
|
||||
SLEEP_FOREGROUND
|
||||
};
|
||||
thread::sleep(sleep_duration);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use crate::{
|
|||
ui::calc_scroll_top,
|
||||
ui::style::Theme,
|
||||
};
|
||||
use asyncgit::{sync, AsyncLog, AsyncNotification, CWD};
|
||||
use asyncgit::{sync, AsyncLog, AsyncNotification, CWD, FetchStatus};
|
||||
use crossbeam_channel::Sender;
|
||||
use crossterm::event::Event;
|
||||
use std::{borrow::Cow, cmp, convert::TryFrom, time::Instant};
|
||||
|
|
@ -32,7 +32,6 @@ pub struct Revlog {
|
|||
items: ItemBatch,
|
||||
git_log: AsyncLog,
|
||||
visible: bool,
|
||||
first_open_done: bool,
|
||||
scroll_state: (Instant, f32),
|
||||
tags: Tags,
|
||||
current_size: (u16, u16),
|
||||
|
|
@ -52,7 +51,6 @@ impl Revlog {
|
|||
selection: 0,
|
||||
count_total: 0,
|
||||
visible: false,
|
||||
first_open_done: false,
|
||||
scroll_state: (Instant::now(), 0_f32),
|
||||
tags: Tags::new(),
|
||||
current_size: (0, 0),
|
||||
|
|
@ -73,20 +71,22 @@ impl Revlog {
|
|||
///
|
||||
pub fn update(&mut self) {
|
||||
if self.visible {
|
||||
self.git_log.fetch().unwrap();
|
||||
}
|
||||
let log_changed =
|
||||
self.git_log.fetch().unwrap() == FetchStatus::Started;
|
||||
|
||||
let old_total = self.count_total;
|
||||
self.count_total = self.git_log.count().unwrap();
|
||||
self.count_total = self.git_log.count().unwrap();
|
||||
|
||||
if self.items.needs_data(self.selection, self.selection_max())
|
||||
|| old_total != self.count_total
|
||||
{
|
||||
self.fetch_commits();
|
||||
}
|
||||
if self
|
||||
.items
|
||||
.needs_data(self.selection, self.selection_max())
|
||||
|| log_changed
|
||||
{
|
||||
self.fetch_commits();
|
||||
}
|
||||
|
||||
if self.tags.is_empty() {
|
||||
self.tags = sync::get_tags(CWD).unwrap();
|
||||
if self.tags.is_empty() {
|
||||
self.tags = sync::get_tags(CWD).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -340,14 +340,11 @@ impl Component for Revlog {
|
|||
|
||||
fn hide(&mut self) {
|
||||
self.visible = false;
|
||||
self.git_log.set_background();
|
||||
}
|
||||
|
||||
fn show(&mut self) {
|
||||
self.visible = true;
|
||||
|
||||
if !self.first_open_done {
|
||||
self.first_open_done = true;
|
||||
self.git_log.fetch().unwrap();
|
||||
}
|
||||
self.git_log.fetch().unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue