/* * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0 * (the "License"). You may not use this work except in compliance with the License, which is * available at www.apache.org/licenses/LICENSE-2.0 * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied, as more fully set forth in the License. * * See the NOTICE file distributed with this work for information regarding copyright ownership. */ package alluxio.master.journalv0.ufs; import alluxio.master.journalv0.JournalInputStream; import alluxio.master.journalv0.JournalReader; import alluxio.underfs.UnderFileSystem; import com.google.common.base.Preconditions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.URI; import javax.annotation.concurrent.NotThreadSafe; /** * Implementation of {@link JournalReader} based on UFS. */ @NotThreadSafe public class UfsJournalReader implements JournalReader { private static final Logger LOG = LoggerFactory.getLogger(UfsJournalReader.class); private final UfsJournal mJournal; /** The UFS where the journal is being written to. */ private final UnderFileSystem mUfs; /** Absolute path for the journal checkpoint. */ private final URI mCheckpoint; /** true if the checkpoint has already been read. */ private boolean mCheckpointRead = false; /** The modified time (in ms) for the opened checkpoint file. */ private long mCheckpointOpenedTime = -1; /** The modified time (in ms) for the latest checkpoint file. */ private long mCheckpointLastModifiedTime = -1; /** The log number for the completed log file. */ private long mCurrentLogNumber = UfsJournal.FIRST_COMPLETED_LOG_NUMBER; /** * Creates a new instance of {@link UfsJournalReader}. * * @param journal the handle to the journal */ UfsJournalReader(UfsJournal journal) { mJournal = Preconditions.checkNotNull(journal, "journal"); mUfs = UnderFileSystem.Factory.create(mJournal.getLocation()); mCheckpoint = mJournal.getCheckpoint(); } @Override public boolean isValid() { return mCheckpointRead && (mCheckpointOpenedTime == mCheckpointLastModifiedTime); } @Override public JournalInputStream getCheckpointInputStream() throws IOException { if (mCheckpointRead) { throw new IOException("Checkpoint file has already been read."); } mCheckpointOpenedTime = getCheckpointLastModifiedTimeMs(); LOG.info("Opening journal checkpoint file: {}", mCheckpoint); JournalInputStream jis = mJournal.getJournalFormatter().deserialize(mUfs.open(mCheckpoint.toString())); mCheckpointRead = true; return jis; } @Override public JournalInputStream getNextInputStream() throws IOException { if (!mCheckpointRead) { throw new IOException("Must read the checkpoint file before getting input stream."); } if (getCheckpointLastModifiedTimeMs() != mCheckpointOpenedTime) { throw new IOException("Checkpoint file has been updated. This reader is no longer valid."); } URI currentLog = mJournal.getCompletedLog(mCurrentLogNumber); if (!mUfs.isFile(currentLog.toString())) { LOG.debug("Journal log file: {} does not exist yet.", currentLog); return null; } // Open input stream from the current log file. LOG.info("Opening journal log file: {}", currentLog); JournalInputStream jis = mJournal.getJournalFormatter().deserialize(mUfs.open(currentLog.toString())); // Increment the log file number. mCurrentLogNumber++; return jis; } @Override public long getCheckpointLastModifiedTimeMs() throws IOException { if (!mUfs.isFile(mCheckpoint.toString())) { throw new IOException("Checkpoint file " + mCheckpoint + " does not exist."); } mCheckpointLastModifiedTime = mUfs.getFileStatus(mCheckpoint.toString()).getLastModifiedTime(); return mCheckpointLastModifiedTime; } }