def update(self, obj, edit_session): '''Updates model object lock as being active. Raises exception on error. obj should be either model object or its global identifier.''' cfg = self.env.cfg redis = self.env.redis key = self._item_lock_key(obj) with redis.pipeline() as pipe: for i in range(2): try: # put a WATCH on the key that holds our sequence value pipe.watch(key) old_value = loads(pipe.get(key)) if old_value is None: raise ModelLockIsLost() elif old_value['edit_session']==edit_session: # now we can put the pipeline back into buffered mode with MULTI pipe.multi() pipe.expire(key, cfg.MODEL_LOCK_TIMEOUT) pipe.execute() return edit_session else: lock_user = self.env.db.query(self.env.auth_model)\ .get(old_value['user_id']) raise ModelLockedByOther(lock_user, old_value['edit_session']) except WatchError: continue logger.error('Failed to update model object lock. '\ 'Problem with redis?') raise ModelLockError()
def update(self, obj, edit_session): '''Updates model object lock as being active. Raises exception on error. obj should be either model object or its global identifier.''' cfg = self.env.cfg redis = self.env.redis key = self._item_lock_key(obj) with redis.pipeline() as pipe: for i in range(2): try: # put a WATCH on the key that holds our sequence value pipe.watch(key) old_value = loads(pipe.get(key)) if old_value is None: raise ModelLockIsLost() elif old_value['edit_session'] == edit_session: # now we can put the pipeline back into buffered mode with MULTI pipe.multi() pipe.expire(key, cfg.MODEL_LOCK_TIMEOUT) pipe.execute() return edit_session else: lock_user = self.env.db.query(self.env.auth_model)\ .get(old_value['user_id']) raise ModelLockedByOther(lock_user, old_value['edit_session']) except WatchError: continue logger.error('Failed to update model object lock. '\ 'Problem with redis?') raise ModelLockError()
def create(self, obj, force=False): '''Marks model object as editted. Returns edit session on success or raises exception. obj should be either model object or its global identifier. When force is True the current lock is ignored.''' cfg = self.env.cfg redis = self.env.redis edit_session = self._create_edit_session() key = self._item_lock_key(obj) value = self._item_lock_value(edit_session) if force: redis.set(key, json.dumps(value)) redis.expire(key, cfg.MODEL_LOCK_TIMEOUT) return edit_session with redis.pipeline() as pipe: for i in range(2): try: # put a WATCH on the key that holds our sequence value pipe.watch(key) # after WATCHing, the pipeline is put into immediate execution # mode until we tell it to start buffering commands again. # this allows us to get the current value of our sequence old_value = loads(pipe.get(key)) if old_value is None: # now we can put the pipeline back into buffered mode with MULTI pipe.multi() pipe.set(key, json.dumps(value)) pipe.expire(key, cfg.MODEL_LOCK_TIMEOUT) # and finally, execute the pipeline (the set command) pipe.execute() # if a WatchError wasn't raised during execution, everything # we just did happened atomically. return edit_session else: lock_user = self.env.db.query(self.env.auth_model)\ .get(old_value['user_id']) raise ModelLockedByOther(lock_user, old_value['edit_session']) except WatchError: continue logger.error('Failed to lock model object. '\ 'Problem with redis?') raise ModelLockError()
def create(self, obj, force=False): '''Marks model object as editted. Returns edit session on success or raises exception. obj should be either model object or its global identifier. When force is True the current lock is ignored.''' cfg = self.env.cfg cache = self.env.cache cache.cas_ids.clear() edit_session = self._create_edit_session() key = self._item_lock_key(obj) value = self._item_lock_value(edit_session) if force: if cache.set(key, value, time=cfg.MODEL_LOCK_TIMEOUT): return edit_session else: raise ModelLockError() for i in range(3): if cache.add(key, value, time=cfg.MODEL_LOCK_TIMEOUT): return edit_session old_value = cache.gets(key) if old_value is None: # Should try add() again continue if not old_value or \ time()-old_value['time']>cfg.MODEL_LOCK_TIMEOUT: # Somebody's lock is already expired if cache.cas(key, value, time=cfg.MODEL_LOCK_TIMEOUT): return edit_session else: continue # Somebody holds active lock, no farther attempts break else: logger.error('Failed to lock model object. '\ 'Problem with memcached?') raise ModelLockError() lock_user = self.env.db.query(self.env.auth_model)\ .get(old_value['user_id']) raise ModelLockedByOther(lock_user, old_value['edit_session'])