mirror of
https://github.com/gitui-org/gitui
synced 2026-05-23 17:08:21 +00:00
perf: prevent repeated status fetches in large repos (#2824)
* perf: prevent repeated status fetches in large repos Replace time-based cache invalidation with a generation counter. The old `StatusParams` included a millisecond timestamp (tick) in its hash, causing the cache to invalidate on every UI tick. For large repos with millions of files, this led to repeated index loading and 5+ minute load times. This change uses a different strategy to manage cache invalidation: - Remove tick from StatusParams hash - Add generation counter that increments after each fetch completes - Include generation in cache hash This ensures: - No repeated fetches while one is already pending, making gitui usable in large repos - New fetch starts immediately after completion, keeping gitui responsive in small repos - External file changes will still be detected on the next fetch cycle * fix changelog --------- Co-authored-by: Daniel Stoll <dstoll@radix.trade> Co-authored-by: extrawurst <776816+extrawurst@users.noreply.github.com> Co-authored-by: extrawurst <mail@rusticorn.com>
This commit is contained in:
parent
3cf7a818d1
commit
49555ce966
2 changed files with 13 additions and 17 deletions
|
|
@ -8,14 +8,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
## Unreleased
|
||||
|
||||
### Changed
|
||||
<<<<<<< feat/version-message
|
||||
* improve `gitui --version` message [[@hlsxx](https://github.com/hlsxx)] ([#2838](https://github.com/gitui-org/gitui/issues/2838))
|
||||
=======
|
||||
* rust msrv bumped to `1.88`
|
||||
|
||||
### Fixed
|
||||
* fix extremely slow status loading in large repositories by replacing time-based cache invalidation with generation counter [[@DannyStoll1](https://github.com/DannyStoll1)] ([#2823](https://github.com/gitui-org/gitui/issues/2823))
|
||||
* fix panic when renaming or updating remote URL with no remotes configured [[@xvchris](https://github.com/xvchris)] ([#2868](https://github.com/gitui-org/gitui/issues/2868))
|
||||
>>>>>>> master
|
||||
|
||||
## [0.28.0] - 2025-12-14
|
||||
|
||||
|
|
|
|||
|
|
@ -10,19 +10,11 @@ use crossbeam_channel::Sender;
|
|||
use std::{
|
||||
hash::Hash,
|
||||
sync::{
|
||||
atomic::{AtomicUsize, Ordering},
|
||||
atomic::{AtomicU64, AtomicUsize, Ordering},
|
||||
Arc, Mutex,
|
||||
},
|
||||
time::{SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
|
||||
fn current_tick() -> u128 {
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("time before unix epoch!")
|
||||
.as_millis()
|
||||
}
|
||||
|
||||
#[derive(Default, Hash, Clone)]
|
||||
pub struct Status {
|
||||
pub items: Vec<StatusItem>,
|
||||
|
|
@ -31,19 +23,17 @@ pub struct Status {
|
|||
///
|
||||
#[derive(Default, Hash, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct StatusParams {
|
||||
tick: u128,
|
||||
status_type: StatusType,
|
||||
config: Option<ShowUntrackedFilesConfig>,
|
||||
}
|
||||
|
||||
impl StatusParams {
|
||||
///
|
||||
pub fn new(
|
||||
pub const fn new(
|
||||
status_type: StatusType,
|
||||
config: Option<ShowUntrackedFilesConfig>,
|
||||
) -> Self {
|
||||
Self {
|
||||
tick: current_tick(),
|
||||
status_type,
|
||||
config,
|
||||
}
|
||||
|
|
@ -59,6 +49,8 @@ pub struct AsyncStatus {
|
|||
sender: Sender<AsyncGitNotification>,
|
||||
pending: Arc<AtomicUsize>,
|
||||
repo: RepoPath,
|
||||
/// Counter that increments after each completed fetch.
|
||||
generation: Arc<AtomicU64>,
|
||||
}
|
||||
|
||||
impl AsyncStatus {
|
||||
|
|
@ -73,6 +65,7 @@ impl AsyncStatus {
|
|||
last: Arc::new(Mutex::new(Status::default())),
|
||||
sender,
|
||||
pending: Arc::new(AtomicUsize::new(0)),
|
||||
generation: Arc::new(AtomicU64::new(0)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -97,12 +90,14 @@ impl AsyncStatus {
|
|||
return Ok(None);
|
||||
}
|
||||
|
||||
let hash_request = hash(¶ms);
|
||||
let generation = self.generation.load(Ordering::Relaxed);
|
||||
let hash_request = hash(&(params, generation));
|
||||
|
||||
log::trace!(
|
||||
"request: [hash: {}] (type: {:?})",
|
||||
"request: [hash: {}] (type: {:?}, gen: {})",
|
||||
hash_request,
|
||||
params.status_type,
|
||||
generation,
|
||||
);
|
||||
|
||||
{
|
||||
|
|
@ -118,6 +113,7 @@ impl AsyncStatus {
|
|||
|
||||
let arc_current = Arc::clone(&self.current);
|
||||
let arc_last = Arc::clone(&self.last);
|
||||
let arc_generation = Arc::clone(&self.generation);
|
||||
let sender = self.sender.clone();
|
||||
let arc_pending = Arc::clone(&self.pending);
|
||||
let status_type = params.status_type;
|
||||
|
|
@ -138,6 +134,8 @@ impl AsyncStatus {
|
|||
log::error!("fetch_helper: {e}");
|
||||
}
|
||||
|
||||
// Increment generation to invalidate cache for next request
|
||||
arc_generation.fetch_add(1, Ordering::Relaxed);
|
||||
arc_pending.fetch_sub(1, Ordering::Relaxed);
|
||||
|
||||
sender
|
||||
|
|
|
|||
Loading…
Reference in a new issue