/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.fs.slive; import java.io.IOException; import java.util.List; import java.util.Random; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.slive.DataWriter.GenerateOutput; import org.apache.hadoop.fs.slive.OperationOutput.OutputType; /** * Operation which selects a random file and a random number of bytes to create * that file with (from the write size option) and selects a random block size * (from the block size option) and a random replication amount (from the * replication option) and attempts to create a file with those options. * * This operation will capture statistics on success for bytes written, time * taken (milliseconds), and success count and on failure it will capture the * number of failures and the time taken (milliseconds) to fail. */ class CreateOp extends Operation { private static final Log LOG = LogFactory.getLog(CreateOp.class); private static int DEF_IO_BUFFER_SIZE = 4096; private static final String IO_BUF_CONFIG = ("io.file.buffer.size"); CreateOp(ConfigExtractor cfg, Random rnd) { super(CreateOp.class.getSimpleName(), cfg, rnd); } /** * Returns the block size to use (aligned to nearest BYTES_PER_CHECKSUM if * configuration says a value exists) - this will avoid the warnings caused by * this not occurring and the file will not be created if it is not correct... * * @return long */ private long determineBlockSize() { Range<Long> blockSizeRange = getConfig().getBlockSize(); long blockSize = Range.betweenPositive(getRandom(), blockSizeRange); Long byteChecksum = getConfig().getByteCheckSum(); if (byteChecksum == null) { return blockSize; } // adjust to nearest multiple long full = (blockSize / byteChecksum) * byteChecksum; long toFull = blockSize - full; if (toFull >= (byteChecksum / 2)) { full += byteChecksum; } // adjust if over extended if (full > blockSizeRange.getUpper()) { full = blockSizeRange.getUpper(); } if (full < blockSizeRange.getLower()) { full = blockSizeRange.getLower(); } return full; } /** * Gets the replication amount * * @return short */ private short determineReplication() { Range<Short> replicationAmountRange = getConfig().getReplication(); Range<Long> repRange = new Range<Long>(replicationAmountRange.getLower() .longValue(), replicationAmountRange.getUpper().longValue()); short replicationAmount = (short) Range.betweenPositive(getRandom(), repRange); return replicationAmount; } /** * Gets the output buffering size to use * * @return int */ private int getBufferSize() { return getConfig().getConfig().getInt(IO_BUF_CONFIG, DEF_IO_BUFFER_SIZE); } /** * Gets the file to create * * @return Path */ protected Path getCreateFile() { Path fn = getFinder().getFile(); return fn; } @Override // Operation List<OperationOutput> run(FileSystem fs) { List<OperationOutput> out = super.run(fs); FSDataOutputStream os = null; try { Path fn = getCreateFile(); Range<Long> writeSizeRange = getConfig().getWriteSize(); long writeSize = 0; long blockSize = determineBlockSize(); short replicationAmount = determineReplication(); if (getConfig().shouldWriteUseBlockSize()) { writeSizeRange = getConfig().getBlockSize(); } writeSize = Range.betweenPositive(getRandom(), writeSizeRange); long bytesWritten = 0; long timeTaken = 0; int bufSize = getBufferSize(); boolean overWrite = false; DataWriter writer = new DataWriter(getRandom()); LOG.info("Attempting to create file at " + fn + " of size " + Helper.toByteInfo(writeSize) + " using blocksize " + Helper.toByteInfo(blockSize) + " and replication amount " + replicationAmount); { // open & create long startTime = Timer.now(); os = fs.create(fn, overWrite, bufSize, replicationAmount, blockSize); timeTaken += Timer.elapsed(startTime); // write the given length GenerateOutput stats = writer.writeSegment(writeSize, os); bytesWritten += stats.getBytesWritten(); timeTaken += stats.getTimeTaken(); // capture close time startTime = Timer.now(); os.close(); os = null; timeTaken += Timer.elapsed(startTime); } LOG.info("Created file at " + fn + " of size " + Helper.toByteInfo(bytesWritten) + " bytes using blocksize " + Helper.toByteInfo(blockSize) + " and replication amount " + replicationAmount + " in " + timeTaken + " milliseconds"); // collect all the stats out.add(new OperationOutput(OutputType.LONG, getType(), ReportWriter.OK_TIME_TAKEN, timeTaken)); out.add(new OperationOutput(OutputType.LONG, getType(), ReportWriter.BYTES_WRITTEN, bytesWritten)); out.add(new OperationOutput(OutputType.LONG, getType(), ReportWriter.SUCCESSES, 1L)); } catch (IOException e) { out.add(new OperationOutput(OutputType.LONG, getType(), ReportWriter.FAILURES, 1L)); LOG.warn("Error with creating", e); } finally { if (os != null) { try { os.close(); } catch (IOException e) { LOG.warn("Error closing create stream", e); } } } return out; } }