Implement the guard side of shared state directories.

This commit is contained in:
Nick Mathewson 2021-10-21 13:31:38 -04:00
parent fdddb74de4
commit 8a99833777
4 changed files with 51 additions and 3 deletions

View File

@ -60,7 +60,7 @@ pub enum Error {
/// Problem creating or updating a guard manager.
#[error("Problem creating or updating guards list: {0}")]
GuardMgr(#[from] tor_guardmgr::GuardMgrError),
GuardMgr(#[source] tor_guardmgr::GuardMgrError),
/// Problem selecting a guard relay.
#[error("Unable to select a guard relay: {0}")]
@ -84,3 +84,12 @@ impl From<tor_rtcompat::TimeoutError> for Error {
Error::CircTimeout
}
}
impl From<tor_guardmgr::GuardMgrError> for Error {
fn from(err: tor_guardmgr::GuardMgrError) -> Error {
match err {
tor_guardmgr::GuardMgrError::State(e) => Error::State(e),
_ => Error::GuardMgr(err),
}
}
}

View File

@ -201,6 +201,20 @@ impl Guard {
self.reachable
}
/// Copy all _non-persistent_ status from `other` to self.
///
/// Requires that the two `Guard`s have the same ID.
pub(crate) fn copy_status_from(&mut self, other: &Guard) {
debug_assert_eq!(self.id, other.id);
self.last_tried_to_connect_at = other.last_tried_to_connect_at;
self.retry_at = other.retry_at;
self.reachable = other.reachable;
self.failing_since = other.failing_since;
self.is_dir_cache = other.is_dir_cache;
self.exploratory_circ_pending = other.exploratory_circ_pending;
}
/// Change the reachability status for this guard.
fn set_reachable(&mut self, r: Reachable) {
if self.reachable != r {

View File

@ -288,7 +288,11 @@ impl<R: Runtime> GuardMgr<R> {
/// We only call this method if we _don't_ have the lock on the state
/// files. If we have the lock, we only want to save.
pub fn reload_persistent_state(&self) -> Result<(), GuardMgrError> {
warn!("Not yet implemented");
let mut inner = self.inner.lock().expect("Poisoned lock");
if let Some(new_guards) = inner.default_storage.load()? {
let now = self.runtime.wallclock();
inner.replace_guards_with(new_guards, now);
}
Ok(())
}
@ -296,7 +300,11 @@ impl<R: Runtime> GuardMgr<R> {
///
/// Requires that we hold the lock on the state files.
pub fn upgrade_to_owned_persistent_state(&self) -> Result<(), GuardMgrError> {
warn!("Not yet implemented");
let mut inner = self.inner.lock().expect("Poisoned lock");
debug_assert!(inner.default_storage.can_store());
let new_guards = inner.default_storage.load()?.unwrap_or_else(GuardSet::new);
let now = self.runtime.wallclock();
inner.replace_guards_with(new_guards, now);
Ok(())
}
@ -492,6 +500,14 @@ impl GuardMgrInner {
self.active_guards.select_primary_guards(&self.params);
}
/// Replace the active guard set with `new_guards`, preserving
/// non-persistent state for any guards that are retained.
fn replace_guards_with(&mut self, mut new_guards: GuardSet, now: SystemTime) {
new_guards.copy_status_from(&self.active_guards);
self.active_guards = new_guards;
self.update(now, None);
}
/// Called when the circuit manager reports (via [`GuardMonitor`]) that
/// a guard succeeded or failed.
///

View File

@ -163,6 +163,15 @@ impl GuardSet {
self.primary_guards_invalidated = true;
}
/// Copy non-persistent status from every guard shared with `other`.
pub(crate) fn copy_status_from(&mut self, other: &GuardSet) {
for (id, guard) in self.guards.iter_mut() {
if let Some(other_guard) = other.get(id) {
guard.copy_status_from(other_guard);
}
}
}
/// Return a serializable state object that can be stored to disk
/// to capture the current state of this GuardSet.
fn get_state(&self) -> GuardSample<'_> {