blob: a87b6a629c6373a86fe020dbe99b3bfdd8b87e40 [file] [log] [blame]
/**
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.ozone.freon;
import org.apache.commons.io.FileUtils;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.ozone.MiniOzoneCluster;
import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.hadoop.ozone.client.ObjectStore;
import org.apache.hadoop.ozone.client.OzoneClientFactory;
import org.apache.hadoop.ozone.client.OzoneVolume;
import org.apache.hadoop.ozone.om.OMConfigKeys;
import org.apache.hadoop.ozone.om.helpers.BucketLayout;
import org.apache.hadoop.ozone.om.lock.OMLockMetrics;
import org.apache.ozone.test.GenericTestUtils;
import org.apache.ratis.server.RaftServer;
import org.apache.ratis.server.raftlog.RaftLog;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
/**
* Test for OmBucketReadWriteFileOps.
*/
public class TestOmBucketReadWriteFileOps {
private String path;
private OzoneConfiguration conf = null;
private MiniOzoneCluster cluster = null;
private ObjectStore store = null;
private static final Logger LOG =
LoggerFactory.getLogger(TestOmBucketReadWriteFileOps.class);
@Before
public void setup() {
path = GenericTestUtils
.getTempPath(TestOmBucketReadWriteFileOps.class.getSimpleName());
GenericTestUtils.setLogLevel(RaftLog.LOG, Level.DEBUG);
GenericTestUtils.setLogLevel(RaftServer.LOG, Level.DEBUG);
File baseDir = new File(path);
baseDir.mkdirs();
}
/**
* Shutdown MiniDFSCluster.
*/
private void shutdown() throws IOException {
if (cluster != null) {
cluster.shutdown();
FileUtils.deleteDirectory(new File(path));
}
}
/**
* Create a MiniDFSCluster for testing.
*
* @throws IOException
*/
private void startCluster() throws Exception {
conf = getOzoneConfiguration();
conf.set(OMConfigKeys.OZONE_DEFAULT_BUCKET_LAYOUT,
BucketLayout.LEGACY.name());
cluster = MiniOzoneCluster.newBuilder(conf).setNumDatanodes(5).build();
cluster.waitForClusterToBeReady();
cluster.waitTobeOutOfSafeMode();
store = OzoneClientFactory.getRpcClient(conf).getObjectStore();
}
protected OzoneConfiguration getOzoneConfiguration() {
return new OzoneConfiguration();
}
@Test
public void testOmBucketReadWriteFileOps() throws Exception {
try {
startCluster();
FileOutputStream out = FileUtils.openOutputStream(new File(path,
"conf"));
cluster.getConf().writeXml(out);
out.getFD().sync();
out.close();
verifyFreonCommand(new ParameterBuilder().setTotalThreadCount(10)
.setNumOfReadOperations(10).setNumOfWriteOperations(5)
.setFileCountForRead(10).setFileCountForWrite(5));
verifyFreonCommand(
new ParameterBuilder().setVolumeName("vol2").setBucketName("bucket1")
.setPrefixFilePath("/dir1/dir2/dir3").setTotalThreadCount(10)
.setNumOfReadOperations(10).setNumOfWriteOperations(5)
.setFileCountForRead(10).setFileCountForWrite(5));
verifyFreonCommand(
new ParameterBuilder().setVolumeName("vol3").setBucketName("bucket1")
.setPrefixFilePath("/").setTotalThreadCount(15)
.setNumOfReadOperations(5).setNumOfWriteOperations(3)
.setFileCountForRead(5).setFileCountForWrite(3));
verifyFreonCommand(
new ParameterBuilder().setVolumeName("vol4").setBucketName("bucket1")
.setPrefixFilePath("/dir1/").setTotalThreadCount(10)
.setNumOfReadOperations(5).setNumOfWriteOperations(3)
.setFileCountForRead(5).setFileCountForWrite(3).
setFileSizeInBytes(64).setBufferSize(16));
verifyFreonCommand(
new ParameterBuilder().setVolumeName("vol5").setBucketName("bucket1")
.setPrefixFilePath("/dir1/dir2/dir3").setTotalThreadCount(10)
.setNumOfReadOperations(5).setNumOfWriteOperations(0)
.setFileCountForRead(5));
verifyFreonCommand(
new ParameterBuilder().setVolumeName("vol6").setBucketName("bucket1")
.setPrefixFilePath("/dir1/dir2/dir3/dir4").setTotalThreadCount(20)
.setNumOfReadOperations(0).setNumOfWriteOperations(5)
.setFileCountForRead(0).setFileCountForWrite(5));
} finally {
shutdown();
}
}
private void verifyFreonCommand(ParameterBuilder parameterBuilder)
throws IOException {
store.createVolume(parameterBuilder.volumeName);
OzoneVolume volume = store.getVolume(parameterBuilder.volumeName);
volume.createBucket(parameterBuilder.bucketName);
String rootPath = "o3fs://" + parameterBuilder.bucketName + "." +
parameterBuilder.volumeName + parameterBuilder.prefixFilePath;
String confPath = new File(path, "conf").getAbsolutePath();
new Freon().execute(
new String[]{"-conf", confPath, "obrwf", "-P", rootPath,
"-r", String.valueOf(parameterBuilder.fileCountForRead),
"-w", String.valueOf(parameterBuilder.fileCountForWrite),
"-g", String.valueOf(parameterBuilder.fileSizeInBytes),
"-b", String.valueOf(parameterBuilder.bufferSize),
"-l", String.valueOf(parameterBuilder.length),
"-c", String.valueOf(parameterBuilder.totalThreadCount),
"-T", String.valueOf(parameterBuilder.readThreadPercentage),
"-R", String.valueOf(parameterBuilder.numOfReadOperations),
"-W", String.valueOf(parameterBuilder.numOfWriteOperations),
"-n", String.valueOf(1)});
LOG.info("Started verifying OM bucket read/write ops file generation...");
FileSystem fileSystem = FileSystem.get(URI.create(rootPath),
conf);
Path rootDir = new Path(rootPath.concat(OzoneConsts.OM_KEY_PREFIX));
FileStatus[] fileStatuses = fileSystem.listStatus(rootDir);
verifyFileCreation(2, fileStatuses, true);
Path readDir = new Path(rootPath.concat("/readPath"));
FileStatus[] readFileStatuses = fileSystem.listStatus(readDir);
verifyFileCreation(parameterBuilder.fileCountForRead, readFileStatuses,
false);
int readThreadCount = (parameterBuilder.readThreadPercentage *
parameterBuilder.totalThreadCount) / 100;
int writeThreadCount = parameterBuilder.totalThreadCount - readThreadCount;
Path writeDir = new Path(rootPath.concat("/writePath"));
FileStatus[] writeFileStatuses = fileSystem.listStatus(writeDir);
verifyFileCreation(writeThreadCount * parameterBuilder.fileCountForWrite *
parameterBuilder.numOfWriteOperations, writeFileStatuses, false);
verifyOMLockMetrics(cluster.getOzoneManager().getMetadataManager().getLock()
.getOMLockMetrics());
}
private void verifyFileCreation(int expectedCount, FileStatus[] fileStatuses,
boolean checkDirectoryCount) {
int actual = 0;
if (checkDirectoryCount) {
for (FileStatus fileStatus : fileStatuses) {
if (fileStatus.isDirectory()) {
++actual;
}
}
} else {
for (FileStatus fileStatus : fileStatuses) {
if (fileStatus.isFile()) {
++actual;
}
}
}
Assert.assertEquals("Mismatch Count!", expectedCount, actual);
}
private void verifyOMLockMetrics(OMLockMetrics omLockMetrics) {
String readLockWaitingTimeMsStat =
omLockMetrics.getReadLockWaitingTimeMsStat();
LOG.info("Read Lock Waiting Time Stat: " + readLockWaitingTimeMsStat);
LOG.info("Longest Read Lock Waiting Time (ms): " +
omLockMetrics.getLongestReadLockWaitingTimeMs());
int readWaitingSamples =
Integer.parseInt(readLockWaitingTimeMsStat.split(" ")[2]);
Assert.assertTrue("Read Lock Waiting Samples should be positive",
readWaitingSamples > 0);
String readLockHeldTimeMsStat = omLockMetrics.getReadLockHeldTimeMsStat();
LOG.info("Read Lock Held Time Stat: " + readLockHeldTimeMsStat);
LOG.info("Longest Read Lock Held Time (ms): " +
omLockMetrics.getLongestReadLockHeldTimeMs());
int readHeldSamples =
Integer.parseInt(readLockHeldTimeMsStat.split(" ")[2]);
Assert.assertTrue("Read Lock Held Samples should be positive",
readHeldSamples > 0);
String writeLockWaitingTimeMsStat =
omLockMetrics.getWriteLockWaitingTimeMsStat();
LOG.info("Write Lock Waiting Time Stat: " + writeLockWaitingTimeMsStat);
LOG.info("Longest Write Lock Waiting Time (ms): " +
omLockMetrics.getLongestWriteLockWaitingTimeMs());
int writeWaitingSamples =
Integer.parseInt(writeLockWaitingTimeMsStat.split(" ")[2]);
Assert.assertTrue("Write Lock Waiting Samples should be positive",
writeWaitingSamples > 0);
String writeLockHeldTimeMsStat = omLockMetrics.getWriteLockHeldTimeMsStat();
LOG.info("Write Lock Held Time Stat: " + writeLockHeldTimeMsStat);
LOG.info("Longest Write Lock Held Time (ms): " +
omLockMetrics.getLongestWriteLockHeldTimeMs());
int writeHeldSamples =
Integer.parseInt(writeLockHeldTimeMsStat.split(" ")[2]);
Assert.assertTrue("Write Lock Held Samples should be positive",
writeHeldSamples > 0);
}
private static class ParameterBuilder {
private String volumeName = "vol1";
private String bucketName = "bucket1";
private String prefixFilePath = "/dir1/dir2";
private int fileCountForRead = 100;
private int fileCountForWrite = 10;
private long fileSizeInBytes = 256;
private int bufferSize = 64;
private int length = 10;
private int totalThreadCount = 100;
private int readThreadPercentage = 90;
private int numOfReadOperations = 50;
private int numOfWriteOperations = 10;
private ParameterBuilder setVolumeName(String volumeNameParam) {
volumeName = volumeNameParam;
return this;
}
private ParameterBuilder setBucketName(String bucketNameParam) {
bucketName = bucketNameParam;
return this;
}
private ParameterBuilder setPrefixFilePath(String prefixFilePathParam) {
prefixFilePath = prefixFilePathParam;
return this;
}
private ParameterBuilder setFileCountForRead(int fileCountForReadParam) {
fileCountForRead = fileCountForReadParam;
return this;
}
private ParameterBuilder setFileCountForWrite(int fileCountForWriteParam) {
fileCountForWrite = fileCountForWriteParam;
return this;
}
private ParameterBuilder setFileSizeInBytes(long fileSizeInBytesParam) {
fileSizeInBytes = fileSizeInBytesParam;
return this;
}
private ParameterBuilder setBufferSize(int bufferSizeParam) {
bufferSize = bufferSizeParam;
return this;
}
private ParameterBuilder setLength(int lengthParam) {
length = lengthParam;
return this;
}
private ParameterBuilder setTotalThreadCount(int totalThreadCountParam) {
totalThreadCount = totalThreadCountParam;
return this;
}
private ParameterBuilder setReadThreadPercentage(
int readThreadPercentageParam) {
readThreadPercentage = readThreadPercentageParam;
return this;
}
private ParameterBuilder setNumOfReadOperations(
int numOfReadOperationsParam) {
numOfReadOperations = numOfReadOperationsParam;
return this;
}
private ParameterBuilder setNumOfWriteOperations(
int numOfWriteOperationsParam) {
numOfWriteOperations = numOfWriteOperationsParam;
return this;
}
}
}