Nir Soffer has uploaded a new change for review. Change subject: domainMonitor: Introduce cancellation points ......................................................................
domainMonitor: Introduce cancellation points While monitoring domain, the monitor perform some operations that we would like to avoid if the monitor thread was stopped while running the _monitorDomain method. Example operations are accessing shared storage, which may block for long time, or acquiring a host id. This patch adds the @cancelpoint decorator, that can be used to mark methods as cancellation points. Some of the domain monitor thread methods are marked as cancellation points, ensuring that a monitor will stop as soon as possible when stopped. Change-Id: I0a965758736a0b9fa7ac7c2e105bcbbfb04163b8 Signed-off-by: Nir Soffer <[email protected]> --- M lib/vdsm/utils.py M vdsm/storage/domainMonitor.py 2 files changed, 32 insertions(+), 0 deletions(-) git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/21/28721/1 diff --git a/lib/vdsm/utils.py b/lib/vdsm/utils.py index 5561a4b..807926f 100644 --- a/lib/vdsm/utils.py +++ b/lib/vdsm/utils.py @@ -793,6 +793,27 @@ return decorator +class Canceled(Exception): + """ Raised by methods decorated with @cancelpoint """ + + +def cancelpoint(meth): + """ + Decorate a method so it raises Canceled exception if the methods is invoked + after the object was canceled. + + Decorated object must implement __canceled__ method, returning truthy value + if the object is canceled. The object may also like to handle the Canceled + exception. + """ + @functools.wraps(meth) + def wrapper(self, *a, **kw): + if self.__canceled__(): + raise Canceled() + return meth(self, *a, **kw) + return wrapper + + def tobool(s): try: if s is None: diff --git a/vdsm/storage/domainMonitor.py b/vdsm/storage/domainMonitor.py index 788a520..72819e8 100644 --- a/vdsm/storage/domainMonitor.py +++ b/vdsm/storage/domainMonitor.py @@ -177,6 +177,10 @@ def getStatus(self): return self.status.copy() + def __canceled__(self): + """ Accessed by methods decorated with @util.cancelpoint """ + return self.stopEvent.is_set() + @utils.traceback(on=log.name) def _monitorLoop(self): self.log.debug("Starting domain monitor for %s", self.sdUUID) @@ -184,6 +188,8 @@ while not self.stopEvent.is_set(): try: self._monitorDomain() + except utils.Canceled: + break except: self.log.error("The domain monitor for %s failed unexpectedly", self.sdUUID, exc_info=True) @@ -228,6 +234,7 @@ def _statusDidChange(self): return self.firstChange or self.status.valid != self.nextStatus.valid + @utils.cancelpoint def _notifyStatusChanges(self): self.log.debug("Domain %s changed its status to %s", self.sdUUID, "Valid" if self.nextStatus.valid else "Invalid") @@ -243,6 +250,7 @@ def _shouldRefreshDomain(self): return time() - self.lastRefresh > self.refreshTime + @utils.cancelpoint def _refreshDomain(self): self.log.debug("Refreshing domain %s", self.sdUUID) sdCache.manuallyRemoveDomain(self.sdUUID) @@ -272,11 +280,13 @@ # Collecting monitoring info + @utils.cancelpoint def _performDomainSelftest(self): # This may trigger a refresh of lvm cache. We have seen this taking up # to 90 seconds on overloaded machines. self.domain.selftest() + @utils.cancelpoint def _checkReadDelay(self): # This may block for long time if the storage server is not accessible. # On overloaded machines we have seen this take up to 15 seconds. @@ -314,6 +324,7 @@ # it is superfluous. return self.domain and not self.isIsoDomain + @utils.cancelpoint def _acquireHostId(self): try: self.domain.acquireHostId(self.hostId, async=True) -- To view, visit http://gerrit.ovirt.org/28721 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I0a965758736a0b9fa7ac7c2e105bcbbfb04163b8 Gerrit-PatchSet: 1 Gerrit-Project: vdsm Gerrit-Branch: master Gerrit-Owner: Nir Soffer <[email protected]> _______________________________________________ vdsm-patches mailing list [email protected] https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches
