From 2260ab4890e3d41cdb80946fc2e87322fcc90210 Mon Sep 17 00:00:00 2001 From: Gerhard Roethlin Date: Sat, 4 Jul 2020 17:03:29 +0200 Subject: [PATCH] Auto Import Redesign Instead of trying to guess which pools can be auto-reimported based on the appearance and disappearance of importable pools, keep track of pools with their associated devices, and only auto-reimport them if at least one of the associated devices disappears. Initially, all imported pools are considered known. --- ZetaWatch/Base.lproj/MainMenu.xib | 1 - ZetaWatch/ZetaAutoImporter.h | 4 +- ZetaWatch/ZetaAutoImporter.mm | 108 ++++++++++++++++-------------- 3 files changed, 57 insertions(+), 56 deletions(-) diff --git a/ZetaWatch/Base.lproj/MainMenu.xib b/ZetaWatch/Base.lproj/MainMenu.xib index 88f8290..d43d00f 100644 --- a/ZetaWatch/Base.lproj/MainMenu.xib +++ b/ZetaWatch/Base.lproj/MainMenu.xib @@ -76,7 +76,6 @@ - diff --git a/ZetaWatch/ZetaAutoImporter.h b/ZetaWatch/ZetaAutoImporter.h index ca9b990..44ca9b0 100644 --- a/ZetaWatch/ZetaAutoImporter.h +++ b/ZetaWatch/ZetaAutoImporter.h @@ -15,12 +15,10 @@ #include -@interface ZetaAutoImporter : ZetaCommanderBase +@interface ZetaAutoImporter : ZetaCommanderBase - (id)init; -@property (weak) IBOutlet ZetaPoolWatcher * poolWatcher; - @property (readonly) std::vector const & importablePools; @end diff --git a/ZetaWatch/ZetaAutoImporter.mm b/ZetaWatch/ZetaAutoImporter.mm index fedb630..bfbb1e9 100644 --- a/ZetaWatch/ZetaAutoImporter.mm +++ b/ZetaWatch/ZetaAutoImporter.mm @@ -10,6 +10,7 @@ #include "IDDiskArbitrationDispatcher.hpp" #include "IDDiskArbitrationHandler.hpp" +#include "IDDiskArbitrationUtils.hpp" #include #include @@ -22,8 +23,7 @@ have not been seen recently are importable and are imported automatically. This set prevents attempting to import a pool multiple times in case of an error. Pools that were imported previously are added to the knownPools set and are - not imported. They are ignored until they vanish from being importable, at - which point they are removed from the known pools set. + not imported. They are ignored until one of their underlying devices disappears. */ @interface ZetaAutoImporter () { @@ -33,11 +33,11 @@ @interface ZetaAutoImporter () // Management std::vector _importable; - std::vector _importableKnown; - std::set _knownPools; + std::vector _importedBefore; } - (void)scheduleChecking; +- (void)handleDisappearedDevice:(ID::DiskInformation const &)info; @end @@ -58,6 +58,7 @@ virtual void diskAppeared(DADiskRef disk, ID::DiskInformation const & info) virtual void diskDisappeared(DADiskRef disk, ID::DiskInformation const & info) { scheduleChecking(); + [watcher handleDisappearedDevice:info]; } private: @@ -79,18 +80,12 @@ - (id)init // ID _idDispatcher.addHandler(std::make_shared(self)); _idDispatcher.start(); + // Auto-Import handling + [self seedKnownPools]; } return self; } -- (void)awakeFromNib -{ - if (self.poolWatcher) - { - [self.poolWatcher.delegates addObject:self]; - } -} - - (void)dealloc { _idDispatcher.stop(); @@ -108,6 +103,22 @@ - (void)scheduleChecking [[NSRunLoop currentRunLoop] addTimer:checkTimer forMode:NSDefaultRunLoopMode]; } +- (void)handleDisappearedDevice:(ID::DiskInformation const &)info +{ + if (info.mediaBSDName.empty()) + return; + std::string devicePath = "/dev/" + info.mediaBSDName; + // Forget pools that were once importable but now are no longer since at + // least one device was removed + _importedBefore.erase( + std::remove_if(_importedBefore.begin(), _importedBefore.end(), + [&](zfs::ImportablePool const & pool) + { + auto const & devices = pool.devices; + return std::find(devices.begin(), devices.end(), devicePath) != devices.end(); + }), _importedBefore.end()); +} + - (void)checkForImportablePools { [_authorization importablePoolsWithReply: @@ -146,38 +157,45 @@ - (void)checkForImportablePools return pools; } +- (void)seedKnownPools +{ + zfs::LibZFSHandle lib; + std::vector knownPools; + for (auto const & pool : lib.pools()) + { + knownPools.push_back({ + pool.name(), + pool.guid(), + pool.status(), + lib.devicesFromPoolConfig(pool.config()), + }); + } + std::sort(knownPools.begin(), knownPools.end()); + _importedBefore = std::move(knownPools); +} + - (void)handleImportablePools:(NSArray*)importablePools { - std::vector importableAll = arrayToPoolVec(importablePools); - // Find the pools that had not been imported before - std::vector importableFresh; - std::set_difference(importableAll.begin(), importableAll.end(), - _knownPools.begin(), _knownPools.end(), - std::back_inserter(importableFresh)); - // Find the pools that had been imported before - std::vector importableKnown; - std::set_difference(importableAll.begin(), importableAll.end(), - importableFresh.begin(), importableFresh.end(), - std::back_inserter(importableKnown)); - // Find new importable pools + std::vector importableCurrent = arrayToPoolVec(importablePools); + // Find the pools that had not been imported before, for auto import std::vector importableNew; - std::set_difference(importableFresh.begin(), importableFresh.end(), - _importable.begin(), _importable.end(), + std::set_difference(importableCurrent.begin(), importableCurrent.end(), + _importedBefore.begin(), _importedBefore.end(), std::back_inserter(importableNew)); - // Find no longer importable pools that were known before - std::vector importableKnownRemoved; - std::set_difference(_importableKnown.begin(), _importableKnown.end(), - importableAll.begin(), importableAll.end(), - std::back_inserter(importableKnownRemoved)); + auto importedPools = [self handleNewImportablePools:importableNew]; + // Aggregate all known pools to prevent double-auto import + std::vector importedBefore; + std::set_union(_importedBefore.begin(), _importedBefore.end(), + importedPools.begin(), importedPools.end(), + std::back_inserter(importedBefore)); // Update currently importable pools collection - _importable = std::move(importableAll); - _importableKnown = std::move(importableKnown); - [self handleNewImportablePools:importableNew]; - [self handleRemovedKnownImportablePools:importableKnownRemoved]; + _importable = std::move(importableCurrent); + _importedBefore = std::move(importedBefore); } -- (void)handleNewImportablePools:(std::vector const &)importableNew +- (std::vector)handleNewImportablePools:(std::vector const &)importableNew { + std::vector importedPools; auto defaults = [NSUserDefaults standardUserDefaults]; bool allowHostIDMismatch = [defaults boolForKey:@"allowHostIDMismatch"]; if ([defaults boolForKey:@"autoImport"]) @@ -210,23 +228,10 @@ - (void)handleNewImportablePools:(std::vector const &)impor { [self handlePoolImportReply:error forPool:poolDict]; }]; + importedPools.push_back(pool); } } -} - -- (void)handleRemovedKnownImportablePools:(std::vector const &)importableKnownRemoved -{ - for (auto const & p : importableKnownRemoved) - { - _knownPools.erase(p); - } -} - -- (void)newPoolDetected:(zfs::ZPool const &)pool -{ - _knownPools.insert({pool.name(), pool.guid(), 0}); - // An imported pool might have changed which pools can be imported - [self scheduleChecking]; + return importedPools; } - (void)handlePoolImportReply:(NSError*)error forPool:(NSDictionary*)pool @@ -247,7 +252,6 @@ - (void)handlePoolImportReply:(NSError*)error forPool:(NSDictionary*)pool pool[@"poolName"], pool[@"poolGUID"]]; [self notifySuccessWithTitle:title text:text]; } - [[self poolWatcher] checkForChanges]; } - (std::vector const &)importablePools