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; }
@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; }
@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(); } }
@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 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(); } }
@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(); } } }