/*
* Copyright 2013-2014 eXascale Infolab, University of Fribourg. All rights reserved.
*/
package org.apache.hadoop.hadaps;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.fs.permission.FsPermission;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.SequenceFile;
import org.apache.hadoop.io.Text;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Random;
class WriteMode {
private static final Logger LOG = LoggerFactory.getLogger(WriteMode.class);
private static final int ONE_MEGABYTE = 1024 * 1024;
private final Parameters parameters;
private final Configuration configuration;
private final FileContext fileContext;
WriteMode(Parameters parameters, Configuration configuration) throws UnsupportedFileSystemException {
if (parameters == null) throw new IllegalArgumentException();
if (configuration == null) throw new IllegalArgumentException();
this.parameters = parameters;
this.configuration = configuration;
fileContext = FileContext.getFileContext(configuration);
}
void run() throws IOException, InterruptedException, NoSuchAlgorithmException {
// Write files
List<Path> files = write();
// Wait for replication
waitForReplication(files);
}
private List<Path> write() throws IOException, NoSuchAlgorithmException {
List<Path> files = new ArrayList<Path>();
MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
Random random = new Random();
// Create test directory
Path outputDirectory = fileContext.makeQualified(new Path(parameters.outputDirectory));
if (!fileContext.util().exists(outputDirectory)) {
LOG.info("Creating non-existent directory {}", outputDirectory);
fileContext.mkdir(outputDirectory, FsPermission.getDirDefault(), true);
}
fileContext.setWorkingDirectory(outputDirectory);
LOG.debug("Working directory is now {}", fileContext.getWorkingDirectory().toString());
// Create files
for (int j = 0; j < parameters.count; ++j) {
Path file = null;
FSDataOutputStream outputStream = null;
String digest = null;
long size = (parameters.minsize + random.nextInt(parameters.maxsize - parameters.minsize + 1))
* (long) ONE_MEGABYTE;
try {
// Create file
file = new Path(Long.toString(System.currentTimeMillis()));
long blockSize = file.getFileSystem(configuration).getDefaultBlockSize(file);
outputStream = fileContext.create(
file, EnumSet.of(CreateFlag.CREATE, CreateFlag.OVERWRITE),
Options.CreateOpts.createParent(), Options.CreateOpts.blockSize(blockSize));
// Write random bytes
long currentSize = size;
byte[] bytes = new byte[ONE_MEGABYTE]; // 1 megabyte
while (currentSize > 0) {
long length = Math.min(currentSize, ONE_MEGABYTE);
random.nextBytes(bytes);
messageDigest.update(bytes, 0, (int) length);
outputStream.write(bytes, 0, (int) length);
currentSize -= length;
}
// Get the digest string
digest = Utils.getHexString(messageDigest.digest());
} finally {
if (outputStream != null) {
outputStream.close();
}
}
// Rename to digest string
Path digestFile = fileContext.makeQualified(new Path(digest));
fileContext.rename(file, digestFile, Options.Rename.OVERWRITE);
files.add(digestFile);
// Create control file
Path controlFile = new Path(digestFile + ".control");
SequenceFile.Writer writer = SequenceFile.createWriter(configuration,
SequenceFile.Writer.file(controlFile),
SequenceFile.Writer.keyClass(Text.class),
SequenceFile.Writer.valueClass(LongWritable.class),
SequenceFile.Writer.compression(SequenceFile.CompressionType.NONE));
writer.append(new Text(controlFile.toUri().getPath()), new LongWritable(size));
writer.close();
LOG.info("Created file {}", digestFile.toString());
}
return files;
}
private void waitForReplication(List<Path> files) throws IOException, InterruptedException {
assert files != null;
for (Path file : files) {
FileStatus status = fileContext.getFileStatus(file);
short replication = status.getReplication();
LOG.info("Waiting for replication to adjust to factor {} for file {}",
replication, file.toString());
boolean done = false;
while (!done) {
done = true;
// For each block location, check number of hosts
BlockLocation[] locations = fileContext.getFileBlockLocations(file, 0, status.getLen());
for (BlockLocation location : locations) {
if (location.getHosts().length != replication) {
done = false;
break;
}
}
if (!done) {
Thread.sleep(1000);
}
}
LOG.info("Replicated file {}", file.toString());
}
}
}