@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"); } }
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; } } }
@Override public void startBackup() throws Exception { LOGGER.debug("ENTER startBackup"); try { ActiveMQServerLogger.LOGGER.waitingToBecomeBackup(); lock(scheduledBackupLock.lock()); scheduledBackupLock.start(); ActiveMQServerLogger.LOGGER.gotBackupLock(); if (getUUID() == null) readNodeId(); } finally { LOGGER.debug("EXIT startBackup"); } }
@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"); } }
@Override public synchronized void stop() throws Exception { if (isStarted()) { try { this.scheduledLiveLock.stop(); this.scheduledBackupLock.stop(); } finally { super.stop(); this.sharedStateManager.close(); this.sharedStateManager = null; this.scheduledLiveLock = null; this.scheduledBackupLock = null; } } }
private JdbcNodeManager(Supplier<? extends SharedStateManager> sharedStateManagerFactory, long lockRenewPeriodMillis, long lockAcquisitionTimeoutMillis, ScheduledExecutorService scheduledExecutorService, ExecutorFactory executorFactory, IOCriticalErrorListener ioCriticalErrorListener) { super(false, null); this.lockAcquisitionTimeoutMillis = lockAcquisitionTimeoutMillis; this.pauser = LeaseLock.Pauser.sleep(Math.min(lockRenewPeriodMillis, MAX_PAUSE_MILLIS), TimeUnit.MILLISECONDS); this.sharedStateManagerFactory = sharedStateManagerFactory; this.scheduledLiveLockFactory = () -> ScheduledLeaseLock.of( scheduledExecutorService, executorFactory != null ? executorFactory.getExecutor() : null, "live", this.sharedStateManager.liveLock(), lockRenewPeriodMillis, ioCriticalErrorListener); this.scheduledBackupLockFactory = () -> ScheduledLeaseLock.of( scheduledExecutorService, executorFactory != null ? executorFactory.getExecutor() : null, "backup", this.sharedStateManager.backupLock(), lockRenewPeriodMillis, ioCriticalErrorListener); this.ioCriticalErrorListener = ioCriticalErrorListener; this.sharedStateManager = null; this.scheduledLiveLock = null; this.scheduledBackupLock = null; }
@Override public void awaitLiveNode() throws Exception { LOGGER.debug("ENTER awaitLiveNode"); try { boolean liveWhileLocked = false; while (!liveWhileLocked) { //check first without holding any lock final SharedStateManager.State state = readSharedState(); if (state == SharedStateManager.State.LIVE) { //verify if the state is live while holding the live node lock too liveWhileLocked = lockLiveAndCheckLiveState(); } else { LOGGER.debugf("state while awaiting live node: %s", state); } if (!liveWhileLocked) { checkInterrupted(() -> "awaitLiveNode got interrupted!"); pauser.idle(); } } //state is LIVE and live lock is acquired and valid LOGGER.debugf("acquired live node lock while state is %s: starting scheduledLiveLock", SharedStateManager.State.LIVE); this.scheduledLiveLock.start(); } finally { LOGGER.debug("EXIT awaitLiveNode"); } }
@Override public ActivateCallback startLiveNode() throws Exception { LOGGER.debug("ENTER startLiveNode"); try { setFailingBack(); final String timeoutMessage = lockAcquisitionTimeoutMillis == -1 ? "indefinitely" : lockAcquisitionTimeoutMillis + " milliseconds"; ActiveMQServerLogger.LOGGER.waitingToObtainLiveLock(timeoutMessage); lock(this.scheduledLiveLock.lock()); this.scheduledLiveLock.start(); ActiveMQServerLogger.LOGGER.obtainedLiveLock(); return new ActivateCallback() { @Override public void activationComplete() { LOGGER.debug("ENTER activationComplete"); try { //state can be written only if the live renew task is running setLive(); } catch (Exception e) { ActiveMQServerLogger.LOGGER.warn(e.getMessage(), e); } finally { LOGGER.debug("EXIT activationComplete"); } } }; } finally { LOGGER.debug("EXIT startLiveNode"); } }
/** * Lock live node and check for a live state, taking care to renew it (if needed) or releasing it otherwise */ private boolean lockLiveAndCheckLiveState() throws Exception { lock(this.scheduledLiveLock.lock()); final long acquiredOn = System.nanoTime(); boolean liveWhileLocked = false; //check if the state is live final SharedStateManager.State stateWhileLocked; try { stateWhileLocked = readSharedState(); } catch (Throwable t) { LOGGER.error("error while holding the live node lock and tried to read the shared state", t); this.scheduledLiveLock.lock().release(); throw t; } if (stateWhileLocked == SharedStateManager.State.LIVE) { renewLiveLockIfNeeded(acquiredOn); liveWhileLocked = true; } else { LOGGER.debugf("state is %s while holding the live lock: releasing live lock", stateWhileLocked); //state is not live: can (try to) release the lock this.scheduledLiveLock.lock().release(); } return liveWhileLocked; }
@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"); } }
@Override public void crashLiveServer() throws Exception { LOGGER.debug("ENTER crashLiveServer"); try { if (this.scheduledLiveLock.isStarted()) { LOGGER.debug("scheduledLiveLock is running: request stop it and release live lock"); this.scheduledLiveLock.stop(); this.scheduledLiveLock.lock().release(); } else { LOGGER.debug("scheduledLiveLock is not running"); } } finally { LOGGER.debug("EXIT crashLiveServer"); } }
@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"); } }