@VisibleForTesting public void doTransitionToWritableMode() { if (shuttingdown) { return; } if (!readOnly.compareAndSet(true, false)) { return; } LOG.info("Transitioning Bookie to Writable mode and will serve read/write requests."); // change zookeeper state only when using zookeeper if (null == zk) { return; } try { doRegisterBookie(zkBookieRegPath); try { // Clear the current readonly node zk.delete(zkBookieReadOnlyPath, -1); } catch (KeeperException.NoNodeException nne) { LOG.warn( "No readonly bookie registered node {} when transitioning to writable", zkBookieReadOnlyPath, nne); } } catch (IOException e) { LOG.error("Error in transition to ReadOnly Mode." + " Shutting down", e); triggerBookieShutdown(ExitCode.BOOKIE_EXCEPTION); } catch (KeeperException e) { LOG.error("Error in transition to ReadOnly Mode." + " Shutting down", e); triggerBookieShutdown(ExitCode.BOOKIE_EXCEPTION); } catch (InterruptedException e) { Thread.currentThread().interrupt(); LOG.warn("Interrupted Exception while transitioning to ReadOnly Mode."); } }
@VisibleForTesting public void doTransitionToReadOnlyMode() { if (shuttingdown) { return; } if (!readOnly.compareAndSet(false, true)) { return; } if (!conf.isReadOnlyModeEnabled()) { LOG.warn( "ReadOnly mode is not enabled. " + "Can be enabled by configuring " + "'readOnlyModeEnabled=true' in configuration." + "Shutting down bookie"); triggerBookieShutdown(ExitCode.BOOKIE_EXCEPTION); return; } LOG.info( "Transitioning Bookie to ReadOnly mode," + " and will serve only read requests from clients!"); // change zookeeper state only when using zookeeper if (null == zk) { return; } try { if (null == zk.exists(this.bookieReadonlyRegistrationPath, false)) { try { zk.create( this.bookieReadonlyRegistrationPath, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } catch (NodeExistsException e) { // this node is just now created by someone. } } doRegisterBookie(zkBookieReadOnlyPath); try { // Clear the current registered node zk.delete(zkBookieRegPath, -1); } catch (KeeperException.NoNodeException nne) { LOG.warn( "No writable bookie registered node {} when transitioning to readonly", zkBookieRegPath, nne); } } catch (IOException e) { LOG.error("Error in transition to ReadOnly Mode." + " Shutting down", e); triggerBookieShutdown(ExitCode.BOOKIE_EXCEPTION); return; } catch (KeeperException e) { LOG.error("Error in transition to ReadOnly Mode." + " Shutting down", e); triggerBookieShutdown(ExitCode.BOOKIE_EXCEPTION); } catch (InterruptedException e) { Thread.currentThread().interrupt(); LOG.warn("Interrupted Exception while transitioning to ReadOnly Mode."); } }
// Triggering the Bookie shutdown in its own thread, // because shutdown can be called from sync thread which would be // interrupted by shutdown call. void triggerBookieShutdown(final int exitCode) { LOG.info("Triggering shutdown of Bookie-{} with exitCode {}", conf.getBookiePort(), exitCode); BookieThread shutdownThread = new BookieThread("BookieShutdownTrigger") { @Override public void run() { Bookie.this.shutdown(exitCode); } }; shutdownThread.start(); try { shutdownThread.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); LOG.debug("InterruptedException while waiting for shutdown. Not a problem!!"); } }
@Override public synchronized void start() { setDaemon(true); LOG.info("I'm starting a bookie with journal directory {}", journalDirectory.getName()); // Start DiskChecker thread ledgerDirsManager.start(); if (indexDirsManager != ledgerDirsManager) { indexDirsManager.start(); } // start sync thread first, so during replaying journals, we could do checkpoint // which reduce the chance that we need to replay journals again if bookie restarted // again before finished journal replays. syncThread.start(); // replay journals try { readJournal(); } catch (IOException ioe) { LOG.error("Exception while replaying journals, shutting down", ioe); shutdown(ExitCode.BOOKIE_EXCEPTION); return; } catch (BookieException be) { LOG.error("Exception while replaying journals, shutting down", be); shutdown(ExitCode.BOOKIE_EXCEPTION); return; } // Do a fully flush after journal replay try { syncThread.requestFlush().get(); } catch (InterruptedException e) { LOG.warn("Interrupting the fully flush after replaying journals : ", e); Thread.currentThread().interrupt(); } catch (ExecutionException e) { LOG.error("Error on executing a fully flush after replaying journals."); shutdown(ExitCode.BOOKIE_EXCEPTION); } // start bookie thread super.start(); // After successful bookie startup, register listener for disk // error/full notifications. ledgerDirsManager.addLedgerDirsListener(getLedgerDirsListener()); if (indexDirsManager != ledgerDirsManager) { indexDirsManager.addLedgerDirsListener(getLedgerDirsListener()); } ledgerStorage.start(); // set running here. // since bookie server use running as a flag to tell bookie server whether it is alive // if setting it in bookie thread, the watcher might run before bookie thread. running = true; try { registerBookie(true).get(); } catch (Exception ie) { LOG.error("Couldn't register bookie with zookeeper, shutting down : ", ie); shutdown(ExitCode.ZK_REG_FAIL); } }