fix performance regression in revlog

This commit is contained in:
Stephan Dilly 2020-05-22 22:41:17 +02:00
parent df43ea03aa
commit 2497c4fe9e
3 changed files with 80 additions and 38 deletions

View file

@ -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},

View file

@ -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);
}
}

View file

@ -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();
}
}