/*
* 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.Configuration;
import alluxio.PropertyKey;
import alluxio.master.journalv0.Journal;
import alluxio.master.journalv0.JournalFormatter;
import alluxio.master.journalv0.JournalReader;
import alluxio.underfs.UfsStatus;
import alluxio.underfs.UnderFileSystem;
import alluxio.util.URIUtils;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import javax.annotation.concurrent.ThreadSafe;
/**
* Implementation of UFS-based journal.
*
* The journal is made up of 2 components:
* - The checkpoint: the full state of the master
* - The entries: incremental entries to apply to the checkpoint.
*
* To construct the full state of the master, all the entries must be applied to the checkpoint in
* order. The entry file most recently being written to is in the base journal folder, where the
* completed entry files are in the "completed" folder.
*/
@ThreadSafe
public class UfsJournal implements Journal {
/** The log number for the first completed log. */
protected static final long FIRST_COMPLETED_LOG_NUMBER = 1L;
/** The folder for completed logs. */
private static final String COMPLETED_LOCATION = "completed";
/** The file extension for the current log file. */
private static final String CURRENT_LOG_EXTENSION = ".out";
/** The file name of the checkpoint file. */
private static final String CHECKPOINT_FILENAME = "checkpoint.data";
/** The base of the entry log file names, without the file extension. */
private static final String ENTRY_LOG_FILENAME_BASE = "log";
/** The location where this journal is stored. */
protected final URI mLocation;
/** The formatter for this journal. */
private final JournalFormatter mJournalFormatter;
/**
* Creates a new instance of {@link UfsJournal}.
*
* @param location the location for this journal
*/
public UfsJournal(URI location) {
mLocation = location;
mJournalFormatter = JournalFormatter.Factory.create();
}
/**
* @return the location of the completed logs
*/
public URI getCompletedLocation() {
try {
return URIUtils.appendPath(mLocation, COMPLETED_LOCATION);
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
/**
* @return the location of the journal checkpoint
*/
protected URI getCheckpoint() {
try {
return URIUtils.appendPath(mLocation, CHECKPOINT_FILENAME);
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
/**
* @return the location of the current log
*/
public URI getCurrentLog() {
try {
return URIUtils.appendPath(mLocation, ENTRY_LOG_FILENAME_BASE + CURRENT_LOG_EXTENSION);
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
/**
* @param logNumber the log number to get the path for
* @return the location of the completed log for a particular log number
*/
protected URI getCompletedLog(long logNumber) {
try {
return URIUtils.appendPath(getCompletedLocation(),
String.format("%s.%020d", ENTRY_LOG_FILENAME_BASE, logNumber));
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
/**
* @return the {@link JournalFormatter} for this journal
*/
protected JournalFormatter getJournalFormatter() {
return mJournalFormatter;
}
@Override
public URI getLocation() {
return mLocation;
}
@Override
public JournalReader getReader() {
return new UfsJournalReader(this);
}
@Override
public boolean isFormatted() throws IOException {
UnderFileSystem ufs = UnderFileSystem.Factory.create(mLocation);
UfsStatus[] files = ufs.listStatus(mLocation.toString());
if (files == null) {
return false;
}
// Search for the format file.
String formatFilePrefix = Configuration.get(PropertyKey.MASTER_FORMAT_FILE_PREFIX);
for (UfsStatus file : files) {
if (file.getName().startsWith(formatFilePrefix)) {
return true;
}
}
return false;
}
}