clawhdf5: a dropped FileEditor releases its lock at once
FileEditor's flock belongs to the open file description. When another thread forks to spawn a process, the child shares the locked descriptor until it execs, so a reopen right after the drop could be refused with Error::Locked (a one-off failure of edit_interop::editor_locks_the_file in a parallel test run). Drop now unlocks before closing, which releases the lock for every descriptor sharing it. Reproducer edit_tests::drop_releases_the_lock_while_other_threads_spawn_processes (4 threads running `true`, 2000 open/drop rounds): 1483 of 2000 reopens refused before, 0 in 30 runs after (tank). An OFD lock would not help: it is inherited across fork the same way and does not conflict with libhdf5's flock. The agent store's lock file unlocks on drop too. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
@@ -20,7 +20,7 @@ const LOCK_RETRY_DELAY: std::time::Duration = std::time::Duration::from_millis(1
|
||||
/// never leaves a stale lock behind; the empty lock file itself is harmless).
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct StoreLock {
|
||||
_file: File,
|
||||
file: File,
|
||||
}
|
||||
|
||||
impl StoreLock {
|
||||
@@ -42,7 +42,7 @@ impl StoreLock {
|
||||
let mut attempts_left = LOCK_RETRIES;
|
||||
loop {
|
||||
match file.try_lock() {
|
||||
Ok(()) => return Ok(Self { _file: file }),
|
||||
Ok(()) => return Ok(Self { file }),
|
||||
Err(TryLockError::WouldBlock) if attempts_left > 0 => {
|
||||
attempts_left -= 1;
|
||||
std::thread::sleep(LOCK_RETRY_DELAY);
|
||||
@@ -60,6 +60,16 @@ impl StoreLock {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for StoreLock {
|
||||
/// Unlocks before the file is closed: a process another thread forks
|
||||
/// inherits the descriptor until it execs, and a `flock` lasts while any
|
||||
/// descriptor of the open file does, so closing alone could keep the
|
||||
/// store locked for a moment after the drop (see `FileEditor`'s `Drop`).
|
||||
fn drop(&mut self) {
|
||||
let _ = self.file.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user