class AdaptiveLock: timeout = 600 def __init__(self): self.method = "hard_links" self.lock_instance = None def lock(self, lock_file): if self.method == "hard_links": self.lock_instance = FluflLock( lock_file, lifetime=60) # seconds after which the lock is broken try: self.lock_instance.lock( timeout=self.timeout) # try for a long time return except TimeoutError: pass except OSError: pass except PermissionError: pass logger.warning( "Unable to use hard link-based file locks. " "Trying fcntl-based file locks", exc_info=True) self.method = "fcntl" if self.method == "fcntl": self.lock_instance = FcntlLock(lock_file) acquired = self.lock_instance.acquire(timeout=self.timeout) if acquired: return logger.warning( "Unable to use fcntl-based file locks. " "Disabling file locks", exc_info=True) self.method = None self.delay = 10.0 # use a large delay to make write collisions unlikely def unlock(self): if self.method == "hard_links": self.lock_instance.unlock( unconditionally=True) # do not raise errors in unlock self.lock_instance = None elif self.method == "fcntl": self.lock_instance.release()
class AdaptiveLock: def __init__(self, timeout: int = 180): self.timeout = timeout self.methods: List[str] = ["fcntl", "hard_links", "delay"] self.lock_instance = None def lock(self, lock_file): if self.methods[0] == "hard_links": self.lock_instance = FluflLock( lock_file, lifetime=self.timeout ) # seconds after which the lock is broken try: self.lock_instance.lock( timeout=self.timeout) # try for a long time return except (FluflLockError, TimeOutError): # timeouts etc. pass except OSError: # such as PermissionError pass logger.warning("Unable to use hard link-based file locks", exc_info=True) self.methods.pop(0) self.lock(lock_file) elif self.methods[0] == "fcntl": self.lock_instance = FcntlLock(lock_file) acquired = self.lock_instance.acquire(timeout=self.timeout, delay=1) if acquired: return logger.warning("Unable to use fcntl-based file locks", exc_info=True) self.methods.pop(0) self.lock(lock_file) else: # use a random delay to make write collisions unlikely delay = gauss(20, 5) if delay > 0: sleep(delay) def unlock(self): if self.methods[0] == "hard_links": assert isinstance(self.lock_instance, FluflLock) self.lock_instance.unlock( unconditionally=True) # do not raise errors in unlock self.lock_instance = None elif self.methods[0] == "fcntl": assert isinstance(self.lock_instance, FcntlLock) self.lock_instance.release()