fix: docker update mem&cpu use binate value
spawn_id for mem&cpu use the current binate value, to enable two concurrent executes from the same docker container id
This commit is contained in:
+2
-2
@@ -443,7 +443,7 @@ impl AppData {
|
|||||||
if f.starts_with('/') {
|
if f.starts_with('/') {
|
||||||
f.remove(0);
|
f.remove(0);
|
||||||
}
|
}
|
||||||
f.to_string()
|
f.clone()
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -457,7 +457,7 @@ impl AppData {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or("".to_owned(), |f| f.trim().to_owned());
|
.map_or("".to_owned(), |f| f.trim().to_owned());
|
||||||
|
|
||||||
let image = i.image.as_ref().map_or("".to_owned(), |f| f.clone());
|
let image = i.image.as_ref().map_or("".to_owned(), std::clone::Clone::clone);
|
||||||
|
|
||||||
if let Some(current_container) = self.get_container_by_id(id) {
|
if let Some(current_container) = self.get_container_by_id(id) {
|
||||||
if current_container.name != name {
|
if current_container.name != name {
|
||||||
|
|||||||
+43
-32
@@ -7,7 +7,6 @@ use futures_util::StreamExt;
|
|||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fmt,
|
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicBool, Ordering},
|
atomic::{AtomicBool, Ordering},
|
||||||
Arc,
|
Arc,
|
||||||
@@ -24,19 +23,28 @@ use crate::{
|
|||||||
mod message;
|
mod message;
|
||||||
pub use message::DockerMessage;
|
pub use message::DockerMessage;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Hash, Clone, PartialEq, Eq)]
|
#[derive(Debug, Hash, Clone, PartialEq, Eq)]
|
||||||
enum SpawnId {
|
enum SpawnId {
|
||||||
Stats(String),
|
Stats((String, Binate)),
|
||||||
Log(String),
|
Log(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for SpawnId {
|
/// Cpu & Mem stats take twice as long as the update interval to get a value, so will have two being executed at the same time
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
/// SpawnId::Stats takes container_id and binate value to enable both cycles of the same container to be inserted into the hashmap
|
||||||
let disp = match self {
|
/// Binate value is toggled when all join handles have been spawned off
|
||||||
Self::Stats(id) => format!("stats::{id}"),
|
#[derive(Debug, Hash, Clone, PartialEq, Eq)]
|
||||||
Self::Log(id) => format!("logs::{id}"),
|
enum Binate {
|
||||||
|
One,
|
||||||
|
Two
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Binate {
|
||||||
|
fn toggle(&mut self) {
|
||||||
|
*self = match self {
|
||||||
|
Self::One => Self::Two,
|
||||||
|
Self::Two => Self::One,
|
||||||
};
|
};
|
||||||
write!(f, "{}", disp)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,6 +57,7 @@ pub struct DockerData {
|
|||||||
receiver: Receiver<DockerMessage>,
|
receiver: Receiver<DockerMessage>,
|
||||||
spawns: Arc<Mutex<HashMap<SpawnId, JoinHandle<()>>>>,
|
spawns: Arc<Mutex<HashMap<SpawnId, JoinHandle<()>>>>,
|
||||||
timestamps: bool,
|
timestamps: bool,
|
||||||
|
binate: Binate
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DockerData {
|
impl DockerData {
|
||||||
@@ -88,6 +97,7 @@ impl DockerData {
|
|||||||
app_data: Arc<Mutex<AppData>>,
|
app_data: Arc<Mutex<AppData>>,
|
||||||
is_running: bool,
|
is_running: bool,
|
||||||
spawns: Arc<Mutex<HashMap<SpawnId, JoinHandle<()>>>>,
|
spawns: Arc<Mutex<HashMap<SpawnId, JoinHandle<()>>>>,
|
||||||
|
spawn_id: SpawnId,
|
||||||
) {
|
) {
|
||||||
let mut stream = docker
|
let mut stream = docker
|
||||||
.stats(
|
.stats(
|
||||||
@@ -110,14 +120,15 @@ impl DockerData {
|
|||||||
|
|
||||||
let cpu_stats = Self::calculate_usage(&stats);
|
let cpu_stats = Self::calculate_usage(&stats);
|
||||||
|
|
||||||
let no_bytes = (0, 0);
|
let no_bytes = || (0, 0);
|
||||||
|
|
||||||
let (rx, tx) = if let Some(key) = some_key {
|
let (rx, tx) = if let Some(key) = some_key {
|
||||||
match stats.networks.unwrap_or_default().get(&key) {
|
match stats.networks.unwrap_or_default().get(&key) {
|
||||||
Some(data) => (data.rx_bytes.to_owned(), data.tx_bytes.to_owned()),
|
Some(data) => (data.rx_bytes, data.tx_bytes),
|
||||||
None => no_bytes,
|
None => no_bytes(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
no_bytes
|
no_bytes()
|
||||||
};
|
};
|
||||||
|
|
||||||
if is_running {
|
if is_running {
|
||||||
@@ -134,7 +145,7 @@ impl DockerData {
|
|||||||
.lock()
|
.lock()
|
||||||
.update_stats(&id, None, None, mem_limit, rx, tx);
|
.update_stats(&id, None, None, mem_limit, rx, tx);
|
||||||
}
|
}
|
||||||
spawns.lock().remove(&SpawnId::Stats(id.clone()));
|
spawns.lock().remove(&spawn_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,19 +158,21 @@ impl DockerData {
|
|||||||
let is_running = *is_running;
|
let is_running = *is_running;
|
||||||
let id = id.clone();
|
let id = id.clone();
|
||||||
|
|
||||||
let key = SpawnId::Stats(id.clone());
|
let key = SpawnId::Stats((id.clone(), self.binate.clone()));
|
||||||
let spawn_contains_id = spawns.lock().contains_key(&key);
|
|
||||||
let s = tokio::spawn(Self::update_container_stat(
|
let spawn_key = key.clone();
|
||||||
|
self.spawns.lock().entry(key).or_insert_with(|| {
|
||||||
|
tokio::spawn(Self::update_container_stat(
|
||||||
docker,
|
docker,
|
||||||
id.clone(),
|
id.clone(),
|
||||||
app_data,
|
app_data,
|
||||||
is_running,
|
is_running,
|
||||||
spawns,
|
spawns,
|
||||||
));
|
spawn_key
|
||||||
if !spawn_contains_id {
|
))
|
||||||
self.spawns.lock().insert(key, s);
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
self.binate.toggle()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all current containers, handle into ContainerItem in the app_data struct rather than here
|
/// Get all current containers, handle into ContainerItem in the app_data struct rather than here
|
||||||
@@ -252,37 +265,34 @@ impl DockerData {
|
|||||||
let app_data = Arc::clone(&self.app_data);
|
let app_data = Arc::clone(&self.app_data);
|
||||||
let spawns = Arc::clone(&self.spawns);
|
let spawns = Arc::clone(&self.spawns);
|
||||||
let key = SpawnId::Log(id.clone());
|
let key = SpawnId::Log(id.clone());
|
||||||
let join_handle = tokio::spawn(Self::update_log(
|
self.spawns.lock().insert(key, tokio::spawn(Self::update_log(
|
||||||
docker, id, timestamps, 0, app_data, spawns,
|
docker, id, timestamps, 0, app_data, spawns,
|
||||||
));
|
)));
|
||||||
self.spawns.lock().insert(key, join_handle);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update all cpu_mem, and selected container log (if a log update join_handle isn't currently being executed)
|
||||||
async fn update_everything(&mut self) {
|
async fn update_everything(&mut self) {
|
||||||
let all_ids = self.update_all_containers().await;
|
let all_ids = self.update_all_containers().await;
|
||||||
let optional_index = self.app_data.lock().get_selected_log_index();
|
let optional_index = self.app_data.lock().get_selected_log_index();
|
||||||
if let Some(index) = optional_index {
|
if let Some(index) = optional_index {
|
||||||
|
// this could be neater
|
||||||
let id = self.app_data.lock().containers.items[index].id.clone();
|
let id = self.app_data.lock().containers.items[index].id.clone();
|
||||||
|
|
||||||
let key = SpawnId::Log(id.clone());
|
let key = SpawnId::Log(id.clone());
|
||||||
let running = self.spawns.lock().contains_key(&key);
|
|
||||||
|
|
||||||
if !running {
|
self.spawns.lock().entry(key).or_insert_with(|| {
|
||||||
let since = self.app_data.lock().containers.items[index].last_updated as i64;
|
let since = self.app_data.lock().containers.items[index].last_updated as i64;
|
||||||
let docker = Arc::clone(&self.docker);
|
let docker = Arc::clone(&self.docker);
|
||||||
let timestamps = self.timestamps;
|
let timestamps = self.timestamps;
|
||||||
|
|
||||||
let app_data = Arc::clone(&self.app_data);
|
let app_data = Arc::clone(&self.app_data);
|
||||||
let spawns = Arc::clone(&self.spawns);
|
let spawns = Arc::clone(&self.spawns);
|
||||||
let s = tokio::spawn(Self::update_log(
|
tokio::spawn(Self::update_log(
|
||||||
docker, id, timestamps, since, app_data, spawns,
|
docker, id, timestamps, since, app_data, spawns,
|
||||||
));
|
))
|
||||||
self.spawns.lock().insert(key, s);
|
});
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.update_all_container_stats(&all_ids).await;
|
self.update_all_container_stats(&all_ids).await;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Animate the loading icon
|
/// Animate the loading icon
|
||||||
@@ -413,6 +423,7 @@ impl DockerData {
|
|||||||
spawns: Arc::new(Mutex::new(HashMap::new())),
|
spawns: Arc::new(Mutex::new(HashMap::new())),
|
||||||
timestamps: args.timestamp,
|
timestamps: args.timestamp,
|
||||||
is_running,
|
is_running,
|
||||||
|
binate: Binate::One
|
||||||
};
|
};
|
||||||
inner.initialise_container_data().await;
|
inner.initialise_container_data().await;
|
||||||
|
|
||||||
|
|||||||
+10
-10
@@ -143,8 +143,8 @@ impl InputHandler {
|
|||||||
|
|
||||||
if show_error {
|
if show_error {
|
||||||
match key_code {
|
match key_code {
|
||||||
KeyCode::Char('q') | KeyCode::Char('Q') => self.quit().await,
|
KeyCode::Char('q' | 'Q') => self.quit().await,
|
||||||
KeyCode::Char('c') | KeyCode::Char('C') => {
|
KeyCode::Char('c' | 'C') => {
|
||||||
self.app_data.lock().show_error = false;
|
self.app_data.lock().show_error = false;
|
||||||
self.app_data.lock().remove_error();
|
self.app_data.lock().remove_error();
|
||||||
}
|
}
|
||||||
@@ -152,9 +152,9 @@ impl InputHandler {
|
|||||||
}
|
}
|
||||||
} else if show_info {
|
} else if show_info {
|
||||||
match key_code {
|
match key_code {
|
||||||
KeyCode::Char('q') | KeyCode::Char('Q') => self.quit().await,
|
KeyCode::Char('q' | 'Q') => self.quit().await,
|
||||||
KeyCode::Char('h') | KeyCode::Char('H') => self.gui_state.lock().show_help = false,
|
KeyCode::Char('h' | 'H') => self.gui_state.lock().show_help = false,
|
||||||
KeyCode::Char('m') | KeyCode::Char('M') => self.m_button(),
|
KeyCode::Char('m' | 'M') => self.m_button(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -169,9 +169,9 @@ impl InputHandler {
|
|||||||
KeyCode::Char('7') => self.sort(Header::Image),
|
KeyCode::Char('7') => self.sort(Header::Image),
|
||||||
KeyCode::Char('8') => self.sort(Header::Rx),
|
KeyCode::Char('8') => self.sort(Header::Rx),
|
||||||
KeyCode::Char('9') => self.sort(Header::Tx),
|
KeyCode::Char('9') => self.sort(Header::Tx),
|
||||||
KeyCode::Char('q') | KeyCode::Char('Q') => self.quit().await,
|
KeyCode::Char('q' | 'Q') => self.quit().await,
|
||||||
KeyCode::Char('h') | KeyCode::Char('H') => self.gui_state.lock().show_help = true,
|
KeyCode::Char('h' | 'H') => self.gui_state.lock().show_help = true,
|
||||||
KeyCode::Char('m') | KeyCode::Char('M') => self.m_button(),
|
KeyCode::Char('m' | 'M') => self.m_button(),
|
||||||
KeyCode::Tab => {
|
KeyCode::Tab => {
|
||||||
// Skip control panel if no containers, could be refactored
|
// Skip control panel if no containers, could be refactored
|
||||||
let has_containers = self.app_data.lock().get_container_len() == 0;
|
let has_containers = self.app_data.lock().get_container_len() == 0;
|
||||||
@@ -216,13 +216,13 @@ impl InputHandler {
|
|||||||
SelectablePanel::Commands => locked_data.docker_command_end(),
|
SelectablePanel::Commands => locked_data.docker_command_end(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KeyCode::Up | KeyCode::Char('k') | KeyCode::Char('K') => self.previous(),
|
KeyCode::Up | KeyCode::Char('k' | 'K') => self.previous(),
|
||||||
KeyCode::PageUp => {
|
KeyCode::PageUp => {
|
||||||
for _ in 0..=6 {
|
for _ in 0..=6 {
|
||||||
self.previous();
|
self.previous();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KeyCode::Down | KeyCode::Char('j') | KeyCode::Char('J') => self.next(),
|
KeyCode::Down | KeyCode::Char('j' | 'J') => self.next(),
|
||||||
KeyCode::PageDown => {
|
KeyCode::PageDown => {
|
||||||
for _ in 0..=6 {
|
for _ in 0..=6 {
|
||||||
self.next();
|
self.next();
|
||||||
|
|||||||
Reference in New Issue
Block a user