LockCleaner extends ServerLockCleaner { public boolean tryToCleanLock(ThemisLock lock) throws IOException { if (lock.getColumn() == null) { throw new ThemisFatalException("column of lock should not be null for clean, lock=" + lock); } for (int current = 0; current < retry; ++current) { if (this.shouldCleanLock(lock)) { this.cleanLock(lock); return true; } if (current + 1 < retry) { LOG.warn("sleep " + pause + " to clean lock, current=" + current + ", retry=" + retry + ", clientLockTTL=" + clientLockTTl + ", type=" + TransactionTTL.timestampType); Threads.sleep(pause); checkLockExpired(lock, cpClient, clientLockTTl); } } if (hasLock(lock)) { throw new LockConflictException("lock can't be cleaned after retry=" + retry + ", column=" + lock.getColumn() + ", prewriteTs=" + lock.getTimestamp()); } else { LOG.warn("lock has been clean by other transaction, lock=" + lock); } return false; } LockCleaner(Configuration conf, HConnection conn, WorkerRegister register,
      ThemisCoprocessorClient cpClient); static LockCleaner getLockCleaner(Configuration conf, HConnection conn,
      WorkerRegister register, ThemisCoprocessorClient cpClient); boolean shouldCleanLock(ThemisLock lock); static List<ThemisLock> constructLocks(byte[] tableName, List<KeyValue> lockKvs,
      ThemisCoprocessorClient cpClient, int clientLockTTL); static void checkLockExpired(ThemisLock lock, ThemisCoprocessorClient cpClient,
      int clientLockTTL); void tryToCleanLocks(byte[] tableName, List<KeyValue> lockColumns); boolean checkLockExpiredAndTryToCleanLock(ThemisLock lock); boolean tryToCleanLock(ThemisLock lock);  }
@Test public void testTryToCleanLockFail() throws Exception { ThemisLock nullColumnLock = getLock(COLUMN); nullColumnLock.setColumn(null); try { lockCleaner.tryToCleanLock(nullColumnLock); Assert.fail(); } catch (ThemisFatalException e) {} boolean[] cleanLocksOptions = new boolean[]{false, true}; for (boolean cleanLocks : cleanLocksOptions) { ThemisLock lc = getLock(COLUMN); writeLockAndData(COLUMN); Mockito.when(mockRegister.isWorkerAlive(lc.getClientAddress())).thenReturn(false); HBaseAdmin admin = new HBaseAdmin(connection.getConfiguration()); admin.disableTable(TABLENAME); try { invokeTryToCleanLock(lc, cleanLocks); } catch (IOException e) { Assert.assertTrue(e.getCause() instanceof RetriesExhaustedException); admin.enableTable(TABLENAME); checkPrewriteColumnSuccess(COLUMN); } finally { admin.close(); } deleteOldDataAndUpdateTs(); writeLockAndData(COLUMN); lc = getLock(COLUMN); Mockito.when(mockRegister.isWorkerAlive(lc.getClientAddress())).thenReturn(true); long startTs = System.currentTimeMillis(); try { invokeTryToCleanLock(lc, cleanLocks); Assert.fail(); } catch (LockConflictException e) { checkPrewriteColumnSuccess(COLUMN); Assert.assertTrue((System.currentTimeMillis() - startTs) >= 100); } } }