Commit 3ac6ee71 authored by eta's avatar eta
Browse files

Merge branch 'eta/335' into 'main'

arti-client: Unlock the state manager on failure to bootstrap

Closes #335

See merge request !334
parents 8f9831b2 c6fdd7c0
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ use std::sync::{Arc, Mutex, Weak};
use std::time::Duration;

use crate::err::ErrorDetail;
use crate::{status, TorClientBuilder};
use crate::{status, util, TorClientBuilder};
#[cfg(feature = "async-std")]
use tor_rtcompat::async_std::PreferredRuntime as PreferredAsyncStdRuntime;
#[cfg(feature = "tokio")]
@@ -472,11 +472,18 @@ impl<R: Runtime> TorClient<R> {
            );
        }

        // If we fail to bootstrap (i.e. we return before the disarm() point below), attempt to
        // unlock the state files.
        let unlock_guard = util::StateMgrUnlockGuard::new(&self.statemgr);

        self.dirmgr.bootstrap().await?;

        self.circmgr
            .update_network_parameters(self.dirmgr.netdir()?.params());

        // Since we succeeded, disarm the unlock guard.
        unlock_guard.disarm();

        Ok(())
    }

+1 −0
Original line number Diff line number Diff line
@@ -192,6 +192,7 @@
mod address;
mod builder;
mod client;
mod util;

pub mod config;
pub mod status;
+29 −0
Original line number Diff line number Diff line
//! Utility functions for the rest of the crate.

use tor_persist::StateMgr;
use tracing::error;

/// A RAII guard that calls `<T as StateMgr>::unlock` on drop.
pub(crate) struct StateMgrUnlockGuard<'a, T: StateMgr + 'a> {
    /// The inner manager.
    mgr: &'a T,
}

impl<'a, T: StateMgr + 'a> Drop for StateMgrUnlockGuard<'a, T> {
    fn drop(&mut self) {
        if let Err(e) = self.mgr.unlock() {
            error!("Failed to unlock state manager: {}", e);
        }
    }
}

impl<'a, T: StateMgr + 'a> StateMgrUnlockGuard<'a, T> {
    /// Create an unlock guard.
    pub(crate) fn new(mgr: &'a T) -> Self {
        Self { mgr }
    }
    /// Consume the unlock guard without unlocking the state manager.
    pub(crate) fn disarm(self) {
        std::mem::forget(self);
    }
}
+11 −0
Original line number Diff line number Diff line
@@ -117,6 +117,17 @@ impl StateMgr for FsStateMgr {
            Ok(LockStatus::NoLock)
        }
    }
    fn unlock(&self) -> Result<()> {
        let mut lockfile = self
            .inner
            .lockfile
            .lock()
            .expect("Poisoned lock on state lockfile");
        if lockfile.owns_lock() {
            lockfile.unlock()?;
        }
        Ok(())
    }
    fn load<D>(&self, key: &str) -> Result<Option<D>>
    where
        D: DeserializeOwned,
+4 −0
Original line number Diff line number Diff line
@@ -98,6 +98,10 @@ pub trait StateMgr: Clone {
    /// `[StateMgr::can_store()`] to see if the lock is held.
    fn try_lock(&self) -> Result<LockStatus>;

    /// Release any locks held and become a read-only state manager
    /// again. If no locks were held, do nothing.
    fn unlock(&self) -> Result<()>;

    /// Make a new [`StorageHandle`] to store values of particular type
    /// at a particular key.
    fn create_handle<T>(self, key: impl Into<String>) -> DynStorageHandle<T>
Loading