def unlock(self, name): name_256 = make_sha256(name) pattern_name = name_256 + '.' folder_path = join_paths(self.path, name_256[0]) # Lookup for locked positions files = [] for filename in get_dir_filenames(folder_path): if filename.startswith(pattern_name): position = int(filename.split('.', 1)[1]) files.append((position, filename)) if files: files.sort() for position, filename in files: file_path = join_paths(folder_path, filename) if remove_file( file_path, retries=self.retries, retry_errno=self.retry_errno): return True # If no position found, delete base lock return remove_file_quietly(self.get_file_path(name), retries=self.retries, retry_errno=self.retry_errno)
def lock(self, name, timeout=MARKER, delete_lock_on_timeout=MARKER): path = self.get_file_path(name) lock_code = make_uuid_hash() lock_name = '%s %s %s' % (DOMAIN_NAME, PROCESS_ID, lock_code) lock_name_to_file = lock_name + NEW_LINE position = None while position is None: # Enter on wait list put_binary_on_file(path, lock_name_to_file, mode='a', retries=self.retries, retry_errno=self.retry_errno) # Find my wait position binary = get_file_binary(path, mode='r', retries=self.retries, retry_errno=self.retry_errno) if binary: for i, code in enumerate(binary.splitlines()): if code.split()[-1] == lock_code: position = i break if position is 0: # Me first! Thank you! return # Define expire time expire_time = None if timeout is MARKER: timeout = self.timeout if timeout: expire_time = NOW_TIME() + int(timeout) # Lock my wait position position_path = '%s.%s' % (path, position) put_binary_on_file(position_path, lock_name, retries=self.retries, retry_errno=self.retry_errno) # Wait until my locked position is cleaned while isfile(position_path): sleep(0.1) if expire_time and NOW_TIME() > expire_time: # Im done! No more wait for me! try: remove_file(position_path) except OSError as error: if error.errno is errno.ENOENT: # Wait.. after all.. its show time! return None else: raise if delete_lock_on_timeout is MARKER: delete_lock_on_timeout = self.delete_lock_on_timeout if delete_lock_on_timeout: self.unlock(name) # Sorry, you need to do everything again return self.lock(name, timeout=timeout, delete_lock_on_timeout=delete_lock_on_timeout) else: # Clean locks! self.clean_junk_locks_as_daemon() message = 'Timeout (%ss) on lock "%s". Delete (%s*) to unlock' % (timeout, name, path) raise LockTimeout(message, position_path) remove_file_quietly(position_path, retries=self.retries, retry_errno=self.retry_errno)