async def check_lock_tree(self, obj_id: str, owner: str) -> None: """Checks if locking whole tree is possible. :param obj_id: object id to dry run locking for :param owner: owner of dry run lock """ root_id = await self.get_root_id(obj_id) children = self.get_all_children(root_id) children.add(root_id) async with self._lock: lock_record = self._locked_objects.get(root_id) if not lock_record: return for lock in children.intersection(lock_record.write): if owner != lock_record.write[lock]: raise CannotLock( self.ErrMessages.SOMETHING_LOCKED_IN_TREE.value) for lock in children.intersection(lock_record.read): if len(lock_record.read[lock] ) > 1 or owner not in lock_record.read[lock]: raise CannotLock( self.ErrMessages.SOMETHING_LOCKED_IN_TREE.value)
async def get_lock( self, dry_run: bool = False ) -> AsyncGenerator[Optional[asyncio.Lock], None]: """Get lock for data structure, method should be used for operation with whole scene/project e.g. saving project, where no changes should be made during this operation. :param dry_run: self._lock is not acquired/blocked when set """ if self._ui_user_locks: raise CannotLock(self.ErrMessages.LOCK_FAIL.value) i = 0 yielded = False try: for _ in range(self.LOCK_RETRIES): i += 1 try: async with self._lock: if self._get_write_locks_count(): raise CannotLock(self.ErrMessages.LOCK_FAIL.value) if not dry_run: yielded = True yield self._lock if dry_run: yielded = True yield None break except CannotLock: await asyncio.sleep(self.RETRY_WAIT) finally: if i > self.LOCK_RETRIES * 0.25: from arcor2_arserver.globals import logger logger.warn(f"Retry took {i * self.LOCK_TIMEOUT}") if not yielded: raise CannotLock(self.ErrMessages.LOCK_FAIL.value)
async def write_lock_cb(req: srpc.lock.WriteLock.Request, ui: WsClient) -> None: if not await glob.LOCK.write_lock(req.args.object_id, glob.USERS.user_name(ui), req.args.lock_tree, notify=True): raise CannotLock(glob.LOCK.ErrMessages.LOCK_FAIL.value)
async def read_lock_cb(req: srpc.lock.ReadLock.Request, ui: WsClient) -> None: # TODO currently unused, maybe delete? if not await glob.LOCK.read_lock(req.args.object_id, glob.USERS.user_name(ui)): raise CannotLock(glob.LOCK.ErrMessages.LOCK_FAIL.value)
async def lock() -> None: if not await glob.LOCK.read_lock(obj_ids, owner): raise CannotLock(glob.LOCK.ErrMessages.LOCK_FAIL.value)
async def lock(): if not await glob.LOCK.write_lock(obj_ids, owner): raise CannotLock(glob.LOCK.ErrMessages.LOCK_FAIL.value)