code: private KeyAwareLockPromise checkPendingAndLockKey(InvocationContext ctx, Object key, long lockTimeout) throws InterruptedException {
        final long remaining = pendingLockManager.awaitPendingTransactionsForKey((TxInvocationContext<?>) ctx, key,
                                                                                 lockTimeout, TimeUnit.MILLISECONDS);
        return lockAndRecord(ctx, key, remaining);
     }
docs: Besides acquiring a lock, this method also handles the following situation:
  1. consistentHash("k") == {A, B}, tx1 prepared on A and B. Then node A crashed (A  == single lock owner)
  2. at this point tx2 which also writes "k" tries to prepare on B.
  3. tx2 has to determine that "k" is already locked by another tx (i.e. tx1) and it has to wait for that tx to finish before acquiring the lock.
  
  The algorithm used at step 3 is:
  - the transaction table(TT) associates the current topology id with every remote and local transaction it creates
  - TT also keeps track of the minimal value of all the topology ids of all the transactions still present in the cache (minTopologyId)
  - when a tx wants to acquire lock "k":
  - if tx.topologyId > TT.minTopologyId then "k" might be a key whose owner crashed. If so:
  - obtain the list LT of transactions that started in a previous topology (txTable.getTransactionsPreparedBefore)
  - for each t in LT:
  - if t wants to write "k" then block until t finishes (CacheTransaction.waitForTransactionsToFinishIfItWritesToKey)
  - only then try to acquire lock on "k"
  - if tx.topologyId == TT.minTopologyId try to acquire lock straight away.
  
  Note: The algorithm described below only when nodes leave the cluster, so it doesn't add a performance burden
  when the cluster is stable.