/** Initiate the shutdown of this tailer thread, and also wait for it to finish. */
 public void shutdownAndJoin() {
   shutdown();
   try {
     // Wait for the thread to finish.
     join();
   } catch (InterruptedException ie) {
     LOG.warn(
         "{}: stopping the journal tailer caused exception: {}",
         mMaster.getServiceName(),
         ie.getMessage());
   }
 }
  @Override
  public void run() {
    LOG.info("{}: Journal tailer started.", mMaster.getServiceName());
    // Continually loop loading the checkpoint file, and then loading all completed files. The loop
    // only repeats when the checkpoint file is updated after it was read.
    while (!mInitiateShutdown) {
      try {
        // The start time (ms) for the initiated shutdown.
        long waitForShutdownStart = -1;

        // Load the checkpoint file.
        LOG.info("{}: Waiting to load the checkpoint file.", mMaster.getServiceName());
        mJournalTailer = new JournalTailer(mMaster, mJournal);
        while (!mJournalTailer.checkpointExists()) {
          CommonUtils.sleepMs(LOG, mJournalTailerSleepTimeMs);
          if (mInitiateShutdown) {
            LOG.info("Journal tailer has been shutdown while waiting to load the checkpoint file.");
            mStopped = true;
            return;
          }
        }
        LOG.info("{}: Start loading the checkpoint file.", mMaster.getServiceName());
        mJournalTailer.processJournalCheckpoint(true);
        LOG.info("{}: Checkpoint file has been loaded.", mMaster.getServiceName());

        // Continually process completed log files.
        while (mJournalTailer.isValid()) {
          if (mJournalTailer.processNextJournalLogFiles() > 0) {
            // Reset the shutdown timer.
            waitForShutdownStart = -1;
          } else {
            if (mInitiateShutdown) {
              if (waitForShutdownStart == -1) {
                waitForShutdownStart = CommonUtils.getCurrentMs();
              } else if ((CommonUtils.getCurrentMs() - waitForShutdownStart)
                  > mShutdownQuietWaitTimeMs) {
                // There have been no new logs for the quiet period. Shutdown now.
                LOG.info(
                    "{}: Journal tailer has been shutdown. No new logs for the quiet period.",
                    mMaster.getServiceName());
                mStopped = true;
                return;
              }
            }
            LOG.debug(
                "{}: The next complete log file does not exist yet. "
                    + "Sleeping and checking again.",
                mMaster.getServiceName());
            CommonUtils.sleepMs(LOG, mJournalTailerSleepTimeMs);
          }
        }
        LOG.info(
            "{}: The checkpoint is out of date. Will reload the checkpoint file.",
            mMaster.getServiceName());
        CommonUtils.sleepMs(LOG, mJournalTailerSleepTimeMs);
      } catch (IOException ioe) {
        // Log the error and continue the loop.
        LOG.error(ioe.getMessage());
      }
    }
    LOG.info("{}: Journal tailer has been shutdown.", mMaster.getServiceName());
    mStopped = true;
  }
 /** Initiate the shutdown of this tailer thread. */
 public void shutdown() {
   LOG.info("{}: Journal tailer shutdown has been initiated.", mMaster.getServiceName());
   mInitiateShutdown = true;
 }