Skip to content

Commit a336b69

Browse files
committed
Don't release gc locks a second time from Drop
If the lock is explicitly released then we need to remember not to delete it again. In the worst (unlikely) case it could delete another process's lock. More likely, it just emits a spurious warning.
1 parent 10ac219 commit a336b69

File tree

1 file changed

+19
-4
lines changed

1 file changed

+19
-4
lines changed

src/gc_lock.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Conserve backup system.
2-
// Copyright 2017, 2018, 2019, 2020 Martin Pool.
2+
// Copyright 2017-2025 Martin Pool.
33

44
// This program is free software; you can redistribute it and/or modify
55
// it under the terms of the GNU General Public License as published by
@@ -45,6 +45,11 @@ pub struct GarbageCollectionLock {
4545
/// Last band id present when the guard was created. May be None if
4646
/// there are no bands.
4747
band_id: Option<BandId>,
48+
49+
/// Is the lock actually held?
50+
///
51+
/// Present so that we can avoid dropping it a second time from Drop.
52+
held: bool,
4853
}
4954

5055
/// Lock on an archive for gc, that excludes backups and gc by other processes.
@@ -70,7 +75,11 @@ impl GarbageCollectionLock {
7075
.transport()
7176
.write(GC_LOCK, b"{}\n", WriteMode::CreateNew)
7277
.await?;
73-
Ok(GarbageCollectionLock { archive, band_id })
78+
Ok(GarbageCollectionLock {
79+
archive,
80+
band_id,
81+
held: true,
82+
})
7483
}
7584

7685
/// Take a lock on an archive, breaking any existing gc lock.
@@ -107,7 +116,7 @@ impl GarbageCollectionLock {
107116
/// Explicitly release the lock.
108117
///
109118
/// Awaiting the future will ensure that the lock is released.
110-
pub async fn release(self) -> Result<()> {
119+
pub async fn release(mut self) -> Result<()> {
111120
trace!("Releasing GC lock");
112121
self.archive
113122
.transport()
@@ -116,14 +125,20 @@ impl GarbageCollectionLock {
116125
.map_err(|err| {
117126
error!(?err, "Failed to delete GC lock");
118127
Error::from(err)
119-
})
128+
})?;
129+
self.held = false;
130+
Ok(())
120131
}
121132
}
122133

123134
impl Drop for GarbageCollectionLock {
124135
fn drop(&mut self) {
125136
// The lock will, hopefully, be deleted soon after the lock is dropped,
126137
// and before the process exits.
138+
if !self.held {
139+
return;
140+
}
141+
trace!("Releasing GC lock from Drop");
127142
let transport = self.archive.transport().clone();
128143
tokio::task::spawn(async move {
129144
transport.remove_file(GC_LOCK).await.inspect_err(|err| {

0 commit comments

Comments
 (0)