Files
rustfs/common/workers/src/workers.rs
T
houseme 29ddf4dbc8 refactor: standardize constant management and fix typos (#387)
* init rustfs config

* init rustfs-utils crate

* improve code for rustfs-config crate

* add

* improve code for comment

* init rustfs config

* improve code for rustfs-config crate

* add

* improve code for comment

* Unified management of configurations and constants

* fix: modify rustfs-config crate name

* add default fn

* improve code for rustfs config

* refactor: standardize constant management and fix typos

- Create centralized constants module for global static constants
- Replace runtime format! expressions with compile-time constants
- Fix DEFAULT_PORT reference issues in configuration arguments
- Use const-str crate for compile-time string concatenation
- Update tokio dependency from 1.42.2 to 1.45.0
- Ensure consistent naming convention for configuration constants

* fix

* Update common/workers/src/workers.rs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-05-07 17:23:22 +08:00

97 lines
2.5 KiB
Rust

use std::sync::Arc;
use tokio::sync::{Mutex, Notify};
use tracing::info;
pub struct Workers {
available: Mutex<usize>, // Available working slots
notify: Notify, // Used to notify waiting tasks
limit: usize, // Maximum number of concurrent jobs
}
impl Workers {
// Create a Workers object that allows up to n jobs to execute concurrently
pub fn new(n: usize) -> Result<Arc<Workers>, &'static str> {
if n == 0 {
return Err("n must be > 0");
}
Ok(Arc::new(Workers {
available: Mutex::new(n),
notify: Notify::new(),
limit: n,
}))
}
// Give a job a chance to be executed
pub async fn take(&self) {
loop {
let mut available = self.available.lock().await;
info!("worker take, {}", *available);
if *available == 0 {
drop(available);
self.notify.notified().await;
} else {
*available -= 1;
break;
}
}
}
// Release a job's slot
pub async fn give(&self) {
let mut available = self.available.lock().await;
info!("worker give, {}", *available);
*available += 1; // Increase available slots
self.notify.notify_one(); // Notify a waiting task
}
// Wait for all concurrent jobs to complete
pub async fn wait(&self) {
loop {
{
let available = self.available.lock().await;
if *available == self.limit {
break;
}
}
// Wait until all slots are freed
self.notify.notified().await;
}
info!("worker wait end");
}
pub async fn available(&self) -> usize {
*self.available.lock().await
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::time::Duration;
use tokio::time::sleep;
#[tokio::test]
async fn test_workers() {
let workers = Arc::new(Workers::new(5).unwrap());
for _ in 0..5 {
let workers = workers.clone();
tokio::spawn(async move {
workers.take().await;
sleep(Duration::from_secs(3)).await;
});
}
for _ in 0..5 {
workers.give().await;
}
// Sleep: wait for spawn task started
sleep(Duration::from_secs(1)).await;
workers.wait().await;
if workers.available().await != workers.limit {
unreachable!();
}
}
}