public Entry getLockEntry(long id) throws IOException {
    Thread currentThread = Thread.currentThread();
    Entry entry = new Entry(id, currentThread);
    Entry existing;
    while ((existing = map.putIfAbsent(entry.id, entry)) != null) {
      synchronized (existing) {
        if (existing.locked) {
          ++existing.numWaiters; // Add ourselves to waiters.
          while (existing.locked) {
            try {
              existing.wait();
            } catch (InterruptedException e) {
              --existing.numWaiters; // Remove ourselves from waiters.
              // HBASE-21292
              // There is a rare case that interrupting and the lock owner thread call
              // releaseLockEntry at the same time. Since the owner thread found there
              // still one waiting, it won't remove the entry from the map. If the interrupted
              // thread is the last one waiting on the lock, and since an exception is thrown,
              // the 'existing' entry will stay in the map forever. Later threads which try to
              // get this lock will stuck in a infinite loop because
              // existing = map.putIfAbsent(entry.id, entry)) != null and existing.locked=false.
              if (!existing.locked && existing.numWaiters == 0) {
                map.remove(existing.id);
              }
              throw new InterruptedIOException("Interrupted waiting to acquire sparse lock");
            }
          }

          --existing.numWaiters; // Remove ourselves from waiters.
          existing.locked = true;
          existing.holder = currentThread;
          return existing;
        }
        // If the entry is not locked, it might already be deleted from the
        // map, so we cannot return it. We need to get our entry into the map
        // or get someone else's locked entry.
      }
    }
    return entry;
  }
Blocks until the lock corresponding to the given id is acquired.
@param id an arbitrary number to lock on
@return an "entry" to pass to {@link #releaseLockEntry(Entry)} to release the lock
@throws IOException if interrupted
hbase-common/src/main/java/org/apache/hadoop/hbase/util/IdLock.java