original_docstring: 
          Attempts to atomically acquire a lock with the given key and namespace.
          If holder is given and holder already has the lock, renew.
          Checks for expired locks.
          @param timeout  Secs until lock expiration or 0 for no expiration
          @param lock_holder  Str value identifying lock holder for subsequent exclusive access
          @param lock_info  Dict value for additional attributes describing lock
          @retval  bool - could lock be acquired?
          
docstring: Attempts to atomically acquire a lock with the given key and namespace.
  If holder is given and holder already has the lock, renew.
  Checks for expired locks.
docstring_tokens: Attempts to atomically acquire a lock with the given key and namespace . If holder is given and holder already has the lock renew . Checks for expired locks .
code: def acquire_lock(self, key, timeout=LOCK_EXPIRES_DEFAULT, lock_holder=None, lock_info=None):
          """
          Attempts to atomically acquire a lock with the given key and namespace.
          If holder is given and holder already has the lock, renew.
          Checks for expired locks.
          @param timeout  Secs until lock expiration or 0 for no expiration
          @param lock_holder  Str value identifying lock holder for subsequent exclusive access
          @param lock_info  Dict value for additional attributes describing lock
          @retval  bool - could lock be acquired?
          """
          if not key:
              raise BadRequest("Missing argument: key")
          if "/" in key:
              raise BadRequest("Invalid argument value: key")
  
          lock_attrs = {LOCK_EXPIRES_ATTR: get_ion_ts_millis() + int(1000*timeout) if timeout else 0,
                        LOCK_HOLDER_ATTR: lock_holder or ""}
          if lock_info:
              lock_attrs.update(lock_info)
          expires = int(lock_attrs[LOCK_EXPIRES_ATTR])  # Check type just to be sure
          if expires and get_ion_ts_millis() > expires:
              raise BadRequest("Invalid lock expiration value: %s", expires)
  
          direntry = self._create_dir_entry(LOCK_DIR_PATH, key, attributes=lock_attrs)
          lock_result = False
          try:
              # This is an atomic operation. It relies on the unique key constraint of the directory service
              self.dir_store.create(direntry, create_unique_directory_id())
              lock_result = True
          except BadRequest as ex:
              if ex.message.startswith("DirEntry already exists"):
                  de_old = self.lookup(LOCK_DIR_PATH, key, return_entry=True)
                  if de_old:
                      if self._is_lock_expired(de_old):
                          # Lock is expired: remove, try to relock
                          # Note: even as holder, it's safer to reacquire in this case than renew
                          log.warn("Removing expired lock: %s/%s", de_old.parent, de_old.key)
                          try:
                              # This is safe, because of lock was deleted + recreated in the meantime, it has different id
                              self._delete_lock(de_old)
                              # Try recreate - may fail again due to concurrency
                              self.dir_store.create(direntry, create_unique_directory_id())
                              lock_result = True
                          except BadRequest as ex:
                              if not ex.message.startswith("DirEntry already exists"):
                                  log.exception("Error releasing/reacquiring expired lock %s", de_old.key)
                          except Exception:
                              log.exception("Error releasing/reacquiring expired lock %s", de_old.key)
                      elif lock_holder and de_old.attributes[LOCK_HOLDER_ATTR] == lock_holder:
                          # Holder currently holds the lock: renew
                          log.debug("Renewing lock %s/%s for holder %s", de_old.parent, de_old.key, lock_holder)
                          de_old.attributes = lock_attrs
                          try:
                              self.dir_store.update(de_old)
                              lock_result = True
                          except Exception:
                              log.exception("Error renewing expired lock %s", de_old.key)
                  # We do nothing if we could not find the lock now...
              else:
                  raise
  
          log.debug("Directory.acquire_lock(%s): %s -> %s", key, lock_attrs, lock_result)
  
          return lock_result
code_tokens: def acquire_lock ( self , key , timeout = LOCK_EXPIRES_DEFAULT , lock_holder = None , lock_info = None ) : if not key : raise BadRequest ( "Missing argument: key" ) if "/" in key : raise BadRequest ( "Invalid argument value: key" ) lock_attrs = { LOCK_EXPIRES_ATTR : get_ion_ts_millis ( ) + int ( 1000 * timeout ) if timeout else 0 , LOCK_HOLDER_ATTR : lock_holder or "" } if lock_info : lock_attrs . update ( lock_info ) expires = int ( lock_attrs [ LOCK_EXPIRES_ATTR ] ) if expires and get_ion_ts_millis ( ) > expires : raise BadRequest ( "Invalid lock expiration value: %s" , expires ) direntry = self . _create_dir_entry ( LOCK_DIR_PATH , key , attributes = lock_attrs ) lock_result = False try : self . dir_store . create ( direntry , create_unique_directory_id ( ) ) lock_result = True except BadRequest as ex : if ex . message . startswith ( "DirEntry already exists" ) : de_old = self . lookup ( LOCK_DIR_PATH , key , return_entry = True ) if de_old : if self . _is_lock_expired ( de_old ) : log . warn ( "Removing expired lock: %s/%s" , de_old . parent , de_old . key ) try : self . _delete_lock ( de_old ) self . dir_store . create ( direntry , create_unique_directory_id ( ) ) lock_result = True except BadRequest as ex : if not ex . message . startswith ( "DirEntry already exists" ) : log . exception ( "Error releasing/reacquiring expired lock %s" , de_old . key ) except Exception : log . exception ( "Error releasing/reacquiring expired lock %s" , de_old . key ) elif lock_holder and de_old . attributes [ LOCK_HOLDER_ATTR ] == lock_holder : log . debug ( "Renewing lock %s/%s for holder %s" , de_old . parent , de_old . key , lock_holder ) de_old . attributes = lock_attrs try : self . dir_store . update ( de_old ) lock_result = True except Exception : log . exception ( "Error renewing expired lock %s" , de_old . key ) else : raise log . debug ( "Directory.acquire_lock(%s): %s -> %s" , key , lock_attrs , lock_result ) return lock_result
short_docstring: Attempts to atomically acquire a lock with the given key and namespace.
short_docstring_tokens: Attempts to atomically acquire a lock with the given key and namespace .
comment: """
          Attempts to atomically acquire a lock with the given key and namespace.
          If holder is given and holder already has the lock, renew.
          Checks for expired locks.
          @param timeout  Secs until lock expiration or 0 for no expiration
          @param lock_holder  Str value identifying lock holder for subsequent exclusive access
          @param lock_info  Dict value for additional attributes describing lock
          @retval  bool - could lock be acquired?
          """$SEP$# Check type just to be sure$SEP$# This is an atomic operation. It relies on the unique key constraint of the directory service$SEP$# Lock is expired: remove, try to relock$SEP$# Note: even as holder, it's safer to reacquire in this case than renew$SEP$# This is safe, because of lock was deleted + recreated in the meantime, it has different id$SEP$# Try recreate - may fail again due to concurrency$SEP$# Holder currently holds the lock: renew$SEP$# We do nothing if we could not find the lock now...