code: def lock(self, key, ttl=-1):
          
          check_not_none(key, "key can't be None")
          key_data = self._to_data(key)
          return self._encode_invoke_on_key(map_lock_codec, key_data, invocation_timeout=MAX_SIZE, key=key_data,
                                            thread_id=thread_id(), ttl=to_millis(ttl),
                                            reference_id=self.reference_id_generator.get_and_increment())
docs: Acquires the lock for the specified key infinitely or for the specified lease time if provided.
  
          If the lock is not available, the current thread becomes disabled for thread scheduling purposes and lies
          dormant until the lock has been acquired.
  
          You get a lock whether the value is present in the map or not. Other threads (possibly on other systems) would
          block on their invoke of lock() until the non-existent key is unlocked. If the lock holder introduces the key to
          the map, the put() operation is not blocked. If a thread not holding a lock on the non-existent key tries to
          introduce the key while a lock exists on the non-existent key, the put() operation blocks until it is unlocked.
  
          Scope of the lock is this map only. Acquired lock is only for the key in this map.
  
          Locks are re-entrant; so, if the key is locked N times, it should be unlocked N times before another thread can
          acquire it.
  
          **Warning: This method uses __hash__ and __eq__ methods of binary form of the key, not the actual implementations
          of __hash__ and __eq__ defined in key's class.**
  
          :param key: (object), the key to lock.
          :param ttl: (int), time in seconds to wait before releasing the lock (optional).