test under lock contention

This commit is contained in:
Cyryl Płotnicki 2020-12-27 21:10:13 +00:00
parent 1c231e0fd1
commit b1f8e8a709
4 changed files with 45 additions and 4 deletions

12
Cargo.lock generated
View file

@ -31,6 +31,7 @@ dependencies = [
"atomicwrites", "atomicwrites",
"base64", "base64",
"cargo-husky", "cargo-husky",
"fail",
"femme", "femme",
"fs2", "fs2",
"glob", "glob",
@ -198,6 +199,17 @@ version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "fail"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3be3c61c59fdc91f5dbc3ea31ee8623122ce80057058be560654c5d410d181a6"
dependencies = [
"lazy_static",
"log",
"rand 0.7.3",
]
[[package]] [[package]]
name = "femme" name = "femme"
version = "2.1.1" version = "2.1.1"

View file

@ -9,6 +9,7 @@ license = "AGPL-3.0"
anyhow = "1.0" anyhow = "1.0"
atomicwrites = "0.2" atomicwrites = "0.2"
base64 = "0.13" base64 = "0.13"
fail = "0.4"
femme = "2.1" femme = "2.1"
fs2 = "0.4" fs2 = "0.4"
glob = "0.3" glob = "0.3"
@ -38,3 +39,6 @@ features = ["run-for-all", "prepush-hook", "run-cargo-check", "run-cargo-test",
[profile.release] [profile.release]
debug = 1 debug = 1
[features]
failpoints = [ "fail/failpoints" ]

View file

@ -8,5 +8,5 @@ fi
cargo fmt -- --check cargo fmt -- --check
cargo clippy --all-targets --all-features -- -D warnings cargo clippy --all-targets --all-features -- -D warnings
cargo check --frozen cargo check --frozen
cargo test cargo test --all-targets --all-features
cargo test -- --ignored cargo test --all-targets --all-features -- --ignored

View file

@ -1,4 +1,7 @@
use anyhow::Result; use anyhow::Result;
#[cfg(feature = "failpoints")]
use anyhow::*;
use fail::fail_point;
use std::io::Write; use std::io::Write;
use uuid::Uuid; use uuid::Uuid;
use vfs::VfsPath; use vfs::VfsPath;
@ -33,13 +36,13 @@ impl Lock {
} }
fn wait_to_have_sole_lock(lock_id: Uuid, index_directory: &VfsPath) -> Result<()> { fn wait_to_have_sole_lock(lock_id: Uuid, index_directory: &VfsPath) -> Result<()> {
Lock::create_lock_file(lock_id, index_directory)?; let _ = Lock::create_lock_file(lock_id, index_directory);
while !Lock::sole_lock(lock_id, index_directory)? { while !Lock::sole_lock(lock_id, index_directory)? {
let path = Lock::lock_file_path(index_directory, lock_id)?; let path = Lock::lock_file_path(index_directory, lock_id)?;
path.remove_file()?; path.remove_file()?;
let sleep_duration = time::Duration::from_millis((OsRng.next_u32() % 256).into()); let sleep_duration = time::Duration::from_millis((OsRng.next_u32() % 256).into());
thread::sleep(sleep_duration); thread::sleep(sleep_duration);
Lock::create_lock_file(lock_id, index_directory)?; let _ = Lock::create_lock_file(lock_id, index_directory);
} }
Ok(()) Ok(())
} }
@ -67,6 +70,7 @@ impl Lock {
fn create_lock_file(lock_id: Uuid, index_directory: &VfsPath) -> Result<()> { fn create_lock_file(lock_id: Uuid, index_directory: &VfsPath) -> Result<()> {
let lock_file_path = Lock::lock_file_path(index_directory, lock_id)?; let lock_file_path = Lock::lock_file_path(index_directory, lock_id)?;
fail_point!("create-lock-file", |e: Option<String>| Err(anyhow!(e.unwrap())));
let mut file = lock_file_path.create_file()?; let mut file = lock_file_path.create_file()?;
let lock_id_text = lock_id.to_hyphenated().to_string(); let lock_id_text = lock_id.to_hyphenated().to_string();
let lock_id_bytes = lock_id_text.as_bytes(); let lock_id_bytes = lock_id_text.as_bytes();
@ -89,6 +93,11 @@ impl Drop for Lock {
mod must { mod must {
use super::Lock; use super::Lock;
use anyhow::Result; use anyhow::Result;
#[cfg(feature = "failpoints")]
use anyhow::*;
#[cfg(feature = "failpoints")]
use fail::FailScenario;
use vfs::{MemoryFS, VfsPath}; use vfs::{MemoryFS, VfsPath};
#[test] #[test]
@ -102,4 +111,20 @@ mod must {
assert_eq!(entries, 0); assert_eq!(entries, 0);
Ok(()) Ok(())
} }
#[test]
#[cfg(feature = "failpoints")]
fn be_able_to_lock_under_high_contention() -> Result<()> {
let scenario = FailScenario::setup();
fail::cfg("create-lock-file", "90%10*return(some lock file creation error)->off").map_err(|e| anyhow!(e))?;
{
let path = MemoryFS::new().into();
let lock = Lock::lock(&path)?;
lock.release()?;
}
scenario.teardown();
Ok(())
}
} }