mirror of
https://github.com/gitui-org/gitui
synced 2026-05-24 09:28: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::{
|
pub use crate::{
|
||||||
diff::{AsyncDiff, DiffParams},
|
diff::{AsyncDiff, DiffParams},
|
||||||
revlog::AsyncLog,
|
revlog::{AsyncLog, FetchStatus},
|
||||||
status::{AsyncStatus, StatusParams},
|
status::{AsyncStatus, StatusParams},
|
||||||
sync::{
|
sync::{
|
||||||
diff::{DiffLine, DiffLineType, FileDiff},
|
diff::{DiffLine, DiffLineType, FileDiff},
|
||||||
|
|
|
||||||
|
|
@ -13,16 +13,32 @@ use std::{
|
||||||
atomic::{AtomicBool, Ordering},
|
atomic::{AtomicBool, Ordering},
|
||||||
Arc, Mutex,
|
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 {
|
pub struct AsyncLog {
|
||||||
current: Arc<Mutex<Vec<Oid>>>,
|
current: Arc<Mutex<Vec<Oid>>>,
|
||||||
sender: Sender<AsyncNotification>,
|
sender: Sender<AsyncNotification>,
|
||||||
pending: Arc<AtomicBool>,
|
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 {
|
impl AsyncLog {
|
||||||
///
|
///
|
||||||
|
|
@ -31,6 +47,7 @@ impl AsyncLog {
|
||||||
current: Arc::new(Mutex::new(Vec::new())),
|
current: Arc::new(Mutex::new(Vec::new())),
|
||||||
sender,
|
sender,
|
||||||
pending: Arc::new(AtomicBool::new(false)),
|
pending: Arc::new(AtomicBool::new(false)),
|
||||||
|
background: Arc::new(AtomicBool::new(false)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -58,6 +75,11 @@ impl AsyncLog {
|
||||||
self.pending.load(Ordering::Relaxed)
|
self.pending.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pub fn set_background(&mut self) {
|
||||||
|
self.background.store(true, Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
fn current_head(&self) -> Result<Oid> {
|
fn current_head(&self) -> Result<Oid> {
|
||||||
Ok(self.current.lock()?.first().map_or(Oid::zero(), |f| *f))
|
Ok(self.current.lock()?.first().map_or(Oid::zero(), |f| *f))
|
||||||
|
|
@ -79,29 +101,44 @@ impl AsyncLog {
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pub fn fetch(&mut self) -> Result<()> {
|
pub fn fetch(&mut self) -> Result<FetchStatus> {
|
||||||
if !self.is_pending() && self.head_changed()? {
|
self.background.store(false, Ordering::Relaxed);
|
||||||
self.clear()?;
|
|
||||||
|
|
||||||
let arc_current = Arc::clone(&self.current);
|
if self.is_pending() {
|
||||||
let sender = self.sender.clone();
|
return Ok(FetchStatus::Pending);
|
||||||
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);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
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(
|
fn fetch_helper(
|
||||||
arc_current: Arc<Mutex<Vec<Oid>>>,
|
arc_current: Arc<Mutex<Vec<Oid>>>,
|
||||||
|
arc_background: Arc<AtomicBool>,
|
||||||
sender: &Sender<AsyncNotification>,
|
sender: &Sender<AsyncNotification>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut entries = Vec::with_capacity(LIMIT_COUNT);
|
let mut entries = Vec::with_capacity(LIMIT_COUNT);
|
||||||
|
|
@ -121,6 +158,14 @@ impl AsyncLog {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
Self::notify(&sender);
|
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::calc_scroll_top,
|
||||||
ui::style::Theme,
|
ui::style::Theme,
|
||||||
};
|
};
|
||||||
use asyncgit::{sync, AsyncLog, AsyncNotification, CWD};
|
use asyncgit::{sync, AsyncLog, AsyncNotification, CWD, FetchStatus};
|
||||||
use crossbeam_channel::Sender;
|
use crossbeam_channel::Sender;
|
||||||
use crossterm::event::Event;
|
use crossterm::event::Event;
|
||||||
use std::{borrow::Cow, cmp, convert::TryFrom, time::Instant};
|
use std::{borrow::Cow, cmp, convert::TryFrom, time::Instant};
|
||||||
|
|
@ -32,7 +32,6 @@ pub struct Revlog {
|
||||||
items: ItemBatch,
|
items: ItemBatch,
|
||||||
git_log: AsyncLog,
|
git_log: AsyncLog,
|
||||||
visible: bool,
|
visible: bool,
|
||||||
first_open_done: bool,
|
|
||||||
scroll_state: (Instant, f32),
|
scroll_state: (Instant, f32),
|
||||||
tags: Tags,
|
tags: Tags,
|
||||||
current_size: (u16, u16),
|
current_size: (u16, u16),
|
||||||
|
|
@ -52,7 +51,6 @@ impl Revlog {
|
||||||
selection: 0,
|
selection: 0,
|
||||||
count_total: 0,
|
count_total: 0,
|
||||||
visible: false,
|
visible: false,
|
||||||
first_open_done: false,
|
|
||||||
scroll_state: (Instant::now(), 0_f32),
|
scroll_state: (Instant::now(), 0_f32),
|
||||||
tags: Tags::new(),
|
tags: Tags::new(),
|
||||||
current_size: (0, 0),
|
current_size: (0, 0),
|
||||||
|
|
@ -73,20 +71,22 @@ impl Revlog {
|
||||||
///
|
///
|
||||||
pub fn update(&mut self) {
|
pub fn update(&mut self) {
|
||||||
if self.visible {
|
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())
|
if self
|
||||||
|| old_total != self.count_total
|
.items
|
||||||
{
|
.needs_data(self.selection, self.selection_max())
|
||||||
self.fetch_commits();
|
|| log_changed
|
||||||
}
|
{
|
||||||
|
self.fetch_commits();
|
||||||
|
}
|
||||||
|
|
||||||
if self.tags.is_empty() {
|
if self.tags.is_empty() {
|
||||||
self.tags = sync::get_tags(CWD).unwrap();
|
self.tags = sync::get_tags(CWD).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -340,14 +340,11 @@ impl Component for Revlog {
|
||||||
|
|
||||||
fn hide(&mut self) {
|
fn hide(&mut self) {
|
||||||
self.visible = false;
|
self.visible = false;
|
||||||
|
self.git_log.set_background();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show(&mut self) {
|
fn show(&mut self) {
|
||||||
self.visible = true;
|
self.visible = true;
|
||||||
|
self.git_log.fetch().unwrap();
|
||||||
if !self.first_open_done {
|
|
||||||
self.first_open_done = true;
|
|
||||||
self.git_log.fetch().unwrap();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue