protect vbranches with a semaphore

This commit is contained in:
Nikita Galaiko 2023-06-26 12:19:46 +02:00
parent 77c00a0723
commit 9b5e6eec2b
3 changed files with 42 additions and 6 deletions

View File

@ -1,7 +1,7 @@
use std::{collections::HashMap, ops, sync}; use std::{collections::HashMap, ops, sync};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use tokio::sync::mpsc; use tokio::sync::{mpsc, Semaphore};
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
use crate::{ use crate::{
@ -29,6 +29,8 @@ pub struct App {
files_database: files::Database, files_database: files::Database,
deltas_database: deltas::Database, deltas_database: deltas::Database,
bookmarks_database: bookmarks::Database, bookmarks_database: bookmarks::Database,
vbranch_semaphores: sync::Arc<tokio::sync::Mutex<HashMap<String, Semaphore>>>,
} }
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
@ -63,6 +65,7 @@ impl App {
deltas_database: deltas::Database::new(database.clone()), deltas_database: deltas::Database::new(database.clone()),
files_database: files::Database::new(database.clone()), files_database: files::Database::new(database.clone()),
bookmarks_database: bookmarks::Database::new(database), bookmarks_database: bookmarks::Database::new(database),
vbranch_semaphores: sync::Arc::new(tokio::sync::Mutex::new(HashMap::new())),
}) })
} }
@ -333,7 +336,7 @@ impl App {
Ok(()) Ok(())
} }
pub fn list_virtual_branches( pub async fn list_virtual_branches(
&self, &self,
project_id: &str, project_id: &str,
) -> Result<Vec<virtual_branches::VirtualBranch>> { ) -> Result<Vec<virtual_branches::VirtualBranch>> {
@ -341,11 +344,30 @@ impl App {
let project = self.gb_project(project_id)?; let project = self.gb_project(project_id)?;
let project_repository = project_repository::Repository::open(&project) let project_repository = project_repository::Repository::open(&project)
.context("failed to open project repository")?; .context("failed to open project repository")?;
let mut semaphores = self.vbranch_semaphores.lock().await;
let semaphore = semaphores
.entry(project_id.to_string())
.or_insert_with(|| Semaphore::new(1));
let _permit = semaphore.acquire().await?;
virtual_branches::list_virtual_branches(&gb_repository, &project_repository) virtual_branches::list_virtual_branches(&gb_repository, &project_repository)
} }
pub fn create_virtual_branch(&self, project_id: &str, name: &str, path: &str) -> Result<()> { pub async fn create_virtual_branch(
&self,
project_id: &str,
name: &str,
path: &str,
) -> Result<()> {
let gb_repository = self.gb_repository(project_id)?; let gb_repository = self.gb_repository(project_id)?;
let mut semaphores = self.vbranch_semaphores.lock().await;
let semaphore = semaphores
.entry(project_id.to_string())
.or_insert_with(|| Semaphore::new(1));
let _permit = semaphore.acquire().await?;
let branch_id = virtual_branches::create_virtual_branch(&gb_repository, name)?; let branch_id = virtual_branches::create_virtual_branch(&gb_repository, name)?;
virtual_branches::move_files(&gb_repository, &branch_id, &vec![path.try_into()?])?; virtual_branches::move_files(&gb_repository, &branch_id, &vec![path.try_into()?])?;
Ok(()) Ok(())
@ -361,7 +383,7 @@ impl App {
Ok(()) Ok(())
} }
pub fn move_virtual_branch_files( pub async fn move_virtual_branch_files(
&self, &self,
project_id: &str, project_id: &str,
branch: &str, branch: &str,
@ -372,6 +394,13 @@ impl App {
.into_iter() .into_iter()
.map(|p| p.try_into()) .map(|p| p.try_into())
.collect::<Result<Vec<branch::Ownership>, _>>()?; .collect::<Result<Vec<branch::Ownership>, _>>()?;
let mut semaphores = self.vbranch_semaphores.lock().await;
let semaphore = semaphores
.entry(project_id.to_string())
.or_insert_with(|| Semaphore::new(1));
let _permit = semaphore.acquire().await?;
virtual_branches::move_files(&gb_repository, branch, &paths)?; virtual_branches::move_files(&gb_repository, branch, &paths)?;
Ok(()) Ok(())
} }

View File

@ -577,6 +577,7 @@ async fn list_virtual_branches(
let app = handle.state::<app::App>(); let app = handle.state::<app::App>();
let branches = app let branches = app
.list_virtual_branches(project_id) .list_virtual_branches(project_id)
.await
.context("failed to list virtual branches")?; .context("failed to list virtual branches")?;
Ok(branches) Ok(branches)
} }
@ -590,7 +591,9 @@ async fn create_virtual_branch(
path: &str, path: &str,
) -> Result<(), Error> { ) -> Result<(), Error> {
let app = handle.state::<app::App>(); let app = handle.state::<app::App>();
app.create_virtual_branch(project_id, name, path)?; app.create_virtual_branch(project_id, name, path)
.await
.context("failed to create virtual branch")?;
Ok(()) Ok(())
} }
@ -615,7 +618,10 @@ async fn move_virtual_branch_files(
paths: Vec<&str>, paths: Vec<&str>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let app = handle.state::<app::App>(); let app = handle.state::<app::App>();
let target = app.move_virtual_branch_files(project_id, branch, paths)?; let target = app
.move_virtual_branch_files(project_id, branch, paths)
.await
.context("failed to move virtual branch files")?;
Ok(target) Ok(target)
} }

View File

@ -13,6 +13,7 @@ use serde::Serialize;
pub use branch::Branch; pub use branch::Branch;
pub use iterator::BranchIterator as Iterator; pub use iterator::BranchIterator as Iterator;
use tokio::sync::Semaphore;
use uuid::Uuid; use uuid::Uuid;
use crate::{gb_repository, project_repository, reader, sessions}; use crate::{gb_repository, project_repository, reader, sessions};