@Override public void run() { final long lastRenewStart = this.lastLockRenewStart; final long renewStart = System.nanoTime(); try { if (!this.lock.renew()) { ioCriticalErrorListener.onIOException(new IllegalStateException(lockName + " lock can't be renewed"), "Critical error while on " + lockName + " renew", null); } } catch (Throwable t) { ioCriticalErrorListener.onIOException(t, "Critical error while on " + lockName + " renew", null); throw t; } //logic to detect slowness of DB and/or the scheduled executor service detectAndReportRenewSlowness(lockName, lastRenewStart, renewStart, renewPeriodMillis, lock.expirationMillis()); this.lastLockRenewStart = renewStart; }
@Override public boolean isBackupLive() throws Exception { LOGGER.debug("ENTER isBackupLive"); try { //is anyone holding the live lock? return this.scheduledLiveLock.lock().isHeld(); } finally { LOGGER.debug("EXIT isBackupLive"); } }
/** * It release the lock itself and all the resources used by it (eg connections, file handlers) */ @Override default void close() throws Exception { release(); }
@Test public void shouldRenewExpiredLockNotAcquiredByOthers() throws InterruptedException { final LeaseLock lock = lock(TimeUnit.SECONDS.toMillis(1)); Assert.assertTrue("lock is not owned by anyone", lock.tryAcquire()); try { Thread.sleep(lock.expirationMillis() * 2); Assert.assertFalse("lock is already expired", lock.isHeldByCaller()); Assert.assertFalse("lock is already expired", lock.isHeld()); Assert.assertTrue("lock is owned", lock.renew()); } finally { lock.release(); } }
@Test public void shouldRenewAcquiredLock() throws InterruptedException { final LeaseLock lock = lock(TimeUnit.SECONDS.toMillis(10)); Assert.assertTrue("lock is not owned by anyone", lock.tryAcquire()); try { Assert.assertTrue("lock is owned", lock.renew()); } finally { lock.release(); } }
@Test public void shouldAcquireLock() { final LeaseLock lock = lock(); final boolean acquired = lock.tryAcquire(); Assert.assertTrue("Must acquire the lock!", acquired); try { Assert.assertTrue("The lock is been held by the caller!", lock.isHeldByCaller()); } finally { lock.release(); } }
@Test public void shouldNotAcquireLockTwice() { final LeaseLock lock = lock(); Assert.assertTrue("Must acquire the lock", lock.tryAcquire()); try { Assert.assertFalse("lock already acquired", lock.tryAcquire()); } finally { lock.release(); } }
@Override public void pauseLiveServer() throws Exception { LOGGER.debug("ENTER pauseLiveServer"); try { if (scheduledLiveLock.isStarted()) { LOGGER.debug("scheduledLiveLock is running: set paused shared state, stop it and release live lock"); setPaused(); scheduledLiveLock.stop(); scheduledLiveLock.lock().release(); } else { LOGGER.debug("scheduledLiveLock is not running: try renew live lock"); if (scheduledLiveLock.lock().renew()) { LOGGER.debug("live lock renewed: set paused shared state and release live lock"); setPaused(); scheduledLiveLock.lock().release(); } else { final IllegalStateException e = new IllegalStateException("live lock can't be renewed"); ioCriticalErrorListener.onIOException(e, "live lock can't be renewed on pauseLiveServer", null); throw e; } } } finally { LOGGER.debug("EXIT pauseLiveServer"); } }
/** * Try to acquire a lock, failing with an exception otherwise. */ private void lock(LeaseLock lock) throws Exception { final LeaseLock.AcquireResult acquireResult = lock.tryAcquire(this.lockAcquisitionTimeoutMillis, this.pauser, () -> !this.interrupted); switch (acquireResult) { case Timeout: throw new Exception("timed out waiting for lock"); case Exit: this.interrupted = false; throw new InterruptedException("LeaseLock was interrupted"); case Done: break; default: throw new AssertionError(acquireResult + " not managed"); } }
ActiveMQScheduledLeaseLock(ScheduledExecutorService scheduledExecutorService, ArtemisExecutor executor, String lockName, LeaseLock lock, long renewPeriodMillis, IOCriticalErrorListener ioCriticalErrorListener) { super(scheduledExecutorService, executor, 0, renewPeriodMillis, TimeUnit.MILLISECONDS, false); if (renewPeriodMillis >= lock.expirationMillis()) { throw new IllegalArgumentException("renewPeriodMillis must be < lock's expirationMillis"); } this.lockName = lockName; this.lock = lock; this.renewPeriodMillis = renewPeriodMillis; //already expired start time this.lastLockRenewStart = System.nanoTime() - TimeUnit.MILLISECONDS.toNanos(lock.expirationMillis()); this.ioCriticalErrorListener = ioCriticalErrorListener; }
private void renewLiveLockIfNeeded(final long acquiredOn) { final long acquiredMillis = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - acquiredOn); if (acquiredMillis > this.scheduledLiveLock.renewPeriodMillis()) { if (!this.scheduledLiveLock.lock().renew()) { final IllegalStateException e = new IllegalStateException("live lock can't be renewed"); ioCriticalErrorListener.onIOException(e, "live lock can't be renewed", null); throw e; } } }
@Test public void shouldAcquireExpiredLock() throws InterruptedException { final LeaseLock lock = lock(TimeUnit.SECONDS.toMillis(1)); Assert.assertTrue("lock is not owned by anyone", lock.tryAcquire()); try { Thread.sleep(lock.expirationMillis() * 2); Assert.assertFalse("lock is already expired", lock.isHeldByCaller()); Assert.assertFalse("lock is already expired", lock.isHeld()); Assert.assertTrue("lock is already expired", lock.tryAcquire()); } finally { lock.release(); } }
try { for (int i = 0; i < writesPerProducer; i++) { final LeaseLock.AcquireResult acquireResult = lock.tryAcquire(millisToAcquireLock, pauser, () -> true); if (acquireResult != LeaseLock.AcquireResult.Done) { throw new IllegalStateException(acquireResult + " from " + Thread.currentThread()); lock.release();
/** * Not reentrant lock acquisition operation (ie {@link #tryAcquire()}). * It tries to acquire the lock until will succeed (ie {@link AcquireResult#Done}), got interrupted (ie {@link AcquireResult#Exit}) * or exceed {@code tryAcquireTimeoutMillis}. * After each failed attempt is performed a {@link Pauser#idle} call. * If the specified timeout is <=0 then it behaves as {@link #tryAcquire(ExitCondition, Pauser)}. */ default AcquireResult tryAcquire(long tryAcquireTimeoutMillis, Pauser pauser, ExitCondition exitCondition) { if (tryAcquireTimeoutMillis < 0) { return tryAcquire(exitCondition, pauser); } final long timeoutInNanosecond = TimeUnit.MILLISECONDS.toNanos(tryAcquireTimeoutMillis); final long startAcquire = System.nanoTime(); while (exitCondition.keepRunning()) { if (tryAcquire()) { return AcquireResult.Done; } else if (System.nanoTime() - startAcquire >= timeoutInNanosecond) { return AcquireResult.Timeout; } else { pauser.idle(); //check before doing anything if time is expired if (System.nanoTime() - startAcquire >= timeoutInNanosecond) { return AcquireResult.Timeout; } } } return AcquireResult.Exit; }
@Test public void shouldNotRenewReleasedLock() throws InterruptedException { final LeaseLock lock = lock(TimeUnit.SECONDS.toMillis(10)); Assert.assertTrue("lock is not owned by anyone", lock.tryAcquire()); lock.release(); Assert.assertFalse("lock is already released", lock.isHeldByCaller()); Assert.assertFalse("lock is already released", lock.isHeld()); Assert.assertFalse("lock is already released", lock.renew()); }
@Override public void stopBackup() throws Exception { LOGGER.debug("ENTER stopBackup"); try { if (this.scheduledBackupLock.isStarted()) { LOGGER.debug("scheduledBackupLock is running: stop it and release backup lock"); this.scheduledBackupLock.stop(); this.scheduledBackupLock.lock().release(); } else { LOGGER.debug("scheduledBackupLock is not running"); } } finally { LOGGER.debug("EXIT stopBackup"); } }
/** * Not reentrant lock acquisition operation (ie {@link #tryAcquire()}). * It tries to acquire the lock until will succeed (ie {@link AcquireResult#Done})or got interrupted (ie {@link AcquireResult#Exit}). * After each failed attempt is performed a {@link Pauser#idle} call. */ default AcquireResult tryAcquire(ExitCondition exitCondition, Pauser pauser) { while (exitCondition.keepRunning()) { if (tryAcquire()) { return AcquireResult.Done; } else { pauser.idle(); } } return AcquireResult.Exit; }
@Test public void shouldOtherAcquireExpiredLock() throws InterruptedException { final LeaseLock lock = lock(TimeUnit.SECONDS.toMillis(1)); Assert.assertTrue("lock is not owned by anyone", lock.tryAcquire()); try { Thread.sleep(lock.expirationMillis() * 2); Assert.assertFalse("lock is already expired", lock.isHeldByCaller()); Assert.assertFalse("lock is already expired", lock.isHeld()); final LeaseLock otherLock = lock(TimeUnit.SECONDS.toMillis(10)); try { Assert.assertTrue("lock is already expired", otherLock.tryAcquire()); } finally { otherLock.release(); } } finally { lock.release(); } }
@Override public void releaseBackup() throws Exception { LOGGER.debug("ENTER releaseBackup"); try { if (this.scheduledBackupLock.isStarted()) { LOGGER.debug("scheduledBackupLock is running: stop it and release backup lock"); this.scheduledBackupLock.stop(); this.scheduledBackupLock.lock().release(); } else { LOGGER.debug("scheduledBackupLock is not running"); } } finally { LOGGER.debug("EXIT releaseBackup"); } }
@Test public void shouldNotRenewLockAcquiredByOthers() throws InterruptedException { final LeaseLock lock = lock(TimeUnit.SECONDS.toMillis(1)); Assert.assertTrue("lock is not owned by anyone", lock.tryAcquire()); try { Thread.sleep(lock.expirationMillis() * 2); Assert.assertFalse("lock is already expired", lock.isHeldByCaller()); Assert.assertFalse("lock is already expired", lock.isHeld()); final LeaseLock otherLock = lock(TimeUnit.SECONDS.toMillis(10)); Assert.assertTrue("lock is already expired", otherLock.tryAcquire()); try { Assert.assertFalse("lock is owned by others", lock.renew()); } finally { otherLock.release(); } } finally { lock.release(); } } }