If unspecified, the default order of credential providers is: 1. org.apache.hadoop.fs.auth.SimpleCredentialProvider; 2. org.apache.hadoop.fs.auth.EnvironmentVariableCredentialProvider. | None | NO |
+| fs.cosn.userinfo.secretId/secretKey | The API key information of your account | None | YES |
+| fs.cosn.bucket.region | The region where the bucket is located. | None | YES |
+| fs.cosn.impl | The implementation class of the CosN filesystem. | None | YES |
+| fs.AbstractFileSystem.cosn.impl | The implementation class of the CosN AbstractFileSystem. | None | YES |
+| fs.cosn.tmp.dir | Temporary files generated by cosn would be stored here during the program running. | /tmp/hadoop_cos | NO |
+| fs.cosn.buffer.size | The total size of the buffer pool. Require greater than or equal to block size. | 33554432 | NO |
+| fs.cosn.block.size | The size of file block. Considering the limitation that each file can be divided into a maximum of 10,000 to upload, the option must be set according to the maximum size of used single file. For example, 8MB part size can allow writing a 78GB single file. | 8388608 | NO |
+| fs.cosn.upload_thread_pool | Number of threads used for concurrent uploads when files are streamed to COS. | CPU core number * 3 | NO |
+| fs.cosn.read.ahead.block.size | The size of each read-ahead block. | 524288 (512KB) | NO |
+| fs.cosn.read.ahead.queue.size | The length of readahead queue. | 10 | NO |
+| fs.cosn.maxRetries | The maxium number of retries for reading or writing files to COS, before throwing a failure to the application. | 3 | NO |
+| fs.cosn.retry.interval.seconds | The number of seconds to sleep between each retry | 3 | NO |
+
+
+#### Command Usage
+
+Command format: `hadoop fs -ls -R cosn://bucket-appid/` or `hadoop fs -ls -R /`, the latter requires the defaultFs option to be set as `cosn`.
+
+
+#### Example
+
+Use CosN as the underlying file system to run the WordCount routine:
+
+```shell
+bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-x.x.x.jar wordcount cosn://example/mr/input.txt cosn://example/mr/output
+```
+
+If setting CosN as the default file system for Hadoop, you can run it as follows:
+
+```shell
+bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-x.x.x.jar wordcount /mr/input.txt /mr/output
+```
+
+## Testing the hadoop-cos Module
+
+To test CosN filesystem, the following two files which pass in authentication details to the test runner are needed.
+
+1. auth-keys.xml
+2. core-site.xml
+
+These two files need to be created under the `hadoop-cloud-storage-project/hadoop-cos/src/test/resource` directory.
+
+
+### `auth-key.xml`
+
+COS credentials can specified in `auth-key.xml`. At the same time, it is also a trigger for the CosN filesystem tests.
+COS bucket URL should be provided by specifying the option: `test.fs.cosn.name`.
+
+An example of the `auth-keys.xml` is as follow:
+
+```xml
+
+
+ test.fs.cosn.name
+ cosn://testbucket-12xxxxxx
+
+
+ fs.cosn.bucket.region
+ ap-xxx
+ The region where the bucket is located
+
+
+ fs.cosn.userinfo.secretId
+ AKIDXXXXXXXXXXXXXXXXXXXX
+
+
+ fs.cosn.userinfo.secretKey
+ xxxxxxxxxxxxxxxxxxxxxxxxx
+
+
+
+
+```
+
+Without this file, all tests in this module will be skipped.
+
+### `core-site.xml`
+
+This file pre-exists and sources the configurations created in auth-keys.xml.
+For most cases, no modification is needed, unless a specific, non-default property needs to be set during the testing.
+
+### `contract-test-options.xml`
+
+All configurations related to support contract tests need to be specified in `contract-test-options.xml`. Here is an example of `contract-test-options.xml`.
+
+```xml
+
+
+
+
+
+ fs.contract.test.fs.cosn
+ cosn://testbucket-12xxxxxx
+
+
+
+ fs.cosn.bucket.region
+ ap-xxx
+ The region where the bucket is located
+
+
+
+
+```
+
+If the option `fs.contract.test.fs.cosn` not definded in the file, all contract tests will be skipped.
+
+## Other issues
+
+### Performance Loss
+
+The IO performance of COS is lower than HDFS in principle, even on virtual clusters running on Tencent CVM.
+
+The main reason can be attributed to the following points:
+
+- HDFS replicates data for faster query.
+
+- HDFS is significantly faster for many “metadata” operations: listing the contents of a directory, calling getFileStatus() on path, creating or deleting directories.
+
+- HDFS stores the data on the local hard disks, avoiding network traffic if the code can be executed on that host. But access to the object storing in COS requires access to network almost each time. It is a critical point in damaging IO performance. Hadoop-COS also do a lot of optimization work for it, such as the pre-read queue, the upload buffer pool, the concurrent upload thread pool, etc.
+
+- File IO performing many seek calls/positioned read calls will also encounter performance problems due to the size of the HTTP requests made. Despite the pre-read cache optimizations, a large number of random reads can still cause frequent network requests.
+
+- On HDFS, both the `rename` and `mv` for a directory or a file are an atomic and O(1)-level operation, but in COS, the operation need to combine `copy` and `delete` sequentially. Therefore, performing rename and move operations on a COS object is not only low performance, but also difficult to guarantee data consistency.
+
+At present, using the COS blob storage system through Hadoop-COS occurs about 20% ~ 25% performance loss compared to HDFS. But, the cost of using COS is lower than HDFS, which includes both storage and maintenance costs.
diff --git a/hadoop-submarine/hadoop-submarine-tony-runtime/src/site/resources/css/site.css b/hadoop-cloud-storage-project/hadoop-cos/site/resources/css/site.css
similarity index 100%
rename from hadoop-submarine/hadoop-submarine-tony-runtime/src/site/resources/css/site.css
rename to hadoop-cloud-storage-project/hadoop-cos/site/resources/css/site.css
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/BufferPool.java b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/BufferPool.java
new file mode 100644
index 0000000000000..a4ee4d5be9ac8
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/BufferPool.java
@@ -0,0 +1,245 @@
+/**
+ * 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
+ *
+ * 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.cosn;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.hadoop.conf.Configuration;
+
+/**
+ * BufferPool class is used to manage the buffers during program execution.
+ * It is provided in a thread-safe singleton mode,and
+ * keeps the program's memory and disk consumption at a stable value.
+ */
+public final class BufferPool {
+ private static final Logger LOG =
+ LoggerFactory.getLogger(BufferPool.class);
+
+ private static BufferPool ourInstance = new BufferPool();
+
+ /**
+ * Use this method to get the instance of BufferPool.
+ *
+ * @return the instance of BufferPool
+ */
+ public static BufferPool getInstance() {
+ return ourInstance;
+ }
+
+ private BlockingQueue bufferPool = null;
+ private long singleBufferSize = 0;
+ private File diskBufferDir = null;
+
+ private AtomicBoolean isInitialize = new AtomicBoolean(false);
+
+ private BufferPool() {
+ }
+
+ private File createDir(String dirPath) throws IOException {
+ File dir = new File(dirPath);
+ if (null != dir) {
+ if (!dir.exists()) {
+ LOG.debug("Buffer dir: [{}] does not exists. create it first.",
+ dirPath);
+ if (dir.mkdirs()) {
+ if (!dir.setWritable(true) || !dir.setReadable(true)
+ || !dir.setExecutable(true)) {
+ LOG.warn("Set the buffer dir: [{}]'s permission [writable,"
+ + "readable, executable] failed.", dir.getAbsolutePath());
+ }
+ LOG.debug("Buffer dir: [{}] is created successfully.",
+ dir.getAbsolutePath());
+ } else {
+ // Once again, check if it has been created successfully.
+ // Prevent problems created by multiple processes at the same time.
+ if (!dir.exists()) {
+ throw new IOException("buffer dir:" + dir.getAbsolutePath()
+ + " is created unsuccessfully");
+ }
+ }
+ } else {
+ LOG.debug("buffer dir: {} already exists.", dirPath);
+ }
+ } else {
+ throw new IOException("creating buffer dir: " + dir.getAbsolutePath()
+ + "unsuccessfully.");
+ }
+
+ return dir;
+ }
+
+ /**
+ * Create buffers correctly by reading the buffer file directory,
+ * buffer pool size,and file block size in the configuration.
+ *
+ * @param conf Provides configurations for the Hadoop runtime
+ * @throws IOException Configuration errors,
+ * insufficient or no access for memory or
+ * disk space may cause this exception
+ */
+ public synchronized void initialize(Configuration conf)
+ throws IOException {
+ if (this.isInitialize.get()) {
+ return;
+ }
+ this.singleBufferSize = conf.getLong(CosNConfigKeys.COSN_BLOCK_SIZE_KEY,
+ CosNConfigKeys.DEFAULT_BLOCK_SIZE);
+
+ // The block size of CosN can only support up to 2GB.
+ if (this.singleBufferSize < Constants.MIN_PART_SIZE
+ || this.singleBufferSize > Constants.MAX_PART_SIZE) {
+ String exceptionMsg = String.format(
+ "The block size of CosN is limited to %d to %d",
+ Constants.MIN_PART_SIZE, Constants.MAX_PART_SIZE);
+ throw new IOException(exceptionMsg);
+ }
+
+ long memoryBufferLimit = conf.getLong(
+ CosNConfigKeys.COSN_UPLOAD_BUFFER_SIZE_KEY,
+ CosNConfigKeys.DEFAULT_UPLOAD_BUFFER_SIZE);
+
+ this.diskBufferDir = this.createDir(conf.get(
+ CosNConfigKeys.COSN_BUFFER_DIR_KEY,
+ CosNConfigKeys.DEFAULT_BUFFER_DIR));
+
+ int bufferPoolSize = (int) (memoryBufferLimit / this.singleBufferSize);
+ if (0 == bufferPoolSize) {
+ throw new IOException(
+ String.format("The total size of the buffer [%d] is " +
+ "smaller than a single block [%d]."
+ + "please consider increase the buffer size " +
+ "or decrease the block size",
+ memoryBufferLimit, this.singleBufferSize));
+ }
+ this.bufferPool = new LinkedBlockingQueue<>(bufferPoolSize);
+ for (int i = 0; i < bufferPoolSize; i++) {
+ this.bufferPool.add(ByteBuffer.allocateDirect(
+ (int) this.singleBufferSize));
+ }
+
+ this.isInitialize.set(true);
+ }
+
+ /**
+ * Check if the buffer pool has been initialized.
+ *
+ * @throws IOException if the buffer pool is not initialized
+ */
+ private void checkInitialize() throws IOException {
+ if (!this.isInitialize.get()) {
+ throw new IOException(
+ "The buffer pool has not been initialized yet");
+ }
+ }
+
+ /**
+ * Obtain a buffer from this buffer pool through the method.
+ *
+ * @param bufferSize expected buffer size to get
+ * @return a buffer wrapper that satisfies the bufferSize.
+ * @throws IOException if the buffer pool not initialized,
+ * or the bufferSize parameter is not within
+ * the range[1MB to the single buffer size]
+ */
+ public ByteBufferWrapper getBuffer(int bufferSize) throws IOException {
+ this.checkInitialize();
+ if (bufferSize > 0 && bufferSize <= this.singleBufferSize) {
+ ByteBufferWrapper byteBufferWrapper = this.getByteBuffer();
+ if (null == byteBufferWrapper) {
+ // Use a disk buffer when the memory buffer is not enough
+ byteBufferWrapper = this.getMappedBuffer();
+ }
+ return byteBufferWrapper;
+ } else {
+ String exceptionMsg = String.format(
+ "Parameter buffer size out of range: 1048576 to %d",
+ this.singleBufferSize
+ );
+ throw new IOException(exceptionMsg);
+ }
+ }
+
+ /**
+ * Get a ByteBufferWrapper from the buffer pool.
+ *
+ * @return a new byte buffer wrapper
+ * @throws IOException if the buffer pool is not initialized
+ */
+ private ByteBufferWrapper getByteBuffer() throws IOException {
+ this.checkInitialize();
+ ByteBuffer buffer = this.bufferPool.poll();
+ return buffer == null ? null : new ByteBufferWrapper(buffer);
+ }
+
+ /**
+ * Get a mapped buffer from the buffer pool.
+ *
+ * @return a new mapped buffer
+ * @throws IOException If the buffer pool is not initialized.
+ * or some I/O error occurs
+ */
+ private ByteBufferWrapper getMappedBuffer() throws IOException {
+ this.checkInitialize();
+ File tmpFile = File.createTempFile(Constants.BLOCK_TMP_FILE_PREFIX,
+ Constants.BLOCK_TMP_FILE_SUFFIX, this.diskBufferDir);
+ tmpFile.deleteOnExit();
+ RandomAccessFile raf = new RandomAccessFile(tmpFile, "rw");
+ raf.setLength(this.singleBufferSize);
+ MappedByteBuffer buf = raf.getChannel().map(
+ FileChannel.MapMode.READ_WRITE, 0, this.singleBufferSize);
+ return new ByteBufferWrapper(buf, raf, tmpFile);
+ }
+
+ /**
+ * return the byte buffer wrapper to the buffer pool.
+ *
+ * @param byteBufferWrapper the byte buffer wrapper getting from the pool
+ * @throws InterruptedException if interrupted while waiting
+ * @throws IOException some io error occurs
+ */
+ public void returnBuffer(ByteBufferWrapper byteBufferWrapper)
+ throws InterruptedException, IOException {
+ if (null == this.bufferPool || null == byteBufferWrapper) {
+ return;
+ }
+
+ if (byteBufferWrapper.isDiskBuffer()) {
+ byteBufferWrapper.close();
+ } else {
+ ByteBuffer byteBuffer = byteBufferWrapper.getByteBuffer();
+ if (null != byteBuffer) {
+ byteBuffer.clear();
+ LOG.debug("Return the buffer to the buffer pool.");
+ if (!this.bufferPool.offer(byteBuffer)) {
+ LOG.error("Return the buffer to buffer pool failed.");
+ }
+ }
+ }
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/ByteBufferInputStream.java b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/ByteBufferInputStream.java
new file mode 100644
index 0000000000000..440a7deda09d8
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/ByteBufferInputStream.java
@@ -0,0 +1,89 @@
+/**
+ * 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
+ *
+ * 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.cosn;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.InvalidMarkException;
+
+/**
+ * The input stream class is used for buffered files.
+ * The purpose of providing this class is to optimize buffer read performance.
+ */
+public class ByteBufferInputStream extends InputStream {
+ private ByteBuffer byteBuffer;
+ private boolean isClosed;
+
+ public ByteBufferInputStream(ByteBuffer byteBuffer) throws IOException {
+ if (null == byteBuffer) {
+ throw new IOException("byte buffer is null");
+ }
+ this.byteBuffer = byteBuffer;
+ this.isClosed = false;
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (null == this.byteBuffer) {
+ throw new IOException("this byte buffer for InputStream is null");
+ }
+ if (!this.byteBuffer.hasRemaining()) {
+ return -1;
+ }
+ return this.byteBuffer.get() & 0xFF;
+ }
+
+ @Override
+ public synchronized void mark(int readLimit) {
+ if (!this.markSupported()) {
+ return;
+ }
+ this.byteBuffer.mark();
+ // Parameter readLimit is ignored
+ }
+
+ @Override
+ public boolean markSupported() {
+ return true;
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ if (this.isClosed) {
+ throw new IOException("Closed in InputStream");
+ }
+ try {
+ this.byteBuffer.reset();
+ } catch (InvalidMarkException e) {
+ throw new IOException("Invalid mark");
+ }
+ }
+
+ @Override
+ public int available() {
+ return this.byteBuffer.remaining();
+ }
+
+ @Override
+ public void close() {
+ this.byteBuffer.rewind();
+ this.byteBuffer = null;
+ this.isClosed = true;
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/ByteBufferOutputStream.java b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/ByteBufferOutputStream.java
new file mode 100644
index 0000000000000..9e6a6fc5f3663
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/ByteBufferOutputStream.java
@@ -0,0 +1,74 @@
+/**
+ * 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
+ *
+ * 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.cosn;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+
+/**
+ * The input stream class is used for buffered files.
+ * The purpose of providing this class is to optimize buffer write performance.
+ */
+public class ByteBufferOutputStream extends OutputStream {
+ private ByteBuffer byteBuffer;
+ private boolean isFlush;
+ private boolean isClosed;
+
+ public ByteBufferOutputStream(ByteBuffer byteBuffer) throws IOException {
+ if (null == byteBuffer) {
+ throw new IOException("byte buffer is null");
+ }
+ this.byteBuffer = byteBuffer;
+ this.byteBuffer.clear();
+ this.isFlush = false;
+ this.isClosed = false;
+ }
+
+ @Override
+ public void write(int b) {
+ byte[] singleBytes = new byte[1];
+ singleBytes[0] = (byte) b;
+ this.byteBuffer.put(singleBytes, 0, 1);
+ this.isFlush = false;
+ }
+
+ @Override
+ public void flush() {
+ if (this.isFlush) {
+ return;
+ }
+ this.isFlush = true;
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (this.isClosed) {
+ return;
+ }
+ if (null == this.byteBuffer) {
+ throw new IOException("Can not close a null object");
+ }
+
+ this.flush();
+ this.byteBuffer.flip();
+ this.byteBuffer = null;
+ this.isFlush = false;
+ this.isClosed = true;
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/ByteBufferWrapper.java b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/ByteBufferWrapper.java
new file mode 100644
index 0000000000000..a7d1c5fffce0e
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/ByteBufferWrapper.java
@@ -0,0 +1,103 @@
+/**
+ * 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
+ *
+ * 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.cosn;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.hadoop.util.CleanerUtil;
+
+/**
+ * The wrapper for memory buffers and disk buffers.
+ */
+public class ByteBufferWrapper {
+ private static final Logger LOG =
+ LoggerFactory.getLogger(ByteBufferWrapper.class);
+ private ByteBuffer byteBuffer;
+ private File file;
+ private RandomAccessFile randomAccessFile;
+
+ ByteBufferWrapper(ByteBuffer byteBuffer) {
+ this(byteBuffer, null, null);
+ }
+
+ ByteBufferWrapper(ByteBuffer byteBuffer, RandomAccessFile randomAccessFile,
+ File file) {
+ this.byteBuffer = byteBuffer;
+ this.file = file;
+ this.randomAccessFile = randomAccessFile;
+ }
+
+ public ByteBuffer getByteBuffer() {
+ return this.byteBuffer;
+ }
+
+ boolean isDiskBuffer() {
+ return this.file != null && this.randomAccessFile != null;
+ }
+
+ private void munmap(MappedByteBuffer buffer) {
+ if (CleanerUtil.UNMAP_SUPPORTED) {
+ try {
+ CleanerUtil.getCleaner().freeBuffer(buffer);
+ } catch (IOException e) {
+ LOG.warn("Failed to unmap the buffer", e);
+ }
+ } else {
+ LOG.trace(CleanerUtil.UNMAP_NOT_SUPPORTED_REASON);
+ }
+ }
+
+ void close() throws IOException {
+ if (null != this.byteBuffer) {
+ this.byteBuffer.clear();
+ }
+
+ IOException exception = null;
+ // catch all exceptions, and try to free up resources that can be freed.
+ try {
+ if (null != randomAccessFile) {
+ this.randomAccessFile.close();
+ }
+ } catch (IOException e) {
+ LOG.error("Close the random access file occurs an exception.", e);
+ exception = e;
+ }
+
+ if (this.byteBuffer instanceof MappedByteBuffer) {
+ munmap((MappedByteBuffer) this.byteBuffer);
+ }
+
+ if (null != this.file && this.file.exists()) {
+ if (!this.file.delete()) {
+ LOG.warn("Delete the tmp file: [{}] failed.",
+ this.file.getAbsolutePath());
+ }
+ }
+
+ if (null != exception) {
+ throw exception;
+ }
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/Constants.java b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/Constants.java
new file mode 100644
index 0000000000000..f67e07ecff370
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/Constants.java
@@ -0,0 +1,43 @@
+/**
+ * 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
+ *
+ * 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.cosn;
+
+/**
+ * constant definition.
+ */
+public final class Constants {
+ private Constants() {
+ }
+
+ public static final String BLOCK_TMP_FILE_PREFIX = "cos_";
+ public static final String BLOCK_TMP_FILE_SUFFIX = "_local_block";
+
+ // The maximum number of files listed in a single COS list request.
+ public static final int COS_MAX_LISTING_LENGTH = 999;
+
+ // The maximum number of parts supported by a multipart uploading.
+ public static final int MAX_PART_NUM = 10000;
+
+ // The maximum size of a part
+ public static final long MAX_PART_SIZE = (long) 2 * Unit.GB;
+ // The minimum size of a part
+ public static final long MIN_PART_SIZE = (long) Unit.MB;
+
+ public static final String COSN_SECRET_ID_ENV = "COSN_SECRET_ID";
+ public static final String COSN_SECRET_KEY_ENV = "COSN_SECRET_KEY";
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosN.java b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosN.java
new file mode 100644
index 0000000000000..990fcbd56b3bb
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosN.java
@@ -0,0 +1,41 @@
+/**
+ * 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
+ *
+ * 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.cosn;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.DelegateToFileSystem;
+
+/**
+ * CosN implementation for the Hadoop's AbstractFileSystem.
+ * This implementation delegates to the CosNFileSystem {@link CosNFileSystem}.
+ */
+public class CosN extends DelegateToFileSystem {
+ public CosN(URI theUri, Configuration conf)
+ throws IOException, URISyntaxException {
+ super(theUri, new CosNFileSystem(), conf, CosNFileSystem.SCHEME, false);
+ }
+
+ @Override
+ public int getUriDefaultPort() {
+ return -1;
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNConfigKeys.java b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNConfigKeys.java
new file mode 100644
index 0000000000000..4d98d5f7e2961
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNConfigKeys.java
@@ -0,0 +1,86 @@
+/**
+ * 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
+ *
+ * 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.cosn;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.fs.CommonConfigurationKeys;
+
+/**
+ * This class contains constants for configuration keys used in COS.
+ */
+@InterfaceAudience.Private
+@InterfaceStability.Unstable
+public class CosNConfigKeys extends CommonConfigurationKeys {
+ public static final String USER_AGENT = "fs.cosn.user.agent";
+ public static final String DEFAULT_USER_AGENT = "cos-hadoop-plugin-v5.3";
+
+ public static final String COSN_CREDENTIALS_PROVIDER =
+ "fs.cosn.credentials.provider";
+ public static final String COSN_SECRET_ID_KEY = "fs.cosn.userinfo.secretId";
+ public static final String COSN_SECRET_KEY_KEY = "fs.cosn.userinfo.secretKey";
+ public static final String COSN_REGION_KEY = "fs.cosn.bucket.region";
+ public static final String COSN_ENDPOINT_SUFFIX_KEY =
+ "fs.cosn.bucket.endpoint_suffix";
+
+ public static final String COSN_USE_HTTPS_KEY = "fs.cosn.useHttps";
+ public static final boolean DEFAULT_USE_HTTPS = false;
+
+ public static final String COSN_BUFFER_DIR_KEY = "fs.cosn.tmp.dir";
+ public static final String DEFAULT_BUFFER_DIR = "/tmp/hadoop_cos";
+
+ public static final String COSN_UPLOAD_BUFFER_SIZE_KEY =
+ "fs.cosn.buffer.size";
+ public static final long DEFAULT_UPLOAD_BUFFER_SIZE = 32 * Unit.MB;
+
+ public static final String COSN_BLOCK_SIZE_KEY = "fs.cosn.block.size";
+ public static final long DEFAULT_BLOCK_SIZE = 8 * Unit.MB;
+
+ public static final String COSN_MAX_RETRIES_KEY = "fs.cosn.maxRetries";
+ public static final int DEFAULT_MAX_RETRIES = 3;
+ public static final String COSN_RETRY_INTERVAL_KEY =
+ "fs.cosn.retry.interval.seconds";
+ public static final long DEFAULT_RETRY_INTERVAL = 3;
+
+ public static final String UPLOAD_THREAD_POOL_SIZE_KEY =
+ "fs.cosn.upload_thread_pool";
+ public static final int DEFAULT_UPLOAD_THREAD_POOL_SIZE = 1;
+
+ public static final String COPY_THREAD_POOL_SIZE_KEY =
+ "fs.cosn.copy_thread_pool";
+ public static final int DEFAULT_COPY_THREAD_POOL_SIZE = 1;
+
+ /**
+ * This is the maximum time that excess idle threads will wait for new tasks
+ * before terminating. The time unit for it is second.
+ */
+ public static final String THREAD_KEEP_ALIVE_TIME_KEY =
+ "fs.cosn.threads.keep_alive_time";
+ // The default keep_alive_time is 60 seconds.
+ public static final long DEFAULT_THREAD_KEEP_ALIVE_TIME = 60L;
+
+ public static final String READ_AHEAD_BLOCK_SIZE_KEY =
+ "fs.cosn.read.ahead.block.size";
+ public static final long DEFAULT_READ_AHEAD_BLOCK_SIZE = 512 * Unit.KB;
+ public static final String READ_AHEAD_QUEUE_SIZE =
+ "fs.cosn.read.ahead.queue.size";
+ public static final int DEFAULT_READ_AHEAD_QUEUE_SIZE = 5;
+
+ public static final String MAX_CONNECTION_NUM = "fs.cosn.max.connection.num";
+ public static final int DEFAULT_MAX_CONNECTION_NUM = 2048;
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNCopyFileContext.java b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNCopyFileContext.java
new file mode 100644
index 0000000000000..39a2e91351f23
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNCopyFileContext.java
@@ -0,0 +1,66 @@
+/**
+ * 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
+ *
+ * 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.cosn;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * The context of the copy task, including concurrency control,
+ * asynchronous acquisition of copy results and etc.
+ */
+public class CosNCopyFileContext {
+
+ private final ReentrantLock lock = new ReentrantLock();
+ private Condition readyCondition = lock.newCondition();
+
+ private AtomicBoolean copySuccess = new AtomicBoolean(true);
+ private AtomicInteger copiesFinish = new AtomicInteger(0);
+
+ public void lock() {
+ this.lock.lock();
+ }
+
+ public void unlock() {
+ this.lock.unlock();
+ }
+
+ public void awaitAllFinish(int waitCopiesFinish) throws InterruptedException {
+ while (this.copiesFinish.get() != waitCopiesFinish) {
+ this.readyCondition.await();
+ }
+ }
+
+ public void signalAll() {
+ this.readyCondition.signalAll();
+ }
+
+ public boolean isCopySuccess() {
+ return this.copySuccess.get();
+ }
+
+ public void setCopySuccess(boolean copySuccess) {
+ this.copySuccess.set(copySuccess);
+ }
+
+ public void incCopiesFinish() {
+ this.copiesFinish.addAndGet(1);
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNCopyFileTask.java b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNCopyFileTask.java
new file mode 100644
index 0000000000000..33d38b80e2e0a
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNCopyFileTask.java
@@ -0,0 +1,68 @@
+/**
+ * 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
+ *
+ * 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.cosn;
+
+import java.io.IOException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Used by {@link CosNFileSystem} as an task that submitted
+ * to the thread pool to accelerate the copy progress.
+ * Each task is responsible for copying the source key to the destination.
+ */
+public class CosNCopyFileTask implements Runnable {
+ private static final Logger LOG =
+ LoggerFactory.getLogger(CosNCopyFileTask.class);
+
+ private NativeFileSystemStore store;
+ private String srcKey;
+ private String dstKey;
+ private CosNCopyFileContext cosCopyFileContext;
+
+ public CosNCopyFileTask(NativeFileSystemStore store, String srcKey,
+ String dstKey, CosNCopyFileContext cosCopyFileContext) {
+ this.store = store;
+ this.srcKey = srcKey;
+ this.dstKey = dstKey;
+ this.cosCopyFileContext = cosCopyFileContext;
+ }
+
+ @Override
+ public void run() {
+ boolean fail = false;
+ LOG.info(Thread.currentThread().getName() + "copying...");
+ try {
+ this.store.copy(srcKey, dstKey);
+ } catch (IOException e) {
+ LOG.warn("Exception thrown when copy from {} to {}, exception:{}",
+ this.srcKey, this.dstKey, e);
+ fail = true;
+ } finally {
+ this.cosCopyFileContext.lock();
+ if (fail) {
+ cosCopyFileContext.setCopySuccess(false);
+ }
+ cosCopyFileContext.incCopiesFinish();
+ cosCopyFileContext.signalAll();
+ this.cosCopyFileContext.unlock();
+ }
+ }
+
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNFileReadTask.java b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNFileReadTask.java
new file mode 100644
index 0000000000000..a5dcdda07120b
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNFileReadTask.java
@@ -0,0 +1,125 @@
+/**
+ * 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
+ *
+ * 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.cosn;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.io.IOUtils;
+import org.apache.hadoop.io.retry.RetryPolicies;
+import org.apache.hadoop.io.retry.RetryPolicy;
+
+/**
+ * Used by {@link CosNInputStream} as an asynchronous task
+ * submitted to the thread pool.
+ * Each task is responsible for reading a part of a large file.
+ * It is used to pre-read the data from COS to accelerate file reading process.
+ */
+public class CosNFileReadTask implements Runnable {
+ private static final Logger LOG =
+ LoggerFactory.getLogger(CosNFileReadTask.class);
+
+ private final String key;
+ private final NativeFileSystemStore store;
+ private final CosNInputStream.ReadBuffer readBuffer;
+
+ private RetryPolicy retryPolicy;
+
+ public CosNFileReadTask(
+ Configuration conf,
+ String key, NativeFileSystemStore store,
+ CosNInputStream.ReadBuffer readBuffer) {
+ this.key = key;
+ this.store = store;
+ this.readBuffer = readBuffer;
+
+ RetryPolicy defaultPolicy =
+ RetryPolicies.retryUpToMaximumCountWithFixedSleep(
+ conf.getInt(
+ CosNConfigKeys.COSN_MAX_RETRIES_KEY,
+ CosNConfigKeys.DEFAULT_MAX_RETRIES),
+ conf.getLong(
+ CosNConfigKeys.COSN_RETRY_INTERVAL_KEY,
+ CosNConfigKeys.DEFAULT_RETRY_INTERVAL),
+ TimeUnit.SECONDS);
+ Map, RetryPolicy> retryPolicyMap =
+ new HashMap<>();
+ retryPolicyMap.put(IOException.class, defaultPolicy);
+ retryPolicyMap.put(
+ IndexOutOfBoundsException.class, RetryPolicies.TRY_ONCE_THEN_FAIL);
+ retryPolicyMap.put(
+ NullPointerException.class, RetryPolicies.TRY_ONCE_THEN_FAIL);
+
+ this.retryPolicy = RetryPolicies.retryByException(
+ defaultPolicy, retryPolicyMap);
+ }
+
+ @Override
+ public void run() {
+ int retries = 0;
+ RetryPolicy.RetryAction retryAction;
+ LOG.info(Thread.currentThread().getName() + "read ...");
+ try {
+ this.readBuffer.lock();
+ do {
+ try {
+ InputStream inputStream = this.store.retrieveBlock(this.key,
+ this.readBuffer.getStart(), this.readBuffer.getEnd());
+ IOUtils.readFully(inputStream, this.readBuffer.getBuffer(), 0,
+ readBuffer.getBuffer().length);
+ inputStream.close();
+ this.readBuffer.setStatus(CosNInputStream.ReadBuffer.SUCCESS);
+ break;
+ } catch (IOException e) {
+ this.readBuffer.setStatus(CosNInputStream.ReadBuffer.ERROR);
+ LOG.warn(
+ "Exception occurs when retrieve the block range start: "
+ + String.valueOf(this.readBuffer.getStart()) + " end: "
+ + this.readBuffer.getEnd());
+ try {
+ retryAction = this.retryPolicy.shouldRetry(
+ e, retries++, 0, true);
+ if (retryAction.action
+ == RetryPolicy.RetryAction.RetryDecision.RETRY) {
+ Thread.sleep(retryAction.delayMillis);
+ }
+ } catch (Exception e1) {
+ String errMsg = String.format("Exception occurs when retry[%s] "
+ + "to retrieve the block range start: %s, end:%s",
+ this.retryPolicy.toString(),
+ String.valueOf(this.readBuffer.getStart()),
+ String.valueOf(this.readBuffer.getEnd()));
+ LOG.error(errMsg, e1);
+ break;
+ }
+ }
+ } while (retryAction.action ==
+ RetryPolicy.RetryAction.RetryDecision.RETRY);
+ this.readBuffer.signalAll();
+ } finally {
+ this.readBuffer.unLock();
+ }
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNFileSystem.java b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNFileSystem.java
new file mode 100644
index 0000000000000..333b34929ecda
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNFileSystem.java
@@ -0,0 +1,814 @@
+/**
+ * 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
+ *
+ * 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.cosn;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.google.common.util.concurrent.ListeningExecutorService;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.BufferedFSInputStream;
+import org.apache.hadoop.fs.CreateFlag;
+import org.apache.hadoop.fs.FSDataInputStream;
+import org.apache.hadoop.fs.FSDataOutputStream;
+import org.apache.hadoop.fs.FileAlreadyExistsException;
+import org.apache.hadoop.fs.FileStatus;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.PathIOException;
+import org.apache.hadoop.fs.permission.FsPermission;
+import org.apache.hadoop.io.retry.RetryPolicies;
+import org.apache.hadoop.io.retry.RetryPolicy;
+import org.apache.hadoop.io.retry.RetryProxy;
+import org.apache.hadoop.util.BlockingThreadPoolExecutorService;
+import org.apache.hadoop.util.Progressable;
+
+/**
+ * The core CosN Filesystem implementation.
+ */
+@InterfaceAudience.Private
+@InterfaceStability.Stable
+public class CosNFileSystem extends FileSystem {
+ static final Logger LOG = LoggerFactory.getLogger(CosNFileSystem.class);
+
+ public static final String SCHEME = "cosn";
+ public static final String PATH_DELIMITER = Path.SEPARATOR;
+
+ private URI uri;
+ private String bucket;
+ private NativeFileSystemStore store;
+ private Path workingDir;
+ private String owner = "Unknown";
+ private String group = "Unknown";
+
+ private ListeningExecutorService boundedIOThreadPool;
+ private ListeningExecutorService boundedCopyThreadPool;
+
+ public CosNFileSystem() {
+ }
+
+ public CosNFileSystem(NativeFileSystemStore store) {
+ this.store = store;
+ }
+
+ /**
+ * Return the protocol scheme for the FileSystem.
+ *
+ * @return cosn
+ */
+ @Override
+ public String getScheme() {
+ return CosNFileSystem.SCHEME;
+ }
+
+ @Override
+ public void initialize(URI name, Configuration conf) throws IOException {
+ super.initialize(name, conf);
+ this.bucket = name.getHost();
+ if (this.store == null) {
+ this.store = createDefaultStore(conf);
+ }
+ this.store.initialize(name, conf);
+ setConf(conf);
+ this.uri = URI.create(name.getScheme() + "://" + name.getAuthority());
+ this.workingDir = new Path("/user",
+ System.getProperty("user.name")).makeQualified(
+ this.uri,
+ this.getWorkingDirectory());
+ this.owner = getOwnerId();
+ this.group = getGroupId();
+ LOG.debug("owner:" + owner + ", group:" + group);
+
+ BufferPool.getInstance().initialize(this.getConf());
+
+ // initialize the thread pool
+ int uploadThreadPoolSize = this.getConf().getInt(
+ CosNConfigKeys.UPLOAD_THREAD_POOL_SIZE_KEY,
+ CosNConfigKeys.DEFAULT_UPLOAD_THREAD_POOL_SIZE
+ );
+ int readAheadPoolSize = this.getConf().getInt(
+ CosNConfigKeys.READ_AHEAD_QUEUE_SIZE,
+ CosNConfigKeys.DEFAULT_READ_AHEAD_QUEUE_SIZE
+ );
+ int ioThreadPoolSize = uploadThreadPoolSize + readAheadPoolSize / 3;
+ long threadKeepAlive = this.getConf().getLong(
+ CosNConfigKeys.THREAD_KEEP_ALIVE_TIME_KEY,
+ CosNConfigKeys.DEFAULT_THREAD_KEEP_ALIVE_TIME
+ );
+ this.boundedIOThreadPool = BlockingThreadPoolExecutorService.newInstance(
+ ioThreadPoolSize / 2, ioThreadPoolSize,
+ threadKeepAlive, TimeUnit.SECONDS,
+ "cos-transfer-thread-pool");
+ int copyThreadPoolSize = this.getConf().getInt(
+ CosNConfigKeys.COPY_THREAD_POOL_SIZE_KEY,
+ CosNConfigKeys.DEFAULT_COPY_THREAD_POOL_SIZE
+ );
+ this.boundedCopyThreadPool = BlockingThreadPoolExecutorService.newInstance(
+ CosNConfigKeys.DEFAULT_COPY_THREAD_POOL_SIZE, copyThreadPoolSize,
+ 60L, TimeUnit.SECONDS,
+ "cos-copy-thread-pool");
+ }
+
+ private static NativeFileSystemStore createDefaultStore(Configuration conf) {
+ NativeFileSystemStore store = new CosNativeFileSystemStore();
+ RetryPolicy basePolicy = RetryPolicies.retryUpToMaximumCountWithFixedSleep(
+ conf.getInt(CosNConfigKeys.COSN_MAX_RETRIES_KEY,
+ CosNConfigKeys.DEFAULT_MAX_RETRIES),
+ conf.getLong(CosNConfigKeys.COSN_RETRY_INTERVAL_KEY,
+ CosNConfigKeys.DEFAULT_RETRY_INTERVAL),
+ TimeUnit.SECONDS);
+ Map, RetryPolicy> exceptionToPolicyMap =
+ new HashMap<>();
+
+ exceptionToPolicyMap.put(IOException.class, basePolicy);
+ RetryPolicy methodPolicy = RetryPolicies.retryByException(
+ RetryPolicies.TRY_ONCE_THEN_FAIL,
+ exceptionToPolicyMap);
+ Map methodNameToPolicyMap = new HashMap<>();
+ methodNameToPolicyMap.put("storeFile", methodPolicy);
+ methodNameToPolicyMap.put("rename", methodPolicy);
+
+ return (NativeFileSystemStore) RetryProxy.create(
+ NativeFileSystemStore.class, store, methodNameToPolicyMap);
+ }
+
+ private String getOwnerId() {
+ return System.getProperty("user.name");
+ }
+
+ private String getGroupId() {
+ return System.getProperty("user.name");
+ }
+
+ private String getOwnerInfo(boolean getOwnerId) {
+ String ownerInfoId = "";
+ try {
+ String userName = System.getProperty("user.name");
+ String command = "id -u " + userName;
+ if (!getOwnerId) {
+ command = "id -g " + userName;
+ }
+ Process child = Runtime.getRuntime().exec(command);
+ child.waitFor();
+
+ // Get the input stream and read from it
+ InputStream in = child.getInputStream();
+ StringBuilder strBuffer = new StringBuilder();
+ int c;
+ while ((c = in.read()) != -1) {
+ strBuffer.append((char) c);
+ }
+ in.close();
+ ownerInfoId = strBuffer.toString();
+ } catch (IOException | InterruptedException e) {
+ LOG.error("Getting owner info occurs a exception", e);
+ }
+ return ownerInfoId;
+ }
+
+ private static String pathToKey(Path path) {
+ if (path.toUri().getScheme() != null && path.toUri().getPath().isEmpty()) {
+ // allow uris without trailing slash after bucket to refer to root,
+ // like cosn://mybucket
+ return "";
+ }
+ if (!path.isAbsolute()) {
+ throw new IllegalArgumentException("Path must be absolute: " + path);
+ }
+ String ret = path.toUri().getPath();
+ if (ret.endsWith("/") && (ret.indexOf("/") != ret.length() - 1)) {
+ ret = ret.substring(0, ret.length() - 1);
+ }
+ return ret;
+ }
+
+ private static Path keyToPath(String key) {
+ if (!key.startsWith(PATH_DELIMITER)) {
+ return new Path("/" + key);
+ } else {
+ return new Path(key);
+ }
+ }
+
+ private Path makeAbsolute(Path path) {
+ if (path.isAbsolute()) {
+ return path;
+ }
+ return new Path(workingDir, path);
+ }
+
+ /**
+ * This optional operation is not yet supported.
+ */
+ @Override
+ public FSDataOutputStream append(Path f, int bufferSize,
+ Progressable progress) throws IOException {
+ throw new IOException("Not supported");
+ }
+
+ @Override
+ public FSDataOutputStream create(Path f, FsPermission permission,
+ boolean overwrite, int bufferSize, short replication, long blockSize,
+ Progressable progress) throws IOException {
+ FileStatus fileStatus;
+
+ try {
+ fileStatus = getFileStatus(f);
+ if (fileStatus.isDirectory()) {
+ throw new FileAlreadyExistsException(f + " is a directory");
+ }
+ if (!overwrite) {
+ // path references a file and overwrite is disabled
+ throw new FileAlreadyExistsException(f + " already exists");
+ }
+
+ } catch (FileNotFoundException e) {
+ LOG.debug("Creating a new file: [{}] in COS.", f);
+ }
+
+ Path absolutePath = makeAbsolute(f);
+ String key = pathToKey(absolutePath);
+ return new FSDataOutputStream(
+ new CosNOutputStream(getConf(), store, key, blockSize,
+ this.boundedIOThreadPool), statistics);
+ }
+
+ private boolean rejectRootDirectoryDelete(boolean isEmptyDir,
+ boolean recursive) throws PathIOException {
+ if (isEmptyDir) {
+ return true;
+ }
+ if (recursive) {
+ return false;
+ } else {
+ throw new PathIOException(this.bucket, "Can not delete root path");
+ }
+ }
+
+ @Override
+ public FSDataOutputStream createNonRecursive(Path f, FsPermission permission,
+ EnumSet flags, int bufferSize, short replication,
+ long blockSize, Progressable progress) throws IOException {
+ Path parent = f.getParent();
+ if (null != parent) {
+ if (!getFileStatus(parent).isDirectory()) {
+ throw new FileAlreadyExistsException("Not a directory: " + parent);
+ }
+ }
+
+ return create(f, permission, flags.contains(CreateFlag.OVERWRITE),
+ bufferSize, replication, blockSize, progress);
+ }
+
+ @Override
+ public boolean delete(Path f, boolean recursive) throws IOException {
+ LOG.debug("Ready to delete path: [{}]. recursive: [{}].", f, recursive);
+ FileStatus status;
+ try {
+ status = getFileStatus(f);
+ } catch (FileNotFoundException e) {
+ LOG.debug("Ready to delete the file: [{}], but it does not exist.", f);
+ return false;
+ }
+ Path absolutePath = makeAbsolute(f);
+ String key = pathToKey(absolutePath);
+ if (key.compareToIgnoreCase("/") == 0) {
+ FileStatus[] fileStatuses = listStatus(f);
+ return this.rejectRootDirectoryDelete(
+ fileStatuses.length == 0, recursive);
+ }
+
+ if (status.isDirectory()) {
+ if (!key.endsWith(PATH_DELIMITER)) {
+ key += PATH_DELIMITER;
+ }
+ if (!recursive && listStatus(f).length > 0) {
+ String errMsg = String.format("Can not delete the directory: [%s], as"
+ + " it is not empty and option recursive is false.", f);
+ throw new IOException(errMsg);
+ }
+
+ createParent(f);
+
+ String priorLastKey = null;
+ do {
+ PartialListing listing = store.list(
+ key,
+ Constants.COS_MAX_LISTING_LENGTH,
+ priorLastKey,
+ true);
+ for (FileMetadata file : listing.getFiles()) {
+ store.delete(file.getKey());
+ }
+ for (FileMetadata commonPrefix : listing.getCommonPrefixes()) {
+ store.delete(commonPrefix.getKey());
+ }
+ priorLastKey = listing.getPriorLastKey();
+ } while (priorLastKey != null);
+ try {
+ store.delete(key);
+ } catch (Exception e) {
+ LOG.error("Deleting the COS key: [{}] occurs an exception.", key, e);
+ }
+
+ } else {
+ LOG.debug("Delete the file: {}", f);
+ createParent(f);
+ store.delete(key);
+ }
+ return true;
+ }
+
+ @Override
+ public FileStatus getFileStatus(Path f) throws IOException {
+ Path absolutePath = makeAbsolute(f);
+ String key = pathToKey(absolutePath);
+
+ if (key.length() == 0) {
+ // root always exists
+ return newDirectory(absolutePath);
+ }
+
+ LOG.debug("Call the getFileStatus to obtain the metadata for "
+ + "the file: [{}].", f);
+
+ FileMetadata meta = store.retrieveMetadata(key);
+ if (meta != null) {
+ if (meta.isFile()) {
+ LOG.debug("Path: [{}] is a file. COS key: [{}]", f, key);
+ return newFile(meta, absolutePath);
+ } else {
+ LOG.debug("Path: [{}] is a dir. COS key: [{}]", f, key);
+ return newDirectory(meta, absolutePath);
+ }
+ }
+
+ if (!key.endsWith(PATH_DELIMITER)) {
+ key += PATH_DELIMITER;
+ }
+
+ // Considering that the object store's directory is a common prefix in
+ // the object key, it needs to check the existence of the path by listing
+ // the COS key.
+ LOG.debug("List COS key: [{}] to check the existence of the path.", key);
+ PartialListing listing = store.list(key, 1);
+ if (listing.getFiles().length > 0
+ || listing.getCommonPrefixes().length > 0) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Path: [{}] is a directory. COS key: [{}]", f, key);
+ }
+ return newDirectory(absolutePath);
+ }
+
+ throw new FileNotFoundException(
+ "No such file or directory '" + absolutePath + "'");
+ }
+
+ @Override
+ public URI getUri() {
+ return uri;
+ }
+
+ /**
+ *
+ * If f is a file, this method will make a single call to COS.
+ * If f is a directory,
+ * this method will make a maximum of ( n / 199) + 2 calls to cos,
+ * where n is the total number of files
+ * and directories contained directly in f.
+ *
+ */
+ @Override
+ public FileStatus[] listStatus(Path f) throws IOException {
+ Path absolutePath = makeAbsolute(f);
+ String key = pathToKey(absolutePath);
+
+ if (key.length() > 0) {
+ FileStatus fileStatus = this.getFileStatus(f);
+ if (fileStatus.isFile()) {
+ return new FileStatus[]{fileStatus};
+ }
+ }
+
+ if (!key.endsWith(PATH_DELIMITER)) {
+ key += PATH_DELIMITER;
+ }
+
+ URI pathUri = absolutePath.toUri();
+ Set status = new TreeSet<>();
+ String priorLastKey = null;
+ do {
+ PartialListing listing = store.list(
+ key, Constants.COS_MAX_LISTING_LENGTH, priorLastKey, false);
+ for (FileMetadata fileMetadata : listing.getFiles()) {
+ Path subPath = keyToPath(fileMetadata.getKey());
+ if (fileMetadata.getKey().equals(key)) {
+ // this is just the directory we have been asked to list.
+ LOG.debug("The file list contains the COS key [{}] to be listed.",
+ key);
+ } else {
+ status.add(newFile(fileMetadata, subPath));
+ }
+ }
+
+ for (FileMetadata commonPrefix : listing.getCommonPrefixes()) {
+ Path subPath = keyToPath(commonPrefix.getKey());
+ String relativePath = pathUri.relativize(subPath.toUri()).getPath();
+ status.add(
+ newDirectory(commonPrefix, new Path(absolutePath, relativePath)));
+ }
+ priorLastKey = listing.getPriorLastKey();
+ } while (priorLastKey != null);
+
+ return status.toArray(new FileStatus[status.size()]);
+ }
+
+ private FileStatus newFile(FileMetadata meta, Path path) {
+ return new FileStatus(meta.getLength(), false, 1, getDefaultBlockSize(),
+ meta.getLastModified(), 0, null, this.owner, this.group,
+ path.makeQualified(this.getUri(), this.getWorkingDirectory()));
+ }
+
+ private FileStatus newDirectory(Path path) {
+ return new FileStatus(0, true, 1, 0, 0, 0, null, this.owner, this.group,
+ path.makeQualified(this.getUri(), this.getWorkingDirectory()));
+ }
+
+ private FileStatus newDirectory(FileMetadata meta, Path path) {
+ if (meta == null) {
+ return newDirectory(path);
+ }
+ return new FileStatus(0, true, 1, 0, meta.getLastModified(),
+ 0, null, this.owner, this.group,
+ path.makeQualified(this.getUri(), this.getWorkingDirectory()));
+ }
+
+ /**
+ * Validate the path from the bottom up.
+ *
+ * @param path The path to be validated
+ * @throws FileAlreadyExistsException The specified path is an existing file
+ * @throws IOException Getting the file status of the
+ * specified path occurs
+ * an IOException.
+ */
+ private void validatePath(Path path) throws IOException {
+ Path parent = path.getParent();
+ do {
+ try {
+ FileStatus fileStatus = getFileStatus(parent);
+ if (fileStatus.isDirectory()) {
+ break;
+ } else {
+ throw new FileAlreadyExistsException(String.format(
+ "Can't make directory for path '%s', it is a file.", parent));
+ }
+ } catch (FileNotFoundException e) {
+ LOG.debug("The Path: [{}] does not exist.", path);
+ }
+ parent = parent.getParent();
+ } while (parent != null);
+ }
+
+ @Override
+ public boolean mkdirs(Path f, FsPermission permission) throws IOException {
+ try {
+ FileStatus fileStatus = getFileStatus(f);
+ if (fileStatus.isDirectory()) {
+ return true;
+ } else {
+ throw new FileAlreadyExistsException("Path is a file: " + f);
+ }
+ } catch (FileNotFoundException e) {
+ validatePath(f);
+ }
+
+ return mkDirRecursively(f, permission);
+ }
+
+ /**
+ * Recursively create a directory.
+ *
+ * @param f Absolute path to the directory.
+ * @param permission Directory permissions. Permission does not work for
+ * the CosN filesystem currently.
+ * @return Return true if the creation was successful, throw a IOException.
+ * @throws IOException The specified path already exists or an error
+ * creating the path.
+ */
+ public boolean mkDirRecursively(Path f, FsPermission permission)
+ throws IOException {
+ Path absolutePath = makeAbsolute(f);
+ List paths = new ArrayList<>();
+ do {
+ paths.add(absolutePath);
+ absolutePath = absolutePath.getParent();
+ } while (absolutePath != null);
+
+ for (Path path : paths) {
+ if (path.equals(new Path(CosNFileSystem.PATH_DELIMITER))) {
+ break;
+ }
+ try {
+ FileStatus fileStatus = getFileStatus(path);
+ if (fileStatus.isFile()) {
+ throw new FileAlreadyExistsException(
+ String.format("Can't make directory for path: %s, "
+ + "since it is a file.", f));
+ }
+ if (fileStatus.isDirectory()) {
+ break;
+ }
+ } catch (FileNotFoundException e) {
+ LOG.debug("Making dir: [{}] in COS", f);
+
+ String folderPath = pathToKey(makeAbsolute(f));
+ if (!folderPath.endsWith(PATH_DELIMITER)) {
+ folderPath += PATH_DELIMITER;
+ }
+ store.storeEmptyFile(folderPath);
+ }
+ }
+ return true;
+ }
+
+ private boolean mkdir(Path f) throws IOException {
+ try {
+ FileStatus fileStatus = getFileStatus(f);
+ if (fileStatus.isFile()) {
+ throw new FileAlreadyExistsException(
+ String.format(
+ "Can't make directory for path '%s' since it is a file.", f));
+ }
+ } catch (FileNotFoundException e) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Make directory: [{}] in COS.", f);
+ }
+
+ String folderPath = pathToKey(makeAbsolute(f));
+ if (!folderPath.endsWith(PATH_DELIMITER)) {
+ folderPath += PATH_DELIMITER;
+ }
+ store.storeEmptyFile(folderPath);
+ }
+ return true;
+ }
+
+ @Override
+ public FSDataInputStream open(Path f, int bufferSize) throws IOException {
+ FileStatus fs = getFileStatus(f); // will throw if the file doesn't
+ // exist
+ if (fs.isDirectory()) {
+ throw new FileNotFoundException("'" + f + "' is a directory");
+ }
+ LOG.info("Open the file: [{}] for reading.", f);
+ Path absolutePath = makeAbsolute(f);
+ String key = pathToKey(absolutePath);
+ long fileSize = store.getFileLength(key);
+ return new FSDataInputStream(new BufferedFSInputStream(
+ new CosNInputStream(this.getConf(), store, statistics, key, fileSize,
+ this.boundedIOThreadPool), bufferSize));
+ }
+
+ @Override
+ public boolean rename(Path src, Path dst) throws IOException {
+ LOG.debug("Rename source path: [{}] to dest path: [{}].", src, dst);
+
+ // Renaming the root directory is not allowed
+ if (src.isRoot()) {
+ LOG.debug("Cannot rename the root directory of a filesystem.");
+ return false;
+ }
+
+ // check the source path whether exists or not
+ FileStatus srcFileStatus = this.getFileStatus(src);
+
+ // Source path and destination path are not allowed to be the same
+ if (src.equals(dst)) {
+ LOG.debug("Source path and dest path refer to "
+ + "the same file or directory: [{}].", dst);
+ throw new IOException("Source path and dest path refer "
+ + "the same file or directory");
+ }
+
+ // It is not allowed to rename a parent directory to its subdirectory
+ Path dstParentPath;
+ for (dstParentPath = dst.getParent();
+ null != dstParentPath && !src.equals(dstParentPath);
+ dstParentPath = dstParentPath.getParent()) {
+ // Recursively find the common parent path of the source and
+ // destination paths.
+ LOG.debug("Recursively find the common parent directory of the source "
+ + "and destination paths. The currently found parent path: {}",
+ dstParentPath);
+ }
+
+ if (null != dstParentPath) {
+ LOG.debug("It is not allowed to rename a parent directory:[{}] "
+ + "to its subdirectory:[{}].", src, dst);
+ throw new IOException(String.format(
+ "It is not allowed to rename a parent directory: %s "
+ + "to its subdirectory: %s", src, dst));
+ }
+
+ FileStatus dstFileStatus;
+ try {
+ dstFileStatus = this.getFileStatus(dst);
+
+ // The destination path exists and is a file,
+ // and the rename operation is not allowed.
+ if (dstFileStatus.isFile()) {
+ throw new FileAlreadyExistsException(String.format(
+ "File: %s already exists", dstFileStatus.getPath()));
+ } else {
+ // The destination path is an existing directory,
+ // and it is checked whether there is a file or directory
+ // with the same name as the source path under the destination path
+ dst = new Path(dst, src.getName());
+ FileStatus[] statuses;
+ try {
+ statuses = this.listStatus(dst);
+ } catch (FileNotFoundException e) {
+ statuses = null;
+ }
+ if (null != statuses && statuses.length > 0) {
+ LOG.debug("Cannot rename source file: [{}] to dest file: [{}], "
+ + "because the file already exists.", src, dst);
+ throw new FileAlreadyExistsException(
+ String.format(
+ "File: %s already exists", dst
+ )
+ );
+ }
+ }
+ } catch (FileNotFoundException e) {
+ // destination path not exists
+ Path tempDstParentPath = dst.getParent();
+ FileStatus dstParentStatus = this.getFileStatus(tempDstParentPath);
+ if (!dstParentStatus.isDirectory()) {
+ throw new IOException(String.format(
+ "Cannot rename %s to %s, %s is a file", src, dst, dst.getParent()
+ ));
+ }
+ // The default root directory is definitely there.
+ }
+
+ boolean result;
+ if (srcFileStatus.isDirectory()) {
+ result = this.copyDirectory(src, dst);
+ } else {
+ result = this.copyFile(src, dst);
+ }
+
+ if (!result) {
+ //Since rename is a non-atomic operation, after copy fails,
+ // it is not allowed to delete the data of the original path.
+ return false;
+ } else {
+ return this.delete(src, true);
+ }
+ }
+
+ private boolean copyFile(Path srcPath, Path dstPath) throws IOException {
+ String srcKey = pathToKey(srcPath);
+ String dstKey = pathToKey(dstPath);
+ this.store.copy(srcKey, dstKey);
+ return true;
+ }
+
+ private boolean copyDirectory(Path srcPath, Path dstPath) throws IOException {
+ String srcKey = pathToKey(srcPath);
+ if (!srcKey.endsWith(PATH_DELIMITER)) {
+ srcKey += PATH_DELIMITER;
+ }
+ String dstKey = pathToKey(dstPath);
+ if (!dstKey.endsWith(PATH_DELIMITER)) {
+ dstKey += PATH_DELIMITER;
+ }
+
+ if (dstKey.startsWith(srcKey)) {
+ throw new IOException(
+ "can not copy a directory to a subdirectory of self");
+ }
+
+ this.store.storeEmptyFile(dstKey);
+ CosNCopyFileContext copyFileContext = new CosNCopyFileContext();
+
+ int copiesToFinishes = 0;
+ String priorLastKey = null;
+ do {
+ PartialListing objectList = this.store.list(
+ srcKey, Constants.COS_MAX_LISTING_LENGTH, priorLastKey, true);
+ for (FileMetadata file : objectList.getFiles()) {
+ this.boundedCopyThreadPool.execute(new CosNCopyFileTask(
+ this.store,
+ file.getKey(),
+ dstKey.concat(file.getKey().substring(srcKey.length())),
+ copyFileContext));
+ copiesToFinishes++;
+ if (!copyFileContext.isCopySuccess()) {
+ break;
+ }
+ }
+ priorLastKey = objectList.getPriorLastKey();
+ } while (null != priorLastKey);
+
+ copyFileContext.lock();
+ try {
+ copyFileContext.awaitAllFinish(copiesToFinishes);
+ } catch (InterruptedException e) {
+ LOG.warn("interrupted when wait copies to finish");
+ } finally {
+ copyFileContext.lock();
+ }
+
+ return copyFileContext.isCopySuccess();
+ }
+
+ private void createParent(Path path) throws IOException {
+ Path parent = path.getParent();
+ if (parent != null) {
+ String parentKey = pathToKey(parent);
+ LOG.debug("Create parent key: {}", parentKey);
+ if (!parentKey.equals(PATH_DELIMITER)) {
+ String key = pathToKey(makeAbsolute(parent));
+ if (key.length() > 0) {
+ try {
+ store.storeEmptyFile(key + PATH_DELIMITER);
+ } catch (IOException e) {
+ LOG.debug("Store a empty file in COS failed.", e);
+ throw e;
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ public long getDefaultBlockSize() {
+ return getConf().getLong(
+ CosNConfigKeys.COSN_BLOCK_SIZE_KEY,
+ CosNConfigKeys.DEFAULT_BLOCK_SIZE);
+ }
+
+ /**
+ * Set the working directory to the given directory.
+ */
+ @Override
+ public void setWorkingDirectory(Path newDir) {
+ workingDir = newDir;
+ }
+
+ @Override
+ public Path getWorkingDirectory() {
+ return workingDir;
+ }
+
+ @Override
+ public String getCanonicalServiceName() {
+ // Does not support Token
+ return null;
+ }
+
+ @Override
+ public void close() throws IOException {
+ try {
+ this.store.close();
+ this.boundedIOThreadPool.shutdown();
+ this.boundedCopyThreadPool.shutdown();
+ } finally {
+ super.close();
+ }
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNInputStream.java b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNInputStream.java
new file mode 100644
index 0000000000000..e759b55a559ad
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNInputStream.java
@@ -0,0 +1,365 @@
+/**
+ * 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
+ *
+ * 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.cosn;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+
+/**
+ *
+ * Holds basic metadata for a file stored in a {@link NativeFileSystemStore}.
+ *
+ */
+@InterfaceAudience.Private
+@InterfaceStability.Unstable
+class FileMetadata {
+ private final String key;
+ private final long length;
+ private final long lastModified;
+ private final boolean isFile;
+
+ FileMetadata(String key, long length, long lastModified) {
+ this(key, length, lastModified, true);
+ }
+
+ FileMetadata(String key, long length, long lastModified, boolean isFile) {
+ this.key = key;
+ this.length = length;
+ this.lastModified = lastModified;
+ this.isFile = isFile;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public long getLength() {
+ return length;
+ }
+
+ public long getLastModified() {
+ return lastModified;
+ }
+
+ @Override
+ public String toString() {
+ return "FileMetadata[" + key + ", " + length + ", " + lastModified + ", "
+ + "file?" + isFile + "]";
+ }
+
+ public boolean isFile() {
+ return isFile;
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/NativeFileSystemStore.java b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/NativeFileSystemStore.java
new file mode 100644
index 0000000000000..536c6de6367cb
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/NativeFileSystemStore.java
@@ -0,0 +1,99 @@
+/**
+ * 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
+ *
+ * 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.cosn;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.List;
+
+import com.qcloud.cos.model.CompleteMultipartUploadResult;
+import com.qcloud.cos.model.PartETag;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.conf.Configuration;
+
+/**
+ *
+ * An abstraction for a key-based {@link File} store.
+ *
+ */
+@InterfaceAudience.Private
+@InterfaceStability.Stable
+interface NativeFileSystemStore {
+
+ void initialize(URI uri, Configuration conf) throws IOException;
+
+ void storeFile(String key, File file, byte[] md5Hash) throws IOException;
+
+ void storeFile(String key, InputStream inputStream, byte[] md5Hash,
+ long contentLength) throws IOException;
+
+ void storeEmptyFile(String key) throws IOException;
+
+ CompleteMultipartUploadResult completeMultipartUpload(
+ String key, String uploadId, List partETagList);
+
+ void abortMultipartUpload(String key, String uploadId);
+
+ String getUploadId(String key);
+
+ PartETag uploadPart(File file, String key, String uploadId, int partNum)
+ throws IOException;
+
+ PartETag uploadPart(InputStream inputStream, String key, String uploadId,
+ int partNum, long partSize) throws IOException;
+
+ FileMetadata retrieveMetadata(String key) throws IOException;
+
+ InputStream retrieve(String key) throws IOException;
+
+ InputStream retrieve(String key, long byteRangeStart) throws IOException;
+
+ InputStream retrieveBlock(String key, long byteRangeStart, long byteRangeEnd)
+ throws IOException;
+
+ long getFileLength(String key) throws IOException;
+
+ PartialListing list(String prefix, int maxListingLength) throws IOException;
+
+ PartialListing list(String prefix, int maxListingLength,
+ String priorLastKey, boolean recursive) throws IOException;
+
+ void delete(String key) throws IOException;
+
+ void copy(String srcKey, String dstKey) throws IOException;
+
+ /**
+ * Delete all keys with the given prefix. Used for testing.
+ *
+ * @throws IOException if purge is not supported
+ */
+ void purge(String prefix) throws IOException;
+
+ /**
+ * Diagnostic method to dump state to the console.
+ *
+ * @throws IOException if dump is not supported
+ */
+ void dump() throws IOException;
+
+ void close();
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/PartialListing.java b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/PartialListing.java
new file mode 100644
index 0000000000000..78cba38a83d60
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/PartialListing.java
@@ -0,0 +1,64 @@
+/**
+ * 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
+ *
+ * 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.cosn;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+
+/**
+ *
+ * Holds information on a directory listing for a
+ * {@link NativeFileSystemStore}.
+ * This includes the {@link FileMetadata files} and directories
+ * (their names) contained in a directory.
+ *
+ *
+ * This listing may be returned in chunks, so a priorLastKey
+ * is provided so that the next chunk may be requested.
+ *
+ *
+ * @see NativeFileSystemStore#list(String, int, String, boolean)
+ */
+@InterfaceAudience.Private
+@InterfaceStability.Unstable
+class PartialListing {
+
+ private final String priorLastKey;
+ private final FileMetadata[] files;
+ private final FileMetadata[] commonPrefixes;
+
+ PartialListing(String priorLastKey, FileMetadata[] files,
+ FileMetadata[] commonPrefixes) {
+ this.priorLastKey = priorLastKey;
+ this.files = files;
+ this.commonPrefixes = commonPrefixes;
+ }
+
+ public FileMetadata[] getFiles() {
+ return files;
+ }
+
+ public FileMetadata[] getCommonPrefixes() {
+ return commonPrefixes;
+ }
+
+ public String getPriorLastKey() {
+ return priorLastKey;
+ }
+
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/Unit.java b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/Unit.java
new file mode 100644
index 0000000000000..5950ba7301423
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/Unit.java
@@ -0,0 +1,32 @@
+/**
+ * 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
+ *
+ * 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.cosn;
+
+/**
+ * Constant definition of storage unit.
+ */
+public final class Unit {
+ private Unit() {
+ }
+
+ public static final int KB = 1024;
+ public static final int MB = 1024 * KB;
+ public static final int GB = 1024 * MB;
+ public static final long TB = (long) 1024 * GB;
+ public static final long PB = (long) 1024 * TB;
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/auth/COSCredentialProviderList.java b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/auth/COSCredentialProviderList.java
new file mode 100644
index 0000000000000..e900b997e4858
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/auth/COSCredentialProviderList.java
@@ -0,0 +1,139 @@
+/**
+ * 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
+ *
+ * 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.cosn.auth;
+
+import java.io.Closeable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import com.google.common.base.Preconditions;
+import com.qcloud.cos.auth.AnonymousCOSCredentials;
+import com.qcloud.cos.auth.COSCredentials;
+import com.qcloud.cos.auth.COSCredentialsProvider;
+import com.qcloud.cos.exception.CosClientException;
+import com.qcloud.cos.utils.StringUtils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * a list of cos credentials provider.
+ */
+public class COSCredentialProviderList implements
+ COSCredentialsProvider, AutoCloseable {
+ private static final Logger LOG =
+ LoggerFactory.getLogger(COSCredentialProviderList.class);
+
+ private static final String NO_COS_CREDENTIAL_PROVIDERS =
+ "No COS Credential Providers";
+ private static final String CREDENTIALS_REQUESTED_WHEN_CLOSED =
+ "Credentials requested after provider list was closed";
+
+ private final List providers =
+ new ArrayList<>(1);
+ private boolean reuseLastProvider = true;
+ private COSCredentialsProvider lastProvider;
+
+ private final AtomicInteger refCount = new AtomicInteger(1);
+ private final AtomicBoolean isClosed = new AtomicBoolean(false);
+
+ public COSCredentialProviderList() {
+ }
+
+ public COSCredentialProviderList(
+ Collection providers) {
+ this.providers.addAll(providers);
+ }
+
+ public void add(COSCredentialsProvider provider) {
+ this.providers.add(provider);
+ }
+
+ public int getRefCount() {
+ return this.refCount.get();
+ }
+
+ public void checkNotEmpty() {
+ if (this.providers.isEmpty()) {
+ throw new NoAuthWithCOSException(NO_COS_CREDENTIAL_PROVIDERS);
+ }
+ }
+
+ public COSCredentialProviderList share() {
+ Preconditions.checkState(!this.closed(), "Provider list is closed");
+ this.refCount.incrementAndGet();
+ return this;
+ }
+
+ public boolean closed() {
+ return this.isClosed.get();
+ }
+
+ @Override
+ public COSCredentials getCredentials() {
+ if (this.closed()) {
+ throw new NoAuthWithCOSException(CREDENTIALS_REQUESTED_WHEN_CLOSED);
+ }
+
+ this.checkNotEmpty();
+
+ if (this.reuseLastProvider && this.lastProvider != null) {
+ return this.lastProvider.getCredentials();
+ }
+
+ for (COSCredentialsProvider provider : this.providers) {
+ try {
+ COSCredentials credentials = provider.getCredentials();
+ if (!StringUtils.isNullOrEmpty(credentials.getCOSAccessKeyId())
+ && !StringUtils.isNullOrEmpty(credentials.getCOSSecretKey())
+ || credentials instanceof AnonymousCOSCredentials) {
+ this.lastProvider = provider;
+ return credentials;
+ }
+ } catch (CosClientException e) {
+ LOG.warn("No credentials provided by {}: {}", provider, e.toString());
+ }
+ }
+
+ throw new NoAuthWithCOSException(
+ "No COS Credentials provided by " + this.providers.toString());
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (this.closed()) {
+ return;
+ }
+
+ int remainder = this.refCount.decrementAndGet();
+ if (remainder != 0) {
+ return;
+ }
+ this.isClosed.set(true);
+
+ for (COSCredentialsProvider provider : this.providers) {
+ if (provider instanceof Closeable) {
+ ((Closeable) provider).close();
+ }
+ }
+ }
+
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/auth/EnvironmentVariableCredentialProvider.java b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/auth/EnvironmentVariableCredentialProvider.java
new file mode 100644
index 0000000000000..0a7786b882f8b
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/auth/EnvironmentVariableCredentialProvider.java
@@ -0,0 +1,55 @@
+/**
+ * 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
+ *
+ * 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.cosn.auth;
+
+import com.qcloud.cos.auth.BasicCOSCredentials;
+import com.qcloud.cos.auth.COSCredentials;
+import com.qcloud.cos.auth.COSCredentialsProvider;
+import com.qcloud.cos.exception.CosClientException;
+import com.qcloud.cos.utils.StringUtils;
+
+import org.apache.hadoop.fs.cosn.Constants;
+
+/**
+ * the provider obtaining the cos credentials from the environment variables.
+ */
+public class EnvironmentVariableCredentialProvider
+ implements COSCredentialsProvider {
+ @Override
+ public COSCredentials getCredentials() {
+ String secretId = System.getenv(Constants.COSN_SECRET_ID_ENV);
+ String secretKey = System.getenv(Constants.COSN_SECRET_KEY_ENV);
+
+ secretId = StringUtils.trim(secretId);
+ secretKey = StringUtils.trim(secretKey);
+
+ if (!StringUtils.isNullOrEmpty(secretId)
+ && !StringUtils.isNullOrEmpty(secretKey)) {
+ return new BasicCOSCredentials(secretId, secretKey);
+ } else {
+ throw new CosClientException(
+ "Unable to load COS credentials from environment variables" +
+ "(COS_SECRET_ID or COS_SECRET_KEY)");
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "EnvironmentVariableCredentialProvider{}";
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/auth/NoAuthWithCOSException.java b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/auth/NoAuthWithCOSException.java
new file mode 100644
index 0000000000000..fa188bfb3ffea
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/auth/NoAuthWithCOSException.java
@@ -0,0 +1,37 @@
+/**
+ * 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
+ *
+ * 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.cosn.auth;
+
+import com.qcloud.cos.exception.CosClientException;
+
+/**
+ * Exception thrown when no credentials can be obtained.
+ */
+public class NoAuthWithCOSException extends CosClientException {
+ public NoAuthWithCOSException(String message, Throwable t) {
+ super(message, t);
+ }
+
+ public NoAuthWithCOSException(String message) {
+ super(message);
+ }
+
+ public NoAuthWithCOSException(Throwable t) {
+ super(t);
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/auth/SimpleCredentialProvider.java b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/auth/SimpleCredentialProvider.java
new file mode 100644
index 0000000000000..f0635fc0d00cf
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/auth/SimpleCredentialProvider.java
@@ -0,0 +1,54 @@
+/**
+ * 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
+ *
+ * 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.cosn.auth;
+
+import com.qcloud.cos.auth.BasicCOSCredentials;
+import com.qcloud.cos.auth.COSCredentials;
+import com.qcloud.cos.auth.COSCredentialsProvider;
+import com.qcloud.cos.exception.CosClientException;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.cosn.CosNConfigKeys;
+
+/**
+ * Get the credentials from the hadoop configuration.
+ */
+public class SimpleCredentialProvider implements COSCredentialsProvider {
+ private String secretId;
+ private String secretKey;
+
+ public SimpleCredentialProvider(Configuration conf) {
+ this.secretId = conf.get(
+ CosNConfigKeys.COSN_SECRET_ID_KEY
+ );
+ this.secretKey = conf.get(
+ CosNConfigKeys.COSN_SECRET_KEY_KEY
+ );
+ }
+
+ @Override
+ public COSCredentials getCredentials() {
+ if (!StringUtils.isEmpty(this.secretId)
+ && !StringUtils.isEmpty(this.secretKey)) {
+ return new BasicCOSCredentials(this.secretId, this.secretKey);
+ }
+ throw new CosClientException("secret id or secret key is unset");
+ }
+
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/auth/package-info.java b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/auth/package-info.java
new file mode 100644
index 0000000000000..4b6f8cf48b9b2
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/auth/package-info.java
@@ -0,0 +1,18 @@
+/**
+ * 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
+ *
+ * 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.cosn.auth;
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/package-info.java b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/package-info.java
new file mode 100644
index 0000000000000..b46608239ab5f
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/package-info.java
@@ -0,0 +1,18 @@
+/**
+ * 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
+ *
+ * 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.cosn;
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/CosNTestConfigKey.java b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/CosNTestConfigKey.java
new file mode 100644
index 0000000000000..4d5ee4814c3b9
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/CosNTestConfigKey.java
@@ -0,0 +1,33 @@
+/**
+ * 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
+ *
+ * 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.cosn;
+
+/**
+ * Configuration options for the CosN file system for testing.
+ */
+public final class CosNTestConfigKey {
+ private CosNTestConfigKey() {
+ }
+
+ public static final String TEST_COS_FILESYSTEM_CONF_KEY =
+ "test.fs.cosn.name";
+ public static final String DEFAULT_TEST_COS_FILESYSTEM_CONF_VALUE =
+ "";
+ public static final String TEST_UNIQUE_FORK_ID_KEY =
+ "test.unique.fork.id";
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/CosNTestUtils.java b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/CosNTestUtils.java
new file mode 100644
index 0000000000000..8afce51b1717c
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/CosNTestUtils.java
@@ -0,0 +1,78 @@
+/**
+ * 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
+ *
+ * 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.cosn;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.Path;
+import org.junit.internal.AssumptionViolatedException;
+
+/**
+ * Utilities for the CosN tests.
+ */
+public final class CosNTestUtils {
+
+ private CosNTestUtils() {
+ }
+
+ /**
+ * Create the file system for test.
+ *
+ * @param configuration hadoop's configuration
+ * @return The file system for test
+ * @throws IOException If fail to create or initialize the file system.
+ */
+ public static CosNFileSystem createTestFileSystem(
+ Configuration configuration) throws IOException {
+ String fsName = configuration.getTrimmed(
+ CosNTestConfigKey.TEST_COS_FILESYSTEM_CONF_KEY,
+ CosNTestConfigKey.DEFAULT_TEST_COS_FILESYSTEM_CONF_VALUE);
+
+ boolean liveTest = StringUtils.isNotEmpty(fsName);
+ URI testUri;
+ if (liveTest) {
+ testUri = URI.create(fsName);
+ liveTest = testUri.getScheme().equals(CosNFileSystem.SCHEME);
+ } else {
+ throw new AssumptionViolatedException("no test file system in " +
+ fsName);
+ }
+
+ CosNFileSystem cosFs = new CosNFileSystem();
+ cosFs.initialize(testUri, configuration);
+ return cosFs;
+ }
+
+ /**
+ * Create a dir path for test.
+ * The value of {@link CosNTestConfigKey#TEST_UNIQUE_FORK_ID_KEY}
+ * will be used if it is set.
+ *
+ * @param defVal default value
+ * @return The test path
+ */
+ public static Path createTestPath(Path defVal) {
+ String testUniqueForkId = System.getProperty(
+ CosNTestConfigKey.TEST_UNIQUE_FORK_ID_KEY);
+ return testUniqueForkId ==
+ null ? defVal : new Path("/" + testUniqueForkId, "test");
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/TestCosNInputStream.java b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/TestCosNInputStream.java
new file mode 100644
index 0000000000000..79884bad070c2
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/TestCosNInputStream.java
@@ -0,0 +1,167 @@
+/**
+ * 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
+ *
+ * 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.cosn;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.contract.ContractTestUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.Before;
+import org.junit.After;
+import org.junit.rules.Timeout;
+
+import java.io.IOException;
+
+/**
+ * CosNOutputStream Tester.
+ *
+ * If the test.fs.cosn.name property is not set, all test case will fail.
+ */
+public class TestCosNOutputStream {
+ private FileSystem fs;
+ private Path testRootDir;
+
+ @Rule
+ public Timeout timeout = new Timeout(3600 * 1000);
+
+ @Before
+ public void setUp() throws Exception {
+ Configuration configuration = new Configuration();
+ configuration.setInt(
+ CosNConfigKeys.COSN_BLOCK_SIZE_KEY, 2 * Unit.MB);
+ configuration.setLong(
+ CosNConfigKeys.COSN_UPLOAD_BUFFER_SIZE_KEY,
+ CosNConfigKeys.DEFAULT_UPLOAD_BUFFER_SIZE);
+ this.fs = CosNTestUtils.createTestFileSystem(configuration);
+ this.testRootDir = new Path("/test");
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void testEmptyFileUpload() throws IOException {
+ ContractTestUtils.createAndVerifyFile(this.fs, this.testRootDir, 0);
+ }
+
+ @Test
+ public void testSingleFileUpload() throws IOException {
+ ContractTestUtils.createAndVerifyFile(
+ this.fs, this.testRootDir, 1 * Unit.MB - 1);
+ ContractTestUtils.createAndVerifyFile(
+ this.fs, this.testRootDir, 1 * Unit.MB);
+ ContractTestUtils.createAndVerifyFile(
+ this.fs, this.testRootDir, 2 * Unit.MB - 1);
+ }
+
+ @Test
+ public void testLargeFileUpload() throws IOException {
+ ContractTestUtils.createAndVerifyFile(
+ this.fs, this.testRootDir, 2 * Unit.MB);
+ ContractTestUtils.createAndVerifyFile(
+ this.fs, this.testRootDir, 2 * Unit.MB + 1);
+ ContractTestUtils.createAndVerifyFile(
+ this.fs, this.testRootDir, 100 * Unit.MB);
+ // In principle, a maximum boundary test (file size: 2MB * 10000 - 1)
+ // should be provided here,
+ // but it is skipped due to network bandwidth and test time constraints.
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/CosNContract.java b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/CosNContract.java
new file mode 100644
index 0000000000000..cd4097951d33b
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/CosNContract.java
@@ -0,0 +1,46 @@
+/**
+ * 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
+ *
+ * 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.cosn.contract;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.contract.AbstractBondedFSContract;
+import org.apache.hadoop.fs.cosn.CosNFileSystem;
+import org.apache.hadoop.fs.cosn.CosNTestUtils;
+
+/**
+ * The contract of CosN: only enabled if the test bucket is provided.
+ */
+public class CosNContract extends AbstractBondedFSContract {
+ private static final String CONTRACT_XML = "contract/cosn.xml";
+
+ protected CosNContract(Configuration conf) {
+ super(conf);
+ addConfResource(CONTRACT_XML);
+ }
+
+ @Override
+ public String getScheme() {
+ return CosNFileSystem.SCHEME;
+ }
+
+ @Override
+ public Path getTestPath() {
+ return CosNTestUtils.createTestPath(super.getTestPath());
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractCreate.java b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractCreate.java
new file mode 100644
index 0000000000000..9488bd469af99
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractCreate.java
@@ -0,0 +1,32 @@
+/**
+ * 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
+ *
+ * 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.cosn.contract;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.contract.AbstractContractCreateTest;
+import org.apache.hadoop.fs.contract.AbstractFSContract;
+
+/**
+ * CosN contract tests for creating files.
+ */
+public class TestCosNContractCreate extends AbstractContractCreateTest {
+ @Override
+ protected AbstractFSContract createContract(Configuration configuration) {
+ return new CosNContract(configuration);
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractDelete.java b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractDelete.java
new file mode 100644
index 0000000000000..1c23ac218453f
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractDelete.java
@@ -0,0 +1,32 @@
+/**
+ * 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
+ *
+ * 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.cosn.contract;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.contract.AbstractContractDeleteTest;
+import org.apache.hadoop.fs.contract.AbstractFSContract;
+
+/**
+ * CosN contract tests for deleting files.
+ */
+public class TestCosNContractDelete extends AbstractContractDeleteTest {
+ @Override
+ protected AbstractFSContract createContract(Configuration configuration) {
+ return new CosNContract(configuration);
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractDistCp.java b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractDistCp.java
new file mode 100644
index 0000000000000..75ac53b9de8fb
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractDistCp.java
@@ -0,0 +1,54 @@
+/**
+ * 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
+ *
+ * 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.cosn.contract;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.contract.AbstractFSContract;
+import org.apache.hadoop.fs.cosn.CosNConfigKeys;
+import org.apache.hadoop.fs.cosn.Unit;
+import org.apache.hadoop.tools.contract.AbstractContractDistCpTest;
+
+/**
+ * Contract test suit covering CosN integration with DistCp.
+ */
+public class TestCosNContractDistCp extends AbstractContractDistCpTest {
+
+ private static final int MULTIPART_SETTING = 2 * Unit.MB;
+ private static final long UPLOAD_BUFFER_POOL_SIZE = 5 * 2 * Unit.MB;
+ private static final int UPLOAD_THREAD_POOL_SIZE = 5;
+ private static final int COPY_THREAD_POOL_SIZE = 3;
+
+ @Override
+ protected AbstractFSContract createContract(Configuration conf) {
+ return new CosNContract(conf);
+ }
+
+ @Override
+ protected Configuration createConfiguration() {
+ Configuration newConf = super.createConfiguration();
+ newConf.setInt(CosNConfigKeys.COSN_BLOCK_SIZE_KEY,
+ MULTIPART_SETTING);
+ newConf.setLong(CosNConfigKeys.COSN_UPLOAD_BUFFER_SIZE_KEY,
+ UPLOAD_BUFFER_POOL_SIZE);
+ newConf.setInt(CosNConfigKeys.UPLOAD_THREAD_POOL_SIZE_KEY,
+ UPLOAD_THREAD_POOL_SIZE);
+ newConf.setInt(CosNConfigKeys.COPY_THREAD_POOL_SIZE_KEY,
+ COPY_THREAD_POOL_SIZE);
+ return newConf;
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractGetFileStatus.java b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractGetFileStatus.java
new file mode 100644
index 0000000000000..9fba6eef44f36
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractGetFileStatus.java
@@ -0,0 +1,33 @@
+/**
+ * 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
+ *
+ * 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.cosn.contract;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.contract.AbstractContractGetFileStatusTest;
+import org.apache.hadoop.fs.contract.AbstractFSContract;
+
+/**
+ * CosN contract tests covering getFileStatus.
+ */
+public class TestCosNContractGetFileStatus
+ extends AbstractContractGetFileStatusTest {
+ @Override
+ protected AbstractFSContract createContract(Configuration conf) {
+ return new CosNContract(conf);
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractMkdir.java b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractMkdir.java
new file mode 100644
index 0000000000000..e704e13df856a
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractMkdir.java
@@ -0,0 +1,32 @@
+/**
+ * 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
+ *
+ * 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.cosn.contract;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.contract.AbstractContractMkdirTest;
+import org.apache.hadoop.fs.contract.AbstractFSContract;
+
+/**
+ * CosN contract tests for making directories.
+ */
+public class TestCosNContractMkdir extends AbstractContractMkdirTest {
+ @Override
+ protected AbstractFSContract createContract(Configuration configuration) {
+ return new CosNContract(configuration);
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractOpen.java b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractOpen.java
new file mode 100644
index 0000000000000..1bb732b312bf6
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractOpen.java
@@ -0,0 +1,32 @@
+/**
+ * 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
+ *
+ * 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.cosn.contract;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.contract.AbstractContractOpenTest;
+import org.apache.hadoop.fs.contract.AbstractFSContract;
+
+/**
+ * CosN contract tests for opening files.
+ */
+public class TestCosNContractOpen extends AbstractContractOpenTest {
+ @Override
+ protected AbstractFSContract createContract(Configuration configuration) {
+ return new CosNContract(configuration);
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractRename.java b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractRename.java
new file mode 100644
index 0000000000000..f82c8dfb4cb87
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractRename.java
@@ -0,0 +1,32 @@
+/**
+ * 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
+ *
+ * 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.cosn.contract;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.contract.AbstractContractRenameTest;
+import org.apache.hadoop.fs.contract.AbstractFSContract;
+
+/**
+ * CosN contract tests for renaming a file.
+ */
+public class TestCosNContractRename extends AbstractContractRenameTest {
+ @Override
+ protected AbstractFSContract createContract(Configuration configuration) {
+ return new CosNContract(configuration);
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractRootDir.java b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractRootDir.java
new file mode 100644
index 0000000000000..145aee9ca1048
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractRootDir.java
@@ -0,0 +1,33 @@
+/**
+ * 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
+ *
+ * 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.cosn.contract;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.contract.AbstractContractRootDirectoryTest;
+import org.apache.hadoop.fs.contract.AbstractFSContract;
+
+/**
+ * root dir operations against an COS bucket.
+ */
+public class TestCosNContractRootDir
+ extends AbstractContractRootDirectoryTest {
+ @Override
+ protected AbstractFSContract createContract(Configuration configuration) {
+ return new CosNContract(configuration);
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractSeek.java b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractSeek.java
new file mode 100644
index 0000000000000..e3915676ee3bd
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/TestCosNContractSeek.java
@@ -0,0 +1,32 @@
+/**
+ * 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
+ *
+ * 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.cosn.contract;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.contract.AbstractContractSeekTest;
+import org.apache.hadoop.fs.contract.AbstractFSContract;
+
+/**
+ * CosN contract tests for seeking a position in a file.
+ */
+public class TestCosNContractSeek extends AbstractContractSeekTest {
+ @Override
+ protected AbstractFSContract createContract(Configuration configuration) {
+ return new CosNContract(configuration);
+ }
+}
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/package-info.java b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/package-info.java
new file mode 100644
index 0000000000000..97598b10bc73a
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/test/java/org/apache/hadoop/fs/cosn/contract/package-info.java
@@ -0,0 +1,18 @@
+/**
+ * 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
+ *
+ * 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.cosn.contract;
\ No newline at end of file
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/test/resources/contract/cosn.xml b/hadoop-cloud-storage-project/hadoop-cos/src/test/resources/contract/cosn.xml
new file mode 100644
index 0000000000000..ac4f58c066be0
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/test/resources/contract/cosn.xml
@@ -0,0 +1,120 @@
+
+
+
+
+ fs.contract.test.root-tests-enabled
+ true
+
+
+
+ fs.contract.is-blobstore
+ true
+
+
+
+ fs.contract.create-overwrites-directory
+ true
+
+
+
+ fs.contract.create-visibility-delayed
+ true
+
+
+
+ fs.contract.is-case-sensitive
+ true
+
+
+
+ fs.contract.rename-returns-false-if-source-missing
+ false
+
+
+
+ fs.contract.rename-remove-dest-if-empty-dir
+ false
+
+
+
+ fs.contract.supports-append
+ false
+
+
+
+ fs.contract.supports-atomic-directory-delete
+ false
+
+
+
+ fs.contract.supports-atomic-rename
+ false
+
+
+
+ fs.contract.supports-block-locality
+ false
+
+
+
+ fs.contract.supports-concat
+ false
+
+
+
+ fs.contract.supports-seek
+ true
+
+
+
+ fs.contract.supports-seek-on-closed-file
+ false
+
+
+
+ fs.contract.rejects-seek-past-eof
+ true
+
+
+
+ fs.contract.rename-overwrites-dest
+ false
+
+
+
+ fs.contract.supports-getfilestatus
+ true
+
+
+
+ fs.contract.supports-unix-permissions
+ false
+
+
+
+ fs.contract.supports-strict-exceptions
+ true
+
+
+
+ fs.contract.test.random-seek-count
+ 10
+
+
+
\ No newline at end of file
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/test/resources/core-site.xml b/hadoop-cloud-storage-project/hadoop-cos/src/test/resources/core-site.xml
new file mode 100644
index 0000000000000..fbd23bb326eb4
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/test/resources/core-site.xml
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+
+ fs.cosn.credentials.provider
+ org.apache.hadoop.fs.cosn.auth.SimpleCredentialProvider
+
+ This option allows the user to specify how to get the credentials.
+ Comma-separated class names of credential provider classes which
+ implement
+ com.qcloud.cos.auth.COSCredentialsProvider:
+
+ 1.org.apache.hadoop.fs.cosn.auth.SimpleCredentialProvider: Obtain the
+ secret id and secret key
+ from fs.cosn.userinfo.secretId and fs.cosn.userinfo.secretKey in
+ core-site.xml
+ 2.org.apache.hadoop.fs.cosn.auth.EnvironmentVariableCredentialProvider:
+ Obtain the secret id and secret key
+ from the system environment variables named COS_SECRET_ID and
+ COS_SECRET_KEY
+
+ If unspecified, the default order of credential providers is:
+ 1. org.apache.hadoop.fs.cosn.auth.SimpleCredentialProvider
+ 2. org.apache.hadoop.fs.cosn.auth.EnvironmentVariableCredentialProvider
+
+
+
+ fs.cosn.impl
+ org.apache.hadoop.fs.cosn.CosNFileSystem
+
+ The implementation class of the CosN Filesystem.
+
+
+
+
+ fs.AbstractFileSystem.cosn.impl
+ org.apache.hadoop.fs.cosn.CosN
+
+ The implementation class of the CosN AbstractFileSystem.
+
+
+
+
+ fs.cosn.tmp.dir
+ /tmp/hadoop_cos
+
+ Temporary files will be placed here.
+
+
+
+
+ fs.cosn.block.size
+ 8388608
+
+ Block size to use cosn filesystem, which is the part size for
+ MultipartUpload.
+ Considering the COS supports up to 10000 blocks, user should
+ estimate the maximum size of a single file.
+ for example, 8MB part size can allow writing a 78GB single file.
+
+
+
+
+ fs.cosn.upload.buffer.size
+ 536870912
+ The total size of the memory buffer pool.
+
+
+
+ fs.cosn.read.ahead.block.size
+ 1048576
+
+ Bytes to read ahead during a seek() before closing and
+ re-opening the cosn HTTP connection.
+
+
+
+
+ fs.cosn.read.ahead.queue.size
+ 64
+
+ The length of the pre-read queue.
+
+
+
+
+
+
+
+
diff --git a/hadoop-cloud-storage-project/hadoop-cos/src/test/resources/log4j.properties b/hadoop-cloud-storage-project/hadoop-cos/src/test/resources/log4j.properties
new file mode 100644
index 0000000000000..1a6baaec65ae7
--- /dev/null
+++ b/hadoop-cloud-storage-project/hadoop-cos/src/test/resources/log4j.properties
@@ -0,0 +1,18 @@
+# Licensed 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.
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=info,stdout
+log4j.threshhold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n
diff --git a/hadoop-cloud-storage-project/pom.xml b/hadoop-cloud-storage-project/pom.xml
index 50dd70ef6169a..f39e8c3aaf9f8 100644
--- a/hadoop-cloud-storage-project/pom.xml
+++ b/hadoop-cloud-storage-project/pom.xml
@@ -15,7 +15,7 @@
+ https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0org.apache.hadoop
@@ -31,6 +31,7 @@
hadoop-cloud-storage
+ hadoop-cos
diff --git a/hadoop-common-project/hadoop-annotations/pom.xml b/hadoop-common-project/hadoop-annotations/pom.xml
index d8373c801f5c6..738f0ada8f1e9 100644
--- a/hadoop-common-project/hadoop-annotations/pom.xml
+++ b/hadoop-common-project/hadoop-annotations/pom.xml
@@ -15,7 +15,7 @@
+ https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0org.apache.hadoop
diff --git a/hadoop-common-project/hadoop-auth-examples/pom.xml b/hadoop-common-project/hadoop-auth-examples/pom.xml
index a105885654a1a..fb904912999b8 100644
--- a/hadoop-common-project/hadoop-auth-examples/pom.xml
+++ b/hadoop-common-project/hadoop-auth-examples/pom.xml
@@ -15,7 +15,7 @@
+ https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0org.apache.hadoop
diff --git a/hadoop-common-project/hadoop-auth/pom.xml b/hadoop-common-project/hadoop-auth/pom.xml
index d9ea33dfb2189..20a3e7059b154 100644
--- a/hadoop-common-project/hadoop-auth/pom.xml
+++ b/hadoop-common-project/hadoop-auth/pom.xml
@@ -15,7 +15,7 @@
+ https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0org.apache.hadoop
diff --git a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java
index 5aeddac26d4ca..94d11f48cf2a9 100644
--- a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java
+++ b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java
@@ -681,7 +681,7 @@ public static void createAuthCookie(HttpServletResponse resp, String token,
if (expires >= 0 && isCookiePersistent) {
Date date = new Date(expires);
SimpleDateFormat df = new SimpleDateFormat("EEE, " +
- "dd-MMM-yyyy HH:mm:ss zzz");
+ "dd-MMM-yyyy HH:mm:ss zzz", Locale.US);
df.setTimeZone(TimeZone.getTimeZone("GMT"));
sb.append("; Expires=").append(df.format(date));
}
diff --git a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/KerberosAuthenticationHandler.java b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/KerberosAuthenticationHandler.java
index 7a918b20bb606..50eeb2a965e27 100644
--- a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/KerberosAuthenticationHandler.java
+++ b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/KerberosAuthenticationHandler.java
@@ -13,6 +13,7 @@
*/
package org.apache.hadoop.security.authentication.server;
+import com.google.common.annotations.VisibleForTesting;
import org.apache.hadoop.security.authentication.client.AuthenticationException;
import org.apache.hadoop.security.authentication.client.KerberosAuthenticator;
import org.apache.commons.codec.binary.Base64;
@@ -38,6 +39,8 @@
import java.security.Principal;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
+import java.util.Collection;
+import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Pattern;
@@ -94,10 +97,18 @@ public class KerberosAuthenticationHandler implements AuthenticationHandler {
*/
public static final String RULE_MECHANISM = TYPE + ".name.rules.mechanism";
+ /**
+ * Constant for the list of endpoints that skips Kerberos authentication.
+ */
+ @VisibleForTesting
+ static final String ENDPOINT_WHITELIST = TYPE + ".endpoint.whitelist";
+ private static final Pattern ENDPOINT_PATTERN = Pattern.compile("^/[\\w]+");
+
private String type;
private String keytab;
private GSSManager gssManager;
private Subject serverSubject = new Subject();
+ private final Collection whitelist = new HashSet<>();
/**
* Creates a Kerberos SPNEGO authentication handler with the default
@@ -173,6 +184,22 @@ public void init(Properties config) throws ServletException {
if (ruleMechanism != null) {
KerberosName.setRuleMechanism(ruleMechanism);
}
+
+ final String whitelistStr = config.getProperty(ENDPOINT_WHITELIST, null);
+ if (whitelistStr != null) {
+ final String[] strs = whitelistStr.trim().split("\\s*[,\n]\\s*");
+ for (String s: strs) {
+ if (s.isEmpty()) continue;
+ if (ENDPOINT_PATTERN.matcher(s).matches()) {
+ whitelist.add(s);
+ } else {
+ throw new ServletException(
+ "The element of the whitelist: " + s + " must start with '/'"
+ + " and must not contain special characters afterwards");
+ }
+ }
+ }
+
try {
gssManager = Subject.doAs(serverSubject,
new PrivilegedExceptionAction() {
@@ -269,6 +296,16 @@ public boolean managementOperation(AuthenticationToken token,
public AuthenticationToken authenticate(HttpServletRequest request,
final HttpServletResponse response)
throws IOException, AuthenticationException {
+
+ // If the request servlet path is in the whitelist,
+ // skip Kerberos authentication and return anonymous token.
+ final String path = request.getServletPath();
+ for(final String endpoint: whitelist) {
+ if (endpoint.equals(path)) {
+ return AuthenticationToken.ANONYMOUS;
+ }
+ }
+
AuthenticationToken token = null;
String authorization = request.getHeader(
KerberosAuthenticator.AUTHORIZATION);
diff --git a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/LdapAuthenticationHandler.java b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/LdapAuthenticationHandler.java
index f452317f931a1..8cc8d03447a99 100644
--- a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/LdapAuthenticationHandler.java
+++ b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/LdapAuthenticationHandler.java
@@ -96,9 +96,8 @@ public class LdapAuthenticationHandler implements AuthenticationHandler {
public static final String LDAP_BIND_DOMAIN = TYPE + ".binddomain";
/**
- * Constant for the configuration property that indicates the base
- * distinguished name (DN) to be used with the LDAP server. This value is
- * appended to the provided user id for authentication purpose.
+ * Constant for the configuration property that indicates whether
+ * the LDAP server supports 'StartTLS' extension.
*/
public static final String ENABLE_START_TLS = TYPE + ".enablestarttls";
@@ -336,4 +335,4 @@ private static int indexOfDomainMatch(String userName) {
return endIdx;
}
-}
\ No newline at end of file
+}
diff --git a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/KerberosName.java b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/KerberosName.java
index 684d2c8c1e8ce..67c2c10237d49 100644
--- a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/KerberosName.java
+++ b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/KerberosName.java
@@ -281,7 +281,7 @@ static String replaceParameters(String format,
if (paramNum != null) {
try {
int num = Integer.parseInt(paramNum);
- if (num < 0 || num > params.length) {
+ if (num < 0 || num >= params.length) {
throw new BadFormatString("index " + num + " from " + format +
" is outside of the valid range 0 to " +
(params.length - 1));
diff --git a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/ZKSignerSecretProvider.java b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/ZKSignerSecretProvider.java
index a7fc76f6a12e4..f0c350ed9594b 100644
--- a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/ZKSignerSecretProvider.java
+++ b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/ZKSignerSecretProvider.java
@@ -15,7 +15,6 @@
import com.google.common.annotations.VisibleForTesting;
import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
import java.security.SecureRandom;
import java.util.Collections;
import java.util.HashMap;
@@ -36,7 +35,7 @@
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs.Perms;
-import org.apache.zookeeper.client.ZooKeeperSaslClient;
+import org.apache.zookeeper.client.ZKClientConfig;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Id;
import org.apache.zookeeper.data.Stat;
@@ -368,7 +367,7 @@ protected CuratorFramework createCuratorClient(Properties config)
LOG.info("Connecting to ZooKeeper with SASL/Kerberos"
+ "and using 'sasl' ACLs");
String principal = setJaasConfiguration(config);
- System.setProperty(ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY,
+ System.setProperty(ZKClientConfig.LOGIN_CONTEXT_NAME_KEY,
JAAS_LOGIN_ENTRY_NAME);
System.setProperty("zookeeper.authProvider.1",
"org.apache.zookeeper.server.auth.SASLAuthenticationProvider");
diff --git a/hadoop-common-project/hadoop-auth/src/site/markdown/Examples.md b/hadoop-common-project/hadoop-auth/src/site/markdown/Examples.md
index 4dad79dd063ae..4f29c8da5cf40 100644
--- a/hadoop-common-project/hadoop-auth/src/site/markdown/Examples.md
+++ b/hadoop-common-project/hadoop-auth/src/site/markdown/Examples.md
@@ -36,14 +36,14 @@ Login to the KDC using **kinit** and then use `curl` to fetch protected URL:
$ kinit
Please enter the password for tucu@LOCALHOST:
- $ curl --negotiate -u foo -b ~/cookiejar.txt -c ~/cookiejar.txt http://localhost:8080/hadoop-auth-examples/kerberos/who
+ $ curl --negotiate -u : -b ~/cookiejar.txt -c ~/cookiejar.txt http://$(hostname -f):8080/hadoop-auth-examples/kerberos/who
Enter host password for user 'tucu':
Hello Hadoop Auth Examples!
* The `--negotiate` option enables SPNEGO in `curl`.
-* The `-u foo` option is required but the user ignored (the principal
+* The `-u :` option is required but the user ignored (the principal
that has been kinit-ed is used).
* The `-b` and `-c` are use to store and send HTTP Cookies.
@@ -88,7 +88,7 @@ Try accessing protected resources using `curl`. The protected resources are:
$ curl http://localhost:8080/hadoop-auth-examples/simple/who?user.name=foo
- $ curl --negotiate -u foo -b ~/cookiejar.txt -c ~/cookiejar.txt http://localhost:8080/hadoop-auth-examples/kerberos/who
+ $ curl --negotiate -u : -b ~/cookiejar.txt -c ~/cookiejar.txt http://$(hostname -f):8080/hadoop-auth-examples/kerberos/who
### Accessing the server using the Java client example
diff --git a/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestKerberosAuthenticationHandler.java b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestKerberosAuthenticationHandler.java
index bef3018ca4a70..629b68bffbbd9 100644
--- a/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestKerberosAuthenticationHandler.java
+++ b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestKerberosAuthenticationHandler.java
@@ -89,6 +89,9 @@ public void setup() throws Exception {
// handler
handler = getNewAuthenticationHandler();
Properties props = getDefaultProperties();
+ // Set whitelist for testing
+ props.setProperty(KerberosAuthenticationHandler.ENDPOINT_WHITELIST,
+ "/white,/white2,/white3");
try {
handler.init(props);
} catch (Exception ex) {
@@ -371,6 +374,27 @@ public void testRequestWithInvalidKerberosAuthorization() {
}
}
+ @Test
+ public void testRequestToWhitelist() throws Exception {
+ final String token = new Base64(0).encodeToString(new byte[]{0, 1, 2});
+ final HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ final HttpServletResponse response =
+ Mockito.mock(HttpServletResponse.class);
+ Mockito.when(request.getHeader(KerberosAuthenticator.AUTHORIZATION))
+ .thenReturn(KerberosAuthenticator.NEGOTIATE + token);
+ Mockito.when(request.getServletPath()).thenReturn("/white");
+ handler.authenticate(request, response);
+ Mockito.when(request.getServletPath()).thenReturn("/white4");
+ try {
+ handler.authenticate(request, response);
+ Assert.fail();
+ } catch (AuthenticationException ex) {
+ // Expected
+ } catch (Exception ex) {
+ Assert.fail();
+ }
+ }
+
@After
public void tearDown() throws Exception {
if (handler != null) {
diff --git a/hadoop-common-project/hadoop-common/dev-support/jdiff/Apache_Hadoop_Common_2.10.0.xml b/hadoop-common-project/hadoop-common/dev-support/jdiff/Apache_Hadoop_Common_2.10.0.xml
new file mode 100644
index 0000000000000..7b63a07b309c7
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/dev-support/jdiff/Apache_Hadoop_Common_2.10.0.xml
@@ -0,0 +1,40847 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ UnsupportedOperationException
+
+ If a key is deprecated in favor of multiple keys, they are all treated as
+ aliases of each other, and setting any one of them resets all the others
+ to the new value.
+
+ If you have multiple deprecation entries to add, it is more efficient to
+ use #addDeprecations(DeprecationDelta[] deltas) instead.
+
+ @param key
+ @param newKeys
+ @param customMessage
+ @deprecated use {@link #addDeprecation(String key, String newKey,
+ String customMessage)} instead]]>
+
+
+
+
+
+
+
+ UnsupportedOperationException
+
+ If you have multiple deprecation entries to add, it is more efficient to
+ use #addDeprecations(DeprecationDelta[] deltas) instead.
+
+ @param key
+ @param newKey
+ @param customMessage]]>
+
+
+
+
+
+
+ UnsupportedOperationException
+
+ If a key is deprecated in favor of multiple keys, they are all treated as
+ aliases of each other, and setting any one of them resets all the others
+ to the new value.
+
+ If you have multiple deprecation entries to add, it is more efficient to
+ use #addDeprecations(DeprecationDelta[] deltas) instead.
+
+ @param key Key that is to be deprecated
+ @param newKeys list of keys that take up the values of deprecated key
+ @deprecated use {@link #addDeprecation(String key, String newKey)} instead]]>
+
+
+
+
+
+
+ UnsupportedOperationException
+
+ If you have multiple deprecation entries to add, it is more efficient to
+ use #addDeprecations(DeprecationDelta[] deltas) instead.
+
+ @param key Key that is to be deprecated
+ @param newKey key that takes up the value of deprecated key]]>
+
+
+
+
+
+ key is deprecated.
+
+ @param key the parameter which is to be checked for deprecation
+ @return true if the key is deprecated and
+ false otherwise.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ final.
+
+ @param name resource to be added, the classpath is examined for a file
+ with that name.]]>
+
+
+
+
+
+
+
+
+
+ final.
+
+ @param url url of the resource to be added, the local filesystem is
+ examined directly to find the resource, without referring to
+ the classpath.]]>
+
+
+
+
+
+
+
+
+
+ final.
+
+ @param file file-path of resource to be added, the local filesystem is
+ examined directly to find the resource, without referring to
+ the classpath.]]>
+
+
+
+
+
+
+
+
+
+ final.
+
+ WARNING: The contents of the InputStream will be cached, by this method.
+ So use this sparingly because it does increase the memory consumption.
+
+ @param in InputStream to deserialize the object from. In will be read from
+ when a get or set is called next. After it is read the stream will be
+ closed.]]>
+
+
+
+
+
+
+
+
+
+
+ final.
+
+ @param in InputStream to deserialize the object from.
+ @param name the name of the resource because InputStream.toString is not
+ very descriptive some times.]]>
+
+
+
+
+
+
+
+
+
+
+ final.
+
+ @param conf Configuration object from which to load properties]]>
+
+
+
+
+
+
+
+
+
+
+ name property, null if
+ no such property exists. If the key is deprecated, it returns the value of
+ the first key which replaces the deprecated key and is not null.
+
+ Values are processed for variable expansion
+ before being returned.
+
+ @param name the property name, will be trimmed before get value.
+ @return the value of the name or its replacing property,
+ or null if no such property exists.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ name property, but only for
+ names which have no valid value, usually non-existent or commented
+ out in XML.
+
+ @param name the property name
+ @return true if the property name exists without value]]>
+
+
+
+
+
+ name property as a trimmed String,
+ null if no such property exists.
+ If the key is deprecated, it returns the value of
+ the first key which replaces the deprecated key and is not null
+
+ Values are processed for variable expansion
+ before being returned.
+
+ @param name the property name.
+ @return the value of the name or its replacing property,
+ or null if no such property exists.]]>
+
+
+
+
+
+
+ name property as a trimmed String,
+ defaultValue if no such property exists.
+ See @{Configuration#getTrimmed} for more details.
+
+ @param name the property name.
+ @param defaultValue the property default value.
+ @return the value of the name or defaultValue
+ if it is not set.]]>
+
+
+
+
+
+ name property, without doing
+ variable expansion.If the key is
+ deprecated, it returns the value of the first key which replaces
+ the deprecated key and is not null.
+
+ @param name the property name.
+ @return the value of the name property or
+ its replacing property and null if no such property exists.]]>
+
+
+
+
+
+
+ value of the name property. If
+ name is deprecated or there is a deprecated name associated to it,
+ it sets the value to both names. Name will be trimmed before put into
+ configuration.
+
+ @param name property name.
+ @param value property value.]]>
+
+
+
+
+
+
+
+ value of the name property. If
+ name is deprecated, it also sets the value to
+ the keys that replace the deprecated key. Name will be trimmed before put
+ into configuration.
+
+ @param name property name.
+ @param value property value.
+ @param source the place that this configuration value came from
+ (For debugging).
+ @throws IllegalArgumentException when the value or name is null.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ name. If the key is deprecated,
+ it returns the value of the first key which replaces the deprecated key
+ and is not null.
+ If no such property exists,
+ then defaultValue is returned.
+
+ @param name property name, will be trimmed before get value.
+ @param defaultValue default value.
+ @return property value, or defaultValue if the property
+ doesn't exist.]]>
+
+
+
+
+
+
+ name property as an int.
+
+ If no such property exists, the provided default value is returned,
+ or if the specified value is not a valid int,
+ then an error is thrown.
+
+ @param name property name.
+ @param defaultValue default value.
+ @throws NumberFormatException when the value is invalid
+ @return property value as an int,
+ or defaultValue.]]>
+
+
+
+
+
+ name property as a set of comma-delimited
+ int values.
+
+ If no such property exists, an empty array is returned.
+
+ @param name property name
+ @return property value interpreted as an array of comma-delimited
+ int values]]>
+
+
+
+
+
+
+ name property to an int.
+
+ @param name property name.
+ @param value int value of the property.]]>
+
+
+
+
+
+
+ name property as a long.
+ If no such property exists, the provided default value is returned,
+ or if the specified value is not a valid long,
+ then an error is thrown.
+
+ @param name property name.
+ @param defaultValue default value.
+ @throws NumberFormatException when the value is invalid
+ @return property value as a long,
+ or defaultValue.]]>
+
+
+
+
+
+
+ name property as a long or
+ human readable format. If no such property exists, the provided default
+ value is returned, or if the specified value is not a valid
+ long or human readable format, then an error is thrown. You
+ can use the following suffix (case insensitive): k(kilo), m(mega), g(giga),
+ t(tera), p(peta), e(exa)
+
+ @param name property name.
+ @param defaultValue default value.
+ @throws NumberFormatException when the value is invalid
+ @return property value as a long,
+ or defaultValue.]]>
+
+
+
+
+
+
+ name property to a long.
+
+ @param name property name.
+ @param value long value of the property.]]>
+
+
+
+
+
+
+ name property as a float.
+ If no such property exists, the provided default value is returned,
+ or if the specified value is not a valid float,
+ then an error is thrown.
+
+ @param name property name.
+ @param defaultValue default value.
+ @throws NumberFormatException when the value is invalid
+ @return property value as a float,
+ or defaultValue.]]>
+
+
+
+
+
+
+ name property to a float.
+
+ @param name property name.
+ @param value property value.]]>
+
+
+
+
+
+
+ name property as a double.
+ If no such property exists, the provided default value is returned,
+ or if the specified value is not a valid double,
+ then an error is thrown.
+
+ @param name property name.
+ @param defaultValue default value.
+ @throws NumberFormatException when the value is invalid
+ @return property value as a double,
+ or defaultValue.]]>
+
+
+
+
+
+
+ name property to a double.
+
+ @param name property name.
+ @param value property value.]]>
+
+
+
+
+
+
+ name property as a boolean.
+ If no such property is specified, or if the specified value is not a valid
+ boolean, then defaultValue is returned.
+
+ @param name property name.
+ @param defaultValue default value.
+ @return property value as a boolean,
+ or defaultValue.]]>
+
+
+
+
+
+
+ name property to a boolean.
+
+ @param name property name.
+ @param value boolean value of the property.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ name property to the given type. This
+ is equivalent to set(<name>, value.toString()).
+ @param name property name
+ @param value new value]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ name to the given time duration. This
+ is equivalent to set(<name>, value + <time suffix>).
+ @param name Property name
+ @param value Time duration
+ @param unit Unit of time]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ name property as a Pattern.
+ If no such property is specified, or if the specified value is not a valid
+ Pattern, then DefaultValue is returned.
+ Note that the returned value is NOT trimmed by this method.
+
+ @param name property name
+ @param defaultValue default value
+ @return property value as a compiled Pattern, or defaultValue]]>
+
+
+
+
+
+
+ Pattern.
+ If the pattern is passed as null, sets the empty pattern which results in
+ further calls to getPattern(...) returning the default value.
+
+ @param name property name
+ @param pattern new value]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ name property as
+ a collection of Strings.
+ If no such property is specified then empty collection is returned.
+
+ This is an optimized version of {@link #getStrings(String)}
+
+ @param name property name.
+ @return property value as a collection of Strings.]]>
+
+
+
+
+
+ name property as
+ an array of Strings.
+ If no such property is specified then null is returned.
+
+ @param name property name.
+ @return property value as an array of Strings,
+ or null.]]>
+
+
+
+
+
+
+ name property as
+ an array of Strings.
+ If no such property is specified then default value is returned.
+
+ @param name property name.
+ @param defaultValue The default value
+ @return property value as an array of Strings,
+ or default value.]]>
+
+
+
+
+
+ name property as
+ a collection of Strings, trimmed of the leading and trailing whitespace.
+ If no such property is specified then empty Collection is returned.
+
+ @param name property name.
+ @return property value as a collection of Strings, or empty Collection]]>
+
+
+
+
+
+ name property as
+ an array of Strings, trimmed of the leading and trailing whitespace.
+ If no such property is specified then an empty array is returned.
+
+ @param name property name.
+ @return property value as an array of trimmed Strings,
+ or empty array.]]>
+
+
+
+
+
+
+ name property as
+ an array of Strings, trimmed of the leading and trailing whitespace.
+ If no such property is specified then default value is returned.
+
+ @param name property name.
+ @param defaultValue The default value
+ @return property value as an array of trimmed Strings,
+ or default value.]]>
+
+
+
+
+
+
+ name property as
+ as comma delimited values.
+
+ @param name property name.
+ @param values The values]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ hostProperty as a
+ InetSocketAddress. If hostProperty is
+ null, addressProperty will be used. This
+ is useful for cases where we want to differentiate between host
+ bind address and address clients should use to establish connection.
+
+ @param hostProperty bind host property name.
+ @param addressProperty address property name.
+ @param defaultAddressValue the default value
+ @param defaultPort the default port
+ @return InetSocketAddress]]>
+
+
+
+
+
+
+
+ name property as a
+ InetSocketAddress.
+ @param name property name.
+ @param defaultAddress the default value
+ @param defaultPort the default port
+ @return InetSocketAddress]]>
+
+
+
+
+
+
+ name property as
+ a host:port.]]>
+
+
+
+
+
+
+
+
+ name property as a host:port. The wildcard
+ address is replaced with the local host's address. If the host and address
+ properties are configured the host component of the address will be combined
+ with the port component of the addr to generate the address. This is to allow
+ optional control over which host name is used in multi-home bind-host
+ cases where a host can have multiple names
+ @param hostProperty the bind-host configuration name
+ @param addressProperty the service address configuration name
+ @param defaultAddressValue the service default address configuration value
+ @param addr InetSocketAddress of the service listener
+ @return InetSocketAddress for clients to connect]]>
+
+
+
+
+
+
+ name property as a host:port. The wildcard
+ address is replaced with the local host's address.
+ @param name property name.
+ @param addr InetSocketAddress of a listener to store in the given property
+ @return InetSocketAddress for clients to connect]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ name property
+ as an array of Class.
+ The value of the property specifies a list of comma separated class names.
+ If no such property is specified, then defaultValue is
+ returned.
+
+ @param name the property name.
+ @param defaultValue default value.
+ @return property value as a Class[],
+ or defaultValue.]]>
+
+
+
+
+
+
+ name property as a Class.
+ If no such property is specified, then defaultValue is
+ returned.
+
+ @param name the class name.
+ @param defaultValue default value.
+ @return property value as a Class,
+ or defaultValue.]]>
+
+
+
+
+
+
+
+ name property as a Class
+ implementing the interface specified by xface.
+
+ If no such property is specified, then defaultValue is
+ returned.
+
+ An exception is thrown if the returned class does not implement the named
+ interface.
+
+ @param name the class name.
+ @param defaultValue default value.
+ @param xface the interface implemented by the named class.
+ @return property value as a Class,
+ or defaultValue.]]>
+
+
+
+
+
+
+ name property as a List
+ of objects implementing the interface specified by xface.
+
+ An exception is thrown if any of the classes does not exist, or if it does
+ not implement the named interface.
+
+ @param name the property name.
+ @param xface the interface implemented by the classes named by
+ name.
+ @return a List of objects implementing xface.]]>
+
+
+
+
+
+
+
+ name property to the name of a
+ theClass implementing the given interface xface.
+
+ An exception is thrown if theClass does not implement the
+ interface xface.
+
+ @param name property name.
+ @param theClass property value.
+ @param xface the interface implemented by the named class.]]>
+
+
+
+
+
+
+
+ dirsProp with
+ the given path. If dirsProp contains multiple directories,
+ then one is chosen based on path's hash code. If the selected
+ directory does not exist, an attempt is made to create it.
+
+ @param dirsProp directory in which to locate the file.
+ @param path file-path.
+ @return local file under the directory with the given path.]]>
+
+
+
+
+
+
+
+ dirsProp with
+ the given path. If dirsProp contains multiple directories,
+ then one is chosen based on path's hash code. If the selected
+ directory does not exist, an attempt is made to create it.
+
+ @param dirsProp directory in which to locate the file.
+ @param path file-path.
+ @return local file under the directory with the given path.]]>
+
+
+
+
+
+
+
+
+
+
+
+ name.
+
+ @param name configuration resource name.
+ @return an input stream attached to the resource.]]>
+
+
+
+
+
+ name.
+
+ @param name configuration resource name.
+ @return a reader attached to the resource.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ String
+ key-value pairs in the configuration.
+
+ @return an iterator over the entries.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ When property name is not empty and the property exists in the
+ configuration, this method writes the property and its attributes
+ to the {@link Writer}.
+
+
+
+
+ When property name is null or empty, this method writes all the
+ configuration properties and their attributes to the {@link Writer}.
+
+
+
+
+ When property name is not empty but the property doesn't exist in
+ the configuration, this method throws an {@link IllegalArgumentException}.
+
+
+ @param out the writer to write to.]]>
+
+
+
+
+
+
+
+
+
+ When propertyName is not empty, and the property exists
+ in the configuration, the format of the output would be,
+
+ When propertyName is not empty, and the property is not
+ found in the configuration, this method will throw an
+ {@link IllegalArgumentException}.
+
+
+ @param config the configuration
+ @param propertyName property name
+ @param out the Writer to write to
+ @throws IOException
+ @throws IllegalArgumentException when property name is not
+ empty and the property is not found in configuration]]>
+
+
+
+
+
+
+
+
+ { "properties" :
+ [ { key : "key1",
+ value : "value1",
+ isFinal : "key1.isFinal",
+ resource : "key1.resource" },
+ { key : "key2",
+ value : "value2",
+ isFinal : "ke2.isFinal",
+ resource : "key2.resource" }
+ ]
+ }
+
+
+ It does not output the properties of the configuration object which
+ is loaded from an input stream.
+
+
+ @param config the configuration
+ @param out the Writer to write to
+ @throws IOException]]>
+
Configurations are specified by resources. A resource contains a set of
+ name/value pairs as XML data. Each resource is named by either a
+ String or by a {@link Path}. If named by a String,
+ then the classpath is examined for a file with that name. If named by a
+ Path, then the local filesystem is examined directly, without
+ referring to the classpath.
+
+
Unless explicitly turned off, Hadoop by default specifies two
+ resources, loaded in-order from the classpath:
core-site.xml: Site-specific configuration for a given hadoop
+ installation.
+
+ Applications may add additional resources, which are loaded
+ subsequent to these resources in the order they are added.
+
+
Final Parameters
+
+
Configuration parameters may be declared final.
+ Once a resource declares a value final, no subsequently-loaded
+ resource can alter that value.
+ For example, one might define a final parameter with:
+
+
+ When conf.get("tempdir") is called, then ${basedir}
+ will be resolved to another property in this Configuration, while
+ ${user.name} would then ordinarily be resolved to the value
+ of the System property with that name.
+
When conf.get("otherdir") is called, then ${env.BASE_DIR}
+ will be resolved to the value of the ${BASE_DIR} environment variable.
+ It supports ${env.NAME:-default} and ${env.NAME-default} notations.
+ The former is resolved to "default" if ${NAME} environment variable is undefined
+ or its value is empty.
+ The latter behaves the same way only if ${NAME} is undefined.
+
By default, warnings will be given to any deprecated configuration
+ parameters and these are suppressible by configuring
+ log4j.logger.org.apache.hadoop.conf.Configuration.deprecation in
+ log4j.properties file.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This implementation generates the key material and calls the
+ {@link #createKey(String, byte[], Options)} method.
+
+ @param name the base name of the key
+ @param options the options for the new key.
+ @return the version name of the first version of the key.
+ @throws IOException
+ @throws NoSuchAlgorithmException]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This implementation generates the key material and calls the
+ {@link #rollNewVersion(String, byte[])} method.
+
+ @param name the basename of the key
+ @return the name of the new version of the key
+ @throws IOException]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ KeyProvider implementations must be thread safe.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ NULL if
+ a provider for the specified URI scheme could not be found.
+ @throws IOException thrown if the provider failed to initialize.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ uri has syntax error]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ uri is
+ not found]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ uri
+ determines a configuration property name,
+ fs.AbstractFileSystem.scheme.impl whose value names the
+ AbstractFileSystem class.
+
+ The entire URI and conf is passed to the AbstractFileSystem factory method.
+
+ @param uri for the file system to be created.
+ @param conf which is passed to the file system impl.
+
+ @return file system for the given URI.
+
+ @throws UnsupportedFileSystemException if the file system for
+ uri is not supported.]]>
+
+
+
+
+
+
+
+
+
+
+
+ default port;]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ describing modifications
+ @throws IOException if an ACL could not be modified]]>
+
+
+
+
+
+
+
+ describing entries to remove
+ @throws IOException if an ACL could not be modified]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ describing modifications, must include entries
+ for user, group, and others for compatibility with permission bits.
+ @throws IOException if an ACL could not be modified]]>
+
+
+
+
+
+
+ which returns each AclStatus
+ @throws IOException if an ACL could not be read]]>
+
+
+
+
+
+
+
+
+
+ Refer to the HDFS extended attributes user documentation for details.
+
+ @param path Path to modify
+ @param name xattr name.
+ @param value xattr value.
+ @throws IOException]]>
+
+
+
+
+
+
+
+
+
+
+ Refer to the HDFS extended attributes user documentation for details.
+
+ @param path Path to modify
+ @param name xattr name.
+ @param value xattr value.
+ @param flag xattr set flag
+ @throws IOException]]>
+
+
+
+
+
+
+
+
+ Refer to the HDFS extended attributes user documentation for details.
+
+ @param path Path to get extended attribute
+ @param name xattr name.
+ @return byte[] xattr value.
+ @throws IOException]]>
+
+
+
+
+
+
+
+ Refer to the HDFS extended attributes user documentation for details.
+
+ @param path Path to get extended attributes
+ @return Map describing the XAttrs of the file or directory
+ @throws IOException]]>
+
+
+
+
+
+
+
+
+ Refer to the HDFS extended attributes user documentation for details.
+
+ @param path Path to get extended attributes
+ @param names XAttr names.
+ @return Map describing the XAttrs of the file or directory
+ @throws IOException]]>
+
+
+
+
+
+
+
+ Refer to the HDFS extended attributes user documentation for details.
+
+ @param path Path to get extended attributes
+ @return Map describing the XAttrs of the file or directory
+ @throws IOException]]>
+
+
+
+
+
+
+
+
+ Refer to the HDFS extended attributes user documentation for details.
+
+ @param path Path to remove extended attribute
+ @param name xattr name
+ @throws IOException]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ After a successful call, {@code buf.position()} will be advanced by the
+ number of bytes read and {@code buf.limit()} will be unchanged.
+
+ In the case of an exception, the state of the buffer (the contents of the
+ buffer, the {@code buf.position()}, the {@code buf.limit()}, etc.) is
+ undefined, and callers should be prepared to recover from this eventuality.
+
+ Callers should use {@link StreamCapabilities#hasCapability(String)} with
+ {@link StreamCapabilities#PREADBYTEBUFFER} to check if the underlying
+ stream supports this interface, otherwise they might get a
+ {@link UnsupportedOperationException}.
+
+ Implementations should treat 0-length requests as legitimate, and must not
+ signal an error upon their receipt.
+
+ @param position position within file
+ @param buf the ByteBuffer to receive the results of the read operation.
+ @return the number of bytes read, possibly zero, or -1 if reached
+ end-of-stream
+ @throws IOException if there is some error performing the read]]>
+
CREATE - to create a file if it does not exist,
+ else throw FileAlreadyExists.
+
APPEND - to append to a file if it exists,
+ else throw FileNotFoundException.
+
OVERWRITE - to truncate a file if it exists,
+ else throw FileNotFoundException.
+
CREATE|APPEND - to create a file if it does not exist,
+ else append to an existing file.
+
CREATE|OVERWRITE - to create a file if it does not exist,
+ else overwrite an existing file.
+
SYNC_BLOCK - to force closed blocks to the disk device.
+ In addition {@link Syncable#hsync()} should be called after each write,
+ if true synchronous behavior is required.
+
LAZY_PERSIST - Create the block on transient storage (RAM) if
+ available.
+
APPEND_NEWBLOCK - Append data to a new block instead of end of the last
+ partial block.
+
+
+ Following combinations are not valid and will result in
+ {@link HadoopIllegalArgumentException}:
+
+
]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ f does not exist
+ @throws AccessControlException if access denied
+ @throws IOException If an IO Error occurred
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws RpcServerException If an exception occurred in the RPC server
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server
+
+ RuntimeExceptions:
+ @throws InvalidPathException If path f is not valid]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Progress - to report progress on the operation - default null
+
Permission - umask is applied against permisssion: default is
+ FsPermissions:getDefault()
+
+
CreateParent - create missing parent path; default is to not
+ to create parents
+
The defaults for the following are SS defaults of the file
+ server implementing the target path. Not all parameters make sense
+ for all kinds of file system - eg. localFS ignores Blocksize,
+ replication, checksum
+
+
BufferSize - buffersize used in FSDataOutputStream
+
Blocksize - block size for file blocks
+
ReplicationFactor - replication for blocks
+
ChecksumParam - Checksum parameters. server default is used
+ if not specified.
+
+
+
+ @return {@link FSDataOutputStream} for created file
+
+ @throws AccessControlException If access is denied
+ @throws FileAlreadyExistsException If file f already exists
+ @throws FileNotFoundException If parent of f does not exist
+ and createParent is false
+ @throws ParentNotDirectoryException If parent of f is not a
+ directory.
+ @throws UnsupportedFileSystemException If file system for f is
+ not supported
+ @throws IOException If an I/O error occurred
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws RpcServerException If an exception occurred in the RPC server
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server
+
+ RuntimeExceptions:
+ @throws InvalidPathException If path f is not valid]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ dir already
+ exists
+ @throws FileNotFoundException If parent of dir does not exist
+ and createParent is false
+ @throws ParentNotDirectoryException If parent of dir is not a
+ directory
+ @throws UnsupportedFileSystemException If file system for dir
+ is not supported
+ @throws IOException If an I/O error occurred
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server
+
+ RuntimeExceptions:
+ @throws InvalidPathException If path dir is not valid]]>
+
+
+
+
+
+
+
+
+
+
+ f does not exist
+ @throws UnsupportedFileSystemException If file system for f is
+ not supported
+ @throws IOException If an I/O error occurred
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws RpcServerException If an exception occurred in the RPC server
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server
+
+ RuntimeExceptions:
+ @throws InvalidPathException If path f is invalid]]>
+
+
+
+
+
+
+
+
+
+ f does not exist
+ @throws UnsupportedFileSystemException If file system for f
+ is not supported
+ @throws IOException If an I/O error occurred
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws RpcServerException If an exception occurred in the RPC server
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server]]>
+
+
+
+
+
+
+
+
+
+
+ f does not exist
+ @throws UnsupportedFileSystemException If file system for f is
+ not supported
+ @throws IOException If an I/O error occurred
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws RpcServerException If an exception occurred in the RPC server
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server]]>
+
+
+
+
+
+
+
+
+
+
+
+
Fails if path is a directory.
+
Fails if path does not exist.
+
Fails if path is not closed.
+
Fails if new size is greater than current size.
+
+ @param f The path to the file to be truncated
+ @param newLength The size the file is to be truncated to
+
+ @return true if the file has been truncated to the desired
+ newLength and is immediately available to be reused for
+ write operations such as append, or
+ false if a background process of adjusting the length of
+ the last block has been started, and clients should wait for it to
+ complete before proceeding with further file updates.
+
+ @throws AccessControlException If access is denied
+ @throws FileNotFoundException If file f does not exist
+ @throws UnsupportedFileSystemException If file system for f is
+ not supported
+ @throws IOException If an I/O error occurred
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws RpcServerException If an exception occurred in the RPC server
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server]]>
+
+
+
+
+
+
+
+
+
+ f does not exist
+ @throws IOException If an I/O error occurred
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws RpcServerException If an exception occurred in the RPC server
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Fails if src is a file and dst is a directory.
+
Fails if src is a directory and dst is a file.
+
Fails if the parent of dst does not exist or is a file.
+
+
+ If OVERWRITE option is not passed as an argument, rename fails if the dst
+ already exists.
+
+ If OVERWRITE option is passed as an argument, rename overwrites the dst if
+ it is a file or an empty directory. Rename fails if dst is a non-empty
+ directory.
+
+ Note that atomicity of rename is dependent on the file system
+ implementation. Please refer to the file system documentation for details
+
+
+ @param src path to be renamed
+ @param dst new path after rename
+
+ @throws AccessControlException If access is denied
+ @throws FileAlreadyExistsException If dst already exists and
+ options has {@link Options.Rename#OVERWRITE}
+ option false.
+ @throws FileNotFoundException If src does not exist
+ @throws ParentNotDirectoryException If parent of dst is not a
+ directory
+ @throws UnsupportedFileSystemException If file system for src
+ and dst is not supported
+ @throws IOException If an I/O error occurred
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws RpcServerException If an exception occurred in the RPC server
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server]]>
+
+
+
+
+
+
+
+
+
+
+ f does not exist
+ @throws UnsupportedFileSystemException If file system for f
+ is not supported
+ @throws IOException If an I/O error occurred
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws RpcServerException If an exception occurred in the RPC server
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server]]>
+
+
+
+
+
+
+
+
+
+
+
+ f does not exist
+ @throws UnsupportedFileSystemException If file system for f is
+ not supported
+ @throws IOException If an I/O error occurred
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws RpcServerException If an exception occurred in the RPC server
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server
+
+ RuntimeExceptions:
+ @throws HadoopIllegalArgumentException If username or
+ groupname is invalid.]]>
+
+
+
+
+
+
+
+
+
+
+
+ f does not exist
+ @throws UnsupportedFileSystemException If file system for f is
+ not supported
+ @throws IOException If an I/O error occurred
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws RpcServerException If an exception occurred in the RPC server
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server]]>
+
+
+
+
+
+
+
+
+ f does not exist
+ @throws IOException If an I/O error occurred
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws RpcServerException If an exception occurred in the RPC server
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server]]>
+
+
+
+
+
+
+
+
+
+
+ f does not exist
+ @throws UnsupportedFileSystemException If file system for f is
+ not supported
+ @throws IOException If an I/O error occurred
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws RpcServerException If an exception occurred in the RPC server
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server]]>
+
+
+
+
+
+
+
+
+
+ f does not exist
+ @throws UnsupportedFileSystemException If file system for f is
+ not supported
+ @throws IOException If an I/O error occurred
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws RpcServerException If an exception occurred in the RPC server
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server]]>
+
+
+
+
+
+
+
+
+
+ f does not exist
+ @throws UnsupportedFileSystemException If file system for f is
+ not supported
+ @throws IOException If an I/O error occurred]]>
+
+
+
+
+
+
+
+
+
+ f does not exist
+ @throws UnsupportedFileSystemException If file system for f is
+ not supported
+ @throws IOException If the given path does not refer to a symlink
+ or an I/O error occurred]]>
+
+
+
+
+
+
+
+
+
+ f does not exist
+ @throws UnsupportedFileSystemException If file system for f is
+ not supported
+ @throws IOException If an I/O error occurred
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws RpcServerException If an exception occurred in the RPC server
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Given a path referring to a symlink of form:
+
+ <---X--->
+ fs://host/A/B/link
+ <-----Y----->
+
+ In this path X is the scheme and authority that identify the file system,
+ and Y is the path leading up to the final path component "link". If Y is
+ a symlink itself then let Y' be the target of Y and X' be the scheme and
+ authority of Y'. Symlink targets may:
+
+ 1. Fully qualified URIs
+
+ fs://hostX/A/B/file Resolved according to the target file system.
+
+ 2. Partially qualified URIs (eg scheme but no host)
+
+ fs:///A/B/file Resolved according to the target file system. Eg resolving
+ a symlink to hdfs:///A results in an exception because
+ HDFS URIs must be fully qualified, while a symlink to
+ file:///A will not since Hadoop's local file systems
+ require partially qualified URIs.
+
+ 3. Relative paths
+
+ path Resolves to [Y'][path]. Eg if Y resolves to hdfs://host/A and path
+ is "../B/file" then [Y'][path] is hdfs://host/B/file
+
+ 4. Absolute paths
+
+ path Resolves to [X'][path]. Eg if Y resolves hdfs://host/A/B and path
+ is "/file" then [X][path] is hdfs://host/file
+
+
+ @param target the target of the symbolic link
+ @param link the path to be created that points to target
+ @param createParent if true then missing parent dirs are created if
+ false then parent must exist
+
+
+ @throws AccessControlException If access is denied
+ @throws FileAlreadyExistsException If file linkcode> already exists
+ @throws FileNotFoundException If target does not exist
+ @throws ParentNotDirectoryException If parent of link is not a
+ directory.
+ @throws UnsupportedFileSystemException If file system for
+ target or link is not supported
+ @throws IOException If an I/O error occurred]]>
+
+
+
+
+
+
+
+
+
+ f does not exist
+ @throws UnsupportedFileSystemException If file system for f is
+ not supported
+ @throws IOException If an I/O error occurred
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws RpcServerException If an exception occurred in the RPC server
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ f does not exist
+ @throws UnsupportedFileSystemException If file system for f is
+ not supported
+ @throws IOException If an I/O error occurred
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws RpcServerException If an exception occurred in the RPC server
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server]]>
+
+
+
+
+
+
+
+ f is
+ not supported
+ @throws IOException If an I/O error occurred
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws RpcServerException If an exception occurred in the RPC server
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ describing modifications
+ @throws IOException if an ACL could not be modified]]>
+
+
+
+
+
+
+
+ describing entries to remove
+ @throws IOException if an ACL could not be modified]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ describing modifications, must include entries
+ for user, group, and others for compatibility with permission bits.
+ @throws IOException if an ACL could not be modified]]>
+
+
+
+
+
+
+ which returns each AclStatus
+ @throws IOException if an ACL could not be read]]>
+
+
+
+
+
+
+
+
+
+ Refer to the HDFS extended attributes user documentation for details.
+
+ @param path Path to modify
+ @param name xattr name.
+ @param value xattr value.
+ @throws IOException]]>
+
+
+
+
+
+
+
+
+
+
+ Refer to the HDFS extended attributes user documentation for details.
+
+ @param path Path to modify
+ @param name xattr name.
+ @param value xattr value.
+ @param flag xattr set flag
+ @throws IOException]]>
+
+
+
+
+
+
+
+
+ Refer to the HDFS extended attributes user documentation for details.
+
+ @param path Path to get extended attribute
+ @param name xattr name.
+ @return byte[] xattr value.
+ @throws IOException]]>
+
+
+
+
+
+
+
+ Refer to the HDFS extended attributes user documentation for details.
+
+ @param path Path to get extended attributes
+ @return Map describing the XAttrs of the file or directory
+ @throws IOException]]>
+
+
+
+
+
+
+
+
+ Refer to the HDFS extended attributes user documentation for details.
+
+ @param path Path to get extended attributes
+ @param names XAttr names.
+ @return Map describing the XAttrs of the file or directory
+ @throws IOException]]>
+
+
+
+
+
+
+
+
+ Refer to the HDFS extended attributes user documentation for details.
+
+ @param path Path to remove extended attribute
+ @param name xattr name
+ @throws IOException]]>
+
+
+
+
+
+
+
+ Refer to the HDFS extended attributes user documentation for details.
+
+ @param path Path to get extended attributes
+ @return List of the XAttr names of the file or directory
+ @throws IOException]]>
+
+
+
+
+
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws RpcServerException If an exception occurred in the RPC server
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server]]>
+
+
+
+
+
+
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws RpcServerException If an exception occurred in the RPC server
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server]]>
+
+
+
+
+
+
+
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws RpcServerException If an exception occurred in the RPC server
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server]]>
+
+
+
+
+
+
+
+ Exceptions applicable to file systems accessed over RPC:
+ @throws RpcClientException If an exception occurred in the RPC client
+ @throws RpcServerException If an exception occurred in the RPC server
+ @throws UnexpectedServerException If server implementation throws
+ undeclared exception to RPC server]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ *** Path Names ***
+
+
+ The Hadoop file system supports a URI name space and URI names.
+ It offers a forest of file systems that can be referenced using fully
+ qualified URIs.
+ Two common Hadoop file systems implementations are
+
+
the local file system: file:///path
+
the hdfs file system hdfs://nnAddress:nnPort/path
+
+
+ While URI names are very flexible, it requires knowing the name or address
+ of the server. For convenience one often wants to access the default system
+ in one's environment without knowing its name/address. This has an
+ additional benefit that it allows one to change one's default fs
+ (e.g. admin moves application from cluster1 to cluster2).
+
+
+ To facilitate this, Hadoop supports a notion of a default file system.
+ The user can set his default file system, although this is
+ typically set up for you in your environment via your default config.
+ A default file system implies a default scheme and authority; slash-relative
+ names (such as /for/bar) are resolved relative to that default FS.
+ Similarly a user can also have working-directory-relative names (i.e. names
+ not starting with a slash). While the working directory is generally in the
+ same default FS, the wd can be in a different FS.
+
+ Hence Hadoop path names can be one of:
+
+
fully qualified URI: scheme://authority/path
+
slash relative names: /path relative to the default file system
+
wd-relative names: path relative to the working dir
+
+ Relative paths with scheme (scheme:foo/bar) are illegal.
+
+
+ ****The Role of the FileContext and configuration defaults****
+
+ The FileContext provides file namespace context for resolving file names;
+ it also contains the umask for permissions, In that sense it is like the
+ per-process file-related state in Unix system.
+ These two properties
+
+
default file system i.e your slash)
+
umask
+
+ in general, are obtained from the default configuration file
+ in your environment, (@see {@link Configuration}).
+
+ No other configuration parameters are obtained from the default config as
+ far as the file context layer is concerned. All file system instances
+ (i.e. deployments of file systems) have default properties; we call these
+ server side (SS) defaults. Operation like create allow one to select many
+ properties: either pass them in as explicit parameters or use
+ the SS properties.
+
+ The file system related SS defaults are
+
+
the home directory (default is "/user/userName")
+
the initial wd (only for local fs)
+
replication factor
+
block size
+
buffer size
+
encryptDataTransfer
+
checksum option. (checksumType and bytesPerChecksum)
+
+
+
+ *** Usage Model for the FileContext class ***
+
+ Example 1: use the default config read from the $HADOOP_CONFIG/core.xml.
+ Unspecified values come from core-defaults.xml in the release jar.
+
+
myFContext = FileContext.getFileContext(); // uses the default config
+ // which has your default FS
+
myFContext.create(path, ...);
+
myFContext.setWorkingDir(path)
+
myFContext.open (path, ...);
+
+ Example 2: Get a FileContext with a specific URI as the default FS
+
+
myFContext = FileContext.getFileContext(URI)
+
myFContext.create(path, ...);
+ ...
+
+ Example 3: FileContext with local file system as the default
+
+ If the configuration has the property
+ {@code "fs.$SCHEME.impl.disable.cache"} set to true,
+ a new instance will be created, initialized with the supplied URI and
+ configuration, then returned without being cached.
+
+
+ If the there is a cached FS instance matching the same URI, it will
+ be returned.
+
+
+ Otherwise: a new FS instance will be created, initialized with the
+ configuration and URI, cached and returned to the caller.
+
+
+ @throws IOException if the FileSystem cannot be instantiated.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if f == null :
+ result = null
+ elif f.getLen() <= start:
+ result = []
+ else result = [ locations(FS, b) for b in blocks(FS, p, s, s+l)]
+
+ This call is most helpful with and distributed filesystem
+ where the hostnames of machines that contain blocks of the given file
+ can be determined.
+
+ The default implementation returns an array containing one element:
+
Fails if the parent of dst does not exist or is a file.
+
+
+ If OVERWRITE option is not passed as an argument, rename fails
+ if the dst already exists.
+
+ If OVERWRITE option is passed as an argument, rename overwrites
+ the dst if it is a file or an empty directory. Rename fails if dst is
+ a non-empty directory.
+
+ Note that atomicity of rename is dependent on the file system
+ implementation. Please refer to the file system documentation for
+ details. This default implementation is non atomic.
+
+ This method is deprecated since it is a temporary method added to
+ support the transition from FileSystem to FileContext for user
+ applications.
+
+ @param src path to be renamed
+ @param dst new path after rename
+ @throws FileNotFoundException src path does not exist, or the parent
+ path of dst does not exist.
+ @throws FileAlreadyExistsException dest path exists and is a file
+ @throws ParentNotDirectoryException if the parent path of dest is not
+ a directory
+ @throws IOException on failure]]>
+
+
+
+
+
+
+
+
+
Fails if path is a directory.
+
Fails if path does not exist.
+
Fails if path is not closed.
+
Fails if new size is greater than current size.
+
+ @param f The path to the file to be truncated
+ @param newLength The size the file is to be truncated to
+
+ @return true if the file has been truncated to the desired
+ newLength and is immediately available to be reused for
+ write operations such as append, or
+ false if a background process of adjusting the length of
+ the last block has been started, and clients should wait for it to
+ complete before proceeding with further file updates.
+ @throws IOException IO failure
+ @throws UnsupportedOperationException if the operation is unsupported
+ (default).]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Clean shutdown of the JVM cannot be guaranteed.
+
The time to shut down a FileSystem will depends on the number of
+ files to delete. For filesystems where the cost of checking
+ for the existence of a file/directory and the actual delete operation
+ (for example: object stores) is high, the time to shutdown the JVM can be
+ significantly extended by over-use of this feature.
+
Connectivity problems with a remote filesystem may delay shutdown
+ further, and may cause the files to not be deleted.
+
+ @param f the path to delete.
+ @return true if deleteOnExit is successful, otherwise false.
+ @throws IOException IO failure]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Does not guarantee to return the List of files/directories status in a
+ sorted order.
+ @param f given path
+ @return the statuses of the files/directories in the given patch
+ @throws FileNotFoundException when the path does not exist
+ @throws IOException see specific implementation]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Does not guarantee to return the List of files/directories status in a
+ sorted order.
+
+ @param f
+ a path name
+ @param filter
+ the user-supplied path filter
+ @return an array of FileStatus objects for the files under the given path
+ after applying the filter
+ @throws FileNotFoundException when the path does not exist
+ @throws IOException see specific implementation]]>
+
+
+
+
+
+
+
+
+ Does not guarantee to return the List of files/directories status in a
+ sorted order.
+
+ @param files
+ a list of paths
+ @return a list of statuses for the files under the given paths after
+ applying the filter default Path filter
+ @throws FileNotFoundException when the path does not exist
+ @throws IOException see specific implementation]]>
+
+
+
+
+
+
+
+
+
+ Does not guarantee to return the List of files/directories status in a
+ sorted order.
+
+ @param files
+ a list of paths
+ @param filter
+ the user-supplied path filter
+ @return a list of statuses for the files under the given paths after
+ applying the filter
+ @throws FileNotFoundException when the path does not exist
+ @throws IOException see specific implementation]]>
+
+
+
+
+
+
+ Return all the files that match filePattern and are not checksum
+ files. Results are sorted by their names.
+
+
+ A filename pattern is composed of regular characters and
+ special pattern matching characters, which are:
+
+
+
+
+
+
?
+
Matches any single character.
+
+
+
*
+
Matches zero or more characters.
+
+
+
[abc]
+
Matches a single character from character set
+ {a,b,c}.
+
+
+
[a-b]
+
Matches a single character from the character range
+ {a...b}. Note that character a must be
+ lexicographically less than or equal to character b.
+
+
+
[^a]
+
Matches a single character that is not from character set or range
+ {a}. Note that the ^ character must occur
+ immediately to the right of the opening bracket.
+
+
+
\c
+
Removes (escapes) any special meaning of character c.
+
+
+
{ab,cd}
+
Matches a string from the string set {ab, cd}
+
+
+
{ab,c{de,fh}}
+
Matches a string from the string set {ab, cde, cfh}
+
+
+
+
+
+ @param pathPattern a regular expression specifying a pth pattern
+
+ @return an array of paths that match the path pattern
+ @throws IOException IO failure]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ f does not exist
+ @throws IOException If an I/O error occurred]]>
+
+
+
+
+
+
+
+
+ f does not exist
+ @throws IOException if any I/O error occurred]]>
+
+
+
+
+
+
+
+ p does not exist
+ @throws IOException if any I/O error occurred]]>
+
+
+
+
+
+
+
+
+
+ If the path is a directory,
+ if recursive is false, returns files in the directory;
+ if recursive is true, return files in the subtree rooted at the path.
+ If the path is a file, return the file's status and block locations.
+
+ @param f is the path
+ @param recursive if the subdirectories need to be traversed recursively
+
+ @return an iterator that traverses statuses of the files
+
+ @throws FileNotFoundException when the path does not exist;
+ @throws IOException see specific implementation]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ undefined.
+ @throws IOException IO failure]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ describing modifications
+ @throws IOException if an ACL could not be modified
+ @throws UnsupportedOperationException if the operation is unsupported
+ (default outcome).]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Refer to the HDFS extended attributes user documentation for details.
+
+ @param path Path to modify
+ @param name xattr name.
+ @param value xattr value.
+ @throws IOException IO failure
+ @throws UnsupportedOperationException if the operation is unsupported
+ (default outcome).]]>
+
+
+
+
+
+
+
+
+
+
+ Refer to the HDFS extended attributes user documentation for details.
+
+ @param path Path to modify
+ @param name xattr name.
+ @param value xattr value.
+ @param flag xattr set flag
+ @throws IOException IO failure
+ @throws UnsupportedOperationException if the operation is unsupported
+ (default outcome).]]>
+
+
+
+
+
+
+
+
+ Refer to the HDFS extended attributes user documentation for details.
+
+ @param path Path to get extended attribute
+ @param name xattr name.
+ @return byte[] xattr value.
+ @throws IOException IO failure
+ @throws UnsupportedOperationException if the operation is unsupported
+ (default outcome).]]>
+
+
+
+
+
+
+
+ Refer to the HDFS extended attributes user documentation for details.
+
+ @param path Path to get extended attributes
+ @return Map describing the XAttrs of the file or directory
+ @throws IOException IO failure
+ @throws UnsupportedOperationException if the operation is unsupported
+ (default outcome).]]>
+
+
+
+
+
+
+
+
+ Refer to the HDFS extended attributes user documentation for details.
+
+ @param path Path to get extended attributes
+ @param names XAttr names.
+ @return Map describing the XAttrs of the file or directory
+ @throws IOException IO failure
+ @throws UnsupportedOperationException if the operation is unsupported
+ (default outcome).]]>
+
+
+
+
+
+
+
+ Refer to the HDFS extended attributes user documentation for details.
+
+ @param path Path to get extended attributes
+ @return List of the XAttr names of the file or directory
+ @throws IOException IO failure
+ @throws UnsupportedOperationException if the operation is unsupported
+ (default outcome).]]>
+
+
+
+
+
+
+
+
+ Refer to the HDFS extended attributes user documentation for details.
+
+ @param path Path to remove extended attribute
+ @param name xattr name
+ @throws IOException IO failure
+ @throws UnsupportedOperationException if the operation is unsupported
+ (default outcome).]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This is a default method which is intended to be overridden by
+ subclasses. The default implementation returns an empty storage statistics
+ object.
+
+ @return The StorageStatistics for this FileSystem instance.
+ Will never be null.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ All user code that may potentially use the Hadoop Distributed
+ File System should be written to use a FileSystem object or its
+ successor, {@link FileContext}.
+
+
+ The local implementation is {@link LocalFileSystem} and distributed
+ implementation is DistributedFileSystem. There are other implementations
+ for object stores and (outside the Apache Hadoop codebase),
+ third party filesystems.
+
+ Notes
+
+
The behaviour of the filesystem is
+
+ specified in the Hadoop documentation.
+ However, the normative specification of the behavior of this class is
+ actually HDFS: if HDFS does not behave the way these Javadocs or
+ the specification in the Hadoop documentations define, assume that
+ the documentation is incorrect.
+
+
The term {@code FileSystem} refers to an instance of this class.
+
The acronym "FS" is used as an abbreviation of FileSystem.
+
The term {@code filesystem} refers to the distributed/local filesystem
+ itself, rather than the class used to interact with it.
+
The term "file" refers to a file in the remote filesystem,
+ rather than instances of {@code java.io.File}.
/tmp -> hdfs://nnTmp/privateTmpForUserXXX
+
+
+ ViewFs is specified with the following URI: viewfs:///
+
+ To use viewfs one would typically set the default file system in the
+ config (i.e. fs.defaultFS < = viewfs:///) along with the
+ mount table config variables as described below.
+
+
+ ** Config variables to specify the mount table entries **
+
+
+ The file system is initialized from the standard Hadoop config through
+ config variables.
+ See {@link FsConstants} for URI and Scheme constants;
+ See {@link Constants} for config var constants;
+ see {@link ConfigUtil} for convenient lib.
+
+
+ All the mount table config entries for view fs are prefixed by
+ fs.viewfs.mounttable.
+ For example the above example can be specified with the following
+ config variables:
+
+
+ The default mount table (when no authority is specified) is
+ from config variables prefixed by fs.viewFs.mounttable.default
+ The authority component of a URI can be used to specify a different mount
+ table. For example,
+
+
viewfs://sanjayMountable/
+
+ is initialized from fs.viewFs.mounttable.sanjayMountable.* config variables.
+
+
+ **** Merge Mounts **** (NOTE: merge mounts are not implemented yet.)
+
+
+ One can also use "MergeMounts" to merge several directories (this is
+ sometimes called union-mounts or junction-mounts in the literature.
+ For example of the home directories are stored on say two file systems
+ (because they do not fit on one) then one could specify a mount
+ entry such as following merges two dirs:
+
+ In this cases the root of the mount table is merged with the root of
+ hdfs://nn99/ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Since these methods are often vendor- or device-specific, operators
+ may implement this interface in order to achieve fencing.
+
+ Fencing is configured by the operator as an ordered list of methods to
+ attempt. Each method will be tried in turn, and the next in the list
+ will only be attempted if the previous one fails. See {@link NodeFencer}
+ for more information.
+
+ If an implementation also implements {@link Configurable} then its
+ setConf method will be called upon instantiation.]]>
+
StaticUserWebFilter - An authorization plugin that makes all
+users a static configured user.
+
]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ public class IntArrayWritable extends ArrayWritable {
+ public IntArrayWritable() {
+ super(IntWritable.class);
+ }
+ }
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ o is a ByteWritable with the same value.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ the class of the item
+ @param conf the configuration to store
+ @param item the object to be stored
+ @param keyName the name of the key to use
+ @throws IOException : forwards Exceptions from the underlying
+ {@link Serialization} classes.]]>
+
+
+
+
+
+
+
+
+ the class of the item
+ @param conf the configuration to use
+ @param keyName the name of the key to use
+ @param itemClass the class of the item
+ @return restored object
+ @throws IOException : forwards Exceptions from the underlying
+ {@link Serialization} classes.]]>
+
+
+
+
+
+
+
+
+ the class of the item
+ @param conf the configuration to use
+ @param items the objects to be stored
+ @param keyName the name of the key to use
+ @throws IndexOutOfBoundsException if the items array is empty
+ @throws IOException : forwards Exceptions from the underlying
+ {@link Serialization} classes.]]>
+
+
+
+
+
+
+
+
+ the class of the item
+ @param conf the configuration to use
+ @param keyName the name of the key to use
+ @param itemClass the class of the item
+ @return restored object
+ @throws IOException : forwards Exceptions from the underlying
+ {@link Serialization} classes.]]>
+
+
+
+
+ DefaultStringifier offers convenience methods to store/load objects to/from
+ the configuration.
+
+ @param the class of the objects to stringify]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ o is a DoubleWritable with the same value.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ value argument is null or
+ its size is zero, the elementType argument must not be null. If
+ the argument value's size is bigger than zero, the argument
+ elementType is not be used.
+
+ @param value
+ @param elementType]]>
+
+
+
+
+ value should not be null
+ or empty.
+
+ @param value]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ value and elementType. If the value argument
+ is null or its size is zero, the elementType argument must not be
+ null. If the argument value's size is bigger than zero, the
+ argument elementType is not be used.
+
+ @param value
+ @param elementType]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ o is an EnumSetWritable with the same value,
+ or both are null.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ o is a FloatWritable with the same value.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ When two sequence files, which have same Key type but different Value
+ types, are mapped out to reduce, multiple Value types is not allowed.
+ In this case, this class can help you wrap instances with different types.
+
+
+
+ Compared with ObjectWritable, this class is much more effective,
+ because ObjectWritable will append the class declaration as a String
+ into the output file in every Key-Value pair.
+
+
+
+ Generic Writable implements {@link Configurable} interface, so that it will be
+ configured by the framework. The configuration is passed to the wrapped objects
+ implementing {@link Configurable} interface before deserialization.
+
+
+ how to use it:
+ 1. Write your own class, such as GenericObject, which extends GenericWritable.
+ 2. Implements the abstract method getTypes(), defines
+ the classes which will be wrapped in GenericObject in application.
+ Attention: this classes defined in getTypes() method, must
+ implement Writable interface.
+
+
+ @since Nov 8, 2006]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ o is a IntWritable with the same value.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ closes the input and output streams
+ at the end.
+
+ @param in InputStrem to read from
+ @param out OutputStream to write to
+ @param conf the Configuration object]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ignore any {@link Throwable} or
+ null pointers. Must only be used for cleanup in exception handlers.
+
+ @param log the log to record problems to at debug level. Can be null.
+ @param closeables the objects to close
+ @deprecated use {@link #cleanupWithLogger(Logger, java.io.Closeable...)}
+ instead]]>
+
+
+
+
+
+
+ ignore any {@link Throwable} or
+ null pointers. Must only be used for cleanup in exception handlers.
+
+ @param logger the log to record problems to at debug level. Can be null.
+ @param closeables the objects to close]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This is better than File#listDir because it does not ignore IOExceptions.
+
+ @param dir The directory to list.
+ @param filter If non-null, the filter to use when listing
+ this directory.
+ @return The list of files in the directory.
+
+ @throws IOException On I/O error]]>
+
+
+
+
+
+
+
+ Borrowed from Uwe Schindler in LUCENE-5588
+ @param fileToSync the file to fsync]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ o is a LongWritable with the same value.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A map is a directory containing two files, the data file,
+ containing all keys and values in the map, and a smaller index
+ file, containing a fraction of the keys. The fraction is determined by
+ {@link Writer#getIndexInterval()}.
+
+
The index file is read entirely into memory. Thus key implementations
+ should try to keep themselves small.
+
+
Map files are created by adding entries in-order. To maintain a large
+ database, perform updates by copying the previous version of a database and
+ merging in a sorted change list, to create a new version of the database in
+ a new file. Sorting large change lists can be done with {@link
+ SequenceFile.Sorter}.]]>
+
SequenceFile provides {@link SequenceFile.Writer},
+ {@link SequenceFile.Reader} and {@link Sorter} classes for writing,
+ reading and sorting respectively.
+
+ There are three SequenceFileWriters based on the
+ {@link CompressionType} used to compress key/value pairs:
+
+
+ Writer : Uncompressed records.
+
+
+ RecordCompressWriter : Record-compressed files, only compress
+ values.
+
+
+ BlockCompressWriter : Block-compressed files, both keys &
+ values are collected in 'blocks'
+ separately and compressed. The size of
+ the 'block' is configurable.
+
+
+
The actual compression algorithm used to compress key and/or values can be
+ specified by using the appropriate {@link CompressionCodec}.
+
+
The recommended way is to use the static createWriter methods
+ provided by the SequenceFile to chose the preferred format.
+
+
The {@link SequenceFile.Reader} acts as the bridge and can read any of the
+ above SequenceFile formats.
+
+
SequenceFile Formats
+
+
Essentially there are 3 different formats for SequenceFiles
+ depending on the CompressionType specified. All of them share a
+ common header described below.
+
+
SequenceFile Header
+
+
+ version - 3 bytes of magic header SEQ, followed by 1 byte of actual
+ version number (e.g. SEQ4 or SEQ6)
+
+
+ keyClassName -key class
+
+
+ valueClassName - value class
+
+
+ compression - A boolean which specifies if compression is turned on for
+ keys/values in this file.
+
+
+ blockCompression - A boolean which specifies if block-compression is
+ turned on for keys/values in this file.
+
+
+ compression codec - CompressionCodec class which is used for
+ compression of keys and/or values (if compression is
+ enabled).
+
+
+ metadata - {@link Metadata} for this file.
+
+
+ sync - A sync marker to denote end of the header.
+
The compressed blocks of key lengths and value lengths consist of the
+ actual lengths of individual keys/values encoded in ZeroCompressedInteger
+ format.
+
+ @see CompressionCodec]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ o is a ShortWritable with the same value.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ the class of the objects to stringify]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ position. Note that this
+ method avoids using the converter or doing String instantiation
+ @return the Unicode scalar value at position or -1
+ if the position is invalid or points to a
+ trailing byte]]>
+
+
+
+
+
+
+
+
+
+ what in the backing
+ buffer, starting as position start. The starting
+ position is measured in bytes and the return value is in
+ terms of byte position in the buffer. The backing buffer is
+ not converted to a string for this operation.
+ @return byte position of the first occurence of the search
+ string in the UTF-8 buffer or -1 if not found]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Note: For performance reasons, this call does not clear the
+ underlying byte array that is retrievable via {@link #getBytes()}.
+ In order to free the byte-array memory, call {@link #set(byte[])}
+ with an empty byte array (For example, new byte[0]).]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ o is a Text with the same contents.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ replace is true, then
+ malformed input is replaced with the
+ substitution character, which is U+FFFD. Otherwise the
+ method throws a MalformedInputException.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ replace is true, then
+ malformed input is replaced with the
+ substitution character, which is U+FFFD. Otherwise the
+ method throws a MalformedInputException.
+ @return ByteBuffer: bytes stores at ByteBuffer.array()
+ and length is ByteBuffer.limit()]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ In
+ addition, it provides methods for string traversal without converting the
+ byte array to a string.
Also includes utilities for
+ serializing/deserialing a string, coding/decoding a string, checking if a
+ byte array contains valid UTF8 code, calculating the length of an encoded
+ string.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This is useful when a class may evolve, so that instances written by the
+ old version of the class may still be processed by the new version. To
+ handle this situation, {@link #readFields(DataInput)}
+ implementations should catch {@link VersionMismatchException}.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ o is a VIntWritable with the same value.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ o is a VLongWritable with the same value.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ out.
+
+ @param out DataOuput to serialize this object into.
+ @throws IOException]]>
+
+
+
+
+
+
+ in.
+
+
For efficiency, implementations should attempt to re-use storage in the
+ existing object where possible.
+
+ @param in DataInput to deseriablize this object from.
+ @throws IOException]]>
+
+
+
+ Any key or value type in the Hadoop Map-Reduce
+ framework implements this interface.
+
+
Implementations typically implement a static read(DataInput)
+ method which constructs a new instance, calls {@link #readFields(DataInput)}
+ and returns the instance.
+
+
Example:
+
+ public class MyWritable implements Writable {
+ // Some data
+ private int counter;
+ private long timestamp;
+
+ public void write(DataOutput out) throws IOException {
+ out.writeInt(counter);
+ out.writeLong(timestamp);
+ }
+
+ public void readFields(DataInput in) throws IOException {
+ counter = in.readInt();
+ timestamp = in.readLong();
+ }
+
+ public static MyWritable read(DataInput in) throws IOException {
+ MyWritable w = new MyWritable();
+ w.readFields(in);
+ return w;
+ }
+ }
+
]]>
+
+
+
+
+
+
+
+
+ WritableComparables can be compared to each other, typically
+ via Comparators. Any type which is to be used as a
+ key in the Hadoop Map-Reduce framework should implement this
+ interface.
+
+
Note that hashCode() is frequently used in Hadoop to partition
+ keys. It's important that your implementation of hashCode() returns the same
+ result across different instances of the JVM. Note also that the default
+ hashCode() implementation in Object does not
+ satisfy this property.
+
+
Example:
+
+ public class MyWritableComparable implements WritableComparable {
+ // Some data
+ private int counter;
+ private long timestamp;
+
+ public void write(DataOutput out) throws IOException {
+ out.writeInt(counter);
+ out.writeLong(timestamp);
+ }
+
+ public void readFields(DataInput in) throws IOException {
+ counter = in.readInt();
+ timestamp = in.readLong();
+ }
+
+ public int compareTo(MyWritableComparable o) {
+ int thisValue = this.value;
+ int thatValue = o.value;
+ return (thisValue < thatValue ? -1 : (thisValue==thatValue ? 0 : 1));
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + counter;
+ result = prime * result + (int) (timestamp ^ (timestamp >>> 32));
+ return result
+ }
+ }
+
One may optimize compare-intensive operations by overriding
+ {@link #compare(byte[],int,int,byte[],int,int)}. Static utility methods are
+ provided to assist in optimized implementations of this method.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Enum type
+ @param in DataInput to read from
+ @param enumType Class type of Enum
+ @return Enum represented by String read from DataInput
+ @throws IOException]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ len number of bytes in input streamin
+ @param in input stream
+ @param len number of bytes to skip
+ @throws IOException when skipped less number of bytes]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CompressionCodec for which to get the
+ Compressor
+ @param conf the Configuration object which contains confs for creating or reinit the compressor
+ @return Compressor for the given
+ CompressionCodec from the pool or a new one]]>
+
+
+
+
+
+
+
+
+ CompressionCodec for which to get the
+ Decompressor
+ @return Decompressor for the given
+ CompressionCodec the pool or a new one]]>
+
+
+
+
+
+ Compressor to be returned to the pool]]>
+
+
+
+
+
+ Decompressor to be returned to the
+ pool]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Codec aliases are case insensitive.
+
+ The code alias is the short class name (without the package name).
+ If the short class name ends with 'Codec', then there are two aliases for
+ the codec, the complete short class name and the short class name without
+ the 'Codec' ending. For example for the 'GzipCodec' codec class name the
+ alias are 'gzip' and 'gzipcodec'.
+
+ @param codecName the canonical class name of the codec
+ @return the codec object]]>
+
+
+
+
+
+
+ Codec aliases are case insensitive.
+
+ The code alias is the short class name (without the package name).
+ If the short class name ends with 'Codec', then there are two aliases for
+ the codec, the complete short class name and the short class name without
+ the 'Codec' ending. For example for the 'GzipCodec' codec class name the
+ alias are 'gzip' and 'gzipcodec'.
+
+ @param codecName the canonical class name of the codec
+ @return the codec class]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Implementations are assumed to be buffered. This permits clients to
+ reposition the underlying input stream then call {@link #resetState()},
+ without having to also synchronize client buffers.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true indicating that more input data is required.
+
+ @param b Input data
+ @param off Start offset
+ @param len Length]]>
+
+
+
+
+ true if the input data buffer is empty and
+ #setInput() should be called in order to provide more input.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true if the end of the compressed
+ data output stream has been reached.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true indicating that more input data is required.
+ (Both native and non-native versions of various Decompressors require
+ that the data passed in via b[] remain unmodified until
+ the caller is explicitly notified--via {@link #needsInput()}--that the
+ buffer may be safely modified. With this requirement, an extra
+ buffer-copy can be avoided.)
+
+ @param b Input data
+ @param off Start offset
+ @param len Length]]>
+
+
+
+
+ true if the input data buffer is empty and
+ {@link #setInput(byte[], int, int)} should be called to
+ provide more input.
+
+ @return true if the input data buffer is empty and
+ {@link #setInput(byte[], int, int)} should be called in
+ order to provide more input.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+ true if a preset dictionary is needed for decompression.
+ @return true if a preset dictionary is needed for decompression]]>
+
+
+
+
+ true if the end of the decompressed
+ data output stream has been reached. Indicates a concatenated data stream
+ when finished() returns true and {@link #getRemaining()}
+ returns a positive value. finished() will be reset with the
+ {@link #reset()} method.
+ @return true if the end of the decompressed
+ data output stream has been reached.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true and getRemaining() returns a positive value. If
+ {@link #finished()} returns true and getRemaining() returns
+ a zero value, indicates that the end of data stream has been reached and
+ is not a concatenated data stream.
+ @return The number of bytes remaining in the compressed data buffer.]]>
+
+
+
+
+ true and {@link #getRemaining()} returns a positive value,
+ reset() is called before processing of the next data stream in the
+ concatenated data stream. {@link #finished()} will be reset and will
+ return false when reset() is called.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Seek by key or by file offset.
+
+ The memory footprint of a TFile includes the following:
+
+
Some constant overhead of reading or writing a compressed block.
+
+
Each compressed block requires one compression/decompression codec for
+ I/O.
+
Temporary space to buffer the key.
+
Temporary space to buffer the value (for TFile.Writer only). Values are
+ chunk encoded, so that we buffer at most one chunk of user data. By default,
+ the chunk buffer is 1MB. Reading chunked value does not require additional
+ memory.
+
+
TFile index, which is proportional to the total number of Data Blocks.
+ The total amount of memory needed to hold the index can be estimated as
+ (56+AvgKeySize)*NumBlocks.
+
MetaBlock index, which is proportional to the total number of Meta
+ Blocks.The total amount of memory needed to hold the index for Meta Blocks
+ can be estimated as (40+AvgMetaBlockName)*NumMetaBlock.
+
+
+ The behavior of TFile can be customized by the following variables through
+ Configuration:
+
+
tfile.io.chunk.size: Value chunk size. Integer (in bytes). Default
+ to 1MB. Values of the length less than the chunk size is guaranteed to have
+ known value length in read time (See
+ {@link TFile.Reader.Scanner.Entry#isValueLengthKnown()}).
+
tfile.fs.output.buffer.size: Buffer size used for
+ FSDataOutputStream. Integer (in bytes). Default to 256KB.
+
tfile.fs.input.buffer.size: Buffer size used for
+ FSDataInputStream. Integer (in bytes). Default to 256KB.
+
+
+ Suggestions on performance optimization.
+
+
Minimum block size. We recommend a setting of minimum block size between
+ 256KB to 1MB for general usage. Larger block size is preferred if files are
+ primarily for sequential access. However, it would lead to inefficient random
+ access (because there are more data to decompress). Smaller blocks are good
+ for random access, but require more memory to hold the block index, and may
+ be slower to create (because we must flush the compressor stream at the
+ conclusion of each data block, which leads to an FS I/O flush). Further, due
+ to the internal caching in Compression codec, the smallest possible block
+ size would be around 20KB-30KB.
+
The current implementation does not offer true multi-threading for
+ reading. The implementation uses FSDataInputStream seek()+read(), which is
+ shown to be much faster than positioned-read call in single thread mode.
+ However, it also means that if multiple threads attempt to access the same
+ TFile (using multiple scanners) simultaneously, the actual I/O is carried out
+ sequentially even if they access different DFS blocks.
+
Compression codec. Use "none" if the data is not very compressable (by
+ compressable, I mean a compression ratio at least 2:1). Generally, use "lzo"
+ as the starting point for experimenting. "gz" overs slightly better
+ compression ratio over "lzo" but requires 4x CPU to compress and 2x CPU to
+ decompress, comparing to "lzo".
+
File system buffering, if the underlying FSDataInputStream and
+ FSDataOutputStream is already adequately buffered; or if applications
+ reads/writes keys and values in large buffers, we can reduce the sizes of
+ input/output buffering in TFile layer by setting the configuration parameters
+ "tfile.fs.input.buffer.size" and "tfile.fs.output.buffer.size".
+
+
+ Some design rationale behind TFile can be found at Hadoop-3315.]]>
+
+
+
+
+
+
+
+
+
+
+ Utils#writeVLong(out, n).
+
+ @param out
+ output stream
+ @param n
+ The integer to be encoded
+ @throws IOException
+ @see Utils#writeVLong(DataOutput, long)]]>
+
+
+
+
+
+
+
+
+
if n in [-32, 127): encode in one byte with the actual value.
+ Otherwise,
+
if n in [-20*2^8, 20*2^8): encode in two bytes: byte[0] = n/256 - 52;
+ byte[1]=n&0xff. Otherwise,
+
if n IN [-16*2^16, 16*2^16): encode in three bytes: byte[0]=n/2^16 -
+ 88; byte[1]=(n>>8)&0xff; byte[2]=n&0xff. Otherwise,
+
if n in [-8*2^24, 8*2^24): encode in four bytes: byte[0]=n/2^24 - 112;
+ byte[1] = (n>>16)&0xff; byte[2] = (n>>8)&0xff; byte[3]=n&0xff. Otherwise:
+
if n in [-2^31, 2^31): encode in five bytes: byte[0]=-125; byte[1] =
+ (n>>24)&0xff; byte[2]=(n>>16)&0xff; byte[3]=(n>>8)&0xff; byte[4]=n&0xff;
+
if n in [-2^39, 2^39): encode in six bytes: byte[0]=-124; byte[1] =
+ (n>>32)&0xff; byte[2]=(n>>24)&0xff; byte[3]=(n>>16)&0xff;
+ byte[4]=(n>>8)&0xff; byte[5]=n&0xff
+
if n in [-2^47, 2^47): encode in seven bytes: byte[0]=-123; byte[1] =
+ (n>>40)&0xff; byte[2]=(n>>32)&0xff; byte[3]=(n>>24)&0xff;
+ byte[4]=(n>>16)&0xff; byte[5]=(n>>8)&0xff; byte[6]=n&0xff;
+
if n in [-2^55, 2^55): encode in eight bytes: byte[0]=-122; byte[1] =
+ (n>>48)&0xff; byte[2] = (n>>40)&0xff; byte[3]=(n>>32)&0xff;
+ byte[4]=(n>>24)&0xff; byte[5]=(n>>16)&0xff; byte[6]=(n>>8)&0xff;
+ byte[7]=n&0xff;
+
if n in [-2^63, 2^63): encode in nine bytes: byte[0]=-121; byte[1] =
+ (n>>54)&0xff; byte[2] = (n>>48)&0xff; byte[3] = (n>>40)&0xff;
+ byte[4]=(n>>32)&0xff; byte[5]=(n>>24)&0xff; byte[6]=(n>>16)&0xff;
+ byte[7]=(n>>8)&0xff; byte[8]=n&0xff;
+
+
+ @param out
+ output stream
+ @param n
+ the integer number
+ @throws IOException]]>
+
if (FB in [-72, -33]), return (FB+52)<<8 + NB[0]&0xff;
+
if (FB in [-104, -73]), return (FB+88)<<16 + (NB[0]&0xff)<<8 +
+ NB[1]&0xff;
+
if (FB in [-120, -105]), return (FB+112)<<24 + (NB[0]&0xff)<<16 +
+ (NB[1]&0xff)<<8 + NB[2]&0xff;
+
if (FB in [-128, -121]), return interpret NB[FB+129] as a signed
+ big-endian integer.
+
+ @param in
+ input stream
+ @return the decoded long integer.
+ @throws IOException]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Type of the input key.
+ @param list
+ The list
+ @param key
+ The input key.
+ @param cmp
+ Comparator for the key.
+ @return The index to the desired element if it exists; or list.size()
+ otherwise.]]>
+
+
+
+
+
+
+
+
+ Type of the input key.
+ @param list
+ The list
+ @param key
+ The input key.
+ @param cmp
+ Comparator for the key.
+ @return The index to the desired element if it exists; or list.size()
+ otherwise.]]>
+
+
+
+
+
+
+
+ Type of the input key.
+ @param list
+ The list
+ @param key
+ The input key.
+ @return The index to the desired element if it exists; or list.size()
+ otherwise.]]>
+
+
+
+
+
+
+
+ Type of the input key.
+ @param list
+ The list
+ @param key
+ The input key.
+ @return The index to the desired element if it exists; or list.size()
+ otherwise.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ An experimental {@link Serialization} for Java {@link Serializable} classes.
+
+ @see JavaSerializationComparator]]>
+
+
+
+
+
+
+
+
+
+
+ A {@link RawComparator} that uses a {@link JavaSerialization}
+ {@link Deserializer} to deserialize objects that are then compared via
+ their {@link Comparable} interfaces.
+
+ @param
+ @see JavaSerialization]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+This package provides a mechanism for using different serialization frameworks
+in Hadoop. The property "io.serializations" defines a list of
+{@link org.apache.hadoop.io.serializer.Serialization}s that know how to create
+{@link org.apache.hadoop.io.serializer.Serializer}s and
+{@link org.apache.hadoop.io.serializer.Deserializer}s.
+
+
+
+To add a new serialization framework write an implementation of
+{@link org.apache.hadoop.io.serializer.Serialization} and add its name to the
+"io.serializations" property.
+
]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ avro.reflect.pkgs or implement
+ {@link AvroReflectSerializable} interface.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+This package provides Avro serialization in Hadoop. This can be used to
+serialize/deserialize Avro types in Hadoop.
+
+
+
+Use {@link org.apache.hadoop.io.serializer.avro.AvroSpecificSerialization} for
+serialization of classes generated by Avro's 'specific' compiler.
+
+
+
+Use {@link org.apache.hadoop.io.serializer.avro.AvroReflectSerialization} for
+other classes.
+{@link org.apache.hadoop.io.serializer.avro.AvroReflectSerialization} work for
+any class which is either in the package list configured via
+{@link org.apache.hadoop.io.serializer.avro.AvroReflectSerialization#AVRO_REFLECT_PACKAGES}
+or implement {@link org.apache.hadoop.io.serializer.avro.AvroReflectSerializable}
+interface.
+
]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+The API is abstract so that it can be implemented on top of
+a variety of metrics client libraries. The choice of
+client library is a configuration option, and different
+modules within the same application can use
+different metrics implementation libraries.
+
+Sub-packages:
+
+
org.apache.hadoop.metrics.spi
+
The abstract Server Provider Interface package. Those wishing to
+ integrate the metrics API with a particular metrics client library should
+ extend this package.
+
+
org.apache.hadoop.metrics.file
+
An implementation package which writes the metric data to
+ a file, or sends it to the standard output stream.
+
+
org.apache.hadoop.metrics.ganglia
+
An implementation package which sends metric data to
+ Ganglia.
+
+
+
Introduction to the Metrics API
+
+Here is a simple example of how to use this package to report a single
+metric value:
+
The context name will typically identify either the application, or else a
+ module within an application or library.
+
+
myRecord
+
The record name generally identifies some entity for which a set of
+ metrics are to be reported. For example, you could have a record named
+ "cacheStats" for reporting a number of statistics relating to the usage of
+ some cache in your application.
+
+
myMetric
+
This identifies a particular metric. For example, you might have metrics
+ named "cache_hits" and "cache_misses".
+
+
+
+
Tags
+
+In some cases it is useful to have multiple records with the same name. For
+example, suppose that you want to report statistics about each disk on a computer.
+In this case, the record name would be something like "diskStats", but you also
+need to identify the disk which is done by adding a tag to the record.
+The code could look something like this:
+
+
+Data is not sent immediately to the metrics system when
+MetricsRecord.update() is called. Instead it is stored in an
+internal table, and the contents of the table are sent periodically.
+This can be important for two reasons:
+
+
It means that a programmer is free to put calls to this API in an
+ inner loop, since updates can be very frequent without slowing down
+ the application significantly.
+
Some implementations can gain efficiency by combining many metrics
+ into a single UDP message.
+
+
+The API provides a timer-based callback via the
+registerUpdater() method. The benefit of this
+versus using java.util.Timer is that the callbacks will be done
+immediately before sending the data, making the data as current as possible.
+
+
Configuration
+
+It is possible to programmatically examine and modify configuration data
+before creating a context, like this:
+
+The factory attributes can be examined and modified using the following
+ContextFactorymethods:
+
+
Object getAttribute(String attributeName)
+
String[] getAttributeNames()
+
void setAttribute(String name, Object value)
+
void removeAttribute(attributeName)
+
+
+
+ContextFactory.getFactory() initializes the factory attributes by
+reading the properties file hadoop-metrics.properties if it exists
+on the class path.
+
+
+A factory attribute named:
+
+contextName.class
+
+should have as its value the fully qualified name of the class to be
+instantiated by a call of the CodeFactory method
+getContext(contextName). If this factory attribute is not
+specified, the default is to instantiate
+org.apache.hadoop.metrics.file.FileContext.
+
+
+Other factory attributes are specific to a particular implementation of this
+API and are documented elsewhere. For example, configuration attributes for
+the file and Ganglia implementations can be found in the javadoc for
+their respective packages.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Implementation of the metrics package that sends metric data to
+Ganglia.
+Programmers should not normally need to use this package directly. Instead
+they should use org.hadoop.metrics.
+
+
+These are the implementation specific factory attributes
+(See ContextFactory.getFactory()):
+
+
+
contextName.servers
+
Space and/or comma separated sequence of servers to which UDP
+ messages should be sent.
+
+
contextName.period
+
The period in seconds on which the metric data is sent to the
+ server(s).
+
+
contextName.multicast
+
Enable multicast for Ganglia
+
+
contextName.multicast.ttl
+
TTL for multicast packets
+
+
contextName.units.recordName.metricName
+
The units for the specified metric in the specified record.
+
+
contextName.slope.recordName.metricName
+
The slope for the specified metric in the specified record.
+
+
contextName.tmax.recordName.metricName
+
The tmax for the specified metric in the specified record.
+
+
contextName.dmax.recordName.metricName
+
The dmax for the specified metric in the specified record.
+
+
]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ contextName.tableName. The returned map consists of
+ those attributes with the contextName and tableName stripped off.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ recordName.
+ Throws an exception if the metrics implementation is configured with a fixed
+ set of record names and recordName is not in that set.
+
+ @param recordName the name of the record
+ @throws MetricsException if recordName conflicts with configuration data]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This class implements the internal table of metric data, and the timer
+ on which data is to be sent to the metrics system. Subclasses must
+ override the abstract emitRecord method in order to transmit
+ the data.
+
+ @deprecated Use org.apache.hadoop.metrics2 package instead.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ update
+ and remove().
+
+ @deprecated Use {@link org.apache.hadoop.metrics2.impl.MetricsRecordImpl}
+ instead.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ hostname or hostname:port. If
+ the specs string is null, defaults to localhost:defaultPort.
+
+ @return a list of InetSocketAddress objects.]]>
+
+
+
+
+
+
+
+
+ org.apache.hadoop.metrics.file and
+org.apache.hadoop.metrics.ganglia.
+
+Plugging in an implementation involves writing a concrete subclass of
+AbstractMetricsContext. The subclass should get its
+ configuration information using the getAttribute(attributeName)
+ method.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Implementations of this interface consume the {@link MetricsRecord} generated
+ from {@link MetricsSource}. It registers with {@link MetricsSystem} which
+ periodically pushes the {@link MetricsRecord} to the sink using
+ {@link #putMetrics(MetricsRecord)} method. If the implementing class also
+ implements {@link Closeable}, then the MetricsSystem will close the sink when
+ it is stopped.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ the actual type of the source object
+ @param source object to register
+ @return the source object
+ @exception MetricsException]]>
+
+
+
+
+
+
+
+ the actual type of the source object
+ @param source object to register
+ @param name of the source. Must be unique or null (then extracted from
+ the annotations of the source object.)
+ @param desc the description of the source (or null. See above.)
+ @return the source object
+ @exception MetricsException]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (aggregate).
+ Filter out entries that don't have at least minSamples.
+
+ @return a map of peer DataNode Id to the average latency to that
+ node seen over the measurement period.]]>
+
+
+
+
+ This class maintains a group of rolling average metrics. It implements the
+ algorithm of rolling average, i.e. a number of sliding windows are kept to
+ roll over and evict old subsets of samples. Each window has a subset of
+ samples in a stream, where sub-sum and sub-total are collected. All sub-sums
+ and sub-totals in all windows will be aggregated to final-sum and final-total
+ used to compute final average, which is called rolling average.
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This class is a metrics sink that uses
+ {@link org.apache.hadoop.fs.FileSystem} to write the metrics logs. Every
+ roll interval a new directory will be created under the path specified by the
+ basepath property. All metrics will be logged to a file in the
+ current interval's directory in a file named <hostname>.log, where
+ <hostname> is the name of the host on which the metrics logging
+ process is running. The base path is set by the
+ <prefix>.sink.<instance>.basepath property. The
+ time zone used to create the current interval's directory name is GMT. If
+ the basepath property isn't specified, it will default to
+ "/tmp", which is the temp directory on whatever default file
+ system is configured for the cluster.
+
+
The <prefix>.sink.<instance>.ignore-error
+ property controls whether an exception is thrown when an error is encountered
+ writing a log file. The default value is true. When set to
+ false, file errors are quietly swallowed.
+
+
The roll-interval property sets the amount of time before
+ rolling the directory. The default value is 1 hour. The roll interval may
+ not be less than 1 minute. The property's value should be given as
+ number unit, where number is an integer value, and
+ unit is a valid unit. Valid units are minute, hour,
+ and day. The units are case insensitive and may be abbreviated or
+ plural. If no units are specified, hours are assumed. For example,
+ "2", "2h", "2 hour", and
+ "2 hours" are all valid ways to specify two hours.
+
+
The roll-offset-interval-millis property sets the upper
+ bound on a random time interval (in milliseconds) that is used to delay
+ before the initial roll. All subsequent rolls will happen an integer
+ number of roll intervals after the initial roll, hence retaining the original
+ offset. The purpose of this property is to insert some variance in the roll
+ times so that large clusters using this sink on every node don't cause a
+ performance impact on HDFS by rolling simultaneously. The default value is
+ 30000 (30s). When writing to HDFS, as a rule of thumb, the roll offset in
+ millis should be no less than the number of sink instances times 5.
+
+
The primary use of this class is for logging to HDFS. As it uses
+ {@link org.apache.hadoop.fs.FileSystem} to access the target file system,
+ however, it can be used to write to the local file system, Amazon S3, or any
+ other supported file system. The base path for the sink will determine the
+ file system used. An unqualified path will write to the default file system
+ set by the configuration.
+
+
Not all file systems support the ability to append to files. In file
+ systems without the ability to append to files, only one writer can write to
+ a file at a time. To allow for concurrent writes from multiple daemons on a
+ single host, the source property is used to set unique headers
+ for the log files. The property should be set to the name of
+ the source daemon, e.g. namenode. The value of the
+ source property should typically be the same as the property's
+ prefix. If this property is not set, the source is taken to be
+ unknown.
+
+
Instead of appending to an existing file, by default the sink
+ will create a new file with a suffix of ".<n>&quet;, where
+ n is the next lowest integer that isn't already used in a file name,
+ similar to the Hadoop daemon logs. NOTE: the file with the highest
+ sequence number is the newest file, unlike the Hadoop daemon logs.
+
+
For file systems that allow append, the sink supports appending to the
+ existing file instead. If the allow-append property is set to
+ true, the sink will instead append to the existing file on file systems that
+ support appends. By default, the allow-append property is
+ false.
+
+
Note that when writing to HDFS with allow-append set to true,
+ there is a minimum acceptable number of data nodes. If the number of data
+ nodes drops below that minimum, the append will succeed, but reading the
+ data will fail with an IOException in the DataStreamer class. The minimum
+ number of data nodes required for a successful append is generally 2 or
+ 3.
+
+
Note also that when writing to HDFS, the file size information is not
+ updated until the file is closed (at the end of the interval) even though
+ the data is being written successfully. This is a known HDFS limitation that
+ exists because of the performance cost of updating the metadata. See
+ HDFS-5478.
+
+
When using this sink in a secure (Kerberos) environment, two additional
+ properties must be set: keytab-key and
+ principal-key. keytab-key should contain the key by
+ which the keytab file can be found in the configuration, for example,
+ yarn.nodemanager.keytab. principal-key should
+ contain the key by which the principal can be found in the configuration,
+ for example, yarn.nodemanager.principal.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CollectD StatsD plugin).
+
+ To configure this plugin, you will need to add the following
+ entries to your hadoop-metrics2.properties file:
+
+
+ *.sink.statsd.class=org.apache.hadoop.metrics2.sink.StatsDSink
+ [prefix].sink.statsd.server.host=
+ [prefix].sink.statsd.server.port=
+ [prefix].sink.statsd.skip.hostname=true|false (optional)
+ [prefix].sink.statsd.service.name=NameNode (name you want for service)
+
]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ,name="
+ Where the and are the supplied parameters
+
+ @param serviceName
+ @param nameName
+ @param theMbean - the MBean to register
+ @return the named used to register the MBean]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ hostname or hostname:port. If
+ the specs string is null, defaults to localhost:defaultPort.
+
+ @param specs server specs (see description)
+ @param defaultPort the default port if not specified
+ @return a list of InetSocketAddress objects.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This method is used when parts of Hadoop need know whether to apply
+ single rack vs multi-rack policies, such as during block placement.
+ Such algorithms behave differently if they are on multi-switch systems.
+
+
+ @return true if the mapping thinks that it is on a single switch]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This predicate simply assumes that all mappings not derived from
+ this class are multi-switch.
+ @param mapping the mapping to query
+ @return true if the base class says it is single switch, or the mapping
+ is not derived from this class.]]>
+
+
+
+ It is not mandatory to
+ derive {@link DNSToSwitchMapping} implementations from it, but it is strongly
+ recommended, as it makes it easy for the Hadoop developers to add new methods
+ to this base class that are automatically picked up by all implementations.
+
+
+ This class does not extend the Configured
+ base class, and should not be changed to do so, as it causes problems
+ for subclasses. The constructor of the Configured calls
+ the {@link #setConf(Configuration)} method, which will call into the
+ subclasses before they have been fully constructed.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ If a name cannot be resolved to a rack, the implementation
+ should return {@link NetworkTopology#DEFAULT_RACK}. This
+ is what the bundled implementations do, though it is not a formal requirement
+
+ @param names the list of hosts to resolve (can be empty)
+ @return list of resolved network paths.
+ If names is empty, the returned list is also empty]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Calling {@link #setConf(Configuration)} will trigger a
+ re-evaluation of the configuration settings and so be used to
+ set up the mapping script.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This will get called in the superclass constructor, so a check is needed
+ to ensure that the raw mapping is defined before trying to relaying a null
+ configuration.
+ @param conf]]>
+
+
+
+
+
+
+
+
+
+ It contains a static class RawScriptBasedMapping that performs
+ the work: reading the configuration parameters, executing any defined
+ script, handling errors and such like. The outer
+ class extends {@link CachedDNSToSwitchMapping} to cache the delegated
+ queries.
+
+ This DNS mapper's {@link #isSingleSwitch()} predicate returns
+ true if and only if a script is defined.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Simple {@link DNSToSwitchMapping} implementation that reads a 2 column text
+ file. The columns are separated by whitespace. The first column is a DNS or
+ IP address and the second column specifies the rack where the address maps.
+
+
+ This class uses the configuration parameter {@code
+ net.topology.table.file.name} to locate the mapping file.
+
+
+ Calls to {@link #resolve(List)} will look up the address as defined in the
+ mapping file. If no entry corresponding to the address is found, the value
+ {@code /default-rack} is returned.
+
+
+ Software systems of any significant complexity require mechanisms for data
+interchange with the outside world. These interchanges typically involve the
+marshaling and unmarshaling of logical units of data to and from data streams
+(files, network connections, memory buffers etc.). Applications usually have
+some code for serializing and deserializing the data types that they manipulate
+embedded in them. The work of serialization has several features that make
+automatic code generation for it worthwhile. Given a particular output encoding
+(binary, XML, etc.), serialization of primitive types and simple compositions
+of primitives (structs, vectors etc.) is a very mechanical task. Manually
+written serialization code can be susceptible to bugs especially when records
+have a large number of fields or a record definition changes between software
+versions. Lastly, it can be very useful for applications written in different
+programming languages to be able to share and interchange data. This can be
+made a lot easier by describing the data records manipulated by these
+applications in a language agnostic manner and using the descriptions to derive
+implementations of serialization in multiple target languages.
+
+This document describes Hadoop Record I/O, a mechanism that is aimed
+at
+
+
enabling the specification of simple serializable data types (records)
+
enabling the generation of code in multiple target languages for
+marshaling and unmarshaling such types
+
providing target language specific support that will enable application
+programmers to incorporate generated code into their applications
+
+
+The goals of Hadoop Record I/O are similar to those of mechanisms such as XDR,
+ASN.1, PADS and ICE. While these systems all include a DDL that enables
+the specification of most record types, they differ widely in what else they
+focus on. The focus in Hadoop Record I/O is on data marshaling and
+multi-lingual support. We take a translator-based approach to serialization.
+Hadoop users have to describe their data in a simple data description
+language. The Hadoop DDL translator rcc generates code that users
+can invoke in order to read/write their data from/to simple stream
+abstractions. Next we list explicitly some of the goals and non-goals of
+Hadoop Record I/O.
+
+
+
Goals
+
+
+
Support for commonly used primitive types. Hadoop should include as
+primitives commonly used builtin types from programming languages we intend to
+support.
+
+
Support for common data compositions (including recursive compositions).
+Hadoop should support widely used composite types such as structs and
+vectors.
+
+
Code generation in multiple target languages. Hadoop should be capable of
+generating serialization code in multiple target languages and should be
+easily extensible to new target languages. The initial target languages are
+C++ and Java.
+
+
Support for generated target languages. Hadooop should include support
+in the form of headers, libraries, packages for supported target languages
+that enable easy inclusion and use of generated code in applications.
+
+
Support for multiple output encodings. Candidates include
+packed binary, comma-separated text, XML etc.
+
+
Support for specifying record types in a backwards/forwards compatible
+manner. This will probably be in the form of support for optional fields in
+records. This version of the document does not include a description of the
+planned mechanism, we intend to include it in the next iteration.
+
+
+
+
Non-Goals
+
+
+
Serializing existing arbitrary C++ classes.
+
Serializing complex data structures such as trees, linked lists etc.
+
Built-in indexing schemes, compression, or check-sums.
+
Dynamic construction of objects from an XML schema.
+
+
+The remainder of this document describes the features of Hadoop record I/O
+in more detail. Section 2 describes the data types supported by the system.
+Section 3 lays out the DDL syntax with some examples of simple records.
+Section 4 describes the process of code generation with rcc. Section 5
+describes target language mappings and support for Hadoop types. We include a
+fairly complete description of C++ mappings with intent to include Java and
+others in upcoming iterations of this document. The last section talks about
+supported output encodings.
+
+
+
Data Types and Streams
+
+This section describes the primitive and composite types supported by Hadoop.
+We aim to support a set of types that can be used to simply and efficiently
+express a wide range of record types in different programming languages.
+
+
Primitive Types
+
+For the most part, the primitive types of Hadoop map directly to primitive
+types in high level programming languages. Special cases are the
+ustring (a Unicode string) and buffer types, which we believe
+find wide use and which are usually implemented in library code and not
+available as language built-ins. Hadoop also supplies these via library code
+when a target language built-in is not present and there is no widely
+adopted "standard" implementation. The complete list of primitive types is:
+
+
+
byte: An 8-bit unsigned integer.
+
boolean: A boolean value.
+
int: A 32-bit signed integer.
+
long: A 64-bit signed integer.
+
float: A single precision floating point number as described by
+ IEEE-754.
+
double: A double precision floating point number as described by
+ IEEE-754.
+
ustring: A string consisting of Unicode characters.
+
buffer: An arbitrary sequence of bytes.
+
+
+
+
Composite Types
+Hadoop supports a small set of composite types that enable the description
+of simple aggregate types and containers. A composite type is serialized
+by sequentially serializing it constituent elements. The supported
+composite types are:
+
+
+
+
record: An aggregate type like a C-struct. This is a list of
+typed fields that are together considered a single unit of data. A record
+is serialized by sequentially serializing its constituent fields. In addition
+to serialization a record has comparison operations (equality and less-than)
+implemented for it, these are defined as memberwise comparisons.
+
+
vector: A sequence of entries of the same data type, primitive
+or composite.
+
+
map: An associative container mapping instances of a key type to
+instances of a value type. The key and value types may themselves be primitive
+or composite types.
+
+
+
+
Streams
+
+Hadoop generates code for serializing and deserializing record types to
+abstract streams. For each target language Hadoop defines very simple input
+and output stream interfaces. Application writers can usually develop
+concrete implementations of these by putting a one method wrapper around
+an existing stream implementation.
+
+
+
DDL Syntax and Examples
+
+We now describe the syntax of the Hadoop data description language. This is
+followed by a few examples of DDL usage.
+
+
+
+A DDL file describes one or more record types. It begins with zero or
+more include declarations, a single mandatory module declaration
+followed by zero or more class declarations. The semantics of each of
+these declarations are described below:
+
+
+
+
include: An include declaration specifies a DDL file to be
+referenced when generating code for types in the current DDL file. Record types
+in the current compilation unit may refer to types in all included files.
+File inclusion is recursive. An include does not trigger code
+generation for the referenced file.
+
+
module: Every Hadoop DDL file must have a single module
+declaration that follows the list of includes and precedes all record
+declarations. A module declaration identifies a scope within which
+the names of all types in the current file are visible. Module names are
+mapped to C++ namespaces, Java packages etc. in generated code.
+
+
class: Records types are specified through class
+declarations. A class declaration is like a Java class declaration.
+It specifies a named record type and a list of fields that constitute records
+of the type. Usage is illustrated in the following examples.
+
+
+
+
Examples
+
+
+
A simple DDL file links.jr with just one record declaration.
+
+module links {
+ class Link {
+ ustring URL;
+ boolean isRelative;
+ ustring anchorText;
+ };
+}
+
+
+The Hadoop translator is written in Java. Invocation is done by executing a
+wrapper shell script named named rcc. It takes a list of
+record description files as a mandatory argument and an
+optional language argument (the default is Java) --language or
+-l. Thus a typical invocation would look like:
+
+$ rcc -l C++ ...
+
+
+
+
Target Language Mappings and Support
+
+For all target languages, the unit of code generation is a record type.
+For each record type, Hadoop generates code for serialization and
+deserialization, record comparison and access to record members.
+
+
C++
+
+Support for including Hadoop generated C++ code in applications comes in the
+form of a header file recordio.hh which needs to be included in source
+that uses Hadoop types and a library librecordio.a which applications need
+to be linked with. The header declares the Hadoop C++ namespace which defines
+appropriate types for the various primitives, the basic interfaces for
+records and streams and enumerates the supported serialization encodings.
+Declarations of these interfaces and a description of their semantics follow:
+
+
RecFormat: An enumeration of the serialization encodings supported
+by this implementation of Hadoop.
+
+
InStream: A simple abstraction for an input stream. This has a
+single public read method that reads n bytes from the stream into
+the buffer buf. Has the same semantics as a blocking read system
+call. Returns the number of bytes read or -1 if an error occurs.
+
+
OutStream: A simple abstraction for an output stream. This has a
+single write method that writes n bytes to the stream from the
+buffer buf. Has the same semantics as a blocking write system
+call. Returns the number of bytes written or -1 if an error occurs.
+
+
RecordReader: A RecordReader reads records one at a time from
+an underlying stream in a specified record format. The reader is instantiated
+with a stream and a serialization format. It has a read method that
+takes an instance of a record and deserializes the record from the stream.
+
+
RecordWriter: A RecordWriter writes records one at a
+time to an underlying stream in a specified record format. The writer is
+instantiated with a stream and a serialization format. It has a
+write method that takes an instance of a record and serializes the
+record to the stream.
+
+
Record: The base class for all generated record types. This has two
+public methods type and signature that return the typename and the
+type signature of the record.
+
+
+
+Two files are generated for each record file (note: not for each record). If a
+record file is named "name.jr", the generated files are
+"name.jr.cc" and "name.jr.hh" containing serialization
+implementations and record type declarations respectively.
+
+For each record in the DDL file, the generated header file will contain a
+class definition corresponding to the record type, method definitions for the
+generated type will be present in the '.cc' file. The generated class will
+inherit from the abstract class hadoop::Record. The DDL files
+module declaration determines the namespace the record belongs to.
+Each '.' delimited token in the module declaration results in the
+creation of a namespace. For instance, the declaration module docs.links
+results in the creation of a docs namespace and a nested
+docs::links namespace. In the preceding examples, the Link class
+is placed in the links namespace. The header file corresponding to
+the links.jr file will contain:
+
+
+namespace links {
+ class Link : public hadoop::Record {
+ // ....
+ };
+};
+
+
+Each field within the record will cause the generation of a private member
+declaration of the appropriate type in the class declaration, and one or more
+acccessor methods. The generated class will implement the serialize and
+deserialize methods defined in hadoop::Record+. It will also
+implement the inspection methods type and signature from
+hadoop::Record. A default constructor and virtual destructor will also
+be generated. Serialization code will read/write records into streams that
+implement the hadoop::InStream and the hadoop::OutStream interfaces.
+
+For each member of a record an accessor method is generated that returns
+either the member or a reference to the member. For members that are returned
+by value, a setter method is also generated. This is true for primitive
+data members of the types byte, int, long, boolean, float and
+double. For example, for a int field called MyField the folowing
+code is generated.
+
+
+
+For a ustring or buffer or composite field. The generated code
+only contains accessors that return a reference to the field. A const
+and a non-const accessor are generated. For example:
+
+
+
+Code generation for Java is similar to that for C++. A Java class is generated
+for each record type with private members corresponding to the fields. Getters
+and setters for fields are also generated. Some differences arise in the
+way comparison is expressed and in the mapping of modules to packages and
+classes to files. For equality testing, an equals method is generated
+for each record type. As per Java requirements a hashCode method is also
+generated. For comparison a compareTo method is generated for each
+record type. This has the semantics as defined by the Java Comparable
+interface, that is, the method returns a negative integer, zero, or a positive
+integer as the invoked object is less than, equal to, or greater than the
+comparison parameter.
+
+A .java file is generated per record type as opposed to per DDL
+file as in C++. The module declaration translates to a Java
+package declaration. The module name maps to an identical Java package
+name. In addition to this mapping, the DDL compiler creates the appropriate
+directory hierarchy for the package and places the generated .java
+files in the correct directories.
+
+
Mapping Summary
+
+
+DDL Type C++ Type Java Type
+
+boolean bool boolean
+byte int8_t byte
+int int32_t int
+long int64_t long
+float float float
+double double double
+ustring std::string java.lang.String
+buffer std::string org.apache.hadoop.record.Buffer
+class type class type class type
+vector std::vector java.util.ArrayList
+map std::map java.util.TreeMap
+
+
+
Data encodings
+
+This section describes the format of the data encodings supported by Hadoop.
+Currently, three data encodings are supported, namely binary, CSV and XML.
+
+
Binary Serialization Format
+
+The binary data encoding format is fairly dense. Serialization of composite
+types is simply defined as a concatenation of serializations of the constituent
+elements (lengths are included in vectors and maps).
+
+Composite types are serialized as follows:
+
+
class: Sequence of serialized members.
+
vector: The number of elements serialized as an int. Followed by a
+sequence of serialized elements.
+
map: The number of key value pairs serialized as an int. Followed
+by a sequence of serialized (key,value) pairs.
+
+
+Serialization of primitives is more interesting, with a zero compression
+optimization for integral types and normalization to UTF-8 for strings.
+Primitive types are serialized as follows:
+
+
+
byte: Represented by 1 byte, as is.
+
boolean: Represented by 1-byte (0 or 1)
+
int/long: Integers and longs are serialized zero compressed.
+Represented as 1-byte if -120 <= value < 128. Otherwise, serialized as a
+sequence of 2-5 bytes for ints, 2-9 bytes for longs. The first byte represents
+the number of trailing bytes, N, as the negative number (-120-N). For example,
+the number 1024 (0x400) is represented by the byte sequence 'x86 x04 x00'.
+This doesn't help much for 4-byte integers but does a reasonably good job with
+longs without bit twiddling.
+
float/double: Serialized in IEEE 754 single and double precision
+format in network byte order. This is the format used by Java.
+
ustring: Serialized as 4-byte zero compressed length followed by
+data encoded as UTF-8. Strings are normalized to UTF-8 regardless of native
+language representation.
+
buffer: Serialized as a 4-byte zero compressed length followed by the
+raw bytes in the buffer.
+
+
+
+
CSV Serialization Format
+
+The CSV serialization format has a lot more structure than the "standard"
+Excel CSV format, but we believe the additional structure is useful because
+
+
+
it makes parsing a lot easier without detracting too much from legibility
+
the delimiters around composites make it obvious when one is reading a
+sequence of Hadoop records
+
+
+Serialization formats for the various types are detailed in the grammar that
+follows. The notable feature of the formats is the use of delimiters for
+indicating the certain field types.
+
+
+
A string field begins with a single quote (').
+
A buffer field begins with a sharp (#).
+
A class, vector or map begins with 's{', 'v{' or 'm{' respectively and
+ends with '}'.
+
+
+The CSV format can be described by the following grammar:
+
+
+
+The XML serialization format is the same used by Apache XML-RPC
+(http://ws.apache.org/xmlrpc/types.html). This is an extension of the original
+XML-RPC format and adds some additional data types. All record I/O types are
+not directly expressible in this format, and access to a DDL is required in
+order to convert these to valid types. All types primitive or composite are
+represented by <value> elements. The particular XML-RPC type is
+indicated by a nested element in the <value> element. The encoding for
+records is always UTF-8. Primitive types are serialized as follows:
+
+
+
byte: XML tag <ex:i1>. Values: 1-byte unsigned
+integers represented in US-ASCII
+
boolean: XML tag <boolean>. Values: "0" or "1"
+
int: XML tags <i4> or <int>. Values: 4-byte
+signed integers represented in US-ASCII.
+
long: XML tag <ex:i8>. Values: 8-byte signed integers
+represented in US-ASCII.
+
float: XML tag <ex:float>. Values: Single precision
+floating point numbers represented in US-ASCII.
+
double: XML tag <double>. Values: Double precision
+floating point numbers represented in US-ASCII.
+
ustring: XML tag <;string>. Values: String values
+represented as UTF-8. XML does not permit all Unicode characters in literal
+data. In particular, NULLs and control chars are not allowed. Additionally,
+XML processors are required to replace carriage returns with line feeds and to
+replace CRLF sequences with line feeds. Programming languages that we work
+with do not impose these restrictions on string types. To work around these
+restrictions, disallowed characters and CRs are percent escaped in strings.
+The '%' character is also percent escaped.
+
buffer: XML tag <string&>. Values: Arbitrary binary
+data. Represented as hexBinary, each byte is replaced by its 2-byte
+hexadecimal representation.
+
+
+Composite types are serialized as follows:
+
+
+
class: XML tag <struct>. A struct is a sequence of
+<member> elements. Each <member> element has a <name>
+element and a <value> element. The <name> is a string that must
+match /[a-zA-Z][a-zA-Z0-9_]*/. The value of the member is represented
+by a <value> element.
+
+
vector: XML tag <array<. An <array> contains a
+single <data> element. The <data> element is a sequence of
+<value> elements each of which represents an element of the vector.
+
+
map: XML tag <array>. Same as vector.
+
+
+
+For example:
+
+
+class {
+ int MY_INT; // value 5
+ vector MY_VEC; // values 0.1, -0.89, 2.45e4
+ buffer MY_BUF; // value '\00\n\tabc%'
+}
+
]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This task takes the given record definition files and compiles them into
+ java or c++
+ files. It is then up to the user to compile the generated files.
+
+
The task requires the file or the nested fileset element to be
+ specified. Optional attributes are language (set the output
+ language, default is "java"),
+ destdir (name of the destination directory for generated java/c++
+ code, default is ".") and failonerror (specifies error handling
+ behavior. default is true).
+
]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Avro.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Avro.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Avro.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Avro.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Avro.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Avro.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Avro.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (cause==null ? null : cause.toString()) (which
+ typically contains the class and detail message of cause).
+ @param cause the cause (which is saved for later retrieval by the
+ {@link #getCause()} method). (A null value is
+ permitted, and indicates that the cause is nonexistent or
+ unknown.)]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ mapping
+ and mapping]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /host@realm.
+ @param principalName principal name of format as described above
+ @return host name if the the string conforms to the above format, else null]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ "jack"
+
+ @param userName
+ @return userName without login method]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ the return type of the run method
+ @param action the method to execute
+ @return the value from the run method]]>
+
+
+
+
+
+
+
+ the return type of the run method
+ @param action the method to execute
+ @return the value from the run method
+ @throws IOException if the action throws an IOException
+ @throws Error if the action throws an Error
+ @throws RuntimeException if the action throws a RuntimeException
+ @throws InterruptedException if the action throws an InterruptedException
+ @throws UndeclaredThrowableException if the action throws something else]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (cause==null ? null : cause.toString()) (which
+ typically contains the class and detail message of cause).
+ @param cause the cause (which is saved for later retrieval by the
+ {@link #getCause()} method). (A null value is
+ permitted, and indicates that the cause is nonexistent or
+ unknown.)]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ does not provide the stack trace for security purposes.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A User-Agent String is considered to be a browser if it matches
+ any of the regex patterns from browser-useragent-regex; the default
+ behavior is to consider everything a browser that matches the following:
+ "^Mozilla.*,^Opera.*". Subclasses can optionally override
+ this method to use different behavior.
+
+ @param userAgent The User-Agent String, or null if there isn't one
+ @return true if the User-Agent String refers to a browser, false if not]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The type of the token identifier]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ T extends TokenIdentifier]]>
+
+
+
+
+
+
+
+
+
+ DelegationTokenAuthenticatedURL.
+
+ An instance of the default {@link DelegationTokenAuthenticator} will be
+ used.]]>
+
+
+
+
+ DelegationTokenAuthenticatedURL.
+
+ @param authenticator the {@link DelegationTokenAuthenticator} instance to
+ use, if null the default one will be used.]]>
+
+
+
+
+ DelegationTokenAuthenticatedURL using the default
+ {@link DelegationTokenAuthenticator} class.
+
+ @param connConfigurator a connection configurator.]]>
+
+
+
+
+ DelegationTokenAuthenticatedURL.
+
+ @param authenticator the {@link DelegationTokenAuthenticator} instance to
+ use, if null the default one will be used.
+ @param connConfigurator a connection configurator.]]>
+
+
+
+
+
+
+
+
+
+
+
+ The default class is {@link KerberosDelegationTokenAuthenticator}
+
+ @return the delegation token authenticator class to use as default.]]>
+
+
+
+
+
+
+ This method is provided to enable WebHDFS backwards compatibility.
+
+ @param useQueryString TRUE if the token is transmitted in the
+ URL query string, FALSE if the delegation token is transmitted
+ using the {@link DelegationTokenAuthenticator#DELEGATION_TOKEN_HEADER} HTTP
+ header.]]>
+
+
+
+
+ TRUE if the token is transmitted in the URL query
+ string, FALSE if the delegation token is transmitted using the
+ {@link DelegationTokenAuthenticator#DELEGATION_TOKEN_HEADER} HTTP header.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Authenticator.
+
+ @param url the URL to connect to. Only HTTP/S URLs are supported.
+ @param token the authentication token being used for the user.
+ @return an authenticated {@link HttpURLConnection}.
+ @throws IOException if an IO error occurred.
+ @throws AuthenticationException if an authentication exception occurred.]]>
+
+
+
+
+
+
+
+
+
+ Authenticator. If the doAs parameter is not NULL,
+ the request will be done on behalf of the specified doAs user.
+
+ @param url the URL to connect to. Only HTTP/S URLs are supported.
+ @param token the authentication token being used for the user.
+ @param doAs user to do the the request on behalf of, if NULL the request is
+ as self.
+ @return an authenticated {@link HttpURLConnection}.
+ @throws IOException if an IO error occurred.
+ @throws AuthenticationException if an authentication exception occurred.]]>
+
+
+
+
+
+
+
+
+
+ Authenticator
+ for authentication.
+
+ @param url the URL to get the delegation token from. Only HTTP/S URLs are
+ supported.
+ @param token the authentication token being used for the user where the
+ Delegation token will be stored.
+ @param renewer the renewer user.
+ @return a delegation token.
+ @throws IOException if an IO error occurred.
+ @throws AuthenticationException if an authentication exception occurred.]]>
+
+
+
+
+
+
+
+
+
+
+ Authenticator
+ for authentication.
+
+ @param url the URL to get the delegation token from. Only HTTP/S URLs are
+ supported.
+ @param token the authentication token being used for the user where the
+ Delegation token will be stored.
+ @param renewer the renewer user.
+ @param doAsUser the user to do as, which will be the token owner.
+ @return a delegation token.
+ @throws IOException if an IO error occurred.
+ @throws AuthenticationException if an authentication exception occurred.]]>
+
+
+
+
+
+
+
+
+ Authenticator for authentication.
+
+ @param url the URL to renew the delegation token from. Only HTTP/S URLs are
+ supported.
+ @param token the authentication token with the Delegation Token to renew.
+ @throws IOException if an IO error occurred.
+ @throws AuthenticationException if an authentication exception occurred.]]>
+
+
+
+
+
+
+
+
+
+ Authenticator for authentication.
+
+ @param url the URL to renew the delegation token from. Only HTTP/S URLs are
+ supported.
+ @param token the authentication token with the Delegation Token to renew.
+ @param doAsUser the user to do as, which will be the token owner.
+ @throws IOException if an IO error occurred.
+ @throws AuthenticationException if an authentication exception occurred.]]>
+
+
+
+
+
+
+
+ Authenticator.
+
+ @param url the URL to cancel the delegation token from. Only HTTP/S URLs
+ are supported.
+ @param token the authentication token with the Delegation Token to cancel.
+ @throws IOException if an IO error occurred.]]>
+
+
+
+
+
+
+
+
+ Authenticator.
+
+ @param url the URL to cancel the delegation token from. Only HTTP/S URLs
+ are supported.
+ @param token the authentication token with the Delegation Token to cancel.
+ @param doAsUser the user to do as, which will be the token owner.
+ @throws IOException if an IO error occurred.]]>
+
+
+
+ DelegationTokenAuthenticatedURL is a
+ {@link AuthenticatedURL} sub-class with built-in Hadoop Delegation Token
+ functionality.
+
+ The authentication mechanisms supported by default are Hadoop Simple
+ authentication (also known as pseudo authentication) and Kerberos SPNEGO
+ authentication.
+
+ Additional authentication mechanisms can be supported via {@link
+ DelegationTokenAuthenticator} implementations.
+
+ The default {@link DelegationTokenAuthenticator} is the {@link
+ KerberosDelegationTokenAuthenticator} class which supports
+ automatic fallback from Kerberos SPNEGO to Hadoop Simple authentication via
+ the {@link PseudoDelegationTokenAuthenticator} class.
+
+ AuthenticatedURL instances are not thread-safe.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Authenticator
+ for authentication.
+
+ @param url the URL to get the delegation token from. Only HTTP/S URLs are
+ supported.
+ @param token the authentication token being used for the user where the
+ Delegation token will be stored.
+ @param renewer the renewer user.
+ @throws IOException if an IO error occurred.
+ @throws AuthenticationException if an authentication exception occurred.]]>
+
+
+
+
+
+
+
+
+
+
+ Authenticator
+ for authentication.
+
+ @param url the URL to get the delegation token from. Only HTTP/S URLs are
+ supported.
+ @param token the authentication token being used for the user where the
+ Delegation token will be stored.
+ @param renewer the renewer user.
+ @param doAsUser the user to do as, which will be the token owner.
+ @throws IOException if an IO error occurred.
+ @throws AuthenticationException if an authentication exception occurred.]]>
+
+
+
+
+
+
+
+
+
+ Authenticator for authentication.
+
+ @param url the URL to renew the delegation token from. Only HTTP/S URLs are
+ supported.
+ @param token the authentication token with the Delegation Token to renew.
+ @throws IOException if an IO error occurred.
+ @throws AuthenticationException if an authentication exception occurred.]]>
+
+
+
+
+
+
+
+
+
+
+ Authenticator for authentication.
+
+ @param url the URL to renew the delegation token from. Only HTTP/S URLs are
+ supported.
+ @param token the authentication token with the Delegation Token to renew.
+ @param doAsUser the user to do as, which will be the token owner.
+ @throws IOException if an IO error occurred.
+ @throws AuthenticationException if an authentication exception occurred.]]>
+
+
+
+
+
+
+
+
+ Authenticator.
+
+ @param url the URL to cancel the delegation token from. Only HTTP/S URLs
+ are supported.
+ @param token the authentication token with the Delegation Token to cancel.
+ @throws IOException if an IO error occurred.]]>
+
+
+
+
+
+
+
+
+
+ Authenticator.
+
+ @param url the URL to cancel the delegation token from. Only HTTP/S URLs
+ are supported.
+ @param token the authentication token with the Delegation Token to cancel.
+ @param doAsUser the user to do as, which will be the token owner.
+ @throws IOException if an IO error occurred.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ KerberosDelegationTokenAuthenticator provides support for
+ Kerberos SPNEGO authentication mechanism and support for Hadoop Delegation
+ Token operations.
+
+ It falls back to the {@link PseudoDelegationTokenAuthenticator} if the HTTP
+ endpoint does not trigger a SPNEGO authentication]]>
+
+
+
+
+
+
+
+
+ PseudoDelegationTokenAuthenticator provides support for
+ Hadoop's pseudo authentication mechanism that accepts
+ the user name specified as a query string parameter and support for Hadoop
+ Delegation Token operations.
+
+ This mimics the model of Hadoop Simple authentication trusting the
+ {@link UserGroupInformation#getCurrentUser()} value.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ live.
+ @return a (snapshotted) map of blocker name->description values]]>
+
+
+
+
+
+
+
+
+
+
+
+
+ Do nothing if the service is null or not
+ in a state in which it can be/needs to be stopped.
+
+ The service state is checked before the operation begins.
+ This process is not thread safe.
+ @param service a service or null]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Any long-lived operation here will prevent the service state
+ change from completing in a timely manner.
+
If another thread is somehow invoked from the listener, and
+ that thread invokes the methods of the service (including
+ subclass-specific methods), there is a risk of a deadlock.
+
+
+
+ @param service the service that has changed.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The base implementation logs all arguments at the debug level,
+ then returns the passed in config unchanged.]]>
+
+
+
+
+
+
+ The action is to signal success by returning the exit code 0.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This method is called before {@link #init(Configuration)};
+ Any non-null configuration that is returned from this operation
+ becomes the one that is passed on to that {@link #init(Configuration)}
+ operation.
+
+ This permits implementations to change the configuration before
+ the init operation. As the ServiceLauncher only creates
+ an instance of the base {@link Configuration} class, it is
+ recommended to instantiate any subclass (such as YarnConfiguration)
+ that injects new resources.
+
+ @param config the initial configuration build up by the
+ service launcher.
+ @param args list of arguments passed to the command line
+ after any launcher-specific commands have been stripped.
+ @return the configuration to init the service with.
+ Recommended: pass down the config parameter with any changes
+ @throws Exception any problem]]>
+
+
+
+
+
+
+ The return value becomes the exit code of the launched process.
+
+ If an exception is raised, the policy is:
+
+
Any subset of {@link org.apache.hadoop.util.ExitUtil.ExitException}:
+ the exception is passed up unmodified.
+
+
Any exception which implements
+ {@link org.apache.hadoop.util.ExitCodeProvider}:
+ A new {@link ServiceLaunchException} is created with the exit code
+ and message of the thrown exception; the thrown exception becomes the
+ cause.
+
Any other exception: a new {@link ServiceLaunchException} is created
+ with the exit code {@link LauncherExitCodes#EXIT_EXCEPTION_THROWN} and
+ the message of the original exception (which becomes the cause).
+
+ @return the exit code
+ @throws org.apache.hadoop.util.ExitUtil.ExitException an exception passed
+ up as the exit code and error text.
+ @throws Exception any exception to report. If it provides an exit code
+ this is used in a wrapping exception.]]>
+
+
+
+
+ The command line options will be passed down before the
+ {@link Service#init(Configuration)} operation is invoked via an
+ invocation of {@link LaunchableService#bindArgs(Configuration, List)}
+ After the service has been successfully started via {@link Service#start()}
+ the {@link LaunchableService#execute()} method is called to execute the
+ service. When this method returns, the service launcher will exit, using
+ the return code from the method as its exit option.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Approximate HTTP equivalent: {@code 400 Bad Request}]]>
+
+
+
+
+
+ approximate HTTP equivalent: Approximate HTTP equivalent: {@code 401 Unauthorized}]]>
+
+
+
+
+
+
+
+
+
+
+ Approximate HTTP equivalent: Approximate HTTP equivalent: {@code 403: Forbidden}]]>
+
+
+
+
+
+ Approximate HTTP equivalent: {@code 404: Not Found}]]>
+
+
+
+
+
+ Approximate HTTP equivalent: {@code 405: Not allowed}]]>
+
+
+
+
+
+ Approximate HTTP equivalent: {@code 406: Not Acceptable}]]>
+
+
+
+
+
+ Approximate HTTP equivalent: {@code 408: Request Timeout}]]>
+
+
+
+
+
+ Approximate HTTP equivalent: {@code 409: Conflict}]]>
+
+
+
+
+
+ Approximate HTTP equivalent: {@code 500 Internal Server Error}]]>
+
+
+
+
+
+ Approximate HTTP equivalent: {@code 501: Not Implemented}]]>
+
+
+
+
+
+ Approximate HTTP equivalent: {@code 503 Service Unavailable}]]>
+
+
+
+
+
+ If raised, this is expected to be raised server-side and likely due
+ to client/server version incompatibilities.
+
+ Approximate HTTP equivalent: {@code 505: Version Not Supported}]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Codes with a YARN prefix are YARN-related.
+
+ Many of the exit codes are designed to resemble HTTP error codes,
+ squashed into a single byte. e.g 44 , "not found" is the equivalent
+ of 404. The various 2XX HTTP error codes aren't followed;
+ the Unix standard of "0" for success is used.
+
+ 0-10: general command issues
+ 30-39: equivalent to the 3XX responses, where those responses are
+ considered errors by the application.
+ 40-49: client-side/CLI/config problems
+ 50-59: service-side problems.
+ 60+ : application specific error codes
+
]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This uses {@link String#format(String, Object...)}
+ to build the formatted exception in the ENGLISH locale.
+
+ If the last argument is a throwable, it becomes the cause of the exception.
+ It will also be used as a parameter for the format.
+ @param exitCode exit code
+ @param format format for message to use in exception
+ @param args list of arguments]]>
+
+
+
+
+ When caught by the ServiceLauncher, it will convert that
+ into a process exit code.
+
+ The {@link #ServiceLaunchException(int, String, Object...)} constructor
+ generates formatted exceptions.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Clients and/or applications can use the provided Progressable
+ to explicitly report progress to the Hadoop framework. This is especially
+ important for operations which take significant amount of time since,
+ in-lieu of the reported progress, the framework has to assume that an error
+ has occured and time-out the operation.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Class is to be obtained
+ @return the correctly typed Class of the given object.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ kill -0 command or equivalent]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ".cmd" on Windows, or ".sh" otherwise.
+
+ @param parent File parent directory
+ @param basename String script file basename
+ @return File referencing the script in the directory]]>
+
+
+
+
+
+ ".cmd" on Windows, or ".sh" otherwise.
+
+ @param basename String script file basename
+ @return String script file name]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IOException.
+ @return the path to {@link #WINUTILS_EXE}
+ @throws RuntimeException if the path is not resolvable]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Shell.
+ @return the thread that ran runCommand() that spawned this shell
+ or null if no thread is waiting for this shell to complete]]>
+
+
+
+
+
+
+
+
+
+
+
+ Shell interface.
+ @param cmd shell command to execute.
+ @return the output of the executed command.]]>
+
+
+
+
+
+
+
+
+ Shell interface.
+ @param env the map of environment key=value
+ @param cmd shell command to execute.
+ @param timeout time in milliseconds after which script should be marked timeout
+ @return the output of the executed command.
+ @throws IOException on any problem.]]>
+
+
+
+
+
+
+
+ Shell interface.
+ @param env the map of environment key=value
+ @param cmd shell command to execute.
+ @return the output of the executed command.
+ @throws IOException on any problem.]]>
+
+
+
+
+ Shell processes.
+ Iterates through a map of all currently running Shell
+ processes and destroys them one by one. This method is thread safe]]>
+
+
+
+
+ Shell objects.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CreateProcess synchronization object.]]>
+
+
+
+
+ os.name property.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Important: caller must check for this value being null.
+ The lack of such checks has led to many support issues being raised.
+
+ @deprecated use one of the exception-raising getter methods,
+ specifically {@link #getWinUtilsPath()} or {@link #getWinUtilsFile()}]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Shell can be used to run shell commands like du or
+ df. It also offers facilities to gate commands by
+ time-intervals.]]>
+
+
+
+
+
+
+
+ ShutdownHookManager singleton.
+
+ @return ShutdownHookManager singleton.]]>
+
+
+
+
+
+
+ Runnable
+ @param priority priority of the shutdownHook.]]>
+
+
+
+
+
+
+
+
+ Runnable
+ @param priority priority of the shutdownHook
+ @param timeout timeout of the shutdownHook
+ @param unit unit of the timeout TimeUnit]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ShutdownHookManager enables running shutdownHook
+ in a deterministic order, higher priority first.
+
+ The JVM runs ShutdownHooks in a non-deterministic order or in parallel.
+ This class registers a single JVM shutdownHook and run all the
+ shutdownHooks registered to it (to this class) in order based on their
+ priority.
+
+ Unless a hook was registered with a shutdown explicitly set through
+ {@link #addShutdownHook(Runnable, int, long, TimeUnit)},
+ the shutdown time allocated to it is set by the configuration option
+ {@link CommonConfigurationKeysPublic#SERVICE_SHUTDOWN_TIMEOUT} in
+ {@code core-site.xml}, with a default value of
+ {@link CommonConfigurationKeysPublic#SERVICE_SHUTDOWN_TIMEOUT_DEFAULT}
+ seconds.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tool, is the standard for any Map-Reduce tool/application.
+ The tool/application should delegate the handling of
+
+ standard command-line options to {@link ToolRunner#run(Tool, String[])}
+ and only handle its custom arguments.
+
+
Here is how a typical Tool is implemented:
+
+ public class MyApp extends Configured implements Tool {
+
+ public int run(String[] args) throws Exception {
+ // Configuration processed by ToolRunner
+ Configuration conf = getConf();
+
+ // Create a JobConf using the processed conf
+ JobConf job = new JobConf(conf, MyApp.class);
+
+ // Process custom command-line options
+ Path in = new Path(args[1]);
+ Path out = new Path(args[2]);
+
+ // Specify various job-specific parameters
+ job.setJobName("my-app");
+ job.setInputPath(in);
+ job.setOutputPath(out);
+ job.setMapperClass(MyMapper.class);
+ job.setReducerClass(MyReducer.class);
+
+ // Submit the job, then poll for progress until the job is complete
+ RunningJob runningJob = JobClient.runJob(job);
+ if (runningJob.isSuccessful()) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ // Let ToolRunner handle generic command-line options
+ int res = ToolRunner.run(new Configuration(), new MyApp(), args);
+
+ System.exit(res);
+ }
+ }
+
+
+ @see GenericOptionsParser
+ @see ToolRunner]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tool by {@link Tool#run(String[])}, after
+ parsing with the given generic arguments. Uses the given
+ Configuration, or builds one if null.
+
+ Sets the Tool's configuration with the possibly modified
+ version of the conf.
+
+ @param conf Configuration for the Tool.
+ @param tool Tool to run.
+ @param args command-line arguments to the tool.
+ @return exit code of the {@link Tool#run(String[])} method.]]>
+
+
+
+
+
+
+
+ Tool with its Configuration.
+
+ Equivalent to run(tool.getConf(), tool, args).
+
+ @param tool Tool to run.
+ @param args command-line arguments to the tool.
+ @return exit code of the {@link Tool#run(String[])} method.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ToolRunner can be used to run classes implementing
+ Tool interface. It works in conjunction with
+ {@link GenericOptionsParser} to parse the
+
+ generic hadoop command line arguments and modifies the
+ Configuration of the Tool. The
+ application-specific options are passed along without being modified.
+
+
+ @see Tool
+ @see GenericOptionsParser]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ this filter.
+ @param nbHash The number of hash function to consider.
+ @param hashType type of the hashing function (see
+ {@link org.apache.hadoop.util.hash.Hash}).]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Bloom filter, as defined by Bloom in 1970.
+
+ The Bloom filter is a data structure that was introduced in 1970 and that has been adopted by
+ the networking research community in the past decade thanks to the bandwidth efficiencies that it
+ offers for the transmission of set membership information between networked hosts. A sender encodes
+ the information into a bit vector, the Bloom filter, that is more compact than a conventional
+ representation. Computation and space costs for construction are linear in the number of elements.
+ The receiver uses the filter to test whether various elements are members of the set. Though the
+ filter will occasionally return a false positive, it will never return a false negative. When creating
+ the filter, the sender can choose its desired point in a trade-off between the false positive rate and the size.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ this filter.
+ @param nbHash The number of hash function to consider.
+ @param hashType type of the hashing function (see
+ {@link org.apache.hadoop.util.hash.Hash}).]]>
+
+
+
+
+
+
+
+
+ this counting Bloom filter.
+
+ Invariant: nothing happens if the specified key does not belong to this counter Bloom filter.
+ @param key The key to remove.]]>
+
+
+
+
+
+
+
+
+
+
+
+ key -> count map.
+
NOTE: due to the bucket size of this filter, inserting the same
+ key more than 15 times will cause an overflow at all filter positions
+ associated with this key, and it will significantly increase the error
+ rate for this and other keys. For this reason the filter can only be
+ used to store small count values 0 <= N << 15.
+ @param key key to be tested
+ @return 0 if the key is not present. Otherwise, a positive value v will
+ be returned such that v == count with probability equal to the
+ error rate of this filter, and v > count otherwise.
+ Additionally, if the filter experienced an underflow as a result of
+ {@link #delete(Key)} operation, the return value may be lower than the
+ count with the probability of the false negative rate of such
+ filter.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ counting Bloom filter, as defined by Fan et al. in a ToN
+ 2000 paper.
+
+ A counting Bloom filter is an improvement to standard a Bloom filter as it
+ allows dynamic additions and deletions of set membership information. This
+ is achieved through the use of a counting vector instead of a bit vector.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Builds an empty Dynamic Bloom filter.
+ @param vectorSize The number of bits in the vector.
+ @param nbHash The number of hash function to consider.
+ @param hashType type of the hashing function (see
+ {@link org.apache.hadoop.util.hash.Hash}).
+ @param nr The threshold for the maximum number of keys to record in a
+ dynamic Bloom filter row.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ dynamic Bloom filter, as defined in the INFOCOM 2006 paper.
+
+ A dynamic Bloom filter (DBF) makes use of a s * m bit matrix but
+ each of the s rows is a standard Bloom filter. The creation
+ process of a DBF is iterative. At the start, the DBF is a 1 * m
+ bit matrix, i.e., it is composed of a single standard Bloom filter.
+ It assumes that nr elements are recorded in the
+ initial bit vector, where nr <= n (n is
+ the cardinality of the set A to record in the filter).
+
+ As the size of A grows during the execution of the application,
+ several keys must be inserted in the DBF. When inserting a key into the DBF,
+ one must first get an active Bloom filter in the matrix. A Bloom filter is
+ active when the number of recorded keys, nr, is
+ strictly less than the current cardinality of A, n.
+ If an active Bloom filter is found, the key is inserted and
+ nr is incremented by one. On the other hand, if there
+ is no active Bloom filter, a new one is created (i.e., a new row is added to
+ the matrix) according to the current size of A and the element
+ is added in this new Bloom filter and the nr value of
+ this new Bloom filter is set to one. A given key is said to belong to the
+ DBF if the k positions are set to one in one of the matrix rows.
+
+
+
+
+
+
+
+
+ Builds a hash function that must obey to a given maximum number of returned values and a highest value.
+ @param maxValue The maximum highest returned value.
+ @param nbHash The number of resulting hashed values.
+ @param hashType type of the hashing function (see {@link Hash}).]]>
+
+
+
+
+ this hash function. A NOOP]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The idea is to randomly select a bit to reset.]]>
+
+
+
+
+
+ The idea is to select the bit to reset that will generate the minimum
+ number of false negative.]]>
+
+
+
+
+
+ The idea is to select the bit to reset that will remove the maximum number
+ of false positive.]]>
+
+
+
+
+
+ The idea is to select the bit to reset that will, at the same time, remove
+ the maximum number of false positve while minimizing the amount of false
+ negative generated.]]>
+
+
+
+
+ Originally created by
+ European Commission One-Lab Project 034819.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ this filter.
+ @param nbHash The number of hash function to consider.
+ @param hashType type of the hashing function (see
+ {@link org.apache.hadoop.util.hash.Hash}).]]>
+
+
+
+
+
+
+
+
+ this retouched Bloom filter.
+
+ Invariant: if the false positive is null, nothing happens.
+ @param key The false positive key to add.]]>
+
+
+
+
+
+ this retouched Bloom filter.
+ @param coll The collection of false positive.]]>
+
+
+
+
+
+ this retouched Bloom filter.
+ @param keys The list of false positive.]]>
+
+
+
+
+
+ this retouched Bloom filter.
+ @param keys The array of false positive.]]>
+
+
+
+
+
+
+ this retouched Bloom filter.
+ @param scheme The selective clearing scheme to apply.]]>
+
+
+
+
+
+
+
+
+
+
+
+ retouched Bloom filter, as defined in the CoNEXT 2006 paper.
+
+ It allows the removal of selected false positives at the cost of introducing
+ random false negatives, and with the benefit of eliminating some random false
+ positives at the same time.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hadoop-common-project/hadoop-common/pom.xml b/hadoop-common-project/hadoop-common/pom.xml
index 10417eb910bf3..84d3ae5b5addc 100644
--- a/hadoop-common-project/hadoop-common/pom.xml
+++ b/hadoop-common-project/hadoop-common/pom.xml
@@ -15,7 +15,7 @@
+ https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0org.apache.hadoop
@@ -30,7 +30,6 @@
jar
- src/test/resources/kdccommontruetrue
@@ -161,6 +160,16 @@
junittest
+
+ org.assertj
+ assertj-core
+ test
+
+
+ org.glassfish.grizzly
+ grizzly-http-servlet
+ test
+ commons-beanutilscommons-beanutils
@@ -371,6 +380,20 @@
+
+ org.xolstice.maven.plugins
+ protobuf-maven-plugin
+
+
+ src-compile-protoc
+ false
+
+
+ src-test-compile-protoc
+ false
+
+
+ org.apache.hadoophadoop-maven-plugins
@@ -391,58 +414,6 @@
-
- compile-protoc
-
- protoc
-
-
- ${protobuf.version}
- ${protoc.path}
-
- ${basedir}/src/main/proto
-
-
- ${basedir}/src/main/proto
-
- HAServiceProtocol.proto
- IpcConnectionContext.proto
- ProtocolInfo.proto
- RpcHeader.proto
- ZKFCProtocol.proto
- ProtobufRpcEngine.proto
- Security.proto
- GetUserMappingsProtocol.proto
- TraceAdmin.proto
- RefreshAuthorizationPolicyProtocol.proto
- RefreshUserMappingsProtocol.proto
- RefreshCallQueueProtocol.proto
- GenericRefreshProtocol.proto
- FSProtos.proto
-
-
-
-
-
- compile-test-protoc
-
- test-protoc
-
-
- ${protobuf.version}
- ${protoc.path}
-
- ${basedir}/src/test/proto
-
-
- ${basedir}/src/test/proto
-
- test.proto
- test_rpc_service.proto
-
-
-
- resource-gzgenerate-resources
@@ -462,8 +433,6 @@
maven-surefire-plugin
- ${startKdc}
- ${kdc.resource.dir}${runningWithNative}
@@ -544,7 +513,6 @@
src/main/native/m4/*src/test/empty-filesrc/test/all-tests
- src/test/resources/kdc/ldif/users.ldifsrc/main/native/src/org/apache/hadoop/io/compress/lz4/lz4.hsrc/main/native/src/org/apache/hadoop/io/compress/lz4/lz4.csrc/main/native/src/org/apache/hadoop/io/compress/lz4/lz4hc.h
@@ -686,6 +654,8 @@
${require.isal} ${isal.prefix} ${isal.lib}
+ ${require.pmdk}
+ ${pmdk.lib}${require.openssl} ${openssl.prefix} ${openssl.lib}
@@ -743,7 +713,7 @@
- false
+ falsetrue
@@ -846,7 +816,7 @@
/p:CustomZstdPrefix=${zstd.prefix}/p:CustomZstdLib=${zstd.lib}/p:CustomZstdInclude=${zstd.include}
- /p:RequireZstd=${require.ztsd}
+ /p:RequireZstd=${require.zstd}/p:CustomOpensslPrefix=${openssl.prefix}/p:CustomOpensslLib=${openssl.lib}/p:CustomOpensslInclude=${openssl.include}
@@ -862,87 +832,6 @@
-
-
-
- startKdc
-
-
- startKdc
- true
-
-
-
-
-
- org.apache.maven.plugins
- maven-enforcer-plugin
-
-
- enforce-os
-
- enforce
-
-
-
-
-
- mac
- unix
-
-
- true
-
-
-
-
-
- org.apache.maven.plugins
- maven-antrun-plugin
-
-
- kdc
- compile
-
- run
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- killKdc
- test
-
- run
-
-
-
-
-
-
-
-
-
-
-
-
- parallel-tests
diff --git a/hadoop-common-project/hadoop-common/src/CMakeLists.txt b/hadoop-common-project/hadoop-common/src/CMakeLists.txt
index b9287c0f4b5ad..10591f6ce2aa8 100644
--- a/hadoop-common-project/hadoop-common/src/CMakeLists.txt
+++ b/hadoop-common-project/hadoop-common/src/CMakeLists.txt
@@ -121,6 +121,7 @@ else ()
ENDIF(REQUIRE_ZSTD)
endif ()
+#Require ISA-L
set(STORED_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
hadoop_set_find_shared_library_version("2")
find_library(ISAL_LIBRARY
@@ -159,6 +160,25 @@ else (ISAL_LIBRARY)
ENDIF(REQUIRE_ISAL)
endif (ISAL_LIBRARY)
+# Build with PMDK library if -Drequire.pmdk option is specified.
+if(REQUIRE_PMDK)
+ set(STORED_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ hadoop_set_find_shared_library_version("1")
+ find_library(PMDK_LIBRARY
+ NAMES pmem
+ PATHS ${CUSTOM_PMDK_LIB} /usr/lib /usr/lib64)
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ${STORED_CMAKE_FIND_LIBRARY_SUFFIXES})
+
+ if(PMDK_LIBRARY)
+ GET_FILENAME_COMPONENT(HADOOP_PMDK_LIBRARY ${PMDK_LIBRARY} REALPATH)
+ set(PMDK_SOURCE_FILES ${SRC}/io/nativeio/pmdk_load.c)
+ else(PMDK_LIBRARY)
+ MESSAGE(FATAL_ERROR "The required PMDK library is NOT found. PMDK_LIBRARY=${PMDK_LIBRARY}")
+ endif(PMDK_LIBRARY)
+else(REQUIRE_PMDK)
+ MESSAGE(STATUS "Build without PMDK support.")
+endif(REQUIRE_PMDK)
+
# Build hardware CRC32 acceleration, if supported on the platform.
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^i.86$" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "amd64")
set(BULK_CRC_ARCH_SOURCE_FIlE "${SRC}/util/bulk_crc32_x86.c")
@@ -256,6 +276,7 @@ hadoop_add_dual_library(hadoop
${SRC}/io/compress/zlib/ZlibDecompressor.c
${BZIP2_SOURCE_FILES}
${SRC}/io/nativeio/NativeIO.c
+ ${PMDK_SOURCE_FILES}
${SRC}/io/nativeio/errno_enum.c
${SRC}/io/nativeio/file_descriptor.c
${SRC}/io/nativeio/SharedFileDescriptorFactory.c
diff --git a/hadoop-common-project/hadoop-common/src/config.h.cmake b/hadoop-common-project/hadoop-common/src/config.h.cmake
index 40aa467373c8d..7e23a5df3281c 100644
--- a/hadoop-common-project/hadoop-common/src/config.h.cmake
+++ b/hadoop-common-project/hadoop-common/src/config.h.cmake
@@ -24,6 +24,7 @@
#cmakedefine HADOOP_ZSTD_LIBRARY "@HADOOP_ZSTD_LIBRARY@"
#cmakedefine HADOOP_OPENSSL_LIBRARY "@HADOOP_OPENSSL_LIBRARY@"
#cmakedefine HADOOP_ISAL_LIBRARY "@HADOOP_ISAL_LIBRARY@"
+#cmakedefine HADOOP_PMDK_LIBRARY "@HADOOP_PMDK_LIBRARY@"
#cmakedefine HAVE_SYNC_FILE_RANGE
#cmakedefine HAVE_POSIX_FADVISE
diff --git a/hadoop-common-project/hadoop-common/src/main/bin/hadoop b/hadoop-common-project/hadoop-common/src/main/bin/hadoop
index 750dca31457a2..7d9ffc69bc503 100755
--- a/hadoop-common-project/hadoop-common/src/main/bin/hadoop
+++ b/hadoop-common-project/hadoop-common/src/main/bin/hadoop
@@ -140,6 +140,10 @@ function hadoopcmd_case
if [[ -n "${YARN_OPTS}" ]] || [[ -n "${YARN_CLIENT_OPTS}" ]]; then
hadoop_error "WARNING: Use \"yarn jar\" to launch YARN applications."
fi
+ if [[ -z $1 || $1 = "--help" ]]; then
+ echo "Usage: hadoop jar [mainClass] args..."
+ exit 0
+ fi
HADOOP_CLASSNAME=org.apache.hadoop.util.RunJar
;;
jnipath)
diff --git a/hadoop-common-project/hadoop-common/src/main/bin/hadoop.cmd b/hadoop-common-project/hadoop-common/src/main/bin/hadoop.cmd
index 91c65d1f2d6f2..04e5039d19812 100644
--- a/hadoop-common-project/hadoop-common/src/main/bin/hadoop.cmd
+++ b/hadoop-common-project/hadoop-common/src/main/bin/hadoop.cmd
@@ -189,6 +189,11 @@ call :updatepath %HADOOP_BIN_PATH%
) else if defined YARN_CLIENT_OPTS (
@echo WARNING: Use "yarn jar" to launch YARN applications.
)
+ @rem if --help option is used, no need to call command
+ if [!hadoop-command-arguments[%1%]!]==["--help"] (
+ @echo Usage: hadoop jar [mainClass] args...
+ goto :eof
+ )
set CLASS=org.apache.hadoop.util.RunJar
goto :eof
diff --git a/hadoop-common-project/hadoop-common/src/main/conf/hadoop-policy.xml b/hadoop-common-project/hadoop-common/src/main/conf/hadoop-policy.xml
index bd7c11124f5b3..e1640f97546ac 100644
--- a/hadoop-common-project/hadoop-common/src/main/conf/hadoop-policy.xml
+++ b/hadoop-common-project/hadoop-common/src/main/conf/hadoop-policy.xml
@@ -109,6 +109,16 @@
active and stand-by states of namenode.
+
+ security.router.admin.protocol.acl
+ *
+ ACL for RouterAdmin Protocol. The ACL is a comma-separated
+ list of user and group names. The user and
+ group list is separated by a blank. For e.g. "alice,bob users,wheel".
+ A special value of "*" means all users are allowed.
+
+
+
security.zkfc.protocol.acl*
diff --git a/hadoop-common-project/hadoop-common/src/main/conf/log4j.properties b/hadoop-common-project/hadoop-common/src/main/conf/log4j.properties
index 246a9d12d6715..7f9ea462679b3 100644
--- a/hadoop-common-project/hadoop-common/src/main/conf/log4j.properties
+++ b/hadoop-common-project/hadoop-common/src/main/conf/log4j.properties
@@ -216,6 +216,36 @@ log4j.appender.RMSUMMARY.MaxBackupIndex=20
log4j.appender.RMSUMMARY.layout=org.apache.log4j.PatternLayout
log4j.appender.RMSUMMARY.layout.ConversionPattern=%d{ISO8601} %p %c{2}: %m%n
+#
+# YARN ResourceManager audit logging
+#
+rm.audit.logger=INFO,NullAppender
+rm.audit.log.maxfilesize=256MB
+rm.audit.log.maxbackupindex=20
+log4j.logger.org.apache.hadoop.yarn.server.resourcemanager.RMAuditLogger=${rm.audit.logger}
+log4j.additivity.org.apache.hadoop.yarn.server.resourcemanager.RMAuditLogger=false
+log4j.appender.RMAUDIT=org.apache.log4j.RollingFileAppender
+log4j.appender.RMAUDIT.File=${hadoop.log.dir}/rm-audit.log
+log4j.appender.RMAUDIT.layout=org.apache.log4j.PatternLayout
+log4j.appender.RMAUDIT.layout.ConversionPattern=%d{ISO8601} %p %c{2}: %m%n
+log4j.appender.RMAUDIT.MaxFileSize=${rm.audit.log.maxfilesize}
+log4j.appender.RMAUDIT.MaxBackupIndex=${rm.audit.log.maxbackupindex}
+
+#
+# YARN NodeManager audit logging
+#
+nm.audit.logger=INFO,NullAppender
+nm.audit.log.maxfilesize=256MB
+nm.audit.log.maxbackupindex=20
+log4j.logger.org.apache.hadoop.yarn.server.nodemanager.NMAuditLogger=${nm.audit.logger}
+log4j.additivity.org.apache.hadoop.yarn.server.nodemanager.NMAuditLogger=false
+log4j.appender.NMAUDIT=org.apache.log4j.RollingFileAppender
+log4j.appender.NMAUDIT.File=${hadoop.log.dir}/nm-audit.log
+log4j.appender.NMAUDIT.layout=org.apache.log4j.PatternLayout
+log4j.appender.NMAUDIT.layout.ConversionPattern=%d{ISO8601}%p %c{2}: %m%n
+log4j.appender.NMAUDIT.MaxFileSize=${nm.audit.log.maxfilesize}
+log4j.appender.NMAUDIT.MaxBackupIndex=${nm.audit.log.maxbackupindex}
+
# HS audit log configs
#mapreduce.hs.audit.logger=INFO,HSAUDIT
#log4j.logger.org.apache.hadoop.mapreduce.v2.hs.HSAuditLogger=${mapreduce.hs.audit.logger}
diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/conf/Configuration.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/conf/Configuration.java
old mode 100644
new mode 100755
index c30ce0db84e22..180bde26574ca
--- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/conf/Configuration.java
+++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/conf/Configuration.java
@@ -1885,8 +1885,6 @@ private long getTimeDurationHelper(String name, String vStr,
vStr = StringUtils.toLowerCase(vStr);
ParsedTimeDuration vUnit = ParsedTimeDuration.unitFor(vStr);
if (null == vUnit) {
- logDeprecation("No unit for " + name + "(" + vStr + ") assuming " +
- defaultUnit);
vUnit = ParsedTimeDuration.unitFor(defaultUnit);
} else {
vStr = vStr.substring(0, vStr.lastIndexOf(vUnit.suffix()));
@@ -3436,8 +3434,10 @@ private void readTagFromConfig(String attributeValue, String confName, String
}
private void overlay(Properties to, Properties from) {
- for (Entry
@@ -1213,8 +1213,12 @@
fs.s3a.connection.maximum
- 15
- Controls the maximum number of simultaneous connections to S3.
+ 48
+ Controls the maximum number of simultaneous connections to S3.
+ This must be bigger than the value of fs.s3a.threads.max so as to stop
+ threads being blocked waiting for new HTTPS connections.
+ Why not equal? The AWS SDK transfer manager also uses these connections.
+
@@ -1312,7 +1316,7 @@
fs.s3a.threads.max
- 10
+ 64The total number of threads available in the filesystem for data
uploads *or any other queued filesystem operation*.
@@ -1326,13 +1330,30 @@
fs.s3a.max.total.tasks
- 5
- The number of operations which can be queued for execution
+ 32
+ The number of operations which can be queued for execution.
+ This is in addition to the number of active threads in fs.s3a.threads.max.
+
+
+
+
+ fs.s3a.executor.capacity
+ 16
+ The maximum number of submitted tasks which is a single
+ operation (e.g. rename(), delete()) may submit simultaneously for
+ execution -excluding the IO-heavy block uploads, whose capacity
+ is set in "fs.s3a.fast.upload.active.blocks"
+
+ All tasks are submitted to the shared thread pool whose size is
+ set in "fs.s3a.threads.max"; the value of capacity should be less than that
+ of the thread pool itself, as the goal is to stop a single operation
+ from overloading that thread pool.
+ fs.s3a.multipart.size
- 100M
+ 64MHow big (in bytes) to split upload or copy operations up into.
A suffix from the set {K,M,G,T,P} may be used to scale the numeric value.
@@ -1340,7 +1361,7 @@
fs.s3a.multipart.threshold
- 2147483647
+ 128MHow big (in bytes) to split upload or copy operations up into.
This also controls the partition size in renamed files, as rename() involves
copying the source file(s).
@@ -1502,12 +1523,10 @@
- fs.s3a.metadatastore.authoritative.dir.ttl
- 3600000
+ fs.s3a.metadatastore.metadata.ttl
+ 15m
- This value sets how long a directory listing in the MS is considered as
- authoritative. The value is in milliseconds.
- MetadataStore should be authoritative to use this configuration knob.
+ This value sets how long an entry in a MetadataStore is valid.
@@ -1581,23 +1600,27 @@
fs.s3a.s3guard.ddb.table.capacity.read
- 500
+ 0
Provisioned throughput requirements for read operations in terms of capacity
- units for the DynamoDB table. This config value will only be used when
- creating a new DynamoDB table, though later you can manually provision by
- increasing or decreasing read capacity as needed for existing tables.
- See DynamoDB documents for more information.
+ units for the DynamoDB table. This config value will only be used when
+ creating a new DynamoDB table.
+ If set to 0 (the default), new tables are created with "per-request" capacity.
+ If a positive integer is provided for this and the write capacity, then
+ a table with "provisioned capacity" will be created.
+ You can change the capacity of an existing provisioned-capacity table
+ through the "s3guard set-capacity" command.
fs.s3a.s3guard.ddb.table.capacity.write
- 100
+ 0
Provisioned throughput requirements for write operations in terms of
- capacity units for the DynamoDB table. Refer to related config
- fs.s3a.s3guard.ddb.table.capacity.read before usage.
+ capacity units for the DynamoDB table.
+ If set to 0 (the default), new tables are created with "per-request" capacity.
+ Refer to related configuration option fs.s3a.s3guard.ddb.table.capacity.read
@@ -1637,10 +1660,10 @@
fs.s3a.retry.limit
- ${fs.s3a.attempts.maximum}
+ 7
Number of times to retry any repeatable S3 client request on failure,
- excluding throttling requests.
+ excluding throttling requests and S3Guard inconsistency resolution.
@@ -1648,8 +1671,8 @@
fs.s3a.retry.interval500ms
- Interval between attempts to retry operations for any reason other
- than S3 throttle errors.
+ Initial retry interval when retrying operations for any reason other
+ than S3 throttle errors and S3Guard inconsistency resolution.
@@ -1669,6 +1692,27 @@
+
+ fs.s3a.s3guard.consistency.retry.limit
+ 7
+
+ Number of times to retry attempts to read/open/copy files when
+ S3Guard believes a specific version of the file to be available,
+ but the S3 request does not find any version of a file, or a different
+ version.
+
+
+
+
+ fs.s3a.s3guard.consistency.retry.interval
+ 2s
+
+ Initial interval between attempts to retry operations while waiting for S3
+ to become consistent with the S3Guard data.
+ An exponential back-off is used here: every failure doubles the delay.
+
+
+
fs.s3a.committer.namefile
@@ -1724,7 +1768,7 @@
fs.s3a.committer.staging.conflict-mode
- fail
+ append
Staging committer conflict resolution policy.
Supported: "fail", "append", "replace".
@@ -1929,6 +1973,20 @@
+
+ fs.s3a.ssl.channel.mode
+ default_jsse
+
+ If secure connections to S3 are enabled, configures the SSL
+ implementation used to encrypt connections to S3. Supported values are:
+ "default_jsse" and "default_jsse_with_gcm". "default_jsse" uses the Java
+ Secure Socket Extension package (JSSE). However, when running on Java 8,
+ the GCM cipher is removed from the list of enabled ciphers. This is due
+ to performance issues with GCM in Java 8. "default_jsse_with_gcm" uses
+ the JSSE with the default list of cipher suites.
+
+
+
fs.AbstractFileSystem.wasb.impl
@@ -2173,7 +2231,7 @@
ipc.server.listen.queue.size
- 128
+ 256Indicates the length of the listen queue for servers accepting
client connections.
@@ -2190,7 +2248,7 @@
ipc.maximum.data.length
- 67108864
+ 134217728This indicates the maximum IPC message length (bytes) that can be
accepted by the server. Messages larger than this value are rejected by the
immediately to avoid possible OOMs. This setting should rarely need to be
@@ -2216,6 +2274,193 @@
because the server side is stuck in TIME_WAIT state.
+
+
+
+
+
+
+
+
+
+
+
+
+ ipc.[port_number].backoff.enable
+ false
+ Whether or not to enable client backoff when a queue is full.
+
+
+
+
+ ipc.[port_number].callqueue.impl
+ java.util.concurrent.LinkedBlockingQueue
+ The fully qualified name of a class to use as the implementation
+ of a call queue. The default implementation is
+ java.util.concurrent.LinkedBlockingQueue (FIFO queue).
+ Use org.apache.hadoop.ipc.FairCallQueue for the Fair Call Queue.
+
+
+
+
+ ipc.[port_number].scheduler.impl
+ org.apache.hadoop.ipc.DefaultRpcScheduler
+ The fully qualified name of a class to use as the
+ implementation of the scheduler. The default implementation is
+ org.apache.hadoop.ipc.DefaultRpcScheduler (no-op scheduler) when not using
+ FairCallQueue. If using FairCallQueue, defaults to
+ org.apache.hadoop.ipc.DecayRpcScheduler. Use
+ org.apache.hadoop.ipc.DecayRpcScheduler in conjunction with the Fair Call
+ Queue.
+
+
+
+
+ ipc.[port_number].scheduler.priority.levels
+ 4
+ How many priority levels to use within the scheduler and call
+ queue. This property applies to RpcScheduler and CallQueue.
+
+
+
+
+ ipc.[port_number].faircallqueue.multiplexer.weights
+ 8,4,2,1
+ How much weight to give to each priority queue. This should be
+ a comma-separated list of length equal to the number of priority levels.
+ Weights descend by a factor of 2 (e.g., for 4 levels: 8,4,2,1).
+ This property applies to WeightedRoundRobinMultiplexer.
+
+
+
+
+ ipc.[port_number].identity-provider.impl
+ org.apache.hadoop.ipc.UserIdentityProvider
+ The identity provider mapping user requests to their identity.
+ This property applies to DecayRpcScheduler.
+
+
+
+
+ ipc.[port_number].cost-provider.impl
+ org.apache.hadoop.ipc.DefaultCostProvider
+ The cost provider mapping user requests to their cost. To
+ enable determination of cost based on processing time, use
+ org.apache.hadoop.ipc.WeightedTimeCostProvider.
+ This property applies to DecayRpcScheduler.
+
+
+
+
+ ipc.[port_number].decay-scheduler.period-ms
+ 5000
+ How frequently the decay factor should be applied to the
+ operation counts of users. Higher values have less overhead, but respond
+ less quickly to changes in client behavior.
+ This property applies to DecayRpcScheduler.
+
+
+
+
+ ipc.[port_number].decay-scheduler.decay-factor
+ 0.5
+ When decaying the operation counts of users, the multiplicative
+ decay factor to apply. Higher values will weight older operations more
+ strongly, essentially giving the scheduler a longer memory, and penalizing
+ heavy clients for a longer period of time.
+ This property applies to DecayRpcScheduler.
+
+
+
+
+ ipc.[port_number].decay-scheduler.thresholds
+ 13,25,50
+ The client load threshold, as an integer percentage, for each
+ priority queue. Clients producing less load, as a percent of total
+ operations, than specified at position i will be given priority i. This
+ should be a comma-separated list of length equal to the number of priority
+ levels minus 1 (the last is implicitly 100).
+ Thresholds ascend by a factor of 2 (e.g., for 4 levels: 13,25,50).
+ This property applies to DecayRpcScheduler.
+
+
+
+
+ ipc.[port_number].decay-scheduler.backoff.responsetime.enable
+ false
+ Whether or not to enable the backoff by response time feature.
+ This property applies to DecayRpcScheduler.
+
+
+
+
+ ipc.[port_number].decay-scheduler.backoff.responsetime.thresholds
+ 10s,20s,30s,40s
+ The response time thresholds, as time durations, for each
+ priority queue. If the average response time for a queue is above this
+ threshold, backoff will occur in lower priority queues. This should be a
+ comma-separated list of length equal to the number of priority levels.
+ Threshold increases by 10s per level (e.g., for 4 levels: 10s,20s,30s,40s)
+ This property applies to DecayRpcScheduler.
+
+
+
+
+ ipc.[port_number].decay-scheduler.metrics.top.user.count
+ 10
+ The number of top (i.e., heaviest) users to emit metric
+ information about. This property applies to DecayRpcScheduler.
+
+
+
+
+ ipc.[port_number].weighted-cost.lockshared
+ 10
+ The weight multiplier to apply to the time spent in the
+ processing phase which holds a shared (read) lock.
+ This property applies to WeightedTimeCostProvider.
+
+
+
+
+ ipc.[port_number].weighted-cost.lockexclusive
+ 100
+ The weight multiplier to apply to the time spent in the
+ processing phase which holds an exclusive (write) lock.
+ This property applies to WeightedTimeCostProvider.
+
+
+
+
+ ipc.[port_number].weighted-cost.handler
+ 1
+ The weight multiplier to apply to the time spent in the
+ HANDLER phase which do not involve holding a lock.
+ See org.apache.hadoop.ipc.ProcessingDetails.Timing for more details on
+ this phase. This property applies to WeightedTimeCostProvider.
+
+
+
+
+ ipc.[port_number].weighted-cost.lockfree
+ 1
+ The weight multiplier to apply to the time spent in the
+ LOCKFREE phase which do not involve holding a lock.
+ See org.apache.hadoop.ipc.ProcessingDetails.Timing for more details on
+ this phase. This property applies to WeightedTimeCostProvider.
+
+
+
+
+ ipc.[port_number].weighted-cost.response
+ 1
+ The weight multiplier to apply to the time spent in the
+ RESPONSE phase which do not involve holding a lock.
+ See org.apache.hadoop.ipc.ProcessingDetails.Timing for more details on
+ this phase. This property applies to WeightedTimeCostProvider.
+
+
+
@@ -2472,6 +2717,19 @@
+
+ hadoop.http.authentication.kerberos.endpoint.whitelist
+
+
+ The comma-separated list of the endpoints that skips Kerberos
+ authentication. The endpoint must start with '/' and must not
+ contain special characters afterwards. This parameter is for
+ the monitoring tools that do not support Kerberos authentication.
+ Administrator must configure this parameter very carefully
+ because it allows unauthenticated access to the daemons.
+
+
+
hadoop.http.cross-origin.enabled
@@ -2667,9 +2925,9 @@
hadoop.ssl.enabled.protocols
- TLSv1.1,TLSv1.2
+ TLSv1.2
- The supported SSL protocols. The parameter will only used from
+ The supported SSL protocols. The parameter will only be used from
DatanodeHttpServer.
@@ -2719,6 +2977,15 @@
+
+ ha.health-monitor.rpc.connect.max.retries
+ 1
+
+ The number of retries on connect error when establishing RPC proxy
+ connection to NameNode, used for monitorHealth() calls.
+
+
+
ha.health-monitor.rpc-timeout.ms45000
@@ -3328,6 +3595,20 @@
+
+ adl.ssl.channel.mode
+
+
+ Valid inputs are OpenSSL, Default_JSE and Default (case insensitive).
+ If config is missing or is invalid, SSL Channel mode will be set to Default.
+
+ When OpenSSL, SSL socket connections are created in OpenSSL mode.
+ When Default_JSE, SSL socket connections are created in the default JSE mode.
+ When Default, SSL socket connections are attempted with OpenSSL
+ and will fallback to Default_JSE mode if OpenSSL is not available at runtime.
+
+
+
@@ -3457,4 +3738,48 @@
with the input domain name of the services by querying the underlying DNS.
+
+
+ dfs.client.ignore.namenode.default.kms.uri
+ false
+
+ Ignore KMS default URI returned from NameNode.
+ When set to true, kms uri is searched in the following order:
+ 1. If there is a mapping in Credential's secrets map for namenode uri.
+ 2. Fallback to local conf. (i.e hadoop.security.key.provider.path)
+ If client choose to ignore KMS uri provided by NameNode then client
+ should set KMS URI using 'hadoop.security.key.provider.path' to access
+ the right KMS for encrypted files.
+
+
+
+
+ hadoop.prometheus.endpoint.enabled
+ false
+
+ If set to true, prometheus compatible metric page on the HTTP servers
+ is enabled via '/prom' endpoint.
+
+
+
+
+ fs.getspaceused.classname
+
+
+ The class that can tell estimate much space is used in a directory.
+ There are four impl classes that being supported:
+ org.apache.hadoop.fs.DU(default), org.apache.hadoop.fs.WindowsGetSpaceUsed
+ org.apache.hadoop.fs.DFCachingGetSpaceUsed and
+ org.apache.hadoop.hdfs.server.datanode.fsdataset.impl.ReplicaCachingGetSpaceUsed.
+ And the ReplicaCachingGetSpaceUsed impl class only used in HDFS module.
+
+
+
+
+ fs.getspaceused.jitterMillis
+ 60000
+
+ fs space usage statistics refresh jitter in msec.
+
+
diff --git a/hadoop-common-project/hadoop-common/src/site/markdown/CommandsManual.md b/hadoop-common-project/hadoop-common/src/site/markdown/CommandsManual.md
index f39a92d9e31af..0bda253fc8b54 100644
--- a/hadoop-common-project/hadoop-common/src/site/markdown/CommandsManual.md
+++ b/hadoop-common-project/hadoop-common/src/site/markdown/CommandsManual.md
@@ -125,6 +125,7 @@ Usage: `hadoop credential [options]`
| create *alias* [-provider *provider-path*] [-strict] [-value *credential-value*] | Prompts the user for a credential to be stored as the given alias. The *hadoop.security.credential.provider.path* within the core-site.xml file will be used unless a `-provider` is indicated. The `-strict` flag will cause the command to fail if the provider uses a default password. Use `-value` flag to supply the credential value (a.k.a. the alias password) instead of being prompted. |
| delete *alias* [-provider *provider-path*] [-strict] [-f] | Deletes the credential with the provided alias. The *hadoop.security.credential.provider.path* within the core-site.xml file will be used unless a `-provider` is indicated. The `-strict` flag will cause the command to fail if the provider uses a default password. The command asks for confirmation unless `-f` is specified |
| list [-provider *provider-path*] [-strict] | Lists all of the credential aliases The *hadoop.security.credential.provider.path* within the core-site.xml file will be used unless a `-provider` is indicated. The `-strict` flag will cause the command to fail if the provider uses a default password. |
+| check *alias* [-provider *provider-path*] [-strict] | Check the password for the given alias. The *hadoop.security.credential.provider.path* within the core-site.xml file will be used unless a `-provider` is indicated. The `-strict` flag will cause the command to fail if the provider uses a default password. |
Command to manage credentials, passwords and secrets within credential providers.
@@ -221,6 +222,8 @@ Usage: `hadoop key [options]`
| roll *keyname* [-provider *provider*] [-strict] [-help] | Creates a new version for the specified key within the provider indicated using the `-provider` argument. The `-strict` flag will cause the command to fail if the provider uses a default password. |
| delete *keyname* [-provider *provider*] [-strict] [-f] [-help] | Deletes all versions of the key specified by the *keyname* argument from within the provider specified by `-provider`. The `-strict` flag will cause the command to fail if the provider uses a default password. The command asks for user confirmation unless `-f` is specified. |
| list [-provider *provider*] [-strict] [-metadata] [-help] | Displays the keynames contained within a particular provider as configured in core-site.xml or specified with the `-provider` argument. The `-strict` flag will cause the command to fail if the provider uses a default password. `-metadata` displays the metadata. |
+| check *keyname* [-provider *provider*] [-strict] [-help] | Check password of the *keyname* contained within a particular provider as configured in core-site.xml or specified with the `-provider` argument. The `-strict` flag will cause the command to fail if the provider uses a default password. |
+
| -help | Prints usage of this command |
Manage keys via the KeyProvider. For details on KeyProviders, see the [Transparent Encryption Guide](../hadoop-hdfs/TransparentEncryption.html).
diff --git a/hadoop-common-project/hadoop-common/src/site/markdown/DeprecatedProperties.md b/hadoop-common-project/hadoop-common/src/site/markdown/DeprecatedProperties.md
index 8ec7c14343865..281e42dad887f 100644
--- a/hadoop-common-project/hadoop-common/src/site/markdown/DeprecatedProperties.md
+++ b/hadoop-common-project/hadoop-common/src/site/markdown/DeprecatedProperties.md
@@ -65,7 +65,6 @@ The following table lists the configuration property names that are deprecated i
| fs.s3a.server-side-encryption-key | fs.s3a.server-side-encryption.key |
| hadoop.configured.node.mapping | net.topology.configured.node.mapping |
| hadoop.native.lib | io.native.lib.available |
-| hadoop.net.static.resolutions | mapreduce.tasktracker.net.static.resolutions |
| hadoop.pipes.command-file.keep | mapreduce.pipes.commandfile.preserve |
| hadoop.pipes.executable.interpretor | mapreduce.pipes.executable.interpretor |
| hadoop.pipes.executable | mapreduce.pipes.executable |
@@ -75,6 +74,10 @@ The following table lists the configuration property names that are deprecated i
| hadoop.pipes.java.reducer | mapreduce.pipes.isjavareducer |
| hadoop.pipes.partitioner | mapreduce.pipes.partitioner |
| heartbeat.recheck.interval | dfs.namenode.heartbeat.recheck-interval |
+| httpfs.authentication.kerberos.keytab | hadoop.http.authentication.kerberos.keytab |
+| httpfs.authentication.kerberos.principal | hadoop.http.authentication.kerberos.principal |
+| httpfs.authentication.signature.secret.file | hadoop.http.authentication.signature.secret.file |
+| httpfs.authentication.type | hadoop.http.authentication.type |
| io.bytes.per.checksum | dfs.bytes-per-checksum |
| io.sort.factor | mapreduce.task.io.sort.factor |
| io.sort.mb | mapreduce.task.io.sort.mb |
@@ -89,7 +92,6 @@ The following table lists the configuration property names that are deprecated i
| keep.failed.task.files | mapreduce.task.files.preserve.failedtasks |
| keep.task.files.pattern | mapreduce.task.files.preserve.filepattern |
| key.value.separator.in.input.line | mapreduce.input.keyvaluelinerecordreader.key.value.separator |
-| local.cache.size | mapreduce.tasktracker.cache.local.size |
| map.input.file | mapreduce.map.input.file |
| map.input.length | mapreduce.map.input.length |
| map.input.start | mapreduce.map.input.start |
@@ -113,10 +115,6 @@ The following table lists the configuration property names that are deprecated i
| mapred.compress.map.output | mapreduce.map.output.compress |
| mapred.data.field.separator | mapreduce.fieldsel.data.field.separator |
| mapred.debug.out.lines | mapreduce.task.debugout.lines |
-| mapred.healthChecker.interval | mapreduce.tasktracker.healthchecker.interval |
-| mapred.healthChecker.script.args | mapreduce.tasktracker.healthchecker.script.args |
-| mapred.healthChecker.script.path | mapreduce.tasktracker.healthchecker.script.path |
-| mapred.healthChecker.script.timeout | mapreduce.tasktracker.healthchecker.script.timeout |
| mapred.inmem.merge.threshold | mapreduce.reduce.merge.inmem.threshold |
| mapred.input.dir.formats | mapreduce.input.multipleinputs.dir.formats |
| mapred.input.dir.mappers | mapreduce.input.multipleinputs.dir.mappers |
@@ -146,8 +144,6 @@ The following table lists the configuration property names that are deprecated i
| mapred.line.input.format.linespermap | mapreduce.input.lineinputformat.linespermap |
| mapred.linerecordreader.maxlength | mapreduce.input.linerecordreader.line.maxlength |
| mapred.local.dir | mapreduce.cluster.local.dir |
-| mapred.local.dir.minspacekill | mapreduce.tasktracker.local.dir.minspacekill |
-| mapred.local.dir.minspacestart | mapreduce.tasktracker.local.dir.minspacestart |
| mapred.map.child.env | mapreduce.map.env |
| mapred.map.child.java.opts | mapreduce.map.java.opts |
| mapred.map.child.log.level | mapreduce.map.log.level |
@@ -212,19 +208,10 @@ The following table lists the configuration property names that are deprecated i
| mapred.task.profile.params | mapreduce.task.profile.params |
| mapred.task.profile.reduces | mapreduce.task.profile.reduces |
| mapred.task.timeout | mapreduce.task.timeout |
-| mapred.tasktracker.dns.interface | mapreduce.tasktracker.dns.interface |
-| mapred.tasktracker.dns.nameserver | mapreduce.tasktracker.dns.nameserver |
-| mapred.tasktracker.events.batchsize | mapreduce.tasktracker.events.batchsize |
-| mapred.task.tracker.http.address | mapreduce.tasktracker.http.address |
| mapred.tasktracker.indexcache.mb | mapreduce.tasktracker.indexcache.mb |
-| mapred.tasktracker.instrumentation | mapreduce.tasktracker.instrumentation |
| mapred.tasktracker.map.tasks.maximum | mapreduce.tasktracker.map.tasks.maximum |
| mapred.tasktracker.memory\_calculator\_plugin | mapreduce.tasktracker.resourcecalculatorplugin |
| mapred.tasktracker.memorycalculatorplugin | mapreduce.tasktracker.resourcecalculatorplugin |
-| mapred.tasktracker.reduce.tasks.maximum | mapreduce.tasktracker.reduce.tasks.maximum |
-| mapred.task.tracker.report.address | mapreduce.tasktracker.report.address |
-| mapred.task.tracker.task-controller | mapreduce.tasktracker.taskcontroller |
-| mapred.tasktracker.tasks.sleeptime-before-sigkill | mapreduce.tasktracker.tasks.sleeptimebeforesigkill |
| mapred.temp.dir | mapreduce.cluster.temp.dir |
| mapred.text.key.comparator.options | mapreduce.partition.keycomparator.options |
| mapred.text.key.partitioner.options | mapreduce.partition.keypartitioner.options |
@@ -239,7 +226,6 @@ The following table lists the configuration property names that are deprecated i
| mapreduce.reduce.class | mapreduce.job.reduce.class |
| mapred.used.genericoptionsparser | mapreduce.client.genericoptionsparser.used |
| mapred.userlog.limit.kb | mapreduce.task.userlog.limit.kb |
-| mapred.userlog.retain.hours | mapreduce.job.userlog.retain.hours |
| mapred.working.dir | mapreduce.job.working.dir |
| mapred.work.output.dir | mapreduce.task.output.dir |
| min.num.spills.for.combine | mapreduce.map.combine.minspills |
@@ -251,9 +237,6 @@ The following table lists the configuration property names that are deprecated i
| sequencefile.filter.regex | mapreduce.input.sequencefileinputfilter.regex |
| session.id | dfs.metrics.session-id |
| slave.host.name | dfs.datanode.hostname |
-| slave.host.name | mapreduce.tasktracker.host.name |
-| tasktracker.contention.tracking | mapreduce.tasktracker.contention.tracking |
-| tasktracker.http.threads | mapreduce.tasktracker.http.threads |
| topology.node.switch.mapping.impl | net.topology.node.switch.mapping.impl |
| topology.script.file.name | net.topology.script.file.name |
| topology.script.number.args | net.topology.script.number.args |
diff --git a/hadoop-common-project/hadoop-common/src/site/markdown/FairCallQueue.md b/hadoop-common-project/hadoop-common/src/site/markdown/FairCallQueue.md
index e62c7ad42efda..22ac05a53b951 100644
--- a/hadoop-common-project/hadoop-common/src/site/markdown/FairCallQueue.md
+++ b/hadoop-common-project/hadoop-common/src/site/markdown/FairCallQueue.md
@@ -91,6 +91,21 @@ This is configurable via the **identity provider**, which defaults to the **User
provider simply uses the username of the client submitting the request. However, a custom identity provider can be used
to performing throttling based on other groupings, or using an external identity provider.
+### Cost-based Fair Call Queue
+
+Though the fair call queue itself does a good job of mitigating the impact from users who submit a very high _number_
+of requests, it does not take account into how expensive each request is to process. Thus, when considering the
+HDFS NameNode, a user who submits 1000 "getFileInfo" requests would be prioritized the same as a user who submits 1000
+"listStatus" requests on some very large directory, or a user who submits 1000 "mkdir" requests, which are more
+expensive as they require an exclusive lock on the namesystem. To account for the _cost_ of an operation when
+considering the prioritization of user requests, there is a "cost-based" extension to the Fair Call Queue which uses
+the aggregate processing time of a user's operations to determine how that user should be prioritized. By default,
+queue time (time spent waiting to be processed) and lock wait time (time spent waiting to acquire a lock) is not
+considered in the cost, time spent processing without a lock is neutrally (1x) weighted, time spent processing with a
+shared lock is weighted 10x higher, and time spent processing with an exclusive lock is weighted 100x higher.
+This attempts to prioritize users based on the actual load they place on the server. To enable this feature, set the
+`costprovder.impl` configuration to `org.apache.hadoop.ipc.WeightedTimeCostProvider` as described below.
+
Configuration
-------------
@@ -115,12 +130,16 @@ omitted.
| scheduler.priority.levels | RpcScheduler, CallQueue | How many priority levels to use within the scheduler and call queue. | 4 |
| faircallqueue.multiplexer.weights | WeightedRoundRobinMultiplexer | How much weight to give to each priority queue. This should be a comma-separated list of length equal to the number of priority levels. | Weights descend by a factor of 2 (e.g., for 4 levels: `8,4,2,1`) |
| identity-provider.impl | DecayRpcScheduler | The identity provider mapping user requests to their identity. | org.apache.hadoop.ipc.UserIdentityProvider |
+| cost-provider.impl | DecayRpcScheduler | The cost provider mapping user requests to their cost. To enable determination of cost based on processing time, use `org.apache.hadoop.ipc.WeightedTimeCostProvider`. | org.apache.hadoop.ipc.DefaultCostProvider |
| decay-scheduler.period-ms | DecayRpcScheduler | How frequently the decay factor should be applied to the operation counts of users. Higher values have less overhead, but respond less quickly to changes in client behavior. | 5000 |
| decay-scheduler.decay-factor | DecayRpcScheduler | When decaying the operation counts of users, the multiplicative decay factor to apply. Higher values will weight older operations more strongly, essentially giving the scheduler a longer memory, and penalizing heavy clients for a longer period of time. | 0.5 |
| decay-scheduler.thresholds | DecayRpcScheduler | The client load threshold, as an integer percentage, for each priority queue. Clients producing less load, as a percent of total operations, than specified at position _i_ will be given priority _i_. This should be a comma-separated list of length equal to the number of priority levels minus 1 (the last is implicitly 100). | Thresholds ascend by a factor of 2 (e.g., for 4 levels: `13,25,50`) |
| decay-scheduler.backoff.responsetime.enable | DecayRpcScheduler | Whether or not to enable the backoff by response time feature. | false |
| decay-scheduler.backoff.responsetime.thresholds | DecayRpcScheduler | The response time thresholds, as time durations, for each priority queue. If the average response time for a queue is above this threshold, backoff will occur in lower priority queues. This should be a comma-separated list of length equal to the number of priority levels. | Threshold increases by 10s per level (e.g., for 4 levels: `10s,20s,30s,40s`) |
| decay-scheduler.metrics.top.user.count | DecayRpcScheduler | The number of top (i.e., heaviest) users to emit metric information about. | 10 |
+| weighted-cost.lockshared | WeightedTimeCostProvider | The weight multiplier to apply to the time spent in the processing phase which holds a shared (read) lock. | 10 |
+| weighted-cost.lockexclusive | WeightedTimeCostProvider | The weight multiplier to apply to the time spent in the processing phase which holds an exclusive (write) lock. | 100 |
+| weighted-cost.{handler,lockfree,response} | WeightedTimeCostProvider | The weight multiplier to apply to the time spent in the processing phases which do not involve holding a lock. See `org.apache.hadoop.ipc.ProcessingDetails.Timing` for more details on each phase. | 1 |
### Example Configuration
diff --git a/hadoop-common-project/hadoop-common/src/site/markdown/FileSystemShell.md b/hadoop-common-project/hadoop-common/src/site/markdown/FileSystemShell.md
index f050e30832c75..7df2cce574b68 100644
--- a/hadoop-common-project/hadoop-common/src/site/markdown/FileSystemShell.md
+++ b/hadoop-common-project/hadoop-common/src/site/markdown/FileSystemShell.md
@@ -268,7 +268,7 @@ Displays a summary of file lengths.
expunge
-------
-Usage: `hadoop fs -expunge [-immediate]`
+Usage: `hadoop fs -expunge [-immediate] [-fs ]`
Permanently delete files in checkpoints older than the retention threshold
from trash directory, and create new checkpoint.
@@ -286,6 +286,15 @@ This value should be smaller or equal to `fs.trash.interval`.
If the `-immediate` option is passed, all files in the trash for the current
user are immediately deleted, ignoring the `fs.trash.interval` setting.
+If the `-fs` option is passed, the supplied filesystem will be expunged,
+rather than the default filesystem and checkpoint is created.
+
+For example
+
+```
+hadoop fs -expunge --immediate -fs s3a://landsat-pds/
+```
+
Refer to the
[HDFS Architecture guide](../hadoop-hdfs/HdfsDesign.html#File_Deletes_and_Undeletes)
for more information about trash feature of HDFS.
@@ -629,7 +638,7 @@ Options:
* -R: Apply operations to all files and directories recursively.
* -m: Modify ACL. New entries are added to the ACL, and existing entries are retained.
* -x: Remove specified ACL entries. Other ACL entries are retained.
-* ``--set``: Fully replace the ACL, discarding all existing entries. The *acl\_spec* must include entries for user, group, and others for compatibility with permission bits.
+* ``--set``: Fully replace the ACL, discarding all existing entries. The *acl\_spec* must include entries for user, group, and others for compatibility with permission bits. If the ACL spec contains only access entries, then the existing default entries are retained. If the ACL spec contains only default entries, then the existing access entries are retained. If the ACL spec contains both access and default entries, then both are replaced.
* *acl\_spec*: Comma separated list of ACL entries.
* *path*: File or directory to modify.
@@ -724,16 +733,16 @@ Exit Code: Returns 0 on success and -1 on error.
test
----
-Usage: `hadoop fs -test -[defsz] URI`
+Usage: `hadoop fs -test -[defswrz] URI`
Options:
-* -d: f the path is a directory, return 0.
+* -d: if the path is a directory, return 0.
* -e: if the path exists, return 0.
* -f: if the path is a file, return 0.
* -s: if the path is not empty, return 0.
-* -r: if the path exists and read permission is granted, return 0.
* -w: if the path exists and write permission is granted, return 0.
+* -r: if the path exists and read permission is granted, return 0.
* -z: if the file is zero length, return 0.
diff --git a/hadoop-common-project/hadoop-common/src/site/markdown/HttpAuthentication.md b/hadoop-common-project/hadoop-common/src/site/markdown/HttpAuthentication.md
index 721abea93b764..ca5ce4898aa71 100644
--- a/hadoop-common-project/hadoop-common/src/site/markdown/HttpAuthentication.md
+++ b/hadoop-common-project/hadoop-common/src/site/markdown/HttpAuthentication.md
@@ -64,3 +64,13 @@ Add org.apache.hadoop.security.HttpCrossOriginFilterInitializer to hadoop.http.f
| hadoop.http.cross-origin.allowed-methods | `GET,POST,HEAD` | Comma separated list of methods that are allowed |
| hadoop.http.cross-origin.allowed-headers | `X-Requested-With,Content-Type,Accept,Origin` | Comma separated list of headers that are allowed |
| hadoop.http.cross-origin.max-age | `1800` | Number of seconds a pre-flighted request can be cached |
+
+
+Trusted Proxy
+-------------
+Trusted Proxy adds support to perform operations using end user instead of proxy user. It fetches the end user from
+doAs query parameter. To enable Trusted Proxy, please set the following configuration parameter:
+
+Add org.apache.hadoop.security.authentication.server.ProxyUserAuthenticationFilterInitializer to hadoop.http.filter.initializers in core-site.xml
+instead of org.apache.hadoop.security.AuthenticationFilterInitializer.
+
diff --git a/hadoop-common-project/hadoop-common/src/site/markdown/Metrics.md b/hadoop-common-project/hadoop-common/src/site/markdown/Metrics.md
index 1ef2b44b6ecb3..2d0f23293bfa3 100644
--- a/hadoop-common-project/hadoop-common/src/site/markdown/Metrics.md
+++ b/hadoop-common-project/hadoop-common/src/site/markdown/Metrics.md
@@ -71,6 +71,8 @@ Each metrics record contains tags such as Hostname and port (number to which ser
| `SentBytes` | Total number of sent bytes |
| `RpcQueueTimeNumOps` | Total number of RPC calls |
| `RpcQueueTimeAvgTime` | Average queue time in milliseconds |
+| `RpcLockWaitTimeNumOps` | Total number of RPC call (same as RpcQueueTimeNumOps) |
+| `RpcLockWaitTimeAvgTime` | Average time waiting for lock acquisition in milliseconds |
| `RpcProcessingTimeNumOps` | Total number of RPC calls (same to RpcQueueTimeNumOps) |
| `RpcProcessingAvgTime` | Average Processing time in milliseconds |
| `RpcAuthenticationFailures` | Total number of authentication failures |
@@ -92,6 +94,12 @@ Each metrics record contains tags such as Hostname and port (number to which ser
| `rpcProcessingTime`*num*`s90thPercentileLatency` | Shows the 90th percentile of RPC processing time in milliseconds (*num* seconds granularity) if `rpc.metrics.quantile.enable` is set to true. *num* is specified by `rpc.metrics.percentiles.intervals`. |
| `rpcProcessingTime`*num*`s95thPercentileLatency` | Shows the 95th percentile of RPC processing time in milliseconds (*num* seconds granularity) if `rpc.metrics.quantile.enable` is set to true. *num* is specified by `rpc.metrics.percentiles.intervals`. |
| `rpcProcessingTime`*num*`s99thPercentileLatency` | Shows the 99th percentile of RPC processing time in milliseconds (*num* seconds granularity) if `rpc.metrics.quantile.enable` is set to true. *num* is specified by `rpc.metrics.percentiles.intervals`. |
+| `rpcLockWaitTime`*num*`sNumOps` | Shows total number of RPC calls (*num* seconds granularity) if `rpc.metrics.quantile.enable` is set to true. *num* is specified by `rpc.metrics.percentiles.intervals`. |
+| `rpcLockWaitTime`*num*`s50thPercentileLatency` | Shows the 50th percentile of RPC lock wait time in milliseconds (*num* seconds granularity) if `rpc.metrics.quantile.enable` is set to true. *num* is specified by `rpc.metrics.percentiles.intervals`. |
+| `rpcLockWaitTime`*num*`s75thPercentileLatency` | Shows the 75th percentile of RPC lock wait time in milliseconds (*num* seconds granularity) if `rpc.metrics.quantile.enable` is set to true. *num* is specified by `rpc.metrics.percentiles.intervals`. |
+| `rpcLockWaitTime`*num*`s90thPercentileLatency` | Shows the 90th percentile of RPC lock wait time in milliseconds (*num* seconds granularity) if `rpc.metrics.quantile.enable` is set to true. *num* is specified by `rpc.metrics.percentiles.intervals`. |
+| `rpcLockWaitTime`*num*`s95thPercentileLatency` | Shows the 95th percentile of RPC lock wait time in milliseconds (*num* seconds granularity) if `rpc.metrics.quantile.enable` is set to true. *num* is specified by `rpc.metrics.percentiles.intervals`. |
+| `rpcLockWaitTime`*num*`s99thPercentileLatency` | Shows the 99th percentile of RPC lock wait time in milliseconds (*num* seconds granularity) if `rpc.metrics.quantile.enable` is set to true. *num* is specified by `rpc.metrics.percentiles.intervals`. |
RetryCache/NameNodeRetryCache
-----------------------------
@@ -118,6 +126,7 @@ rpcdetailed context
===================
Metrics of rpcdetailed context are exposed in unified manner by RPC layer. Two metrics are exposed for each RPC based on its name. Metrics named "(RPC method name)NumOps" indicates total number of method calls, and metrics named "(RPC method name)AvgTime" shows average turn around time for method calls in milliseconds.
+Please note that the AvgTime metrics do not include time spent waiting to acquire locks on data structures (see RpcLockWaitTimeAvgTime).
rpcdetailed
-----------
@@ -469,6 +478,40 @@ contains tags such as Hostname as additional information along with metrics.
| `FileIoErrorRateNumOps` | The number of file io error operations within an interval time of metric |
| `FileIoErrorRateAvgTime` | It measures the mean time in milliseconds from the start of an operation to hitting a failure |
+RBFMetrics
+----------------
+RBFMetrics shows the metrics which are the aggregated values of sub-clusters' information in the Router-based federation.
+
+| Name | Description |
+|:---- |:---- |
+| `NumFiles` | Current number of files and directories |
+| `NumBlocks` | Current number of allocated blocks |
+| `NumOfBlocksPendingReplication` | Current number of blocks pending to be replicated |
+| `NumOfBlocksUnderReplicated` | Current number of blocks under replicated |
+| `NumOfBlocksPendingDeletion` | Current number of blocks pending deletion |
+| `ProvidedSpace` | The total remote storage capacity mounted in the federated cluster |
+| `NumInMaintenanceLiveDataNodes` | Number of live Datanodes which are in maintenance state |
+| `NumInMaintenanceDeadDataNodes` | Number of dead Datanodes which are in maintenance state |
+| `NumEnteringMaintenanceDataNodes` | Number of Datanodes that are entering the maintenance state |
+| `TotalCapacity` | Current raw capacity of DataNodes in bytes |
+| `UsedCapacity` | Current used capacity across all DataNodes in bytes |
+| `RemainingCapacity` | Current remaining capacity in bytes |
+| `NumOfMissingBlocks` | Current number of missing blocks |
+| `NumLiveNodes` | Number of datanodes which are currently live |
+| `NumDeadNodes` | Number of datanodes which are currently dead |
+| `NumStaleNodes` | Current number of DataNodes marked stale due to delayed heartbeat |
+| `NumDecomLiveNodes` | Number of datanodes which have been decommissioned and are now live |
+| `NumDecomDeadNodes` | Number of datanodes which have been decommissioned and are now dead |
+| `NumDecommissioningNodes` | Number of datanodes in decommissioning state |
+| `Namenodes` | Current information about all the namenodes |
+| `Nameservices` | Current information for each registered nameservice |
+| `MountTable` | The mount table for the federated filesystem |
+| `Routers` | Current information about all routers |
+| `NumNameservices` | Number of nameservices |
+| `NumNamenodes` | Number of namenodes |
+| `NumExpiredNamenodes` | Number of expired namenodes |
+| `NodeUsage` | Max, Median, Min and Standard Deviation of DataNodes usage |
+
RouterRPCMetrics
----------------
RouterRPCMetrics shows the statistics of the Router component in Router-based federation.
diff --git a/hadoop-common-project/hadoop-common/src/site/markdown/filesystem/filesystem.md b/hadoop-common-project/hadoop-common/src/site/markdown/filesystem/filesystem.md
index 9440b4e050a72..a2458ee891448 100644
--- a/hadoop-common-project/hadoop-common/src/site/markdown/filesystem/filesystem.md
+++ b/hadoop-common-project/hadoop-common/src/site/markdown/filesystem/filesystem.md
@@ -220,21 +220,21 @@ directory contains many thousands of files.
Consider a directory `"/d"` with the contents:
- a
- part-0000001
- part-0000002
- ...
- part-9999999
+ a
+ part-0000001
+ part-0000002
+ ...
+ part-9999999
If the number of files is such that HDFS returns a partial listing in each
response, then, if a listing `listStatus("/d")` takes place concurrently with the operation
`rename("/d/a","/d/z"))`, the result may be one of:
- [a, part-0000001, ... , part-9999999]
- [part-0000001, ... , part-9999999, z]
- [a, part-0000001, ... , part-9999999, z]
- [part-0000001, ... , part-9999999]
+ [a, part-0000001, ... , part-9999999]
+ [part-0000001, ... , part-9999999, z]
+ [a, part-0000001, ... , part-9999999, z]
+ [part-0000001, ... , part-9999999]
While this situation is likely to be a rare occurrence, it MAY happen. In HDFS
these inconsistent views are only likely when listing a directory with many children.
@@ -526,7 +526,7 @@ on the filesystem.
`getFileStatus(P).getBlockSize()`.
1. By inference, it MUST be > 0 for any file of length > 0.
-## State Changing Operations
+## State Changing Operations
### `boolean mkdirs(Path p, FsPermission permission)`
@@ -964,7 +964,7 @@ A path referring to a file is removed, return value: `True`
Deleting an empty root does not change the filesystem state
and may return true or false.
- if isDir(FS, p) and isRoot(p) and children(FS, p) == {} :
+ if isRoot(p) and children(FS, p) == {} :
FS ' = FS
result = (undetermined)
@@ -973,6 +973,9 @@ There is no consistent return code from an attempt to delete the root directory.
Implementations SHOULD return true; this avoids code which checks for a false
return value from overreacting.
+*Object Stores*: see [Object Stores: root directory deletion](#object-stores-rm-root).
+
+
##### Empty (non-root) directory `recursive == False`
Deleting an empty directory that is not root will remove the path from the FS and
@@ -986,7 +989,7 @@ return true.
##### Recursive delete of non-empty root directory
Deleting a root path with children and `recursive==True`
- can do one of two things.
+can generally have three outcomes:
1. The POSIX model assumes that if the user has
the correct permissions to delete everything,
@@ -1004,6 +1007,8 @@ filesystem is desired.
FS' = FS
result = False
+1. Object Stores: see [Object Stores: root directory deletion](#object-stores-rm-root).
+
HDFS has the notion of *Protected Directories*, which are declared in
the option `fs.protected.directories`. Any attempt to delete such a directory
or a parent thereof raises an `AccessControlException`. Accordingly, any
@@ -1019,6 +1024,23 @@ Any filesystem client which interacts with a remote filesystem which lacks
such a security model, MAY reject calls to `delete("/", true)` on the basis
that it makes it too easy to lose data.
+
+### Object Stores: root directory deletion
+
+Some of the object store based filesystem implementations always return
+false when deleting the root, leaving the state of the store unchanged.
+
+ if isRoot(p) :
+ FS ' = FS
+ result = False
+
+This is irrespective of the recursive flag status or the state of the directory.
+
+This is a simplification which avoids the inevitably non-atomic scan and delete
+of the contents of the store. It also avoids any confusion about whether
+the operation actually deletes that specific store/container itself, and
+adverse consequences of the simpler permissions models of stores.
+
##### Recursive delete of non-root directory
Deleting a non-root path with children `recursive==true`
@@ -1457,7 +1479,7 @@ public interface StreamCapabilities {
### `boolean hasCapability(capability)`
-Return true if the `OutputStream`, `InputStream`, or other FileSystem class
+Return true iff the `OutputStream`, `InputStream`, or other FileSystem class
has the desired capability.
The caller can query the capabilities of a stream using a string value.
@@ -1470,3 +1492,4 @@ hsync | HSYNC | Syncable | Flush out the data in client's us
in:readahead | READAHEAD | CanSetReadahead | Set the readahead on the input stream.
dropbehind | DROPBEHIND | CanSetDropBehind | Drop the cache.
in:unbuffer | UNBUFFER | CanUnbuffer | Reduce the buffering on the input stream.
+
diff --git a/hadoop-common-project/hadoop-common/src/site/markdown/filesystem/fsdatainputstreambuilder.md b/hadoop-common-project/hadoop-common/src/site/markdown/filesystem/fsdatainputstreambuilder.md
index f1beed862cdbf..a7c393d9a41c1 100644
--- a/hadoop-common-project/hadoop-common/src/site/markdown/filesystem/fsdatainputstreambuilder.md
+++ b/hadoop-common-project/hadoop-common/src/site/markdown/filesystem/fsdatainputstreambuilder.md
@@ -54,7 +54,7 @@ of `FileSystem`.
```java
out = fs.openFile(path)
- .opt("fs.s3a.experimental.fadvise", "random")
+ .opt("fs.s3a.experimental.input.fadvise", "random")
.must("fs.s3a.readahead.range", 256 * 1024)
.build()
.get();
diff --git a/hadoop-common-project/hadoop-common/src/site/markdown/filesystem/index.md b/hadoop-common-project/hadoop-common/src/site/markdown/filesystem/index.md
index 6b4399ea2123c..df538ee6cf96b 100644
--- a/hadoop-common-project/hadoop-common/src/site/markdown/filesystem/index.md
+++ b/hadoop-common-project/hadoop-common/src/site/markdown/filesystem/index.md
@@ -33,6 +33,7 @@ HDFS as these are commonly expected by Hadoop client applications.
1. [Model](model.html)
1. [FileSystem class](filesystem.html)
1. [FSDataInputStream class](fsdatainputstream.html)
+1. [PathCapabilities interface](pathcapabilities.html)
1. [FSDataOutputStreamBuilder class](fsdataoutputstreambuilder.html)
2. [Testing with the Filesystem specification](testing.html)
2. [Extending the specification and its tests](extending.html)
diff --git a/hadoop-common-project/hadoop-common/src/site/markdown/filesystem/pathcapabilities.md b/hadoop-common-project/hadoop-common/src/site/markdown/filesystem/pathcapabilities.md
new file mode 100644
index 0000000000000..e053bfbaede9b
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/site/markdown/filesystem/pathcapabilities.md
@@ -0,0 +1,158 @@
+
+
+# interface `PathCapabilities`
+
+The `PathCapabilities` interface provides a way to programmatically query the
+operations offered under a given path by an instance of `FileSystem`, `FileContext`
+or other implementing class.
+
+```java
+public interface PathCapabilities {
+ boolean hasPathCapability(Path path, String capability)
+ throws IOException;
+}
+```
+
+There are a number of goals here:
+
+1. Allow callers to probe for optional filesystem operations without actually
+having to invoke them.
+1. Allow filesystems with their own optional per-instance features to declare
+whether or not they are active for the specific instance.
+1. Allow for fileystem connectors which work with object stores to expose the
+fundamental difference in semantics of these stores (e.g: files not visible
+until closed, file rename being `O(data)`), directory rename being non-atomic,
+etc.
+
+### Available Capabilities
+
+Capabilities are defined as strings and split into "Common Capabilites"
+and non-standard ones for a specific store.
+
+The common capabilities are all defined under the prefix `fs.capability.`
+
+Consult the javadocs for `org.apache.hadoop.fs.CommonPathCapabilities` for these.
+
+
+Individual filesystems MAY offer their own set of capabilities which
+can be probed for. These MUST begin with `fs.` + the filesystem scheme +
+ `.capability`. For example `fs.s3a.capability.select.sql`;
+
+### `boolean hasPathCapability(path, capability)`
+
+Probe for the instance offering a specific capability under the
+given path.
+
+#### Postconditions
+
+```python
+if fs_supports_the_feature(path, capability):
+ return True
+else:
+ return False
+```
+
+Return: `True`, iff the specific capability is available.
+
+A filesystem instance *MUST NOT* return `True` for any capability unless it is
+known to be supported by that specific instance. As a result, if a caller
+probes for a capability then it can assume that the specific feature/semantics
+are available.
+
+If the probe returns `False` then it can mean one of:
+
+1. The capability is unknown.
+1. The capability is known, and known to be unavailable on this instance.
+1. The capability is known but this local class does not know if it is supported
+ under the supplied path.
+
+This predicate is intended to be low cost. If it requires remote calls other
+than path/link resolution, it SHOULD conclude that the availability
+of the feature is unknown and return `False`.
+
+The predicate MUST also be side-effect free.
+
+*Validity of paths*
+There is no requirement that the existence of the path must be checked;
+the parameter exists so that any filesystem which relays operations to other
+filesystems (e.g `viewfs`) can resolve and relay it to the nested filesystem.
+Consider the call to be *relatively* lightweight.
+
+Because of this, it may be that while the filesystem declares that
+it supports a capability under a path, the actual invocation of the operation
+may fail for other reasons.
+
+As an example, while a filesystem may support `append()` under a path,
+if invoked on a directory, the call may fail.
+
+That is for a path `root = new Path("/")`: the capabilities call may succeed
+
+```java
+fs.hasCapabilities(root, "fs.capability.append") == true
+```
+
+But a subsequent call to the operation on that specific path may fail,
+because the root path is a directory:
+
+```java
+fs.append(root)
+```
+
+
+Similarly, there is no checking that the caller has the permission to
+perform a specific operation: just because a feature is available on that
+path does not mean that the caller can execute the operation.
+
+The `hasCapabilities(path, capability)` probe is therefore declaring that
+the operation will not be rejected as unsupported, not that a specific invocation
+will be permitted on that path by the caller.
+
+*Duration of availability*
+
+As the state of a remote store changes,so may path capabilities. This
+may be due to changes in the local state of the fileystem (e.g. symbolic links
+or mount points changing), or changes in its functionality (e.g. a feature
+becoming availaible/unavailable due to operational changes, system upgrades, etc.)
+
+*Capabilities which must be invoked to determine availablity*
+
+Some operations may be known by the client connector, and believed to be available,
+but may actually fail when invoked due to the state and permissons of the remote
+store —state which is cannot be determined except by attempting
+side-effecting operations.
+
+A key example of this is symbolic links and the local filesystem.
+The filesystem declares that it supports this unless symbolic links are explicitly
+disabled —when invoked they may actually fail.
+
+### Implementors Notes
+
+Implementors *MUST NOT* return `true` for any capability which is not guaranteed
+to be supported. To return `true` indicates that the implementation/deployment
+of the filesystem does, to the best of the knowledge of the filesystem client,
+offer the desired operations *and semantics* queried for.
+
+For performance reasons, implementations *SHOULD NOT* check the path for
+existence, unless it needs to resolve symbolic links in parts of the path
+to determine whether a feature is present. This is required of `FileContext`
+and `viewfs`.
+
+Individual filesystems *MUST NOT* unilaterally define new `fs.capability`-prefixed
+capabilities. Instead they *MUST* do one of the following:
+
+* Define and stabilize new cross-filesystem capability flags (preferred),
+and so formally add a new `fs.capability` value.
+* Use the scheme of the filesystem to as a prefix for their own options,
+e.g `fs.hdfs.`
diff --git a/hadoop-common-project/hadoop-common/src/site/markdown/release/2.10.0/CHANGES.2.10.0.md b/hadoop-common-project/hadoop-common/src/site/markdown/release/2.10.0/CHANGES.2.10.0.md
new file mode 100644
index 0000000000000..d8dd2daca09cc
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/site/markdown/release/2.10.0/CHANGES.2.10.0.md
@@ -0,0 +1,788 @@
+
+
+# "Apache Hadoop" Changelog
+
+## Release 2.10.0 - 2019-10-22
+
+### INCOMPATIBLE CHANGES:
+
+| JIRA | Summary | Priority | Component | Reporter | Contributor |
+|:---- |:---- | :--- |:---- |:---- |:---- |
+| [HDFS-12883](https://issues.apache.org/jira/browse/HDFS-12883) | RBF: Document Router and State Store metrics | Major | documentation | Yiqun Lin | Yiqun Lin |
+| [HDFS-12895](https://issues.apache.org/jira/browse/HDFS-12895) | RBF: Add ACL support for mount table | Major | . | Yiqun Lin | Yiqun Lin |
+| [HDFS-13099](https://issues.apache.org/jira/browse/HDFS-13099) | RBF: Use the ZooKeeper as the default State Store | Minor | documentation | Yiqun Lin | Yiqun Lin |
+| [HADOOP-16055](https://issues.apache.org/jira/browse/HADOOP-16055) | Upgrade AWS SDK to 1.11.271 in branch-2 | Blocker | fs/s3 | Akira Ajisaka | Akira Ajisaka |
+| [HADOOP-16053](https://issues.apache.org/jira/browse/HADOOP-16053) | Backport HADOOP-14816 to branch-2 | Major | build | Akira Ajisaka | Akira Ajisaka |
+
+
+### IMPORTANT ISSUES:
+
+| JIRA | Summary | Priority | Component | Reporter | Contributor |
+|:---- |:---- | :--- |:---- |:---- |:---- |
+| [HDFS-13083](https://issues.apache.org/jira/browse/HDFS-13083) | RBF: Fix doc error setting up client | Major | federation | tartarus | tartarus |
+
+
+### NEW FEATURES:
+
+| JIRA | Summary | Priority | Component | Reporter | Contributor |
+|:---- |:---- | :--- |:---- |:---- |:---- |
+| [HDFS-13283](https://issues.apache.org/jira/browse/HDFS-13283) | Percentage based Reserved Space Calculation for DataNode | Major | datanode, hdfs | Lukas Majercak | Lukas Majercak |
+| [HDFS-13553](https://issues.apache.org/jira/browse/HDFS-13553) | RBF: Support global quota | Major | . | Íñigo Goiri | Yiqun Lin |
+| [HADOOP-15950](https://issues.apache.org/jira/browse/HADOOP-15950) | Failover for LdapGroupsMapping | Major | common, security | Lukas Majercak | Lukas Majercak |
+| [YARN-9761](https://issues.apache.org/jira/browse/YARN-9761) | Allow overriding application submissions based on server side configs | Major | . | Jonathan Hung | pralabhkumar |
+| [YARN-9760](https://issues.apache.org/jira/browse/YARN-9760) | Support configuring application priorities on a workflow level | Major | . | Jonathan Hung | Varun Saxena |
+
+
+### IMPROVEMENTS:
+
+| JIRA | Summary | Priority | Component | Reporter | Contributor |
+|:---- |:---- | :--- |:---- |:---- |:---- |
+| [HADOOP-14987](https://issues.apache.org/jira/browse/HADOOP-14987) | Improve KMSClientProvider log around delegation token checking | Major | . | Xiaoyu Yao | Xiaoyu Yao |
+| [HADOOP-14872](https://issues.apache.org/jira/browse/HADOOP-14872) | CryptoInputStream should implement unbuffer | Major | fs, security | John Zhuge | John Zhuge |
+| [HADOOP-14960](https://issues.apache.org/jira/browse/HADOOP-14960) | Add GC time percentage monitor/alerter | Major | . | Misha Dmitriev | Misha Dmitriev |
+| [HADOOP-15023](https://issues.apache.org/jira/browse/HADOOP-15023) | ValueQueue should also validate (lowWatermark \* numValues) \> 0 on construction | Minor | . | Xiao Chen | Xiao Chen |
+| [YARN-6851](https://issues.apache.org/jira/browse/YARN-6851) | Capacity Scheduler: document configs for controlling # containers allowed to be allocated per node heartbeat | Minor | . | Wei Yan | Wei Yan |
+| [YARN-7495](https://issues.apache.org/jira/browse/YARN-7495) | Improve robustness of the AggregatedLogDeletionService | Major | log-aggregation | Jonathan Turner Eagles | Jonathan Turner Eagles |
+| [HADOOP-15056](https://issues.apache.org/jira/browse/HADOOP-15056) | Fix TestUnbuffer#testUnbufferException failure | Minor | test | Jack Bearden | Jack Bearden |
+| [HADOOP-15012](https://issues.apache.org/jira/browse/HADOOP-15012) | Add readahead, dropbehind, and unbuffer to StreamCapabilities | Major | fs | John Zhuge | John Zhuge |
+| [HADOOP-15104](https://issues.apache.org/jira/browse/HADOOP-15104) | AliyunOSS: change the default value of max error retry | Major | fs/oss | wujinhu | wujinhu |
+| [YARN-7274](https://issues.apache.org/jira/browse/YARN-7274) | Ability to disable elasticity at leaf queue level | Major | capacityscheduler | Scott Brokaw | Zian Chen |
+| [YARN-7642](https://issues.apache.org/jira/browse/YARN-7642) | Add test case to verify context update after container promotion or demotion with or without auto update | Minor | nodemanager | Weiwei Yang | Weiwei Yang |
+| [HADOOP-15111](https://issues.apache.org/jira/browse/HADOOP-15111) | AliyunOSS: backport HADOOP-14993 to branch-2 | Major | fs/oss | Genmao Yu | Genmao Yu |
+| [HDFS-12818](https://issues.apache.org/jira/browse/HDFS-12818) | Support multiple storages in DataNodeCluster / SimulatedFSDataset | Minor | datanode, test | Erik Krogen | Erik Krogen |
+| [HDFS-9023](https://issues.apache.org/jira/browse/HDFS-9023) | When NN is not able to identify DN for replication, reason behind it can be logged | Critical | hdfs-client, namenode | Surendra Singh Lilhore | Xiao Chen |
+| [YARN-7678](https://issues.apache.org/jira/browse/YARN-7678) | Ability to enable logging of container memory stats | Major | nodemanager | Jim Brennan | Jim Brennan |
+| [HDFS-12945](https://issues.apache.org/jira/browse/HDFS-12945) | Switch to ClientProtocol instead of NamenodeProtocols in NamenodeWebHdfsMethods | Minor | . | Wei Yan | Wei Yan |
+| [YARN-7622](https://issues.apache.org/jira/browse/YARN-7622) | Allow fair-scheduler configuration on HDFS | Minor | fairscheduler, resourcemanager | Greg Phillips | Greg Phillips |
+| [YARN-7590](https://issues.apache.org/jira/browse/YARN-7590) | Improve container-executor validation check | Major | security, yarn | Eric Yang | Eric Yang |
+| [MAPREDUCE-7029](https://issues.apache.org/jira/browse/MAPREDUCE-7029) | FileOutputCommitter is slow on filesystems lacking recursive delete | Minor | . | Karthik Palaniappan | Karthik Palaniappan |
+| [MAPREDUCE-6984](https://issues.apache.org/jira/browse/MAPREDUCE-6984) | MR AM to clean up temporary files from previous attempt in case of no recovery | Major | applicationmaster | Gergo Repas | Gergo Repas |
+| [HADOOP-15189](https://issues.apache.org/jira/browse/HADOOP-15189) | backport HADOOP-15039 to branch-2 and branch-3 | Blocker | . | Genmao Yu | Genmao Yu |
+| [HADOOP-15212](https://issues.apache.org/jira/browse/HADOOP-15212) | Add independent secret manager method for logging expired tokens | Major | security | Daryn Sharp | Daryn Sharp |
+| [YARN-7728](https://issues.apache.org/jira/browse/YARN-7728) | Expose container preemptions related information in Capacity Scheduler queue metrics | Major | . | Eric Payne | Eric Payne |
+| [MAPREDUCE-7048](https://issues.apache.org/jira/browse/MAPREDUCE-7048) | Uber AM can crash due to unknown task in statusUpdate | Major | mr-am | Peter Bacsko | Peter Bacsko |
+| [HADOOP-13972](https://issues.apache.org/jira/browse/HADOOP-13972) | ADLS to support per-store configuration | Major | fs/adl | John Zhuge | Sharad Sonker |
+| [YARN-7813](https://issues.apache.org/jira/browse/YARN-7813) | Capacity Scheduler Intra-queue Preemption should be configurable for each queue | Major | capacity scheduler, scheduler preemption | Eric Payne | Eric Payne |
+| [HADOOP-15235](https://issues.apache.org/jira/browse/HADOOP-15235) | Authentication Tokens should use HMAC instead of MAC | Major | security | Robert Kanter | Robert Kanter |
+| [HDFS-11187](https://issues.apache.org/jira/browse/HDFS-11187) | Optimize disk access for last partial chunk checksum of Finalized replica | Major | datanode | Wei-Chiu Chuang | Gabor Bota |
+| [HADOOP-15266](https://issues.apache.org/jira/browse/HADOOP-15266) | [branch-2] Upper/Lower case conversion support for group names in LdapGroupsMapping | Major | . | Nanda kumar | Nanda kumar |
+| [HADOOP-15279](https://issues.apache.org/jira/browse/HADOOP-15279) | increase maven heap size recommendations | Minor | build, documentation, test | Allen Wittenauer | Allen Wittenauer |
+| [HDFS-12884](https://issues.apache.org/jira/browse/HDFS-12884) | BlockUnderConstructionFeature.truncateBlock should be of type BlockInfo | Major | namenode | Konstantin Shvachko | chencan |
+| [HADOOP-15334](https://issues.apache.org/jira/browse/HADOOP-15334) | Upgrade Maven surefire plugin | Major | build | Arpit Agarwal | Arpit Agarwal |
+| [HADOOP-15312](https://issues.apache.org/jira/browse/HADOOP-15312) | Undocumented KeyProvider configuration keys | Major | . | Wei-Chiu Chuang | LiXin Ge |
+| [YARN-7623](https://issues.apache.org/jira/browse/YARN-7623) | Fix the CapacityScheduler Queue configuration documentation | Major | . | Arun Suresh | Jonathan Hung |
+| [HDFS-13314](https://issues.apache.org/jira/browse/HDFS-13314) | NameNode should optionally exit if it detects FsImage corruption | Major | namenode | Arpit Agarwal | Arpit Agarwal |
+| [HDFS-13418](https://issues.apache.org/jira/browse/HDFS-13418) | NetworkTopology should be configurable when enable DFSNetworkTopology | Major | . | Tao Jie | Tao Jie |
+| [HADOOP-15394](https://issues.apache.org/jira/browse/HADOOP-15394) | Backport PowerShell NodeFencer HADOOP-14309 to branch-2 | Minor | . | Íñigo Goiri | Íñigo Goiri |
+| [HDFS-13462](https://issues.apache.org/jira/browse/HDFS-13462) | Add BIND\_HOST configuration for JournalNode's HTTP and RPC Servers | Major | hdfs, journal-node | Lukas Majercak | Lukas Majercak |
+| [HDFS-13492](https://issues.apache.org/jira/browse/HDFS-13492) | Limit httpfs binds to certain IP addresses in branch-2 | Major | httpfs | Wei-Chiu Chuang | Wei-Chiu Chuang |
+| [HDFS-12981](https://issues.apache.org/jira/browse/HDFS-12981) | renameSnapshot a Non-Existent snapshot to itself should throw error | Minor | hdfs | Sailesh Patel | Kitti Nanasi |
+| [HADOOP-15441](https://issues.apache.org/jira/browse/HADOOP-15441) | Log kms url and token service at debug level. | Minor | . | Wei-Chiu Chuang | Gabor Bota |
+| [HDFS-13544](https://issues.apache.org/jira/browse/HDFS-13544) | Improve logging for JournalNode in federated cluster | Major | federation, hdfs | Hanisha Koneru | Hanisha Koneru |
+| [YARN-8249](https://issues.apache.org/jira/browse/YARN-8249) | Few REST api's in RMWebServices are missing static user check | Critical | webapp, yarn | Sunil G | Sunil G |
+| [HADOOP-15486](https://issues.apache.org/jira/browse/HADOOP-15486) | Make NetworkTopology#netLock fair | Major | net | Nanda kumar | Nanda kumar |
+| [HADOOP-15449](https://issues.apache.org/jira/browse/HADOOP-15449) | Increase default timeout of ZK session to avoid frequent NameNode failover | Critical | common | Karthik Palanisamy | Karthik Palanisamy |
+| [HDFS-13602](https://issues.apache.org/jira/browse/HDFS-13602) | Add checkOperation(WRITE) checks in FSNamesystem | Major | ha, namenode | Erik Krogen | Chao Sun |
+| [HDFS-13644](https://issues.apache.org/jira/browse/HDFS-13644) | Backport HDFS-10376 to branch-2 | Major | . | Yiqun Lin | Zsolt Venczel |
+| [HDFS-13653](https://issues.apache.org/jira/browse/HDFS-13653) | Make dfs.client.failover.random.order a per nameservice configuration | Major | federation | Ekanth Sethuramalingam | Ekanth Sethuramalingam |
+| [HDFS-13686](https://issues.apache.org/jira/browse/HDFS-13686) | Add overall metrics for FSNamesystemLock | Major | hdfs, namenode | Lukas Majercak | Lukas Majercak |
+| [HDFS-13714](https://issues.apache.org/jira/browse/HDFS-13714) | Fix TestNameNodePrunesMissingStorages test failures on Windows | Major | hdfs, namenode, test | Lukas Majercak | Lukas Majercak |
+| [HDFS-13719](https://issues.apache.org/jira/browse/HDFS-13719) | Docs around dfs.image.transfer.timeout are misleading | Major | documentation | Kitti Nanasi | Kitti Nanasi |
+| [HDFS-11060](https://issues.apache.org/jira/browse/HDFS-11060) | make DEFAULT\_MAX\_CORRUPT\_FILEBLOCKS\_RETURNED configurable | Minor | hdfs | Lantao Jin | Lantao Jin |
+| [YARN-8155](https://issues.apache.org/jira/browse/YARN-8155) | Improve ATSv2 client logging in RM and NM publisher | Major | . | Rohith Sharma K S | Abhishek Modi |
+| [HDFS-13814](https://issues.apache.org/jira/browse/HDFS-13814) | Remove super user privilege requirement for NameNode.getServiceStatus | Minor | namenode | Chao Sun | Chao Sun |
+| [YARN-8559](https://issues.apache.org/jira/browse/YARN-8559) | Expose mutable-conf scheduler's configuration in RM /scheduler-conf endpoint | Major | resourcemanager | Anna Savarin | Weiwei Yang |
+| [HDFS-13813](https://issues.apache.org/jira/browse/HDFS-13813) | Exit NameNode if dangling child inode is detected when saving FsImage | Major | hdfs, namenode | Siyao Meng | Siyao Meng |
+| [HDFS-13821](https://issues.apache.org/jira/browse/HDFS-13821) | RBF: Add dfs.federation.router.mount-table.cache.enable so that users can disable cache | Major | hdfs | Fei Hui | Fei Hui |
+| [HADOOP-15689](https://issues.apache.org/jira/browse/HADOOP-15689) | Add "\*.patch" into .gitignore file of branch-2 | Major | . | Rui Gao | Rui Gao |
+| [HDFS-13831](https://issues.apache.org/jira/browse/HDFS-13831) | Make block increment deletion number configurable | Major | . | Yiqun Lin | Ryan Wu |
+| [YARN-8051](https://issues.apache.org/jira/browse/YARN-8051) | TestRMEmbeddedElector#testCallbackSynchronization is flakey | Major | test | Robert Kanter | Robert Kanter |
+| [HADOOP-15547](https://issues.apache.org/jira/browse/HADOOP-15547) | WASB: improve listStatus performance | Major | fs/azure | Thomas Marqardt | Thomas Marqardt |
+| [HDFS-13857](https://issues.apache.org/jira/browse/HDFS-13857) | RBF: Choose to enable the default nameservice to read/write files | Major | federation, hdfs | yanghuafeng | yanghuafeng |
+| [HDFS-13812](https://issues.apache.org/jira/browse/HDFS-13812) | Fix the inconsistent default refresh interval on Caching documentation | Trivial | documentation | David Mollitor | Hrishikesh Gadre |
+| [HADOOP-15657](https://issues.apache.org/jira/browse/HADOOP-15657) | Registering MutableQuantiles via Metric annotation | Major | metrics | Sushil Ks | Sushil Ks |
+| [HDFS-13902](https://issues.apache.org/jira/browse/HDFS-13902) | Add JMX, conf and stacks menus to the datanode page | Minor | datanode | fengchuang | fengchuang |
+| [HADOOP-15726](https://issues.apache.org/jira/browse/HADOOP-15726) | Create utility to limit frequency of log statements | Major | common, util | Erik Krogen | Erik Krogen |
+| [YARN-7974](https://issues.apache.org/jira/browse/YARN-7974) | Allow updating application tracking url after registration | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-8750](https://issues.apache.org/jira/browse/YARN-8750) | Refactor TestQueueMetrics | Minor | resourcemanager | Szilard Nemeth | Szilard Nemeth |
+| [YARN-8896](https://issues.apache.org/jira/browse/YARN-8896) | Limit the maximum number of container assignments per heartbeat | Major | . | Weiwei Yang | Zhankun Tang |
+| [HADOOP-15804](https://issues.apache.org/jira/browse/HADOOP-15804) | upgrade to commons-compress 1.18 | Major | . | PJ Fanning | Akira Ajisaka |
+| [YARN-8915](https://issues.apache.org/jira/browse/YARN-8915) | Update the doc about the default value of "maximum-container-assignments" for capacity scheduler | Minor | . | Zhankun Tang | Zhankun Tang |
+| [YARN-7225](https://issues.apache.org/jira/browse/YARN-7225) | Add queue and partition info to RM audit log | Major | resourcemanager | Jonathan Hung | Eric Payne |
+| [HADOOP-15919](https://issues.apache.org/jira/browse/HADOOP-15919) | AliyunOSS: Enable Yarn to use OSS | Major | fs/oss | wujinhu | wujinhu |
+| [HADOOP-15943](https://issues.apache.org/jira/browse/HADOOP-15943) | AliyunOSS: add missing owner & group attributes for oss FileStatus | Major | fs/oss | wujinhu | wujinhu |
+| [YARN-9036](https://issues.apache.org/jira/browse/YARN-9036) | Escape newlines in health report in YARN UI | Major | . | Jonathan Hung | Keqiu Hu |
+| [YARN-9085](https://issues.apache.org/jira/browse/YARN-9085) | Add Guaranteed and MaxCapacity to CSQueueMetrics | Major | . | Jonathan Hung | Jonathan Hung |
+| [HDFS-14171](https://issues.apache.org/jira/browse/HDFS-14171) | Performance improvement in Tailing EditLog | Major | namenode | Kenneth Yang | Kenneth Yang |
+| [HADOOP-15481](https://issues.apache.org/jira/browse/HADOOP-15481) | Emit FairCallQueue stats as metrics | Major | metrics, rpc-server | Erik Krogen | Christopher Gregorian |
+| [HADOOP-15617](https://issues.apache.org/jira/browse/HADOOP-15617) | Node.js and npm package loading in the Dockerfile failing on branch-2 | Major | build | Allen Wittenauer | Akhil PB |
+| [HADOOP-16089](https://issues.apache.org/jira/browse/HADOOP-16089) | AliyunOSS: update oss-sdk version to 3.4.1 | Major | fs/oss | wujinhu | wujinhu |
+| [YARN-7171](https://issues.apache.org/jira/browse/YARN-7171) | RM UI should sort memory / cores numerically | Major | . | Eric Maynard | Ahmed Hussein |
+| [YARN-9282](https://issues.apache.org/jira/browse/YARN-9282) | Typo in javadoc of class LinuxContainerExecutor: hadoop.security.authetication should be 'authentication' | Trivial | . | Szilard Nemeth | Charan Hebri |
+| [HADOOP-16126](https://issues.apache.org/jira/browse/HADOOP-16126) | ipc.Client.stop() may sleep too long to wait for all connections | Major | ipc | Tsz-wo Sze | Tsz-wo Sze |
+| [HDFS-14247](https://issues.apache.org/jira/browse/HDFS-14247) | Repeat adding node description into network topology | Minor | datanode | HuangTao | HuangTao |
+| [YARN-9150](https://issues.apache.org/jira/browse/YARN-9150) | Making TimelineSchemaCreator support different backends for Timeline Schema Creation in ATSv2 | Major | ATSv2 | Sushil Ks | Sushil Ks |
+| [HDFS-14366](https://issues.apache.org/jira/browse/HDFS-14366) | Improve HDFS append performance | Major | hdfs | Chao Sun | Chao Sun |
+| [HDFS-14205](https://issues.apache.org/jira/browse/HDFS-14205) | Backport HDFS-6440 to branch-2 | Major | . | Chen Liang | Chao Sun |
+| [HDFS-14391](https://issues.apache.org/jira/browse/HDFS-14391) | Backport HDFS-9659 to branch-2 | Minor | . | Chao Sun | Chao Sun |
+| [HDFS-14415](https://issues.apache.org/jira/browse/HDFS-14415) | Backport HDFS-13799 to branch-2 | Trivial | . | Chao Sun | Chao Sun |
+| [HDFS-14432](https://issues.apache.org/jira/browse/HDFS-14432) | dfs.datanode.shared.file.descriptor.paths duplicated in hdfs-default.xml | Minor | hdfs | puleya7 | puleya7 |
+| [YARN-9529](https://issues.apache.org/jira/browse/YARN-9529) | Log correct cpu controller path on error while initializing CGroups. | Major | nodemanager | Jonathan Hung | Jonathan Hung |
+| [HDFS-14502](https://issues.apache.org/jira/browse/HDFS-14502) | keepResults option in NNThroughputBenchmark should call saveNamespace() | Major | benchmarks, hdfs | Konstantin Shvachko | Konstantin Shvachko |
+| [HADOOP-16323](https://issues.apache.org/jira/browse/HADOOP-16323) | https everywhere in Maven settings | Minor | build | Akira Ajisaka | Akira Ajisaka |
+| [YARN-9563](https://issues.apache.org/jira/browse/YARN-9563) | Resource report REST API could return NaN or Inf | Minor | . | Ahmed Hussein | Ahmed Hussein |
+| [HDFS-14513](https://issues.apache.org/jira/browse/HDFS-14513) | FSImage which is saving should be clean while NameNode shutdown | Major | namenode | Xiaoqiao He | Xiaoqiao He |
+| [HADOOP-16369](https://issues.apache.org/jira/browse/HADOOP-16369) | Fix zstandard shortname misspelled as zts | Major | . | Jonathan Turner Eagles | Jonathan Turner Eagles |
+| [HADOOP-16359](https://issues.apache.org/jira/browse/HADOOP-16359) | Bundle ZSTD native in branch-2 | Major | native | Chao Sun | Chao Sun |
+| [HADOOP-15253](https://issues.apache.org/jira/browse/HADOOP-15253) | Should update maxQueueSize when refresh call queue | Minor | . | Tao Jie | Tao Jie |
+| [HADOOP-16266](https://issues.apache.org/jira/browse/HADOOP-16266) | Add more fine-grained processing time metrics to the RPC layer | Minor | ipc | Christopher Gregorian | Erik Krogen |
+| [HDFS-13694](https://issues.apache.org/jira/browse/HDFS-13694) | Making md5 computing being in parallel with image loading | Major | . | zhouyingchao | Lisheng Sun |
+| [HDFS-14632](https://issues.apache.org/jira/browse/HDFS-14632) | Reduce useless #getNumLiveDataNodes call in SafeModeMonitor | Major | namenode | Xiaoqiao He | Xiaoqiao He |
+| [HDFS-14547](https://issues.apache.org/jira/browse/HDFS-14547) | DirectoryWithQuotaFeature.quota costs additional memory even the storage type quota is not set. | Major | . | Jinglun | Jinglun |
+| [HDFS-14697](https://issues.apache.org/jira/browse/HDFS-14697) | Backport HDFS-14513 to branch-2 | Minor | namenode | Xiaoqiao He | Xiaoqiao He |
+| [YARN-8045](https://issues.apache.org/jira/browse/YARN-8045) | Reduce log output from container status calls | Major | . | Shane Kumpf | Craig Condit |
+| [HDFS-14313](https://issues.apache.org/jira/browse/HDFS-14313) | Get hdfs used space from FsDatasetImpl#volumeMap#ReplicaInfo in memory instead of df/du | Major | datanode, performance | Lisheng Sun | Lisheng Sun |
+| [HDFS-14696](https://issues.apache.org/jira/browse/HDFS-14696) | Backport HDFS-11273 to branch-2 (Move TransferFsImage#doGetUrl function to a Util class) | Major | . | Siyao Meng | Siyao Meng |
+| [HDFS-14370](https://issues.apache.org/jira/browse/HDFS-14370) | Edit log tailing fast-path should allow for backoff | Major | namenode, qjm | Erik Krogen | Erik Krogen |
+| [YARN-9442](https://issues.apache.org/jira/browse/YARN-9442) | container working directory has group read permissions | Minor | yarn | Jim Brennan | Jim Brennan |
+| [HADOOP-16459](https://issues.apache.org/jira/browse/HADOOP-16459) | Backport [HADOOP-16266] "Add more fine-grained processing time metrics to the RPC layer" to branch-2 | Major | . | Erik Krogen | Erik Krogen |
+| [HDFS-14707](https://issues.apache.org/jira/browse/HDFS-14707) | Add JAVA\_LIBRARY\_PATH to HTTPFS startup options in branch-2 | Major | httpfs | Masatake Iwasaki | Masatake Iwasaki |
+| [HDFS-14723](https://issues.apache.org/jira/browse/HDFS-14723) | Add helper method FSNamesystem#setBlockManagerForTesting() in branch-2 | Blocker | namenode | Wei-Chiu Chuang | Wei-Chiu Chuang |
+| [HDFS-14276](https://issues.apache.org/jira/browse/HDFS-14276) | [SBN read] Reduce tailing overhead | Major | ha, namenode | Wei-Chiu Chuang | Ayush Saxena |
+| [HDFS-14617](https://issues.apache.org/jira/browse/HDFS-14617) | Improve fsimage load time by writing sub-sections to the fsimage index | Major | namenode | Stephen O'Donnell | Stephen O'Donnell |
+| [YARN-9756](https://issues.apache.org/jira/browse/YARN-9756) | Create metric that sums total memory/vcores preempted per round | Major | capacity scheduler | Eric Payne | Manikandan R |
+| [HDFS-14633](https://issues.apache.org/jira/browse/HDFS-14633) | The StorageType quota and consume in QuotaFeature is not handled for rename | Major | . | Jinglun | Jinglun |
+| [HADOOP-16439](https://issues.apache.org/jira/browse/HADOOP-16439) | Upgrade bundled Tomcat in branch-2 | Major | httpfs, kms | Masatake Iwasaki | Masatake Iwasaki |
+| [YARN-9810](https://issues.apache.org/jira/browse/YARN-9810) | Add queue capacity/maxcapacity percentage metrics | Major | . | Jonathan Hung | Shubham Gupta |
+| [YARN-9763](https://issues.apache.org/jira/browse/YARN-9763) | Print application tags in application summary | Major | . | Jonathan Hung | Manoj Kumar |
+| [YARN-9764](https://issues.apache.org/jira/browse/YARN-9764) | Print application submission context label in application summary | Major | . | Jonathan Hung | Manoj Kumar |
+| [HADOOP-16530](https://issues.apache.org/jira/browse/HADOOP-16530) | Update xercesImpl in branch-2 | Major | . | Wei-Chiu Chuang | Wei-Chiu Chuang |
+| [YARN-9824](https://issues.apache.org/jira/browse/YARN-9824) | Fall back to configured queue ordering policy class name | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-9825](https://issues.apache.org/jira/browse/YARN-9825) | Changes for initializing placement rules with ResourceScheduler in branch-2 | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-9762](https://issues.apache.org/jira/browse/YARN-9762) | Add submission context label to audit logs | Major | . | Jonathan Hung | Manoj Kumar |
+| [HDFS-14667](https://issues.apache.org/jira/browse/HDFS-14667) | Backport [HDFS-14403] "Cost-based FairCallQueue" to branch-2 | Major | . | Erik Krogen | Erik Krogen |
+
+
+### BUG FIXES:
+
+| JIRA | Summary | Priority | Component | Reporter | Contributor |
+|:---- |:---- | :--- |:---- |:---- |:---- |
+| [MAPREDUCE-6896](https://issues.apache.org/jira/browse/MAPREDUCE-6896) | Document wrong spelling in usage of MapredTestDriver tools. | Major | documentation | LiXin Ge | LiXin Ge |
+| [HDFS-12052](https://issues.apache.org/jira/browse/HDFS-12052) | Set SWEBHDFS delegation token kind when ssl is enabled in HttpFS | Major | httpfs, webhdfs | Zoran Dimitrijevic | Zoran Dimitrijevic |
+| [HDFS-12318](https://issues.apache.org/jira/browse/HDFS-12318) | Fix IOException condition for openInfo in DFSInputStream | Major | . | legend | legend |
+| [HDFS-12614](https://issues.apache.org/jira/browse/HDFS-12614) | FSPermissionChecker#getINodeAttrs() throws NPE when INodeAttributesProvider configured | Major | . | Manoj Govindassamy | Manoj Govindassamy |
+| [YARN-7396](https://issues.apache.org/jira/browse/YARN-7396) | NPE when accessing container logs due to null dirsHandler | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-7370](https://issues.apache.org/jira/browse/YARN-7370) | Preemption properties should be refreshable | Major | capacity scheduler, scheduler preemption | Eric Payne | Gergely Novák |
+| [YARN-7428](https://issues.apache.org/jira/browse/YARN-7428) | Add containerId to Localizer failed logs | Minor | nodemanager | Prabhu Joseph | Prabhu Joseph |
+| [YARN-7410](https://issues.apache.org/jira/browse/YARN-7410) | Cleanup FixedValueResource to avoid dependency to ResourceUtils | Major | resourcemanager | Sunil G | Wangda Tan |
+| [HDFS-12783](https://issues.apache.org/jira/browse/HDFS-12783) | [branch-2] "dfsrouter" should use hdfsScript | Major | . | Brahma Reddy Battula | Brahma Reddy Battula |
+| [HDFS-12788](https://issues.apache.org/jira/browse/HDFS-12788) | Reset the upload button when file upload fails | Critical | ui, webhdfs | Brahma Reddy Battula | Brahma Reddy Battula |
+| [YARN-7469](https://issues.apache.org/jira/browse/YARN-7469) | Capacity Scheduler Intra-queue preemption: User can starve if newest app is exactly at user limit | Major | capacity scheduler, yarn | Eric Payne | Eric Payne |
+| [HADOOP-14982](https://issues.apache.org/jira/browse/HADOOP-14982) | Clients using FailoverOnNetworkExceptionRetry can go into a loop if they're used without authenticating with kerberos in HA env | Major | common | Peter Bacsko | Peter Bacsko |
+| [YARN-7489](https://issues.apache.org/jira/browse/YARN-7489) | ConcurrentModificationException in RMAppImpl#getRMAppMetrics | Major | capacityscheduler | Tao Yang | Tao Yang |
+| [YARN-7525](https://issues.apache.org/jira/browse/YARN-7525) | Incorrect query parameters in cluster nodes REST API document | Minor | documentation | Tao Yang | Tao Yang |
+| [HDFS-12813](https://issues.apache.org/jira/browse/HDFS-12813) | RequestHedgingProxyProvider can hide Exception thrown from the Namenode for proxy size of 1 | Major | ha | Mukul Kumar Singh | Mukul Kumar Singh |
+| [HADOOP-15045](https://issues.apache.org/jira/browse/HADOOP-15045) | ISA-L build options are documented in branch-2 | Major | build, documentation | Akira Ajisaka | Akira Ajisaka |
+| [HADOOP-15067](https://issues.apache.org/jira/browse/HADOOP-15067) | GC time percentage reported in JvmMetrics should be a gauge, not counter | Major | . | Misha Dmitriev | Misha Dmitriev |
+| [YARN-7363](https://issues.apache.org/jira/browse/YARN-7363) | ContainerLocalizer doesn't have a valid log4j config when using LinuxContainerExecutor | Major | nodemanager | Yufei Gu | Yufei Gu |
+| [HDFS-12754](https://issues.apache.org/jira/browse/HDFS-12754) | Lease renewal can hit a deadlock | Major | . | Kuhu Shukla | Kuhu Shukla |
+| [HDFS-12832](https://issues.apache.org/jira/browse/HDFS-12832) | INode.getFullPathName may throw ArrayIndexOutOfBoundsException lead to NameNode exit | Critical | namenode | DENG FEI | Konstantin Shvachko |
+| [HDFS-11754](https://issues.apache.org/jira/browse/HDFS-11754) | Make FsServerDefaults cache configurable. | Minor | . | Rushabh Shah | Mikhail Erofeev |
+| [HADOOP-15042](https://issues.apache.org/jira/browse/HADOOP-15042) | Azure PageBlobInputStream.skip() can return negative value when numberOfPagesRemaining is 0 | Minor | fs/azure | Rajesh Balamohan | Rajesh Balamohan |
+| [HDFS-12638](https://issues.apache.org/jira/browse/HDFS-12638) | Delete copy-on-truncate block along with the original block, when deleting a file being truncated | Blocker | hdfs | Jiandan Yang | Konstantin Shvachko |
+| [YARN-4813](https://issues.apache.org/jira/browse/YARN-4813) | TestRMWebServicesDelegationTokenAuthentication.testDoAs fails intermittently | Major | resourcemanager | Daniel Templeton | Gergo Repas |
+| [MAPREDUCE-5124](https://issues.apache.org/jira/browse/MAPREDUCE-5124) | AM lacks flow control for task events | Major | mr-am | Jason Darrell Lowe | Peter Bacsko |
+| [YARN-7455](https://issues.apache.org/jira/browse/YARN-7455) | quote\_and\_append\_arg can overflow buffer | Major | nodemanager | Jason Darrell Lowe | Jim Brennan |
+| [YARN-7594](https://issues.apache.org/jira/browse/YARN-7594) | TestNMWebServices#testGetNMResourceInfo fails on trunk | Major | nodemanager, webapp | Gergely Novák | Gergely Novák |
+| [YARN-5594](https://issues.apache.org/jira/browse/YARN-5594) | Handle old RMDelegationToken format when recovering RM | Major | resourcemanager | Tatyana But | Robert Kanter |
+| [HADOOP-14985](https://issues.apache.org/jira/browse/HADOOP-14985) | Remove subversion related code from VersionInfoMojo.java | Minor | build | Akira Ajisaka | Ajay Kumar |
+| [HDFS-11751](https://issues.apache.org/jira/browse/HDFS-11751) | DFSZKFailoverController daemon exits with wrong status code | Major | auto-failover | Doris Gu | Bharat Viswanadham |
+| [HDFS-12889](https://issues.apache.org/jira/browse/HDFS-12889) | Router UI is missing robots.txt file | Major | . | Bharat Viswanadham | Bharat Viswanadham |
+| [YARN-7607](https://issues.apache.org/jira/browse/YARN-7607) | Remove the trailing duplicated timestamp in container diagnostics message | Minor | nodemanager | Weiwei Yang | Weiwei Yang |
+| [HADOOP-15080](https://issues.apache.org/jira/browse/HADOOP-15080) | Aliyun OSS: update oss sdk from 2.8.1 to 2.8.3 to remove its dependency on Cat-x "json-lib" | Blocker | fs/oss | Christopher Douglas | Sammi Chen |
+| [YARN-7608](https://issues.apache.org/jira/browse/YARN-7608) | Incorrect sTarget column causing DataTable warning on RM application and scheduler web page | Major | resourcemanager, webapp | Weiwei Yang | Gergely Novák |
+| [HDFS-12833](https://issues.apache.org/jira/browse/HDFS-12833) | Distcp : Update the usage of delete option for dependency with update and overwrite option | Minor | distcp, hdfs | Harshakiran Reddy | usharani |
+| [YARN-7647](https://issues.apache.org/jira/browse/YARN-7647) | NM print inappropriate error log when node-labels is enabled | Minor | . | Yang Wang | Yang Wang |
+| [HDFS-12907](https://issues.apache.org/jira/browse/HDFS-12907) | Allow read-only access to reserved raw for non-superusers | Major | namenode | Daryn Sharp | Rushabh Shah |
+| [HDFS-12881](https://issues.apache.org/jira/browse/HDFS-12881) | Output streams closed with IOUtils suppressing write errors | Major | . | Jason Darrell Lowe | Ajay Kumar |
+| [YARN-7595](https://issues.apache.org/jira/browse/YARN-7595) | Container launching code suppresses close exceptions after writes | Major | nodemanager | Jason Darrell Lowe | Jim Brennan |
+| [HADOOP-15085](https://issues.apache.org/jira/browse/HADOOP-15085) | Output streams closed with IOUtils suppressing write errors | Major | . | Jason Darrell Lowe | Jim Brennan |
+| [HADOOP-15123](https://issues.apache.org/jira/browse/HADOOP-15123) | KDiag tries to load krb5.conf from KRB5CCNAME instead of KRB5\_CONFIG | Minor | security | Vipin Rathor | Vipin Rathor |
+| [YARN-7661](https://issues.apache.org/jira/browse/YARN-7661) | NodeManager metrics return wrong value after update node resource | Major | . | Yang Wang | Yang Wang |
+| [HDFS-12347](https://issues.apache.org/jira/browse/HDFS-12347) | TestBalancerRPCDelay#testBalancerRPCDelay fails very frequently | Critical | test | Xiao Chen | Bharat Viswanadham |
+| [YARN-7662](https://issues.apache.org/jira/browse/YARN-7662) | [Atsv2] Define new set of configurations for reader and collectors to bind. | Major | . | Rohith Sharma K S | Rohith Sharma K S |
+| [YARN-7674](https://issues.apache.org/jira/browse/YARN-7674) | Update Timeline Reader web app address in UI2 | Major | . | Rohith Sharma K S | Sunil G |
+| [YARN-7542](https://issues.apache.org/jira/browse/YARN-7542) | Fix issue that causes some Running Opportunistic Containers to be recovered as PAUSED | Major | . | Arun Suresh | Sampada Dehankar |
+| [HADOOP-15143](https://issues.apache.org/jira/browse/HADOOP-15143) | NPE due to Invalid KerberosTicket in UGI | Major | . | Jitendra Nath Pandey | Mukul Kumar Singh |
+| [YARN-7692](https://issues.apache.org/jira/browse/YARN-7692) | Skip validating priority acls while recovering applications | Blocker | resourcemanager | Charan Hebri | Sunil G |
+| [MAPREDUCE-7028](https://issues.apache.org/jira/browse/MAPREDUCE-7028) | Concurrent task progress updates causing NPE in Application Master | Blocker | mr-am | Gergo Repas | Gergo Repas |
+| [YARN-7619](https://issues.apache.org/jira/browse/YARN-7619) | Max AM Resource value in Capacity Scheduler UI has to be refreshed for every user | Major | capacity scheduler, yarn | Eric Payne | Eric Payne |
+| [YARN-7699](https://issues.apache.org/jira/browse/YARN-7699) | queueUsagePercentage is coming as INF for getApp REST api call | Major | webapp | Sunil G | Sunil G |
+| [HDFS-12985](https://issues.apache.org/jira/browse/HDFS-12985) | NameNode crashes during restart after an OpenForWrite file present in the Snapshot got deleted | Major | hdfs | Manoj Govindassamy | Manoj Govindassamy |
+| [YARN-4227](https://issues.apache.org/jira/browse/YARN-4227) | Ignore expired containers from removed nodes in FairScheduler | Critical | fairscheduler | Wilfred Spiegelenburg | Wilfred Spiegelenburg |
+| [YARN-7508](https://issues.apache.org/jira/browse/YARN-7508) | NPE in FiCaSchedulerApp when debug log enabled in async-scheduling mode | Major | capacityscheduler | Tao Yang | Tao Yang |
+| [YARN-7663](https://issues.apache.org/jira/browse/YARN-7663) | RMAppImpl:Invalid event: START at KILLED | Major | resourcemanager | lujie | lujie |
+| [YARN-6948](https://issues.apache.org/jira/browse/YARN-6948) | Invalid event: ATTEMPT\_ADDED at FINAL\_SAVING | Major | yarn | lujie | lujie |
+| [HADOOP-15060](https://issues.apache.org/jira/browse/HADOOP-15060) | TestShellBasedUnixGroupsMapping.testFiniteGroupResolutionTime flaky | Major | . | Miklos Szegedi | Miklos Szegedi |
+| [YARN-7735](https://issues.apache.org/jira/browse/YARN-7735) | Fix typo in YARN documentation | Minor | documentation | Takanobu Asanuma | Takanobu Asanuma |
+| [YARN-7727](https://issues.apache.org/jira/browse/YARN-7727) | Incorrect log levels in few logs with QueuePriorityContainerCandidateSelector | Minor | yarn | Prabhu Joseph | Prabhu Joseph |
+| [HDFS-11915](https://issues.apache.org/jira/browse/HDFS-11915) | Sync rbw dir on the first hsync() to avoid file lost on power failure | Critical | . | Kanaka Kumar Avvaru | Vinayakumar B |
+| [YARN-7705](https://issues.apache.org/jira/browse/YARN-7705) | Create the container log directory with correct sticky bit in C code | Major | nodemanager | Yufei Gu | Yufei Gu |
+| [HDFS-9049](https://issues.apache.org/jira/browse/HDFS-9049) | Make Datanode Netty reverse proxy port to be configurable | Major | datanode | Vinayakumar B | Vinayakumar B |
+| [YARN-7758](https://issues.apache.org/jira/browse/YARN-7758) | Add an additional check to the validity of container and application ids passed to container-executor | Major | nodemanager | Miklos Szegedi | Yufei Gu |
+| [HADOOP-15150](https://issues.apache.org/jira/browse/HADOOP-15150) | in FsShell, UGI params should be overidden through env vars(-D arg) | Major | . | Brahma Reddy Battula | Brahma Reddy Battula |
+| [HADOOP-15181](https://issues.apache.org/jira/browse/HADOOP-15181) | Typo in SecureMode.md | Trivial | documentation | Masahiro Tanaka | Masahiro Tanaka |
+| [YARN-7806](https://issues.apache.org/jira/browse/YARN-7806) | Distributed Shell should use timeline async api's | Major | distributed-shell | Sumana Sathish | Rohith Sharma K S |
+| [HADOOP-15121](https://issues.apache.org/jira/browse/HADOOP-15121) | Encounter NullPointerException when using DecayRpcScheduler | Major | . | Tao Jie | Tao Jie |
+| [MAPREDUCE-7015](https://issues.apache.org/jira/browse/MAPREDUCE-7015) | Possible race condition in JHS if the job is not loaded | Major | jobhistoryserver | Peter Bacsko | Peter Bacsko |
+| [YARN-7737](https://issues.apache.org/jira/browse/YARN-7737) | prelaunch.err file not found exception on container failure | Major | . | Jonathan Hung | Keqiu Hu |
+| [HDFS-13063](https://issues.apache.org/jira/browse/HDFS-13063) | Fix the incorrect spelling in HDFSHighAvailabilityWithQJM.md | Trivial | documentation | Jianfei Jiang | Jianfei Jiang |
+| [YARN-7102](https://issues.apache.org/jira/browse/YARN-7102) | NM heartbeat stuck when responseId overflows MAX\_INT | Critical | . | Botong Huang | Botong Huang |
+| [MAPREDUCE-7041](https://issues.apache.org/jira/browse/MAPREDUCE-7041) | MR should not try to clean up at first job attempt | Major | . | Takanobu Asanuma | Gergo Repas |
+| [MAPREDUCE-7020](https://issues.apache.org/jira/browse/MAPREDUCE-7020) | Task timeout in uber mode can crash AM | Major | mr-am | Akira Ajisaka | Peter Bacsko |
+| [YARN-7765](https://issues.apache.org/jira/browse/YARN-7765) | [Atsv2] GSSException: No valid credentials provided - Failed to find any Kerberos tgt thrown by Timelinev2Client & HBaseClient in NM | Blocker | . | Sumana Sathish | Rohith Sharma K S |
+| [HDFS-12974](https://issues.apache.org/jira/browse/HDFS-12974) | Exception message is not printed when creating an encryption zone fails with AuthorizationException | Minor | encryption | fang zhenyi | fang zhenyi |
+| [YARN-7698](https://issues.apache.org/jira/browse/YARN-7698) | A misleading variable's name in ApplicationAttemptEventDispatcher | Minor | resourcemanager | Jinjiang Ling | Jinjiang Ling |
+| [HDFS-12528](https://issues.apache.org/jira/browse/HDFS-12528) | Add an option to not disable short-circuit reads on failures | Major | hdfs-client, performance | Andre Araujo | Xiao Chen |
+| [HDFS-13100](https://issues.apache.org/jira/browse/HDFS-13100) | Handle IllegalArgumentException when GETSERVERDEFAULTS is not implemented in webhdfs. | Critical | hdfs, webhdfs | Yongjun Zhang | Yongjun Zhang |
+| [YARN-7849](https://issues.apache.org/jira/browse/YARN-7849) | TestMiniYarnClusterNodeUtilization#testUpdateNodeUtilization fails due to heartbeat sync error | Major | test | Jason Darrell Lowe | Botong Huang |
+| [YARN-7801](https://issues.apache.org/jira/browse/YARN-7801) | AmFilterInitializer should addFilter after fill all parameters | Critical | . | Sumana Sathish | Wangda Tan |
+| [YARN-7890](https://issues.apache.org/jira/browse/YARN-7890) | NPE during container relaunch | Major | . | Billie Rinaldi | Jason Darrell Lowe |
+| [HDFS-13115](https://issues.apache.org/jira/browse/HDFS-13115) | In getNumUnderConstructionBlocks(), ignore the inodeIds for which the inodes have been deleted | Major | . | Yongjun Zhang | Yongjun Zhang |
+| [HDFS-12935](https://issues.apache.org/jira/browse/HDFS-12935) | Get ambiguous result for DFSAdmin command in HA mode when only one namenode is up | Major | tools | Jianfei Jiang | Jianfei Jiang |
+| [HDFS-13120](https://issues.apache.org/jira/browse/HDFS-13120) | Snapshot diff could be corrupted after concat | Major | namenode, snapshots | Xiaoyu Yao | Xiaoyu Yao |
+| [HDFS-10453](https://issues.apache.org/jira/browse/HDFS-10453) | ReplicationMonitor thread could stuck for long time due to the race between replication and delete of same file in a large cluster. | Major | namenode | Xiaoqiao He | Xiaoqiao He |
+| [HDFS-8693](https://issues.apache.org/jira/browse/HDFS-8693) | refreshNamenodes does not support adding a new standby to a running DN | Critical | datanode, ha | Jian Fang | Ajith S |
+| [MAPREDUCE-7052](https://issues.apache.org/jira/browse/MAPREDUCE-7052) | TestFixedLengthInputFormat#testFormatCompressedIn is flaky | Major | client, test | Peter Bacsko | Peter Bacsko |
+| [HDFS-13112](https://issues.apache.org/jira/browse/HDFS-13112) | Token expiration edits may cause log corruption or deadlock | Critical | namenode | Daryn Sharp | Daryn Sharp |
+| [MAPREDUCE-7053](https://issues.apache.org/jira/browse/MAPREDUCE-7053) | Timed out tasks can fail to produce thread dump | Major | . | Jason Darrell Lowe | Jason Darrell Lowe |
+| [HADOOP-15206](https://issues.apache.org/jira/browse/HADOOP-15206) | BZip2 drops and duplicates records when input split size is small | Major | . | Aki Tanaka | Aki Tanaka |
+| [YARN-7937](https://issues.apache.org/jira/browse/YARN-7937) | Fix http method name in Cluster Application Timeout Update API example request | Minor | docs, documentation | Charan Hebri | Charan Hebri |
+| [YARN-7947](https://issues.apache.org/jira/browse/YARN-7947) | Capacity Scheduler intra-queue preemption can NPE for non-schedulable apps | Major | capacity scheduler, scheduler preemption | Eric Payne | Eric Payne |
+| [YARN-7945](https://issues.apache.org/jira/browse/YARN-7945) | Java Doc error in UnmanagedAMPoolManager for branch-2 | Major | . | Rohith Sharma K S | Botong Huang |
+| [HADOOP-14903](https://issues.apache.org/jira/browse/HADOOP-14903) | Add json-smart explicitly to pom.xml | Major | common | Ray Chiang | Ray Chiang |
+| [HADOOP-15236](https://issues.apache.org/jira/browse/HADOOP-15236) | Fix typo in RequestHedgingProxyProvider and RequestHedgingRMFailoverProxyProvider | Trivial | documentation | Akira Ajisaka | Gabor Bota |
+| [MAPREDUCE-7027](https://issues.apache.org/jira/browse/MAPREDUCE-7027) | HadoopArchiveLogs shouldn't delete the original logs if the HAR creation fails | Critical | harchive | Gergely Novák | Gergely Novák |
+| [HDFS-12781](https://issues.apache.org/jira/browse/HDFS-12781) | After Datanode down, In Namenode UI Datanode tab is throwing warning message. | Major | datanode | Harshakiran Reddy | Brahma Reddy Battula |
+| [HDFS-12070](https://issues.apache.org/jira/browse/HDFS-12070) | Failed block recovery leaves files open indefinitely and at risk for data loss | Major | . | Daryn Sharp | Kihwal Lee |
+| [HADOOP-15251](https://issues.apache.org/jira/browse/HADOOP-15251) | Backport HADOOP-13514 (surefire upgrade) to branch-2 | Major | test | Christopher Douglas | Christopher Douglas |
+| [HDFS-13194](https://issues.apache.org/jira/browse/HDFS-13194) | CachePool permissions incorrectly checked | Major | . | Yiqun Lin | Jianfei Jiang |
+| [HADOOP-15276](https://issues.apache.org/jira/browse/HADOOP-15276) | branch-2 site not building after ADL troubleshooting doc added | Major | documentation | Steve Loughran | Steve Loughran |
+| [YARN-7835](https://issues.apache.org/jira/browse/YARN-7835) | [Atsv2] Race condition in NM while publishing events if second attempt is launched on the same node | Critical | . | Rohith Sharma K S | Rohith Sharma K S |
+| [HADOOP-15275](https://issues.apache.org/jira/browse/HADOOP-15275) | Incorrect javadoc for return type of RetryPolicy#shouldRetry | Minor | documentation | Nanda kumar | Nanda kumar |
+| [YARN-7511](https://issues.apache.org/jira/browse/YARN-7511) | NPE in ContainerLocalizer when localization failed for running container | Major | nodemanager | Tao Yang | Tao Yang |
+| [MAPREDUCE-7023](https://issues.apache.org/jira/browse/MAPREDUCE-7023) | TestHadoopArchiveLogs.testCheckFilesAndSeedApps fails on rerun | Minor | test | Gergely Novák | Gergely Novák |
+| [HADOOP-15283](https://issues.apache.org/jira/browse/HADOOP-15283) | Upgrade from findbugs 3.0.1 to spotbugs 3.1.2 in branch-2 to fix docker image build | Major | . | Xiao Chen | Akira Ajisaka |
+| [HADOOP-15286](https://issues.apache.org/jira/browse/HADOOP-15286) | Remove unused imports from TestKMSWithZK.java | Minor | test | Akira Ajisaka | Ajay Kumar |
+| [HDFS-13040](https://issues.apache.org/jira/browse/HDFS-13040) | Kerberized inotify client fails despite kinit properly | Major | namenode | Wei-Chiu Chuang | Xiao Chen |
+| [YARN-7736](https://issues.apache.org/jira/browse/YARN-7736) | Fix itemization in YARN federation document | Minor | documentation | Akira Ajisaka | Sen Zhao |
+| [HDFS-13164](https://issues.apache.org/jira/browse/HDFS-13164) | File not closed if streamer fail with DSQuotaExceededException | Major | hdfs-client | Xiao Chen | Xiao Chen |
+| [HDFS-13109](https://issues.apache.org/jira/browse/HDFS-13109) | Support fully qualified hdfs path in EZ commands | Major | hdfs | Hanisha Koneru | Hanisha Koneru |
+| [MAPREDUCE-6930](https://issues.apache.org/jira/browse/MAPREDUCE-6930) | mapreduce.map.cpu.vcores and mapreduce.reduce.cpu.vcores are both present twice in mapred-default.xml | Major | mrv2 | Daniel Templeton | Sen Zhao |
+| [HDFS-10618](https://issues.apache.org/jira/browse/HDFS-10618) | TestPendingReconstruction#testPendingAndInvalidate is flaky due to race condition | Major | . | Eric Badger | Eric Badger |
+| [HDFS-10803](https://issues.apache.org/jira/browse/HDFS-10803) | TestBalancerWithMultipleNameNodes#testBalancing2OutOf3Blockpools fails intermittently due to no free space available | Major | . | Yiqun Lin | Yiqun Lin |
+| [HDFS-12156](https://issues.apache.org/jira/browse/HDFS-12156) | TestFSImage fails without -Pnative | Major | test | Akira Ajisaka | Akira Ajisaka |
+| [HDFS-13261](https://issues.apache.org/jira/browse/HDFS-13261) | Fix incorrect null value check | Minor | hdfs | Jianfei Jiang | Jianfei Jiang |
+| [HDFS-12886](https://issues.apache.org/jira/browse/HDFS-12886) | Ignore minReplication for block recovery | Major | hdfs, namenode | Lukas Majercak | Lukas Majercak |
+| [YARN-8039](https://issues.apache.org/jira/browse/YARN-8039) | Clean up log dir configuration in TestLinuxContainerExecutorWithMocks.testStartLocalizer | Minor | . | Miklos Szegedi | Miklos Szegedi |
+| [HDFS-13296](https://issues.apache.org/jira/browse/HDFS-13296) | GenericTestUtils generates paths with drive letter in Windows and fail webhdfs related test cases | Major | . | Xiao Liang | Xiao Liang |
+| [HDFS-13268](https://issues.apache.org/jira/browse/HDFS-13268) | TestWebHdfsFileContextMainOperations fails on Windows | Major | . | Íñigo Goiri | Xiao Liang |
+| [YARN-8054](https://issues.apache.org/jira/browse/YARN-8054) | Improve robustness of the LocalDirsHandlerService MonitoringTimerTask thread | Major | . | Jonathan Turner Eagles | Jonathan Turner Eagles |
+| [YARN-7873](https://issues.apache.org/jira/browse/YARN-7873) | Revert YARN-6078 | Blocker | . | Billie Rinaldi | Billie Rinaldi |
+| [HDFS-13195](https://issues.apache.org/jira/browse/HDFS-13195) | DataNode conf page cannot display the current value after reconfig | Minor | datanode | maobaolong | maobaolong |
+| [YARN-8063](https://issues.apache.org/jira/browse/YARN-8063) | DistributedShellTimelinePlugin wrongly check for entityId instead of entityType | Major | . | Rohith Sharma K S | Rohith Sharma K S |
+| [YARN-8068](https://issues.apache.org/jira/browse/YARN-8068) | Application Priority field causes NPE in app timeline publish when Hadoop 2.7 based clients to 2.8+ | Blocker | yarn | Sunil G | Sunil G |
+| [HADOOP-12862](https://issues.apache.org/jira/browse/HADOOP-12862) | LDAP Group Mapping over SSL can not specify trust store | Major | . | Wei-Chiu Chuang | Wei-Chiu Chuang |
+| [HADOOP-15317](https://issues.apache.org/jira/browse/HADOOP-15317) | Improve NetworkTopology chooseRandom's loop | Major | . | Xiao Chen | Xiao Chen |
+| [HADOOP-15355](https://issues.apache.org/jira/browse/HADOOP-15355) | TestCommonConfigurationFields is broken by HADOOP-15312 | Major | test | Konstantin Shvachko | LiXin Ge |
+| [HDFS-13176](https://issues.apache.org/jira/browse/HDFS-13176) | WebHdfs file path gets truncated when having semicolon (;) inside | Major | webhdfs | Zsolt Venczel | Zsolt Venczel |
+| [HADOOP-15375](https://issues.apache.org/jira/browse/HADOOP-15375) | Branch-2 pre-commit failed to build docker image | Major | . | Xiao Chen | Xiao Chen |
+| [HADOOP-15357](https://issues.apache.org/jira/browse/HADOOP-15357) | Configuration.getPropsWithPrefix no longer does variable substitution | Major | . | Jim Brennan | Jim Brennan |
+| [MAPREDUCE-7062](https://issues.apache.org/jira/browse/MAPREDUCE-7062) | Update mapreduce.job.tags description for making use for ATSv2 purpose. | Major | . | Charan Hebri | Charan Hebri |
+| [YARN-8073](https://issues.apache.org/jira/browse/YARN-8073) | TimelineClientImpl doesn't honor yarn.timeline-service.versions configuration | Major | . | Rohith Sharma K S | Rohith Sharma K S |
+| [YARN-6629](https://issues.apache.org/jira/browse/YARN-6629) | NPE occurred when container allocation proposal is applied but its resource requests are removed before | Critical | . | Tao Yang | Tao Yang |
+| [HDFS-13427](https://issues.apache.org/jira/browse/HDFS-13427) | Fix the section titles of transparent encryption document | Minor | documentation | Akira Ajisaka | Akira Ajisaka |
+| [YARN-7527](https://issues.apache.org/jira/browse/YARN-7527) | Over-allocate node resource in async-scheduling mode of CapacityScheduler | Major | capacityscheduler | Tao Yang | Tao Yang |
+| [HDFS-7101](https://issues.apache.org/jira/browse/HDFS-7101) | Potential null dereference in DFSck#doWork() | Minor | . | Ted Yu | skrho |
+| [YARN-8120](https://issues.apache.org/jira/browse/YARN-8120) | JVM can crash with SIGSEGV when exiting due to custom leveldb logger | Major | nodemanager, resourcemanager | Jason Darrell Lowe | Jason Darrell Lowe |
+| [YARN-8147](https://issues.apache.org/jira/browse/YARN-8147) | TestClientRMService#testGetApplications sporadically fails | Major | test | Jason Darrell Lowe | Jason Darrell Lowe |
+| [HADOOP-14970](https://issues.apache.org/jira/browse/HADOOP-14970) | MiniHadoopClusterManager doesn't respect lack of format option | Minor | . | Erik Krogen | Erik Krogen |
+| [YARN-8156](https://issues.apache.org/jira/browse/YARN-8156) | Increase the default value of yarn.timeline-service.app-collector.linger-period.ms | Major | . | Rohith Sharma K S | Charan Hebri |
+| [YARN-8165](https://issues.apache.org/jira/browse/YARN-8165) | Incorrect queue name logging in AbstractContainerAllocator | Trivial | capacityscheduler | Weiwei Yang | Weiwei Yang |
+| [YARN-8164](https://issues.apache.org/jira/browse/YARN-8164) | Fix a potential NPE in AbstractSchedulerPlanFollower | Major | . | lujie | lujie |
+| [HDFS-12828](https://issues.apache.org/jira/browse/HDFS-12828) | OIV ReverseXML Processor fails with escaped characters | Critical | hdfs | Erik Krogen | Erik Krogen |
+| [HADOOP-15180](https://issues.apache.org/jira/browse/HADOOP-15180) | branch-2 : daemon processes' sysout overwrites 'ulimit -a' in daemon's out file | Minor | scripts | Ranith Sardar | Ranith Sardar |
+| [HADOOP-15396](https://issues.apache.org/jira/browse/HADOOP-15396) | Some java source files are executable | Minor | . | Akira Ajisaka | Shashikant Banerjee |
+| [YARN-6827](https://issues.apache.org/jira/browse/YARN-6827) | [ATS1/1.5] NPE exception while publishing recovering applications into ATS during RM restart. | Major | resourcemanager | Rohith Sharma K S | Rohith Sharma K S |
+| [YARN-7786](https://issues.apache.org/jira/browse/YARN-7786) | NullPointerException while launching ApplicationMaster | Major | . | lujie | lujie |
+| [HDFS-13408](https://issues.apache.org/jira/browse/HDFS-13408) | MiniDFSCluster to support being built on randomized base directory | Major | test | Xiao Liang | Xiao Liang |
+| [HADOOP-15390](https://issues.apache.org/jira/browse/HADOOP-15390) | Yarn RM logs flooded by DelegationTokenRenewer trying to renew KMS tokens | Critical | . | Xiao Chen | Xiao Chen |
+| [HDFS-13336](https://issues.apache.org/jira/browse/HDFS-13336) | Test cases of TestWriteToReplica failed in windows | Major | . | Xiao Liang | Xiao Liang |
+| [YARN-7598](https://issues.apache.org/jira/browse/YARN-7598) | Document how to use classpath isolation for aux-services in YARN | Major | . | Xuan Gong | Xuan Gong |
+| [YARN-8183](https://issues.apache.org/jira/browse/YARN-8183) | Fix ConcurrentModificationException inside RMAppAttemptMetrics#convertAtomicLongMaptoLongMap | Critical | yarn | Sumana Sathish | Suma Shivaprasad |
+| [HADOOP-15385](https://issues.apache.org/jira/browse/HADOOP-15385) | Many tests are failing in hadoop-distcp project in branch-2 | Critical | tools/distcp | Rushabh Shah | Jason Darrell Lowe |
+| [MAPREDUCE-7042](https://issues.apache.org/jira/browse/MAPREDUCE-7042) | Killed MR job data does not move to mapreduce.jobhistory.done-dir when ATS v2 is enabled | Major | . | Yesha Vora | Xuan Gong |
+| [YARN-8205](https://issues.apache.org/jira/browse/YARN-8205) | Application State is not updated to ATS if AM launching is delayed. | Critical | . | Sumana Sathish | Rohith Sharma K S |
+| [MAPREDUCE-7072](https://issues.apache.org/jira/browse/MAPREDUCE-7072) | mapred job -history prints duplicate counter in human output | Major | client | Wilfred Spiegelenburg | Wilfred Spiegelenburg |
+| [YARN-8221](https://issues.apache.org/jira/browse/YARN-8221) | RMWebServices also need to honor yarn.resourcemanager.display.per-user-apps | Major | webapp | Sunil G | Sunil G |
+| [HDFS-13509](https://issues.apache.org/jira/browse/HDFS-13509) | Bug fix for breakHardlinks() of ReplicaInfo/LocalReplica, and fix TestFileAppend failures on Windows | Major | . | Xiao Liang | Xiao Liang |
+| [MAPREDUCE-7073](https://issues.apache.org/jira/browse/MAPREDUCE-7073) | Optimize TokenCache#obtainTokensForNamenodesInternal | Major | . | Bibin Chundatt | Bibin Chundatt |
+| [YARN-8025](https://issues.apache.org/jira/browse/YARN-8025) | UsersManangers#getComputedResourceLimitForActiveUsers throws NPE due to preComputedActiveUserLimit is empty | Major | yarn | Jiandan Yang | Tao Yang |
+| [YARN-8232](https://issues.apache.org/jira/browse/YARN-8232) | RMContainer lost queue name when RM HA happens | Major | resourcemanager | Hu Ziqian | Hu Ziqian |
+| [HDFS-13537](https://issues.apache.org/jira/browse/HDFS-13537) | TestHdfsHelper does not generate jceks path properly for relative path in Windows | Major | . | Xiao Liang | Xiao Liang |
+| [HADOOP-15446](https://issues.apache.org/jira/browse/HADOOP-15446) | WASB: PageBlobInputStream.skip breaks HBASE replication | Major | fs/azure | Thomas Marqardt | Thomas Marqardt |
+| [YARN-8244](https://issues.apache.org/jira/browse/YARN-8244) | TestContainerSchedulerQueuing.testStartMultipleContainers failed | Major | . | Miklos Szegedi | Jim Brennan |
+| [HDFS-13586](https://issues.apache.org/jira/browse/HDFS-13586) | Fsync fails on directories on Windows | Critical | datanode, hdfs | Lukas Majercak | Lukas Majercak |
+| [HDFS-13590](https://issues.apache.org/jira/browse/HDFS-13590) | Backport HDFS-12378 to branch-2 | Major | datanode, hdfs, test | Lukas Majercak | Lukas Majercak |
+| [HADOOP-15478](https://issues.apache.org/jira/browse/HADOOP-15478) | WASB: hflush() and hsync() regression | Major | fs/azure | Thomas Marqardt | Thomas Marqardt |
+| [HADOOP-15450](https://issues.apache.org/jira/browse/HADOOP-15450) | Avoid fsync storm triggered by DiskChecker and handle disk full situation | Blocker | . | Kihwal Lee | Arpit Agarwal |
+| [HDFS-13601](https://issues.apache.org/jira/browse/HDFS-13601) | Optimize ByteString conversions in PBHelper | Major | . | Andrew Wang | Andrew Wang |
+| [HDFS-13588](https://issues.apache.org/jira/browse/HDFS-13588) | Fix TestFsDatasetImpl test failures on Windows | Major | . | Xiao Liang | Xiao Liang |
+| [YARN-8310](https://issues.apache.org/jira/browse/YARN-8310) | Handle old NMTokenIdentifier, AMRMTokenIdentifier, and ContainerTokenIdentifier formats | Major | . | Robert Kanter | Robert Kanter |
+| [YARN-8344](https://issues.apache.org/jira/browse/YARN-8344) | Missing nm.stop() in TestNodeManagerResync to fix testKillContainersOnResync | Major | . | Giovanni Matteo Fumarola | Giovanni Matteo Fumarola |
+| [YARN-8327](https://issues.apache.org/jira/browse/YARN-8327) | Fix TestAggregatedLogFormat#testReadAcontainerLogs1 on Windows | Major | log-aggregation | Giovanni Matteo Fumarola | Giovanni Matteo Fumarola |
+| [YARN-8346](https://issues.apache.org/jira/browse/YARN-8346) | Upgrading to 3.1 kills running containers with error "Opportunistic container queue is full" | Blocker | . | Rohith Sharma K S | Jason Darrell Lowe |
+| [HDFS-13611](https://issues.apache.org/jira/browse/HDFS-13611) | Unsafe use of Text as a ConcurrentHashMap key in PBHelperClient | Major | . | Andrew Wang | Andrew Wang |
+| [HDFS-13618](https://issues.apache.org/jira/browse/HDFS-13618) | Fix TestDataNodeFaultInjector test failures on Windows | Major | test | Xiao Liang | Xiao Liang |
+| [HADOOP-15473](https://issues.apache.org/jira/browse/HADOOP-15473) | Configure serialFilter in KeyProvider to avoid UnrecoverableKeyException caused by JDK-8189997 | Critical | kms | Gabor Bota | Gabor Bota |
+| [HDFS-13626](https://issues.apache.org/jira/browse/HDFS-13626) | Fix incorrect username when deny the setOwner operation | Minor | namenode | luhuachao | Zsolt Venczel |
+| [MAPREDUCE-7103](https://issues.apache.org/jira/browse/MAPREDUCE-7103) | Fix TestHistoryViewerPrinter on windows due to a mismatch line separator | Minor | . | Giovanni Matteo Fumarola | Giovanni Matteo Fumarola |
+| [YARN-8359](https://issues.apache.org/jira/browse/YARN-8359) | Exclude containermanager.linux test classes on Windows | Major | . | Giovanni Matteo Fumarola | Jason Darrell Lowe |
+| [HDFS-13664](https://issues.apache.org/jira/browse/HDFS-13664) | Refactor ConfiguredFailoverProxyProvider to make inheritance easier | Minor | hdfs-client | Chao Sun | Chao Sun |
+| [YARN-8405](https://issues.apache.org/jira/browse/YARN-8405) | RM zk-state-store.parent-path ACLs has been changed since HADOOP-14773 | Major | . | Rohith Sharma K S | Íñigo Goiri |
+| [MAPREDUCE-7108](https://issues.apache.org/jira/browse/MAPREDUCE-7108) | TestFileOutputCommitter fails on Windows | Minor | test | Zuoming Zhang | Zuoming Zhang |
+| [MAPREDUCE-7101](https://issues.apache.org/jira/browse/MAPREDUCE-7101) | Add config parameter to allow JHS to alway scan user dir irrespective of modTime | Critical | . | Wangda Tan | Thomas Marqardt |
+| [YARN-8404](https://issues.apache.org/jira/browse/YARN-8404) | Timeline event publish need to be async to avoid Dispatcher thread leak in case ATS is down | Blocker | . | Rohith Sharma K S | Rohith Sharma K S |
+| [HDFS-13675](https://issues.apache.org/jira/browse/HDFS-13675) | Speed up TestDFSAdminWithHA | Major | hdfs, namenode | Lukas Majercak | Lukas Majercak |
+| [HDFS-13673](https://issues.apache.org/jira/browse/HDFS-13673) | TestNameNodeMetrics fails on Windows | Minor | test | Zuoming Zhang | Zuoming Zhang |
+| [HDFS-13676](https://issues.apache.org/jira/browse/HDFS-13676) | TestEditLogRace fails on Windows | Minor | test | Zuoming Zhang | Zuoming Zhang |
+| [HADOOP-15523](https://issues.apache.org/jira/browse/HADOOP-15523) | Shell command timeout given is in seconds whereas it is taken as millisec while scheduling | Major | . | Bilwa S T | Bilwa S T |
+| [YARN-8444](https://issues.apache.org/jira/browse/YARN-8444) | NodeResourceMonitor crashes on bad swapFree value | Major | . | Jim Brennan | Jim Brennan |
+| [YARN-8457](https://issues.apache.org/jira/browse/YARN-8457) | Compilation is broken with -Pyarn-ui | Major | webapp | Sunil G | Sunil G |
+| [YARN-8401](https://issues.apache.org/jira/browse/YARN-8401) | [UI2] new ui is not accessible with out internet connection | Blocker | . | Bibin Chundatt | Bibin Chundatt |
+| [YARN-8451](https://issues.apache.org/jira/browse/YARN-8451) | Multiple NM heartbeat thread created when a slow NM resync with RM | Major | nodemanager | Botong Huang | Botong Huang |
+| [HADOOP-15548](https://issues.apache.org/jira/browse/HADOOP-15548) | Randomize local dirs | Minor | . | Jim Brennan | Jim Brennan |
+| [YARN-8473](https://issues.apache.org/jira/browse/YARN-8473) | Containers being launched as app tears down can leave containers in NEW state | Major | nodemanager | Jason Darrell Lowe | Jason Darrell Lowe |
+| [HDFS-13729](https://issues.apache.org/jira/browse/HDFS-13729) | Fix broken links to RBF documentation | Minor | documentation | jwhitter | Gabor Bota |
+| [YARN-8515](https://issues.apache.org/jira/browse/YARN-8515) | container-executor can crash with SIGPIPE after nodemanager restart | Major | . | Jim Brennan | Jim Brennan |
+| [YARN-8421](https://issues.apache.org/jira/browse/YARN-8421) | when moving app, activeUsers is increased, even though app does not have outstanding request | Major | . | kyungwan nam | |
+| [HADOOP-15614](https://issues.apache.org/jira/browse/HADOOP-15614) | TestGroupsCaching.testExceptionOnBackgroundRefreshHandled reliably fails | Major | . | Kihwal Lee | Weiwei Yang |
+| [YARN-4606](https://issues.apache.org/jira/browse/YARN-4606) | CapacityScheduler: applications could get starved because computation of #activeUsers considers pending apps | Critical | capacity scheduler, capacityscheduler | Karam Singh | Manikandan R |
+| [HADOOP-15637](https://issues.apache.org/jira/browse/HADOOP-15637) | LocalFs#listLocatedStatus does not filter out hidden .crc files | Minor | fs | Erik Krogen | Erik Krogen |
+| [HADOOP-15644](https://issues.apache.org/jira/browse/HADOOP-15644) | Hadoop Docker Image Pip Install Fails on branch-2 | Critical | build | Haibo Chen | Haibo Chen |
+| [YARN-6966](https://issues.apache.org/jira/browse/YARN-6966) | NodeManager metrics may return wrong negative values when NM restart | Major | . | Yang Wang | Szilard Nemeth |
+| [YARN-8331](https://issues.apache.org/jira/browse/YARN-8331) | Race condition in NM container launched after done | Major | . | Yang Wang | Pradeep Ambati |
+| [HDFS-13758](https://issues.apache.org/jira/browse/HDFS-13758) | DatanodeManager should throw exception if it has BlockRecoveryCommand but the block is not under construction | Major | namenode | Wei-Chiu Chuang | chencan |
+| [YARN-8612](https://issues.apache.org/jira/browse/YARN-8612) | Fix NM Collector Service Port issue in YarnConfiguration | Major | ATSv2 | Prabha Manepalli | Prabha Manepalli |
+| [HADOOP-15674](https://issues.apache.org/jira/browse/HADOOP-15674) | Test failure TestSSLHttpServer.testExcludedCiphers with TLS\_ECDHE\_RSA\_WITH\_AES\_128\_CBC\_SHA256 cipher suite | Major | common | Gabor Bota | Szilard Nemeth |
+| [YARN-8640](https://issues.apache.org/jira/browse/YARN-8640) | Restore previous state in container-executor after failure | Major | . | Jim Brennan | Jim Brennan |
+| [YARN-8679](https://issues.apache.org/jira/browse/YARN-8679) | [ATSv2] If HBase cluster is down for long time, high chances that NM ContainerManager dispatcher get blocked | Major | . | Rohith Sharma K S | Wangda Tan |
+| [HADOOP-14314](https://issues.apache.org/jira/browse/HADOOP-14314) | The OpenSolaris taxonomy link is dead in InterfaceClassification.md | Major | documentation | Daniel Templeton | Rui Gao |
+| [YARN-8649](https://issues.apache.org/jira/browse/YARN-8649) | NPE in localizer hearbeat processing if a container is killed while localizing | Major | . | lujie | lujie |
+| [HADOOP-10219](https://issues.apache.org/jira/browse/HADOOP-10219) | ipc.Client.setupIOstreams() needs to check for ClientCache.stopClient requested shutdowns | Major | ipc | Steve Loughran | Kihwal Lee |
+| [MAPREDUCE-7131](https://issues.apache.org/jira/browse/MAPREDUCE-7131) | Job History Server has race condition where it moves files from intermediate to finished but thinks file is in intermediate | Major | . | Anthony Hsu | Anthony Hsu |
+| [HDFS-13836](https://issues.apache.org/jira/browse/HDFS-13836) | RBF: Handle mount table znode with null value | Major | federation, hdfs | yanghuafeng | yanghuafeng |
+| [HDFS-12716](https://issues.apache.org/jira/browse/HDFS-12716) | 'dfs.datanode.failed.volumes.tolerated' to support minimum number of volumes to be available | Major | datanode | usharani | Ranith Sardar |
+| [YARN-8709](https://issues.apache.org/jira/browse/YARN-8709) | CS preemption monitor always fails since one under-served queue was deleted | Major | capacityscheduler, scheduler preemption | Tao Yang | Tao Yang |
+| [HDFS-13051](https://issues.apache.org/jira/browse/HDFS-13051) | Fix dead lock during async editlog rolling if edit queue is full | Major | namenode | zhangwei | Daryn Sharp |
+| [HDFS-13914](https://issues.apache.org/jira/browse/HDFS-13914) | Fix DN UI logs link broken when https is enabled after HDFS-13902 | Minor | datanode | Jianfei Jiang | Jianfei Jiang |
+| [MAPREDUCE-7133](https://issues.apache.org/jira/browse/MAPREDUCE-7133) | History Server task attempts REST API returns invalid data | Major | jobhistoryserver | Oleksandr Shevchenko | Oleksandr Shevchenko |
+| [YARN-8720](https://issues.apache.org/jira/browse/YARN-8720) | CapacityScheduler does not enforce max resource allocation check at queue level | Major | capacity scheduler, capacityscheduler, resourcemanager | Tarun Parimi | Tarun Parimi |
+| [HDFS-13844](https://issues.apache.org/jira/browse/HDFS-13844) | Fix the fmt\_bytes function in the dfs-dust.js | Minor | hdfs, ui | yanghuafeng | yanghuafeng |
+| [HADOOP-15755](https://issues.apache.org/jira/browse/HADOOP-15755) | StringUtils#createStartupShutdownMessage throws NPE when args is null | Major | . | Lokesh Jain | Dinesh Chitlangia |
+| [MAPREDUCE-3801](https://issues.apache.org/jira/browse/MAPREDUCE-3801) | org.apache.hadoop.mapreduce.v2.app.TestRuntimeEstimators.testExponentialEstimator fails intermittently | Major | mrv2 | Robert Joseph Evans | Jason Darrell Lowe |
+| [MAPREDUCE-7137](https://issues.apache.org/jira/browse/MAPREDUCE-7137) | MRAppBenchmark.benchmark1() fails with NullPointerException | Minor | test | Oleksandr Shevchenko | Oleksandr Shevchenko |
+| [MAPREDUCE-7138](https://issues.apache.org/jira/browse/MAPREDUCE-7138) | ThrottledContainerAllocator in MRAppBenchmark should implement RMHeartbeatHandler | Minor | test | Oleksandr Shevchenko | Oleksandr Shevchenko |
+| [HDFS-13908](https://issues.apache.org/jira/browse/HDFS-13908) | TestDataNodeMultipleRegistrations is flaky | Major | . | Íñigo Goiri | Ayush Saxena |
+| [HADOOP-15772](https://issues.apache.org/jira/browse/HADOOP-15772) | Remove the 'Path ... should be specified as a URI' warnings on startup | Major | conf | Arpit Agarwal | Ayush Saxena |
+| [YARN-8804](https://issues.apache.org/jira/browse/YARN-8804) | resourceLimits may be wrongly calculated when leaf-queue is blocked in cluster with 3+ level queues | Critical | capacityscheduler | Tao Yang | Tao Yang |
+| [YARN-8774](https://issues.apache.org/jira/browse/YARN-8774) | Memory leak when CapacityScheduler allocates from reserved container with non-default label | Critical | capacityscheduler | Tao Yang | Tao Yang |
+| [YARN-8840](https://issues.apache.org/jira/browse/YARN-8840) | Add missing cleanupSSLConfig() call for TestTimelineClient test | Minor | test, timelineclient | Aki Tanaka | Aki Tanaka |
+| [HADOOP-15817](https://issues.apache.org/jira/browse/HADOOP-15817) | Reuse Object Mapper in KMSJSONReader | Major | kms | Jonathan Turner Eagles | Jonathan Turner Eagles |
+| [HADOOP-15820](https://issues.apache.org/jira/browse/HADOOP-15820) | ZStandardDecompressor native code sets an integer field as a long | Blocker | . | Jason Darrell Lowe | Jason Darrell Lowe |
+| [HDFS-13964](https://issues.apache.org/jira/browse/HDFS-13964) | RBF: TestRouterWebHDFSContractAppend fails with No Active Namenode under nameservice | Major | . | Ayush Saxena | Ayush Saxena |
+| [HDFS-13768](https://issues.apache.org/jira/browse/HDFS-13768) | Adding replicas to volume map makes DataNode start slowly | Major | . | Yiqun Lin | Surendra Singh Lilhore |
+| [HADOOP-15818](https://issues.apache.org/jira/browse/HADOOP-15818) | Fix deprecated maven-surefire-plugin configuration in hadoop-kms module | Minor | kms | Akira Ajisaka | Vidura Bhathiya Mudalige |
+| [HDFS-13802](https://issues.apache.org/jira/browse/HDFS-13802) | RBF: Remove FSCK from Router Web UI | Major | . | Fei Hui | Fei Hui |
+| [HADOOP-15859](https://issues.apache.org/jira/browse/HADOOP-15859) | ZStandardDecompressor.c mistakes a class for an instance | Blocker | . | Ben Lau | Jason Darrell Lowe |
+| [HADOOP-15850](https://issues.apache.org/jira/browse/HADOOP-15850) | CopyCommitter#concatFileChunks should check that the blocks per chunk is not 0 | Critical | tools/distcp | Ted Yu | Ted Yu |
+| [YARN-7502](https://issues.apache.org/jira/browse/YARN-7502) | Nodemanager restart docs should describe nodemanager supervised property | Major | documentation | Jason Darrell Lowe | Suma Shivaprasad |
+| [HADOOP-15866](https://issues.apache.org/jira/browse/HADOOP-15866) | Renamed HADOOP\_SECURITY\_GROUP\_SHELL\_COMMAND\_TIMEOUT keys break compatibility | Blocker | . | Wei-Chiu Chuang | Wei-Chiu Chuang |
+| [YARN-8826](https://issues.apache.org/jira/browse/YARN-8826) | Fix lingering timeline collector after serviceStop in TimelineCollectorManager | Trivial | ATSv2 | Prabha Manepalli | Prabha Manepalli |
+| [HADOOP-15822](https://issues.apache.org/jira/browse/HADOOP-15822) | zstd compressor can fail with a small output buffer | Major | . | Jason Darrell Lowe | Jason Darrell Lowe |
+| [HDFS-13959](https://issues.apache.org/jira/browse/HDFS-13959) | TestUpgradeDomainBlockPlacementPolicy is flaky | Major | . | Ayush Saxena | Ayush Saxena |
+| [HADOOP-15899](https://issues.apache.org/jira/browse/HADOOP-15899) | Update AWS Java SDK versions in NOTICE.txt | Major | . | Akira Ajisaka | Akira Ajisaka |
+| [HADOOP-15900](https://issues.apache.org/jira/browse/HADOOP-15900) | Update JSch versions in LICENSE.txt | Major | . | Akira Ajisaka | Akira Ajisaka |
+| [HDFS-14043](https://issues.apache.org/jira/browse/HDFS-14043) | Tolerate corrupted seen\_txid file | Major | hdfs, namenode | Lukas Majercak | Lukas Majercak |
+| [YARN-8858](https://issues.apache.org/jira/browse/YARN-8858) | CapacityScheduler should respect maximum node resource when per-queue maximum-allocation is being used. | Major | . | Sumana Sathish | Wangda Tan |
+| [HDFS-14048](https://issues.apache.org/jira/browse/HDFS-14048) | DFSOutputStream close() throws exception on subsequent call after DataNode restart | Major | hdfs-client | Erik Krogen | Erik Krogen |
+| [MAPREDUCE-7156](https://issues.apache.org/jira/browse/MAPREDUCE-7156) | NullPointerException when reaching max shuffle connections | Major | mrv2 | Peter Bacsko | Peter Bacsko |
+| [YARN-8233](https://issues.apache.org/jira/browse/YARN-8233) | NPE in CapacityScheduler#tryCommit when handling allocate/reserve proposal whose allocatedOrReservedContainer is null | Critical | capacityscheduler | Tao Yang | Tao Yang |
+| [HADOOP-15923](https://issues.apache.org/jira/browse/HADOOP-15923) | create-release script should set max-cache-ttl as well as default-cache-ttl for gpg-agent | Blocker | build | Akira Ajisaka | Akira Ajisaka |
+| [HADOOP-15930](https://issues.apache.org/jira/browse/HADOOP-15930) | Exclude MD5 checksum files from release artifact | Critical | build | Akira Ajisaka | Akira Ajisaka |
+| [HADOOP-15925](https://issues.apache.org/jira/browse/HADOOP-15925) | The config and log of gpg-agent are removed in create-release script | Major | build | Akira Ajisaka | Dinesh Chitlangia |
+| [HDFS-14056](https://issues.apache.org/jira/browse/HDFS-14056) | Fix error messages in HDFS-12716 | Minor | hdfs | Adam Antal | Ayush Saxena |
+| [YARN-7794](https://issues.apache.org/jira/browse/YARN-7794) | SLSRunner is not loading timeline service jars causing failure | Blocker | scheduler-load-simulator | Sunil G | Yufei Gu |
+| [HADOOP-16008](https://issues.apache.org/jira/browse/HADOOP-16008) | Fix typo in CommandsManual.md | Minor | . | Akira Ajisaka | Shweta |
+| [HADOOP-15973](https://issues.apache.org/jira/browse/HADOOP-15973) | Configuration: Included properties are not cached if resource is a stream | Critical | . | Eric Payne | Eric Payne |
+| [YARN-9175](https://issues.apache.org/jira/browse/YARN-9175) | Null resources check in ResourceInfo for branch-3.0 | Major | . | Jonathan Hung | Jonathan Hung |
+| [HADOOP-15992](https://issues.apache.org/jira/browse/HADOOP-15992) | JSON License is included in the transitive dependency of aliyun-sdk-oss 3.0.0 | Blocker | . | Akira Ajisaka | Akira Ajisaka |
+| [HADOOP-16030](https://issues.apache.org/jira/browse/HADOOP-16030) | AliyunOSS: bring fixes back from HADOOP-15671 | Blocker | fs/oss | wujinhu | wujinhu |
+| [YARN-9162](https://issues.apache.org/jira/browse/YARN-9162) | Fix TestRMAdminCLI#testHelp | Major | resourcemanager, test | Ayush Saxena | Ayush Saxena |
+| [YARN-8833](https://issues.apache.org/jira/browse/YARN-8833) | Avoid potential integer overflow when computing fair shares | Major | fairscheduler | liyakun | liyakun |
+| [HADOOP-16016](https://issues.apache.org/jira/browse/HADOOP-16016) | TestSSLFactory#testServerWeakCiphers sporadically fails in precommit builds | Major | security, test | Jason Darrell Lowe | Akira Ajisaka |
+| [HADOOP-16013](https://issues.apache.org/jira/browse/HADOOP-16013) | DecayRpcScheduler decay thread should run as a daemon | Major | ipc | Erik Krogen | Erik Krogen |
+| [YARN-8747](https://issues.apache.org/jira/browse/YARN-8747) | [UI2] YARN UI2 page loading failed due to js error under some time zone configuration | Critical | webapp | collinma | collinma |
+| [YARN-9210](https://issues.apache.org/jira/browse/YARN-9210) | RM nodes web page can not display node info | Blocker | yarn | Jiandan Yang | Jiandan Yang |
+| [YARN-7088](https://issues.apache.org/jira/browse/YARN-7088) | Add application launch time to Resource Manager REST API | Major | . | Abdullah Yousufi | Kanwaljeet Sachdev |
+| [YARN-9222](https://issues.apache.org/jira/browse/YARN-9222) | Print launchTime in ApplicationSummary | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-6616](https://issues.apache.org/jira/browse/YARN-6616) | YARN AHS shows submitTime for jobs same as startTime | Minor | . | Prabhu Joseph | Prabhu Joseph |
+| [MAPREDUCE-7177](https://issues.apache.org/jira/browse/MAPREDUCE-7177) | Disable speculative execution in TestDFSIO | Major | . | Kihwal Lee | Zhaohui Xin |
+| [YARN-9206](https://issues.apache.org/jira/browse/YARN-9206) | RMServerUtils does not count SHUTDOWN as an accepted state | Major | . | Kuhu Shukla | Kuhu Shukla |
+| [YARN-9283](https://issues.apache.org/jira/browse/YARN-9283) | Javadoc of LinuxContainerExecutor#addSchedPriorityCommand has a wrong property name as reference | Minor | documentation | Szilard Nemeth | Adam Antal |
+| [HADOOP-15813](https://issues.apache.org/jira/browse/HADOOP-15813) | Enable more reliable SSL connection reuse | Major | common | Daryn Sharp | Daryn Sharp |
+| [HDFS-14314](https://issues.apache.org/jira/browse/HDFS-14314) | fullBlockReportLeaseId should be reset after registering to NN | Critical | datanode | star | star |
+| [YARN-5714](https://issues.apache.org/jira/browse/YARN-5714) | ContainerExecutor does not order environment map | Trivial | nodemanager | Remi Catherinot | Remi Catherinot |
+| [HADOOP-16192](https://issues.apache.org/jira/browse/HADOOP-16192) | CallQueue backoff bug fixes: doesn't perform backoff when add() is used, and doesn't update backoff when refreshed | Major | ipc | Erik Krogen | Erik Krogen |
+| [HDFS-14399](https://issues.apache.org/jira/browse/HDFS-14399) | Backport HDFS-10536 to branch-2 | Critical | . | Chao Sun | Chao Sun |
+| [HDFS-14407](https://issues.apache.org/jira/browse/HDFS-14407) | Fix misuse of SLF4j logging API in DatasetVolumeChecker#checkAllVolumes | Minor | . | Wanqiang Ji | Wanqiang Ji |
+| [HDFS-14414](https://issues.apache.org/jira/browse/HDFS-14414) | Clean up findbugs warning in branch-2 | Major | . | Wei-Chiu Chuang | Dinesh Chitlangia |
+| [HADOOP-14544](https://issues.apache.org/jira/browse/HADOOP-14544) | DistCp documentation for command line options is misaligned. | Minor | documentation | Chris Nauroth | Masatake Iwasaki |
+| [HDFS-10477](https://issues.apache.org/jira/browse/HDFS-10477) | Stop decommission a rack of DataNodes caused NameNode fail over to standby | Major | namenode | yunjiong zhao | yunjiong zhao |
+| [HDFS-13677](https://issues.apache.org/jira/browse/HDFS-13677) | Dynamic refresh Disk configuration results in overwriting VolumeMap | Blocker | . | xuzq | xuzq |
+| [YARN-9285](https://issues.apache.org/jira/browse/YARN-9285) | RM UI progress column is of wrong type | Minor | yarn | Ahmed Hussein | Ahmed Hussein |
+| [HDFS-14500](https://issues.apache.org/jira/browse/HDFS-14500) | NameNode StartupProgress continues to report edit log segments after the LOADING\_EDITS phase is finished | Major | namenode | Erik Krogen | Erik Krogen |
+| [HADOOP-16331](https://issues.apache.org/jira/browse/HADOOP-16331) | Fix ASF License check in pom.xml | Major | . | Wanqiang Ji | Akira Ajisaka |
+| [HDFS-14514](https://issues.apache.org/jira/browse/HDFS-14514) | Actual read size of open file in encryption zone still larger than listing size even after enabling HDFS-11402 in Hadoop 2 | Major | encryption, hdfs, snapshots | Siyao Meng | Siyao Meng |
+| [HDFS-14512](https://issues.apache.org/jira/browse/HDFS-14512) | ONE\_SSD policy will be violated while write data with DistributedFileSystem.create(....favoredNodes) | Major | . | Shen Yinjie | Ayush Saxena |
+| [HDFS-14521](https://issues.apache.org/jira/browse/HDFS-14521) | Suppress setReplication logging. | Major | . | Kihwal Lee | Kihwal Lee |
+| [YARN-8625](https://issues.apache.org/jira/browse/YARN-8625) | Aggregate Resource Allocation for each job is not present in ATS | Major | ATSv2 | Prabhu Joseph | Prabhu Joseph |
+| [HADOOP-16345](https://issues.apache.org/jira/browse/HADOOP-16345) | Potential NPE when instantiating FairCallQueue metrics | Major | ipc | Erik Krogen | Erik Krogen |
+| [HDFS-14494](https://issues.apache.org/jira/browse/HDFS-14494) | Move Server logging of StatedId inside receiveRequestState() | Major | . | Konstantin Shvachko | Shweta |
+| [HDFS-14535](https://issues.apache.org/jira/browse/HDFS-14535) | The default 8KB buffer in requestFileDescriptors#BufferedOutputStream is causing lots of heap allocation in HBase when using short-circut read | Major | hdfs-client | Zheng Hu | Zheng Hu |
+| [HDFS-13730](https://issues.apache.org/jira/browse/HDFS-13730) | BlockReaderRemote.sendReadResult throws NPE | Major | hdfs-client | Wei-Chiu Chuang | Yuanbo Liu |
+| [HDFS-13770](https://issues.apache.org/jira/browse/HDFS-13770) | dfsadmin -report does not always decrease "missing blocks (with replication factor 1)" metrics when file is deleted | Major | hdfs | Kitti Nanasi | Kitti Nanasi |
+| [HDFS-14101](https://issues.apache.org/jira/browse/HDFS-14101) | Random failure of testListCorruptFilesCorruptedBlock | Major | test | Kihwal Lee | Zsolt Venczel |
+| [HDFS-14465](https://issues.apache.org/jira/browse/HDFS-14465) | When the Block expected replications is larger than the number of DataNodes, entering maintenance will never exit. | Major | . | Yicong Cai | Yicong Cai |
+| [HDFS-14541](https://issues.apache.org/jira/browse/HDFS-14541) | When evictableMmapped or evictable size is zero, do not throw NoSuchElementException | Major | hdfs-client, performance | Zheng Hu | Lisheng Sun |
+| [HDFS-14629](https://issues.apache.org/jira/browse/HDFS-14629) | Property value Hard Coded in DNConf.java | Trivial | . | hemanthboyina | hemanthboyina |
+| [HDFS-12703](https://issues.apache.org/jira/browse/HDFS-12703) | Exceptions are fatal to decommissioning monitor | Critical | namenode | Daryn Sharp | Xiaoqiao He |
+| [HDFS-12748](https://issues.apache.org/jira/browse/HDFS-12748) | NameNode memory leak when accessing webhdfs GETHOMEDIRECTORY | Major | hdfs | Jiandan Yang | Weiwei Yang |
+| [HADOOP-16386](https://issues.apache.org/jira/browse/HADOOP-16386) | FindBugs warning in branch-2: GlobalStorageStatistics defines non-transient non-serializable instance field map | Major | fs | Wei-Chiu Chuang | Masatake Iwasaki |
+| [MAPREDUCE-6521](https://issues.apache.org/jira/browse/MAPREDUCE-6521) | MiniMRYarnCluster should not create /tmp/hadoop-yarn/staging on local filesystem in unit test | Major | test | Masatake Iwasaki | Masatake Iwasaki |
+| [MAPREDUCE-7076](https://issues.apache.org/jira/browse/MAPREDUCE-7076) | TestNNBench#testNNBenchCreateReadAndDelete failing in our internal build | Minor | test | Rushabh Shah | kevin su |
+| [YARN-9668](https://issues.apache.org/jira/browse/YARN-9668) | UGI conf doesn't read user overridden configurations on RM and NM startup | Major | . | Jonathan Hung | Jonathan Hung |
+| [HADOOP-9844](https://issues.apache.org/jira/browse/HADOOP-9844) | NPE when trying to create an error message response of SASL RPC | Major | ipc | Steve Loughran | Steve Loughran |
+| [HADOOP-16245](https://issues.apache.org/jira/browse/HADOOP-16245) | Enabling SSL within LdapGroupsMapping can break system SSL configs | Major | common, security | Erik Krogen | Erik Krogen |
+| [HDFS-14660](https://issues.apache.org/jira/browse/HDFS-14660) | [SBN Read] ObserverNameNode should throw StandbyException for requests not from ObserverProxyProvider | Major | . | Chao Sun | Chao Sun |
+| [HDFS-14429](https://issues.apache.org/jira/browse/HDFS-14429) | Block remain in COMMITTED but not COMPLETE caused by Decommission | Major | . | Yicong Cai | Yicong Cai |
+| [HDFS-14672](https://issues.apache.org/jira/browse/HDFS-14672) | Backport HDFS-12703 to branch-2 | Major | namenode | Xiaoqiao He | Xiaoqiao He |
+| [HADOOP-16435](https://issues.apache.org/jira/browse/HADOOP-16435) | RpcMetrics should not be retained forever | Critical | rpc-server | Zoltan Haindrich | Zoltan Haindrich |
+| [HDFS-14464](https://issues.apache.org/jira/browse/HDFS-14464) | Remove unnecessary log message from DFSInputStream | Trivial | . | Kihwal Lee | Chao Sun |
+| [HDFS-14569](https://issues.apache.org/jira/browse/HDFS-14569) | Result of crypto -listZones is not formatted properly | Major | . | hemanthboyina | hemanthboyina |
+| [YARN-9596](https://issues.apache.org/jira/browse/YARN-9596) | QueueMetrics has incorrect metrics when labelled partitions are involved | Major | capacity scheduler | Muhammad Samir Khan | Muhammad Samir Khan |
+| [HADOOP-15237](https://issues.apache.org/jira/browse/HADOOP-15237) | In KMS docs there should be one space between KMS\_LOG and NOTE | Minor | kms | Snigdhanjali Mishra | Snigdhanjali Mishra |
+| [HDFS-14462](https://issues.apache.org/jira/browse/HDFS-14462) | WebHDFS throws "Error writing request body to server" instead of DSQuotaExceededException | Major | webhdfs | Erik Krogen | Simbarashe Dzinamarira |
+| [HDFS-14631](https://issues.apache.org/jira/browse/HDFS-14631) | The DirectoryScanner doesn't fix the wrongly placed replica. | Major | . | Jinglun | Jinglun |
+| [HDFS-14724](https://issues.apache.org/jira/browse/HDFS-14724) | Fix JDK7 compatibility in branch-2 | Blocker | . | Wei-Chiu Chuang | Chen Liang |
+| [HDFS-14423](https://issues.apache.org/jira/browse/HDFS-14423) | Percent (%) and plus (+) characters no longer work in WebHDFS | Major | webhdfs | Jing Wang | Masatake Iwasaki |
+| [HDFS-13101](https://issues.apache.org/jira/browse/HDFS-13101) | Yet another fsimage corruption related to snapshot | Major | snapshots | Yongjun Zhang | Shashikant Banerjee |
+| [HDFS-14311](https://issues.apache.org/jira/browse/HDFS-14311) | Multi-threading conflict at layoutVersion when loading block pool storage | Major | rolling upgrades | Yicong Cai | Yicong Cai |
+| [HADOOP-16494](https://issues.apache.org/jira/browse/HADOOP-16494) | Add SHA-256 or SHA-512 checksum to release artifacts to comply with the release distribution policy | Blocker | build | Akira Ajisaka | Akira Ajisaka |
+| [HDFS-13977](https://issues.apache.org/jira/browse/HDFS-13977) | NameNode can kill itself if it tries to send too many txns to a QJM simultaneously | Major | namenode, qjm | Erik Krogen | Erik Krogen |
+| [YARN-9438](https://issues.apache.org/jira/browse/YARN-9438) | launchTime not written to state store for running applications | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-7585](https://issues.apache.org/jira/browse/YARN-7585) | NodeManager should go unhealthy when state store throws DBException | Major | nodemanager | Wilfred Spiegelenburg | Wilfred Spiegelenburg |
+| [HDFS-14726](https://issues.apache.org/jira/browse/HDFS-14726) | Fix JN incompatibility issue in branch-2 due to backport of HDFS-10519 | Blocker | journal-node | Chen Liang | Chen Liang |
+| [YARN-9806](https://issues.apache.org/jira/browse/YARN-9806) | TestNMSimulator#testNMSimulator fails in branch-2 | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-9820](https://issues.apache.org/jira/browse/YARN-9820) | RM logs InvalidStateTransitionException when app is submitted | Critical | . | Rohith Sharma K S | Prabhu Joseph |
+| [HDFS-14303](https://issues.apache.org/jira/browse/HDFS-14303) | check block directory logic not correct when there is only meta file, print no meaning warn log | Minor | datanode, hdfs | qiang Liu | qiang Liu |
+| [HADOOP-16582](https://issues.apache.org/jira/browse/HADOOP-16582) | LocalFileSystem's mkdirs() does not work as expected under viewfs. | Major | . | Kihwal Lee | Kihwal Lee |
+| [HADOOP-16581](https://issues.apache.org/jira/browse/HADOOP-16581) | ValueQueue does not trigger an async refill when number of values falls below watermark | Major | common, kms | Yuval Degani | Yuval Degani |
+| [HDFS-14853](https://issues.apache.org/jira/browse/HDFS-14853) | NPE in DFSNetworkTopology#chooseRandomWithStorageType() when the excludedNode is not present | Major | . | Ranith Sardar | Ranith Sardar |
+| [YARN-9858](https://issues.apache.org/jira/browse/YARN-9858) | Optimize RMContext getExclusiveEnforcedPartitions | Major | . | Jonathan Hung | Jonathan Hung |
+| [HDFS-14655](https://issues.apache.org/jira/browse/HDFS-14655) | [SBN Read] Namenode crashes if one of The JN is down | Critical | . | Harshakiran Reddy | Ayush Saxena |
+| [HDFS-14245](https://issues.apache.org/jira/browse/HDFS-14245) | Class cast error in GetGroups with ObserverReadProxyProvider | Major | . | Shen Yinjie | Erik Krogen |
+| [HDFS-14509](https://issues.apache.org/jira/browse/HDFS-14509) | DN throws InvalidToken due to inequality of password when upgrade NN 2.x to 3.x | Blocker | . | Yuxuan Wang | Yuxuan Wang |
+| [HADOOP-16655](https://issues.apache.org/jira/browse/HADOOP-16655) | Change cipher suite when fetching tomcat tarball for branch-2 | Major | . | Jonathan Hung | Jonathan Hung |
+
+
+### TESTS:
+
+| JIRA | Summary | Priority | Component | Reporter | Contributor |
+|:---- |:---- | :--- |:---- |:---- |:---- |
+| [HDFS-13337](https://issues.apache.org/jira/browse/HDFS-13337) | Backport HDFS-4275 to branch-2.9 | Minor | . | Íñigo Goiri | Xiao Liang |
+| [HDFS-13503](https://issues.apache.org/jira/browse/HDFS-13503) | Fix TestFsck test failures on Windows | Major | hdfs | Xiao Liang | Xiao Liang |
+| [HDFS-13542](https://issues.apache.org/jira/browse/HDFS-13542) | TestBlockManager#testNeededReplicationWhileAppending fails due to improper cluster shutdown in TestBlockManager#testBlockManagerMachinesArray on Windows | Minor | . | Anbang Hu | Anbang Hu |
+| [HDFS-13551](https://issues.apache.org/jira/browse/HDFS-13551) | TestMiniDFSCluster#testClusterSetStorageCapacity does not shut down cluster | Minor | . | Anbang Hu | Anbang Hu |
+| [HDFS-11700](https://issues.apache.org/jira/browse/HDFS-11700) | TestHDFSServerPorts#testBackupNodePorts doesn't pass on Windows | Minor | . | Anbang Hu | Anbang Hu |
+| [HDFS-13548](https://issues.apache.org/jira/browse/HDFS-13548) | TestResolveHdfsSymlink#testFcResolveAfs fails on Windows | Minor | . | Anbang Hu | Anbang Hu |
+| [HDFS-13567](https://issues.apache.org/jira/browse/HDFS-13567) | TestNameNodeMetrics#testGenerateEDEKTime,TestNameNodeMetrics#testResourceCheck should use a different cluster basedir | Minor | . | Anbang Hu | Anbang Hu |
+| [HDFS-13557](https://issues.apache.org/jira/browse/HDFS-13557) | TestDFSAdmin#testListOpenFiles fails on Windows | Minor | . | Anbang Hu | Anbang Hu |
+| [HDFS-13550](https://issues.apache.org/jira/browse/HDFS-13550) | TestDebugAdmin#testComputeMetaCommand fails on Windows | Minor | . | Anbang Hu | Anbang Hu |
+| [HDFS-13559](https://issues.apache.org/jira/browse/HDFS-13559) | TestBlockScanner does not close TestContext properly | Minor | . | Anbang Hu | Anbang Hu |
+| [HDFS-13570](https://issues.apache.org/jira/browse/HDFS-13570) | TestQuotaByStorageType,TestQuota,TestDFSOutputStream fail on Windows | Minor | . | Anbang Hu | Anbang Hu |
+| [HDFS-13558](https://issues.apache.org/jira/browse/HDFS-13558) | TestDatanodeHttpXFrame does not shut down cluster | Minor | . | Anbang Hu | Anbang Hu |
+| [HDFS-13554](https://issues.apache.org/jira/browse/HDFS-13554) | TestDatanodeRegistration#testForcedRegistration does not shut down cluster | Minor | . | Anbang Hu | Anbang Hu |
+| [HDFS-13556](https://issues.apache.org/jira/browse/HDFS-13556) | TestNestedEncryptionZones does not shut down cluster | Minor | . | Anbang Hu | Anbang Hu |
+| [HDFS-13560](https://issues.apache.org/jira/browse/HDFS-13560) | Insufficient system resources exist to complete the requested service for some tests on Windows | Minor | . | Anbang Hu | Anbang Hu |
+| [HDFS-13592](https://issues.apache.org/jira/browse/HDFS-13592) | TestNameNodePrunesMissingStorages#testNameNodePrunesUnreportedStorages does not shut down cluster properly | Minor | . | Anbang Hu | Anbang Hu |
+| [HDFS-13593](https://issues.apache.org/jira/browse/HDFS-13593) | TestBlockReaderLocalLegacy#testBlockReaderLocalLegacyWithAppend fails on Windows | Minor | test | Anbang Hu | Anbang Hu |
+| [HDFS-13587](https://issues.apache.org/jira/browse/HDFS-13587) | TestQuorumJournalManager fails on Windows | Minor | . | Anbang Hu | Anbang Hu |
+| [HDFS-13620](https://issues.apache.org/jira/browse/HDFS-13620) | Randomize the test directory path for TestHDFSFileSystemContract | Minor | . | Anbang Hu | Anbang Hu |
+| [HDFS-13591](https://issues.apache.org/jira/browse/HDFS-13591) | TestDFSShell#testSetrepLow fails on Windows | Minor | . | Anbang Hu | Anbang Hu |
+| [HDFS-13632](https://issues.apache.org/jira/browse/HDFS-13632) | Randomize baseDir for MiniJournalCluster in MiniQJMHACluster for TestDFSAdminWithHA | Minor | . | Anbang Hu | Anbang Hu |
+| [MAPREDUCE-7102](https://issues.apache.org/jira/browse/MAPREDUCE-7102) | Fix TestJavaSerialization for Windows due a mismatch line separator | Minor | . | Giovanni Matteo Fumarola | Giovanni Matteo Fumarola |
+| [HDFS-13652](https://issues.apache.org/jira/browse/HDFS-13652) | Randomize baseDir for MiniDFSCluster in TestBlockScanner | Minor | . | Anbang Hu | Anbang Hu |
+| [YARN-8370](https://issues.apache.org/jira/browse/YARN-8370) | Some Node Manager tests fail on Windows due to improper path/file separator | Minor | . | Anbang Hu | Anbang Hu |
+| [YARN-8422](https://issues.apache.org/jira/browse/YARN-8422) | TestAMSimulator failing with NPE | Minor | . | Giovanni Matteo Fumarola | Giovanni Matteo Fumarola |
+| [HADOOP-15532](https://issues.apache.org/jira/browse/HADOOP-15532) | TestBasicDiskValidator fails with NoSuchFileException | Minor | . | Íñigo Goiri | Giovanni Matteo Fumarola |
+| [HDFS-13563](https://issues.apache.org/jira/browse/HDFS-13563) | TestDFSAdminWithHA times out on Windows | Minor | . | Anbang Hu | Lukas Majercak |
+| [HDFS-13681](https://issues.apache.org/jira/browse/HDFS-13681) | Fix TestStartup.testNNFailToStartOnReadOnlyNNDir test failure on Windows | Major | test | Xiao Liang | Xiao Liang |
+| [YARN-8944](https://issues.apache.org/jira/browse/YARN-8944) | TestContainerAllocation.testUserLimitAllocationMultipleContainers failure after YARN-8896 | Minor | capacity scheduler | Wilfred Spiegelenburg | Wilfred Spiegelenburg |
+| [HDFS-11950](https://issues.apache.org/jira/browse/HDFS-11950) | Disable libhdfs zerocopy test on Mac | Minor | libhdfs | John Zhuge | Akira Ajisaka |
+
+
+### SUB-TASKS:
+
+| JIRA | Summary | Priority | Component | Reporter | Contributor |
+|:---- |:---- | :--- |:---- |:---- |:---- |
+| [YARN-4081](https://issues.apache.org/jira/browse/YARN-4081) | Add support for multiple resource types in the Resource class | Major | resourcemanager | Varun Vasudev | Varun Vasudev |
+| [YARN-4172](https://issues.apache.org/jira/browse/YARN-4172) | Extend DominantResourceCalculator to account for all resources | Major | resourcemanager | Varun Vasudev | Varun Vasudev |
+| [YARN-4715](https://issues.apache.org/jira/browse/YARN-4715) | Add support to read resource types from a config file | Major | nodemanager, resourcemanager | Varun Vasudev | Varun Vasudev |
+| [YARN-4829](https://issues.apache.org/jira/browse/YARN-4829) | Add support for binary units | Major | nodemanager, resourcemanager | Varun Vasudev | Varun Vasudev |
+| [YARN-4830](https://issues.apache.org/jira/browse/YARN-4830) | Add support for resource types in the nodemanager | Major | nodemanager | Varun Vasudev | Varun Vasudev |
+| [YARN-5242](https://issues.apache.org/jira/browse/YARN-5242) | Update DominantResourceCalculator to consider all resource types in calculations | Major | resourcemanager | Varun Vasudev | Varun Vasudev |
+| [YARN-5586](https://issues.apache.org/jira/browse/YARN-5586) | Update the Resources class to consider all resource types | Major | nodemanager, resourcemanager | Varun Vasudev | Varun Vasudev |
+| [YARN-6761](https://issues.apache.org/jira/browse/YARN-6761) | Fix build for YARN-3926 branch | Major | nodemanager, resourcemanager | Varun Vasudev | Varun Vasudev |
+| [YARN-6786](https://issues.apache.org/jira/browse/YARN-6786) | ResourcePBImpl imports cleanup | Trivial | resourcemanager | Daniel Templeton | Yeliang Cang |
+| [YARN-6788](https://issues.apache.org/jira/browse/YARN-6788) | Improve performance of resource profile branch | Blocker | nodemanager, resourcemanager | Sunil G | Sunil G |
+| [YARN-6994](https://issues.apache.org/jira/browse/YARN-6994) | Remove last uses of Long from resource types code | Minor | resourcemanager | Daniel Templeton | Daniel Templeton |
+| [YARN-6892](https://issues.apache.org/jira/browse/YARN-6892) | Improve API implementation in Resources and DominantResourceCalculator class | Major | nodemanager, resourcemanager | Sunil G | Sunil G |
+| [YARN-6610](https://issues.apache.org/jira/browse/YARN-6610) | DominantResourceCalculator#getResourceAsValue dominant param is updated to handle multiple resources | Critical | resourcemanager | Daniel Templeton | Daniel Templeton |
+| [YARN-7030](https://issues.apache.org/jira/browse/YARN-7030) | Performance optimizations in Resource and ResourceUtils class | Critical | nodemanager, resourcemanager | Wangda Tan | Wangda Tan |
+| [YARN-7042](https://issues.apache.org/jira/browse/YARN-7042) | Clean up unit tests after YARN-6610 | Major | test | Daniel Templeton | Daniel Templeton |
+| [YARN-6789](https://issues.apache.org/jira/browse/YARN-6789) | Add Client API to get all supported resource types from RM | Major | nodemanager, resourcemanager | Sunil G | Sunil G |
+| [YARN-6781](https://issues.apache.org/jira/browse/YARN-6781) | ResourceUtils#initializeResourcesMap takes an unnecessary Map parameter | Minor | resourcemanager | Daniel Templeton | Yu-Tang Lin |
+| [YARN-7067](https://issues.apache.org/jira/browse/YARN-7067) | Optimize ResourceType information display in UI | Critical | nodemanager, resourcemanager | Wangda Tan | Wangda Tan |
+| [YARN-7039](https://issues.apache.org/jira/browse/YARN-7039) | Fix javac and javadoc errors in YARN-3926 branch | Major | nodemanager, resourcemanager | Sunil G | Sunil G |
+| [YARN-7093](https://issues.apache.org/jira/browse/YARN-7093) | Improve log message in ResourceUtils | Trivial | nodemanager, resourcemanager | Sunil G | Sunil G |
+| [YARN-6933](https://issues.apache.org/jira/browse/YARN-6933) | ResourceUtils.DISALLOWED\_NAMES check is duplicated | Major | resourcemanager | Daniel Templeton | Manikandan R |
+| [YARN-7137](https://issues.apache.org/jira/browse/YARN-7137) | Move newly added APIs to unstable in YARN-3926 branch | Blocker | nodemanager, resourcemanager | Wangda Tan | Wangda Tan |
+| [HADOOP-14799](https://issues.apache.org/jira/browse/HADOOP-14799) | Update nimbus-jose-jwt to 4.41.1 | Major | . | Ray Chiang | Ray Chiang |
+| [YARN-7345](https://issues.apache.org/jira/browse/YARN-7345) | GPU Isolation: Incorrect minor device numbers written to devices.deny file | Major | . | Jonathan Hung | Jonathan Hung |
+| [HADOOP-14997](https://issues.apache.org/jira/browse/HADOOP-14997) | Add hadoop-aliyun as dependency of hadoop-cloud-storage | Minor | fs/oss | Genmao Yu | Genmao Yu |
+| [YARN-7143](https://issues.apache.org/jira/browse/YARN-7143) | FileNotFound handling in ResourceUtils is inconsistent | Major | resourcemanager | Daniel Templeton | Daniel Templeton |
+| [YARN-6909](https://issues.apache.org/jira/browse/YARN-6909) | Use LightWeightedResource when number of resource types more than two | Critical | resourcemanager | Daniel Templeton | Sunil G |
+| [HDFS-12801](https://issues.apache.org/jira/browse/HDFS-12801) | RBF: Set MountTableResolver as default file resolver | Minor | . | Íñigo Goiri | Íñigo Goiri |
+| [YARN-7430](https://issues.apache.org/jira/browse/YARN-7430) | Enable user re-mapping for Docker containers by default | Blocker | security, yarn | Eric Yang | Eric Yang |
+| [HADOOP-15024](https://issues.apache.org/jira/browse/HADOOP-15024) | AliyunOSS: support user agent configuration and include that & Hadoop version information to oss server | Major | fs, fs/oss | Sammi Chen | Sammi Chen |
+| [HDFS-12858](https://issues.apache.org/jira/browse/HDFS-12858) | RBF: Add router admin commands usage in HDFS commands reference doc | Minor | documentation | Yiqun Lin | Yiqun Lin |
+| [HDFS-12835](https://issues.apache.org/jira/browse/HDFS-12835) | RBF: Fix Javadoc parameter errors | Minor | . | Wei Yan | Wei Yan |
+| [YARN-7573](https://issues.apache.org/jira/browse/YARN-7573) | Gpu Information page could be empty for nodes without GPU | Major | webapp, yarn-ui-v2 | Sunil G | Sunil G |
+| [HDFS-12396](https://issues.apache.org/jira/browse/HDFS-12396) | Webhdfs file system should get delegation token from kms provider. | Major | encryption, kms, webhdfs | Rushabh Shah | Rushabh Shah |
+| [YARN-6704](https://issues.apache.org/jira/browse/YARN-6704) | Add support for work preserving NM restart when FederationInterceptor is enabled in AMRMProxyService | Major | . | Botong Huang | Botong Huang |
+| [HDFS-12875](https://issues.apache.org/jira/browse/HDFS-12875) | RBF: Complete logic for -readonly option of dfsrouteradmin add command | Major | . | Yiqun Lin | Íñigo Goiri |
+| [YARN-7383](https://issues.apache.org/jira/browse/YARN-7383) | Node resource is not parsed correctly for resource names containing dot | Major | nodemanager, resourcemanager | Jonathan Hung | Gergely Novák |
+| [YARN-7630](https://issues.apache.org/jira/browse/YARN-7630) | Fix AMRMToken rollover handling in AMRMProxy | Minor | . | Botong Huang | Botong Huang |
+| [HDFS-12937](https://issues.apache.org/jira/browse/HDFS-12937) | RBF: Add more unit tests for router admin commands | Major | test | Yiqun Lin | Yiqun Lin |
+| [YARN-7032](https://issues.apache.org/jira/browse/YARN-7032) | [ATSv2] NPE while starting hbase co-processor when HBase authorization is enabled. | Critical | . | Rohith Sharma K S | Rohith Sharma K S |
+| [HDFS-12988](https://issues.apache.org/jira/browse/HDFS-12988) | RBF: Mount table entries not properly updated in the local cache | Major | . | Íñigo Goiri | Íñigo Goiri |
+| [HDFS-12802](https://issues.apache.org/jira/browse/HDFS-12802) | RBF: Control MountTableResolver cache size | Major | . | Íñigo Goiri | Íñigo Goiri |
+| [HDFS-12934](https://issues.apache.org/jira/browse/HDFS-12934) | RBF: Federation supports global quota | Major | . | Yiqun Lin | Yiqun Lin |
+| [HDFS-12972](https://issues.apache.org/jira/browse/HDFS-12972) | RBF: Display mount table quota info in Web UI and admin command | Major | . | Yiqun Lin | Yiqun Lin |
+| [YARN-6736](https://issues.apache.org/jira/browse/YARN-6736) | Consider writing to both ats v1 & v2 from RM for smoother upgrades | Major | timelineserver | Vrushali C | Aaron Gresch |
+| [HADOOP-15027](https://issues.apache.org/jira/browse/HADOOP-15027) | AliyunOSS: Support multi-thread pre-read to improve sequential read from Hadoop to Aliyun OSS performance | Major | fs/oss | wujinhu | wujinhu |
+| [HDFS-12973](https://issues.apache.org/jira/browse/HDFS-12973) | RBF: Document global quota supporting in federation | Major | . | Yiqun Lin | Yiqun Lin |
+| [HDFS-13028](https://issues.apache.org/jira/browse/HDFS-13028) | RBF: Fix spurious TestRouterRpc#testProxyGetStats | Minor | . | Íñigo Goiri | Íñigo Goiri |
+| [HDFS-12772](https://issues.apache.org/jira/browse/HDFS-12772) | RBF: Federation Router State State Store internal API | Major | . | Íñigo Goiri | Íñigo Goiri |
+| [HDFS-13042](https://issues.apache.org/jira/browse/HDFS-13042) | RBF: Heartbeat Router State | Major | . | Íñigo Goiri | Íñigo Goiri |
+| [HDFS-13049](https://issues.apache.org/jira/browse/HDFS-13049) | RBF: Inconsistent Router OPTS config in branch-2 and branch-3 | Minor | . | Wei Yan | Wei Yan |
+| [YARN-7817](https://issues.apache.org/jira/browse/YARN-7817) | Add Resource reference to RM's NodeInfo object so REST API can get non memory/vcore resource usages. | Major | . | Sumana Sathish | Sunil G |
+| [HDFS-12574](https://issues.apache.org/jira/browse/HDFS-12574) | Add CryptoInputStream to WebHdfsFileSystem read call. | Major | encryption, kms, webhdfs | Rushabh Shah | Rushabh Shah |
+| [HDFS-13044](https://issues.apache.org/jira/browse/HDFS-13044) | RBF: Add a safe mode for the Router | Major | . | Íñigo Goiri | Íñigo Goiri |
+| [HDFS-13043](https://issues.apache.org/jira/browse/HDFS-13043) | RBF: Expose the state of the Routers in the federation | Major | . | Íñigo Goiri | Íñigo Goiri |
+| [HDFS-13068](https://issues.apache.org/jira/browse/HDFS-13068) | RBF: Add router admin option to manage safe mode | Major | . | Íñigo Goiri | Yiqun Lin |
+| [YARN-7860](https://issues.apache.org/jira/browse/YARN-7860) | Fix UT failure TestRMWebServiceAppsNodelabel#testAppsRunning | Major | . | Weiwei Yang | Sunil G |
+| [HDFS-13119](https://issues.apache.org/jira/browse/HDFS-13119) | RBF: Manage unavailable clusters | Major | . | Íñigo Goiri | Yiqun Lin |
+| [YARN-7223](https://issues.apache.org/jira/browse/YARN-7223) | Document GPU isolation feature | Blocker | . | Wangda Tan | Wangda Tan |
+| [HDFS-13187](https://issues.apache.org/jira/browse/HDFS-13187) | RBF: Fix Routers information shown in the web UI | Minor | . | Wei Yan | Wei Yan |
+| [HDFS-13184](https://issues.apache.org/jira/browse/HDFS-13184) | RBF: Improve the unit test TestRouterRPCClientRetries | Minor | test | Yiqun Lin | Yiqun Lin |
+| [HDFS-13199](https://issues.apache.org/jira/browse/HDFS-13199) | RBF: Fix the hdfs router page missing label icon issue | Major | federation, hdfs | maobaolong | maobaolong |
+| [HADOOP-15090](https://issues.apache.org/jira/browse/HADOOP-15090) | Add ADL troubleshooting doc | Major | documentation, fs/adl | Steve Loughran | Steve Loughran |
+| [YARN-7919](https://issues.apache.org/jira/browse/YARN-7919) | Refactor timelineservice-hbase module into submodules | Major | timelineservice | Haibo Chen | Haibo Chen |
+| [YARN-8003](https://issues.apache.org/jira/browse/YARN-8003) | Backport the code structure changes in YARN-7346 to branch-2 | Major | . | Haibo Chen | Haibo Chen |
+| [HDFS-13214](https://issues.apache.org/jira/browse/HDFS-13214) | RBF: Complete document of Router configuration | Major | . | Tao Jie | Yiqun Lin |
+| [HADOOP-15267](https://issues.apache.org/jira/browse/HADOOP-15267) | S3A multipart upload fails when SSE-C encryption is enabled | Critical | fs/s3 | Anis Elleuch | Anis Elleuch |
+| [HDFS-13230](https://issues.apache.org/jira/browse/HDFS-13230) | RBF: ConnectionManager's cleanup task will compare each pool's own active conns with its total conns | Minor | . | Wei Yan | Chao Sun |
+| [HDFS-13233](https://issues.apache.org/jira/browse/HDFS-13233) | RBF: MountTableResolver doesn't return the correct mount point of the given path | Major | hdfs | wangzhiyuan | wangzhiyuan |
+| [HDFS-13212](https://issues.apache.org/jira/browse/HDFS-13212) | RBF: Fix router location cache issue | Major | federation, hdfs | Wu Weiwei | Wu Weiwei |
+| [HDFS-13232](https://issues.apache.org/jira/browse/HDFS-13232) | RBF: ConnectionPool should return first usable connection | Minor | . | Wei Yan | Ekanth Sethuramalingam |
+| [HDFS-13240](https://issues.apache.org/jira/browse/HDFS-13240) | RBF: Update some inaccurate document descriptions | Minor | . | Yiqun Lin | Yiqun Lin |
+| [HDFS-11399](https://issues.apache.org/jira/browse/HDFS-11399) | Many tests fails in Windows due to injecting disk failures | Major | . | Yiqun Lin | Yiqun Lin |
+| [HDFS-13241](https://issues.apache.org/jira/browse/HDFS-13241) | RBF: TestRouterSafemode failed if the port 8888 is in use | Major | hdfs, test | maobaolong | maobaolong |
+| [HDFS-13253](https://issues.apache.org/jira/browse/HDFS-13253) | RBF: Quota management incorrect parent-child relationship judgement | Major | . | Yiqun Lin | Yiqun Lin |
+| [HDFS-13226](https://issues.apache.org/jira/browse/HDFS-13226) | RBF: Throw the exception if mount table entry validated failed | Major | hdfs | maobaolong | maobaolong |
+| [HADOOP-15308](https://issues.apache.org/jira/browse/HADOOP-15308) | TestConfiguration fails on Windows because of paths | Major | test | Íñigo Goiri | Xiao Liang |
+| [HDFS-12773](https://issues.apache.org/jira/browse/HDFS-12773) | RBF: Improve State Store FS implementation | Major | . | Íñigo Goiri | Íñigo Goiri |
+| [HDFS-13198](https://issues.apache.org/jira/browse/HDFS-13198) | RBF: RouterHeartbeatService throws out CachedStateStore related exceptions when starting router | Minor | . | Wei Yan | Wei Yan |
+| [HDFS-13224](https://issues.apache.org/jira/browse/HDFS-13224) | RBF: Resolvers to support mount points across multiple subclusters | Major | . | Íñigo Goiri | Íñigo Goiri |
+| [HDFS-13299](https://issues.apache.org/jira/browse/HDFS-13299) | RBF : Fix compilation error in branch-2 (TestMultipleDestinationResolver) | Blocker | . | Brahma Reddy Battula | Brahma Reddy Battula |
+| [HADOOP-15262](https://issues.apache.org/jira/browse/HADOOP-15262) | AliyunOSS: move files under a directory in parallel when rename a directory | Major | fs/oss | wujinhu | wujinhu |
+| [HDFS-13215](https://issues.apache.org/jira/browse/HDFS-13215) | RBF: Move Router to its own module | Major | . | Íñigo Goiri | Wei Yan |
+| [HDFS-13307](https://issues.apache.org/jira/browse/HDFS-13307) | RBF: Improve the use of setQuota command | Major | . | liuhongtong | liuhongtong |
+| [HDFS-13250](https://issues.apache.org/jira/browse/HDFS-13250) | RBF: Router to manage requests across multiple subclusters | Major | . | Íñigo Goiri | Íñigo Goiri |
+| [HDFS-13318](https://issues.apache.org/jira/browse/HDFS-13318) | RBF: Fix FindBugs in hadoop-hdfs-rbf | Minor | . | Íñigo Goiri | Ekanth Sethuramalingam |
+| [HDFS-12792](https://issues.apache.org/jira/browse/HDFS-12792) | RBF: Test Router-based federation using HDFSContract | Major | . | Íñigo Goiri | Íñigo Goiri |
+| [YARN-7581](https://issues.apache.org/jira/browse/YARN-7581) | HBase filters are not constructed correctly in ATSv2 | Major | ATSv2 | Haibo Chen | Haibo Chen |
+| [YARN-7986](https://issues.apache.org/jira/browse/YARN-7986) | ATSv2 REST API queries do not return results for uppercase application tags | Critical | . | Charan Hebri | Charan Hebri |
+| [HDFS-12512](https://issues.apache.org/jira/browse/HDFS-12512) | RBF: Add WebHDFS | Major | fs | Íñigo Goiri | Wei Yan |
+| [HDFS-13291](https://issues.apache.org/jira/browse/HDFS-13291) | RBF: Implement available space based OrderResolver | Major | . | Yiqun Lin | Yiqun Lin |
+| [HDFS-13204](https://issues.apache.org/jira/browse/HDFS-13204) | RBF: Optimize name service safe mode icon | Minor | . | liuhongtong | liuhongtong |
+| [HDFS-13352](https://issues.apache.org/jira/browse/HDFS-13352) | RBF: Add xsl stylesheet for hdfs-rbf-default.xml | Major | documentation | Takanobu Asanuma | Takanobu Asanuma |
+| [YARN-8010](https://issues.apache.org/jira/browse/YARN-8010) | Add config in FederationRMFailoverProxy to not bypass facade cache when failing over | Minor | . | Botong Huang | Botong Huang |
+| [HDFS-13347](https://issues.apache.org/jira/browse/HDFS-13347) | RBF: Cache datanode reports | Minor | . | Íñigo Goiri | Íñigo Goiri |
+| [HDFS-13289](https://issues.apache.org/jira/browse/HDFS-13289) | RBF: TestConnectionManager#testCleanup() test case need correction | Minor | . | Dibyendu Karmakar | Dibyendu Karmakar |
+| [HDFS-13364](https://issues.apache.org/jira/browse/HDFS-13364) | RBF: Support NamenodeProtocol in the Router | Major | . | Íñigo Goiri | Íñigo Goiri |
+| [HADOOP-14651](https://issues.apache.org/jira/browse/HADOOP-14651) | Update okhttp version to 2.7.5 | Major | fs/adl | Ray Chiang | Ray Chiang |
+| [YARN-6936](https://issues.apache.org/jira/browse/YARN-6936) | [Atsv2] Retrospect storing entities into sub application table from client perspective | Major | . | Rohith Sharma K S | Rohith Sharma K S |
+| [HDFS-13353](https://issues.apache.org/jira/browse/HDFS-13353) | RBF: TestRouterWebHDFSContractCreate failed | Major | test | Takanobu Asanuma | Takanobu Asanuma |
+| [YARN-8107](https://issues.apache.org/jira/browse/YARN-8107) | Give an informative message when incorrect format is used in ATSv2 filter attributes | Major | ATSv2 | Charan Hebri | Rohith Sharma K S |
+| [YARN-8110](https://issues.apache.org/jira/browse/YARN-8110) | AMRMProxy recover should catch for all throwable to avoid premature exit | Major | . | Botong Huang | Botong Huang |
+| [HDFS-13402](https://issues.apache.org/jira/browse/HDFS-13402) | RBF: Fix java doc for StateStoreFileSystemImpl | Minor | hdfs | Yiran Wu | Yiran Wu |
+| [HDFS-13380](https://issues.apache.org/jira/browse/HDFS-13380) | RBF: mv/rm fail after the directory exceeded the quota limit | Major | . | Wu Weiwei | Yiqun Lin |
+| [HDFS-13410](https://issues.apache.org/jira/browse/HDFS-13410) | RBF: Support federation with no subclusters | Minor | . | Íñigo Goiri | Íñigo Goiri |
+| [HDFS-13384](https://issues.apache.org/jira/browse/HDFS-13384) | RBF: Improve timeout RPC call mechanism | Minor | . | Íñigo Goiri | Íñigo Goiri |
+| [HDFS-13045](https://issues.apache.org/jira/browse/HDFS-13045) | RBF: Improve error message returned from subcluster | Minor | . | Wei Yan | Íñigo Goiri |
+| [HDFS-13428](https://issues.apache.org/jira/browse/HDFS-13428) | RBF: Remove LinkedList From StateStoreFileImpl.java | Trivial | federation | David Mollitor | David Mollitor |
+| [HADOOP-14999](https://issues.apache.org/jira/browse/HADOOP-14999) | AliyunOSS: provide one asynchronous multi-part based uploading mechanism | Major | fs/oss | Genmao Yu | Genmao Yu |
+| [YARN-7810](https://issues.apache.org/jira/browse/YARN-7810) | TestDockerContainerRuntime test failures due to UID lookup of a non-existent user | Major | . | Shane Kumpf | Shane Kumpf |
+| [HDFS-13435](https://issues.apache.org/jira/browse/HDFS-13435) | RBF: Improve the error loggings for printing the stack trace | Major | . | Yiqun Lin | Yiqun Lin |
+| [YARN-7189](https://issues.apache.org/jira/browse/YARN-7189) | Container-executor doesn't remove Docker containers that error out early | Major | yarn | Eric Badger | Eric Badger |
+| [HDFS-13466](https://issues.apache.org/jira/browse/HDFS-13466) | RBF: Add more router-related information to the UI | Minor | . | Wei Yan | Wei Yan |
+| [HDFS-13453](https://issues.apache.org/jira/browse/HDFS-13453) | RBF: getMountPointDates should fetch latest subdir time/date when parent dir is not present but /parent/child dirs are present in mount table | Major | . | Dibyendu Karmakar | Dibyendu Karmakar |
+| [HDFS-13478](https://issues.apache.org/jira/browse/HDFS-13478) | RBF: Disabled Nameservice store API | Major | . | Íñigo Goiri | Íñigo Goiri |
+| [HDFS-13490](https://issues.apache.org/jira/browse/HDFS-13490) | RBF: Fix setSafeMode in the Router | Major | . | Íñigo Goiri | Íñigo Goiri |
+| [HDFS-13484](https://issues.apache.org/jira/browse/HDFS-13484) | RBF: Disable Nameservices from the federation | Major | . | Íñigo Goiri | Íñigo Goiri |
+| [HDFS-13326](https://issues.apache.org/jira/browse/HDFS-13326) | RBF: Improve the interfaces to modify and view mount tables | Minor | . | Wei Yan | Gang Li |
+| [HDFS-13499](https://issues.apache.org/jira/browse/HDFS-13499) | RBF: Show disabled name services in the UI | Minor | . | Íñigo Goiri | Íñigo Goiri |
+| [YARN-8215](https://issues.apache.org/jira/browse/YARN-8215) | ATS v2 returns invalid YARN\_CONTAINER\_ALLOCATED\_HOST\_HTTP\_ADDRESS from NM | Critical | ATSv2 | Yesha Vora | Rohith Sharma K S |
+| [HDFS-13508](https://issues.apache.org/jira/browse/HDFS-13508) | RBF: Normalize paths (automatically) when adding, updating, removing or listing mount table entries | Minor | . | Ekanth Sethuramalingam | Ekanth Sethuramalingam |
+| [HDFS-13434](https://issues.apache.org/jira/browse/HDFS-13434) | RBF: Fix dead links in RBF document | Major | documentation | Akira Ajisaka | Chetna Chaudhari |
+| [HDFS-13488](https://issues.apache.org/jira/browse/HDFS-13488) | RBF: Reject requests when a Router is overloaded | Major | . | Íñigo Goiri | Íñigo Goiri |
+| [HDFS-13525](https://issues.apache.org/jira/browse/HDFS-13525) | RBF: Add unit test TestStateStoreDisabledNameservice | Major | . | Yiqun Lin | Yiqun Lin |
+| [YARN-8253](https://issues.apache.org/jira/browse/YARN-8253) | HTTPS Ats v2 api call fails with "bad HTTP parsed" | Critical | ATSv2 | Yesha Vora | Charan Hebri |
+| [HADOOP-15454](https://issues.apache.org/jira/browse/HADOOP-15454) | TestRollingFileSystemSinkWithLocal fails on Windows | Major | test | Xiao Liang | Xiao Liang |
+| [HDFS-13346](https://issues.apache.org/jira/browse/HDFS-13346) | RBF: Fix synchronization of router quota and nameservice quota | Major | . | liuhongtong | Yiqun Lin |
+| [YARN-8247](https://issues.apache.org/jira/browse/YARN-8247) | Incorrect HTTP status code returned by ATSv2 for non-whitelisted users | Critical | ATSv2 | Charan Hebri | Rohith Sharma K S |
+| [YARN-8130](https://issues.apache.org/jira/browse/YARN-8130) | Race condition when container events are published for KILLED applications | Major | ATSv2 | Charan Hebri | Rohith Sharma K S |
+| [YARN-7900](https://issues.apache.org/jira/browse/YARN-7900) | [AMRMProxy] AMRMClientRelayer for stateful FederationInterceptor | Major | . | Botong Huang | Botong Huang |
+| [HADOOP-15498](https://issues.apache.org/jira/browse/HADOOP-15498) | TestHadoopArchiveLogs (#testGenerateScript, #testPrepareWorkingDir) fails on Windows | Minor | . | Anbang Hu | Anbang Hu |
+| [HADOOP-15497](https://issues.apache.org/jira/browse/HADOOP-15497) | TestTrash should use proper test path to avoid failing on Windows | Minor | . | Anbang Hu | Anbang Hu |
+| [HDFS-13637](https://issues.apache.org/jira/browse/HDFS-13637) | RBF: Router fails when threadIndex (in ConnectionPool) wraps around Integer.MIN\_VALUE | Critical | federation | CR Hota | CR Hota |
+| [YARN-4781](https://issues.apache.org/jira/browse/YARN-4781) | Support intra-queue preemption for fairness ordering policy. | Major | scheduler | Wangda Tan | Eric Payne |
+| [HADOOP-15506](https://issues.apache.org/jira/browse/HADOOP-15506) | Upgrade Azure Storage Sdk version to 7.0.0 and update corresponding code blocks | Minor | fs/azure | Esfandiar Manii | Esfandiar Manii |
+| [HADOOP-15529](https://issues.apache.org/jira/browse/HADOOP-15529) | ContainerLaunch#testInvalidEnvVariableSubstitutionType is not supported in Windows | Minor | . | Giovanni Matteo Fumarola | Giovanni Matteo Fumarola |
+| [HADOOP-15533](https://issues.apache.org/jira/browse/HADOOP-15533) | Make WASB listStatus messages consistent | Trivial | fs/azure | Esfandiar Manii | Esfandiar Manii |
+| [HADOOP-15458](https://issues.apache.org/jira/browse/HADOOP-15458) | TestLocalFileSystem#testFSOutputStreamBuilder fails on Windows | Minor | test | Xiao Liang | Xiao Liang |
+| [YARN-8481](https://issues.apache.org/jira/browse/YARN-8481) | AMRMProxyPolicies should accept heartbeat response from new/unknown subclusters | Minor | amrmproxy, federation | Botong Huang | Botong Huang |
+| [HDFS-13528](https://issues.apache.org/jira/browse/HDFS-13528) | RBF: If a directory exceeds quota limit then quota usage is not refreshed for other mount entries | Major | . | Dibyendu Karmakar | Dibyendu Karmakar |
+| [HDFS-13710](https://issues.apache.org/jira/browse/HDFS-13710) | RBF: setQuota and getQuotaUsage should check the dfs.federation.router.quota.enable | Major | federation, hdfs | yanghuafeng | yanghuafeng |
+| [HDFS-13726](https://issues.apache.org/jira/browse/HDFS-13726) | RBF: Fix RBF configuration links | Minor | documentation | Takanobu Asanuma | Takanobu Asanuma |
+| [HDFS-13475](https://issues.apache.org/jira/browse/HDFS-13475) | RBF: Admin cannot enforce Router enter SafeMode | Major | . | Wei Yan | Chao Sun |
+| [HDFS-13733](https://issues.apache.org/jira/browse/HDFS-13733) | RBF: Add Web UI configurations and descriptions to RBF document | Minor | documentation | Takanobu Asanuma | Takanobu Asanuma |
+| [HDFS-13743](https://issues.apache.org/jira/browse/HDFS-13743) | RBF: Router throws NullPointerException due to the invalid initialization of MountTableResolver | Major | . | Takanobu Asanuma | Takanobu Asanuma |
+| [HDFS-13583](https://issues.apache.org/jira/browse/HDFS-13583) | RBF: Router admin clrQuota is not synchronized with nameservice | Major | . | Dibyendu Karmakar | Dibyendu Karmakar |
+| [HDFS-13750](https://issues.apache.org/jira/browse/HDFS-13750) | RBF: Router ID in RouterRpcClient is always null | Major | . | Takanobu Asanuma | Takanobu Asanuma |
+| [YARN-8129](https://issues.apache.org/jira/browse/YARN-8129) | Improve error message for invalid value in fields attribute | Minor | ATSv2 | Charan Hebri | Abhishek Modi |
+| [YARN-8581](https://issues.apache.org/jira/browse/YARN-8581) | [AMRMProxy] Add sub-cluster timeout in LocalityMulticastAMRMProxyPolicy | Major | amrmproxy, federation | Botong Huang | Botong Huang |
+| [YARN-8673](https://issues.apache.org/jira/browse/YARN-8673) | [AMRMProxy] More robust responseId resync after an YarnRM master slave switch | Major | amrmproxy | Botong Huang | Botong Huang |
+| [HDFS-13848](https://issues.apache.org/jira/browse/HDFS-13848) | Refactor NameNode failover proxy providers | Major | ha, hdfs-client | Konstantin Shvachko | Konstantin Shvachko |
+| [HDFS-13634](https://issues.apache.org/jira/browse/HDFS-13634) | RBF: Configurable value in xml for async connection request queue size. | Major | federation | CR Hota | CR Hota |
+| [HADOOP-15731](https://issues.apache.org/jira/browse/HADOOP-15731) | TestDistributedShell fails on Windows | Major | . | Botong Huang | Botong Huang |
+| [HADOOP-15759](https://issues.apache.org/jira/browse/HADOOP-15759) | AliyunOSS: update oss-sdk version to 3.0.0 | Major | fs/oss | wujinhu | wujinhu |
+| [HADOOP-15748](https://issues.apache.org/jira/browse/HADOOP-15748) | S3 listing inconsistency can raise NPE in globber | Major | fs | Steve Loughran | Steve Loughran |
+| [YARN-8696](https://issues.apache.org/jira/browse/YARN-8696) | [AMRMProxy] FederationInterceptor upgrade: home sub-cluster heartbeat async | Major | nodemanager | Botong Huang | Botong Huang |
+| [HADOOP-15671](https://issues.apache.org/jira/browse/HADOOP-15671) | AliyunOSS: Support Assume Roles in AliyunOSS | Major | fs/oss | wujinhu | wujinhu |
+| [HDFS-13790](https://issues.apache.org/jira/browse/HDFS-13790) | RBF: Move ClientProtocol APIs to its own module | Major | . | Íñigo Goiri | Chao Sun |
+| [YARN-7652](https://issues.apache.org/jira/browse/YARN-7652) | Handle AM register requests asynchronously in FederationInterceptor | Major | amrmproxy, federation | Subramaniam Krishnan | Botong Huang |
+| [YARN-6989](https://issues.apache.org/jira/browse/YARN-6989) | Ensure timeline service v2 codebase gets UGI from HttpServletRequest in a consistent way | Major | timelineserver | Vrushali C | Abhishek Modi |
+| [YARN-3879](https://issues.apache.org/jira/browse/YARN-3879) | [Storage implementation] Create HDFS backing storage implementation for ATS reads | Major | timelineserver | Tsuyoshi Ozawa | Abhishek Modi |
+| [HADOOP-15837](https://issues.apache.org/jira/browse/HADOOP-15837) | DynamoDB table Update can fail S3A FS init | Major | fs/s3 | Steve Loughran | Steve Loughran |
+| [HADOOP-15607](https://issues.apache.org/jira/browse/HADOOP-15607) | AliyunOSS: fix duplicated partNumber issue in AliyunOSSBlockOutputStream | Critical | . | wujinhu | wujinhu |
+| [HADOOP-15868](https://issues.apache.org/jira/browse/HADOOP-15868) | AliyunOSS: update document for properties of multiple part download, multiple part upload and directory copy | Major | fs/oss | wujinhu | wujinhu |
+| [YARN-8893](https://issues.apache.org/jira/browse/YARN-8893) | [AMRMProxy] Fix thread leak in AMRMClientRelayer and UAM client | Major | amrmproxy, federation | Botong Huang | Botong Huang |
+| [YARN-8905](https://issues.apache.org/jira/browse/YARN-8905) | [Router] Add JvmMetricsInfo and pause monitor | Minor | . | Bibin Chundatt | Bilwa S T |
+| [HADOOP-15917](https://issues.apache.org/jira/browse/HADOOP-15917) | AliyunOSS: fix incorrect ReadOps and WriteOps in statistics | Major | fs/oss | wujinhu | wujinhu |
+| [HADOOP-16009](https://issues.apache.org/jira/browse/HADOOP-16009) | Replace the url of the repository in Apache Hadoop source code | Major | documentation | Akira Ajisaka | Akira Ajisaka |
+| [HADOOP-15323](https://issues.apache.org/jira/browse/HADOOP-15323) | AliyunOSS: Improve copy file performance for AliyunOSSFileSystemStore | Major | fs/oss | wujinhu | wujinhu |
+| [YARN-9182](https://issues.apache.org/jira/browse/YARN-9182) | Backport YARN-6445 resource profile performance improvements to branch-2 | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-9181](https://issues.apache.org/jira/browse/YARN-9181) | Backport YARN-6232 for generic resource type usage to branch-2 | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-9177](https://issues.apache.org/jira/browse/YARN-9177) | Use resource map for app metrics in TestCombinedSystemMetricsPublisher for branch-2 | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-9188](https://issues.apache.org/jira/browse/YARN-9188) | Port YARN-7136 to branch-2 | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-9187](https://issues.apache.org/jira/browse/YARN-9187) | Backport YARN-6852 for GPU-specific native changes to branch-2 | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-9180](https://issues.apache.org/jira/browse/YARN-9180) | Port YARN-7033 NM recovery of assigned resources to branch-3.0/branch-2 | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-9280](https://issues.apache.org/jira/browse/YARN-9280) | Backport YARN-6620 to YARN-8200/branch-2 | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-9174](https://issues.apache.org/jira/browse/YARN-9174) | Backport YARN-7224 for refactoring of GpuDevice class | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-9289](https://issues.apache.org/jira/browse/YARN-9289) | Backport YARN-7330 for GPU in UI to branch-2 | Major | . | Jonathan Hung | Jonathan Hung |
+| [HDFS-14262](https://issues.apache.org/jira/browse/HDFS-14262) | [SBN read] Unclear Log.WARN message in GlobalStateIdContext | Major | hdfs | Shweta | Shweta |
+| [YARN-8549](https://issues.apache.org/jira/browse/YARN-8549) | Adding a NoOp timeline writer and reader plugin classes for ATSv2 | Minor | ATSv2, timelineclient, timelineserver | Prabha Manepalli | Prabha Manepalli |
+| [HADOOP-16109](https://issues.apache.org/jira/browse/HADOOP-16109) | Parquet reading S3AFileSystem causes EOF | Blocker | fs/s3 | Dave Christianson | Steve Loughran |
+| [YARN-9397](https://issues.apache.org/jira/browse/YARN-9397) | Fix empty NMResourceInfo object test failures in branch-2 | Major | . | Jonathan Hung | Jonathan Hung |
+| [HADOOP-16191](https://issues.apache.org/jira/browse/HADOOP-16191) | AliyunOSS: improvements for copyFile/copyDirectory and logging | Major | fs/oss | wujinhu | wujinhu |
+| [YARN-9271](https://issues.apache.org/jira/browse/YARN-9271) | Backport YARN-6927 for resource type support in MapReduce | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-9291](https://issues.apache.org/jira/browse/YARN-9291) | Backport YARN-7637 to branch-2 | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-9409](https://issues.apache.org/jira/browse/YARN-9409) | Port resource type changes from YARN-7237 to branch-3.0/branch-2 | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-9272](https://issues.apache.org/jira/browse/YARN-9272) | Backport YARN-7738 for refreshing max allocation for multiple resource types | Major | . | Jonathan Hung | Jonathan Hung |
+| [HADOOP-16205](https://issues.apache.org/jira/browse/HADOOP-16205) | Backporting ABFS driver from trunk to branch 2.0 | Major | fs/azure | Esfandiar Manii | Yuan Gao |
+| [HADOOP-16269](https://issues.apache.org/jira/browse/HADOOP-16269) | ABFS: add listFileStatus with StartFrom | Major | fs/azure | Da Zhou | Da Zhou |
+| [HADOOP-16306](https://issues.apache.org/jira/browse/HADOOP-16306) | AliyunOSS: Remove temporary files when upload small files to OSS | Major | fs/oss | wujinhu | wujinhu |
+| [HDFS-14034](https://issues.apache.org/jira/browse/HDFS-14034) | Support getQuotaUsage API in WebHDFS | Major | fs, webhdfs | Erik Krogen | Chao Sun |
+| [YARN-9775](https://issues.apache.org/jira/browse/YARN-9775) | RMWebServices /scheduler-conf GET returns all hadoop configurations for ZKConfigurationStore | Major | restapi | Prabhu Joseph | Prabhu Joseph |
+| [HDFS-14771](https://issues.apache.org/jira/browse/HDFS-14771) | Backport HDFS-14617 to branch-2 (Improve fsimage load time by writing sub-sections to the fsimage index) | Major | namenode | Xiaoqiao He | Xiaoqiao He |
+| [HDFS-14822](https://issues.apache.org/jira/browse/HDFS-14822) | [SBN read] Revisit GlobalStateIdContext locking when getting server state id | Major | hdfs | Chen Liang | Chen Liang |
+| [HDFS-14785](https://issues.apache.org/jira/browse/HDFS-14785) | [SBN read] Change client logging to be less aggressive | Major | hdfs | Chen Liang | Chen Liang |
+| [HDFS-14858](https://issues.apache.org/jira/browse/HDFS-14858) | [SBN read] Allow configurably enable/disable AlignmentContext on NameNode | Major | hdfs | Chen Liang | Chen Liang |
+| [HDFS-12979](https://issues.apache.org/jira/browse/HDFS-12979) | StandbyNode should upload FsImage to ObserverNode after checkpointing. | Major | hdfs | Konstantin Shvachko | Chen Liang |
+| [HADOOP-16630](https://issues.apache.org/jira/browse/HADOOP-16630) | Backport HADOOP-16548 - "ABFS: Config to enable/disable flush operation" to branch-2 | Minor | fs/azure | Sneha Vijayarajan | Sneha Vijayarajan |
+| [HADOOP-16631](https://issues.apache.org/jira/browse/HADOOP-16631) | Backport HADOOP-16578 - "ABFS: fileSystemExists() should not call container level apis" to Branch-2 | Major | fs/azure | Sneha Vijayarajan | Sneha Vijayarajan |
+| [HDFS-14162](https://issues.apache.org/jira/browse/HDFS-14162) | Balancer should work with ObserverNode | Major | . | Konstantin Shvachko | Erik Krogen |
+
+
+### OTHER:
+
+| JIRA | Summary | Priority | Component | Reporter | Contributor |
+|:---- |:---- | :--- |:---- |:---- |:---- |
+| [HADOOP-15149](https://issues.apache.org/jira/browse/HADOOP-15149) | CryptoOutputStream should implement StreamCapabilities | Major | fs | Mike Drob | Xiao Chen |
+| [HADOOP-15177](https://issues.apache.org/jira/browse/HADOOP-15177) | Update the release year to 2018 | Blocker | build | Akira Ajisaka | Bharat Viswanadham |
+| [YARN-8412](https://issues.apache.org/jira/browse/YARN-8412) | Move ResourceRequest.clone logic everywhere into a proper API | Minor | . | Botong Huang | Botong Huang |
+| [HDFS-13870](https://issues.apache.org/jira/browse/HDFS-13870) | WebHDFS: Document ALLOWSNAPSHOT and DISALLOWSNAPSHOT API doc | Minor | documentation, webhdfs | Siyao Meng | Siyao Meng |
+| [HDFS-12729](https://issues.apache.org/jira/browse/HDFS-12729) | Document special paths in HDFS | Major | documentation | Christopher Douglas | Masatake Iwasaki |
+| [HADOOP-15711](https://issues.apache.org/jira/browse/HADOOP-15711) | Move branch-2 precommit/nightly test builds to java 8 | Critical | . | Jonathan Hung | Jonathan Hung |
+| [HDFS-14510](https://issues.apache.org/jira/browse/HDFS-14510) | Backport HDFS-13087 to branch-2 (Snapshotted encryption zone information should be immutable) | Major | encryption, snapshots | Wei-Chiu Chuang | Siyao Meng |
+| [HDFS-14585](https://issues.apache.org/jira/browse/HDFS-14585) | Backport HDFS-8901 Use ByteBuffer in DFSInputStream#read to branch2.9 | Major | . | Lisheng Sun | Lisheng Sun |
+| [HDFS-14483](https://issues.apache.org/jira/browse/HDFS-14483) | Backport HDFS-14111,HDFS-3246 ByteBuffer pread interface to branch-2.9 | Major | . | Zheng Hu | Lisheng Sun |
+| [YARN-9559](https://issues.apache.org/jira/browse/YARN-9559) | Create AbstractContainersLauncher for pluggable ContainersLauncher logic | Major | . | Jonathan Hung | Jonathan Hung |
+| [HDFS-14725](https://issues.apache.org/jira/browse/HDFS-14725) | Backport HDFS-12914 to branch-2 (Block report leases cause missing blocks until next report) | Major | namenode | Wei-Chiu Chuang | Xiaoqiao He |
+| [YARN-8200](https://issues.apache.org/jira/browse/YARN-8200) | Backport resource types/GPU features to branch-3.0/branch-2 | Major | . | Jonathan Hung | Jonathan Hung |
+| [HADOOP-16555](https://issues.apache.org/jira/browse/HADOOP-16555) | Update commons-compress to 1.19 | Major | . | Wei-Chiu Chuang | YiSheng Lien |
+| [YARN-9730](https://issues.apache.org/jira/browse/YARN-9730) | Support forcing configured partitions to be exclusive based on app node label | Major | . | Jonathan Hung | Jonathan Hung |
+| [HADOOP-16544](https://issues.apache.org/jira/browse/HADOOP-16544) | update io.netty in branch-2 | Major | . | Wei-Chiu Chuang | Masatake Iwasaki |
+| [HADOOP-16588](https://issues.apache.org/jira/browse/HADOOP-16588) | Update commons-beanutils version to 1.9.4 in branch-2 | Critical | . | Wei-Chiu Chuang | Wei-Chiu Chuang |
+
+
diff --git a/hadoop-common-project/hadoop-common/src/site/markdown/release/2.10.0/RELEASENOTES.2.10.0.md b/hadoop-common-project/hadoop-common/src/site/markdown/release/2.10.0/RELEASENOTES.2.10.0.md
index ca8949646a1d8..ebea56ba6da02 100644
--- a/hadoop-common-project/hadoop-common/src/site/markdown/release/2.10.0/RELEASENOTES.2.10.0.md
+++ b/hadoop-common-project/hadoop-common/src/site/markdown/release/2.10.0/RELEASENOTES.2.10.0.md
@@ -16,11 +16,51 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-->
-# Apache Hadoop 2.10.0 Release Notes
+# Apache Hadoop 2.10.0 Release Notes
These release notes cover new developer and user-facing incompatibilities, important issues, features, and major improvements.
+---
+
+* [YARN-8200](https://issues.apache.org/jira/browse/YARN-8200) | *Major* | **Backport resource types/GPU features to branch-3.0/branch-2**
+
+The generic resource types feature allows admins to configure custom resource types outside of memory and CPU. Users can request these resource types which YARN will take into account for resource scheduling.
+
+This also adds GPU as a native resource type, built on top of the generic resource types feature. It adds support for GPU resource discovery, GPU scheduling and GPU isolation.
+
+
+---
+
+* [HDFS-12943](https://issues.apache.org/jira/browse/HDFS-12943) | *Major* | **Consistent Reads from Standby Node**
+
+Observer is a new type of a NameNode in addition to Active and Standby Nodes in HA settings. An Observer Node maintains a replica of the namespace same as a Standby Node. It additionally allows execution of clients read requests.
+
+To ensure read-after-write consistency within a single client, a state ID is introduced in RPC headers. The Observer responds to the client request only after its own state has caught up with the client’s state ID, which it previously received from the Active NameNode.
+
+Clients can explicitly invoke a new client protocol call msync(), which ensures that subsequent reads by this client from an Observer are consistent.
+
+A new client-side ObserverReadProxyProvider is introduced to provide automatic switching between Active and Observer NameNodes for submitting respectively write and read requests.
+
+
+---
+
+* [HDFS-13541](https://issues.apache.org/jira/browse/HDFS-13541) | *Major* | **NameNode Port based selective encryption**
+
+This feature allows HDFS to selectively enforce encryption for both RPC (NameNode) and data transfer (DataNode). With this feature enabled, NameNode can listen on multiple ports, and different ports can have different security configurations. Depending on which NameNode port clients connect to, the RPC calls and the following data transfer will enforce security configuration corresponding to this NameNode port. This can help when there is requirement to enforce different security policies depending on the location where the clients are connecting from.
+
+This can be enabled by setting `hadoop.security.saslproperties.resolver.class` configuration to `org.apache.hadoop.security.IngressPortBasedResolver`, and add the additional NameNode auxiliary ports by setting `dfs.namenode.rpc-address.auxiliary-ports`, and set the security individual ports by configuring `ingress.port.sasl.configured.ports`.
+
+
+---
+
+* [HDFS-14403](https://issues.apache.org/jira/browse/HDFS-14403) | *Major* | **Cost-Based RPC FairCallQueue**
+
+This adds an extension to the IPC FairCallQueue which allows for the consideration of the *cost* of a user's operations when deciding how they should be prioritized, as opposed to the number of operations. This can be helpful for protecting the NameNode from clients which submit very expensive operations (e.g. large listStatus operations or recursive getContentSummary operations).
+
+This can be enabled by setting the `ipc..costprovder.impl` configuration to `org.apache.hadoop.ipc.WeightedTimeCostProvider`.
+
+
---
* [HDFS-12883](https://issues.apache.org/jira/browse/HDFS-12883) | *Major* | **RBF: Document Router and State Store metrics**
@@ -113,3 +153,77 @@ WASB: Fix Spark process hang at shutdown due to use of non-daemon threads by upd
Federation supports and controls global quota at mount table level.
In a federated environment, a folder can be spread across multiple subclusters. Router aggregates quota that queried from these subclusters and uses that for the quota-verification.
+
+
+---
+
+* [HADOOP-15547](https://issues.apache.org/jira/browse/HADOOP-15547) | *Major* | **WASB: improve listStatus performance**
+
+WASB: listStatus 10x performance improvement for listing 700,000 files
+
+
+---
+
+* [HADOOP-16055](https://issues.apache.org/jira/browse/HADOOP-16055) | *Blocker* | **Upgrade AWS SDK to 1.11.271 in branch-2**
+
+This change was required to address license compatibility issues with the JSON parser in the older AWS SDKs.
+
+A consequence of this, where needed, the applied patch contains HADOOP-12705 Upgrade Jackson 2.2.3 to 2.7.8.
+
+
+---
+
+* [HADOOP-16053](https://issues.apache.org/jira/browse/HADOOP-16053) | *Major* | **Backport HADOOP-14816 to branch-2**
+
+This patch changed the default build and test environment from Ubuntu "Trusty" 14.04 to Ubuntu "Xenial" 16.04.
+
+
+---
+
+* [HDFS-14617](https://issues.apache.org/jira/browse/HDFS-14617) | *Major* | **Improve fsimage load time by writing sub-sections to the fsimage index**
+
+This change allows the inode and inode directory sections of the fsimage to be loaded in parallel. Tests on large images have shown this change to reduce the image load time to about 50% of the pre-change run time.
+
+It works by writing sub-section entries to the image index, effectively splitting each image section into many sub-sections which can be processed in parallel. By default 12 sub-sections per image section are created when the image is saved, and 4 threads are used to load the image at startup.
+
+This is disabled by default for any image with more than 1M inodes (dfs.image.parallel.inode.threshold) and can be enabled by setting dfs.image.parallel.load to true. When the feature is enabled, the next HDFS checkpoint will write the image sub-sections and subsequent namenode restarts can load the image in parallel.
+
+A image with the parallel sections can be read even if the feature is disabled, but HDFS versions without this Jira cannot load an image with parallel sections. OIV can process a parallel enabled image without issues.
+
+Key configuration parameters are:
+
+dfs.image.parallel.load=false - enable or disable the feature
+
+dfs.image.parallel.target.sections = 12 - The target number of subsections. Aim for 2 to 3 times the number of dfs.image.parallel.threads.
+
+dfs.image.parallel.inode.threshold = 1000000 - Only save and load in parallel if the image has more than this number of inodes.
+
+dfs.image.parallel.threads = 4 - The number of threads used to load the image. Testing has shown 4 to be optimal, but this may depends on the environment
+
+
+---
+
+* [HDFS-14771](https://issues.apache.org/jira/browse/HDFS-14771) | *Major* | **Backport HDFS-14617 to branch-2 (Improve fsimage load time by writing sub-sections to the fsimage index)**
+
+This change allows the inode and inode directory sections of the fsimage to be loaded in parallel. Tests on large images have shown this change to reduce the image load time to about 50% of the pre-change run time.
+
+It works by writing sub-section entries to the image index, effectively splitting each image section into many sub-sections which can be processed in parallel. By default 12 sub-sections per image section are created when the image is saved, and 4 threads are used to load the image at startup.
+
+This is disabled by default for any image with more than 1M inodes (dfs.image.parallel.inode.threshold) and can be enabled by setting dfs.image.parallel.load to true. When the feature is enabled, the next HDFS checkpoint will write the image sub-sections and subsequent namenode restarts can load the image in parallel.
+
+A image with the parallel sections can be read even if the feature is disabled, but HDFS versions without this Jira cannot load an image with parallel sections. OIV can process a parallel enabled image without issues.
+
+Key configuration parameters are:
+
+dfs.image.parallel.load=false - enable or disable the feature
+
+dfs.image.parallel.target.sections = 12 - The target number of subsections. Aim for 2 to 3 times the number of dfs.image.parallel.threads.
+
+dfs.image.parallel.inode.threshold = 1000000 - Only save and load in parallel if the image has more than this number of inodes.
+
+dfs.image.parallel.threads = 4 - The number of threads used to load the image. Testing has shown 4 to be optimal, but this may depends on the environment.
+
+UPGRADE WARN:
+1. It can upgrade smoothly from 2.10 to 3.\* if not enable this feature ever.
+2. Only path to do upgrade from 2.10 to 3.3 currently when enable fsimage parallel loading feature.
+3. If someone want to upgrade 2.10 to 3.\*(3.1.\*/3.2.\*) prior release, please make sure that save at least one fsimage file after disable this feature. It relies on change configuration parameter(dfs.image.parallel.load=false) first and restart namenode before upgrade operation.
diff --git a/hadoop-common-project/hadoop-common/src/site/markdown/release/3.1.3/CHANGES.3.1.3.md b/hadoop-common-project/hadoop-common/src/site/markdown/release/3.1.3/CHANGES.3.1.3.md
new file mode 100644
index 0000000000000..70187e9739b9f
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/site/markdown/release/3.1.3/CHANGES.3.1.3.md
@@ -0,0 +1,336 @@
+
+
+# Apache Hadoop Changelog
+
+## Release 3.1.3 - 2019-09-12
+
+### INCOMPATIBLE CHANGES:
+
+| JIRA | Summary | Priority | Component | Reporter | Contributor |
+|:---- |:---- | :--- |:---- |:---- |:---- |
+| [HADOOP-15922](https://issues.apache.org/jira/browse/HADOOP-15922) | DelegationTokenAuthenticationFilter get wrong doAsUser since it does not decode URL | Major | common, kms | He Xiaoqiao | He Xiaoqiao |
+
+
+### NEW FEATURES:
+
+| JIRA | Summary | Priority | Component | Reporter | Contributor |
+|:---- |:---- | :--- |:---- |:---- |:---- |
+| [HADOOP-15950](https://issues.apache.org/jira/browse/HADOOP-15950) | Failover for LdapGroupsMapping | Major | common, security | Lukas Majercak | Lukas Majercak |
+
+
+### IMPROVEMENTS:
+
+| JIRA | Summary | Priority | Component | Reporter | Contributor |
+|:---- |:---- | :--- |:---- |:---- |:---- |
+| [HADOOP-15481](https://issues.apache.org/jira/browse/HADOOP-15481) | Emit FairCallQueue stats as metrics | Major | metrics, rpc-server | Erik Krogen | Christopher Gregorian |
+| [HDFS-14213](https://issues.apache.org/jira/browse/HDFS-14213) | Remove Jansson from BUILDING.txt | Minor | documentation | Akira Ajisaka | Dinesh Chitlangia |
+| [HDFS-14221](https://issues.apache.org/jira/browse/HDFS-14221) | Replace Guava Optional with Java Optional | Major | . | Arpit Agarwal | Arpit Agarwal |
+| [HDFS-14222](https://issues.apache.org/jira/browse/HDFS-14222) | Make ThrottledAsyncChecker constructor public | Major | . | Arpit Agarwal | Arpit Agarwal |
+| [HADOOP-16089](https://issues.apache.org/jira/browse/HADOOP-16089) | AliyunOSS: update oss-sdk version to 3.4.1 | Major | fs/oss | wujinhu | wujinhu |
+| [HDFS-14231](https://issues.apache.org/jira/browse/HDFS-14231) | DataXceiver#run() should not log exceptions caused by InvalidToken exception as an error | Major | hdfs | Kitti Nanasi | Kitti Nanasi |
+| [YARN-7171](https://issues.apache.org/jira/browse/YARN-7171) | RM UI should sort memory / cores numerically | Major | . | Eric Maynard | Ahmed Hussein |
+| [YARN-9282](https://issues.apache.org/jira/browse/YARN-9282) | Typo in javadoc of class LinuxContainerExecutor: hadoop.security.authetication should be 'authentication' | Trivial | . | Szilard Nemeth | Charan Hebri |
+| [HADOOP-16108](https://issues.apache.org/jira/browse/HADOOP-16108) | Tail Follow Interval Should Allow To Specify The Sleep Interval To Save Unnecessary RPC's | Major | . | Harshakiran Reddy | Ayush Saxena |
+| [YARN-8295](https://issues.apache.org/jira/browse/YARN-8295) | [UI2] Improve "Resource Usage" tab error message when there are no data available. | Minor | yarn-ui-v2 | Gergely Novák | Charan Hebri |
+| [YARN-7824](https://issues.apache.org/jira/browse/YARN-7824) | [UI2] Yarn Component Instance page should include link to container logs | Major | yarn-ui-v2 | Yesha Vora | Akhil PB |
+| [HADOOP-15281](https://issues.apache.org/jira/browse/HADOOP-15281) | Distcp to add no-rename copy option | Major | tools/distcp | Steve Loughran | Andrew Olson |
+| [YARN-9309](https://issues.apache.org/jira/browse/YARN-9309) | Improve graph text in SLS to avoid overlapping | Minor | . | Bilwa S T | Bilwa S T |
+| [YARN-9168](https://issues.apache.org/jira/browse/YARN-9168) | DistributedShell client timeout should be -1 by default | Minor | . | Zhankun Tang | Zhankun Tang |
+| [YARN-9087](https://issues.apache.org/jira/browse/YARN-9087) | Improve logging for initialization of Resource plugins | Major | yarn | Szilard Nemeth | Szilard Nemeth |
+| [YARN-9121](https://issues.apache.org/jira/browse/YARN-9121) | Replace GpuDiscoverer.getInstance() to a readable object for easy access control | Major | . | Szilard Nemeth | Szilard Nemeth |
+| [YARN-9139](https://issues.apache.org/jira/browse/YARN-9139) | Simplify initializer code of GpuDiscoverer | Major | . | Szilard Nemeth | Szilard Nemeth |
+| [HDFS-14247](https://issues.apache.org/jira/browse/HDFS-14247) | Repeat adding node description into network topology | Minor | datanode | HuangTao | HuangTao |
+| [YARN-9138](https://issues.apache.org/jira/browse/YARN-9138) | Improve test coverage for nvidia-smi binary execution of GpuDiscoverer | Major | . | Szilard Nemeth | Szilard Nemeth |
+| [MAPREDUCE-7191](https://issues.apache.org/jira/browse/MAPREDUCE-7191) | JobHistoryServer should log exception when loading/parsing history file failed | Minor | mrv2 | Jiandan Yang | Jiandan Yang |
+| [HDFS-14346](https://issues.apache.org/jira/browse/HDFS-14346) | Better time precision in getTimeDuration | Minor | namenode | Chao Sun | Chao Sun |
+| [HDFS-14366](https://issues.apache.org/jira/browse/HDFS-14366) | Improve HDFS append performance | Major | hdfs | Chao Sun | Chao Sun |
+| [MAPREDUCE-7190](https://issues.apache.org/jira/browse/MAPREDUCE-7190) | Add SleepJob additional parameter to make parallel runs distinguishable | Major | . | Adam Antal | Adam Antal |
+| [HADOOP-16208](https://issues.apache.org/jira/browse/HADOOP-16208) | Do Not Log InterruptedException in Client | Minor | common | David Mollitor | David Mollitor |
+| [YARN-9463](https://issues.apache.org/jira/browse/YARN-9463) | Add queueName info when failing with queue capacity sanity check | Trivial | capacity scheduler | Aihua Xu | Aihua Xu |
+| [HADOOP-16227](https://issues.apache.org/jira/browse/HADOOP-16227) | Upgrade checkstyle to 8.19 | Major | build | Akira Ajisaka | Akira Ajisaka |
+| [HDFS-14432](https://issues.apache.org/jira/browse/HDFS-14432) | dfs.datanode.shared.file.descriptor.paths duplicated in hdfs-default.xml | Minor | hdfs | puleya7 | puleya7 |
+| [HDFS-14463](https://issues.apache.org/jira/browse/HDFS-14463) | Add Log Level link under NameNode and DataNode Web UI Utilities dropdown | Trivial | webhdfs | Siyao Meng | Siyao Meng |
+| [YARN-9529](https://issues.apache.org/jira/browse/YARN-9529) | Log correct cpu controller path on error while initializing CGroups. | Major | nodemanager | Jonathan Hung | Jonathan Hung |
+| [HADOOP-16289](https://issues.apache.org/jira/browse/HADOOP-16289) | Allow extra jsvc startup option in hadoop\_start\_secure\_daemon in hadoop-functions.sh | Major | scripts | Siyao Meng | Siyao Meng |
+| [HADOOP-16307](https://issues.apache.org/jira/browse/HADOOP-16307) | Intern User Name and Group Name in FileStatus | Major | fs | David Mollitor | David Mollitor |
+| [HDFS-14507](https://issues.apache.org/jira/browse/HDFS-14507) | Document -blockingDecommission option for hdfs dfsadmin -listOpenFiles | Minor | documentation | Siyao Meng | Siyao Meng |
+| [HDFS-14451](https://issues.apache.org/jira/browse/HDFS-14451) | Incorrect header or version mismatch log message | Minor | ipc | David Mollitor | Shweta |
+| [HDFS-14502](https://issues.apache.org/jira/browse/HDFS-14502) | keepResults option in NNThroughputBenchmark should call saveNamespace() | Major | benchmarks, hdfs | Konstantin Shvachko | Konstantin Shvachko |
+| [HADOOP-16323](https://issues.apache.org/jira/browse/HADOOP-16323) | https everywhere in Maven settings | Minor | build | Akira Ajisaka | Akira Ajisaka |
+| [YARN-9563](https://issues.apache.org/jira/browse/YARN-9563) | Resource report REST API could return NaN or Inf | Minor | . | Ahmed Hussein | Ahmed Hussein |
+| [YARN-9545](https://issues.apache.org/jira/browse/YARN-9545) | Create healthcheck REST endpoint for ATSv2 | Major | ATSv2 | Zoltan Siegl | Zoltan Siegl |
+| [HDFS-10659](https://issues.apache.org/jira/browse/HDFS-10659) | Namenode crashes after Journalnode re-installation in an HA cluster due to missing paxos directory | Major | ha, journal-node | Amit Anand | star |
+| [HDFS-14513](https://issues.apache.org/jira/browse/HDFS-14513) | FSImage which is saving should be clean while NameNode shutdown | Major | namenode | He Xiaoqiao | He Xiaoqiao |
+| [YARN-9543](https://issues.apache.org/jira/browse/YARN-9543) | [UI2] Handle ATSv2 server down or failures cases gracefully in YARN UI v2 | Major | ATSv2, yarn-ui-v2 | Zoltan Siegl | Zoltan Siegl |
+| [HADOOP-16369](https://issues.apache.org/jira/browse/HADOOP-16369) | Fix zstandard shortname misspelled as zts | Major | . | Jonathan Eagles | Jonathan Eagles |
+| [HDFS-14560](https://issues.apache.org/jira/browse/HDFS-14560) | Allow block replication parameters to be refreshable | Major | namenode | Stephen O'Donnell | Stephen O'Donnell |
+| [HDFS-12770](https://issues.apache.org/jira/browse/HDFS-12770) | Add doc about how to disable client socket cache | Trivial | hdfs-client | Weiwei Yang | Weiwei Yang |
+| [HADOOP-9157](https://issues.apache.org/jira/browse/HADOOP-9157) | Better option for curl in hadoop-auth-examples | Minor | documentation | Jingguo Yao | Andras Bokor |
+| [HDFS-14340](https://issues.apache.org/jira/browse/HDFS-14340) | Lower the log level when can't get postOpAttr | Minor | nfs | Anuhan Torgonshar | Anuhan Torgonshar |
+| [HADOOP-15914](https://issues.apache.org/jira/browse/HADOOP-15914) | hadoop jar command has no help argument | Major | common | Adam Antal | Adam Antal |
+| [HADOOP-16156](https://issues.apache.org/jira/browse/HADOOP-16156) | [Clean-up] Remove NULL check before instanceof and fix checkstyle in InnerNodeImpl | Minor | . | Shweta | Shweta |
+| [HADOOP-14385](https://issues.apache.org/jira/browse/HADOOP-14385) | HttpExceptionUtils#validateResponse swallows exceptions | Trivial | . | Wei-Chiu Chuang | Wei-Chiu Chuang |
+| [HDFS-12564](https://issues.apache.org/jira/browse/HDFS-12564) | Add the documents of swebhdfs configurations on the client side | Major | documentation, webhdfs | Takanobu Asanuma | Takanobu Asanuma |
+| [HDFS-14403](https://issues.apache.org/jira/browse/HDFS-14403) | Cost-Based RPC FairCallQueue | Major | ipc, namenode | Erik Krogen | Christopher Gregorian |
+| [HADOOP-16266](https://issues.apache.org/jira/browse/HADOOP-16266) | Add more fine-grained processing time metrics to the RPC layer | Minor | ipc | Christopher Gregorian | Erik Krogen |
+| [YARN-9629](https://issues.apache.org/jira/browse/YARN-9629) | Support configurable MIN\_LOG\_ROLLING\_INTERVAL | Minor | log-aggregation, nodemanager, yarn | Adam Antal | Adam Antal |
+| [HDFS-13694](https://issues.apache.org/jira/browse/HDFS-13694) | Making md5 computing being in parallel with image loading | Major | . | zhouyingchao | Lisheng Sun |
+| [HDFS-14632](https://issues.apache.org/jira/browse/HDFS-14632) | Reduce useless #getNumLiveDataNodes call in SafeModeMonitor | Major | namenode | He Xiaoqiao | He Xiaoqiao |
+| [YARN-9573](https://issues.apache.org/jira/browse/YARN-9573) | DistributedShell cannot specify LogAggregationContext | Major | distributed-shell, log-aggregation, yarn | Adam Antal | Adam Antal |
+| [YARN-9337](https://issues.apache.org/jira/browse/YARN-9337) | GPU auto-discovery script runs even when the resource is given by hand | Major | yarn | Adam Antal | Adam Antal |
+| [YARN-9127](https://issues.apache.org/jira/browse/YARN-9127) | Create more tests to verify GpuDeviceInformationParser | Major | . | Szilard Nemeth | Peter Bacsko |
+| [HDFS-14547](https://issues.apache.org/jira/browse/HDFS-14547) | DirectoryWithQuotaFeature.quota costs additional memory even the storage type quota is not set. | Major | . | Jinglun | Jinglun |
+| [HDFS-14697](https://issues.apache.org/jira/browse/HDFS-14697) | Backport HDFS-14513 to branch-2 | Minor | namenode | He Xiaoqiao | He Xiaoqiao |
+| [YARN-8045](https://issues.apache.org/jira/browse/YARN-8045) | Reduce log output from container status calls | Major | . | Shane Kumpf | Craig Condit |
+| [HDFS-14693](https://issues.apache.org/jira/browse/HDFS-14693) | NameNode should log a warning when EditLog IPC logger's pending size exceeds limit. | Minor | namenode | Xudong Cao | Xudong Cao |
+| [YARN-9094](https://issues.apache.org/jira/browse/YARN-9094) | Remove unused interface method: NodeResourceUpdaterPlugin#handleUpdatedResourceFromRM | Trivial | . | Szilard Nemeth | Gergely Pollak |
+| [YARN-9096](https://issues.apache.org/jira/browse/YARN-9096) | Some GpuResourcePlugin and ResourcePluginManager methods are synchronized unnecessarily | Major | . | Szilard Nemeth | Gergely Pollak |
+| [YARN-9092](https://issues.apache.org/jira/browse/YARN-9092) | Create an object for cgroups mount enable and cgroups mount path as they belong together | Minor | . | Szilard Nemeth | Gergely Pollak |
+| [YARN-9124](https://issues.apache.org/jira/browse/YARN-9124) | Resolve contradiction in ResourceUtils: addMandatoryResources / checkMandatoryResources work differently | Minor | . | Szilard Nemeth | Adam Antal |
+| [YARN-8199](https://issues.apache.org/jira/browse/YARN-8199) | Logging fileSize of log files under NM Local Dir | Major | log-aggregation | Prabhu Joseph | Prabhu Joseph |
+| [YARN-9729](https://issues.apache.org/jira/browse/YARN-9729) | [UI2] Fix error message for logs when ATSv2 is offline | Major | yarn-ui-v2 | Zoltan Siegl | Zoltan Siegl |
+| [YARN-9135](https://issues.apache.org/jira/browse/YARN-9135) | NM State store ResourceMappings serialization are tested with Strings instead of real Device objects | Major | . | Szilard Nemeth | Peter Bacsko |
+| [HDFS-14370](https://issues.apache.org/jira/browse/HDFS-14370) | Edit log tailing fast-path should allow for backoff | Major | namenode, qjm | Erik Krogen | Erik Krogen |
+| [YARN-9442](https://issues.apache.org/jira/browse/YARN-9442) | container working directory has group read permissions | Minor | yarn | Jim Brennan | Jim Brennan |
+| [HADOOP-16459](https://issues.apache.org/jira/browse/HADOOP-16459) | Backport [HADOOP-16266] "Add more fine-grained processing time metrics to the RPC layer" to branch-2 | Major | . | Erik Krogen | Erik Krogen |
+| [HDFS-14491](https://issues.apache.org/jira/browse/HDFS-14491) | More Clarity on Namenode UI Around Blocks and Replicas | Minor | . | Alan Jackoway | Siyao Meng |
+| [YARN-9140](https://issues.apache.org/jira/browse/YARN-9140) | Code cleanup in ResourcePluginManager.initialize and in TestResourcePluginManager | Trivial | . | Szilard Nemeth | Peter Bacsko |
+| [YARN-9488](https://issues.apache.org/jira/browse/YARN-9488) | Skip YARNFeatureNotEnabledException from ClientRMService | Minor | resourcemanager | Prabhu Joseph | Prabhu Joseph |
+| [YARN-8586](https://issues.apache.org/jira/browse/YARN-8586) | Extract log aggregation related fields and methods from RMAppImpl | Major | . | Szilard Nemeth | Peter Bacsko |
+| [YARN-9100](https://issues.apache.org/jira/browse/YARN-9100) | Add tests for GpuResourceAllocator and do minor code cleanup | Major | . | Szilard Nemeth | Peter Bacsko |
+| [HADOOP-15246](https://issues.apache.org/jira/browse/HADOOP-15246) | SpanReceiverInfo - Prefer ArrayList over LinkedList | Trivial | common | David Mollitor | David Mollitor |
+| [HADOOP-16158](https://issues.apache.org/jira/browse/HADOOP-16158) | DistCp to support checksum validation when copy blocks in parallel | Major | tools/distcp | Kai Xie | Kai Xie |
+| [HDFS-14746](https://issues.apache.org/jira/browse/HDFS-14746) | Trivial test code update after HDFS-14687 | Trivial | ec | Wei-Chiu Chuang | kevin su |
+| [HDFS-13709](https://issues.apache.org/jira/browse/HDFS-13709) | Report bad block to NN when transfer block encounter EIO exception | Major | datanode | Chen Zhang | Chen Zhang |
+| [HDFS-14665](https://issues.apache.org/jira/browse/HDFS-14665) | HttpFS: LISTSTATUS response is missing HDFS-specific fields | Major | httpfs | Siyao Meng | Siyao Meng |
+| [HDFS-14276](https://issues.apache.org/jira/browse/HDFS-14276) | [SBN read] Reduce tailing overhead | Major | ha, namenode | Wei-Chiu Chuang | Ayush Saxena |
+| [HDFS-14748](https://issues.apache.org/jira/browse/HDFS-14748) | Make DataNodePeerMetrics#minOutlierDetectionSamples configurable | Major | . | Lisheng Sun | Lisheng Sun |
+| [HADOOP-15998](https://issues.apache.org/jira/browse/HADOOP-15998) | Ensure jar validation works on Windows. | Blocker | build | Brian Grunkemeyer | Brian Grunkemeyer |
+| [HDFS-14633](https://issues.apache.org/jira/browse/HDFS-14633) | The StorageType quota and consume in QuotaFeature is not handled for rename | Major | . | Jinglun | Jinglun |
+| [YARN-9795](https://issues.apache.org/jira/browse/YARN-9795) | ClusterMetrics to include AM allocation delay | Minor | . | Fengnan Li | Fengnan Li |
+| [YARN-8995](https://issues.apache.org/jira/browse/YARN-8995) | Log events info in AsyncDispatcher when event queue size cumulatively reaches a certain number every time. | Major | metrics, nodemanager, resourcemanager | zhuqi | zhuqi |
+
+
+### BUG FIXES:
+
+| JIRA | Summary | Priority | Component | Reporter | Contributor |
+|:---- |:---- | :--- |:---- |:---- |:---- |
+| [HDFS-13642](https://issues.apache.org/jira/browse/HDFS-13642) | Creating a file with block size smaller than EC policy's cell size should fail | Major | erasure-coding | Xiao Chen | Xiao Chen |
+| [HADOOP-15948](https://issues.apache.org/jira/browse/HADOOP-15948) | Inconsistency in get and put syntax if filename/dirname contains space | Minor | fs | vivek kumar | Ayush Saxena |
+| [HDFS-13816](https://issues.apache.org/jira/browse/HDFS-13816) | dfs.getQuotaUsage() throws NPE on non-existent dir instead of FileNotFoundException | Major | namenode | Vinayakumar B | Vinayakumar B |
+| [HADOOP-15966](https://issues.apache.org/jira/browse/HADOOP-15966) | Hadoop Kerberos broken on macos as java.security.krb5.realm is reset: Null realm name (601) | Major | scripts | Steve Loughran | Steve Loughran |
+| [HADOOP-16028](https://issues.apache.org/jira/browse/HADOOP-16028) | Fix NetworkTopology chooseRandom function to support excluded nodes | Major | . | Sihai Ke | Sihai Ke |
+| [YARN-9162](https://issues.apache.org/jira/browse/YARN-9162) | Fix TestRMAdminCLI#testHelp | Major | resourcemanager, test | Ayush Saxena | Ayush Saxena |
+| [HADOOP-16031](https://issues.apache.org/jira/browse/HADOOP-16031) | TestSecureLogins#testValidKerberosName fails | Major | security | Akira Ajisaka | Akira Ajisaka |
+| [HADOOP-16016](https://issues.apache.org/jira/browse/HADOOP-16016) | TestSSLFactory#testServerWeakCiphers sporadically fails in precommit builds | Major | security, test | Jason Lowe | Akira Ajisaka |
+| [HDFS-14198](https://issues.apache.org/jira/browse/HDFS-14198) | Upload and Create button doesn't get enabled after getting reset. | Major | . | Ayush Saxena | Ayush Saxena |
+| [YARN-9203](https://issues.apache.org/jira/browse/YARN-9203) | Fix typos in yarn-default.xml | Trivial | documentation | Rahul Padmanabhan | Rahul Padmanabhan |
+| [HDFS-14207](https://issues.apache.org/jira/browse/HDFS-14207) | ZKFC should catch exception when ha configuration missing | Major | hdfs | Fei Hui | Fei Hui |
+| [HDFS-14218](https://issues.apache.org/jira/browse/HDFS-14218) | EC: Ls -e throw NPE when directory ec policy is disabled | Major | . | Surendra Singh Lilhore | Ayush Saxena |
+| [YARN-9210](https://issues.apache.org/jira/browse/YARN-9210) | RM nodes web page can not display node info | Blocker | yarn | Jiandan Yang | Jiandan Yang |
+| [YARN-8961](https://issues.apache.org/jira/browse/YARN-8961) | [UI2] Flow Run End Time shows 'Invalid date' | Major | . | Charan Hebri | Akhil PB |
+| [YARN-7088](https://issues.apache.org/jira/browse/YARN-7088) | Add application launch time to Resource Manager REST API | Major | . | Abdullah Yousufi | Kanwaljeet Sachdev |
+| [YARN-9222](https://issues.apache.org/jira/browse/YARN-9222) | Print launchTime in ApplicationSummary | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-8901](https://issues.apache.org/jira/browse/YARN-8901) | Restart "NEVER" policy does not work with component dependency | Critical | . | Yesha Vora | Suma Shivaprasad |
+| [YARN-9237](https://issues.apache.org/jira/browse/YARN-9237) | NM should ignore sending finished apps to RM during RM fail-over | Major | yarn | Jiandan Yang | Jiandan Yang |
+| [YARN-6616](https://issues.apache.org/jira/browse/YARN-6616) | YARN AHS shows submitTime for jobs same as startTime | Minor | . | Prabhu Joseph | Prabhu Joseph |
+| [YARN-9099](https://issues.apache.org/jira/browse/YARN-9099) | GpuResourceAllocator#getReleasingGpus calculates number of GPUs in a wrong way | Major | . | Szilard Nemeth | Szilard Nemeth |
+| [HADOOP-16086](https://issues.apache.org/jira/browse/HADOOP-16086) | Backport HADOOP-15549 to branch-3.1 | Major | metrics | Yuming Wang | Todd Lipcon |
+| [YARN-9206](https://issues.apache.org/jira/browse/YARN-9206) | RMServerUtils does not count SHUTDOWN as an accepted state | Major | . | Kuhu Shukla | Kuhu Shukla |
+| [HADOOP-16096](https://issues.apache.org/jira/browse/HADOOP-16096) | HADOOP-15281/distcp -Xdirect needs to use commons-logging on 3.1 | Critical | . | Eric Payne | Steve Loughran |
+| [HDFS-14140](https://issues.apache.org/jira/browse/HDFS-14140) | JournalNodeSyncer authentication is failing in secure cluster | Major | journal-node, security | Surendra Singh Lilhore | Surendra Singh Lilhore |
+| [YARN-9257](https://issues.apache.org/jira/browse/YARN-9257) | Distributed Shell client throws a NPE for a non-existent queue | Major | distributed-shell | Charan Hebri | Charan Hebri |
+| [YARN-8761](https://issues.apache.org/jira/browse/YARN-8761) | Service AM support for decommissioning component instances | Major | . | Billie Rinaldi | Billie Rinaldi |
+| [HDFS-14266](https://issues.apache.org/jira/browse/HDFS-14266) | EC : Fsck -blockId shows null for EC Blocks if One Block Is Not Available. | Major | . | Harshakiran Reddy | Ayush Saxena |
+| [HDFS-14274](https://issues.apache.org/jira/browse/HDFS-14274) | EC: NPE While Listing EC Policy For A Directory Following Replication Policy. | Major | erasure-coding | Souryakanta Dwivedy | Ayush Saxena |
+| [HDFS-14263](https://issues.apache.org/jira/browse/HDFS-14263) | Remove unnecessary block file exists check from FsDatasetImpl#getBlockInputStream() | Major | datanode | Surendra Singh Lilhore | Surendra Singh Lilhore |
+| [YARN-7761](https://issues.apache.org/jira/browse/YARN-7761) | [UI2] Clicking 'master container log' or 'Link' next to 'log' under application's appAttempt goes to Old UI's Log link | Major | yarn-ui-v2 | Sumana Sathish | Akhil PB |
+| [YARN-9295](https://issues.apache.org/jira/browse/YARN-9295) | [UI2] Fix label typo in Cluster Overview page | Trivial | yarn-ui-v2 | Charan Hebri | Charan Hebri |
+| [YARN-9284](https://issues.apache.org/jira/browse/YARN-9284) | Fix the unit of yarn.service.am-resource.memory in the document | Minor | documentation, yarn-native-services | Masahiro Tanaka | Masahiro Tanaka |
+| [YARN-9283](https://issues.apache.org/jira/browse/YARN-9283) | Javadoc of LinuxContainerExecutor#addSchedPriorityCommand has a wrong property name as reference | Minor | documentation | Szilard Nemeth | Adam Antal |
+| [YARN-9286](https://issues.apache.org/jira/browse/YARN-9286) | [Timeline Server] Sorting based on FinalStatus shows pop-up message | Minor | timelineserver | Nallasivan | Bilwa S T |
+| [HDFS-14081](https://issues.apache.org/jira/browse/HDFS-14081) | hdfs dfsadmin -metasave metasave\_test results NPE | Major | hdfs | Shweta | Shweta |
+| [HADOOP-15813](https://issues.apache.org/jira/browse/HADOOP-15813) | Enable more reliable SSL connection reuse | Major | common | Daryn Sharp | Daryn Sharp |
+| [HADOOP-16105](https://issues.apache.org/jira/browse/HADOOP-16105) | WASB in secure mode does not set connectingUsingSAS | Major | fs/azure | Steve Loughran | Steve Loughran |
+| [YARN-9238](https://issues.apache.org/jira/browse/YARN-9238) | Avoid allocating opportunistic containers to previous/removed/non-exist application attempt | Critical | . | lujie | lujie |
+| [YARN-9118](https://issues.apache.org/jira/browse/YARN-9118) | Handle exceptions with parsing user defined GPU devices in GpuDiscoverer | Major | . | Szilard Nemeth | Szilard Nemeth |
+| [YARN-9317](https://issues.apache.org/jira/browse/YARN-9317) | Avoid repeated YarnConfiguration#timelineServiceV2Enabled check | Major | . | Bibin A Chundatt | Prabhu Joseph |
+| [YARN-9213](https://issues.apache.org/jira/browse/YARN-9213) | RM Web UI v1 does not show custom resource allocations for containers page | Major | . | Szilard Nemeth | Szilard Nemeth |
+| [YARN-9248](https://issues.apache.org/jira/browse/YARN-9248) | RMContainerImpl:Invalid event: ACQUIRED at KILLED | Major | . | lujie | lujie |
+| [HADOOP-16018](https://issues.apache.org/jira/browse/HADOOP-16018) | DistCp won't reassemble chunks when blocks per chunk \> 0 | Major | tools/distcp | Kai Xie | Kai Xie |
+| [YARN-9334](https://issues.apache.org/jira/browse/YARN-9334) | YARN Service Client does not work with SPNEGO when knox is configured | Major | yarn-native-services | Tarun Parimi | Billie Rinaldi |
+| [HDFS-14305](https://issues.apache.org/jira/browse/HDFS-14305) | Serial number in BlockTokenSecretManager could overlap between different namenodes | Major | namenode, security | Chao Sun | He Xiaoqiao |
+| [HDFS-14314](https://issues.apache.org/jira/browse/HDFS-14314) | fullBlockReportLeaseId should be reset after registering to NN | Critical | datanode | star | star |
+| [YARN-8803](https://issues.apache.org/jira/browse/YARN-8803) | [UI2] Show flow runs in the order of recently created time in graph widgets | Major | yarn-ui-v2 | Akhil PB | Akhil PB |
+| [HADOOP-16114](https://issues.apache.org/jira/browse/HADOOP-16114) | NetUtils#canonicalizeHost gives different value for same host | Minor | net | Praveen Krishna | Praveen Krishna |
+| [HDFS-14317](https://issues.apache.org/jira/browse/HDFS-14317) | Standby does not trigger edit log rolling when in-progress edit log tailing is enabled | Critical | . | Ekanth Sethuramalingam | Ekanth Sethuramalingam |
+| [HDFS-14333](https://issues.apache.org/jira/browse/HDFS-14333) | Datanode fails to start if any disk has errors during Namenode registration | Major | datanode | Stephen O'Donnell | Stephen O'Donnell |
+| [HADOOP-16192](https://issues.apache.org/jira/browse/HADOOP-16192) | CallQueue backoff bug fixes: doesn't perform backoff when add() is used, and doesn't update backoff when refreshed | Major | ipc | Erik Krogen | Erik Krogen |
+| [HDFS-14037](https://issues.apache.org/jira/browse/HDFS-14037) | Fix SSLFactory truststore reloader thread leak in URLConnectionFactory | Major | hdfs-client, webhdfs | Takanobu Asanuma | Takanobu Asanuma |
+| [HADOOP-16225](https://issues.apache.org/jira/browse/HADOOP-16225) | Fix links to the developer mailing lists in DownstreamDev.md | Minor | documentation | Akira Ajisaka | Wanqiang Ji |
+| [HADOOP-16232](https://issues.apache.org/jira/browse/HADOOP-16232) | Fix errors in the checkstyle configration xmls | Major | build | Akira Ajisaka | Wanqiang Ji |
+| [HDFS-14389](https://issues.apache.org/jira/browse/HDFS-14389) | getAclStatus returns incorrect permissions and owner when an iNodeAttributeProvider is configured | Major | namenode | Stephen O'Donnell | Stephen O'Donnell |
+| [HDFS-14407](https://issues.apache.org/jira/browse/HDFS-14407) | Fix misuse of SLF4j logging API in DatasetVolumeChecker#checkAllVolumes | Minor | . | Wanqiang Ji | Wanqiang Ji |
+| [YARN-9413](https://issues.apache.org/jira/browse/YARN-9413) | Queue resource leak after app fail for CapacityScheduler | Major | capacityscheduler | Tao Yang | Tao Yang |
+| [HADOOP-14544](https://issues.apache.org/jira/browse/HADOOP-14544) | DistCp documentation for command line options is misaligned. | Minor | documentation | Chris Nauroth | Masatake Iwasaki |
+| [HDFS-10477](https://issues.apache.org/jira/browse/HDFS-10477) | Stop decommission a rack of DataNodes caused NameNode fail over to standby | Major | namenode | yunjiong zhao | yunjiong zhao |
+| [YARN-6695](https://issues.apache.org/jira/browse/YARN-6695) | Race condition in RM for publishing container events vs appFinished events causes NPE | Critical | . | Rohith Sharma K S | Prabhu Joseph |
+| [YARN-8622](https://issues.apache.org/jira/browse/YARN-8622) | NodeManager native build fails due to getgrouplist not found on macOS | Major | nodemanager | Ewan Higgs | Siyao Meng |
+| [HADOOP-16265](https://issues.apache.org/jira/browse/HADOOP-16265) | Configuration#getTimeDuration is not consistent between default value and manual settings. | Major | . | star | star |
+| [YARN-9307](https://issues.apache.org/jira/browse/YARN-9307) | node\_partitions constraint does not work | Major | . | kyungwan nam | kyungwan nam |
+| [HDFS-13677](https://issues.apache.org/jira/browse/HDFS-13677) | Dynamic refresh Disk configuration results in overwriting VolumeMap | Blocker | . | xuzq | xuzq |
+| [YARN-9285](https://issues.apache.org/jira/browse/YARN-9285) | RM UI progress column is of wrong type | Minor | yarn | Ahmed Hussein | Ahmed Hussein |
+| [HADOOP-16278](https://issues.apache.org/jira/browse/HADOOP-16278) | With S3A Filesystem, Long Running services End up Doing lot of GC and eventually die | Major | common, hadoop-aws, metrics | Rajat Khandelwal | Rajat Khandelwal |
+| [YARN-9504](https://issues.apache.org/jira/browse/YARN-9504) | [UI2] Fair scheduler queue view page does not show actual capacity | Major | fairscheduler, yarn-ui-v2 | Zoltan Siegl | Zoltan Siegl |
+| [YARN-9519](https://issues.apache.org/jira/browse/YARN-9519) | TFile log aggregation file format is not working for yarn.log-aggregation.TFile.remote-app-log-dir config | Major | log-aggregation | Adam Antal | Adam Antal |
+| [HADOOP-16247](https://issues.apache.org/jira/browse/HADOOP-16247) | NPE in FsUrlConnection | Major | hdfs-client | Karthik Palanisamy | Karthik Palanisamy |
+| [HADOOP-16248](https://issues.apache.org/jira/browse/HADOOP-16248) | MutableQuantiles leak memory under heavy load | Major | metrics | Alexis Daboville | Alexis Daboville |
+| [HDFS-14323](https://issues.apache.org/jira/browse/HDFS-14323) | Distcp fails in Hadoop 3.x when 2.x source webhdfs url has special characters in hdfs file path | Major | webhdfs | Srinivasu Majeti | Srinivasu Majeti |
+| [MAPREDUCE-7205](https://issues.apache.org/jira/browse/MAPREDUCE-7205) | Treat container scheduler kill exit code as a task attempt killing event | Major | applicationmaster, mr-am, mrv2 | Wanqiang Ji | Wanqiang Ji |
+| [HDFS-14500](https://issues.apache.org/jira/browse/HDFS-14500) | NameNode StartupProgress continues to report edit log segments after the LOADING\_EDITS phase is finished | Major | namenode | Erik Krogen | Erik Krogen |
+| [HADOOP-16331](https://issues.apache.org/jira/browse/HADOOP-16331) | Fix ASF License check in pom.xml | Major | . | Wanqiang Ji | Akira Ajisaka |
+| [YARN-9542](https://issues.apache.org/jira/browse/YARN-9542) | Fix LogsCLI guessAppOwner ignores custom file format suffix | Minor | log-aggregation | Prabhu Joseph | Prabhu Joseph |
+| [HDFS-14512](https://issues.apache.org/jira/browse/HDFS-14512) | ONE\_SSD policy will be violated while write data with DistributedFileSystem.create(....favoredNodes) | Major | . | Shen Yinjie | Ayush Saxena |
+| [HADOOP-16334](https://issues.apache.org/jira/browse/HADOOP-16334) | Fix yetus-wrapper not working when HADOOP\_YETUS\_VERSION \>= 0.9.0 | Major | yetus | Wanqiang Ji | Wanqiang Ji |
+| [HDFS-14521](https://issues.apache.org/jira/browse/HDFS-14521) | Suppress setReplication logging. | Major | . | Kihwal Lee | Kihwal Lee |
+| [YARN-9507](https://issues.apache.org/jira/browse/YARN-9507) | Fix NPE in NodeManager#serviceStop on startup failure | Minor | . | Bilwa S T | Bilwa S T |
+| [YARN-8947](https://issues.apache.org/jira/browse/YARN-8947) | [UI2] Active User info missing from UI2 | Major | yarn-ui-v2 | Akhil PB | Akhil PB |
+| [YARN-8906](https://issues.apache.org/jira/browse/YARN-8906) | [UI2] NM hostnames not displayed correctly in Node Heatmap Chart | Major | . | Charan Hebri | Akhil PB |
+| [YARN-8625](https://issues.apache.org/jira/browse/YARN-8625) | Aggregate Resource Allocation for each job is not present in ATS | Major | ATSv2 | Prabhu Joseph | Prabhu Joseph |
+| [HADOOP-16345](https://issues.apache.org/jira/browse/HADOOP-16345) | Potential NPE when instantiating FairCallQueue metrics | Major | ipc | Erik Krogen | Erik Krogen |
+| [YARN-9594](https://issues.apache.org/jira/browse/YARN-9594) | Fix missing break statement in ContainerScheduler#handle | Major | . | lujie | lujie |
+| [YARN-9565](https://issues.apache.org/jira/browse/YARN-9565) | RMAppImpl#ranNodes not cleared on FinalTransition | Major | . | Bibin A Chundatt | Bilwa S T |
+| [YARN-9547](https://issues.apache.org/jira/browse/YARN-9547) | ContainerStatusPBImpl default execution type is not returned | Major | . | Bibin A Chundatt | Bilwa S T |
+| [HDFS-13231](https://issues.apache.org/jira/browse/HDFS-13231) | Extend visualization for Decommissioning, Maintenance Mode under Datanode tab in the NameNode UI | Major | datanode, namenode | Haibo Yan | Stephen O'Donnell |
+| [YARN-9621](https://issues.apache.org/jira/browse/YARN-9621) | FIX TestDSWithMultipleNodeManager.testDistributedShellWithPlacementConstraint on branch-3.1 | Major | distributed-shell, test | Peter Bacsko | Prabhu Joseph |
+| [HDFS-14535](https://issues.apache.org/jira/browse/HDFS-14535) | The default 8KB buffer in requestFileDescriptors#BufferedOutputStream is causing lots of heap allocation in HBase when using short-circut read | Major | hdfs-client | Zheng Hu | Zheng Hu |
+| [HDFS-13730](https://issues.apache.org/jira/browse/HDFS-13730) | BlockReaderRemote.sendReadResult throws NPE | Major | hdfs-client | Wei-Chiu Chuang | Yuanbo Liu |
+| [YARN-9584](https://issues.apache.org/jira/browse/YARN-9584) | Should put initializeProcessTrees method call before get pid | Critical | nodemanager | Wanqiang Ji | Wanqiang Ji |
+| [HDFS-14010](https://issues.apache.org/jira/browse/HDFS-14010) | Pass correct DF usage to ReservedSpaceCalculator builder | Minor | . | Lukas Majercak | Lukas Majercak |
+| [HDFS-14078](https://issues.apache.org/jira/browse/HDFS-14078) | Admin helper fails to prettify NullPointerExceptions | Major | . | Elek, Marton | Elek, Marton |
+| [HDFS-14101](https://issues.apache.org/jira/browse/HDFS-14101) | Random failure of testListCorruptFilesCorruptedBlock | Major | test | Kihwal Lee | Zsolt Venczel |
+| [HDFS-14465](https://issues.apache.org/jira/browse/HDFS-14465) | When the Block expected replications is larger than the number of DataNodes, entering maintenance will never exit. | Major | . | Yicong Cai | Yicong Cai |
+| [HDFS-12487](https://issues.apache.org/jira/browse/HDFS-12487) | FsDatasetSpi.isValidBlock() lacks null pointer check inside and neither do the callers | Major | balancer & mover, diskbalancer | liumi | liumi |
+| [HDFS-14074](https://issues.apache.org/jira/browse/HDFS-14074) | DataNode runs async disk checks maybe throws NullPointerException, and DataNode failed to register to NameSpace. | Major | hdfs | guangyi lu | guangyi lu |
+| [HDFS-14541](https://issues.apache.org/jira/browse/HDFS-14541) | When evictableMmapped or evictable size is zero, do not throw NoSuchElementException | Major | hdfs-client, performance | Zheng Hu | Lisheng Sun |
+| [HDFS-14598](https://issues.apache.org/jira/browse/HDFS-14598) | Findbugs warning caused by HDFS-12487 | Minor | diskbalancer | Wei-Chiu Chuang | He Xiaoqiao |
+| [YARN-9639](https://issues.apache.org/jira/browse/YARN-9639) | DecommissioningNodesWatcher cause memory leak | Blocker | . | Bibin A Chundatt | Bilwa S T |
+| [YARN-9327](https://issues.apache.org/jira/browse/YARN-9327) | Improve synchronisation in ProtoUtils#convertToProtoFormat block | Critical | . | Bibin A Chundatt | Bibin A Chundatt |
+| [YARN-9655](https://issues.apache.org/jira/browse/YARN-9655) | AllocateResponse in FederationInterceptor lost applicationPriority | Major | federation | hunshenshi | hunshenshi |
+| [HADOOP-16385](https://issues.apache.org/jira/browse/HADOOP-16385) | Namenode crashes with "RedundancyMonitor thread received Runtime exception" | Major | . | krishna reddy | Ayush Saxena |
+| [YARN-9644](https://issues.apache.org/jira/browse/YARN-9644) | First RMContext object is always leaked during switch over | Blocker | . | Bibin A Chundatt | Bibin A Chundatt |
+| [HDFS-14629](https://issues.apache.org/jira/browse/HDFS-14629) | Property value Hard Coded in DNConf.java | Trivial | . | hemanthboyina | hemanthboyina |
+| [YARN-9557](https://issues.apache.org/jira/browse/YARN-9557) | Application fails in diskchecker when ReadWriteDiskValidator is configured. | Critical | nodemanager | Anuruddh Nayak | Bilwa S T |
+| [HDFS-12703](https://issues.apache.org/jira/browse/HDFS-12703) | Exceptions are fatal to decommissioning monitor | Critical | namenode | Daryn Sharp | He Xiaoqiao |
+| [HDFS-12748](https://issues.apache.org/jira/browse/HDFS-12748) | NameNode memory leak when accessing webhdfs GETHOMEDIRECTORY | Major | hdfs | Jiandan Yang | Weiwei Yang |
+| [YARN-9625](https://issues.apache.org/jira/browse/YARN-9625) | UI2 - No link to a queue on the Queues page for Fair Scheduler | Major | . | Charan Hebri | Zoltan Siegl |
+| [HDFS-14466](https://issues.apache.org/jira/browse/HDFS-14466) | Add a regression test for HDFS-14323 | Minor | fs, test, webhdfs | Yuya Ebihara | Masatake Iwasaki |
+| [YARN-9235](https://issues.apache.org/jira/browse/YARN-9235) | If linux container executor is not set for a GPU cluster GpuResourceHandlerImpl is not initialized and NPE is thrown | Major | yarn | Antal Bálint Steinbach | Adam Antal |
+| [YARN-9626](https://issues.apache.org/jira/browse/YARN-9626) | UI2 - Fair scheduler queue apps page issues | Major | . | Charan Hebri | Zoltan Siegl |
+| [YARN-9682](https://issues.apache.org/jira/browse/YARN-9682) | Wrong log message when finalizing the upgrade | Trivial | . | kyungwan nam | kyungwan nam |
+| [HADOOP-16440](https://issues.apache.org/jira/browse/HADOOP-16440) | Distcp can not preserve timestamp with -delete option | Major | . | ludun | ludun |
+| [MAPREDUCE-7076](https://issues.apache.org/jira/browse/MAPREDUCE-7076) | TestNNBench#testNNBenchCreateReadAndDelete failing in our internal build | Minor | test | Rushabh S Shah | kevin su |
+| [YARN-9668](https://issues.apache.org/jira/browse/YARN-9668) | UGI conf doesn't read user overridden configurations on RM and NM startup | Major | . | Jonathan Hung | Jonathan Hung |
+| [HADOOP-9844](https://issues.apache.org/jira/browse/HADOOP-9844) | NPE when trying to create an error message response of SASL RPC | Major | ipc | Steve Loughran | Steve Loughran |
+| [HADOOP-16245](https://issues.apache.org/jira/browse/HADOOP-16245) | Enabling SSL within LdapGroupsMapping can break system SSL configs | Major | common, security | Erik Krogen | Erik Krogen |
+| [HDFS-14429](https://issues.apache.org/jira/browse/HDFS-14429) | Block remain in COMMITTED but not COMPLETE caused by Decommission | Major | . | Yicong Cai | Yicong Cai |
+| [HADOOP-16435](https://issues.apache.org/jira/browse/HADOOP-16435) | RpcMetrics should not be retained forever | Critical | rpc-server | Zoltan Haindrich | Zoltan Haindrich |
+| [YARN-9596](https://issues.apache.org/jira/browse/YARN-9596) | QueueMetrics has incorrect metrics when labelled partitions are involved | Major | capacity scheduler | Muhammad Samir Khan | Muhammad Samir Khan |
+| [MAPREDUCE-7225](https://issues.apache.org/jira/browse/MAPREDUCE-7225) | Fix broken current folder expansion during MR job start | Major | mrv2 | Adam Antal | Peter Bacsko |
+| [HDFS-13529](https://issues.apache.org/jira/browse/HDFS-13529) | Fix default trash policy emptier trigger time correctly | Major | namenode | He Xiaoqiao | He Xiaoqiao |
+| [HADOOP-15681](https://issues.apache.org/jira/browse/HADOOP-15681) | AuthenticationFilter should generate valid date format for Set-Cookie header regardless of default Locale | Minor | security | Cao Manh Dat | Cao Manh Dat |
+| [HDFS-14685](https://issues.apache.org/jira/browse/HDFS-14685) | DefaultAuditLogger doesn't print CallerContext | Major | hdfs | xuzq | xuzq |
+| [HDFS-14462](https://issues.apache.org/jira/browse/HDFS-14462) | WebHDFS throws "Error writing request body to server" instead of DSQuotaExceededException | Major | webhdfs | Erik Krogen | Simbarashe Dzinamarira |
+| [HDFS-14557](https://issues.apache.org/jira/browse/HDFS-14557) | JournalNode error: Can't scan a pre-transactional edit log | Major | ha | Wei-Chiu Chuang | Stephen O'Donnell |
+| [HDFS-14692](https://issues.apache.org/jira/browse/HDFS-14692) | Upload button should not encode complete url | Major | . | Lokesh Jain | Lokesh Jain |
+| [HDFS-14631](https://issues.apache.org/jira/browse/HDFS-14631) | The DirectoryScanner doesn't fix the wrongly placed replica. | Major | . | Jinglun | Jinglun |
+| [YARN-9685](https://issues.apache.org/jira/browse/YARN-9685) | NPE when rendering the info table of leaf queue in non-accessible partitions | Major | capacityscheduler | Tao Yang | Tao Yang |
+| [HDFS-14459](https://issues.apache.org/jira/browse/HDFS-14459) | ClosedChannelException silently ignored in FsVolumeList.addBlockPool() | Major | datanode | Stephen O'Donnell | Stephen O'Donnell |
+| [HDFS-13359](https://issues.apache.org/jira/browse/HDFS-13359) | DataXceiver hung due to the lock in FsDatasetImpl#getBlockInputStream | Major | datanode | Yiqun Lin | Yiqun Lin |
+| [YARN-9451](https://issues.apache.org/jira/browse/YARN-9451) | AggregatedLogsBlock shows wrong NM http port | Minor | nodemanager | Prabhu Joseph | Prabhu Joseph |
+| [YARN-9723](https://issues.apache.org/jira/browse/YARN-9723) | ApplicationPlacementContext is not required for terminated jobs during recovery | Major | resourcemanager | Prabhu Joseph | Prabhu Joseph |
+| [HDFS-12914](https://issues.apache.org/jira/browse/HDFS-12914) | Block report leases cause missing blocks until next report | Critical | namenode | Daryn Sharp | Santosh Marella |
+| [HDFS-14148](https://issues.apache.org/jira/browse/HDFS-14148) | HDFS OIV ReverseXML SnapshotSection parser throws exception when there are more than one snapshottable directory | Major | hdfs | Siyao Meng | Siyao Meng |
+| [HDFS-14595](https://issues.apache.org/jira/browse/HDFS-14595) | HDFS-11848 breaks API compatibility | Blocker | . | Wei-Chiu Chuang | Siyao Meng |
+| [HDFS-14423](https://issues.apache.org/jira/browse/HDFS-14423) | Percent (%) and plus (+) characters no longer work in WebHDFS | Major | webhdfs | Jing Wang | Masatake Iwasaki |
+| [MAPREDUCE-7230](https://issues.apache.org/jira/browse/MAPREDUCE-7230) | TestHSWebApp.testLogsViewSingle fails | Major | jobhistoryserver, test | Prabhu Joseph | Prabhu Joseph |
+| [HDFS-14687](https://issues.apache.org/jira/browse/HDFS-14687) | Standby Namenode never come out of safemode when EC files are being written. | Critical | ec, namenode | Surendra Singh Lilhore | Surendra Singh Lilhore |
+| [HDFS-13101](https://issues.apache.org/jira/browse/HDFS-13101) | Yet another fsimage corruption related to snapshot | Major | snapshots | Yongjun Zhang | Shashikant Banerjee |
+| [HDFS-13201](https://issues.apache.org/jira/browse/HDFS-13201) | Fix prompt message in testPolicyAndStateCantBeNull | Minor | . | chencan | chencan |
+| [HDFS-14311](https://issues.apache.org/jira/browse/HDFS-14311) | Multi-threading conflict at layoutVersion when loading block pool storage | Major | rolling upgrades | Yicong Cai | Yicong Cai |
+| [HDFS-14582](https://issues.apache.org/jira/browse/HDFS-14582) | Failed to start DN with ArithmeticException when NULL checksum used | Major | datanode | Surendra Singh Lilhore | Surendra Singh Lilhore |
+| [HADOOP-16494](https://issues.apache.org/jira/browse/HADOOP-16494) | Add SHA-256 or SHA-512 checksum to release artifacts to comply with the release distribution policy | Blocker | build | Akira Ajisaka | Akira Ajisaka |
+| [YARN-9774](https://issues.apache.org/jira/browse/YARN-9774) | Fix order of arguments for assertEquals in TestSLSUtils | Minor | test | Nikhil Navadiya | Nikhil Navadiya |
+| [HDFS-13596](https://issues.apache.org/jira/browse/HDFS-13596) | NN restart fails after RollingUpgrade from 2.x to 3.x | Blocker | hdfs | Hanisha Koneru | Fei Hui |
+| [HDFS-14396](https://issues.apache.org/jira/browse/HDFS-14396) | Failed to load image from FSImageFile when downgrade from 3.x to 2.x | Blocker | rolling upgrades | Fei Hui | Fei Hui |
+| [YARN-9642](https://issues.apache.org/jira/browse/YARN-9642) | Fix Memory Leak in AbstractYarnScheduler caused by timer | Blocker | resourcemanager | Bibin A Chundatt | Bibin A Chundatt |
+| [HDFS-13977](https://issues.apache.org/jira/browse/HDFS-13977) | NameNode can kill itself if it tries to send too many txns to a QJM simultaneously | Major | namenode, qjm | Erik Krogen | Erik Krogen |
+| [YARN-9438](https://issues.apache.org/jira/browse/YARN-9438) | launchTime not written to state store for running applications | Major | . | Jonathan Hung | Jonathan Hung |
+| [HDFS-12212](https://issues.apache.org/jira/browse/HDFS-12212) | Options.Rename.To\_TRASH is considered even when Options.Rename.NONE is specified | Major | namenode | Vinayakumar B | Vinayakumar B |
+| [HDFS-8178](https://issues.apache.org/jira/browse/HDFS-8178) | QJM doesn't move aside stale inprogress edits files | Major | qjm | Zhe Zhang | Istvan Fajth |
+| [HDFS-14706](https://issues.apache.org/jira/browse/HDFS-14706) | Checksums are not checked if block meta file is less than 7 bytes | Major | . | Stephen O'Donnell | Stephen O'Donnell |
+| [YARN-9797](https://issues.apache.org/jira/browse/YARN-9797) | LeafQueue#activateApplications should use resourceCalculator#fitsIn | Blocker | . | Bibin A Chundatt | Bilwa S T |
+| [YARN-9785](https://issues.apache.org/jira/browse/YARN-9785) | Fix DominantResourceCalculator when one resource is zero | Blocker | . | Bilwa S T | Bilwa S T |
+| [YARN-9817](https://issues.apache.org/jira/browse/YARN-9817) | Fix failing testcases due to not initialized AsyncDispatcher - ArithmeticException: / by zero | Major | test | Prabhu Joseph | Prabhu Joseph |
+
+
+### TESTS:
+
+| JIRA | Summary | Priority | Component | Reporter | Contributor |
+|:---- |:---- | :--- |:---- |:---- |:---- |
+| [YARN-9315](https://issues.apache.org/jira/browse/YARN-9315) | TestCapacitySchedulerMetrics fails intermittently | Minor | capacity scheduler | Prabhu Joseph | Prabhu Joseph |
+| [YARN-9316](https://issues.apache.org/jira/browse/YARN-9316) | TestPlacementConstraintsUtil#testInterAppConstraintsByAppID fails intermittently | Minor | capacity scheduler | Prabhu Joseph | Prabhu Joseph |
+| [YARN-9325](https://issues.apache.org/jira/browse/YARN-9325) | TestQueueManagementDynamicEditPolicy fails intermittent | Minor | capacity scheduler | Prabhu Joseph | Prabhu Joseph |
+| [HDFS-11950](https://issues.apache.org/jira/browse/HDFS-11950) | Disable libhdfs zerocopy test on Mac | Minor | libhdfs | John Zhuge | Akira Ajisaka |
+
+
+### SUB-TASKS:
+
+| JIRA | Summary | Priority | Component | Reporter | Contributor |
+|:---- |:---- | :--- |:---- |:---- |:---- |
+| [HADOOP-16045](https://issues.apache.org/jira/browse/HADOOP-16045) | Don't run TestDU on Windows | Trivial | common, test | Lukas Majercak | Lukas Majercak |
+| [HADOOP-16079](https://issues.apache.org/jira/browse/HADOOP-16079) | Token.toString faulting if any token listed can't load. | Blocker | security | Steve Loughran | Steve Loughran |
+| [YARN-9253](https://issues.apache.org/jira/browse/YARN-9253) | Add UT to verify Placement Constraint in Distributed Shell | Major | . | Prabhu Joseph | Prabhu Joseph |
+| [YARN-9293](https://issues.apache.org/jira/browse/YARN-9293) | Optimize MockAMLauncher event handling | Major | . | Bibin A Chundatt | Bibin A Chundatt |
+| [HADOOP-16109](https://issues.apache.org/jira/browse/HADOOP-16109) | Parquet reading S3AFileSystem causes EOF | Blocker | fs/s3 | Dave Christianson | Steve Loughran |
+| [HADOOP-16191](https://issues.apache.org/jira/browse/HADOOP-16191) | AliyunOSS: improvements for copyFile/copyDirectory and logging | Major | fs/oss | wujinhu | wujinhu |
+| [YARN-9391](https://issues.apache.org/jira/browse/YARN-9391) | Disable PATH variable to be passed to Docker container | Major | . | Eric Yang | Jim Brennan |
+| [HADOOP-16220](https://issues.apache.org/jira/browse/HADOOP-16220) | Add findbugs ignores for unjustified issues during update to guava to 27.0-jre in hadoop-project | Major | . | Gabor Bota | Gabor Bota |
+| [HADOOP-16233](https://issues.apache.org/jira/browse/HADOOP-16233) | S3AFileStatus to declare that isEncrypted() is always true | Minor | fs/s3 | Steve Loughran | Steve Loughran |
+| [HADOOP-16306](https://issues.apache.org/jira/browse/HADOOP-16306) | AliyunOSS: Remove temporary files when upload small files to OSS | Major | fs/oss | wujinhu | wujinhu |
+| [HDFS-14553](https://issues.apache.org/jira/browse/HDFS-14553) | Make queue size of BlockReportProcessingThread configurable | Major | namenode | He Xiaoqiao | He Xiaoqiao |
+| [HDFS-14034](https://issues.apache.org/jira/browse/HDFS-14034) | Support getQuotaUsage API in WebHDFS | Major | fs, webhdfs | Erik Krogen | Chao Sun |
+| [YARN-9765](https://issues.apache.org/jira/browse/YARN-9765) | SLS runner crashes when run with metrics turned off. | Major | . | Abhishek Modi | Abhishek Modi |
+| [HDFS-14674](https://issues.apache.org/jira/browse/HDFS-14674) | [SBN read] Got an unexpected txid when tail editlog | Blocker | . | wangzhaohui | wangzhaohui |
+| [YARN-9775](https://issues.apache.org/jira/browse/YARN-9775) | RMWebServices /scheduler-conf GET returns all hadoop configurations for ZKConfigurationStore | Major | restapi | Prabhu Joseph | Prabhu Joseph |
+| [HDFS-14779](https://issues.apache.org/jira/browse/HDFS-14779) | Fix logging error in TestEditLog#testMultiStreamsLoadEditWithConfMaxTxns | Major | . | Jonathan Hung | Jonathan Hung |
+
+
+### OTHER:
+
+| JIRA | Summary | Priority | Component | Reporter | Contributor |
+|:---- |:---- | :--- |:---- |:---- |:---- |
+| [HADOOP-16025](https://issues.apache.org/jira/browse/HADOOP-16025) | Update the year to 2019 | Major | build | Ayush Saxena | Ayush Saxena |
+| [HDFS-12729](https://issues.apache.org/jira/browse/HDFS-12729) | Document special paths in HDFS | Major | documentation | Chris Douglas | Masatake Iwasaki |
+| [YARN-9191](https://issues.apache.org/jira/browse/YARN-9191) | Add cli option in DS to support enforceExecutionType in resource requests. | Major | . | Abhishek Modi | Abhishek Modi |
+| [HADOOP-16263](https://issues.apache.org/jira/browse/HADOOP-16263) | Update BUILDING.txt with macOS native build instructions | Minor | . | Siyao Meng | Siyao Meng |
+| [YARN-9559](https://issues.apache.org/jira/browse/YARN-9559) | Create AbstractContainersLauncher for pluggable ContainersLauncher logic | Major | . | Jonathan Hung | Jonathan Hung |
+| [HADOOP-16551](https://issues.apache.org/jira/browse/HADOOP-16551) | The changelog\*.md seems not generated when create-release | Blocker | . | Zhankun Tang | |
+
+
diff --git a/hadoop-common-project/hadoop-common/src/site/markdown/release/3.1.3/RELEASENOTES.3.1.3.md b/hadoop-common-project/hadoop-common/src/site/markdown/release/3.1.3/RELEASENOTES.3.1.3.md
new file mode 100644
index 0000000000000..c806810ae98f8
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/site/markdown/release/3.1.3/RELEASENOTES.3.1.3.md
@@ -0,0 +1,59 @@
+
+
+# Apache Hadoop 3.1.3 Release Notes
+
+These release notes cover new developer and user-facing incompatibilities, important issues, features, and major improvements.
+
+
+---
+
+* [HADOOP-15922](https://issues.apache.org/jira/browse/HADOOP-15922) | *Major* | **DelegationTokenAuthenticationFilter get wrong doAsUser since it does not decode URL**
+
+- Fix DelegationTokenAuthentication filter for incorrectly double encode doAs user parameter.
+
+
+---
+
+* [YARN-8761](https://issues.apache.org/jira/browse/YARN-8761) | *Major* | **Service AM support for decommissioning component instances**
+
+- Component instance number is not linear increment when decommission feature is used. Application with assumption of linear increment component instance number maybe impacted by introduction of this feature.
+
+
+---
+
+* [HDFS-14305](https://issues.apache.org/jira/browse/HDFS-14305) | *Major* | **Serial number in BlockTokenSecretManager could overlap between different namenodes**
+
+NameNodes rely on independent block token key ranges to communicate block token identities to DataNodes and clients in a way that does not create conflicts between the tokens issued by multiple NameNodes. HDFS-6440 introduced the potential for overlaps in key ranges; this fixes the issue by creating 64 possible key ranges that NameNodes assign themselves to, allowing for up to 64 NameNodes to run safely. This limitation only applies within a single Namespace; there may be more than 64 NameNodes total spread among multiple federated Namespaces.
+
+
+---
+
+* [HADOOP-16114](https://issues.apache.org/jira/browse/HADOOP-16114) | *Minor* | **NetUtils#canonicalizeHost gives different value for same host**
+
+The above patch will resolve the race condition
+
+
+---
+
+* [HDFS-14396](https://issues.apache.org/jira/browse/HDFS-14396) | *Blocker* | **Failed to load image from FSImageFile when downgrade from 3.x to 2.x**
+
+During a rolling upgrade from Hadoop 2.x to 3.x, NameNode cannot persist erasure coding information, and therefore a user cannot start using erasure coding feature until finalize is done.
+
+
+
diff --git a/hadoop-common-project/hadoop-common/src/site/markdown/release/3.2.1/CHANGELOG.3.2.1.md b/hadoop-common-project/hadoop-common/src/site/markdown/release/3.2.1/CHANGELOG.3.2.1.md
new file mode 100644
index 0000000000000..64e249ee36431
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/site/markdown/release/3.2.1/CHANGELOG.3.2.1.md
@@ -0,0 +1,553 @@
+
+
+# Apache Hadoop Changelog
+
+## Release 3.2.1 - 2019-09-10
+
+### INCOMPATIBLE CHANGES:
+
+| JIRA | Summary | Priority | Component | Reporter | Contributor |
+|:---- |:---- | :--- |:---- |:---- |:---- |
+| [HADOOP-15922](https://issues.apache.org/jira/browse/HADOOP-15922) | DelegationTokenAuthenticationFilter get wrong doAsUser since it does not decode URL | Major | common, kms | He Xiaoqiao | He Xiaoqiao |
+
+
+### NEW FEATURES:
+
+| JIRA | Summary | Priority | Component | Reporter | Contributor |
+|:---- |:---- | :--- |:---- |:---- |:---- |
+| [HADOOP-15950](https://issues.apache.org/jira/browse/HADOOP-15950) | Failover for LdapGroupsMapping | Major | common, security | Lukas Majercak | Lukas Majercak |
+| [YARN-7055](https://issues.apache.org/jira/browse/YARN-7055) | YARN Timeline Service v.2: beta 1 / GA | Major | timelineclient, timelinereader, timelineserver | Vrushali C | |
+| [YARN-9761](https://issues.apache.org/jira/browse/YARN-9761) | Allow overriding application submissions based on server side configs | Major | . | Jonathan Hung | pralabhkumar |
+
+
+### IMPROVEMENTS:
+
+| JIRA | Summary | Priority | Component | Reporter | Contributor |
+|:---- |:---- | :--- |:---- |:---- |:---- |
+| [HADOOP-15676](https://issues.apache.org/jira/browse/HADOOP-15676) | Cleanup TestSSLHttpServer | Minor | common | Szilard Nemeth | Szilard Nemeth |
+| [YARN-8896](https://issues.apache.org/jira/browse/YARN-8896) | Limit the maximum number of container assignments per heartbeat | Major | . | Weiwei Yang | Zhankun Tang |
+| [YARN-8618](https://issues.apache.org/jira/browse/YARN-8618) | Yarn Service: When all the components of a service have restart policy NEVER then initiation of service upgrade should fail | Major | . | Chandni Singh | Chandni Singh |
+| [HADOOP-15804](https://issues.apache.org/jira/browse/HADOOP-15804) | upgrade to commons-compress 1.18 | Major | . | PJ Fanning | Akira Ajisaka |
+| [YARN-8916](https://issues.apache.org/jira/browse/YARN-8916) | Define a constant "docker" string in "ContainerRuntimeConstants.java" for better maintainability | Minor | . | Zhankun Tang | Zhankun Tang |
+| [YARN-8908](https://issues.apache.org/jira/browse/YARN-8908) | Fix errors in yarn-default.xml related to GPU/FPGA | Major | . | Zhankun Tang | Zhankun Tang |
+| [HDFS-13941](https://issues.apache.org/jira/browse/HDFS-13941) | make storageId in BlockPoolTokenSecretManager.checkAccess optional | Major | . | Ajay Kumar | Ajay Kumar |
+| [HDFS-14029](https://issues.apache.org/jira/browse/HDFS-14029) | Sleep in TestLazyPersistFiles should be put into a loop | Trivial | hdfs | Adam Antal | Adam Antal |
+| [YARN-8915](https://issues.apache.org/jira/browse/YARN-8915) | Update the doc about the default value of "maximum-container-assignments" for capacity scheduler | Minor | . | Zhankun Tang | Zhankun Tang |
+| [HADOOP-15855](https://issues.apache.org/jira/browse/HADOOP-15855) | Review hadoop credential doc, including object store details | Minor | documentation, security | Steve Loughran | Steve Loughran |
+| [YARN-7225](https://issues.apache.org/jira/browse/YARN-7225) | Add queue and partition info to RM audit log | Major | resourcemanager | Jonathan Hung | Eric Payne |
+| [HADOOP-15687](https://issues.apache.org/jira/browse/HADOOP-15687) | Credentials class should allow access to aliases | Trivial | . | Lars Francke | Lars Francke |
+| [YARN-8969](https://issues.apache.org/jira/browse/YARN-8969) | AbstractYarnScheduler#getNodeTracker should return generic type to avoid type casting | Major | . | Wanqiang Ji | Wanqiang Ji |
+| [YARN-8977](https://issues.apache.org/jira/browse/YARN-8977) | Remove unnecessary type casting when calling AbstractYarnScheduler#getSchedulerNode | Trivial | . | Wanqiang Ji | Wanqiang Ji |
+| [HDFS-14070](https://issues.apache.org/jira/browse/HDFS-14070) | Refactor NameNodeWebHdfsMethods to allow better extensibility | Major | . | CR Hota | CR Hota |
+| [HADOOP-15926](https://issues.apache.org/jira/browse/HADOOP-15926) | Document upgrading the section in NOTICE.txt when upgrading the version of AWS SDK | Minor | documentation | Akira Ajisaka | Dinesh Chitlangia |
+| [HADOOP-12558](https://issues.apache.org/jira/browse/HADOOP-12558) | distcp documentation is woefully out of date | Critical | documentation, tools/distcp | Allen Wittenauer | Dinesh Chitlangia |
+| [HDFS-14063](https://issues.apache.org/jira/browse/HDFS-14063) | Support noredirect param for CREATE/APPEND/OPEN/GETFILECHECKSUM in HttpFS | Major | . | Íñigo Goiri | Íñigo Goiri |
+| [HADOOP-15919](https://issues.apache.org/jira/browse/HADOOP-15919) | AliyunOSS: Enable Yarn to use OSS | Major | fs/oss | wujinhu | wujinhu |
+| [HDFS-14064](https://issues.apache.org/jira/browse/HDFS-14064) | WEBHDFS: Support Enable/Disable EC Policy | Major | . | Ayush Saxena | Ayush Saxena |
+| [HADOOP-15943](https://issues.apache.org/jira/browse/HADOOP-15943) | AliyunOSS: add missing owner & group attributes for oss FileStatus | Major | fs/oss | wujinhu | wujinhu |
+| [MAPREDUCE-7164](https://issues.apache.org/jira/browse/MAPREDUCE-7164) | FileOutputCommitter does not report progress while merging paths. | Major | . | Kuhu Shukla | Kuhu Shukla |
+| [YARN-9069](https://issues.apache.org/jira/browse/YARN-9069) | Fix SchedulerInfo#getSchedulerType for custom schedulers | Minor | . | Bilwa S T | Bilwa S T |
+| [HDFS-14095](https://issues.apache.org/jira/browse/HDFS-14095) | EC: Track Erasure Coding commands in DFS statistics | Major | erasure-coding | Ayush Saxena | Ayush Saxena |
+| [HDFS-14112](https://issues.apache.org/jira/browse/HDFS-14112) | Avoid recursive call to external authorizer for getContentSummary. | Critical | namenode | Jitendra Nath Pandey | Tsz Wo Nicholas Sze |
+| [YARN-9036](https://issues.apache.org/jira/browse/YARN-9036) | Escape newlines in health report in YARN UI | Major | . | Jonathan Hung | Keqiu Hu |
+| [YARN-9041](https://issues.apache.org/jira/browse/YARN-9041) | Performance Optimization of method FSPreemptionThread#identifyContainersToPreempt | Major | fairscheduler, scheduler preemption | Wanqiang Ji | Wanqiang Ji |
+| [YARN-9085](https://issues.apache.org/jira/browse/YARN-9085) | Add Guaranteed and MaxCapacity to CSQueueMetrics | Major | . | Jonathan Hung | Jonathan Hung |
+| [HDFS-14124](https://issues.apache.org/jira/browse/HDFS-14124) | EC : Support EC Commands (set/get/unset EcPolicy) via WebHdfs | Major | erasure-coding, httpfs, webhdfs | Souryakanta Dwivedy | Ayush Saxena |
+| [HADOOP-15808](https://issues.apache.org/jira/browse/HADOOP-15808) | Harden Token service loader use | Major | security | Steve Loughran | Steve Loughran |
+| [YARN-9122](https://issues.apache.org/jira/browse/YARN-9122) | Add table of contents to YARN Service API document | Minor | documentation | Akira Ajisaka | Zhankun Tang |
+| [HDFS-14171](https://issues.apache.org/jira/browse/HDFS-14171) | Performance improvement in Tailing EditLog | Major | namenode | Kenneth Yang | Kenneth Yang |
+| [HADOOP-15481](https://issues.apache.org/jira/browse/HADOOP-15481) | Emit FairCallQueue stats as metrics | Major | metrics, rpc-server | Erik Krogen | Christopher Gregorian |
+| [HADOOP-15994](https://issues.apache.org/jira/browse/HADOOP-15994) | Upgrade Jackson2 to 2.9.8 | Major | security | Akira Ajisaka | lqjacklee |
+| [HADOOP-16019](https://issues.apache.org/jira/browse/HADOOP-16019) | ZKDelegationTokenSecretManager won't log exception message occured in function setJaasConfiguration | Minor | common | luhuachao | luhuachao |
+| [HDFS-14213](https://issues.apache.org/jira/browse/HDFS-14213) | Remove Jansson from BUILDING.txt | Minor | documentation | Akira Ajisaka | Dinesh Chitlangia |
+| [HDFS-14221](https://issues.apache.org/jira/browse/HDFS-14221) | Replace Guava Optional with Java Optional | Major | . | Arpit Agarwal | Arpit Agarwal |
+| [HDFS-14222](https://issues.apache.org/jira/browse/HDFS-14222) | Make ThrottledAsyncChecker constructor public | Major | . | Arpit Agarwal | Arpit Agarwal |
+| [HADOOP-16075](https://issues.apache.org/jira/browse/HADOOP-16075) | Upgrade checkstyle version to 8.16 | Minor | build | Dinesh Chitlangia | Dinesh Chitlangia |
+| [HADOOP-16089](https://issues.apache.org/jira/browse/HADOOP-16089) | AliyunOSS: update oss-sdk version to 3.4.1 | Major | fs/oss | wujinhu | wujinhu |
+| [HDFS-14231](https://issues.apache.org/jira/browse/HDFS-14231) | DataXceiver#run() should not log exceptions caused by InvalidToken exception as an error | Major | hdfs | Kitti Nanasi | Kitti Nanasi |
+| [YARN-7171](https://issues.apache.org/jira/browse/YARN-7171) | RM UI should sort memory / cores numerically | Major | . | Eric Maynard | Ahmed Hussein |
+| [YARN-9282](https://issues.apache.org/jira/browse/YARN-9282) | Typo in javadoc of class LinuxContainerExecutor: hadoop.security.authetication should be 'authentication' | Trivial | . | Szilard Nemeth | Charan Hebri |
+| [HADOOP-16108](https://issues.apache.org/jira/browse/HADOOP-16108) | Tail Follow Interval Should Allow To Specify The Sleep Interval To Save Unnecessary RPC's | Major | . | Harshakiran Reddy | Ayush Saxena |
+| [YARN-8295](https://issues.apache.org/jira/browse/YARN-8295) | [UI2] Improve "Resource Usage" tab error message when there are no data available. | Minor | yarn-ui-v2 | Gergely Novák | Charan Hebri |
+| [YARN-7824](https://issues.apache.org/jira/browse/YARN-7824) | [UI2] Yarn Component Instance page should include link to container logs | Major | yarn-ui-v2 | Yesha Vora | Akhil PB |
+| [HADOOP-15281](https://issues.apache.org/jira/browse/HADOOP-15281) | Distcp to add no-rename copy option | Major | tools/distcp | Steve Loughran | Andrew Olson |
+| [YARN-9309](https://issues.apache.org/jira/browse/YARN-9309) | Improve graph text in SLS to avoid overlapping | Minor | . | Bilwa S T | Bilwa S T |
+| [HDFS-14235](https://issues.apache.org/jira/browse/HDFS-14235) | Handle ArrayIndexOutOfBoundsException in DataNodeDiskMetrics#slowDiskDetectionDaemon | Major | . | Surendra Singh Lilhore | Ranith Sardar |
+| [YARN-9168](https://issues.apache.org/jira/browse/YARN-9168) | DistributedShell client timeout should be -1 by default | Minor | . | Zhankun Tang | Zhankun Tang |
+| [YARN-9087](https://issues.apache.org/jira/browse/YARN-9087) | Improve logging for initialization of Resource plugins | Major | yarn | Szilard Nemeth | Szilard Nemeth |
+| [YARN-9121](https://issues.apache.org/jira/browse/YARN-9121) | Replace GpuDiscoverer.getInstance() to a readable object for easy access control | Major | . | Szilard Nemeth | Szilard Nemeth |
+| [YARN-9139](https://issues.apache.org/jira/browse/YARN-9139) | Simplify initializer code of GpuDiscoverer | Major | . | Szilard Nemeth | Szilard Nemeth |
+| [HDFS-14247](https://issues.apache.org/jira/browse/HDFS-14247) | Repeat adding node description into network topology | Minor | datanode | HuangTao | HuangTao |
+| [YARN-9332](https://issues.apache.org/jira/browse/YARN-9332) | RackResolver tool should accept multiple hosts | Minor | yarn | Lantao Jin | Lantao Jin |
+| [HADOOP-16140](https://issues.apache.org/jira/browse/HADOOP-16140) | hadoop fs expunge to add -immediate option to purge trash immediately | Major | fs | Stephen O'Donnell | Stephen O'Donnell |
+| [YARN-9138](https://issues.apache.org/jira/browse/YARN-9138) | Improve test coverage for nvidia-smi binary execution of GpuDiscoverer | Major | . | Szilard Nemeth | Szilard Nemeth |
+| [MAPREDUCE-7191](https://issues.apache.org/jira/browse/MAPREDUCE-7191) | JobHistoryServer should log exception when loading/parsing history file failed | Minor | mrv2 | Jiandan Yang | Jiandan Yang |
+| [MAPREDUCE-7192](https://issues.apache.org/jira/browse/MAPREDUCE-7192) | JobHistoryServer attempts page support jump to containers log page in NM when logAggregation is disable | Major | mrv2 | Jiandan Yang | Jiandan Yang |
+| [HDFS-14346](https://issues.apache.org/jira/browse/HDFS-14346) | Better time precision in getTimeDuration | Minor | namenode | Chao Sun | Chao Sun |
+| [HDFS-14366](https://issues.apache.org/jira/browse/HDFS-14366) | Improve HDFS append performance | Major | hdfs | Chao Sun | Chao Sun |
+| [HADOOP-16196](https://issues.apache.org/jira/browse/HADOOP-16196) | Path Parameterize Comparable | Minor | common | David Mollitor | David Mollitor |
+| [HADOOP-16181](https://issues.apache.org/jira/browse/HADOOP-16181) | HadoopExecutors shutdown Cleanup | Minor | util | David Mollitor | David Mollitor |
+| [HADOOP-16147](https://issues.apache.org/jira/browse/HADOOP-16147) | Allow CopyListing sequence file keys and values to be more easily customized | Major | tools/distcp | Andrew Olson | Andrew Olson |
+| [MAPREDUCE-7190](https://issues.apache.org/jira/browse/MAPREDUCE-7190) | Add SleepJob additional parameter to make parallel runs distinguishable | Major | . | Adam Antal | Adam Antal |
+| [YARN-9394](https://issues.apache.org/jira/browse/YARN-9394) | Use new API of RackResolver to get better performance | Major | yarn | Lantao Jin | Lantao Jin |
+| [HADOOP-16208](https://issues.apache.org/jira/browse/HADOOP-16208) | Do Not Log InterruptedException in Client | Minor | common | David Mollitor | David Mollitor |
+| [YARN-9463](https://issues.apache.org/jira/browse/YARN-9463) | Add queueName info when failing with queue capacity sanity check | Trivial | capacity scheduler | Aihua Xu | Aihua Xu |
+| [HADOOP-16227](https://issues.apache.org/jira/browse/HADOOP-16227) | Upgrade checkstyle to 8.19 | Major | build | Akira Ajisaka | Akira Ajisaka |
+| [HDFS-14432](https://issues.apache.org/jira/browse/HDFS-14432) | dfs.datanode.shared.file.descriptor.paths duplicated in hdfs-default.xml | Minor | hdfs | puleya7 | puleya7 |
+| [HDFS-14463](https://issues.apache.org/jira/browse/HDFS-14463) | Add Log Level link under NameNode and DataNode Web UI Utilities dropdown | Trivial | webhdfs | Siyao Meng | Siyao Meng |
+| [YARN-9529](https://issues.apache.org/jira/browse/YARN-9529) | Log correct cpu controller path on error while initializing CGroups. | Major | nodemanager | Jonathan Hung | Jonathan Hung |
+| [HADOOP-16289](https://issues.apache.org/jira/browse/HADOOP-16289) | Allow extra jsvc startup option in hadoop\_start\_secure\_daemon in hadoop-functions.sh | Major | scripts | Siyao Meng | Siyao Meng |
+| [HADOOP-16307](https://issues.apache.org/jira/browse/HADOOP-16307) | Intern User Name and Group Name in FileStatus | Major | fs | David Mollitor | David Mollitor |
+| [HADOOP-16294](https://issues.apache.org/jira/browse/HADOOP-16294) | Enable access to context by DistCp subclasses | Trivial | tools/distcp | Andrew Olson | Andrew Olson |
+| [HDFS-14507](https://issues.apache.org/jira/browse/HDFS-14507) | Document -blockingDecommission option for hdfs dfsadmin -listOpenFiles | Minor | documentation | Siyao Meng | Siyao Meng |
+| [HDFS-14451](https://issues.apache.org/jira/browse/HDFS-14451) | Incorrect header or version mismatch log message | Minor | ipc | David Mollitor | Shweta |
+| [HDFS-14502](https://issues.apache.org/jira/browse/HDFS-14502) | keepResults option in NNThroughputBenchmark should call saveNamespace() | Major | benchmarks, hdfs | Konstantin Shvachko | Konstantin Shvachko |
+| [HADOOP-16323](https://issues.apache.org/jira/browse/HADOOP-16323) | https everywhere in Maven settings | Minor | build | Akira Ajisaka | Akira Ajisaka |
+| [YARN-9563](https://issues.apache.org/jira/browse/YARN-9563) | Resource report REST API could return NaN or Inf | Minor | . | Ahmed Hussein | Ahmed Hussein |
+| [YARN-9545](https://issues.apache.org/jira/browse/YARN-9545) | Create healthcheck REST endpoint for ATSv2 | Major | ATSv2 | Zoltan Siegl | Zoltan Siegl |
+| [HDFS-10659](https://issues.apache.org/jira/browse/HDFS-10659) | Namenode crashes after Journalnode re-installation in an HA cluster due to missing paxos directory | Major | ha, journal-node | Amit Anand | star |
+| [HDFS-14513](https://issues.apache.org/jira/browse/HDFS-14513) | FSImage which is saving should be clean while NameNode shutdown | Major | namenode | He Xiaoqiao | He Xiaoqiao |
+| [YARN-9543](https://issues.apache.org/jira/browse/YARN-9543) | [UI2] Handle ATSv2 server down or failures cases gracefully in YARN UI v2 | Major | ATSv2, yarn-ui-v2 | Zoltan Siegl | Zoltan Siegl |
+| [HADOOP-16369](https://issues.apache.org/jira/browse/HADOOP-16369) | Fix zstandard shortname misspelled as zts | Major | . | Jonathan Eagles | Jonathan Eagles |
+| [HDFS-14560](https://issues.apache.org/jira/browse/HDFS-14560) | Allow block replication parameters to be refreshable | Major | namenode | Stephen O'Donnell | Stephen O'Donnell |
+| [HDFS-12770](https://issues.apache.org/jira/browse/HDFS-12770) | Add doc about how to disable client socket cache | Trivial | hdfs-client | Weiwei Yang | Weiwei Yang |
+| [HADOOP-9157](https://issues.apache.org/jira/browse/HADOOP-9157) | Better option for curl in hadoop-auth-examples | Minor | documentation | Jingguo Yao | Andras Bokor |
+| [HDFS-14340](https://issues.apache.org/jira/browse/HDFS-14340) | Lower the log level when can't get postOpAttr | Minor | nfs | Anuhan Torgonshar | Anuhan Torgonshar |
+| [HADOOP-15914](https://issues.apache.org/jira/browse/HADOOP-15914) | hadoop jar command has no help argument | Major | common | Adam Antal | Adam Antal |
+| [YARN-9630](https://issues.apache.org/jira/browse/YARN-9630) | [UI2] Add a link in docs's top page | Major | documentation, yarn-ui-v2 | Wanqiang Ji | Wanqiang Ji |
+| [HADOOP-16156](https://issues.apache.org/jira/browse/HADOOP-16156) | [Clean-up] Remove NULL check before instanceof and fix checkstyle in InnerNodeImpl | Minor | . | Shweta | Shweta |
+| [HADOOP-14385](https://issues.apache.org/jira/browse/HADOOP-14385) | HttpExceptionUtils#validateResponse swallows exceptions | Trivial | . | Wei-Chiu Chuang | Wei-Chiu Chuang |
+| [HDFS-12564](https://issues.apache.org/jira/browse/HDFS-12564) | Add the documents of swebhdfs configurations on the client side | Major | documentation, webhdfs | Takanobu Asanuma | Takanobu Asanuma |
+| [HDFS-14403](https://issues.apache.org/jira/browse/HDFS-14403) | Cost-Based RPC FairCallQueue | Major | ipc, namenode | Erik Krogen | Christopher Gregorian |
+| [HADOOP-16266](https://issues.apache.org/jira/browse/HADOOP-16266) | Add more fine-grained processing time metrics to the RPC layer | Minor | ipc | Christopher Gregorian | Erik Krogen |
+| [YARN-9629](https://issues.apache.org/jira/browse/YARN-9629) | Support configurable MIN\_LOG\_ROLLING\_INTERVAL | Minor | log-aggregation, nodemanager, yarn | Adam Antal | Adam Antal |
+| [HDFS-13694](https://issues.apache.org/jira/browse/HDFS-13694) | Making md5 computing being in parallel with image loading | Major | . | zhouyingchao | Lisheng Sun |
+| [HDFS-14632](https://issues.apache.org/jira/browse/HDFS-14632) | Reduce useless #getNumLiveDataNodes call in SafeModeMonitor | Major | namenode | He Xiaoqiao | He Xiaoqiao |
+| [YARN-9573](https://issues.apache.org/jira/browse/YARN-9573) | DistributedShell cannot specify LogAggregationContext | Major | distributed-shell, log-aggregation, yarn | Adam Antal | Adam Antal |
+| [YARN-9337](https://issues.apache.org/jira/browse/YARN-9337) | GPU auto-discovery script runs even when the resource is given by hand | Major | yarn | Adam Antal | Adam Antal |
+| [YARN-9127](https://issues.apache.org/jira/browse/YARN-9127) | Create more tests to verify GpuDeviceInformationParser | Major | . | Szilard Nemeth | Peter Bacsko |
+| [YARN-9326](https://issues.apache.org/jira/browse/YARN-9326) | Fair Scheduler configuration defaults are not documented in case of min and maxResources | Major | docs, documentation, fairscheduler, yarn | Adam Antal | Adam Antal |
+| [HDFS-14547](https://issues.apache.org/jira/browse/HDFS-14547) | DirectoryWithQuotaFeature.quota costs additional memory even the storage type quota is not set. | Major | . | Jinglun | Jinglun |
+| [HDFS-14693](https://issues.apache.org/jira/browse/HDFS-14693) | NameNode should log a warning when EditLog IPC logger's pending size exceeds limit. | Minor | namenode | Xudong Cao | Xudong Cao |
+| [YARN-9094](https://issues.apache.org/jira/browse/YARN-9094) | Remove unused interface method: NodeResourceUpdaterPlugin#handleUpdatedResourceFromRM | Trivial | . | Szilard Nemeth | Gergely Pollak |
+| [YARN-9096](https://issues.apache.org/jira/browse/YARN-9096) | Some GpuResourcePlugin and ResourcePluginManager methods are synchronized unnecessarily | Major | . | Szilard Nemeth | Gergely Pollak |
+| [YARN-9092](https://issues.apache.org/jira/browse/YARN-9092) | Create an object for cgroups mount enable and cgroups mount path as they belong together | Minor | . | Szilard Nemeth | Gergely Pollak |
+| [YARN-9124](https://issues.apache.org/jira/browse/YARN-9124) | Resolve contradiction in ResourceUtils: addMandatoryResources / checkMandatoryResources work differently | Minor | . | Szilard Nemeth | Adam Antal |
+| [YARN-8199](https://issues.apache.org/jira/browse/YARN-8199) | Logging fileSize of log files under NM Local Dir | Major | log-aggregation | Prabhu Joseph | Prabhu Joseph |
+| [YARN-9729](https://issues.apache.org/jira/browse/YARN-9729) | [UI2] Fix error message for logs when ATSv2 is offline | Major | yarn-ui-v2 | Zoltan Siegl | Zoltan Siegl |
+| [YARN-9135](https://issues.apache.org/jira/browse/YARN-9135) | NM State store ResourceMappings serialization are tested with Strings instead of real Device objects | Major | . | Szilard Nemeth | Peter Bacsko |
+| [HDFS-14370](https://issues.apache.org/jira/browse/HDFS-14370) | Edit log tailing fast-path should allow for backoff | Major | namenode, qjm | Erik Krogen | Erik Krogen |
+| [YARN-9442](https://issues.apache.org/jira/browse/YARN-9442) | container working directory has group read permissions | Minor | yarn | Jim Brennan | Jim Brennan |
+| [HADOOP-16459](https://issues.apache.org/jira/browse/HADOOP-16459) | Backport [HADOOP-16266] "Add more fine-grained processing time metrics to the RPC layer" to branch-2 | Major | . | Erik Krogen | Erik Krogen |
+| [HDFS-14491](https://issues.apache.org/jira/browse/HDFS-14491) | More Clarity on Namenode UI Around Blocks and Replicas | Minor | . | Alan Jackoway | Siyao Meng |
+| [YARN-9134](https://issues.apache.org/jira/browse/YARN-9134) | No test coverage for redefining FPGA / GPU resource types in TestResourceUtils | Major | . | Szilard Nemeth | Peter Bacsko |
+| [YARN-9133](https://issues.apache.org/jira/browse/YARN-9133) | Make tests more easy to comprehend in TestGpuResourceHandler | Major | . | Szilard Nemeth | Peter Bacsko |
+| [YARN-9140](https://issues.apache.org/jira/browse/YARN-9140) | Code cleanup in ResourcePluginManager.initialize and in TestResourcePluginManager | Trivial | . | Szilard Nemeth | Peter Bacsko |
+| [YARN-9676](https://issues.apache.org/jira/browse/YARN-9676) | Add DEBUG and TRACE level messages to AppLogAggregatorImpl and connected classes | Major | . | Adam Antal | Adam Antal |
+| [YARN-9488](https://issues.apache.org/jira/browse/YARN-9488) | Skip YARNFeatureNotEnabledException from ClientRMService | Minor | resourcemanager | Prabhu Joseph | Prabhu Joseph |
+| [YARN-8586](https://issues.apache.org/jira/browse/YARN-8586) | Extract log aggregation related fields and methods from RMAppImpl | Major | . | Szilard Nemeth | Peter Bacsko |
+| [YARN-9100](https://issues.apache.org/jira/browse/YARN-9100) | Add tests for GpuResourceAllocator and do minor code cleanup | Major | . | Szilard Nemeth | Peter Bacsko |
+| [HADOOP-15246](https://issues.apache.org/jira/browse/HADOOP-15246) | SpanReceiverInfo - Prefer ArrayList over LinkedList | Trivial | common | David Mollitor | David Mollitor |
+| [HADOOP-16158](https://issues.apache.org/jira/browse/HADOOP-16158) | DistCp to support checksum validation when copy blocks in parallel | Major | tools/distcp | Kai Xie | Kai Xie |
+| [HDFS-14746](https://issues.apache.org/jira/browse/HDFS-14746) | Trivial test code update after HDFS-14687 | Trivial | ec | Wei-Chiu Chuang | kevin su |
+| [HDFS-13709](https://issues.apache.org/jira/browse/HDFS-13709) | Report bad block to NN when transfer block encounter EIO exception | Major | datanode | Chen Zhang | Chen Zhang |
+| [HDFS-14665](https://issues.apache.org/jira/browse/HDFS-14665) | HttpFS: LISTSTATUS response is missing HDFS-specific fields | Major | httpfs | Siyao Meng | Siyao Meng |
+| [HDFS-14276](https://issues.apache.org/jira/browse/HDFS-14276) | [SBN read] Reduce tailing overhead | Major | ha, namenode | Wei-Chiu Chuang | Ayush Saxena |
+| [HADOOP-16061](https://issues.apache.org/jira/browse/HADOOP-16061) | Update Apache Yetus to 0.10.0 | Major | build | Akira Ajisaka | Akira Ajisaka |
+| [YARN-9756](https://issues.apache.org/jira/browse/YARN-9756) | Create metric that sums total memory/vcores preempted per round | Major | capacity scheduler | Eric Payne | Manikandan R |
+| [HDFS-14748](https://issues.apache.org/jira/browse/HDFS-14748) | Make DataNodePeerMetrics#minOutlierDetectionSamples configurable | Major | . | Lisheng Sun | Lisheng Sun |
+| [HADOOP-15998](https://issues.apache.org/jira/browse/HADOOP-15998) | Ensure jar validation works on Windows. | Blocker | build | Brian Grunkemeyer | Brian Grunkemeyer |
+| [HDFS-14633](https://issues.apache.org/jira/browse/HDFS-14633) | The StorageType quota and consume in QuotaFeature is not handled for rename | Major | . | Jinglun | Jinglun |
+| [YARN-9810](https://issues.apache.org/jira/browse/YARN-9810) | Add queue capacity/maxcapacity percentage metrics | Major | . | Jonathan Hung | Shubham Gupta |
+| [YARN-9763](https://issues.apache.org/jira/browse/YARN-9763) | Print application tags in application summary | Major | . | Jonathan Hung | Manoj Kumar |
+| [YARN-9795](https://issues.apache.org/jira/browse/YARN-9795) | ClusterMetrics to include AM allocation delay | Minor | . | Fengnan Li | Fengnan Li |
+| [YARN-8995](https://issues.apache.org/jira/browse/YARN-8995) | Log events info in AsyncDispatcher when event queue size cumulatively reaches a certain number every time. | Major | metrics, nodemanager, resourcemanager | zhuqi | zhuqi |
+
+
+### BUG FIXES:
+
+| JIRA | Summary | Priority | Component | Reporter | Contributor |
+|:---- |:---- | :--- |:---- |:---- |:---- |
+| [HDFS-13973](https://issues.apache.org/jira/browse/HDFS-13973) | getErasureCodingPolicy should log path in audit event | Major | hdfs | Shweta | Shweta |
+| [YARN-8868](https://issues.apache.org/jira/browse/YARN-8868) | Set HTTPOnly attribute to Cookie | Major | . | Chandni Singh | Chandni Singh |
+| [HDFS-14003](https://issues.apache.org/jira/browse/HDFS-14003) | Fix findbugs warning in trunk for FSImageFormatPBINode | Major | . | Yiqun Lin | Yiqun Lin |
+| [YARN-8910](https://issues.apache.org/jira/browse/YARN-8910) | Misleading log statement in NM when max retries is -1 | Minor | . | Chandni Singh | Chandni Singh |
+| [YARN-7502](https://issues.apache.org/jira/browse/YARN-7502) | Nodemanager restart docs should describe nodemanager supervised property | Major | documentation | Jason Lowe | Suma Shivaprasad |
+| [YARN-8826](https://issues.apache.org/jira/browse/YARN-8826) | Fix lingering timeline collector after serviceStop in TimelineCollectorManager | Trivial | ATSv2 | Prabha Manepalli | Prabha Manepalli |
+| [HDFS-14021](https://issues.apache.org/jira/browse/HDFS-14021) | TestReconstructStripedBlocksWithRackAwareness#testReconstructForNotEnoughRacks fails intermittently | Major | erasure-coding, test | Xiao Chen | Xiao Chen |
+| [MAPREDUCE-7151](https://issues.apache.org/jira/browse/MAPREDUCE-7151) | RMContainerAllocator#handleJobPriorityChange expects application\_priority always | Major | . | Bibin A Chundatt | Bilwa S T |
+| [HDFS-14028](https://issues.apache.org/jira/browse/HDFS-14028) | HDFS OIV temporary dir deletes folder | Major | hdfs | Adam Antal | Adam Antal |
+| [HDFS-14027](https://issues.apache.org/jira/browse/HDFS-14027) | DFSStripedOutputStream should implement both hsync methods | Critical | erasure-coding | Xiao Chen | Xiao Chen |
+| [HADOOP-15899](https://issues.apache.org/jira/browse/HADOOP-15899) | Update AWS Java SDK versions in NOTICE.txt | Major | . | Akira Ajisaka | Akira Ajisaka |
+| [HADOOP-15900](https://issues.apache.org/jira/browse/HADOOP-15900) | Update JSch versions in LICENSE.txt | Major | . | Akira Ajisaka | Akira Ajisaka |
+| [HDFS-14042](https://issues.apache.org/jira/browse/HDFS-14042) | Fix NPE when PROVIDED storage is missing | Major | . | Íñigo Goiri | Virajith Jalaparti |
+| [HDFS-14043](https://issues.apache.org/jira/browse/HDFS-14043) | Tolerate corrupted seen\_txid file | Major | hdfs, namenode | Lukas Majercak | Lukas Majercak |
+| [YARN-8970](https://issues.apache.org/jira/browse/YARN-8970) | Improve the debug message in CS#allocateContainerOnSingleNode | Trivial | . | Weiwei Yang | Zhankun Tang |
+| [YARN-8865](https://issues.apache.org/jira/browse/YARN-8865) | RMStateStore contains large number of expired RMDelegationToken | Major | resourcemanager | Wilfred Spiegelenburg | Wilfred Spiegelenburg |
+| [HDFS-14048](https://issues.apache.org/jira/browse/HDFS-14048) | DFSOutputStream close() throws exception on subsequent call after DataNode restart | Major | hdfs-client | Erik Krogen | Erik Krogen |
+| [MAPREDUCE-7156](https://issues.apache.org/jira/browse/MAPREDUCE-7156) | NullPointerException when reaching max shuffle connections | Major | mrv2 | Peter Bacsko | Peter Bacsko |
+| [YARN-8866](https://issues.apache.org/jira/browse/YARN-8866) | Fix a parsing error for crossdomain.xml | Major | build, yarn-ui-v2 | Takanobu Asanuma | Takanobu Asanuma |
+| [HDFS-14039](https://issues.apache.org/jira/browse/HDFS-14039) | ec -listPolicies doesn't show correct state for the default policy when the default is not RS(6,3) | Major | erasure-coding | Xiao Chen | Kitti Nanasi |
+| [HADOOP-15916](https://issues.apache.org/jira/browse/HADOOP-15916) | Upgrade Maven Surefire plugin to 3.0.0-M1 | Blocker | build | Akira Ajisaka | Akira Ajisaka |
+| [YARN-9002](https://issues.apache.org/jira/browse/YARN-9002) | YARN Service keytab does not support s3, wasb, gs and is restricted to HDFS and local filesystem only | Major | yarn-native-services | Gour Saha | Gour Saha |
+| [YARN-8233](https://issues.apache.org/jira/browse/YARN-8233) | NPE in CapacityScheduler#tryCommit when handling allocate/reserve proposal whose allocatedOrReservedContainer is null | Critical | capacityscheduler | Tao Yang | Tao Yang |
+| [HDFS-14065](https://issues.apache.org/jira/browse/HDFS-14065) | Failed Storage Locations shows nothing in the Datanode Volume Failures | Major | . | Ayush Saxena | Ayush Saxena |
+| [HADOOP-15923](https://issues.apache.org/jira/browse/HADOOP-15923) | create-release script should set max-cache-ttl as well as default-cache-ttl for gpg-agent | Blocker | build | Akira Ajisaka | Akira Ajisaka |
+| [HADOOP-15912](https://issues.apache.org/jira/browse/HADOOP-15912) | start-build-env.sh still creates an invalid /etc/sudoers.d/hadoop-build-${USER\_ID} file entry after HADOOP-15802 | Major | build | Akira Ajisaka | Akira Ajisaka |
+| [HADOOP-15869](https://issues.apache.org/jira/browse/HADOOP-15869) | BlockDecompressorStream#decompress should not return -1 in case of IOException. | Major | . | Surendra Singh Lilhore | Surendra Singh Lilhore |
+| [MAPREDUCE-7158](https://issues.apache.org/jira/browse/MAPREDUCE-7158) | Inefficient Flush Logic in JobHistory EventWriter | Major | . | Zichen Sun | Zichen Sun |
+| [HADOOP-15930](https://issues.apache.org/jira/browse/HADOOP-15930) | Exclude MD5 checksum files from release artifact | Critical | build | Akira Ajisaka | Akira Ajisaka |
+| [YARN-8856](https://issues.apache.org/jira/browse/YARN-8856) | TestTimelineReaderWebServicesHBaseStorage tests failing with NoClassDefFoundError | Major | . | Jason Lowe | Sushil Ks |
+| [HADOOP-15925](https://issues.apache.org/jira/browse/HADOOP-15925) | The config and log of gpg-agent are removed in create-release script | Major | build | Akira Ajisaka | Dinesh Chitlangia |
+| [HDFS-13963](https://issues.apache.org/jira/browse/HDFS-13963) | NN UI is broken with IE11 | Minor | namenode, ui | Daisuke Kobayashi | Ayush Saxena |
+| [HDFS-14056](https://issues.apache.org/jira/browse/HDFS-14056) | Fix error messages in HDFS-12716 | Minor | hdfs | Adam Antal | Ayush Saxena |
+| [YARN-8992](https://issues.apache.org/jira/browse/YARN-8992) | Fair scheduler can delete a dynamic queue while an application attempt is being added to the queue | Major | fairscheduler | Haibo Chen | Wilfred Spiegelenburg |
+| [YARN-8984](https://issues.apache.org/jira/browse/YARN-8984) | AMRMClient#OutstandingSchedRequests leaks when AllocationTags is null or empty | Critical | . | Yang Wang | Yang Wang |
+| [HADOOP-15948](https://issues.apache.org/jira/browse/HADOOP-15948) | Inconsistency in get and put syntax if filename/dirname contains space | Minor | fs | vivek kumar | Ayush Saxena |
+| [HDFS-13816](https://issues.apache.org/jira/browse/HDFS-13816) | dfs.getQuotaUsage() throws NPE on non-existent dir instead of FileNotFoundException | Major | namenode | Vinayakumar B | Vinayakumar B |
+| [MAPREDUCE-7162](https://issues.apache.org/jira/browse/MAPREDUCE-7162) | TestEvents#testEvents fails | Critical | jobhistoryserver, test | Zhaohui Xin | Zhaohui Xin |
+| [YARN-9056](https://issues.apache.org/jira/browse/YARN-9056) | Yarn Service Upgrade: Instance state changes from UPGRADING to READY without performing a readiness check | Critical | . | Chandni Singh | Chandni Singh |
+| [YARN-8812](https://issues.apache.org/jira/browse/YARN-8812) | Containers fail during creating a symlink which started with hyphen for a resource file | Minor | . | Oleksandr Shevchenko | Oleksandr Shevchenko |
+| [YARN-9030](https://issues.apache.org/jira/browse/YARN-9030) | Log aggregation changes to handle filesystems which do not support setting permissions | Major | log-aggregation | Suma Shivaprasad | Suma Shivaprasad |
+| [YARN-9067](https://issues.apache.org/jira/browse/YARN-9067) | YARN Resource Manager is running OOM because of leak of Configuration Object | Major | yarn-native-services | Eric Yang | Eric Yang |
+| [MAPREDUCE-7165](https://issues.apache.org/jira/browse/MAPREDUCE-7165) | mapred-site.xml is misformatted in single node setup document | Major | documentation | Akira Ajisaka | Zhaohui Xin |
+| [HADOOP-15970](https://issues.apache.org/jira/browse/HADOOP-15970) | Upgrade plexus-utils from 2.0.5 to 3.1.0 | Major | security | Akira Ajisaka | Akira Ajisaka |
+| [HADOOP-15966](https://issues.apache.org/jira/browse/HADOOP-15966) | Hadoop Kerberos broken on macos as java.security.krb5.realm is reset: Null realm name (601) | Major | scripts | Steve Loughran | Steve Loughran |
+| [HADOOP-15974](https://issues.apache.org/jira/browse/HADOOP-15974) | Upgrade Curator version to 2.13.0 to fix ZK tests | Major | . | Jason Lowe | Akira Ajisaka |
+| [YARN-9071](https://issues.apache.org/jira/browse/YARN-9071) | NM and service AM don't have updated status for reinitialized containers | Critical | . | Billie Rinaldi | Chandni Singh |
+| [MAPREDUCE-7159](https://issues.apache.org/jira/browse/MAPREDUCE-7159) | FrameworkUploader: ensure proper permissions of generated framework tar.gz if restrictive umask is used | Major | mrv2 | Peter Bacsko | Peter Bacsko |
+| [YARN-9009](https://issues.apache.org/jira/browse/YARN-9009) | Fix flaky test TestEntityGroupFSTimelineStore.testCleanLogs | Minor | . | OrDTesters | OrDTesters |
+| [MAPREDUCE-7170](https://issues.apache.org/jira/browse/MAPREDUCE-7170) | Doc typo in PluggableShuffleAndPluggableSort.md | Minor | documentation | Zhaohui Xin | Zhaohui Xin |
+| [YARN-9040](https://issues.apache.org/jira/browse/YARN-9040) | LevelDBCacheTimelineStore in ATS 1.5 leaks native memory | Major | timelineserver | Tarun Parimi | Tarun Parimi |
+| [YARN-9084](https://issues.apache.org/jira/browse/YARN-9084) | Service Upgrade: With default readiness check, the status of upgrade is reported to be successful prematurely | Major | . | Chandni Singh | Chandni Singh |
+| [HDFS-13661](https://issues.apache.org/jira/browse/HDFS-13661) | Ls command with e option fails when the filesystem is not HDFS | Major | erasure-coding, tools | Takanobu Asanuma | Takanobu Asanuma |
+| [YARN-9154](https://issues.apache.org/jira/browse/YARN-9154) | Fix itemization in YARN service quickstart document | Minor | documentation | Akira Ajisaka | Ayush Saxena |
+| [HDFS-14166](https://issues.apache.org/jira/browse/HDFS-14166) | Ls with -e option not giving the result in proper format | Major | . | Soumyapn | Shubham Dewan |
+| [HDFS-14046](https://issues.apache.org/jira/browse/HDFS-14046) | In-Maintenance ICON is missing in datanode info page | Major | datanode | Harshakiran Reddy | Ranith Sardar |
+| [HDFS-14183](https://issues.apache.org/jira/browse/HDFS-14183) | [SPS] Remove the -w parameter from the -satisfystoragepolicy usage | Major | . | Ayush Saxena | Ayush Saxena |
+| [YARN-9164](https://issues.apache.org/jira/browse/YARN-9164) | Shutdown NM may cause NPE when opportunistic container scheduling is enabled | Critical | . | lujie | lujie |
+| [YARN-8567](https://issues.apache.org/jira/browse/YARN-8567) | Fetching yarn logs fails for long running application if it is not present in timeline store | Major | log-aggregation | Tarun Parimi | Tarun Parimi |
+| [HADOOP-16028](https://issues.apache.org/jira/browse/HADOOP-16028) | Fix NetworkTopology chooseRandom function to support excluded nodes | Major | . | Sihai Ke | Sihai Ke |
+| [HADOOP-16030](https://issues.apache.org/jira/browse/HADOOP-16030) | AliyunOSS: bring fixes back from HADOOP-15671 | Blocker | fs/oss | wujinhu | wujinhu |
+| [YARN-9162](https://issues.apache.org/jira/browse/YARN-9162) | Fix TestRMAdminCLI#testHelp | Major | resourcemanager, test | Ayush Saxena | Ayush Saxena |
+| [YARN-9173](https://issues.apache.org/jira/browse/YARN-9173) | FairShare calculation broken for large values after YARN-8833 | Major | fairscheduler | Wilfred Spiegelenburg | Wilfred Spiegelenburg |
+| [YARN-8833](https://issues.apache.org/jira/browse/YARN-8833) | Avoid potential integer overflow when computing fair shares | Major | fairscheduler | liyakun | liyakun |
+| [HADOOP-16036](https://issues.apache.org/jira/browse/HADOOP-16036) | WASB: Disable jetty logging configuration announcement | Major | fs/azure | Da Zhou | Da Zhou |
+| [HADOOP-16016](https://issues.apache.org/jira/browse/HADOOP-16016) | TestSSLFactory#testServerWeakCiphers sporadically fails in precommit builds | Major | security, test | Jason Lowe | Akira Ajisaka |
+| [HDFS-14198](https://issues.apache.org/jira/browse/HDFS-14198) | Upload and Create button doesn't get enabled after getting reset. | Major | . | Ayush Saxena | Ayush Saxena |
+| [YARN-8747](https://issues.apache.org/jira/browse/YARN-8747) | [UI2] YARN UI2 page loading failed due to js error under some time zone configuration | Critical | webapp | collinma | collinma |
+| [YARN-9203](https://issues.apache.org/jira/browse/YARN-9203) | Fix typos in yarn-default.xml | Trivial | documentation | Rahul Padmanabhan | Rahul Padmanabhan |
+| [YARN-9194](https://issues.apache.org/jira/browse/YARN-9194) | Invalid event: REGISTERED and LAUNCH\_FAILED at FAILED, and NullPointerException happens in RM while shutdown a NM | Critical | . | lujie | lujie |
+| [YARN-9204](https://issues.apache.org/jira/browse/YARN-9204) | RM fails to start if absolute resource is specified for partition capacity in CS queues | Blocker | yarn | Jiandan Yang | Jiandan Yang |
+| [HDFS-14207](https://issues.apache.org/jira/browse/HDFS-14207) | ZKFC should catch exception when ha configuration missing | Major | hdfs | Fei Hui | Fei Hui |
+| [HDFS-14218](https://issues.apache.org/jira/browse/HDFS-14218) | EC: Ls -e throw NPE when directory ec policy is disabled | Major | . | Surendra Singh Lilhore | Ayush Saxena |
+| [YARN-9210](https://issues.apache.org/jira/browse/YARN-9210) | RM nodes web page can not display node info | Blocker | yarn | Jiandan Yang | Jiandan Yang |
+| [YARN-9205](https://issues.apache.org/jira/browse/YARN-9205) | When using custom resource type, application will fail to run due to the CapacityScheduler throws InvalidResourceRequestException(GREATER\_THEN\_MAX\_ALLOCATION) | Critical | . | Zhankun Tang | Zhankun Tang |
+| [YARN-8961](https://issues.apache.org/jira/browse/YARN-8961) | [UI2] Flow Run End Time shows 'Invalid date' | Major | . | Charan Hebri | Akhil PB |
+| [HADOOP-16065](https://issues.apache.org/jira/browse/HADOOP-16065) | -Ddynamodb should be -Ddynamo in AWS SDK testing document | Minor | documentation | Akira Ajisaka | Akira Ajisaka |
+| [HDFS-14228](https://issues.apache.org/jira/browse/HDFS-14228) | Incorrect getSnapshottableDirListing() javadoc | Major | snapshots | Wei-Chiu Chuang | Dinesh Chitlangia |
+| [YARN-9222](https://issues.apache.org/jira/browse/YARN-9222) | Print launchTime in ApplicationSummary | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-8901](https://issues.apache.org/jira/browse/YARN-8901) | Restart "NEVER" policy does not work with component dependency | Critical | . | Yesha Vora | Suma Shivaprasad |
+| [YARN-9237](https://issues.apache.org/jira/browse/YARN-9237) | NM should ignore sending finished apps to RM during RM fail-over | Major | yarn | Jiandan Yang | Jiandan Yang |
+| [YARN-6616](https://issues.apache.org/jira/browse/YARN-6616) | YARN AHS shows submitTime for jobs same as startTime | Minor | . | Prabhu Joseph | Prabhu Joseph |
+| [YARN-9099](https://issues.apache.org/jira/browse/YARN-9099) | GpuResourceAllocator#getReleasingGpus calculates number of GPUs in a wrong way | Major | . | Szilard Nemeth | Szilard Nemeth |
+| [YARN-9262](https://issues.apache.org/jira/browse/YARN-9262) | TestRMAppAttemptTransitions is failing with an NPE | Critical | resourcemanager | Sunil Govindan | lujie |
+| [HDFS-14232](https://issues.apache.org/jira/browse/HDFS-14232) | libhdfs is not included in binary tarball | Critical | build, libhdfs | Akira Ajisaka | Akira Ajisaka |
+| [MAPREDUCE-7177](https://issues.apache.org/jira/browse/MAPREDUCE-7177) | Disable speculative execution in TestDFSIO | Major | . | Kihwal Lee | Zhaohui Xin |
+| [HADOOP-16076](https://issues.apache.org/jira/browse/HADOOP-16076) | SPNEGO+SSL Client Connections with HttpClient Broken | Major | build, security | Larry McCay | Larry McCay |
+| [HADOOP-16074](https://issues.apache.org/jira/browse/HADOOP-16074) | WASB: Update container not found error code | Major | fs/azure | Da Zhou | Da Zhou |
+| [YARN-8498](https://issues.apache.org/jira/browse/YARN-8498) | Yarn NodeManager OOM Listener Fails Compilation on Ubuntu 18.04 | Blocker | . | Jack Bearden | Ayush Saxena |
+| [YARN-9206](https://issues.apache.org/jira/browse/YARN-9206) | RMServerUtils does not count SHUTDOWN as an accepted state | Major | . | Kuhu Shukla | Kuhu Shukla |
+| [HADOOP-16032](https://issues.apache.org/jira/browse/HADOOP-16032) | Distcp It should clear sub directory ACL before applying new ACL on it. | Major | tools/distcp | Ranith Sardar | Ranith Sardar |
+| [HDFS-14140](https://issues.apache.org/jira/browse/HDFS-14140) | JournalNodeSyncer authentication is failing in secure cluster | Major | journal-node, security | Surendra Singh Lilhore | Surendra Singh Lilhore |
+| [YARN-9257](https://issues.apache.org/jira/browse/YARN-9257) | Distributed Shell client throws a NPE for a non-existent queue | Major | distributed-shell | Charan Hebri | Charan Hebri |
+| [YARN-8761](https://issues.apache.org/jira/browse/YARN-8761) | Service AM support for decommissioning component instances | Major | . | Billie Rinaldi | Billie Rinaldi |
+| [HDFS-14266](https://issues.apache.org/jira/browse/HDFS-14266) | EC : Fsck -blockId shows null for EC Blocks if One Block Is Not Available. | Major | . | Harshakiran Reddy | Ayush Saxena |
+| [HDFS-14274](https://issues.apache.org/jira/browse/HDFS-14274) | EC: NPE While Listing EC Policy For A Directory Following Replication Policy. | Major | erasure-coding | Souryakanta Dwivedy | Ayush Saxena |
+| [HDFS-14263](https://issues.apache.org/jira/browse/HDFS-14263) | Remove unnecessary block file exists check from FsDatasetImpl#getBlockInputStream() | Major | datanode | Surendra Singh Lilhore | Surendra Singh Lilhore |
+| [YARN-7761](https://issues.apache.org/jira/browse/YARN-7761) | [UI2] Clicking 'master container log' or 'Link' next to 'log' under application's appAttempt goes to Old UI's Log link | Major | yarn-ui-v2 | Sumana Sathish | Akhil PB |
+| [YARN-9295](https://issues.apache.org/jira/browse/YARN-9295) | [UI2] Fix label typo in Cluster Overview page | Trivial | yarn-ui-v2 | Charan Hebri | Charan Hebri |
+| [YARN-9308](https://issues.apache.org/jira/browse/YARN-9308) | fairscheduler-statedump.log gets generated regardless of service again after the merge of HDFS-7240 | Blocker | fairscheduler, scheduler | Akira Ajisaka | Wilfred Spiegelenburg |
+| [YARN-9284](https://issues.apache.org/jira/browse/YARN-9284) | Fix the unit of yarn.service.am-resource.memory in the document | Minor | documentation, yarn-native-services | Masahiro Tanaka | Masahiro Tanaka |
+| [YARN-9283](https://issues.apache.org/jira/browse/YARN-9283) | Javadoc of LinuxContainerExecutor#addSchedPriorityCommand has a wrong property name as reference | Minor | documentation | Szilard Nemeth | Adam Antal |
+| [YARN-9286](https://issues.apache.org/jira/browse/YARN-9286) | [Timeline Server] Sorting based on FinalStatus shows pop-up message | Minor | timelineserver | Nallasivan | Bilwa S T |
+| [HDFS-14081](https://issues.apache.org/jira/browse/HDFS-14081) | hdfs dfsadmin -metasave metasave\_test results NPE | Major | hdfs | Shweta | Shweta |
+| [HADOOP-15813](https://issues.apache.org/jira/browse/HADOOP-15813) | Enable more reliable SSL connection reuse | Major | common | Daryn Sharp | Daryn Sharp |
+| [HDFS-14216](https://issues.apache.org/jira/browse/HDFS-14216) | NullPointerException happens in NamenodeWebHdfs | Critical | . | lujie | lujie |
+| [HADOOP-16105](https://issues.apache.org/jira/browse/HADOOP-16105) | WASB in secure mode does not set connectingUsingSAS | Major | fs/azure | Steve Loughran | Steve Loughran |
+| [YARN-9238](https://issues.apache.org/jira/browse/YARN-9238) | Avoid allocating opportunistic containers to previous/removed/non-exist application attempt | Critical | . | lujie | lujie |
+| [YARN-9118](https://issues.apache.org/jira/browse/YARN-9118) | Handle exceptions with parsing user defined GPU devices in GpuDiscoverer | Major | . | Szilard Nemeth | Szilard Nemeth |
+| [YARN-9317](https://issues.apache.org/jira/browse/YARN-9317) | Avoid repeated YarnConfiguration#timelineServiceV2Enabled check | Major | . | Bibin A Chundatt | Prabhu Joseph |
+| [YARN-9213](https://issues.apache.org/jira/browse/YARN-9213) | RM Web UI v1 does not show custom resource allocations for containers page | Major | . | Szilard Nemeth | Szilard Nemeth |
+| [YARN-9329](https://issues.apache.org/jira/browse/YARN-9329) | updatePriority is blocked when using FairScheduler | Major | . | Jiandan Yang | Jiandan Yang |
+| [YARN-9248](https://issues.apache.org/jira/browse/YARN-9248) | RMContainerImpl:Invalid event: ACQUIRED at KILLED | Major | . | lujie | lujie |
+| [HADOOP-16018](https://issues.apache.org/jira/browse/HADOOP-16018) | DistCp won't reassemble chunks when blocks per chunk \> 0 | Major | tools/distcp | Kai Xie | Kai Xie |
+| [YARN-9334](https://issues.apache.org/jira/browse/YARN-9334) | YARN Service Client does not work with SPNEGO when knox is configured | Major | yarn-native-services | Tarun Parimi | Billie Rinaldi |
+| [HDFS-14305](https://issues.apache.org/jira/browse/HDFS-14305) | Serial number in BlockTokenSecretManager could overlap between different namenodes | Major | namenode, security | Chao Sun | He Xiaoqiao |
+| [HDFS-14314](https://issues.apache.org/jira/browse/HDFS-14314) | fullBlockReportLeaseId should be reset after registering to NN | Critical | datanode | star | star |
+| [YARN-8803](https://issues.apache.org/jira/browse/YARN-8803) | [UI2] Show flow runs in the order of recently created time in graph widgets | Major | yarn-ui-v2 | Akhil PB | Akhil PB |
+| [HDFS-14317](https://issues.apache.org/jira/browse/HDFS-14317) | Standby does not trigger edit log rolling when in-progress edit log tailing is enabled | Critical | . | Ekanth Sethuramalingam | Ekanth Sethuramalingam |
+| [HDFS-14333](https://issues.apache.org/jira/browse/HDFS-14333) | Datanode fails to start if any disk has errors during Namenode registration | Major | datanode | Stephen O'Donnell | Stephen O'Donnell |
+| [HADOOP-16192](https://issues.apache.org/jira/browse/HADOOP-16192) | CallQueue backoff bug fixes: doesn't perform backoff when add() is used, and doesn't update backoff when refreshed | Major | ipc | Erik Krogen | Erik Krogen |
+| [HDFS-14037](https://issues.apache.org/jira/browse/HDFS-14037) | Fix SSLFactory truststore reloader thread leak in URLConnectionFactory | Major | hdfs-client, webhdfs | Takanobu Asanuma | Takanobu Asanuma |
+| [HADOOP-16225](https://issues.apache.org/jira/browse/HADOOP-16225) | Fix links to the developer mailing lists in DownstreamDev.md | Minor | documentation | Akira Ajisaka | Wanqiang Ji |
+| [HADOOP-16226](https://issues.apache.org/jira/browse/HADOOP-16226) | new Path(String str) does not remove all the trailing slashes of str | Minor | fs | Akira Ajisaka | Akira Ajisaka |
+| [HADOOP-16232](https://issues.apache.org/jira/browse/HADOOP-16232) | Fix errors in the checkstyle configration xmls | Major | build | Akira Ajisaka | Wanqiang Ji |
+| [HDFS-14389](https://issues.apache.org/jira/browse/HDFS-14389) | getAclStatus returns incorrect permissions and owner when an iNodeAttributeProvider is configured | Major | namenode | Stephen O'Donnell | Stephen O'Donnell |
+| [HDFS-14407](https://issues.apache.org/jira/browse/HDFS-14407) | Fix misuse of SLF4j logging API in DatasetVolumeChecker#checkAllVolumes | Minor | . | Wanqiang Ji | Wanqiang Ji |
+| [YARN-9413](https://issues.apache.org/jira/browse/YARN-9413) | Queue resource leak after app fail for CapacityScheduler | Major | capacityscheduler | Tao Yang | Tao Yang |
+| [HADOOP-14635](https://issues.apache.org/jira/browse/HADOOP-14635) | Javadoc correction for AccessControlList#buildACL | Minor | documentation | Bibin A Chundatt | Yeliang Cang |
+| [HADOOP-14544](https://issues.apache.org/jira/browse/HADOOP-14544) | DistCp documentation for command line options is misaligned. | Minor | documentation | Chris Nauroth | Masatake Iwasaki |
+| [HDFS-10477](https://issues.apache.org/jira/browse/HDFS-10477) | Stop decommission a rack of DataNodes caused NameNode fail over to standby | Major | namenode | yunjiong zhao | yunjiong zhao |
+| [YARN-9487](https://issues.apache.org/jira/browse/YARN-9487) | NodeManager native build shouldn't link against librt on macOS | Major | nodemanager | Siyao Meng | Siyao Meng |
+| [YARN-6695](https://issues.apache.org/jira/browse/YARN-6695) | Race condition in RM for publishing container events vs appFinished events causes NPE | Critical | . | Rohith Sharma K S | Prabhu Joseph |
+| [YARN-8622](https://issues.apache.org/jira/browse/YARN-8622) | NodeManager native build fails due to getgrouplist not found on macOS | Major | nodemanager | Ewan Higgs | Siyao Meng |
+| [HADOOP-16265](https://issues.apache.org/jira/browse/HADOOP-16265) | Configuration#getTimeDuration is not consistent between default value and manual settings. | Major | . | star | star |
+| [HDFS-13677](https://issues.apache.org/jira/browse/HDFS-13677) | Dynamic refresh Disk configuration results in overwriting VolumeMap | Blocker | . | xuzq | xuzq |
+| [YARN-9285](https://issues.apache.org/jira/browse/YARN-9285) | RM UI progress column is of wrong type | Minor | yarn | Ahmed Hussein | Ahmed Hussein |
+| [HADOOP-16278](https://issues.apache.org/jira/browse/HADOOP-16278) | With S3A Filesystem, Long Running services End up Doing lot of GC and eventually die | Major | common, hadoop-aws, metrics | Rajat Khandelwal | Rajat Khandelwal |
+| [YARN-9504](https://issues.apache.org/jira/browse/YARN-9504) | [UI2] Fair scheduler queue view page does not show actual capacity | Major | fairscheduler, yarn-ui-v2 | Zoltan Siegl | Zoltan Siegl |
+| [YARN-9519](https://issues.apache.org/jira/browse/YARN-9519) | TFile log aggregation file format is not working for yarn.log-aggregation.TFile.remote-app-log-dir config | Major | log-aggregation | Adam Antal | Adam Antal |
+| [YARN-9508](https://issues.apache.org/jira/browse/YARN-9508) | YarnConfiguration areNodeLabel enabled is costly in allocation flow | Critical | . | Bibin A Chundatt | Bilwa S T |
+| [HADOOP-16247](https://issues.apache.org/jira/browse/HADOOP-16247) | NPE in FsUrlConnection | Major | hdfs-client | Karthik Palanisamy | Karthik Palanisamy |
+| [HADOOP-16248](https://issues.apache.org/jira/browse/HADOOP-16248) | MutableQuantiles leak memory under heavy load | Major | metrics | Alexis Daboville | Alexis Daboville |
+| [HDFS-14323](https://issues.apache.org/jira/browse/HDFS-14323) | Distcp fails in Hadoop 3.x when 2.x source webhdfs url has special characters in hdfs file path | Major | webhdfs | Srinivasu Majeti | Srinivasu Majeti |
+| [MAPREDUCE-7205](https://issues.apache.org/jira/browse/MAPREDUCE-7205) | Treat container scheduler kill exit code as a task attempt killing event | Major | applicationmaster, mr-am, mrv2 | Wanqiang Ji | Wanqiang Ji |
+| [HDFS-14500](https://issues.apache.org/jira/browse/HDFS-14500) | NameNode StartupProgress continues to report edit log segments after the LOADING\_EDITS phase is finished | Major | namenode | Erik Krogen | Erik Krogen |
+| [YARN-9500](https://issues.apache.org/jira/browse/YARN-9500) | Fix typos in ResourceModel.md | Trivial | documentation | leiqiang | leiqiang |
+| [HADOOP-16331](https://issues.apache.org/jira/browse/HADOOP-16331) | Fix ASF License check in pom.xml | Major | . | Wanqiang Ji | Akira Ajisaka |
+| [YARN-9542](https://issues.apache.org/jira/browse/YARN-9542) | Fix LogsCLI guessAppOwner ignores custom file format suffix | Minor | log-aggregation | Prabhu Joseph | Prabhu Joseph |
+| [HDFS-14512](https://issues.apache.org/jira/browse/HDFS-14512) | ONE\_SSD policy will be violated while write data with DistributedFileSystem.create(....favoredNodes) | Major | . | Shen Yinjie | Ayush Saxena |
+| [HADOOP-16334](https://issues.apache.org/jira/browse/HADOOP-16334) | Fix yetus-wrapper not working when HADOOP\_YETUS\_VERSION \>= 0.9.0 | Major | yetus | Wanqiang Ji | Wanqiang Ji |
+| [HDFS-14521](https://issues.apache.org/jira/browse/HDFS-14521) | Suppress setReplication logging. | Major | . | Kihwal Lee | Kihwal Lee |
+| [YARN-9507](https://issues.apache.org/jira/browse/YARN-9507) | Fix NPE in NodeManager#serviceStop on startup failure | Minor | . | Bilwa S T | Bilwa S T |
+| [YARN-8947](https://issues.apache.org/jira/browse/YARN-8947) | [UI2] Active User info missing from UI2 | Major | yarn-ui-v2 | Akhil PB | Akhil PB |
+| [YARN-8906](https://issues.apache.org/jira/browse/YARN-8906) | [UI2] NM hostnames not displayed correctly in Node Heatmap Chart | Major | . | Charan Hebri | Akhil PB |
+| [YARN-9580](https://issues.apache.org/jira/browse/YARN-9580) | Fulfilled reservation information in assignment is lost when transferring in ParentQueue#assignContainers | Major | capacityscheduler | Tao Yang | Tao Yang |
+| [YARN-8625](https://issues.apache.org/jira/browse/YARN-8625) | Aggregate Resource Allocation for each job is not present in ATS | Major | ATSv2 | Prabhu Joseph | Prabhu Joseph |
+| [HADOOP-16345](https://issues.apache.org/jira/browse/HADOOP-16345) | Potential NPE when instantiating FairCallQueue metrics | Major | ipc | Erik Krogen | Erik Krogen |
+| [YARN-9594](https://issues.apache.org/jira/browse/YARN-9594) | Fix missing break statement in ContainerScheduler#handle | Major | . | lujie | lujie |
+| [YARN-9565](https://issues.apache.org/jira/browse/YARN-9565) | RMAppImpl#ranNodes not cleared on FinalTransition | Major | . | Bibin A Chundatt | Bilwa S T |
+| [YARN-9547](https://issues.apache.org/jira/browse/YARN-9547) | ContainerStatusPBImpl default execution type is not returned | Major | . | Bibin A Chundatt | Bilwa S T |
+| [HDFS-13231](https://issues.apache.org/jira/browse/HDFS-13231) | Extend visualization for Decommissioning, Maintenance Mode under Datanode tab in the NameNode UI | Major | datanode, namenode | Haibo Yan | Stephen O'Donnell |
+| [HDFS-14535](https://issues.apache.org/jira/browse/HDFS-14535) | The default 8KB buffer in requestFileDescriptors#BufferedOutputStream is causing lots of heap allocation in HBase when using short-circut read | Major | hdfs-client | Zheng Hu | Zheng Hu |
+| [HDFS-13730](https://issues.apache.org/jira/browse/HDFS-13730) | BlockReaderRemote.sendReadResult throws NPE | Major | hdfs-client | Wei-Chiu Chuang | Yuanbo Liu |
+| [YARN-9584](https://issues.apache.org/jira/browse/YARN-9584) | Should put initializeProcessTrees method call before get pid | Critical | nodemanager | Wanqiang Ji | Wanqiang Ji |
+| [HDFS-14010](https://issues.apache.org/jira/browse/HDFS-14010) | Pass correct DF usage to ReservedSpaceCalculator builder | Minor | . | Lukas Majercak | Lukas Majercak |
+| [HDFS-14078](https://issues.apache.org/jira/browse/HDFS-14078) | Admin helper fails to prettify NullPointerExceptions | Major | . | Elek, Marton | Elek, Marton |
+| [HDFS-14101](https://issues.apache.org/jira/browse/HDFS-14101) | Random failure of testListCorruptFilesCorruptedBlock | Major | test | Kihwal Lee | Zsolt Venczel |
+| [HDFS-14465](https://issues.apache.org/jira/browse/HDFS-14465) | When the Block expected replications is larger than the number of DataNodes, entering maintenance will never exit. | Major | . | Yicong Cai | Yicong Cai |
+| [HDFS-13893](https://issues.apache.org/jira/browse/HDFS-13893) | DiskBalancer: no validations for Disk balancer commands | Major | diskbalancer | Harshakiran Reddy | Lokesh Jain |
+| [YARN-9209](https://issues.apache.org/jira/browse/YARN-9209) | When nodePartition is not set in Placement Constraints, containers are allocated only in default partition | Major | capacity scheduler, scheduler | Tarun Parimi | Tarun Parimi |
+| [HDFS-12487](https://issues.apache.org/jira/browse/HDFS-12487) | FsDatasetSpi.isValidBlock() lacks null pointer check inside and neither do the callers | Major | balancer & mover, diskbalancer | liumi | liumi |
+| [HDFS-14074](https://issues.apache.org/jira/browse/HDFS-14074) | DataNode runs async disk checks maybe throws NullPointerException, and DataNode failed to register to NameSpace. | Major | hdfs | guangyi lu | guangyi lu |
+| [HDFS-14541](https://issues.apache.org/jira/browse/HDFS-14541) | When evictableMmapped or evictable size is zero, do not throw NoSuchElementException | Major | hdfs-client, performance | Zheng Hu | Lisheng Sun |
+| [HDFS-14598](https://issues.apache.org/jira/browse/HDFS-14598) | Findbugs warning caused by HDFS-12487 | Minor | diskbalancer | Wei-Chiu Chuang | He Xiaoqiao |
+| [YARN-9639](https://issues.apache.org/jira/browse/YARN-9639) | DecommissioningNodesWatcher cause memory leak | Blocker | . | Bibin A Chundatt | Bilwa S T |
+| [YARN-9581](https://issues.apache.org/jira/browse/YARN-9581) | Fix WebAppUtils#getRMWebAppURLWithScheme ignores rm2 | Major | client | Prabhu Joseph | Prabhu Joseph |
+| [YARN-9327](https://issues.apache.org/jira/browse/YARN-9327) | Improve synchronisation in ProtoUtils#convertToProtoFormat block | Critical | . | Bibin A Chundatt | Bibin A Chundatt |
+| [YARN-9655](https://issues.apache.org/jira/browse/YARN-9655) | AllocateResponse in FederationInterceptor lost applicationPriority | Major | federation | hunshenshi | hunshenshi |
+| [HADOOP-16385](https://issues.apache.org/jira/browse/HADOOP-16385) | Namenode crashes with "RedundancyMonitor thread received Runtime exception" | Major | . | krishna reddy | Ayush Saxena |
+| [YARN-9644](https://issues.apache.org/jira/browse/YARN-9644) | First RMContext object is always leaked during switch over | Blocker | . | Bibin A Chundatt | Bibin A Chundatt |
+| [HDFS-14629](https://issues.apache.org/jira/browse/HDFS-14629) | Property value Hard Coded in DNConf.java | Trivial | . | hemanthboyina | hemanthboyina |
+| [YARN-9557](https://issues.apache.org/jira/browse/YARN-9557) | Application fails in diskchecker when ReadWriteDiskValidator is configured. | Critical | nodemanager | Anuruddh Nayak | Bilwa S T |
+| [HDFS-12703](https://issues.apache.org/jira/browse/HDFS-12703) | Exceptions are fatal to decommissioning monitor | Critical | namenode | Daryn Sharp | He Xiaoqiao |
+| [HDFS-12748](https://issues.apache.org/jira/browse/HDFS-12748) | NameNode memory leak when accessing webhdfs GETHOMEDIRECTORY | Major | hdfs | Jiandan Yang | Weiwei Yang |
+| [YARN-9625](https://issues.apache.org/jira/browse/YARN-9625) | UI2 - No link to a queue on the Queues page for Fair Scheduler | Major | . | Charan Hebri | Zoltan Siegl |
+| [HDFS-14466](https://issues.apache.org/jira/browse/HDFS-14466) | Add a regression test for HDFS-14323 | Minor | fs, test, webhdfs | Yuya Ebihara | Masatake Iwasaki |
+| [YARN-9235](https://issues.apache.org/jira/browse/YARN-9235) | If linux container executor is not set for a GPU cluster GpuResourceHandlerImpl is not initialized and NPE is thrown | Major | yarn | Antal Bálint Steinbach | Adam Antal |
+| [YARN-9626](https://issues.apache.org/jira/browse/YARN-9626) | UI2 - Fair scheduler queue apps page issues | Major | . | Charan Hebri | Zoltan Siegl |
+| [YARN-9645](https://issues.apache.org/jira/browse/YARN-9645) | Fix Invalid event FINISHED\_CONTAINERS\_PULLED\_BY\_AM at NEW on NM restart | Major | . | krishna reddy | Bilwa S T |
+| [YARN-9682](https://issues.apache.org/jira/browse/YARN-9682) | Wrong log message when finalizing the upgrade | Trivial | . | kyungwan nam | kyungwan nam |
+| [HADOOP-16440](https://issues.apache.org/jira/browse/HADOOP-16440) | Distcp can not preserve timestamp with -delete option | Major | . | ludun | ludun |
+| [MAPREDUCE-7076](https://issues.apache.org/jira/browse/MAPREDUCE-7076) | TestNNBench#testNNBenchCreateReadAndDelete failing in our internal build | Minor | test | Rushabh S Shah | kevin su |
+| [HADOOP-16443](https://issues.apache.org/jira/browse/HADOOP-16443) | Improve help text for setfacl --set option | Minor | fs | Stephen O'Donnell | Stephen O'Donnell |
+| [YARN-9668](https://issues.apache.org/jira/browse/YARN-9668) | UGI conf doesn't read user overridden configurations on RM and NM startup | Major | . | Jonathan Hung | Jonathan Hung |
+| [HADOOP-9844](https://issues.apache.org/jira/browse/HADOOP-9844) | NPE when trying to create an error message response of SASL RPC | Major | ipc | Steve Loughran | Steve Loughran |
+| [HADOOP-16245](https://issues.apache.org/jira/browse/HADOOP-16245) | Enabling SSL within LdapGroupsMapping can break system SSL configs | Major | common, security | Erik Krogen | Erik Krogen |
+| [HDFS-14429](https://issues.apache.org/jira/browse/HDFS-14429) | Block remain in COMMITTED but not COMPLETE caused by Decommission | Major | . | Yicong Cai | Yicong Cai |
+| [HADOOP-16435](https://issues.apache.org/jira/browse/HADOOP-16435) | RpcMetrics should not be retained forever | Critical | rpc-server | Zoltan Haindrich | Zoltan Haindrich |
+| [YARN-9596](https://issues.apache.org/jira/browse/YARN-9596) | QueueMetrics has incorrect metrics when labelled partitions are involved | Major | capacity scheduler | Muhammad Samir Khan | Muhammad Samir Khan |
+| [MAPREDUCE-7225](https://issues.apache.org/jira/browse/MAPREDUCE-7225) | Fix broken current folder expansion during MR job start | Major | mrv2 | Adam Antal | Peter Bacsko |
+| [HDFS-13529](https://issues.apache.org/jira/browse/HDFS-13529) | Fix default trash policy emptier trigger time correctly | Major | namenode | He Xiaoqiao | He Xiaoqiao |
+| [HADOOP-15681](https://issues.apache.org/jira/browse/HADOOP-15681) | AuthenticationFilter should generate valid date format for Set-Cookie header regardless of default Locale | Minor | security | Cao Manh Dat | Cao Manh Dat |
+| [HDFS-14685](https://issues.apache.org/jira/browse/HDFS-14685) | DefaultAuditLogger doesn't print CallerContext | Major | hdfs | xuzq | xuzq |
+| [HDFS-14462](https://issues.apache.org/jira/browse/HDFS-14462) | WebHDFS throws "Error writing request body to server" instead of DSQuotaExceededException | Major | webhdfs | Erik Krogen | Simbarashe Dzinamarira |
+| [HDFS-14691](https://issues.apache.org/jira/browse/HDFS-14691) | Wrong usage hint for hadoop fs command test | Minor | hdfs | Jianfei Jiang | Jianfei Jiang |
+| [HDFS-14557](https://issues.apache.org/jira/browse/HDFS-14557) | JournalNode error: Can't scan a pre-transactional edit log | Major | ha | Wei-Chiu Chuang | Stephen O'Donnell |
+| [HDFS-14692](https://issues.apache.org/jira/browse/HDFS-14692) | Upload button should not encode complete url | Major | . | Lokesh Jain | Lokesh Jain |
+| [HADOOP-15908](https://issues.apache.org/jira/browse/HADOOP-15908) | hadoop-build-tools jar is downloaded from remote repository instead of using from local | Minor | build | Oleksandr Shevchenko | Oleksandr Shevchenko |
+| [HDFS-14631](https://issues.apache.org/jira/browse/HDFS-14631) | The DirectoryScanner doesn't fix the wrongly placed replica. | Major | . | Jinglun | Jinglun |
+| [YARN-9685](https://issues.apache.org/jira/browse/YARN-9685) | NPE when rendering the info table of leaf queue in non-accessible partitions | Major | capacityscheduler | Tao Yang | Tao Yang |
+| [HDFS-14459](https://issues.apache.org/jira/browse/HDFS-14459) | ClosedChannelException silently ignored in FsVolumeList.addBlockPool() | Major | datanode | Stephen O'Donnell | Stephen O'Donnell |
+| [HDFS-13359](https://issues.apache.org/jira/browse/HDFS-13359) | DataXceiver hung due to the lock in FsDatasetImpl#getBlockInputStream | Major | datanode | Yiqun Lin | Yiqun Lin |
+| [YARN-9451](https://issues.apache.org/jira/browse/YARN-9451) | AggregatedLogsBlock shows wrong NM http port | Minor | nodemanager | Prabhu Joseph | Prabhu Joseph |
+| [YARN-9723](https://issues.apache.org/jira/browse/YARN-9723) | ApplicationPlacementContext is not required for terminated jobs during recovery | Major | resourcemanager | Prabhu Joseph | Prabhu Joseph |
+| [HDFS-12914](https://issues.apache.org/jira/browse/HDFS-12914) | Block report leases cause missing blocks until next report | Critical | namenode | Daryn Sharp | Santosh Marella |
+| [HDFS-14148](https://issues.apache.org/jira/browse/HDFS-14148) | HDFS OIV ReverseXML SnapshotSection parser throws exception when there are more than one snapshottable directory | Major | hdfs | Siyao Meng | Siyao Meng |
+| [HDFS-14595](https://issues.apache.org/jira/browse/HDFS-14595) | HDFS-11848 breaks API compatibility | Blocker | . | Wei-Chiu Chuang | Siyao Meng |
+| [HDFS-14423](https://issues.apache.org/jira/browse/HDFS-14423) | Percent (%) and plus (+) characters no longer work in WebHDFS | Major | webhdfs | Jing Wang | Masatake Iwasaki |
+| [MAPREDUCE-7230](https://issues.apache.org/jira/browse/MAPREDUCE-7230) | TestHSWebApp.testLogsViewSingle fails | Major | jobhistoryserver, test | Prabhu Joseph | Prabhu Joseph |
+| [YARN-9749](https://issues.apache.org/jira/browse/YARN-9749) | TestAppLogAggregatorImpl#testDFSQuotaExceeded fails on trunk | Major | log-aggregation, test | Peter Bacsko | Adam Antal |
+| [HDFS-14687](https://issues.apache.org/jira/browse/HDFS-14687) | Standby Namenode never come out of safemode when EC files are being written. | Critical | ec, namenode | Surendra Singh Lilhore | Surendra Singh Lilhore |
+| [HDFS-13101](https://issues.apache.org/jira/browse/HDFS-13101) | Yet another fsimage corruption related to snapshot | Major | snapshots | Yongjun Zhang | Shashikant Banerjee |
+| [HDFS-13201](https://issues.apache.org/jira/browse/HDFS-13201) | Fix prompt message in testPolicyAndStateCantBeNull | Minor | . | chencan | chencan |
+| [HDFS-14311](https://issues.apache.org/jira/browse/HDFS-14311) | Multi-threading conflict at layoutVersion when loading block pool storage | Major | rolling upgrades | Yicong Cai | Yicong Cai |
+| [HDFS-14582](https://issues.apache.org/jira/browse/HDFS-14582) | Failed to start DN with ArithmeticException when NULL checksum used | Major | datanode | Surendra Singh Lilhore | Surendra Singh Lilhore |
+| [YARN-9217](https://issues.apache.org/jira/browse/YARN-9217) | Nodemanager will fail to start if GPU is misconfigured on the node or GPU drivers missing | Major | yarn | Antal Bálint Steinbach | Peter Bacsko |
+| [HADOOP-16494](https://issues.apache.org/jira/browse/HADOOP-16494) | Add SHA-256 or SHA-512 checksum to release artifacts to comply with the release distribution policy | Blocker | build | Akira Ajisaka | Akira Ajisaka |
+| [YARN-9774](https://issues.apache.org/jira/browse/YARN-9774) | Fix order of arguments for assertEquals in TestSLSUtils | Minor | test | Nikhil Navadiya | Nikhil Navadiya |
+| [HDFS-13596](https://issues.apache.org/jira/browse/HDFS-13596) | NN restart fails after RollingUpgrade from 2.x to 3.x | Blocker | hdfs | Hanisha Koneru | Fei Hui |
+| [HDFS-14396](https://issues.apache.org/jira/browse/HDFS-14396) | Failed to load image from FSImageFile when downgrade from 3.x to 2.x | Blocker | rolling upgrades | Fei Hui | Fei Hui |
+| [YARN-8917](https://issues.apache.org/jira/browse/YARN-8917) | Absolute (maximum) capacity of level3+ queues is wrongly calculated for absolute resource | Critical | capacityscheduler | Tao Yang | Tao Yang |
+| [YARN-9642](https://issues.apache.org/jira/browse/YARN-9642) | Fix Memory Leak in AbstractYarnScheduler caused by timer | Blocker | resourcemanager | Bibin A Chundatt | Bibin A Chundatt |
+| [HDFS-13977](https://issues.apache.org/jira/browse/HDFS-13977) | NameNode can kill itself if it tries to send too many txns to a QJM simultaneously | Major | namenode, qjm | Erik Krogen | Erik Krogen |
+| [HDFS-2470](https://issues.apache.org/jira/browse/HDFS-2470) | NN should automatically set permissions on dfs.namenode.\*.dir | Major | namenode | Aaron T. Myers | Siddharth Wagle |
+| [YARN-9438](https://issues.apache.org/jira/browse/YARN-9438) | launchTime not written to state store for running applications | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-9640](https://issues.apache.org/jira/browse/YARN-9640) | Slow event processing could cause too many attempt unregister events | Critical | . | Bibin A Chundatt | Bibin A Chundatt |
+| [HDFS-12212](https://issues.apache.org/jira/browse/HDFS-12212) | Options.Rename.To\_TRASH is considered even when Options.Rename.NONE is specified | Major | namenode | Vinayakumar B | Vinayakumar B |
+| [YARN-9714](https://issues.apache.org/jira/browse/YARN-9714) | ZooKeeper connection in ZKRMStateStore leaks after RM transitioned to standby | Major | resourcemanager | Tao Yang | Tao Yang |
+| [HDFS-8178](https://issues.apache.org/jira/browse/HDFS-8178) | QJM doesn't move aside stale inprogress edits files | Major | qjm | Zhe Zhang | Istvan Fajth |
+| [HDFS-14706](https://issues.apache.org/jira/browse/HDFS-14706) | Checksums are not checked if block meta file is less than 7 bytes | Major | . | Stephen O'Donnell | Stephen O'Donnell |
+| [YARN-9797](https://issues.apache.org/jira/browse/YARN-9797) | LeafQueue#activateApplications should use resourceCalculator#fitsIn | Blocker | . | Bibin A Chundatt | Bilwa S T |
+| [YARN-9785](https://issues.apache.org/jira/browse/YARN-9785) | Fix DominantResourceCalculator when one resource is zero | Blocker | . | Bilwa S T | Bilwa S T |
+| [YARN-9718](https://issues.apache.org/jira/browse/YARN-9718) | Yarn REST API, services endpoint remote command ejection | Major | . | Eric Yang | Eric Yang |
+| [HADOOP-16255](https://issues.apache.org/jira/browse/HADOOP-16255) | ChecksumFS.Make FileSystem.rename(path, path, options) doesn't rename checksum | Major | fs | Steve Loughran | Jungtaek Lim |
+| [YARN-9817](https://issues.apache.org/jira/browse/YARN-9817) | Fix failing testcases due to not initialized AsyncDispatcher - ArithmeticException: / by zero | Major | test | Prabhu Joseph | Prabhu Joseph |
+| [YARN-9813](https://issues.apache.org/jira/browse/YARN-9813) | RM does not start on JDK11 when UIv2 is enabled | Critical | resourcemanager, yarn | Adam Antal | Adam Antal |
+| [YARN-9820](https://issues.apache.org/jira/browse/YARN-9820) | RM logs InvalidStateTransitionException when app is submitted | Critical | . | Rohith Sharma K S | Prabhu Joseph |
+
+
+### TESTS:
+
+| JIRA | Summary | Priority | Component | Reporter | Contributor |
+|:---- |:---- | :--- |:---- |:---- |:---- |
+| [YARN-8907](https://issues.apache.org/jira/browse/YARN-8907) | Modify a logging message in TestCapacityScheduler | Trivial | . | Zhankun Tang | Zhankun Tang |
+| [YARN-8904](https://issues.apache.org/jira/browse/YARN-8904) | TestRMDelegationTokens can fail in testRMDTMasterKeyStateOnRollingMasterKey | Minor | test | Wilfred Spiegelenburg | Wilfred Spiegelenburg |
+| [YARN-8944](https://issues.apache.org/jira/browse/YARN-8944) | TestContainerAllocation.testUserLimitAllocationMultipleContainers failure after YARN-8896 | Minor | capacity scheduler | Wilfred Spiegelenburg | Wilfred Spiegelenburg |
+| [YARN-9263](https://issues.apache.org/jira/browse/YARN-9263) | TestConfigurationNodeAttributesProvider fails after Mockito updated | Minor | . | Weiwei Yang | Weiwei Yang |
+| [YARN-9315](https://issues.apache.org/jira/browse/YARN-9315) | TestCapacitySchedulerMetrics fails intermittently | Minor | capacity scheduler | Prabhu Joseph | Prabhu Joseph |
+| [YARN-9316](https://issues.apache.org/jira/browse/YARN-9316) | TestPlacementConstraintsUtil#testInterAppConstraintsByAppID fails intermittently | Minor | capacity scheduler | Prabhu Joseph | Prabhu Joseph |
+| [YARN-9324](https://issues.apache.org/jira/browse/YARN-9324) | TestSchedulingRequestContainerAllocation(Async) fails with junit-4.11 | Major | capacity scheduler | Prabhu Joseph | Prabhu Joseph |
+| [YARN-9325](https://issues.apache.org/jira/browse/YARN-9325) | TestQueueManagementDynamicEditPolicy fails intermittent | Minor | capacity scheduler | Prabhu Joseph | Prabhu Joseph |
+| [HDFS-11950](https://issues.apache.org/jira/browse/HDFS-11950) | Disable libhdfs zerocopy test on Mac | Minor | libhdfs | John Zhuge | Akira Ajisaka |
+
+
+### SUB-TASKS:
+
+| JIRA | Summary | Priority | Component | Reporter | Contributor |
+|:---- |:---- | :--- |:---- |:---- |:---- |
+| [YARN-6989](https://issues.apache.org/jira/browse/YARN-6989) | Ensure timeline service v2 codebase gets UGI from HttpServletRequest in a consistent way | Major | timelineserver | Vrushali C | Abhishek Modi |
+| [YARN-8834](https://issues.apache.org/jira/browse/YARN-8834) | Provide Java client for fetching Yarn specific entities from TimelineReader | Critical | timelinereader | Rohith Sharma K S | Abhishek Modi |
+| [YARN-3879](https://issues.apache.org/jira/browse/YARN-3879) | [Storage implementation] Create HDFS backing storage implementation for ATS reads | Major | timelineserver | Tsuyoshi Ozawa | Abhishek Modi |
+| [YARN-6098](https://issues.apache.org/jira/browse/YARN-6098) | Add documentation for Delete Queue | Major | capacity scheduler, documentation | Naganarasimha G R | Suma Shivaprasad |
+| [YARN-8456](https://issues.apache.org/jira/browse/YARN-8456) | Fix a configuration handling bug when user leave FPGA discover executable path configuration default but set OpenCL SDK path environment variable | Major | yarn | Zhankun Tang | Zhankun Tang |
+| [HADOOP-15868](https://issues.apache.org/jira/browse/HADOOP-15868) | AliyunOSS: update document for properties of multiple part download, multiple part upload and directory copy | Major | fs/oss | wujinhu | wujinhu |
+| [YARN-8871](https://issues.apache.org/jira/browse/YARN-8871) | Document behavior of YARN-5742 | Major | . | Vrushali C | Suma Shivaprasad |
+| [YARN-7754](https://issues.apache.org/jira/browse/YARN-7754) | [Atsv2] Update document for running v1 and v2 TS | Major | . | Rohith Sharma K S | Suma Shivaprasad |
+| [HDFS-14047](https://issues.apache.org/jira/browse/HDFS-14047) | [libhdfs++] Fix hdfsGetLastExceptionRootCause bug in test\_libhdfs\_threaded.c | Major | libhdfs, native | Anatoli Shein | Anatoli Shein |
+| [YARN-8988](https://issues.apache.org/jira/browse/YARN-8988) | Reduce the verbose log on RM heartbeat path when distributed node-attributes is enabled | Major | . | Weiwei Yang | Tao Yang |
+| [HADOOP-15846](https://issues.apache.org/jira/browse/HADOOP-15846) | ABFS: fix mask related bugs in setAcl, modifyAclEntries and removeAclEntries. | Major | fs/azure | Thomas Marquardt | junhua gu |
+| [HADOOP-15812](https://issues.apache.org/jira/browse/HADOOP-15812) | ABFS: Improve AbfsRestOperationException format to ensure full msg can be displayed on console | Major | fs/azure | Da Zhou | Da Zhou |
+| [YARN-8987](https://issues.apache.org/jira/browse/YARN-8987) | Usability improvements node-attributes CLI | Critical | . | Weiwei Yang | Bibin A Chundatt |
+| [HADOOP-15876](https://issues.apache.org/jira/browse/HADOOP-15876) | Use keySet().removeAll() to remove multiple keys from Map in AzureBlobFileSystemStore | Minor | fs/azure | Ted Yu | Da Zhou |
+| [HADOOP-15917](https://issues.apache.org/jira/browse/HADOOP-15917) | AliyunOSS: fix incorrect ReadOps and WriteOps in statistics | Major | fs/oss | wujinhu | wujinhu |
+| [YARN-8303](https://issues.apache.org/jira/browse/YARN-8303) | YarnClient should contact TimelineReader for application/attempt/container report | Critical | . | Rohith Sharma K S | Abhishek Modi |
+| [HADOOP-15872](https://issues.apache.org/jira/browse/HADOOP-15872) | ABFS: Update to target 2018-11-09 REST version for ADLS Gen 2 | Major | fs/azure | Thomas Marquardt | junhua gu |
+| [HADOOP-15940](https://issues.apache.org/jira/browse/HADOOP-15940) | ABFS: For HNS account, avoid unnecessary get call when doing Rename | Major | fs/azure | Da Zhou | Da Zhou |
+| [YARN-8986](https://issues.apache.org/jira/browse/YARN-8986) | publish all exposed ports to random ports when using bridge network | Minor | yarn | dockerzhang | dockerzhang |
+| [HADOOP-15932](https://issues.apache.org/jira/browse/HADOOP-15932) | Oozie unable to create sharelib in s3a filesystem | Critical | fs, fs/s3 | Soumitra Sulav | Steve Loughran |
+| [YARN-9034](https://issues.apache.org/jira/browse/YARN-9034) | ApplicationCLI should have option to take clusterId | Major | . | Rohith Sharma K S | Rohith Sharma K S |
+| [HDFS-13713](https://issues.apache.org/jira/browse/HDFS-13713) | Add specification of Multipart Upload API to FS specification, with contract tests | Blocker | fs, test | Steve Loughran | Ewan Higgs |
+| [HADOOP-15968](https://issues.apache.org/jira/browse/HADOOP-15968) | ABFS: add try catch for UGI failure when initializing ABFS | Major | fs/azure | Da Zhou | Da Zhou |
+| [HADOOP-15969](https://issues.apache.org/jira/browse/HADOOP-15969) | ABFS: getNamespaceEnabled can fail blocking user access thru ACLs | Major | fs/azure | Da Zhou | Da Zhou |
+| [HADOOP-15972](https://issues.apache.org/jira/browse/HADOOP-15972) | ABFS: reduce list page size to to 500 | Major | fs/azure | Da Zhou | Da Zhou |
+| [HADOOP-16004](https://issues.apache.org/jira/browse/HADOOP-16004) | ABFS: Convert 404 error response in AbfsInputStream and AbfsOutPutStream to FileNotFoundException | Major | fs/azure | Da Zhou | Da Zhou |
+| [YARN-9126](https://issues.apache.org/jira/browse/YARN-9126) | Container reinit always fails in branch-3.2 and trunk | Major | . | Eric Yang | Chandni Singh |
+| [YARN-8925](https://issues.apache.org/jira/browse/YARN-8925) | Updating distributed node attributes only when necessary | Major | resourcemanager | Tao Yang | Tao Yang |
+| [HADOOP-16009](https://issues.apache.org/jira/browse/HADOOP-16009) | Replace the url of the repository in Apache Hadoop source code | Major | documentation | Akira Ajisaka | Akira Ajisaka |
+| [HADOOP-15323](https://issues.apache.org/jira/browse/HADOOP-15323) | AliyunOSS: Improve copy file performance for AliyunOSSFileSystemStore | Major | fs/oss | wujinhu | wujinhu |
+| [YARN-6149](https://issues.apache.org/jira/browse/YARN-6149) | Allow port range to be specified while starting NM Timeline collector manager. | Major | timelineserver | Varun Saxena | Abhishek Modi |
+| [HADOOP-16040](https://issues.apache.org/jira/browse/HADOOP-16040) | ABFS: Bug fix for tolerateOobAppends configuration | Major | fs/azure | Da Zhou | Da Zhou |
+| [HADOOP-15975](https://issues.apache.org/jira/browse/HADOOP-15975) | ABFS: remove timeout check for DELETE and RENAME | Major | fs/azure | Da Zhou | Da Zhou |
+| [HADOOP-15662](https://issues.apache.org/jira/browse/HADOOP-15662) | ABFS: Better exception handling of DNS errors | Major | fs/azure | Thomas Marquardt | Da Zhou |
+| [HADOOP-16045](https://issues.apache.org/jira/browse/HADOOP-16045) | Don't run TestDU on Windows | Trivial | common, test | Lukas Majercak | Lukas Majercak |
+| [HADOOP-16044](https://issues.apache.org/jira/browse/HADOOP-16044) | ABFS: Better exception handling of DNS errors followup | Major | . | Da Zhou | Da Zhou |
+| [HADOOP-16048](https://issues.apache.org/jira/browse/HADOOP-16048) | ABFS: Fix Date format parser | Major | fs/azure | Da Zhou | Da Zhou |
+| [YARN-8101](https://issues.apache.org/jira/browse/YARN-8101) | Add UT to verify node-attributes in RM nodes rest API | Minor | resourcemanager, restapi | Weiwei Yang | Prabhu Joseph |
+| [HADOOP-16041](https://issues.apache.org/jira/browse/HADOOP-16041) | UserAgent string for ABFS | Major | fs/azure | Shweta | Shweta |
+| [HADOOP-16079](https://issues.apache.org/jira/browse/HADOOP-16079) | Token.toString faulting if any token listed can't load. | Blocker | security | Steve Loughran | Steve Loughran |
+| [YARN-9275](https://issues.apache.org/jira/browse/YARN-9275) | Add link to NodeAttributes doc in PlacementConstraints document | Minor | documentation | Weiwei Yang | Masatake Iwasaki |
+| [YARN-6735](https://issues.apache.org/jira/browse/YARN-6735) | Have a way to turn off container metrics from NMs | Major | timelineserver | Vrushali C | Abhishek Modi |
+| [HADOOP-15954](https://issues.apache.org/jira/browse/HADOOP-15954) | ABFS: Enable owner and group conversion for MSI and login user using OAuth | Major | fs/azure | junhua gu | Da Zhou |
+| [YARN-9253](https://issues.apache.org/jira/browse/YARN-9253) | Add UT to verify Placement Constraint in Distributed Shell | Major | . | Prabhu Joseph | Prabhu Joseph |
+| [YARN-9252](https://issues.apache.org/jira/browse/YARN-9252) | Allocation Tag Namespace support in Distributed Shell | Major | distributed-shell | Prabhu Joseph | Prabhu Joseph |
+| [YARN-8555](https://issues.apache.org/jira/browse/YARN-8555) | Parameterize TestSchedulingRequestContainerAllocation(Async) to cover both PC handler options | Minor | . | Weiwei Yang | Prabhu Joseph |
+| [YARN-9293](https://issues.apache.org/jira/browse/YARN-9293) | Optimize MockAMLauncher event handling | Major | . | Bibin A Chundatt | Bibin A Chundatt |
+| [HADOOP-16104](https://issues.apache.org/jira/browse/HADOOP-16104) | Wasb tests to downgrade to skip when test a/c is namespace enabled | Major | fs/azure, test | Steve Loughran | Masatake Iwasaki |
+| [YARN-9258](https://issues.apache.org/jira/browse/YARN-9258) | Support to specify allocation tags without constraint in distributed shell CLI | Major | distributed-shell | Prabhu Joseph | Prabhu Joseph |
+| [HADOOP-16136](https://issues.apache.org/jira/browse/HADOOP-16136) | ABFS: Should only transform username to short name | Major | . | Da Zhou | Da Zhou |
+| [YARN-5336](https://issues.apache.org/jira/browse/YARN-5336) | Limit the flow name size & consider cleanup for hex chars | Major | timelineserver | Vrushali C | Sushil Ks |
+| [YARN-3841](https://issues.apache.org/jira/browse/YARN-3841) | [Storage implementation] Adding retry semantics to HDFS backing storage | Major | timelineserver | Tsuyoshi Ozawa | Abhishek Modi |
+| [HADOOP-16169](https://issues.apache.org/jira/browse/HADOOP-16169) | ABFS: Bug fix for getPathProperties | Major | fs/azure | Da Zhou | Da Zhou |
+| [HADOOP-16109](https://issues.apache.org/jira/browse/HADOOP-16109) | Parquet reading S3AFileSystem causes EOF | Blocker | fs/s3 | Dave Christianson | Steve Loughran |
+| [HADOOP-15625](https://issues.apache.org/jira/browse/HADOOP-15625) | S3A input stream to use etags/version number to detect changed source files | Major | fs/s3 | Brahma Reddy Battula | Ben Roling |
+| [HADOOP-16124](https://issues.apache.org/jira/browse/HADOOP-16124) | Extend documentation in testing.md about endpoint constants | Trivial | hadoop-aws | Adam Antal | Adam Antal |
+| [HADOOP-16191](https://issues.apache.org/jira/browse/HADOOP-16191) | AliyunOSS: improvements for copyFile/copyDirectory and logging | Major | fs/oss | wujinhu | wujinhu |
+| [YARN-9387](https://issues.apache.org/jira/browse/YARN-9387) | Update document for ATS HBase Custom tablenames (-entityTableName) | Critical | ATSv2 | Prabhu Joseph | Prabhu Joseph |
+| [YARN-9389](https://issues.apache.org/jira/browse/YARN-9389) | FlowActivity and FlowRun table prefix is wrong | Minor | ATSv2 | Prabhu Joseph | Prabhu Joseph |
+| [YARN-9391](https://issues.apache.org/jira/browse/YARN-9391) | Disable PATH variable to be passed to Docker container | Major | . | Eric Yang | Jim Brennan |
+| [HADOOP-16058](https://issues.apache.org/jira/browse/HADOOP-16058) | S3A tests to include Terasort | Major | fs/s3, test | Steve Loughran | Steve Loughran |
+| [HADOOP-16220](https://issues.apache.org/jira/browse/HADOOP-16220) | Add findbugs ignores for unjustified issues during update to guava to 27.0-jre in hadoop-project | Major | . | Gabor Bota | Gabor Bota |
+| [YARN-9418](https://issues.apache.org/jira/browse/YARN-9418) | ATSV2 /apps/appId/entities/YARN\_CONTAINER rest api does not show metrics | Critical | ATSv2 | Prabhu Joseph | Prabhu Joseph |
+| [HADOOP-16233](https://issues.apache.org/jira/browse/HADOOP-16233) | S3AFileStatus to declare that isEncrypted() is always true | Minor | fs/s3 | Steve Loughran | Steve Loughran |
+| [YARN-9303](https://issues.apache.org/jira/browse/YARN-9303) | Username splits won't help timelineservice.app\_flow table | Major | ATSv2 | Prabhu Joseph | Prabhu Joseph |
+| [YARN-9382](https://issues.apache.org/jira/browse/YARN-9382) | Publish container killed, paused and resumed events to ATSv2. | Major | . | Abhishek Modi | Abhishek Modi |
+| [YARN-9335](https://issues.apache.org/jira/browse/YARN-9335) | [atsv2] Restrict the number of elements held in timeline collector when backend is unreachable for async calls | Major | . | Vrushali C | Abhishek Modi |
+| [HADOOP-16269](https://issues.apache.org/jira/browse/HADOOP-16269) | ABFS: add listFileStatus with StartFrom | Major | fs/azure | Da Zhou | Da Zhou |
+| [HADOOP-16251](https://issues.apache.org/jira/browse/HADOOP-16251) | ABFS: add FSMainOperationsBaseTest | Major | fs/azure | Da Zhou | Da Zhou |
+| [HADOOP-16306](https://issues.apache.org/jira/browse/HADOOP-16306) | AliyunOSS: Remove temporary files when upload small files to OSS | Major | fs/oss | wujinhu | wujinhu |
+| [YARN-7537](https://issues.apache.org/jira/browse/YARN-7537) | [Atsv2] load hbase configuration from filesystem rather than URL | Major | . | Rohith Sharma K S | Prabhu Joseph |
+| [HDFS-14553](https://issues.apache.org/jira/browse/HDFS-14553) | Make queue size of BlockReportProcessingThread configurable | Major | namenode | He Xiaoqiao | He Xiaoqiao |
+| [HADOOP-16211](https://issues.apache.org/jira/browse/HADOOP-16211) | Update guava to 27.0-jre in hadoop-project branch-3.2 | Major | . | Gabor Bota | Gabor Bota |
+| [YARN-8499](https://issues.apache.org/jira/browse/YARN-8499) | ATS v2 Generic TimelineStorageMonitor | Major | ATSv2 | Sunil Govindan | Prabhu Joseph |
+| [YARN-9374](https://issues.apache.org/jira/browse/YARN-9374) | HBaseTimelineWriterImpl sync writes has to avoid thread blocking if storage down | Major | ATSv2 | Prabhu Joseph | Prabhu Joseph |
+| [HADOOP-16401](https://issues.apache.org/jira/browse/HADOOP-16401) | ABFS: port Azure doc to 3.2 branch | Major | fs/azure | Da Zhou | Masatake Iwasaki |
+| [HDFS-14034](https://issues.apache.org/jira/browse/HDFS-14034) | Support getQuotaUsage API in WebHDFS | Major | fs, webhdfs | Erik Krogen | Chao Sun |
+| [YARN-9765](https://issues.apache.org/jira/browse/YARN-9765) | SLS runner crashes when run with metrics turned off. | Major | . | Abhishek Modi | Abhishek Modi |
+| [HDFS-14674](https://issues.apache.org/jira/browse/HDFS-14674) | [SBN read] Got an unexpected txid when tail editlog | Blocker | . | wangzhaohui | wangzhaohui |
+| [YARN-9775](https://issues.apache.org/jira/browse/YARN-9775) | RMWebServices /scheduler-conf GET returns all hadoop configurations for ZKConfigurationStore | Major | restapi | Prabhu Joseph | Prabhu Joseph |
+| [HDFS-14779](https://issues.apache.org/jira/browse/HDFS-14779) | Fix logging error in TestEditLog#testMultiStreamsLoadEditWithConfMaxTxns | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-9804](https://issues.apache.org/jira/browse/YARN-9804) | Update ATSv2 document for latest feature supports | Blocker | . | Rohith Sharma K S | Rohith Sharma K S |
+| [YARN-9821](https://issues.apache.org/jira/browse/YARN-9821) | NM hangs at serviceStop when ATSV2 Backend Hbase is Down | Major | ATSv2 | Prabhu Joseph | Prabhu Joseph |
+
+
+### OTHER:
+
+| JIRA | Summary | Priority | Component | Reporter | Contributor |
+|:---- |:---- | :--- |:---- |:---- |:---- |
+| [HADOOP-15851](https://issues.apache.org/jira/browse/HADOOP-15851) | Disable wildfly logs to the console | Major | fs/azure | Vishwajeet Dusane | Vishwajeet Dusane |
+| [HDFS-12729](https://issues.apache.org/jira/browse/HDFS-12729) | Document special paths in HDFS | Major | documentation | Chris Douglas | Masatake Iwasaki |
+| [YARN-9191](https://issues.apache.org/jira/browse/YARN-9191) | Add cli option in DS to support enforceExecutionType in resource requests. | Major | . | Abhishek Modi | Abhishek Modi |
+| [HADOOP-16037](https://issues.apache.org/jira/browse/HADOOP-16037) | DistCp: Document usage of Sync (-diff option) in detail | Major | documentation, tools/distcp | Siyao Meng | Siyao Meng |
+| [HADOOP-16263](https://issues.apache.org/jira/browse/HADOOP-16263) | Update BUILDING.txt with macOS native build instructions | Minor | . | Siyao Meng | Siyao Meng |
+| [YARN-9559](https://issues.apache.org/jira/browse/YARN-9559) | Create AbstractContainersLauncher for pluggable ContainersLauncher logic | Major | . | Jonathan Hung | Jonathan Hung |
+| [YARN-9796](https://issues.apache.org/jira/browse/YARN-9796) | Fix ASF license issue in branch-3.2 | Blocker | . | Rohith Sharma K S | Prabhu Joseph |
+
+
diff --git a/hadoop-common-project/hadoop-common/src/site/markdown/release/3.2.1/RELEASENOTES.3.2.1.md b/hadoop-common-project/hadoop-common/src/site/markdown/release/3.2.1/RELEASENOTES.3.2.1.md
new file mode 100644
index 0000000000000..0a8862abbbcaa
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/site/markdown/release/3.2.1/RELEASENOTES.3.2.1.md
@@ -0,0 +1,80 @@
+
+
+# Apache Hadoop 3.2.1 Release Notes
+
+These release notes cover new developer and user-facing incompatibilities, important issues, features, and major improvements.
+
+
+---
+
+* [YARN-8986](https://issues.apache.org/jira/browse/YARN-8986) | *Minor* | **publish all exposed ports to random ports when using bridge network**
+
+support -p and -P for bridge type network;
+
+
+---
+
+* [YARN-9071](https://issues.apache.org/jira/browse/YARN-9071) | *Critical* | **NM and service AM don't have updated status for reinitialized containers**
+
+In progress upgrade status may show READY state sooner than actual upgrade operations. External caller to upgrade API is recommended to wait minimum 30 seconds before querying yarn app -status.
+
+
+---
+
+* [YARN-9084](https://issues.apache.org/jira/browse/YARN-9084) | *Major* | **Service Upgrade: With default readiness check, the status of upgrade is reported to be successful prematurely**
+
+Improve transient container status accuracy for upgrade.
+
+
+---
+
+* [HADOOP-15922](https://issues.apache.org/jira/browse/HADOOP-15922) | *Major* | **DelegationTokenAuthenticationFilter get wrong doAsUser since it does not decode URL**
+
+- Fix DelegationTokenAuthentication filter for incorrectly double encode doAs user parameter.
+
+
+---
+
+* [YARN-8761](https://issues.apache.org/jira/browse/YARN-8761) | *Major* | **Service AM support for decommissioning component instances**
+
+- Component instance number is not linear increment when decommission feature is used. Application with assumption of linear increment component instance number maybe impacted by introduction of this feature.
+
+
+---
+
+* [HDFS-14305](https://issues.apache.org/jira/browse/HDFS-14305) | *Major* | **Serial number in BlockTokenSecretManager could overlap between different namenodes**
+
+NameNodes rely on independent block token key ranges to communicate block token identities to DataNodes and clients in a way that does not create conflicts between the tokens issued by multiple NameNodes. HDFS-6440 introduced the potential for overlaps in key ranges; this fixes the issue by creating 64 possible key ranges that NameNodes assign themselves to, allowing for up to 64 NameNodes to run safely. This limitation only applies within a single Namespace; there may be more than 64 NameNodes total spread among multiple federated Namespaces.
+
+
+---
+
+* [HDFS-14396](https://issues.apache.org/jira/browse/HDFS-14396) | *Blocker* | **Failed to load image from FSImageFile when downgrade from 3.x to 2.x**
+
+During a rolling upgrade from Hadoop 2.x to 3.x, NameNode cannot persist erasure coding information, and therefore a user cannot start using erasure coding feature until finalize is done.
+
+
+---
+
+* [YARN-7055](https://issues.apache.org/jira/browse/YARN-7055) | *Major* | **YARN Timeline Service v.2: beta 1 / GA**
+
+Application Timeline Server v2 is ready for production. It is GA from 3.2.1 release on wards.
+
+
+
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/conf/TestConfiguration.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/conf/TestConfiguration.java
index 64beb7b484296..a6adb9f20a3ef 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/conf/TestConfiguration.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/conf/TestConfiguration.java
@@ -2437,7 +2437,7 @@ public void testGettingPropertiesWithPrefix() throws Exception {
}
conf.set("different.prefix" + ".name", "value");
Map prefixedProps = conf.getPropsWithPrefix("prefix.");
- assertEquals(prefixedProps.size(), 10);
+ assertThat(prefixedProps.size(), is(10));
for (int i = 0; i < 10; i++) {
assertEquals("value" + i, prefixedProps.get("name" + i));
}
@@ -2448,7 +2448,7 @@ public void testGettingPropertiesWithPrefix() throws Exception {
conf.set("subprefix." + "subname" + i, "value_${foo}" + i);
}
prefixedProps = conf.getPropsWithPrefix("subprefix.");
- assertEquals(prefixedProps.size(), 10);
+ assertThat(prefixedProps.size(), is(10));
for (int i = 0; i < 10; i++) {
assertEquals("value_bar" + i, prefixedProps.get("subname" + i));
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/CryptoStreamsTestBase.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/CryptoStreamsTestBase.java
index 7463d6c3bc064..53d0939a2d398 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/CryptoStreamsTestBase.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/CryptoStreamsTestBase.java
@@ -46,6 +46,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static org.assertj.core.api.Assertions.assertThat;
+
public abstract class CryptoStreamsTestBase {
protected static final Logger LOG = LoggerFactory.getLogger(
CryptoStreamsTestBase.class);
@@ -198,7 +200,7 @@ private void readCheck(InputStream in) throws Exception {
// EOF
n = in.read(result, 0, dataLen);
- Assert.assertEquals(n, -1);
+ assertThat(n).isEqualTo(-1);
}
/** Test crypto writing with different buffer size. */
@@ -388,42 +390,41 @@ private void positionedReadCheckWithByteBuffer(InputStream in, int pos)
Assert.assertArrayEquals(readData, expectedData);
}
- /** Test read fully */
+ /** Test read fully. */
@Test(timeout=120000)
public void testReadFully() throws Exception {
OutputStream out = getOutputStream(defaultBufferSize);
writeData(out);
- InputStream in = getInputStream(defaultBufferSize);
- final int len1 = dataLen / 4;
- // Read len1 bytes
- byte[] readData = new byte[len1];
- readAll(in, readData, 0, len1);
- byte[] expectedData = new byte[len1];
- System.arraycopy(data, 0, expectedData, 0, len1);
- Assert.assertArrayEquals(readData, expectedData);
-
- // Pos: 1/3 dataLen
- readFullyCheck(in, dataLen / 3);
-
- // Read len1 bytes
- readData = new byte[len1];
- readAll(in, readData, 0, len1);
- expectedData = new byte[len1];
- System.arraycopy(data, len1, expectedData, 0, len1);
- Assert.assertArrayEquals(readData, expectedData);
-
- // Pos: 1/2 dataLen
- readFullyCheck(in, dataLen / 2);
-
- // Read len1 bytes
- readData = new byte[len1];
- readAll(in, readData, 0, len1);
- expectedData = new byte[len1];
- System.arraycopy(data, 2 * len1, expectedData, 0, len1);
- Assert.assertArrayEquals(readData, expectedData);
-
- in.close();
+ try (InputStream in = getInputStream(defaultBufferSize)) {
+ final int len1 = dataLen / 4;
+ // Read len1 bytes
+ byte[] readData = new byte[len1];
+ readAll(in, readData, 0, len1);
+ byte[] expectedData = new byte[len1];
+ System.arraycopy(data, 0, expectedData, 0, len1);
+ Assert.assertArrayEquals(readData, expectedData);
+
+ // Pos: 1/3 dataLen
+ readFullyCheck(in, dataLen / 3);
+
+ // Read len1 bytes
+ readData = new byte[len1];
+ readAll(in, readData, 0, len1);
+ expectedData = new byte[len1];
+ System.arraycopy(data, len1, expectedData, 0, len1);
+ Assert.assertArrayEquals(readData, expectedData);
+
+ // Pos: 1/2 dataLen
+ readFullyCheck(in, dataLen / 2);
+
+ // Read len1 bytes
+ readData = new byte[len1];
+ readAll(in, readData, 0, len1);
+ expectedData = new byte[len1];
+ System.arraycopy(data, 2 * len1, expectedData, 0, len1);
+ Assert.assertArrayEquals(readData, expectedData);
+ }
}
private void readFullyCheck(InputStream in, int pos) throws Exception {
@@ -441,6 +442,60 @@ private void readFullyCheck(InputStream in, int pos) throws Exception {
} catch (EOFException e) {
}
}
+
+ /** Test byte byffer read fully. */
+ @Test(timeout=120000)
+ public void testByteBufferReadFully() throws Exception {
+ OutputStream out = getOutputStream(defaultBufferSize);
+ writeData(out);
+
+ try (InputStream in = getInputStream(defaultBufferSize)) {
+ final int len1 = dataLen / 4;
+ // Read len1 bytes
+ byte[] readData = new byte[len1];
+ readAll(in, readData, 0, len1);
+ byte[] expectedData = new byte[len1];
+ System.arraycopy(data, 0, expectedData, 0, len1);
+ Assert.assertArrayEquals(readData, expectedData);
+
+ // Pos: 1/3 dataLen
+ byteBufferReadFullyCheck(in, dataLen / 3);
+
+ // Read len1 bytes
+ readData = new byte[len1];
+ readAll(in, readData, 0, len1);
+ expectedData = new byte[len1];
+ System.arraycopy(data, len1, expectedData, 0, len1);
+ Assert.assertArrayEquals(readData, expectedData);
+
+ // Pos: 1/2 dataLen
+ byteBufferReadFullyCheck(in, dataLen / 2);
+
+ // Read len1 bytes
+ readData = new byte[len1];
+ readAll(in, readData, 0, len1);
+ expectedData = new byte[len1];
+ System.arraycopy(data, 2 * len1, expectedData, 0, len1);
+ Assert.assertArrayEquals(readData, expectedData);
+ }
+ }
+
+ private void byteBufferReadFullyCheck(InputStream in, int pos)
+ throws Exception {
+ ByteBuffer result = ByteBuffer.allocate(dataLen - pos);
+ ((ByteBufferPositionedReadable) in).readFully(pos, result);
+
+ byte[] expectedData = new byte[dataLen - pos];
+ System.arraycopy(data, pos, expectedData, 0, dataLen - pos);
+ Assert.assertArrayEquals(result.array(), expectedData);
+
+ result = ByteBuffer.allocate(dataLen); // Exceeds maximum length
+ try {
+ ((ByteBufferPositionedReadable) in).readFully(pos, result);
+ Assert.fail("Read fully exceeds maximum length should fail.");
+ } catch (EOFException e) {
+ }
+ }
/** Test seek to different position. */
@Test(timeout=120000)
@@ -559,7 +614,7 @@ public void testSkip() throws Exception {
// Skip after EOF
skipped = in.skip(3);
- Assert.assertEquals(skipped, 0);
+ assertThat(skipped).isZero();
in.close();
}
@@ -791,7 +846,7 @@ public void testCombinedOp() throws Exception {
((Seekable) in).seek(dataLen);
buf.clear();
n = ((ByteBufferReadable) in).read(buf);
- Assert.assertEquals(n, -1);
+ assertThat(n).isEqualTo(-1);
in.close();
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoStreams.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoStreams.java
index 8bcf46eacf041..73c6249612387 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoStreams.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoStreams.java
@@ -330,6 +330,30 @@ public int read(long position, ByteBuffer buf) throws IOException {
return -1;
}
+ @Override
+ public void readFully(long position, ByteBuffer buf) throws IOException {
+ if (buf == null) {
+ throw new NullPointerException();
+ } else if (!buf.hasRemaining()) {
+ return;
+ }
+
+ if (position > length) {
+ throw new IOException("Cannot read after EOF.");
+ }
+ if (position < 0) {
+ throw new IOException("Cannot read to negative offset.");
+ }
+
+ checkStream();
+
+ if (position + buf.remaining() > length) {
+ throw new EOFException("Reach the end of stream.");
+ }
+
+ buf.put(data, (int) position, buf.remaining());
+ }
+
@Override
public void readFully(long position, byte[] b, int off, int len)
throws IOException {
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoStreamsForLocalFS.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoStreamsForLocalFS.java
index e7d922e78a64e..8453889b53a5a 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoStreamsForLocalFS.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoStreamsForLocalFS.java
@@ -95,6 +95,11 @@ public void testByteBufferRead() throws Exception {}
@Override
@Test(timeout=10000)
public void testPositionedReadWithByteBuffer() throws IOException {}
+
+ @Ignore("Wrapped stream doesn't support ByteBufferPositionedReadable")
+ @Override
+ @Test(timeout=10000)
+ public void testByteBufferReadFully() throws Exception {}
@Ignore("ChecksumFSOutputSummer doesn't support Syncable")
@Override
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoStreamsNormal.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoStreamsNormal.java
index 036706f435a60..1bf1dd3e0d6a3 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoStreamsNormal.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoStreamsNormal.java
@@ -96,6 +96,11 @@ public void testPositionedRead() throws IOException {}
@Test(timeout=10000)
public void testPositionedReadWithByteBuffer() throws IOException {}
+ @Ignore("Wrapped stream doesn't support ByteBufferPositionedReadable")
+ @Override
+ @Test(timeout=10000)
+ public void testByteBufferReadFully() throws Exception {}
+
@Ignore("Wrapped stream doesn't support ReadFully")
@Override
@Test(timeout=10000)
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoStreamsWithJceAesCtrCryptoCodec.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoStreamsWithJceAesCtrCryptoCodec.java
index 76c39d694b04c..d47dd307574f8 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoStreamsWithJceAesCtrCryptoCodec.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoStreamsWithJceAesCtrCryptoCodec.java
@@ -19,20 +19,21 @@
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
-import org.junit.Assert;
import org.junit.BeforeClass;
+import static org.assertj.core.api.Assertions.assertThat;
+
public class TestCryptoStreamsWithJceAesCtrCryptoCodec extends
TestCryptoStreams {
@BeforeClass
- public static void init() throws Exception {
+ public static void init() {
Configuration conf = new Configuration();
conf.set(
CommonConfigurationKeysPublic.HADOOP_SECURITY_CRYPTO_CODEC_CLASSES_AES_CTR_NOPADDING_KEY,
JceAesCtrCryptoCodec.class.getName());
codec = CryptoCodec.getInstance(conf);
- Assert.assertEquals(JceAesCtrCryptoCodec.class.getCanonicalName(),
- codec.getClass().getCanonicalName());
+ assertThat(JceAesCtrCryptoCodec.class.getCanonicalName())
+ .isEqualTo(codec.getClass().getCanonicalName());
}
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/key/TestValueQueue.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/key/TestValueQueue.java
index abc4ebf9b4dbc..55a9280d6260a 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/key/TestValueQueue.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/key/TestValueQueue.java
@@ -20,6 +20,7 @@
import java.io.IOException;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeoutException;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
@@ -31,7 +32,6 @@
import org.junit.Assert;
import org.junit.Test;
-import com.google.common.base.Supplier;
import com.google.common.collect.Sets;
public class TestValueQueue {
@@ -62,6 +62,18 @@ public FillInfo getTop() throws InterruptedException {
}
}
+ private void waitForRefill(ValueQueue> valueQueue, String queueName, int queueSize)
+ throws TimeoutException, InterruptedException {
+ GenericTestUtils.waitFor(() -> {
+ int size = valueQueue.getSize(queueName);
+ if (size != queueSize) {
+ LOG.info("Current ValueQueue size is " + size);
+ return false;
+ }
+ return true;
+ }, 100, 3000);
+ }
+
/**
* Verifies that Queue is initially filled to "numInitValues"
*/
@@ -69,7 +81,7 @@ public FillInfo getTop() throws InterruptedException {
public void testInitFill() throws Exception {
MockFiller filler = new MockFiller();
ValueQueue vq =
- new ValueQueue(10, 0.1f, 300, 1,
+ new ValueQueue(10, 0.1f, 30000, 1,
SyncGenerationPolicy.ALL, filler);
Assert.assertEquals("test", vq.getNext("k1"));
Assert.assertEquals(1, filler.getTop().num);
@@ -83,7 +95,7 @@ public void testInitFill() throws Exception {
public void testWarmUp() throws Exception {
MockFiller filler = new MockFiller();
ValueQueue vq =
- new ValueQueue(10, 0.5f, 300, 1,
+ new ValueQueue(10, 0.5f, 30000, 1,
SyncGenerationPolicy.ALL, filler);
vq.initializeQueuesForKeys("k1", "k2", "k3");
FillInfo[] fillInfos =
@@ -106,14 +118,17 @@ public void testWarmUp() throws Exception {
public void testRefill() throws Exception {
MockFiller filler = new MockFiller();
ValueQueue vq =
- new ValueQueue(10, 0.1f, 300, 1,
+ new ValueQueue(100, 0.1f, 30000, 1,
SyncGenerationPolicy.ALL, filler);
+ // Trigger a prefill (10) and an async refill (91)
Assert.assertEquals("test", vq.getNext("k1"));
- Assert.assertEquals(1, filler.getTop().num);
- // Trigger refill
- vq.getNext("k1");
- Assert.assertEquals(1, filler.getTop().num);
Assert.assertEquals(10, filler.getTop().num);
+
+ // Wait for the async task to finish
+ waitForRefill(vq, "k1", 100);
+ // Refill task should add 91 values to get to a full queue (10 produced by
+ // the prefill to the low watermark, 1 consumed by getNext())
+ Assert.assertEquals(91, filler.getTop().num);
vq.shutdown();
}
@@ -125,10 +140,27 @@ public void testRefill() throws Exception {
public void testNoRefill() throws Exception {
MockFiller filler = new MockFiller();
ValueQueue vq =
- new ValueQueue(10, 0.5f, 300, 1,
+ new ValueQueue(10, 0.5f, 30000, 1,
SyncGenerationPolicy.ALL, filler);
+ // Trigger a prefill (5) and an async refill (6)
Assert.assertEquals("test", vq.getNext("k1"));
Assert.assertEquals(5, filler.getTop().num);
+
+ // Wait for the async task to finish
+ waitForRefill(vq, "k1", 10);
+ // Refill task should add 6 values to get to a full queue (5 produced by
+ // the prefill to the low watermark, 1 consumed by getNext())
+ Assert.assertEquals(6, filler.getTop().num);
+
+ // Take another value, queue is still above the watermark
+ Assert.assertEquals("test", vq.getNext("k1"));
+
+ // Wait a while to make sure that no async refills are triggered
+ try {
+ waitForRefill(vq, "k1", 10);
+ } catch (TimeoutException ignored) {
+ // This is the correct outcome - no refill is expected
+ }
Assert.assertEquals(null, filler.getTop());
vq.shutdown();
}
@@ -140,11 +172,29 @@ public void testNoRefill() throws Exception {
public void testgetAtMostPolicyALL() throws Exception {
MockFiller filler = new MockFiller();
final ValueQueue vq =
- new ValueQueue(10, 0.1f, 300, 1,
+ new ValueQueue(10, 0.1f, 30000, 1,
SyncGenerationPolicy.ALL, filler);
+ // Trigger a prefill (1) and an async refill (10)
Assert.assertEquals("test", vq.getNext("k1"));
Assert.assertEquals(1, filler.getTop().num);
+ // Wait for the async task to finish
+ waitForRefill(vq, "k1", 10);
+ // Refill task should add 10 values to get to a full queue (1 produced by
+ // the prefill to the low watermark, 1 consumed by getNext())
+ Assert.assertEquals(10, filler.getTop().num);
+
+ // Drain completely, no further refills triggered
+ vq.drain("k1");
+
+ // Wait a while to make sure that no async refills are triggered
+ try {
+ waitForRefill(vq, "k1", 10);
+ } catch (TimeoutException ignored) {
+ // This is the correct outcome - no refill is expected
+ }
+ Assert.assertNull(filler.getTop());
+
// Synchronous call:
// 1. Synchronously fill returned list
// 2. Start another async task to fill the queue in the cache
@@ -154,23 +204,16 @@ public void testgetAtMostPolicyALL() throws Exception {
filler.getTop().num);
// Wait for the async task to finish
- GenericTestUtils.waitFor(new Supplier() {
- @Override
- public Boolean get() {
- int size = vq.getSize("k1");
- if (size != 10) {
- LOG.info("Current ValueQueue size is " + size);
- return false;
- }
- return true;
- }
- }, 100, 3000);
+ waitForRefill(vq, "k1", 10);
+ // Refill task should add 10 values to get to a full queue
Assert.assertEquals("Failed in async call.", 10, filler.getTop().num);
// Drain completely after filled by the async thread
- Assert.assertEquals("Failed to drain completely after async.", 10,
- vq.getAtMost("k1", 10).size());
- // Synchronous call (No Async call since num > lowWatermark)
+ vq.drain("k1");
+ Assert.assertEquals("Failed to drain completely after async.", 0,
+ vq.getSize("k1"));
+
+ // Synchronous call
Assert.assertEquals("Failed to get all 19.", 19,
vq.getAtMost("k1", 19).size());
Assert.assertEquals("Failed in sync call.", 19, filler.getTop().num);
@@ -184,14 +227,29 @@ public Boolean get() {
public void testgetAtMostPolicyATLEAST_ONE() throws Exception {
MockFiller filler = new MockFiller();
ValueQueue vq =
- new ValueQueue(10, 0.3f, 300, 1,
+ new ValueQueue(10, 0.3f, 30000, 1,
SyncGenerationPolicy.ATLEAST_ONE, filler);
+ // Trigger a prefill (3) and an async refill (8)
Assert.assertEquals("test", vq.getNext("k1"));
Assert.assertEquals(3, filler.getTop().num);
- // Drain completely
- Assert.assertEquals(2, vq.getAtMost("k1", 10).size());
- // Asynch Refill call
- Assert.assertEquals(10, filler.getTop().num);
+
+ // Wait for the async task to finish
+ waitForRefill(vq, "k1", 10);
+ // Refill task should add 8 values to get to a full queue (3 produced by
+ // the prefill to the low watermark, 1 consumed by getNext())
+ Assert.assertEquals("Failed in async call.", 8, filler.getTop().num);
+
+ // Drain completely, no further refills triggered
+ vq.drain("k1");
+
+ // Queue is empty, sync will return a single value and trigger a refill
+ Assert.assertEquals(1, vq.getAtMost("k1", 10).size());
+ Assert.assertEquals(1, filler.getTop().num);
+
+ // Wait for the async task to finish
+ waitForRefill(vq, "k1", 10);
+ // Refill task should add 10 values to get to a full queue
+ Assert.assertEquals("Failed in async call.", 10, filler.getTop().num);
vq.shutdown();
}
@@ -202,16 +260,29 @@ public void testgetAtMostPolicyATLEAST_ONE() throws Exception {
public void testgetAtMostPolicyLOW_WATERMARK() throws Exception {
MockFiller filler = new MockFiller();
ValueQueue vq =
- new ValueQueue(10, 0.3f, 300, 1,
+ new ValueQueue(10, 0.3f, 30000, 1,
SyncGenerationPolicy.LOW_WATERMARK, filler);
+ // Trigger a prefill (3) and an async refill (8)
Assert.assertEquals("test", vq.getNext("k1"));
Assert.assertEquals(3, filler.getTop().num);
- // Drain completely
+
+ // Wait for the async task to finish
+ waitForRefill(vq, "k1", 10);
+ // Refill task should add 8 values to get to a full queue (3 produced by
+ // the prefill to the low watermark, 1 consumed by getNext())
+ Assert.assertEquals("Failed in async call.", 8, filler.getTop().num);
+
+ // Drain completely, no further refills triggered
+ vq.drain("k1");
+
+ // Queue is empty, sync will return 3 values and trigger a refill
Assert.assertEquals(3, vq.getAtMost("k1", 10).size());
- // Synchronous call
- Assert.assertEquals(1, filler.getTop().num);
- // Asynch Refill call
- Assert.assertEquals(10, filler.getTop().num);
+ Assert.assertEquals(3, filler.getTop().num);
+
+ // Wait for the async task to finish
+ waitForRefill(vq, "k1", 10);
+ // Refill task should add 10 values to get to a full queue
+ Assert.assertEquals("Failed in async call.", 10, filler.getTop().num);
vq.shutdown();
}
@@ -219,11 +290,27 @@ public void testgetAtMostPolicyLOW_WATERMARK() throws Exception {
public void testDrain() throws Exception {
MockFiller filler = new MockFiller();
ValueQueue vq =
- new ValueQueue(10, 0.1f, 300, 1,
+ new ValueQueue(10, 0.1f, 30000, 1,
SyncGenerationPolicy.ALL, filler);
+ // Trigger a prefill (1) and an async refill (10)
Assert.assertEquals("test", vq.getNext("k1"));
Assert.assertEquals(1, filler.getTop().num);
+
+ // Wait for the async task to finish
+ waitForRefill(vq, "k1", 10);
+ // Refill task should add 10 values to get to a full queue (1 produced by
+ // the prefill to the low watermark, 1 consumed by getNext())
+ Assert.assertEquals(10, filler.getTop().num);
+
+ // Drain completely, no further refills triggered
vq.drain("k1");
+
+ // Wait a while to make sure that no async refills are triggered
+ try {
+ waitForRefill(vq, "k1", 10);
+ } catch (TimeoutException ignored) {
+ // This is the correct outcome - no refill is expected
+ }
Assert.assertNull(filler.getTop());
vq.shutdown();
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/FileContextURIBase.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/FileContextURIBase.java
index a99f7625e0c9e..abb6d4f901591 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/FileContextURIBase.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/FileContextURIBase.java
@@ -130,7 +130,7 @@ public void testCreateFileWithNullName() throws IOException {
@Test
public void testCreateExistingFile() throws IOException {
- String fileName = "testFile";
+ String fileName = "testCreateExistingFile";
Path testPath = qualifiedPath(fileName, fc2);
// Ensure file does not exist
@@ -153,7 +153,7 @@ public void testCreateExistingFile() throws IOException {
@Test
public void testCreateFileInNonExistingDirectory() throws IOException {
- String fileName = "testDir/testFile";
+ String fileName = "testCreateFileInNonExistingDirectory/testFile";
Path testPath = qualifiedPath(fileName, fc2);
@@ -165,7 +165,8 @@ public void testCreateFileInNonExistingDirectory() throws IOException {
// Ensure using fc2 that file is created
Assert.assertTrue(isDir(fc2, testPath.getParent()));
- Assert.assertEquals("testDir", testPath.getParent().getName());
+ Assert.assertEquals("testCreateFileInNonExistingDirectory",
+ testPath.getParent().getName());
Assert.assertTrue(exists(fc2, testPath));
}
@@ -293,7 +294,7 @@ public void testIsDirectory() throws IOException {
@Test
public void testDeleteFile() throws IOException {
- Path testPath = qualifiedPath("testFile", fc2);
+ Path testPath = qualifiedPath("testDeleteFile", fc2);
// Ensure file does not exist
Assert.assertFalse(exists(fc2, testPath));
@@ -314,7 +315,7 @@ public void testDeleteFile() throws IOException {
@Test
public void testDeleteNonExistingFile() throws IOException {
- String testFileName = "testFile";
+ String testFileName = "testDeleteNonExistingFile";
Path testPath = qualifiedPath(testFileName, fc2);
// TestCase1 : Test delete on file never existed
@@ -341,7 +342,7 @@ public void testDeleteNonExistingFile() throws IOException {
@Test
public void testDeleteNonExistingFileInDir() throws IOException {
- String testFileInDir = "testDir/testDir/TestFile";
+ String testFileInDir = "testDeleteNonExistingFileInDir/testDir/TestFile";
Path testPath = qualifiedPath(testFileInDir, fc2);
// TestCase1 : Test delete on file never existed
@@ -418,7 +419,7 @@ public void testDeleteDirectory() throws IOException {
@Test
public void testDeleteNonExistingDirectory() throws IOException {
- String testDirName = "testFile";
+ String testDirName = "testDeleteNonExistingDirectory";
Path testPath = qualifiedPath(testDirName, fc2);
// TestCase1 : Test delete on directory never existed
@@ -445,7 +446,7 @@ public void testDeleteNonExistingDirectory() throws IOException {
@Test
public void testModificationTime() throws IOException {
- String testFile = "file1";
+ String testFile = "testModificationTime";
long fc2ModificationTime, fc1ModificationTime;
Path testPath = qualifiedPath(testFile, fc2);
@@ -461,7 +462,7 @@ public void testModificationTime() throws IOException {
@Test
public void testFileStatus() throws IOException {
- String fileName = "file1";
+ String fileName = "testModificationTime";
Path path2 = fc2.makeQualified(new Path(BASE, fileName));
// Create a file on fc2's file system using fc1
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestChecksumFs.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestChecksumFs.java
new file mode 100644
index 0000000000000..0959845963000
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestChecksumFs.java
@@ -0,0 +1,135 @@
+/**
+ * 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;
+
+import java.io.IOException;
+import java.util.EnumSet;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.permission.FsPermission;
+import org.apache.hadoop.test.GenericTestUtils;
+import org.apache.hadoop.test.HadoopTestBase;
+
+import static org.apache.hadoop.fs.CreateFlag.*;
+
+/**
+ * This class tests the functionality of ChecksumFs.
+ */
+public class TestChecksumFs extends HadoopTestBase {
+ private Configuration conf;
+ private Path testRootDirPath;
+ private FileContext fc;
+
+ @Before
+ public void setUp() throws Exception {
+ conf = getTestConfiguration();
+ fc = FileContext.getFileContext(conf);
+ testRootDirPath = new Path(GenericTestUtils.getRandomizedTestDir()
+ .getAbsolutePath());
+ mkdirs(testRootDirPath);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (fc != null) {
+ fc.delete(testRootDirPath, true);
+ }
+ }
+
+ @Test
+ public void testRenameFileToFile() throws Exception {
+ Path srcPath = new Path(testRootDirPath, "testRenameSrc");
+ Path dstPath = new Path(testRootDirPath, "testRenameDst");
+ verifyRename(srcPath, dstPath, false);
+ }
+
+ @Test
+ public void testRenameFileToFileWithOverwrite() throws Exception {
+ Path srcPath = new Path(testRootDirPath, "testRenameSrc");
+ Path dstPath = new Path(testRootDirPath, "testRenameDst");
+ verifyRename(srcPath, dstPath, true);
+ }
+
+ @Test
+ public void testRenameFileIntoDirFile() throws Exception {
+ Path srcPath = new Path(testRootDirPath, "testRenameSrc");
+ Path dstPath = new Path(testRootDirPath, "testRenameDir/testRenameDst");
+ mkdirs(dstPath);
+ verifyRename(srcPath, dstPath, false);
+ }
+
+ @Test
+ public void testRenameFileIntoDirFileWithOverwrite() throws Exception {
+ Path srcPath = new Path(testRootDirPath, "testRenameSrc");
+ Path dstPath = new Path(testRootDirPath, "testRenameDir/testRenameDst");
+ mkdirs(dstPath);
+ verifyRename(srcPath, dstPath, true);
+ }
+
+ private void verifyRename(Path srcPath, Path dstPath,
+ boolean overwrite) throws Exception {
+ ChecksumFs fs = (ChecksumFs) fc.getDefaultFileSystem();
+
+ fs.delete(srcPath, true);
+ fs.delete(dstPath, true);
+
+ Options.Rename renameOpt = Options.Rename.NONE;
+ if (overwrite) {
+ renameOpt = Options.Rename.OVERWRITE;
+ createTestFile(fs, dstPath, 2);
+ }
+
+ // ensure file + checksum are moved
+ createTestFile(fs, srcPath, 1);
+ assertTrue("Checksum file doesn't exist for source file - " + srcPath,
+ fc.util().exists(fs.getChecksumFile(srcPath)));
+ fs.rename(srcPath, dstPath, renameOpt);
+ assertTrue("Checksum file doesn't exist for dest file - " + srcPath,
+ fc.util().exists(fs.getChecksumFile(dstPath)));
+ try (FSDataInputStream is = fs.open(dstPath)) {
+ assertEquals(1, is.readInt());
+ }
+ }
+
+ private static Configuration getTestConfiguration() {
+ Configuration conf = new Configuration(false);
+ conf.set("fs.defaultFS", "file:///");
+ conf.setClass("fs.AbstractFileSystem.file.impl",
+ org.apache.hadoop.fs.local.LocalFs.class,
+ org.apache.hadoop.fs.AbstractFileSystem.class);
+ return conf;
+ }
+
+ private void createTestFile(ChecksumFs fs, Path path, int content)
+ throws IOException {
+ try (FSDataOutputStream fout = fs.create(path,
+ EnumSet.of(CREATE, OVERWRITE),
+ Options.CreateOpts.perms(FsPermission.getDefault()))) {
+ fout.writeInt(content);
+ }
+ }
+
+ private void mkdirs(Path dirPath) throws IOException {
+ fc.mkdir(dirPath, FileContext.DEFAULT_PERM, true);
+ }
+}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestFileUtil.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestFileUtil.java
index f5571038a6b5a..5d22a6a2a4896 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestFileUtil.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestFileUtil.java
@@ -1493,4 +1493,10 @@ public void testReadSymlinkWithAFileAsInput() throws IOException {
file.delete();
}
+ /**
+ * The size of FileSystem cache.
+ */
+ public static int getCacheSize() {
+ return FileSystem.cacheSize();
+ }
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestFilterFileSystem.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestFilterFileSystem.java
index e7f42ff2b5603..f0057a6c6d902 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestFilterFileSystem.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestFilterFileSystem.java
@@ -77,7 +77,6 @@ public FSDataOutputStream createNonRecursive(Path f, FsPermission permission,
boolean overwrite, int bufferSize, short replication, long blockSize,
Progressable progress) throws IOException;
- public boolean mkdirs(Path f);
public FSDataInputStream open(Path f);
public FSDataInputStream open(PathHandle f);
public FSDataOutputStream create(Path f);
@@ -135,6 +134,8 @@ public Token>[] addDelegationTokens(String renewer, Credentials creds)
public Path fixRelativePart(Path p);
public ContentSummary getContentSummary(Path f);
public QuotaUsage getQuotaUsage(Path f);
+ void setQuota(Path f, long namespaceQuota, long storagespaceQuota);
+ void setQuotaByStorageType(Path f, StorageType type, long quota);
StorageStatistics getStorageStatistics();
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestFsShellCopy.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestFsShellCopy.java
index f9b2420067029..72ae296c957b5 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestFsShellCopy.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestFsShellCopy.java
@@ -189,7 +189,7 @@ private void checkPut(Path srcPath, Path targetDir, boolean useWindowsPath)
// copy to new file, then again
prepPut(dstPath, false, false);
checkPut(0, srcPath, dstPath, useWindowsPath);
- if (lfs.isFile(srcPath)) {
+ if (lfs.getFileStatus(srcPath).isFile()) {
checkPut(1, srcPath, dstPath, useWindowsPath);
} else { // directory works because it copies into the dir
// clear contents so the check won't think there are extra paths
@@ -228,11 +228,11 @@ private void prepPut(Path dst, boolean create,
if (create) {
if (isDir) {
lfs.mkdirs(dst);
- assertTrue(lfs.isDirectory(dst));
+ assertTrue(lfs.getFileStatus(dst).isDirectory());
} else {
lfs.mkdirs(new Path(dst.getName()));
lfs.create(dst).close();
- assertTrue(lfs.isFile(dst));
+ assertTrue(lfs.getFileStatus(dst).isFile());
}
}
}
@@ -253,7 +253,7 @@ private void checkPut(int exitCode, Path src, Path dest,
Path target;
if (lfs.exists(dest)) {
- if (lfs.isDirectory(dest)) {
+ if (lfs.getFileStatus(dest).isDirectory()) {
target = new Path(pathAsString(dest), src.getName());
} else {
target = dest;
@@ -276,7 +276,8 @@ private void checkPut(int exitCode, Path src, Path dest,
if (exitCode == 0) {
assertTrue(lfs.exists(target));
- assertTrue(lfs.isFile(src) == lfs.isFile(target));
+ assertTrue(lfs.getFileStatus(src).isFile() ==
+ lfs.getFileStatus(target).isFile());
assertEquals(1, lfs.listStatus(lfs.makeQualified(target).getParent()).length);
} else {
assertEquals(targetExists, lfs.exists(target));
@@ -293,7 +294,7 @@ public void testRepresentsDir() throws Exception {
argv = new String[]{ "-put", srcPath.toString(), dstPath.toString() };
assertEquals(0, shell.run(argv));
- assertTrue(lfs.exists(dstPath) && lfs.isFile(dstPath));
+ assertTrue(lfs.exists(dstPath) && lfs.getFileStatus(dstPath).isFile());
lfs.delete(dstPath, true);
assertFalse(lfs.exists(dstPath));
@@ -319,7 +320,7 @@ public void testRepresentsDir() throws Exception {
"-put", srcPath.toString(), dstPath.toString()+suffix };
assertEquals(0, shell.run(argv));
assertTrue(lfs.exists(subdirDstPath));
- assertTrue(lfs.isFile(subdirDstPath));
+ assertTrue(lfs.getFileStatus(subdirDstPath).isFile());
}
// ensure .. is interpreted as a dir
@@ -329,7 +330,7 @@ public void testRepresentsDir() throws Exception {
argv = new String[]{ "-put", srcPath.toString(), dotdotDst };
assertEquals(0, shell.run(argv));
assertTrue(lfs.exists(subdirDstPath));
- assertTrue(lfs.isFile(subdirDstPath));
+ assertTrue(lfs.getFileStatus(subdirDstPath).isFile());
}
@Test
@@ -442,9 +443,33 @@ public void testMoveFileFromLocal() throws Exception {
assertEquals(0, exit);
assertFalse(lfs.exists(srcFile));
assertTrue(lfs.exists(target));
- assertTrue(lfs.isFile(target));
+ assertTrue(lfs.getFileStatus(target).isFile());
}
-
+
+ @Test
+ public void testMoveFileFromLocalDestExists() throws Exception{
+ Path testRoot = new Path(testRootDir, "testPutFile");
+ lfs.delete(testRoot, true);
+ lfs.mkdirs(testRoot);
+
+ Path target = new Path(testRoot, "target");
+ Path srcFile = new Path(testRoot, new Path("srcFile"));
+ lfs.createNewFile(srcFile);
+
+ int exit = shell.run(new String[]{
+ "-moveFromLocal", srcFile.toString(), target.toString()});
+ assertEquals(0, exit);
+ assertFalse(lfs.exists(srcFile));
+ assertTrue(lfs.exists(target));
+ assertTrue(lfs.getFileStatus(target).isFile());
+
+ lfs.createNewFile(srcFile);
+ exit = shell.run(new String[]{
+ "-moveFromLocal", srcFile.toString(), target.toString()});
+ assertEquals(1, exit);
+ assertTrue(lfs.exists(srcFile));
+ }
+
@Test
public void testMoveDirFromLocal() throws Exception {
Path testRoot = new Path(testRootDir, "testPutDir");
@@ -502,7 +527,7 @@ public void testMoveFromWindowsLocalPath() throws Exception {
shellRun(0, "-moveFromLocal", winSrcFile, target.toString());
assertFalse(lfs.exists(srcFile));
assertTrue(lfs.exists(target));
- assertTrue(lfs.isFile(target));
+ assertTrue(lfs.getFileStatus(target).isFile());
}
@Test
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestHarFileSystem.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestHarFileSystem.java
index 57798c2c8b982..3b923e05bd3a5 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestHarFileSystem.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestHarFileSystem.java
@@ -46,8 +46,7 @@
import static org.apache.hadoop.fs.Options.ChecksumOpt;
import static org.apache.hadoop.fs.Options.CreateOpts;
import static org.apache.hadoop.fs.Options.Rename;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.assertj.core.api.Assertions.assertThat;
@SuppressWarnings("deprecation")
public class TestHarFileSystem {
@@ -118,6 +117,8 @@ public FSDataOutputStream create(Path f, FsPermission permission,
public void processDeleteOnExit();
public ContentSummary getContentSummary(Path f);
public QuotaUsage getQuotaUsage(Path f);
+ void setQuota(Path f, long namespaceQuota, long storagespaceQuota);
+ void setQuotaByStorageType(Path f, StorageType type, long quota);
public FsStatus getStatus();
public FileStatus[] listStatus(Path f, PathFilter filter);
public FileStatus[] listStatusBatch(Path f, byte[] token);
@@ -277,13 +278,8 @@ static void checkInvalidPath(String s, Configuration conf) {
@Test
public void testFileChecksum() throws Exception {
final Path p = new Path("har://file-localhost/foo.har/file1");
- final HarFileSystem harfs = new HarFileSystem();
- try {
- Assert.assertEquals(null, harfs.getFileChecksum(p));
- } finally {
- if (harfs != null) {
- harfs.close();
- }
+ try (HarFileSystem harfs = new HarFileSystem()) {
+ assertThat(harfs.getFileChecksum(p)).isNull();
}
}
@@ -297,30 +293,30 @@ public void testFixBlockLocations() {
// case 1: range starts before current har block and ends after
BlockLocation[] b = { new BlockLocation(null, null, 10, 10) };
HarFileSystem.fixBlockLocations(b, 0, 20, 5);
- assertEquals(b[0].getOffset(), 5);
- assertEquals(b[0].getLength(), 10);
+ assertThat(b[0].getOffset()).isEqualTo(5);
+ assertThat(b[0].getLength()).isEqualTo(10);
}
{
// case 2: range starts in current har block and ends after
BlockLocation[] b = { new BlockLocation(null, null, 10, 10) };
HarFileSystem.fixBlockLocations(b, 0, 20, 15);
- assertEquals(b[0].getOffset(), 0);
- assertEquals(b[0].getLength(), 5);
+ assertThat(b[0].getOffset()).isZero();
+ assertThat(b[0].getLength()).isEqualTo(5);
}
{
// case 3: range starts before current har block and ends in
// current har block
BlockLocation[] b = { new BlockLocation(null, null, 10, 10) };
HarFileSystem.fixBlockLocations(b, 0, 10, 5);
- assertEquals(b[0].getOffset(), 5);
- assertEquals(b[0].getLength(), 5);
+ assertThat(b[0].getOffset()).isEqualTo(5);
+ assertThat(b[0].getLength()).isEqualTo(5);
}
{
// case 4: range starts and ends in current har block
BlockLocation[] b = { new BlockLocation(null, null, 10, 10) };
HarFileSystem.fixBlockLocations(b, 0, 6, 12);
- assertEquals(b[0].getOffset(), 0);
- assertEquals(b[0].getLength(), 6);
+ assertThat(b[0].getOffset()).isZero();
+ assertThat(b[0].getLength()).isEqualTo(6);
}
// now try a range where start == 3
@@ -328,30 +324,30 @@ public void testFixBlockLocations() {
// case 5: range starts before current har block and ends after
BlockLocation[] b = { new BlockLocation(null, null, 10, 10) };
HarFileSystem.fixBlockLocations(b, 3, 20, 5);
- assertEquals(b[0].getOffset(), 5);
- assertEquals(b[0].getLength(), 10);
+ assertThat(b[0].getOffset()).isEqualTo(5);
+ assertThat(b[0].getLength()).isEqualTo(10);
}
{
// case 6: range starts in current har block and ends after
BlockLocation[] b = { new BlockLocation(null, null, 10, 10) };
HarFileSystem.fixBlockLocations(b, 3, 20, 15);
- assertEquals(b[0].getOffset(), 3);
- assertEquals(b[0].getLength(), 2);
+ assertThat(b[0].getOffset()).isEqualTo(3);
+ assertThat(b[0].getLength()).isEqualTo(2);
}
{
// case 7: range starts before current har block and ends in
// current har block
BlockLocation[] b = { new BlockLocation(null, null, 10, 10) };
HarFileSystem.fixBlockLocations(b, 3, 7, 5);
- assertEquals(b[0].getOffset(), 5);
- assertEquals(b[0].getLength(), 5);
+ assertThat(b[0].getOffset()).isEqualTo(5);
+ assertThat(b[0].getLength()).isEqualTo(5);
}
{
// case 8: range starts and ends in current har block
BlockLocation[] b = { new BlockLocation(null, null, 10, 10) };
HarFileSystem.fixBlockLocations(b, 3, 3, 12);
- assertEquals(b[0].getOffset(), 3);
- assertEquals(b[0].getLength(), 3);
+ assertThat(b[0].getOffset()).isEqualTo(3);
+ assertThat(b[0].getLength()).isEqualTo(3);
}
// test case from JIRA MAPREDUCE-1752
@@ -359,10 +355,10 @@ public void testFixBlockLocations() {
BlockLocation[] b = { new BlockLocation(null, null, 512, 512),
new BlockLocation(null, null, 1024, 512) };
HarFileSystem.fixBlockLocations(b, 0, 512, 896);
- assertEquals(b[0].getOffset(), 0);
- assertEquals(b[0].getLength(), 128);
- assertEquals(b[1].getOffset(), 128);
- assertEquals(b[1].getLength(), 384);
+ assertThat(b[0].getOffset()).isZero();
+ assertThat(b[0].getLength()).isEqualTo(128);
+ assertThat(b[1].getOffset()).isEqualTo(128);
+ assertThat(b[1].getLength()).isEqualTo(384);
}
}
@@ -394,7 +390,9 @@ public void testInheritedMethodsImplemented() throws Exception {
}
}
}
- assertTrue((errors + " methods were not overridden correctly - see log"),
- errors <= 0);
+ assertThat(errors)
+ .withFailMessage(errors +
+ " methods were not overridden correctly - see log")
+ .isLessThanOrEqualTo(0);
}
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestLocalFileSystem.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestLocalFileSystem.java
index bffcfa76f207e..517f6ce016544 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestLocalFileSystem.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestLocalFileSystem.java
@@ -44,7 +44,11 @@
import static org.apache.hadoop.test.PlatformAssumptions.assumeNotWindows;
import static org.apache.hadoop.test.PlatformAssumptions.assumeWindows;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.Mockito.*;
import org.junit.After;
@@ -56,6 +60,7 @@
import javax.annotation.Nonnull;
+import static org.assertj.core.api.Assertions.assertThat;
/**
* This class tests the local file system via the FileSystem abstraction.
@@ -692,27 +697,33 @@ public void testFSOutputStreamBuilder() throws Exception {
FSDataOutputStreamBuilder builder =
fileSys.createFile(path);
try (FSDataOutputStream stream = builder.build()) {
- Assert.assertEquals("Should be default block size",
- builder.getBlockSize(), fileSys.getDefaultBlockSize());
- Assert.assertEquals("Should be default replication factor",
- builder.getReplication(), fileSys.getDefaultReplication());
- Assert.assertEquals("Should be default buffer size",
- builder.getBufferSize(),
- fileSys.getConf().getInt(IO_FILE_BUFFER_SIZE_KEY,
+ assertThat(builder.getBlockSize())
+ .withFailMessage("Should be default block size")
+ .isEqualTo(fileSys.getDefaultBlockSize());
+ assertThat(builder.getReplication())
+ .withFailMessage("Should be default replication factor")
+ .isEqualTo(fileSys.getDefaultReplication());
+ assertThat(builder.getBufferSize())
+ .withFailMessage("Should be default buffer size")
+ .isEqualTo(fileSys.getConf().getInt(IO_FILE_BUFFER_SIZE_KEY,
IO_FILE_BUFFER_SIZE_DEFAULT));
- Assert.assertEquals("Should be default permission",
- builder.getPermission(), FsPermission.getFileDefault());
+ assertThat(builder.getPermission())
+ .withFailMessage("Should be default permission")
+ .isEqualTo(FsPermission.getFileDefault());
}
// Test set 0 to replication, block size and buffer size
builder = fileSys.createFile(path);
builder.bufferSize(0).blockSize(0).replication((short) 0);
- Assert.assertEquals("Block size should be 0",
- builder.getBlockSize(), 0);
- Assert.assertEquals("Replication factor should be 0",
- builder.getReplication(), 0);
- Assert.assertEquals("Buffer size should be 0",
- builder.getBufferSize(), 0);
+ assertThat(builder.getBlockSize())
+ .withFailMessage("Block size should be 0")
+ .isZero();
+ assertThat(builder.getReplication())
+ .withFailMessage("Replication factor should be 0")
+ .isZero();
+ assertThat(builder.getBufferSize())
+ .withFailMessage("Buffer size should be 0")
+ .isZero();
}
/**
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestRawLocalFileSystemContract.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestRawLocalFileSystemContract.java
index 2e514c4648ea9..b51419d8c53f9 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestRawLocalFileSystemContract.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestRawLocalFileSystemContract.java
@@ -24,12 +24,14 @@
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.test.GenericTestUtils;
import org.apache.hadoop.test.StatUtils;
+import org.apache.hadoop.util.NativeCodeLoader;
import org.apache.hadoop.util.Shell;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeTrue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -127,6 +129,8 @@ protected boolean filesystemIsCaseSensitive() {
@Test
@SuppressWarnings("deprecation")
public void testPermission() throws Exception {
+ assumeTrue("No native library",
+ NativeCodeLoader.isNativeCodeLoaded());
Path testDir = getTestBaseDir();
String testFilename = "teststat2File";
Path path = new Path(testDir, testFilename);
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestTrash.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestTrash.java
index cf22f3b10b58d..e8e028732b2a8 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestTrash.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestTrash.java
@@ -38,7 +38,10 @@
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.TrashPolicyDefault.Emptier;
@@ -112,7 +115,7 @@ static void checkNotInTrash(FileSystem fs, Path trashRoot, String pathname)
* @throws IOException
*/
public static void trashShell(final FileSystem fs, final Path base)
- throws IOException {
+ throws Exception {
Configuration conf = new Configuration();
conf.set("fs.defaultFS", fs.getUri().toString());
trashShell(conf, base, null, null);
@@ -127,8 +130,7 @@ public static void trashShell(final FileSystem fs, final Path base)
* @throws IOException
*/
public static void trashShell(final Configuration conf, final Path base,
- FileSystem trashRootFs, Path trashRoot)
- throws IOException {
+ FileSystem trashRootFs, Path trashRoot) throws Exception {
FileSystem fs = FileSystem.get(conf);
conf.setLong(FS_TRASH_INTERVAL_KEY, 0); // disabled
@@ -163,13 +165,9 @@ public static void trashShell(final Configuration conf, final Path base,
String[] args = new String[1];
args[0] = "-expunge";
int val = -1;
- try {
- val = shell.run(args);
- } catch (Exception e) {
- System.err.println("Exception raised from Trash.run " +
- e.getLocalizedMessage());
- }
- assertTrue(val == 0);
+ val = shell.run(args);
+
+ assertEquals("Expunge should return zero", 0, val);
}
// Verify that we succeed in removing the file we created.
@@ -179,15 +177,10 @@ public static void trashShell(final Configuration conf, final Path base,
args[0] = "-rm";
args[1] = myFile.toString();
int val = -1;
- try {
- val = shell.run(args);
- } catch (Exception e) {
- System.err.println("Exception raised from Trash.run " +
- e.getLocalizedMessage());
- }
- assertTrue(val == 0);
+ val = shell.run(args);
+
+ assertEquals("Remove should return zero", 0, val);
-
checkTrash(trashRootFs, trashRoot, fs.makeQualified(myFile));
}
@@ -200,13 +193,9 @@ public static void trashShell(final Configuration conf, final Path base,
args[0] = "-rm";
args[1] = new Path(base, "test/mkdirs/myFile").toString();
int val = -1;
- try {
- val = shell.run(args);
- } catch (Exception e) {
- System.err.println("Exception raised from Trash.run " +
- e.getLocalizedMessage());
- }
- assertTrue(val == 0);
+ val = shell.run(args);
+
+ assertEquals("Remove should return zero", 0, val);
}
// Verify that we can recreate the file
@@ -219,13 +208,9 @@ public static void trashShell(final Configuration conf, final Path base,
args[0] = "-rmr";
args[1] = new Path(base, "test/mkdirs").toString();
int val = -1;
- try {
- val = shell.run(args);
- } catch (Exception e) {
- System.err.println("Exception raised from Trash.run " +
- e.getLocalizedMessage());
- }
- assertTrue(val == 0);
+ val = shell.run(args);
+
+ assertEquals("Recursive Remove should return zero", 0, val);
}
// recreate directory
@@ -237,29 +222,22 @@ public static void trashShell(final Configuration conf, final Path base,
args[0] = "-rmr";
args[1] = new Path(base, "test/mkdirs").toString();
int val = -1;
- try {
- val = shell.run(args);
- } catch (Exception e) {
- System.err.println("Exception raised from Trash.run " +
- e.getLocalizedMessage());
- }
- assertTrue(val == 0);
+ val = shell.run(args);
+
+ assertEquals("Recursive Remove should return zero", 0, val);
}
// Check that we can delete a file from the trash
{
- Path toErase = new Path(trashRoot, "toErase");
- int retVal = -1;
- writeFile(trashRootFs, toErase, 10);
- try {
- retVal = shell.run(new String[] {"-rm", toErase.toString()});
- } catch (Exception e) {
- System.err.println("Exception raised from Trash.run " +
- e.getLocalizedMessage());
- }
- assertTrue(retVal == 0);
- checkNotInTrash (trashRootFs, trashRoot, toErase.toString());
- checkNotInTrash (trashRootFs, trashRoot, toErase.toString()+".1");
+ Path toErase = new Path(trashRoot, "toErase");
+ int val = -1;
+ writeFile(trashRootFs, toErase, 10);
+
+ val = shell.run(new String[] {"-rm", toErase.toString()});
+
+ assertEquals("Recursive Remove should return zero", 0, val);
+ checkNotInTrash(trashRootFs, trashRoot, toErase.toString());
+ checkNotInTrash(trashRootFs, trashRoot, toErase.toString()+".1");
}
// simulate Trash removal
@@ -267,17 +245,14 @@ public static void trashShell(final Configuration conf, final Path base,
String[] args = new String[1];
args[0] = "-expunge";
int val = -1;
- try {
- val = shell.run(args);
- } catch (Exception e) {
- System.err.println("Exception raised from Trash.run " +
- e.getLocalizedMessage());
- }
- assertTrue(val == 0);
+ val = shell.run(args);
+
+ assertEquals("Expunge should return zero", 0, val);
}
// verify that after expunging the Trash, it really goes away
- checkNotInTrash(trashRootFs, trashRoot, new Path(base, "test/mkdirs/myFile").toString());
+ checkNotInTrash(trashRootFs, trashRoot, new Path(
+ base, "test/mkdirs/myFile").toString());
// recreate directory and file
mkdir(fs, myPath);
@@ -289,26 +264,18 @@ public static void trashShell(final Configuration conf, final Path base,
args[0] = "-rm";
args[1] = myFile.toString();
int val = -1;
- try {
- val = shell.run(args);
- } catch (Exception e) {
- System.err.println("Exception raised from Trash.run " +
- e.getLocalizedMessage());
- }
- assertTrue(val == 0);
+ val = shell.run(args);
+
+ assertEquals("Remove should return zero", 0, val);
checkTrash(trashRootFs, trashRoot, myFile);
args = new String[2];
args[0] = "-rmr";
args[1] = myPath.toString();
val = -1;
- try {
- val = shell.run(args);
- } catch (Exception e) {
- System.err.println("Exception raised from Trash.run " +
- e.getLocalizedMessage());
- }
- assertTrue(val == 0);
+ val = shell.run(args);
+
+ assertEquals("Recursive Remove should return zero", 0, val);
checkTrash(trashRootFs, trashRoot, myPath);
}
@@ -318,13 +285,9 @@ public static void trashShell(final Configuration conf, final Path base,
args[0] = "-rmr";
args[1] = trashRoot.getParent().getParent().toString();
int val = -1;
- try {
- val = shell.run(args);
- } catch (Exception e) {
- System.err.println("Exception raised from Trash.run " +
- e.getLocalizedMessage());
- }
- assertEquals("exit code", 1, val);
+ val = shell.run(args);
+
+ assertEquals("Recursive Remove should return exit code 1", 1, val);
assertTrue(trashRootFs.exists(trashRoot));
}
@@ -341,23 +304,18 @@ public static void trashShell(final Configuration conf, final Path base,
args[1] = "-skipTrash";
args[2] = myFile.toString();
int val = -1;
- try {
- // Clear out trash
- assertEquals("-expunge failed",
- 0, shell.run(new String [] { "-expunge" } ));
-
- val = shell.run(args);
-
- }catch (Exception e) {
- System.err.println("Exception raised from Trash.run " +
- e.getLocalizedMessage());
- }
+ // Clear out trash
+ assertEquals("-expunge failed",
+ 0, shell.run(new String[] {"-expunge" }));
+
+ val = shell.run(args);
+
assertFalse("Expected TrashRoot (" + trashRoot +
") to exist in file system:"
+ trashRootFs.getUri(),
trashRootFs.exists(trashRoot)); // No new Current should be created
assertFalse(fs.exists(myFile));
- assertTrue(val == 0);
+ assertEquals("Remove with skipTrash should return zero", 0, val);
}
// recreate directory and file
@@ -372,64 +330,52 @@ public static void trashShell(final Configuration conf, final Path base,
args[2] = myPath.toString();
int val = -1;
- try {
- // Clear out trash
- assertEquals(0, shell.run(new String [] { "-expunge" } ));
-
- val = shell.run(args);
+ // Clear out trash
+ assertEquals(0, shell.run(new String[] {"-expunge" }));
- }catch (Exception e) {
- System.err.println("Exception raised from Trash.run " +
- e.getLocalizedMessage());
- }
+ val = shell.run(args);
assertFalse(trashRootFs.exists(trashRoot)); // No new Current should be created
assertFalse(fs.exists(myPath));
assertFalse(fs.exists(myFile));
- assertTrue(val == 0);
+ assertEquals("Remove with skipTrash should return zero", 0, val);
}
// deleting same file multiple times
{
int val = -1;
mkdir(fs, myPath);
-
- try {
- assertEquals(0, shell.run(new String [] { "-expunge" } ));
- } catch (Exception e) {
- System.err.println("Exception raised from fs expunge " +
- e.getLocalizedMessage());
- }
+ assertEquals("Expunge should return zero",
+ 0, shell.run(new String[] {"-expunge" }));
+
// create a file in that directory.
myFile = new Path(base, "test/mkdirs/myFile");
- String [] args = new String[] {"-rm", myFile.toString()};
+ String[] args = new String[] {"-rm", myFile.toString()};
int num_runs = 10;
- for(int i=0;i getFileSystem().concat(target, new Path[]{target})));
}
+ @Test
+ public void testFileSystemDeclaresCapability() throws Throwable {
+ assertHasPathCapabilities(getFileSystem(), target, FS_CONCAT);
+ }
+
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/contract/AbstractContractGetFileStatusTest.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/contract/AbstractContractGetFileStatusTest.java
index eb1fd619ca21e..85bd137813f66 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/contract/AbstractContractGetFileStatusTest.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/contract/AbstractContractGetFileStatusTest.java
@@ -112,9 +112,11 @@ public void testListFilesEmptyDirectoryRecursive() throws IOException {
private void listFilesOnEmptyDir(boolean recursive) throws IOException {
describe("Invoke listFiles(recursive=" + recursive + ")" +
" on empty directories, expect nothing found");
- Path subfolder = createDirWithEmptySubFolder();
FileSystem fs = getFileSystem();
- new TreeScanResults(fs.listFiles(getContract().getTestPath(), recursive))
+ Path path = getContract().getTestPath();
+ fs.delete(path, true);
+ Path subfolder = createDirWithEmptySubFolder();
+ new TreeScanResults(fs.listFiles(path, recursive))
.assertSizeEquals("listFiles(test dir, " + recursive + ")", 0, 0, 0);
describe("Test on empty subdirectory");
new TreeScanResults(fs.listFiles(subfolder, recursive))
@@ -126,9 +128,11 @@ private void listFilesOnEmptyDir(boolean recursive) throws IOException {
public void testListLocatedStatusEmptyDirectory() throws IOException {
describe("Invoke listLocatedStatus() on empty directories;" +
" expect directories to be found");
- Path subfolder = createDirWithEmptySubFolder();
FileSystem fs = getFileSystem();
- new TreeScanResults(fs.listLocatedStatus(getContract().getTestPath()))
+ Path path = getContract().getTestPath();
+ fs.delete(path, true);
+ Path subfolder = createDirWithEmptySubFolder();
+ new TreeScanResults(fs.listLocatedStatus(path))
.assertSizeEquals("listLocatedStatus(test dir)", 0, 1, 0);
describe("Test on empty subdirectory");
new TreeScanResults(fs.listLocatedStatus(subfolder))
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/contract/AbstractContractRenameTest.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/contract/AbstractContractRenameTest.java
index 5b76a753de170..2751294beb92c 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/contract/AbstractContractRenameTest.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/contract/AbstractContractRenameTest.java
@@ -268,7 +268,7 @@ public void testRenamePopulatesFileAncestors() throws IOException {
* @param dst the destination root to move
* @param nestedPath the nested path to move
*/
- private void validateAncestorsMoved(Path src, Path dst, String nestedPath)
+ protected void validateAncestorsMoved(Path src, Path dst, String nestedPath)
throws IOException {
assertIsDirectory(dst);
assertPathDoesNotExist("src path should not exist", path(src + nestedPath));
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/contract/AbstractContractRootDirectoryTest.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/contract/AbstractContractRootDirectoryTest.java
index 5fba4bfc2786b..27c6933ae1885 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/contract/AbstractContractRootDirectoryTest.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/contract/AbstractContractRootDirectoryTest.java
@@ -31,8 +31,10 @@
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.hadoop.fs.FileStatus;
+import org.apache.hadoop.fs.RemoteIterator;
import org.apache.hadoop.test.LambdaTestUtils;
+import static org.apache.commons.lang3.StringUtils.join;
import static org.apache.hadoop.fs.contract.ContractTestUtils.createFile;
import static org.apache.hadoop.fs.contract.ContractTestUtils.dataset;
import static org.apache.hadoop.fs.contract.ContractTestUtils.deleteChildren;
@@ -149,14 +151,18 @@ public void testRmRootRecursive() throws Throwable {
Path root = new Path("/");
assertIsDirectory(root);
Path file = new Path("/testRmRootRecursive");
- ContractTestUtils.touch(getFileSystem(), file);
- boolean deleted = getFileSystem().delete(root, true);
- assertIsDirectory(root);
- LOG.info("rm -rf / result is {}", deleted);
- if (deleted) {
- assertPathDoesNotExist("expected file to be deleted", file);
- } else {
- assertPathExists("expected file to be preserved", file);;
+ try {
+ ContractTestUtils.touch(getFileSystem(), file);
+ boolean deleted = getFileSystem().delete(root, true);
+ assertIsDirectory(root);
+ LOG.info("rm -rf / result is {}", deleted);
+ if (deleted) {
+ assertPathDoesNotExist("expected file to be deleted", file);
+ } else {
+ assertPathExists("expected file to be preserved", file);
+ }
+ } finally{
+ getFileSystem().delete(file, false);
}
}
@@ -183,30 +189,59 @@ public void testListEmptyRootDirectory() throws IOException {
Path root = new Path("/");
FileStatus[] statuses = fs.listStatus(root);
for (FileStatus status : statuses) {
- ContractTestUtils.assertDeleted(fs, status.getPath(), true);
+ ContractTestUtils.assertDeleted(fs, status.getPath(), false, true, false);
}
- assertEquals("listStatus on empty root-directory returned a non-empty list",
- 0, fs.listStatus(root).length);
- assertFalse("listFiles(/, false).hasNext",
- fs.listFiles(root, false).hasNext());
- assertFalse("listFiles(/, true).hasNext",
- fs.listFiles(root, true).hasNext());
- assertFalse("listLocatedStatus(/).hasNext",
- fs.listLocatedStatus(root).hasNext());
+ FileStatus[] rootListStatus = fs.listStatus(root);
+ assertEquals("listStatus on empty root-directory returned found: "
+ + join("\n", rootListStatus),
+ 0, rootListStatus.length);
+ assertNoElements("listFiles(/, false)",
+ fs.listFiles(root, false));
+ assertNoElements("listFiles(/, true)",
+ fs.listFiles(root, true));
+ assertNoElements("listLocatedStatus(/)",
+ fs.listLocatedStatus(root));
assertIsDirectory(root);
}
+ /**
+ * Assert that an iterator has no elements; the raised exception
+ * will include the element list.
+ * @param operation operation for assertion text.
+ * @param iter iterator
+ * @throws IOException failure retrieving the values.
+ */
+ protected void assertNoElements(String operation,
+ RemoteIterator iter) throws IOException {
+ List resultList = toList(iter);
+ if (!resultList.isEmpty()) {
+ fail("Expected no results from " + operation + ", but got "
+ + resultList.size() + " elements:\n"
+ + join(resultList, "\n"));
+ }
+ }
+
@Test
public void testSimpleRootListing() throws IOException {
describe("test the nonrecursive root listing calls");
FileSystem fs = getFileSystem();
Path root = new Path("/");
FileStatus[] statuses = fs.listStatus(root);
+ String listStatusResult = join(statuses, "\n");
List locatedStatusList = toList(
fs.listLocatedStatus(root));
- assertEquals(statuses.length, locatedStatusList.size());
+ String locatedStatusResult = join(locatedStatusList, "\n");
+
+ assertEquals("listStatus(/) vs listLocatedStatus(/) with \n"
+ + "listStatus =" + listStatusResult
+ +" listLocatedStatus = " + locatedStatusResult,
+ statuses.length, locatedStatusList.size());
List fileList = toList(fs.listFiles(root, false));
- assertTrue(fileList.size() <= statuses.length);
+ String listFilesResult = join(fileList, "\n");
+ assertTrue("listStatus(/) vs listFiles(/, false) with \n"
+ + "listStatus = " + listStatusResult
+ + "listFiles = " + listFilesResult,
+ fileList.size() <= statuses.length);
}
@Test
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/contract/ContractTestUtils.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/contract/ContractTestUtils.java
index b4db3a5803ad8..f61634943bb7f 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/contract/ContractTestUtils.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/contract/ContractTestUtils.java
@@ -25,11 +25,12 @@
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.LocatedFileStatus;
import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.PathCapabilities;
import org.apache.hadoop.fs.RemoteIterator;
import org.apache.hadoop.fs.StreamCapabilities;
import org.apache.hadoop.io.IOUtils;
import org.junit.Assert;
-import org.junit.internal.AssumptionViolatedException;
+import org.junit.AssumptionViolatedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -457,8 +458,10 @@ public static void rejectRootOperation(Path path) throws IOException {
public static FileStatus[] deleteChildren(FileSystem fileSystem,
Path path,
boolean recursive) throws IOException {
+ LOG.debug("Deleting children of {} (recursive={})", path, recursive);
FileStatus[] children = listChildren(fileSystem, path);
for (FileStatus entry : children) {
+ LOG.debug("Deleting {}", entry);
fileSystem.delete(entry.getPath(), recursive);
}
return children;
@@ -556,7 +559,8 @@ public static void assertFileHasLength(FileSystem fs, Path path,
*/
public static void assertIsDirectory(FileSystem fs,
Path path) throws IOException {
- FileStatus fileStatus = fs.getFileStatus(path);
+ FileStatus fileStatus = verifyPathExists(fs,
+ "Expected to find a directory", path);
assertIsDirectory(fileStatus);
}
@@ -672,7 +676,8 @@ public static void touch(FileSystem fs,
/**
* Delete a file/dir and assert that delete() returned true
* and that the path no longer exists. This variant rejects
- * all operations on root directories.
+ * all operations on root directories and requires the target path
+ * to exist before the deletion operation.
* @param fs filesystem
* @param file path to delete
* @param recursive flag to enable recursive delete
@@ -686,20 +691,41 @@ public static void assertDeleted(FileSystem fs,
/**
* Delete a file/dir and assert that delete() returned true
- * and that the path no longer exists. This variant rejects
- * all operations on root directories
+ * and that the path no longer exists.
+ * This variant requires the target path
+ * to exist before the deletion operation.
+ * @param fs filesystem
+ * @param file path to delete
+ * @param recursive flag to enable recursive delete
+ * @param allowRootOperations can the root dir be deleted?
+ * @throws IOException IO problems
+ */
+ public static void assertDeleted(FileSystem fs,
+ Path file,
+ boolean recursive,
+ boolean allowRootOperations) throws IOException {
+ assertDeleted(fs, file, true, recursive, allowRootOperations);
+ }
+
+ /**
+ * Delete a file/dir and assert that delete() returned true
+ * and that the path no longer exists.
* @param fs filesystem
* @param file path to delete
+ * @param requirePathToExist check for the path existing first?
* @param recursive flag to enable recursive delete
* @param allowRootOperations can the root dir be deleted?
* @throws IOException IO problems
*/
public static void assertDeleted(FileSystem fs,
Path file,
+ boolean requirePathToExist,
boolean recursive,
boolean allowRootOperations) throws IOException {
rejectRootOperation(file, allowRootOperations);
- assertPathExists(fs, "about to be deleted file", file);
+ if (requirePathToExist) {
+ assertPathExists(fs, "about to be deleted file", file);
+ }
boolean deleted = fs.delete(file, recursive);
String dir = ls(fs, file.getParent());
assertTrue("Delete failed on " + file + ": " + dir, deleted);
@@ -1466,22 +1492,61 @@ public static void assertCapabilities(
assertTrue("Stream should be instanceof StreamCapabilities",
stream instanceof StreamCapabilities);
- if (shouldHaveCapabilities!=null) {
+ StreamCapabilities source = (StreamCapabilities) stream;
+ if (shouldHaveCapabilities != null) {
for (String shouldHaveCapability : shouldHaveCapabilities) {
assertTrue("Should have capability: " + shouldHaveCapability,
- ((StreamCapabilities) stream).hasCapability(shouldHaveCapability));
+ source.hasCapability(shouldHaveCapability));
}
}
- if (shouldNotHaveCapabilities!=null) {
+ if (shouldNotHaveCapabilities != null) {
for (String shouldNotHaveCapability : shouldNotHaveCapabilities) {
assertFalse("Should not have capability: " + shouldNotHaveCapability,
- ((StreamCapabilities) stream)
- .hasCapability(shouldNotHaveCapability));
+ source.hasCapability(shouldNotHaveCapability));
}
}
}
+ /**
+ * Custom assert to test {@link PathCapabilities}.
+ *
+ * @param source source (FS, FC, etc)
+ * @param path path to check
+ * @param capabilities The array of unexpected capabilities
+ */
+ public static void assertHasPathCapabilities(
+ final PathCapabilities source,
+ final Path path,
+ final String...capabilities) throws IOException {
+
+ for (String shouldHaveCapability: capabilities) {
+ assertTrue("Should have capability: " + shouldHaveCapability
+ + " under " + path,
+ source.hasPathCapability(path, shouldHaveCapability));
+ }
+ }
+
+ /**
+ * Custom assert to test that the named {@link PathCapabilities}
+ * are not supported.
+ *
+ * @param source source (FS, FC, etc)
+ * @param path path to check
+ * @param capabilities The array of unexpected capabilities
+ */
+ public static void assertLacksPathCapabilities(
+ final PathCapabilities source,
+ final Path path,
+ final String...capabilities) throws IOException {
+
+ for (String shouldHaveCapability: capabilities) {
+ assertFalse("Path must not support capability: " + shouldHaveCapability
+ + " under " + path,
+ source.hasPathCapability(path, shouldHaveCapability));
+ }
+ }
+
/**
* Function which calls {@code InputStream.read()} and
* downgrades an IOE to a runtime exception.
@@ -1603,6 +1668,22 @@ public String toString() {
getFileCount() == 1 ? "" : "s");
}
+ /**
+ * Dump the files and directories to a multi-line string for error
+ * messages and assertions.
+ * @return a dump of the internal state
+ */
+ private String dump() {
+ StringBuilder sb = new StringBuilder(toString());
+ sb.append("\nFiles:");
+ directories.forEach(p ->
+ sb.append("\n \"").append(p.toString()));
+ sb.append("\nDirectories:");
+ files.forEach(p ->
+ sb.append("\n \"").append(p.toString()));
+ return sb.toString();
+ }
+
/**
* Equality check compares files and directory counts.
* As these are non-final fields, this class cannot be used in
@@ -1643,7 +1724,7 @@ public int hashCode() {
* @param o expected other entries.
*/
public void assertSizeEquals(String text, long f, long d, long o) {
- String self = toString();
+ String self = dump();
Assert.assertEquals(text + ": file count in " + self,
f, getFileCount());
Assert.assertEquals(text + ": directory count in " + self,
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/TestCopy.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/TestCopy.java
index 74fb34d9fddb6..f73e83d858bc7 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/TestCopy.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/TestCopy.java
@@ -18,6 +18,7 @@
package org.apache.hadoop.fs.shell;
+import static org.apache.hadoop.test.GenericTestUtils.assertExceptionContains;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
@@ -77,10 +78,19 @@ public void testCopyStreamTarget() throws Exception {
when(in.read(any(byte[].class), anyInt(), anyInt())).thenReturn(-1);
tryCopyStream(in, true);
+ verify(in).close();
+ verify(out, times(2)).close();
+ // no data was written.
+ verify(out, never()).write(any(byte[].class), anyInt(), anyInt());
verify(mockFs, never()).delete(eq(path), anyBoolean());
verify(mockFs).rename(eq(tmpPath), eq(path));
verify(mockFs, never()).delete(eq(tmpPath), anyBoolean());
verify(mockFs, never()).close();
+ // temp path never had is existence checked. This is critical for S3 as it
+ // avoids the successful path accidentally getting a 404 into the S3 load
+ // balancer cache
+ verify(mockFs, never()).exists(eq(tmpPath));
+ verify(mockFs, never()).exists(eq(path));
}
@Test
@@ -110,6 +120,31 @@ public void testInterruptedCreate() throws Exception {
FSDataInputStream in = mock(FSDataInputStream.class);
tryCopyStream(in, false);
+ verify(mockFs, never()).rename(any(Path.class), any(Path.class));
+ verify(mockFs, never()).delete(eq(tmpPath), anyBoolean());
+ verify(mockFs, never()).delete(eq(path), anyBoolean());
+ verify(mockFs, never()).close();
+ }
+
+ /**
+ * Create a file but fail in the write.
+ * The copy operation should attempt to clean up by
+ * closing the output stream then deleting it.
+ */
+ @Test
+ public void testFailedWrite() throws Exception {
+ FSDataOutputStream out = mock(FSDataOutputStream.class);
+ doThrow(new IOException("mocked"))
+ .when(out).write(any(byte[].class), anyInt(), anyInt());
+ whenFsCreate().thenReturn(out);
+ when(mockFs.getFileStatus(eq(tmpPath))).thenReturn(fileStat);
+ FSInputStream in = mock(FSInputStream.class);
+ doReturn(0)
+ .when(in).read(any(byte[].class), anyInt(), anyInt());
+ Throwable thrown = tryCopyStream(in, false);
+ assertExceptionContains("mocked", thrown);
+ verify(in).close();
+ verify(out, times(2)).close();
verify(mockFs).delete(eq(tmpPath), anyBoolean());
verify(mockFs, never()).rename(any(Path.class), any(Path.class));
verify(mockFs, never()).delete(eq(path), anyBoolean());
@@ -155,14 +190,21 @@ private OngoingStubbing whenFsCreate() throws IOException {
anyBoolean(), anyInt(), anyShort(), anyLong(), any()));
}
- private void tryCopyStream(InputStream in, boolean shouldPass) {
+ private Throwable tryCopyStream(InputStream in, boolean shouldPass) {
try {
cmd.copyStreamToTarget(new FSDataInputStream(in), target);
+ return null;
} catch (InterruptedIOException e) {
- assertFalse("copy failed", shouldPass);
+ if (shouldPass) {
+ throw new AssertionError("copy failed", e);
+ }
+ return e;
} catch (Throwable e) {
- assertFalse(e.getMessage(), shouldPass);
- }
+ if (shouldPass) {
+ throw new AssertionError(e.getMessage(), e);
+ }
+ return e;
+ }
}
static class MockFileSystem extends FilterFileSystem {
@@ -183,4 +225,4 @@ public Configuration getConf() {
return conf;
}
}
-}
\ No newline at end of file
+}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestChRootedFileSystem.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestChRootedFileSystem.java
index 780f40974b0ee..8267b214d53bc 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestChRootedFileSystem.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestChRootedFileSystem.java
@@ -22,6 +22,7 @@
import java.net.URI;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
@@ -32,7 +33,6 @@
import org.apache.hadoop.fs.FsConstants;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.permission.AclEntry;
-import org.apache.hadoop.fs.viewfs.ChRootedFileSystem;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -396,7 +396,7 @@ public void testAclMethodsPathTranslation() throws IOException {
}
@Test
- public void testListLocatedFileStatus() throws IOException {
+ public void testListLocatedFileStatus() throws Exception {
final Path mockMount = new Path("mockfs://foo/user");
final Path mockPath = new Path("/usermock");
final Configuration conf = new Configuration();
@@ -404,17 +404,35 @@ public void testListLocatedFileStatus() throws IOException {
ConfigUtil.addLink(conf, mockPath.toString(), mockMount.toUri());
FileSystem vfs = FileSystem.get(URI.create("viewfs:///"), conf);
vfs.listLocatedStatus(mockPath);
- final FileSystem mockFs = ((MockFileSystem)mockMount.getFileSystem(conf))
- .getRawFileSystem();
+ final FileSystem mockFs =
+ ((MockFileSystem) getChildFileSystem((ViewFileSystem) vfs,
+ new URI("mockfs://foo/"))).getRawFileSystem();
verify(mockFs).listLocatedStatus(new Path(mockMount.toUri().getPath()));
}
+ static FileSystem getChildFileSystem(ViewFileSystem viewFs, URI uri) {
+ for (FileSystem fs : viewFs.getChildFileSystems()) {
+ if (Objects.equals(fs.getUri().getScheme(), uri.getScheme()) && Objects
+ .equals(fs.getUri().getAuthority(), uri.getAuthority())) {
+ return fs;
+ }
+ }
+ return null;
+ }
+
static class MockFileSystem extends FilterFileSystem {
+ private URI uri;
MockFileSystem() {
super(mock(FileSystem.class));
}
@Override
- public void initialize(URI name, Configuration conf) throws IOException {}
+ public URI getUri() {
+ return uri;
+ }
+ @Override
+ public void initialize(URI name, Configuration conf) throws IOException {
+ uri = name;
+ }
}
@Test(timeout = 30000)
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFileSystemDelegation.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFileSystemDelegation.java
index cb1f413bda42a..d8c39f79d0454 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFileSystemDelegation.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFileSystemDelegation.java
@@ -20,6 +20,7 @@
import java.io.IOException;
import java.net.URI;
+import java.net.URISyntaxException;
import java.util.Collections;
import java.util.List;
import org.apache.hadoop.conf.Configuration;
@@ -31,6 +32,8 @@
import org.apache.hadoop.fs.permission.AclEntry;
import org.apache.hadoop.fs.viewfs.TestChRootedFileSystem.MockFileSystem;
import org.junit.*;
+
+import static org.apache.hadoop.fs.viewfs.TestChRootedFileSystem.getChildFileSystem;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
@@ -46,12 +49,16 @@ public class TestViewFileSystemDelegation { //extends ViewFileSystemTestSetup {
@BeforeClass
public static void setup() throws Exception {
conf = ViewFileSystemTestSetup.createConfig();
- fs1 = setupFileSystem(new URI("fs1:/"), FakeFileSystem.class);
- fs2 = setupFileSystem(new URI("fs2:/"), FakeFileSystem.class);
+ setupFileSystem(new URI("fs1:/"), FakeFileSystem.class);
+ setupFileSystem(new URI("fs2:/"), FakeFileSystem.class);
viewFs = FileSystem.get(FsConstants.VIEWFS_URI, conf);
+ fs1 = (FakeFileSystem) getChildFileSystem((ViewFileSystem) viewFs,
+ new URI("fs1:/"));
+ fs2 = (FakeFileSystem) getChildFileSystem((ViewFileSystem) viewFs,
+ new URI("fs2:/"));
}
- static FakeFileSystem setupFileSystem(URI uri, Class clazz)
+ static void setupFileSystem(URI uri, Class clazz)
throws Exception {
String scheme = uri.getScheme();
conf.set("fs."+scheme+".impl", clazz.getName());
@@ -59,22 +66,21 @@ static FakeFileSystem setupFileSystem(URI uri, Class clazz)
assertEquals(uri, fs.getUri());
Path targetPath = new FileSystemTestHelper().getAbsoluteTestRootPath(fs);
ConfigUtil.addLink(conf, "/mounts/"+scheme, targetPath.toUri());
- return fs;
}
- private static FileSystem setupMockFileSystem(Configuration conf, URI uri)
+ private static void setupMockFileSystem(Configuration config, URI uri)
throws Exception {
String scheme = uri.getScheme();
- conf.set("fs." + scheme + ".impl", MockFileSystem.class.getName());
- FileSystem fs = FileSystem.get(uri, conf);
- ConfigUtil.addLink(conf, "/mounts/" + scheme, uri);
- return ((MockFileSystem)fs).getRawFileSystem();
+ config.set("fs." + scheme + ".impl", MockFileSystem.class.getName());
+ ConfigUtil.addLink(config, "/mounts/" + scheme, uri);
}
@Test
- public void testSanity() {
- assertEquals("fs1:/", fs1.getUri().toString());
- assertEquals("fs2:/", fs2.getUri().toString());
+ public void testSanity() throws URISyntaxException {
+ assertEquals(new URI("fs1:/").getScheme(), fs1.getUri().getScheme());
+ assertEquals(new URI("fs1:/").getAuthority(), fs1.getUri().getAuthority());
+ assertEquals(new URI("fs2:/").getScheme(), fs2.getUri().getScheme());
+ assertEquals(new URI("fs2:/").getAuthority(), fs2.getUri().getAuthority());
}
@Test
@@ -91,9 +97,15 @@ public void testVerifyChecksum() throws Exception {
@Test
public void testAclMethods() throws Exception {
Configuration conf = ViewFileSystemTestSetup.createConfig();
- FileSystem mockFs1 = setupMockFileSystem(conf, new URI("mockfs1:/"));
- FileSystem mockFs2 = setupMockFileSystem(conf, new URI("mockfs2:/"));
+ setupMockFileSystem(conf, new URI("mockfs1:/"));
+ setupMockFileSystem(conf, new URI("mockfs2:/"));
FileSystem viewFs = FileSystem.get(FsConstants.VIEWFS_URI, conf);
+ FileSystem mockFs1 =
+ ((MockFileSystem) getChildFileSystem((ViewFileSystem) viewFs,
+ new URI("mockfs1:/"))).getRawFileSystem();
+ FileSystem mockFs2 =
+ ((MockFileSystem) getChildFileSystem((ViewFileSystem) viewFs,
+ new URI("mockfs2:/"))).getRawFileSystem();
Path viewFsPath1 = new Path("/mounts/mockfs1/a/b/c");
Path mockFsPath1 = new Path("/a/b/c");
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFileSystemDelegationTokenSupport.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFileSystemDelegationTokenSupport.java
index 735dfcf3cf627..239f47d1da6f3 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFileSystemDelegationTokenSupport.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFileSystemDelegationTokenSupport.java
@@ -18,6 +18,7 @@
package org.apache.hadoop.fs.viewfs;
import static org.junit.Assert.*;
+import static org.apache.hadoop.fs.viewfs.TestChRootedFileSystem.getChildFileSystem;
import java.io.IOException;
import java.net.URI;
@@ -54,12 +55,16 @@ public class TestViewFileSystemDelegationTokenSupport {
@BeforeClass
public static void setup() throws Exception {
conf = ViewFileSystemTestSetup.createConfig();
- fs1 = setupFileSystem(new URI("fs1:///"), FakeFileSystem.class);
- fs2 = setupFileSystem(new URI("fs2:///"), FakeFileSystem.class);
+ setupFileSystem(new URI("fs1:///"), FakeFileSystem.class);
+ setupFileSystem(new URI("fs2:///"), FakeFileSystem.class);
viewFs = FileSystem.get(FsConstants.VIEWFS_URI, conf);
+ fs1 = (FakeFileSystem) getChildFileSystem((ViewFileSystem) viewFs,
+ new URI("fs1:///"));
+ fs2 = (FakeFileSystem) getChildFileSystem((ViewFileSystem) viewFs,
+ new URI("fs2:///"));
}
- static FakeFileSystem setupFileSystem(URI uri, Class extends FileSystem> clazz)
+ static void setupFileSystem(URI uri, Class extends FileSystem> clazz)
throws Exception {
String scheme = uri.getScheme();
conf.set("fs."+scheme+".impl", clazz.getName());
@@ -67,7 +72,6 @@ static FakeFileSystem setupFileSystem(URI uri, Class extends FileSystem> clazz
// mount each fs twice, will later ensure 1 token/fs
ConfigUtil.addLink(conf, "/mounts/"+scheme+"-one", fs.getUri());
ConfigUtil.addLink(conf, "/mounts/"+scheme+"-two", fs.getUri());
- return fs;
}
/**
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFsTrash.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFsTrash.java
index 62ef9d146384e..94c3262eaae92 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFsTrash.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFsTrash.java
@@ -70,7 +70,7 @@ public void tearDown() throws Exception {
}
@Test
- public void testTrash() throws IOException {
+ public void testTrash() throws Exception {
TestTrash.trashShell(conf, fileSystemTestHelper.getTestRootPath(fsView),
fsTarget, new Path(fsTarget.getHomeDirectory(), ".Trash/Current"));
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFileSystemBaseTest.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFileSystemBaseTest.java
index b9453df5699f2..4902d733e954b 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFileSystemBaseTest.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFileSystemBaseTest.java
@@ -27,6 +27,7 @@
import java.util.ArrayList;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Random;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.BlockLocation;
@@ -36,9 +37,11 @@
import org.apache.hadoop.fs.FileSystemTestHelper;
import org.apache.hadoop.fs.FsConstants;
import org.apache.hadoop.fs.FsStatus;
+import org.apache.hadoop.fs.LocalFileSystem;
import org.apache.hadoop.fs.LocatedFileStatus;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.RemoteIterator;
+import org.apache.hadoop.fs.TestFileUtil;
import org.apache.hadoop.fs.Trash;
import org.apache.hadoop.fs.UnsupportedFileSystemException;
import org.apache.hadoop.fs.contract.ContractTestUtils;
@@ -64,10 +67,11 @@
import org.junit.Before;
import org.junit.Test;
+import static org.apache.hadoop.test.GenericTestUtils.assertExceptionContains;
import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.*;
-
/**
*
* A collection of tests for the {@link ViewFileSystem}.
@@ -473,10 +477,10 @@ void compareBLs(BlockLocation[] viewBL, BlockLocation[] targetBL) {
Assert.assertEquals(targetBL.length, viewBL.length);
int i = 0;
for (BlockLocation vbl : viewBL) {
- Assert.assertEquals(vbl.toString(), targetBL[i].toString());
- Assert.assertEquals(targetBL[i].getOffset(), vbl.getOffset());
- Assert.assertEquals(targetBL[i].getLength(), vbl.getLength());
- i++;
+ assertThat(vbl.toString(), equalTo(targetBL[i].toString()));
+ assertThat(vbl.getOffset(), equalTo(targetBL[i].getOffset()));
+ assertThat(vbl.getLength(), equalTo(targetBL[i].getLength()));
+ i++;
}
}
@@ -1272,4 +1276,96 @@ public void testLinkTarget() throws Exception {
containsString("File does not exist:"));
}
}
+
+ @Test
+ public void testViewFileSystemInnerCache() throws Exception {
+ ViewFileSystem.InnerCache cache = new ViewFileSystem.InnerCache();
+ FileSystem fs = cache.get(fsTarget.getUri(), conf);
+
+ // InnerCache caches filesystem.
+ assertSame(fs, cache.get(fsTarget.getUri(), conf));
+
+ // InnerCache and FileSystem.CACHE are independent.
+ assertNotSame(fs, FileSystem.get(fsTarget.getUri(), conf));
+
+ // close InnerCache.
+ cache.closeAll();
+ try {
+ fs.exists(new Path("/"));
+ if (!(fs instanceof LocalFileSystem)) {
+ // Ignore LocalFileSystem because it can still be used after close.
+ fail("Expect Filesystem closed exception");
+ }
+ } catch (IOException e) {
+ assertExceptionContains("Filesystem closed", e);
+ }
+ }
+
+ @Test
+ public void testCloseChildrenFileSystem() throws Exception {
+ final String clusterName = "cluster" + new Random().nextInt();
+ Configuration config = new Configuration(conf);
+ ConfigUtil.addLink(config, clusterName, "/user",
+ new Path(targetTestRoot, "user").toUri());
+ config.setBoolean("fs.viewfs.impl.disable.cache", false);
+ URI uri = new URI("viewfs://" + clusterName + "/");
+
+ ViewFileSystem viewFs = (ViewFileSystem) FileSystem.get(uri, config);
+ assertTrue("viewfs should have at least one child fs.",
+ viewFs.getChildFileSystems().length > 0);
+ // viewFs is cached in FileSystem.CACHE
+ assertSame(viewFs, FileSystem.get(uri, config));
+
+ // child fs is not cached in FileSystem.CACHE
+ FileSystem child = viewFs.getChildFileSystems()[0];
+ assertNotSame(child, FileSystem.get(child.getUri(), config));
+
+ viewFs.close();
+ for (FileSystem childfs : viewFs.getChildFileSystems()) {
+ try {
+ childfs.exists(new Path("/"));
+ if (!(childfs instanceof LocalFileSystem)) {
+ // Ignore LocalFileSystem because it can still be used after close.
+ fail("Expect Filesystem closed exception");
+ }
+ } catch (IOException e) {
+ assertExceptionContains("Filesystem closed", e);
+ }
+ }
+ }
+
+ @Test
+ public void testChildrenFileSystemLeak() throws Exception {
+ final String clusterName = "cluster" + new Random().nextInt();
+ Configuration config = new Configuration(conf);
+ ConfigUtil.addLink(config, clusterName, "/user",
+ new Path(targetTestRoot, "user").toUri());
+
+ final int cacheSize = TestFileUtil.getCacheSize();
+ ViewFileSystem viewFs = (ViewFileSystem) FileSystem
+ .get(new URI("viewfs://" + clusterName + "/"), config);
+ assertEquals(cacheSize + 1, TestFileUtil.getCacheSize());
+ viewFs.close();
+ assertEquals(cacheSize, TestFileUtil.getCacheSize());
+ }
+
+ @Test
+ public void testDeleteOnExit() throws Exception {
+ final String clusterName = "cluster" + new Random().nextInt();
+ Configuration config = new Configuration(conf);
+ ConfigUtil.addLink(config, clusterName, "/user",
+ new Path(targetTestRoot, "user").toUri());
+
+ Path testDir = new Path("/user/testDeleteOnExit");
+ Path realTestPath = new Path(targetTestRoot, "user/testDeleteOnExit");
+ ViewFileSystem viewFs = (ViewFileSystem) FileSystem
+ .get(new URI("viewfs://" + clusterName + "/"), config);
+ viewFs.mkdirs(testDir);
+ assertTrue(viewFs.exists(testDir));
+ assertTrue(fsTarget.exists(realTestPath));
+
+ viewFs.deleteOnExit(testDir);
+ viewFs.close();
+ assertFalse(fsTarget.exists(realTestPath));
+ }
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFsBaseTest.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFsBaseTest.java
index e080cd6715e0e..d96cdb172b702 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFsBaseTest.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFsBaseTest.java
@@ -17,6 +17,7 @@
*/
package org.apache.hadoop.fs.viewfs;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.apache.hadoop.fs.FileContextTestHelper.checkFileLinkStatus;
import static org.apache.hadoop.fs.FileContextTestHelper.checkFileStatus;
import static org.apache.hadoop.fs.FileContextTestHelper.exists;
@@ -459,9 +460,9 @@ void compareBLs(BlockLocation[] viewBL, BlockLocation[] targetBL) {
Assert.assertEquals(targetBL.length, viewBL.length);
int i = 0;
for (BlockLocation vbl : viewBL) {
- Assert.assertEquals(vbl.toString(), targetBL[i].toString());
- Assert.assertEquals(targetBL[i].getOffset(), vbl.getOffset());
- Assert.assertEquals(targetBL[i].getLength(), vbl.getLength());
+ assertThat(vbl.toString()).isEqualTo(targetBL[i].toString());
+ assertThat(vbl.getOffset()).isEqualTo(targetBL[i].getOffset());
+ assertThat(vbl.getLength()).isEqualTo(targetBL[i].getLength());
i++;
}
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ha/ClientBaseWithFixes.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ha/ClientBaseWithFixes.java
index 7396694ce95f8..be6181157c0dd 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ha/ClientBaseWithFixes.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ha/ClientBaseWithFixes.java
@@ -65,6 +65,15 @@ public abstract class ClientBaseWithFixes extends ZKTestCase {
public static int CONNECTION_TIMEOUT = 30000;
static final File BASETEST = GenericTestUtils.getTestDir();
+ static {
+ // The 4-letter-words commands are simple diagnostics telnet commands in
+ // ZooKeeper. Since ZooKeeper 3.5, these are disabled by default due to
+ // security concerns: https://issues.apache.org/jira/browse/ZOOKEEPER-2693
+ // We are enabling them for the tests here, as some tests in hadoop or in
+ // other projects might still use them
+ System.setProperty("zookeeper.4lw.commands.whitelist", "*");
+ }
+
protected final String hostPort = initHostPort();
protected int maxCnxns = 0;
protected ServerCnxnFactory serverFactory = null;
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ha/DummyHAService.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ha/DummyHAService.java
index 51112bedefa87..064527c3fed6d 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ha/DummyHAService.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ha/DummyHAService.java
@@ -39,6 +39,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static org.apache.hadoop.fs.CommonConfigurationKeys.HA_HM_RPC_CONNECT_MAX_RETRIES_DEFAULT;
import static org.apache.hadoop.fs.CommonConfigurationKeys.HA_HM_RPC_TIMEOUT_DEFAULT;
/**
@@ -63,6 +64,7 @@ class DummyHAService extends HAServiceTarget {
public int fenceCount = 0;
public int activeTransitionCount = 0;
boolean testWithProtoBufRPC = false;
+ int rpcTimeout;
static ArrayList instances = Lists.newArrayList();
int index;
@@ -82,7 +84,8 @@ class DummyHAService extends HAServiceTarget {
}
Configuration conf = new Configuration();
this.proxy = makeMock(conf, HA_HM_RPC_TIMEOUT_DEFAULT);
- this.healthMonitorProxy = makeHealthMonitorMock(conf, HA_HM_RPC_TIMEOUT_DEFAULT);
+ this.healthMonitorProxy = makeHealthMonitorMock(conf,
+ HA_HM_RPC_TIMEOUT_DEFAULT, HA_HM_RPC_CONNECT_MAX_RETRIES_DEFAULT);
try {
conf.set(DUMMY_FENCE_KEY, DummyFencer.class.getName());
this.fencer = Mockito.spy(
@@ -149,13 +152,13 @@ private HAServiceProtocol makeMock(Configuration conf, int timeoutMs) {
}
private HAServiceProtocol makeHealthMonitorMock(Configuration conf,
- int timeoutMs) {
+ int timeoutMs, int retries) {
HAServiceProtocol service;
if (!testWithProtoBufRPC) {
service = new MockHAProtocolImpl();
} else {
try {
- service = super.getHealthMonitorProxy(conf, timeoutMs);
+ service = super.getHealthMonitorProxy(conf, timeoutMs, retries);
} catch (IOException e) {
return null;
}
@@ -189,9 +192,9 @@ public HAServiceProtocol getProxy(Configuration conf, int timeout)
@Override
public HAServiceProtocol getHealthMonitorProxy(Configuration conf,
- int timeout) throws IOException {
+ int timeout, int retries) throws IOException {
if (testWithProtoBufRPC) {
- proxy = makeHealthMonitorMock(conf, timeout);
+ proxy = makeHealthMonitorMock(conf, timeout, retries);
}
return proxy;
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestGlobalFilter.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestGlobalFilter.java
index 70361752633c3..ade383883f10e 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestGlobalFilter.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestGlobalFilter.java
@@ -142,6 +142,8 @@ public void testServletFilter() throws Exception {
for(int i = 0; i < urls.length; i++) {
assertTrue(RECORDS.remove(urls[i]));
}
- assertTrue(RECORDS.isEmpty());
+ assertTrue(RECORDS.size()==1);
+ // Accesing "/" will redirect to /index.html
+ assertTrue(RECORDS.contains("/index.html"));
}
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpRequestLog.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpRequestLog.java
index 212807f78ef65..d0123e32039c9 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpRequestLog.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpRequestLog.java
@@ -18,7 +18,7 @@
package org.apache.hadoop.http;
import org.apache.log4j.Logger;
-import org.eclipse.jetty.server.NCSARequestLog;
+import org.eclipse.jetty.server.CustomRequestLog;
import org.eclipse.jetty.server.RequestLog;
import org.junit.Test;
@@ -42,6 +42,7 @@ public void testAppenderDefined() {
RequestLog requestLog = HttpRequestLog.getRequestLog("test");
Logger.getLogger("http.requests.test").removeAppender(requestLogAppender);
assertNotNull("RequestLog should not be null", requestLog);
- assertEquals("Class mismatch", NCSARequestLog.class, requestLog.getClass());
+ assertEquals("Class mismatch",
+ CustomRequestLog.class, requestLog.getClass());
}
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServerWithSpnego.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServerWithSpnego.java
new file mode 100644
index 0000000000000..ea7c8cd4e6864
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServerWithSpnego.java
@@ -0,0 +1,238 @@
+/**
+ * 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
+ *
+ * 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.http;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.CommonConfigurationKeys;
+import org.apache.hadoop.minikdc.MiniKdc;
+import org.apache.hadoop.net.NetUtils;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.security.authentication.KerberosTestUtils;
+import org.apache.hadoop.security.authentication.client.AuthenticatedURL;
+import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
+import org.apache.hadoop.security.authentication.server.AuthenticationToken;
+import org.apache.hadoop.security.authentication.server.ProxyUserAuthenticationFilterInitializer;
+import org.apache.hadoop.security.authentication.util.Signer;
+import org.apache.hadoop.security.authentication.util.SignerSecretProvider;
+import org.apache.hadoop.security.authentication.util.StringSignerSecretProviderCreator;
+import org.apache.hadoop.security.authorize.AccessControlList;
+import org.apache.hadoop.security.authorize.ProxyUsers;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.Assert;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.Writer;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URL;
+import java.util.Properties;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * This class is tested for http server with SPNEGO authentication.
+ */
+public class TestHttpServerWithSpnego {
+
+ static final Log LOG = LogFactory.getLog(TestHttpServerWithSpnego.class);
+
+ private static final String SECRET_STR = "secret";
+ private static final String HTTP_USER = "HTTP";
+ private static final String PREFIX = "hadoop.http.authentication.";
+ private static final long TIMEOUT = 20000;
+
+ private static File httpSpnegoKeytabFile = new File(
+ KerberosTestUtils.getKeytabFile());
+ private static String httpSpnegoPrincipal =
+ KerberosTestUtils.getServerPrincipal();
+ private static String realm = KerberosTestUtils.getRealm();
+
+ private static File testRootDir = new File("target",
+ TestHttpServerWithSpnego.class.getName() + "-root");
+ private static MiniKdc testMiniKDC;
+ private static File secretFile = new File(testRootDir, SECRET_STR);
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ try {
+ testMiniKDC = new MiniKdc(MiniKdc.createConf(), testRootDir);
+ testMiniKDC.start();
+ testMiniKDC.createPrincipal(
+ httpSpnegoKeytabFile, HTTP_USER + "/localhost");
+ } catch (Exception e) {
+ assertTrue("Couldn't setup MiniKDC", false);
+ }
+ Writer w = new FileWriter(secretFile);
+ w.write("secret");
+ w.close();
+ }
+
+ @AfterClass
+ public static void tearDown() {
+ if (testMiniKDC != null) {
+ testMiniKDC.stop();
+ }
+ }
+
+ /**
+ * groupA
+ * - userA
+ * groupB
+ * - userA, userB
+ * groupC
+ * - userC
+ * SPNEGO filter has been enabled.
+ * userA has the privilege to impersonate users in groupB.
+ * userA has admin access to all default servlets, but userB
+ * and userC don't have. So "/logs" can only be accessed by userA.
+ * @throws Exception
+ */
+ @Test
+ public void testAuthenticationWithProxyUser() throws Exception {
+ Configuration spengoConf = getSpengoConf(new Configuration());
+
+ //setup logs dir
+ System.setProperty("hadoop.log.dir", testRootDir.getAbsolutePath());
+
+ // Setup user group
+ UserGroupInformation.createUserForTesting("userA",
+ new String[]{"groupA", "groupB"});
+ UserGroupInformation.createUserForTesting("userB",
+ new String[]{"groupB"});
+ UserGroupInformation.createUserForTesting("userC",
+ new String[]{"groupC"});
+
+ // Make userA impersonate users in groupB
+ spengoConf.set("hadoop.proxyuser.userA.hosts", "*");
+ spengoConf.set("hadoop.proxyuser.userA.groups", "groupB");
+ ProxyUsers.refreshSuperUserGroupsConfiguration(spengoConf);
+
+ HttpServer2 httpServer = null;
+ try {
+ // Create http server to test.
+ httpServer = getCommonBuilder()
+ .setConf(spengoConf)
+ .setACL(new AccessControlList("userA groupA"))
+ .build();
+ httpServer.start();
+
+ // Get signer to encrypt token
+ Signer signer = getSignerToEncrypt();
+
+ // setup auth token for userA
+ AuthenticatedURL.Token token = getEncryptedAuthToken(signer, "userA");
+
+ String serverURL = "http://" +
+ NetUtils.getHostPortString(httpServer.getConnectorAddress(0)) + "/";
+
+ // The default authenticator is kerberos.
+ AuthenticatedURL authUrl = new AuthenticatedURL();
+
+ // userA impersonates userB, it's allowed.
+ for (String servlet :
+ new String[]{"stacks", "jmx", "conf"}) {
+ HttpURLConnection conn = authUrl
+ .openConnection(new URL(serverURL + servlet + "?doAs=userB"),
+ token);
+ Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());
+ }
+
+ // userA cannot impersonate userC, it fails.
+ for (String servlet :
+ new String[]{"stacks", "jmx", "conf"}){
+ HttpURLConnection conn = authUrl
+ .openConnection(new URL(serverURL + servlet + "?doAs=userC"),
+ token);
+ Assert.assertEquals(HttpURLConnection.HTTP_FORBIDDEN,
+ conn.getResponseCode());
+ }
+
+
+ // "/logs" and "/logLevel" require admin authorization,
+ // only userA has the access.
+ for (String servlet :
+ new String[]{"logLevel", "logs"}) {
+ HttpURLConnection conn = authUrl
+ .openConnection(new URL(serverURL + servlet), token);
+ Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());
+ }
+
+ // Setup token for userB
+ token = getEncryptedAuthToken(signer, "userB");
+
+ // userB cannot access these servlets.
+ for (String servlet :
+ new String[]{"logLevel", "logs"}) {
+ HttpURLConnection conn = authUrl
+ .openConnection(new URL(serverURL + servlet), token);
+ Assert.assertEquals(HttpURLConnection.HTTP_FORBIDDEN,
+ conn.getResponseCode());
+ }
+
+ } finally {
+ if (httpServer != null) {
+ httpServer.stop();
+ }
+ }
+ }
+
+ private AuthenticatedURL.Token getEncryptedAuthToken(Signer signer,
+ String user) throws Exception {
+ AuthenticationToken token =
+ new AuthenticationToken(user, user, "kerberos");
+ token.setExpires(System.currentTimeMillis() + TIMEOUT);
+ return new AuthenticatedURL.Token(signer.sign(token.toString()));
+ }
+
+ private Signer getSignerToEncrypt() throws Exception {
+ SignerSecretProvider secretProvider =
+ StringSignerSecretProviderCreator.newStringSignerSecretProvider();
+ Properties secretProviderProps = new Properties();
+ secretProviderProps.setProperty(
+ AuthenticationFilter.SIGNATURE_SECRET, SECRET_STR);
+ secretProvider.init(secretProviderProps, null, TIMEOUT);
+ return new Signer(secretProvider);
+ }
+
+ private Configuration getSpengoConf(Configuration conf) {
+ conf = new Configuration();
+ conf.set(HttpServer2.FILTER_INITIALIZER_PROPERTY,
+ ProxyUserAuthenticationFilterInitializer.class.getName());
+ conf.set(PREFIX + "type", "kerberos");
+ conf.setBoolean(PREFIX + "simple.anonymous.allowed", false);
+ conf.set(PREFIX + "signature.secret.file",
+ secretFile.getAbsolutePath());
+ conf.set(PREFIX + "kerberos.keytab",
+ httpSpnegoKeytabFile.getAbsolutePath());
+ conf.set(PREFIX + "kerberos.principal", httpSpnegoPrincipal);
+ conf.set(PREFIX + "cookie.domain", realm);
+ conf.setBoolean(CommonConfigurationKeys.HADOOP_SECURITY_AUTHORIZATION,
+ true);
+ return conf;
+ }
+
+ private HttpServer2.Builder getCommonBuilder() throws Exception {
+ return new HttpServer2.Builder().setName("test")
+ .addEndpoint(new URI("http://localhost:0"))
+ .setFindPort(true);
+ }
+}
\ No newline at end of file
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestPathFilter.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestPathFilter.java
index 4c35b391c39d6..d54503a0086e9 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestPathFilter.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestPathFilter.java
@@ -35,7 +35,6 @@
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.net.NetUtils;
-import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -102,7 +101,6 @@ static void access(String urlstring) throws IOException {
}
}
- @Test
public void testPathSpecFilters() throws Exception {
Configuration conf = new Configuration();
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestSSLHttpServer.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestSSLHttpServer.java
index 3f6ee7b79f40b..5f7a264190953 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestSSLHttpServer.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestSSLHttpServer.java
@@ -98,6 +98,8 @@ public class TestSSLHttpServer extends HttpServerFunctionalTest {
+ "TLS_DHE_RSA_WITH_AES_128_CBC_SHA,\t\n "
+ "TLS_DHE_DSS_WITH_AES_128_CBC_SHA";
+ private static final String INCLUDED_PROTOCOLS = "SSLv2Hello,TLSv1.1";
+
@BeforeClass
public static void setup() throws Exception {
turnOnSSLDebugLogging();
@@ -128,6 +130,8 @@ public static void setup() throws Exception {
private static void setupServer(Configuration conf, Configuration sslConf)
throws IOException, URISyntaxException {
+ conf.set(SSLFactory.SSL_ENABLED_PROTOCOLS_KEY, INCLUDED_PROTOCOLS);
+ sslConf.set(SSLFactory.SSL_ENABLED_PROTOCOLS_KEY, INCLUDED_PROTOCOLS);
server = new HttpServer2.Builder().setName("test")
.addEndpoint(new URI("https://localhost")).setConf(conf)
.keyPassword(
@@ -214,6 +218,22 @@ private HttpsURLConnection getConnectionWithSSLSocketFactory(URL url,
return conn;
}
+ private HttpsURLConnection
+ getConnectionWithPreferredProtocolSSLSocketFactory(URL url,
+ String protocols) throws IOException, GeneralSecurityException {
+ HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
+ SSLSocketFactory sslSocketFactory = clientSslFactory
+ .createSSLSocketFactory();
+ LOG.info("Creating " +
+ PreferredProtocolSSLSocketFactory.class.getCanonicalName() +
+ " with protocols: " + protocols);
+ PreferredProtocolSSLSocketFactory cipherSSLSocketFactory
+ = new PreferredProtocolSSLSocketFactory(sslSocketFactory,
+ StringUtils.getTrimmedStrings(protocols));
+ conn.setSSLSocketFactory(cipherSSLSocketFactory);
+ return conn;
+ }
+
@Test
public void testEcho() throws Exception {
assertEquals("a:b\nc:d\n",
@@ -269,6 +289,18 @@ public void testExcludedCiphers() throws Exception {
}
}
+ @Test
+ public void testIncludedProtocols() throws Exception {
+ URL url = new URL(baseUrl, SERVLET_PATH_ECHO + "?a=b&c=d");
+ HttpsURLConnection conn =
+ getConnectionWithPreferredProtocolSSLSocketFactory(url,
+ INCLUDED_PROTOCOLS);
+ assertFalse("included protocol list is empty",
+ INCLUDED_PROTOCOLS.isEmpty());
+
+ readFromConnection(conn);
+ }
+
/** Test that verified that additionally included cipher
* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA is only available cipher for working
* TLS connection from client to server disabled for all other common ciphers.
@@ -370,4 +402,78 @@ private void setEnabledCipherSuites(SSLSocket sslSocket) {
}
}
}
+
+ private class PreferredProtocolSSLSocketFactory extends SSLSocketFactory {
+ private final SSLSocketFactory delegateSocketFactory;
+ private final String[] enabledProtocols;
+
+ PreferredProtocolSSLSocketFactory(SSLSocketFactory sslSocketFactory,
+ String[] enabledProtocols) {
+ delegateSocketFactory = sslSocketFactory;
+ if (null != enabledProtocols && enabledProtocols.length > 0) {
+ this.enabledProtocols = enabledProtocols;
+ } else {
+ this.enabledProtocols = null;
+ }
+ }
+
+ @Override
+ public String[] getDefaultCipherSuites() {
+ return delegateSocketFactory.getDefaultCipherSuites();
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites() {
+ return delegateSocketFactory.getSupportedCipherSuites();
+ }
+
+ @Override
+ public Socket createSocket(Socket socket, String string, int i, boolean bln)
+ throws IOException {
+ SSLSocket sslSocket = (SSLSocket) delegateSocketFactory.createSocket(
+ socket, string, i, bln);
+ setEnabledProtocols(sslSocket);
+ return sslSocket;
+ }
+
+ @Override
+ public Socket createSocket(String string, int i) throws IOException {
+ SSLSocket sslSocket = (SSLSocket) delegateSocketFactory.createSocket(
+ string, i);
+ setEnabledProtocols(sslSocket);
+ return sslSocket;
+ }
+
+ @Override
+ public Socket createSocket(String string, int i, InetAddress ia, int i1)
+ throws IOException {
+ SSLSocket sslSocket = (SSLSocket) delegateSocketFactory.createSocket(
+ string, i, ia, i1);
+ setEnabledProtocols(sslSocket);
+ return sslSocket;
+ }
+
+ @Override
+ public Socket createSocket(InetAddress ia, int i) throws IOException {
+ SSLSocket sslSocket = (SSLSocket) delegateSocketFactory.createSocket(ia,
+ i);
+ setEnabledProtocols(sslSocket);
+ return sslSocket;
+ }
+
+ @Override
+ public Socket createSocket(InetAddress ia, int i, InetAddress ia1, int i1)
+ throws IOException {
+ SSLSocket sslSocket = (SSLSocket) delegateSocketFactory.createSocket(ia,
+ i, ia1, i1);
+ setEnabledProtocols(sslSocket);
+ return sslSocket;
+ }
+
+ private void setEnabledProtocols(SSLSocket sslSocket) {
+ if (null != enabledProtocols) {
+ sslSocket.setEnabledProtocols(enabledProtocols);
+ }
+ }
+ }
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestServletFilter.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestServletFilter.java
index eafd0ae9ccae3..a8ecbd4fe28ef 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestServletFilter.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestServletFilter.java
@@ -100,7 +100,6 @@ static void access(String urlstring) throws IOException {
}
}
- @Test
public void testServletFilter() throws Exception {
Configuration conf = new Configuration();
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/TestArrayFile.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/TestArrayFile.java
index 722e9de595823..2f69093d2654e 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/TestArrayFile.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/TestArrayFile.java
@@ -30,9 +30,9 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;
@@ -146,15 +146,16 @@ public void testArrayFileIteration() {
for (int i = 0; i < SIZE; i++) {
nextWritable = (LongWritable)reader.next(nextWritable);
- assertEquals(nextWritable.get(), i);
+ assertThat(nextWritable.get()).isEqualTo(i);
}
assertTrue("testArrayFileIteration seek error !!!",
reader.seek(new LongWritable(6)));
nextWritable = (LongWritable) reader.next(nextWritable);
- assertTrue("testArrayFileIteration error !!!", reader.key() == 7);
- assertTrue("testArrayFileIteration error !!!",
- nextWritable.equals(new LongWritable(7)));
+ assertThat(reader.key()).withFailMessage(
+ "testArrayFileIteration error !!!").isEqualTo(7);
+ assertThat(nextWritable).withFailMessage(
+ "testArrayFileIteration error !!!").isEqualTo(new LongWritable(7));
assertFalse("testArrayFileIteration error !!!",
reader.seek(new LongWritable(SIZE + 5)));
reader.close();
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/TestSequenceFileSync.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/TestSequenceFileSync.java
index 363177b46464b..5fbb083189e8a 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/TestSequenceFileSync.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/TestSequenceFileSync.java
@@ -18,8 +18,6 @@
package org.apache.hadoop.io;
-import static org.junit.Assert.assertEquals;
-
import java.io.IOException;
import java.util.Random;
@@ -31,6 +29,8 @@
import org.apache.hadoop.test.GenericTestUtils;
import org.junit.Test;
+import static org.assertj.core.api.Assertions.assertThat;
+
/** Tests sync based seek reads/write intervals inside SequenceFiles. */
public class TestSequenceFileSync {
private static final int NUMRECORDS = 2000;
@@ -46,12 +46,10 @@ private static void forOffset(SequenceFile.Reader reader,
val.clear();
reader.sync(off);
reader.next(key, val);
- assertEquals(key.get(), expectedRecord);
+ assertThat(key.get()).isEqualTo(expectedRecord);
final String test = String.format(REC_FMT, expectedRecord, expectedRecord);
- assertEquals(
- "Invalid value in iter " + iter + ": " + val,
- 0,
- val.find(test, 0));
+ assertThat(val.find(test, 0)).withFailMessage(
+ "Invalid value in iter " + iter + ": " + val).isZero();
}
@Test
@@ -124,7 +122,7 @@ public void testLowSyncpoint() throws IOException {
SequenceFile.Writer.syncInterval(20*100)
);
// Ensure the custom sync interval value is set
- assertEquals(writer.syncInterval, 20*100);
+ assertThat(writer.syncInterval).isEqualTo(20*100);
try {
writeSequenceFile(writer, NUMRECORDS);
for (int i = 0; i < 5; i++) {
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/TestText.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/TestText.java
index 9771fd1a96623..59856a4de11f9 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/TestText.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/TestText.java
@@ -26,6 +26,8 @@
import com.google.common.base.Charsets;
import com.google.common.primitives.Bytes;
import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -232,10 +234,10 @@ public void testCompare() throws Exception {
@Test
public void testFind() throws Exception {
Text text = new Text("abcd\u20acbdcd\u20ac");
- assertTrue(text.find("abd")==-1);
- assertTrue(text.find("ac") ==-1);
- assertTrue(text.find("\u20ac") == 4);
- assertTrue(text.find("\u20ac", 5)==11);
+ assertThat(text.find("abd")).isEqualTo(-1);
+ assertThat(text.find("ac")).isEqualTo(-1);
+ assertThat(text.find("\u20ac")).isEqualTo(4);
+ assertThat(text.find("\u20ac", 5)).isEqualTo(11);
}
@Test
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/file/tfile/TestTFileUnsortedByteArrays.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/file/tfile/TestTFileUnsortedByteArrays.java
index f243b2a94065a..f849d538d6d61 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/file/tfile/TestTFileUnsortedByteArrays.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/file/tfile/TestTFileUnsortedByteArrays.java
@@ -20,7 +20,6 @@
import java.io.IOException;
import org.junit.After;
-import org.junit.Assert;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
@@ -33,6 +32,9 @@
import org.junit.Before;
import org.junit.Test;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
+
public class TestTFileUnsortedByteArrays {
private static String ROOT = GenericTestUtils.getTestDir().getAbsolutePath();
@@ -84,152 +86,119 @@ public void tearDown() throws IOException {
// we still can scan records in an unsorted TFile
@Test
public void testFailureScannerWithKeys() throws IOException {
- Reader reader =
- new Reader(fs.open(path), fs.getFileStatus(path).getLen(), conf);
- Assert.assertFalse(reader.isSorted());
- Assert.assertEquals((int) reader.getEntryCount(), 4);
-
- try {
- Scanner scanner =
- reader.createScannerByKey("aaa".getBytes(), "zzz".getBytes());
- Assert
- .fail("Failed to catch creating scanner with keys on unsorted file.");
- }
- catch (RuntimeException e) {
- }
- finally {
- reader.close();
+ try (Reader reader =
+ new Reader(fs.open(path), fs.getFileStatus(path).getLen(), conf)) {
+ assertThat(reader.isSorted()).isFalse();
+ assertThat(reader.getEntryCount()).isEqualTo(4);
+ try {
+ reader.createScannerByKey("aaa".getBytes(), "zzz".getBytes());
+ fail("Failed to catch creating scanner with keys on unsorted file.");
+ } catch (RuntimeException expected) {
+ }
}
}
// we still can scan records in an unsorted TFile
@Test
public void testScan() throws IOException {
- Reader reader =
- new Reader(fs.open(path), fs.getFileStatus(path).getLen(), conf);
- Assert.assertFalse(reader.isSorted());
- Assert.assertEquals((int) reader.getEntryCount(), 4);
-
- Scanner scanner = reader.createScanner();
-
- try {
-
- // read key and value
- byte[] kbuf = new byte[BUF_SIZE];
- int klen = scanner.entry().getKeyLength();
- scanner.entry().getKey(kbuf);
- Assert.assertEquals(new String(kbuf, 0, klen), "keyZ");
-
- byte[] vbuf = new byte[BUF_SIZE];
- int vlen = scanner.entry().getValueLength();
- scanner.entry().getValue(vbuf);
- Assert.assertEquals(new String(vbuf, 0, vlen), "valueZ");
-
- scanner.advance();
-
- // now try get value first
- vbuf = new byte[BUF_SIZE];
- vlen = scanner.entry().getValueLength();
- scanner.entry().getValue(vbuf);
- Assert.assertEquals(new String(vbuf, 0, vlen), "valueM");
-
- kbuf = new byte[BUF_SIZE];
- klen = scanner.entry().getKeyLength();
- scanner.entry().getKey(kbuf);
- Assert.assertEquals(new String(kbuf, 0, klen), "keyM");
- }
- finally {
- scanner.close();
- reader.close();
+ try (Reader reader =
+ new Reader(fs.open(path), fs.getFileStatus(path).getLen(), conf)) {
+ assertThat(reader.isSorted()).isFalse();
+ assertThat(reader.getEntryCount()).isEqualTo(4);
+ try (Scanner scanner = reader.createScanner()) {
+ // read key and value
+ byte[] kbuf = new byte[BUF_SIZE];
+ int klen = scanner.entry().getKeyLength();
+ scanner.entry().getKey(kbuf);
+ assertThat(new String(kbuf, 0, klen)).isEqualTo("keyZ");
+
+ byte[] vbuf = new byte[BUF_SIZE];
+ int vlen = scanner.entry().getValueLength();
+ scanner.entry().getValue(vbuf);
+ assertThat(new String(vbuf, 0, vlen)).isEqualTo("valueZ");
+
+ scanner.advance();
+
+ // now try get value first
+ vbuf = new byte[BUF_SIZE];
+ vlen = scanner.entry().getValueLength();
+ scanner.entry().getValue(vbuf);
+ assertThat(new String(vbuf, 0, vlen)).isEqualTo("valueM");
+
+ kbuf = new byte[BUF_SIZE];
+ klen = scanner.entry().getKeyLength();
+ scanner.entry().getKey(kbuf);
+ assertThat(new String(kbuf, 0, klen)).isEqualTo("keyM");
+ }
}
}
// we still can scan records in an unsorted TFile
@Test
public void testScanRange() throws IOException {
- Reader reader =
- new Reader(fs.open(path), fs.getFileStatus(path).getLen(), conf);
- Assert.assertFalse(reader.isSorted());
- Assert.assertEquals((int) reader.getEntryCount(), 4);
-
- Scanner scanner = reader.createScanner();
-
- try {
-
- // read key and value
- byte[] kbuf = new byte[BUF_SIZE];
- int klen = scanner.entry().getKeyLength();
- scanner.entry().getKey(kbuf);
- Assert.assertEquals(new String(kbuf, 0, klen), "keyZ");
-
- byte[] vbuf = new byte[BUF_SIZE];
- int vlen = scanner.entry().getValueLength();
- scanner.entry().getValue(vbuf);
- Assert.assertEquals(new String(vbuf, 0, vlen), "valueZ");
-
- scanner.advance();
-
- // now try get value first
- vbuf = new byte[BUF_SIZE];
- vlen = scanner.entry().getValueLength();
- scanner.entry().getValue(vbuf);
- Assert.assertEquals(new String(vbuf, 0, vlen), "valueM");
-
- kbuf = new byte[BUF_SIZE];
- klen = scanner.entry().getKeyLength();
- scanner.entry().getKey(kbuf);
- Assert.assertEquals(new String(kbuf, 0, klen), "keyM");
- }
- finally {
- scanner.close();
- reader.close();
+ try (Reader reader =
+ new Reader(fs.open(path), fs.getFileStatus(path).getLen(), conf)) {
+ assertThat(reader.isSorted()).isFalse();
+ assertThat(reader.getEntryCount()).isEqualTo(4);
+
+ try (Scanner scanner = reader.createScanner()) {
+
+ // read key and value
+ byte[] kbuf = new byte[BUF_SIZE];
+ int klen = scanner.entry().getKeyLength();
+ scanner.entry().getKey(kbuf);
+ assertThat(new String(kbuf, 0, klen)).isEqualTo("keyZ");
+
+ byte[] vbuf = new byte[BUF_SIZE];
+ int vlen = scanner.entry().getValueLength();
+ scanner.entry().getValue(vbuf);
+ assertThat(new String(vbuf, 0, vlen)).isEqualTo("valueZ");
+
+ scanner.advance();
+
+ // now try get value first
+ vbuf = new byte[BUF_SIZE];
+ vlen = scanner.entry().getValueLength();
+ scanner.entry().getValue(vbuf);
+ assertThat(new String(vbuf, 0, vlen)).isEqualTo("valueM");
+
+ kbuf = new byte[BUF_SIZE];
+ klen = scanner.entry().getKeyLength();
+ scanner.entry().getKey(kbuf);
+ assertThat(new String(kbuf, 0, klen)).isEqualTo("keyM");
+ }
}
}
@Test
public void testFailureSeek() throws IOException {
- Reader reader =
- new Reader(fs.open(path), fs.getFileStatus(path).getLen(), conf);
- Scanner scanner = reader.createScanner();
-
- try {
+ try (Reader reader = new Reader(fs.open(path),
+ fs.getFileStatus(path).getLen(), conf);
+ Scanner scanner = reader.createScanner()) {
// can't find ceil
try {
scanner.lowerBound("keyN".getBytes());
- Assert.fail("Cannot search in a unsorted TFile!");
- }
- catch (Exception e) {
- // noop, expecting excetions
+ fail("Cannot search in a unsorted TFile!");
}
- finally {
+ catch (Exception expected) {
}
// can't find higher
try {
scanner.upperBound("keyA".getBytes());
- Assert.fail("Cannot search higher in a unsorted TFile!");
+ fail("Cannot search higher in a unsorted TFile!");
}
- catch (Exception e) {
- // noop, expecting excetions
- }
- finally {
+ catch (Exception expected) {
}
// can't seek
try {
scanner.seekTo("keyM".getBytes());
- Assert.fail("Cannot search a unsorted TFile!");
- }
- catch (Exception e) {
- // noop, expecting excetions
+ fail("Cannot search a unsorted TFile!");
}
- finally {
+ catch (Exception expected) {
}
}
- finally {
- scanner.close();
- reader.close();
- }
}
private void closeOutput() throws IOException {
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/file/tfile/TestVLong.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/file/tfile/TestVLong.java
index 69e6eb8741270..b7550f9d584d2 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/file/tfile/TestVLong.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/file/tfile/TestVLong.java
@@ -33,6 +33,8 @@
import org.junit.Before;
import org.junit.Test;
+import static org.assertj.core.api.Assertions.assertThat;
+
public class TestVLong {
private static String ROOT = GenericTestUtils.getTestDir().getAbsolutePath();
private Configuration conf;
@@ -70,8 +72,7 @@ public void testVLongByte() throws IOException {
FSDataInputStream in = fs.open(path);
for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; ++i) {
- long n = Utils.readVLong(in);
- Assert.assertEquals(n, i);
+ assertThat(Utils.readVLong(in)).isEqualTo(i);
}
in.close();
fs.delete(path, false);
@@ -85,8 +86,7 @@ private long writeAndVerify(int shift) throws IOException {
out.close();
FSDataInputStream in = fs.open(path);
for (int i = Short.MIN_VALUE; i <= Short.MAX_VALUE; ++i) {
- long n = Utils.readVLong(in);
- Assert.assertEquals(n, ((long) i) << shift);
+ assertThat(Utils.readVLong(in)).isEqualTo(((long) i) << shift);
}
in.close();
long ret = fs.getFileStatus(path).getLen();
@@ -165,7 +165,7 @@ public void testVLongRandom() throws IOException {
FSDataInputStream in = fs.open(path);
for (int i = 0; i < data.length; ++i) {
- Assert.assertEquals(Utils.readVLong(in), data[i]);
+ assertThat(Utils.readVLong(in)).isEqualTo(data[i]);
}
in.close();
fs.delete(path, false);
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/nativeio/TestNativeIO.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/nativeio/TestNativeIO.java
index 6b3c2325d8ff6..a14928c7b4e24 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/nativeio/TestNativeIO.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/nativeio/TestNativeIO.java
@@ -25,6 +25,8 @@
import java.io.FileWriter;
import java.io.IOException;
import java.io.RandomAccessFile;
+import java.nio.file.Files;
+import java.nio.file.Paths;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
@@ -782,4 +784,155 @@ public void testNativeFadviseConsts() {
assertTrue("Native POSIX_FADV_NOREUSE const not set",
POSIX_FADV_NOREUSE >= 0);
}
+
+
+ @Test (timeout=10000)
+ public void testPmemCheckParameters() {
+ assumeNotWindows("Native PMDK not supported on Windows");
+ // Skip testing while the build or environment does not support PMDK
+ assumeTrue(NativeIO.POSIX.isPmdkAvailable());
+
+ // Please make sure /mnt/pmem0 is a persistent memory device with total
+ // volume size 'volumeSize'
+ String filePath = "/$:";
+ long length = 0;
+ long volumnSize = 16 * 1024 * 1024 * 1024L;
+
+ // Incorrect file length
+ try {
+ NativeIO.POSIX.Pmem.mapBlock(filePath, length);
+ fail("Illegal length parameter should be detected");
+ } catch (Exception e) {
+ LOG.info(e.getMessage());
+ }
+
+ // Incorrect file length
+ filePath = "/mnt/pmem0/test_native_io";
+ length = -1L;
+ try {
+ NativeIO.POSIX.Pmem.mapBlock(filePath, length);
+ fail("Illegal length parameter should be detected");
+ }catch (Exception e) {
+ LOG.info(e.getMessage());
+ }
+ }
+
+ @Test (timeout=10000)
+ public void testPmemMapMultipleFiles() {
+ assumeNotWindows("Native PMDK not supported on Windows");
+ // Skip testing while the build or environment does not support PMDK
+ assumeTrue(NativeIO.POSIX.isPmdkAvailable());
+
+ // Please make sure /mnt/pmem0 is a persistent memory device with total
+ // volume size 'volumeSize'
+ String filePath = "/mnt/pmem0/test_native_io";
+ long length = 0;
+ long volumnSize = 16 * 1024 * 1024 * 1024L;
+
+ // Multiple files, each with 128MB size, aggregated size exceeds volume
+ // limit 16GB
+ length = 128 * 1024 * 1024L;
+ long fileNumber = volumnSize / length;
+ LOG.info("File number = " + fileNumber);
+ for (int i = 0; i < fileNumber; i++) {
+ String path = filePath + i;
+ LOG.info("File path = " + path);
+ NativeIO.POSIX.Pmem.mapBlock(path, length);
+ }
+ try {
+ NativeIO.POSIX.Pmem.mapBlock(filePath, length);
+ fail("Request map extra file when persistent memory is all occupied");
+ } catch (Exception e) {
+ LOG.info(e.getMessage());
+ }
+ }
+
+ @Test (timeout=10000)
+ public void testPmemMapBigFile() {
+ assumeNotWindows("Native PMDK not supported on Windows");
+ // Skip testing while the build or environment does not support PMDK
+ assumeTrue(NativeIO.POSIX.isPmdkAvailable());
+
+ // Please make sure /mnt/pmem0 is a persistent memory device with total
+ // volume size 'volumeSize'
+ String filePath = "/mnt/pmem0/test_native_io_big";
+ long length = 0;
+ long volumeSize = 16 * 1024 * 1024 * 1024L;
+
+ // One file length exceeds persistent memory volume 16GB.
+ length = volumeSize + 1024L;
+ try {
+ LOG.info("File length = " + length);
+ NativeIO.POSIX.Pmem.mapBlock(filePath, length);
+ fail("File length exceeds persistent memory total volume size");
+ }catch (Exception e) {
+ LOG.info(e.getMessage());
+ deletePmemMappedFile(filePath);
+ }
+ }
+
+ @Test (timeout=10000)
+ public void testPmemCopy() throws IOException {
+ assumeNotWindows("Native PMDK not supported on Windows");
+ // Skip testing while the build or environment does not support PMDK
+ assumeTrue(NativeIO.POSIX.isPmdkAvailable());
+
+ // Create and map a block file. Please make sure /mnt/pmem0 is a persistent
+ // memory device.
+ String filePath = "/mnt/pmem0/copy";
+ long length = 4096;
+ PmemMappedRegion region = NativeIO.POSIX.Pmem.mapBlock(filePath, length);
+ assertTrue(NativeIO.POSIX.Pmem.isPmem(region.getAddress(), length));
+ assertFalse(NativeIO.POSIX.Pmem.isPmem(region.getAddress(), length + 100));
+ assertFalse(NativeIO.POSIX.Pmem.isPmem(region.getAddress() + 100, length));
+ assertFalse(NativeIO.POSIX.Pmem.isPmem(region.getAddress() - 100, length));
+
+ // Copy content to mapped file
+ byte[] data = generateSequentialBytes(0, (int) length);
+ NativeIO.POSIX.Pmem.memCopy(data, region.getAddress(), region.isPmem(),
+ length);
+
+ // Read content before pmemSync
+ byte[] readBuf1 = new byte[(int)length];
+ IOUtils.readFully(new FileInputStream(filePath), readBuf1, 0, (int)length);
+ assertArrayEquals(data, readBuf1);
+
+ byte[] readBuf2 = new byte[(int)length];
+ // Sync content to persistent memory twice
+ NativeIO.POSIX.Pmem.memSync(region);
+ NativeIO.POSIX.Pmem.memSync(region);
+ // Read content after pmemSync twice
+ IOUtils.readFully(new FileInputStream(filePath), readBuf2, 0, (int)length);
+ assertArrayEquals(data, readBuf2);
+
+ //Read content after unmap twice
+ NativeIO.POSIX.Pmem.unmapBlock(region.getAddress(), length);
+ NativeIO.POSIX.Pmem.unmapBlock(region.getAddress(), length);
+ byte[] readBuf3 = new byte[(int)length];
+ IOUtils.readFully(new FileInputStream(filePath), readBuf3, 0, (int)length);
+ assertArrayEquals(data, readBuf3);
+ }
+
+ private static byte[] generateSequentialBytes(int start, int length) {
+ byte[] result = new byte[length];
+
+ for (int i = 0; i < length; i++) {
+ result[i] = (byte) ((start + i) % 127);
+ }
+ return result;
+ }
+
+ private static void deletePmemMappedFile(String filePath) {
+ try {
+ if (filePath != null) {
+ boolean result = Files.deleteIfExists(Paths.get(filePath));
+ if (!result) {
+ throw new IOException();
+ }
+ }
+ } catch (Throwable e) {
+ LOG.error("Failed to delete the mapped file " + filePath +
+ " from persistent memory", e);
+ }
+ }
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/retry/TestRetryProxy.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/retry/TestRetryProxy.java
index 241e21046d9d4..3b42bb46e828c 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/retry/TestRetryProxy.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/retry/TestRetryProxy.java
@@ -25,6 +25,7 @@
import org.apache.hadoop.io.retry.UnreliableInterface.UnreliableException;
import org.apache.hadoop.ipc.ProtocolTranslator;
import org.apache.hadoop.ipc.RemoteException;
+import org.apache.hadoop.security.AccessControlException;
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
@@ -48,6 +49,14 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.*;
+/**
+ * TestRetryProxy tests the behaviour of the {@link RetryPolicy} class using
+ * a certain method of {@link UnreliableInterface} implemented by
+ * {@link UnreliableImplementation}.
+ *
+ * Some methods may be sensitive to the {@link Idempotent} annotation
+ * (annotated in {@link UnreliableInterface}).
+ */
public class TestRetryProxy {
private UnreliableImplementation unreliableImpl;
@@ -348,4 +357,24 @@ public void testNoRetryOnSaslError() throws Exception {
assertEquals(RetryDecision.FAIL, caughtRetryAction.action);
}
}
+
+ @Test
+ public void testNoRetryOnAccessControlException() throws Exception {
+ RetryPolicy policy = mock(RetryPolicy.class);
+ RetryPolicy realPolicy = RetryPolicies.failoverOnNetworkException(5);
+ setupMockPolicy(policy, realPolicy);
+
+ UnreliableInterface unreliable = (UnreliableInterface) RetryProxy.create(
+ UnreliableInterface.class, unreliableImpl, policy);
+
+ try {
+ unreliable.failsWithAccessControlExceptionEightTimes();
+ fail("Should fail");
+ } catch (AccessControlException e) {
+ // expected
+ verify(policy, times(1)).shouldRetry(any(Exception.class), anyInt(),
+ anyInt(), anyBoolean());
+ assertEquals(RetryDecision.FAIL, caughtRetryAction.action);
+ }
+ }
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/retry/UnreliableImplementation.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/retry/UnreliableImplementation.java
index 465dc6f94e499..a20d898988400 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/retry/UnreliableImplementation.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/retry/UnreliableImplementation.java
@@ -23,7 +23,14 @@
import org.apache.hadoop.ipc.RemoteException;
import org.apache.hadoop.ipc.StandbyException;
+import org.apache.hadoop.security.AccessControlException;
+/**
+ * For the usage and purpose of this class see {@link UnreliableInterface}
+ * which this class implements.
+ *
+ * @see UnreliableInterface
+ */
class UnreliableImplementation implements UnreliableInterface {
private int failsOnceInvocationCount,
@@ -32,6 +39,7 @@ class UnreliableImplementation implements UnreliableInterface {
failsOnceRemoteExceptionInvocationCount,
failsTenTimesInvocationCount,
failsWithSASLExceptionTenTimesInvocationCount,
+ failsWithAccessControlExceptionInvocationCount,
succeedsOnceThenFailsCount,
succeedsOnceThenFailsIdempotentCount,
succeedsTenTimesThenFailsCount;
@@ -123,6 +131,14 @@ public void failsWithSASLExceptionTenTimes() throws SaslException {
}
}
+ @Override
+ public void failsWithAccessControlExceptionEightTimes()
+ throws AccessControlException {
+ if (failsWithAccessControlExceptionInvocationCount++ < 8) {
+ throw new AccessControlException();
+ }
+ }
+
@Override
public String succeedsOnceThenFailsReturningString()
throws UnreliableException, IOException, StandbyException {
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/retry/UnreliableInterface.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/retry/UnreliableInterface.java
index d334542ee69c5..738a76086bae2 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/retry/UnreliableInterface.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/retry/UnreliableInterface.java
@@ -24,7 +24,20 @@
import org.apache.hadoop.ipc.RemoteException;
import org.apache.hadoop.ipc.StandbyException;
+import org.apache.hadoop.security.AccessControlException;
+/**
+ * The methods of UnreliableInterface could throw exceptions in a
+ * predefined way. It is currently used for testing {@link RetryPolicy}
+ * and {@link FailoverProxyProvider} classes, but can be potentially used
+ * to test any class's behaviour where an underlying interface or class
+ * may throw exceptions.
+ *
+ * Some methods may be annotated with the {@link Idempotent} annotation.
+ * In order to test those some methods of UnreliableInterface are annotated,
+ * but they are not actually Idempotent functions.
+ *
+ */
public interface UnreliableInterface {
public static class UnreliableException extends Exception {
@@ -66,6 +79,10 @@ public static class FatalException extends UnreliableException {
void failsWithSASLExceptionTenTimes() throws SaslException;
+ @Idempotent
+ void failsWithAccessControlExceptionEightTimes()
+ throws AccessControlException;
+
public String succeedsOnceThenFailsReturningString()
throws UnreliableException, StandbyException, IOException;
@Idempotent
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestCallQueueManager.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestCallQueueManager.java
index 2b739966d8406..bb4717ed36d35 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestCallQueueManager.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestCallQueueManager.java
@@ -384,9 +384,22 @@ public void testCallQueueOverflowExceptions() throws Exception {
RpcScheduler scheduler = Mockito.mock(RpcScheduler.class);
BlockingQueue queue = Mockito.mock(BlockingQueue.class);
CallQueueManager cqm =
- Mockito.spy(new CallQueueManager<>(queue, scheduler, false));
+ Mockito.spy(new CallQueueManager<>(queue, scheduler, false, false));
+ CallQueueManager cqmTriggerFailover =
+ Mockito.spy(new CallQueueManager<>(queue, scheduler, false, true));
Schedulable call = new FakeCall(0);
+ // call queue exceptions that trigger failover
+ cqmTriggerFailover.setClientBackoffEnabled(true);
+ doReturn(Boolean.TRUE).when(cqmTriggerFailover).shouldBackOff(call);
+ try {
+ cqmTriggerFailover.put(call);
+ fail("didn't fail");
+ } catch (Exception ex) {
+ assertEquals(CallQueueOverflowException.FAILOVER.getCause().getMessage(),
+ ex.getCause().getMessage());
+ }
+
// call queue exceptions passed threw as-is
doThrow(CallQueueOverflowException.KEEPALIVE).when(queue).add(call);
try {
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestDecayRpcScheduler.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestDecayRpcScheduler.java
index 10ab40ace1f67..7bdc6b5e96d0c 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestDecayRpcScheduler.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestDecayRpcScheduler.java
@@ -26,6 +26,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import org.apache.hadoop.fs.CommonConfigurationKeys;
import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.conf.Configuration;
@@ -36,6 +37,7 @@
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.management.ManagementFactory;
+import java.util.concurrent.TimeUnit;
public class TestDecayRpcScheduler {
private Schedulable mockCall(String id) {
@@ -131,67 +133,69 @@ public void testAccumulate() {
conf.set("ns." + DecayRpcScheduler.IPC_FCQ_DECAYSCHEDULER_PERIOD_KEY, "99999999"); // Never flush
scheduler = new DecayRpcScheduler(1, "ns", conf);
- assertEquals(0, scheduler.getCallCountSnapshot().size()); // empty first
+ assertEquals(0, scheduler.getCallCostSnapshot().size()); // empty first
- scheduler.getPriorityLevel(mockCall("A"));
- assertEquals(1, scheduler.getCallCountSnapshot().get("A").longValue());
- assertEquals(1, scheduler.getCallCountSnapshot().get("A").longValue());
+ getPriorityIncrementCallCount("A");
+ assertEquals(1, scheduler.getCallCostSnapshot().get("A").longValue());
+ assertEquals(1, scheduler.getCallCostSnapshot().get("A").longValue());
- scheduler.getPriorityLevel(mockCall("A"));
- scheduler.getPriorityLevel(mockCall("B"));
- scheduler.getPriorityLevel(mockCall("A"));
+ getPriorityIncrementCallCount("A");
+ getPriorityIncrementCallCount("B");
+ getPriorityIncrementCallCount("A");
- assertEquals(3, scheduler.getCallCountSnapshot().get("A").longValue());
- assertEquals(1, scheduler.getCallCountSnapshot().get("B").longValue());
+ assertEquals(3, scheduler.getCallCostSnapshot().get("A").longValue());
+ assertEquals(1, scheduler.getCallCostSnapshot().get("B").longValue());
}
@Test
@SuppressWarnings("deprecation")
public void testDecay() throws Exception {
Configuration conf = new Configuration();
- conf.set("ns." + DecayRpcScheduler.IPC_FCQ_DECAYSCHEDULER_PERIOD_KEY, "999999999"); // Never
- conf.set("ns." + DecayRpcScheduler.IPC_FCQ_DECAYSCHEDULER_FACTOR_KEY, "0.5");
+ conf.setLong("ns." // Never decay
+ + DecayRpcScheduler.IPC_SCHEDULER_DECAYSCHEDULER_PERIOD_KEY, 999999999);
+ conf.setDouble("ns."
+ + DecayRpcScheduler.IPC_SCHEDULER_DECAYSCHEDULER_FACTOR_KEY, 0.5);
scheduler = new DecayRpcScheduler(1, "ns", conf);
assertEquals(0, scheduler.getTotalCallSnapshot());
for (int i = 0; i < 4; i++) {
- scheduler.getPriorityLevel(mockCall("A"));
+ getPriorityIncrementCallCount("A");
}
sleep(1000);
for (int i = 0; i < 8; i++) {
- scheduler.getPriorityLevel(mockCall("B"));
+ getPriorityIncrementCallCount("B");
}
assertEquals(12, scheduler.getTotalCallSnapshot());
- assertEquals(4, scheduler.getCallCountSnapshot().get("A").longValue());
- assertEquals(8, scheduler.getCallCountSnapshot().get("B").longValue());
+ assertEquals(4, scheduler.getCallCostSnapshot().get("A").longValue());
+ assertEquals(8, scheduler.getCallCostSnapshot().get("B").longValue());
scheduler.forceDecay();
assertEquals(6, scheduler.getTotalCallSnapshot());
- assertEquals(2, scheduler.getCallCountSnapshot().get("A").longValue());
- assertEquals(4, scheduler.getCallCountSnapshot().get("B").longValue());
+ assertEquals(2, scheduler.getCallCostSnapshot().get("A").longValue());
+ assertEquals(4, scheduler.getCallCostSnapshot().get("B").longValue());
scheduler.forceDecay();
assertEquals(3, scheduler.getTotalCallSnapshot());
- assertEquals(1, scheduler.getCallCountSnapshot().get("A").longValue());
- assertEquals(2, scheduler.getCallCountSnapshot().get("B").longValue());
+ assertEquals(1, scheduler.getCallCostSnapshot().get("A").longValue());
+ assertEquals(2, scheduler.getCallCostSnapshot().get("B").longValue());
scheduler.forceDecay();
assertEquals(1, scheduler.getTotalCallSnapshot());
- assertEquals(null, scheduler.getCallCountSnapshot().get("A"));
- assertEquals(1, scheduler.getCallCountSnapshot().get("B").longValue());
+ assertEquals(null, scheduler.getCallCostSnapshot().get("A"));
+ assertEquals(1, scheduler.getCallCostSnapshot().get("B").longValue());
scheduler.forceDecay();
assertEquals(0, scheduler.getTotalCallSnapshot());
- assertEquals(null, scheduler.getCallCountSnapshot().get("A"));
- assertEquals(null, scheduler.getCallCountSnapshot().get("B"));
+ assertEquals(null, scheduler.getCallCostSnapshot().get("A"));
+ assertEquals(null, scheduler.getCallCostSnapshot().get("B"));
}
@Test
@@ -205,16 +209,16 @@ public void testPriority() throws Exception {
.IPC_FCQ_DECAYSCHEDULER_THRESHOLDS_KEY, "25, 50, 75");
scheduler = new DecayRpcScheduler(4, namespace, conf);
- assertEquals(0, scheduler.getPriorityLevel(mockCall("A")));
- assertEquals(2, scheduler.getPriorityLevel(mockCall("A")));
- assertEquals(0, scheduler.getPriorityLevel(mockCall("B")));
- assertEquals(1, scheduler.getPriorityLevel(mockCall("B")));
- assertEquals(0, scheduler.getPriorityLevel(mockCall("C")));
- assertEquals(0, scheduler.getPriorityLevel(mockCall("C")));
- assertEquals(1, scheduler.getPriorityLevel(mockCall("A")));
- assertEquals(1, scheduler.getPriorityLevel(mockCall("A")));
- assertEquals(1, scheduler.getPriorityLevel(mockCall("A")));
- assertEquals(2, scheduler.getPriorityLevel(mockCall("A")));
+ assertEquals(0, getPriorityIncrementCallCount("A")); // 0 out of 0 calls
+ assertEquals(3, getPriorityIncrementCallCount("A")); // 1 out of 1 calls
+ assertEquals(0, getPriorityIncrementCallCount("B")); // 0 out of 2 calls
+ assertEquals(1, getPriorityIncrementCallCount("B")); // 1 out of 3 calls
+ assertEquals(0, getPriorityIncrementCallCount("C")); // 0 out of 4 calls
+ assertEquals(0, getPriorityIncrementCallCount("C")); // 1 out of 5 calls
+ assertEquals(1, getPriorityIncrementCallCount("A")); // 2 out of 6 calls
+ assertEquals(1, getPriorityIncrementCallCount("A")); // 3 out of 7 calls
+ assertEquals(2, getPriorityIncrementCallCount("A")); // 4 out of 8 calls
+ assertEquals(2, getPriorityIncrementCallCount("A")); // 5 out of 9 calls
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName mxbeanName = new ObjectName(
@@ -243,7 +247,7 @@ public void testPeriodic() throws InterruptedException {
assertEquals(0, scheduler.getTotalCallSnapshot());
for (int i = 0; i < 64; i++) {
- scheduler.getPriorityLevel(mockCall("A"));
+ getPriorityIncrementCallCount("A");
}
// It should eventually decay to zero
@@ -272,6 +276,108 @@ public void testNPEatInitialization() throws InterruptedException {
//set systout back
System.setOut(output);
}
+ }
+
+ @Test
+ public void testUsingWeightedTimeCostProvider() {
+ scheduler = getSchedulerWithWeightedTimeCostProvider(3);
+
+ // 3 details in increasing order of cost. Although medium has a longer
+ // duration, the shared lock is weighted less than the exclusive lock
+ ProcessingDetails callDetailsLow =
+ new ProcessingDetails(TimeUnit.MILLISECONDS);
+ callDetailsLow.set(ProcessingDetails.Timing.LOCKFREE, 1);
+ ProcessingDetails callDetailsMedium =
+ new ProcessingDetails(TimeUnit.MILLISECONDS);
+ callDetailsMedium.set(ProcessingDetails.Timing.LOCKSHARED, 500);
+ ProcessingDetails callDetailsHigh =
+ new ProcessingDetails(TimeUnit.MILLISECONDS);
+ callDetailsHigh.set(ProcessingDetails.Timing.LOCKEXCLUSIVE, 100);
+
+ for (int i = 0; i < 10; i++) {
+ scheduler.addResponseTime("ignored", mockCall("LOW"), callDetailsLow);
+ }
+ scheduler.addResponseTime("ignored", mockCall("MED"), callDetailsMedium);
+ scheduler.addResponseTime("ignored", mockCall("HIGH"), callDetailsHigh);
+
+ assertEquals(0, scheduler.getPriorityLevel(mockCall("LOW")));
+ assertEquals(1, scheduler.getPriorityLevel(mockCall("MED")));
+ assertEquals(2, scheduler.getPriorityLevel(mockCall("HIGH")));
+
+ assertEquals(3, scheduler.getUniqueIdentityCount());
+ long totalCallInitial = scheduler.getTotalRawCallVolume();
+ assertEquals(totalCallInitial, scheduler.getTotalCallVolume());
+
+ scheduler.forceDecay();
+
+ // Relative priorities should stay the same after a single decay
+ assertEquals(0, scheduler.getPriorityLevel(mockCall("LOW")));
+ assertEquals(1, scheduler.getPriorityLevel(mockCall("MED")));
+ assertEquals(2, scheduler.getPriorityLevel(mockCall("HIGH")));
+
+ assertEquals(3, scheduler.getUniqueIdentityCount());
+ assertEquals(totalCallInitial, scheduler.getTotalRawCallVolume());
+ assertTrue(scheduler.getTotalCallVolume() < totalCallInitial);
+
+ for (int i = 0; i < 100; i++) {
+ scheduler.forceDecay();
+ }
+ // After enough decay cycles, all callers should be high priority again
+ assertEquals(0, scheduler.getPriorityLevel(mockCall("LOW")));
+ assertEquals(0, scheduler.getPriorityLevel(mockCall("MED")));
+ assertEquals(0, scheduler.getPriorityLevel(mockCall("HIGH")));
+ }
+
+ @Test
+ public void testUsingWeightedTimeCostProviderWithZeroCostCalls() {
+ scheduler = getSchedulerWithWeightedTimeCostProvider(2);
+
+ ProcessingDetails emptyDetails =
+ new ProcessingDetails(TimeUnit.MILLISECONDS);
+
+ for (int i = 0; i < 1000; i++) {
+ scheduler.addResponseTime("ignored", mockCall("MANY"), emptyDetails);
+ }
+ scheduler.addResponseTime("ignored", mockCall("FEW"), emptyDetails);
+
+ // Since the calls are all "free", they should have the same priority
+ assertEquals(0, scheduler.getPriorityLevel(mockCall("MANY")));
+ assertEquals(0, scheduler.getPriorityLevel(mockCall("FEW")));
+ }
+
+ @Test
+ public void testUsingWeightedTimeCostProviderNoRequests() {
+ scheduler = getSchedulerWithWeightedTimeCostProvider(2);
+
+ assertEquals(0, scheduler.getPriorityLevel(mockCall("A")));
+ }
+
+ /**
+ * Get a scheduler that uses {@link WeightedTimeCostProvider} and has
+ * normal decaying disabled.
+ */
+ private static DecayRpcScheduler getSchedulerWithWeightedTimeCostProvider(
+ int priorityLevels) {
+ Configuration conf = new Configuration();
+ conf.setClass("ns." + CommonConfigurationKeys.IPC_COST_PROVIDER_KEY,
+ WeightedTimeCostProvider.class, CostProvider.class);
+ conf.setLong("ns."
+ + DecayRpcScheduler.IPC_SCHEDULER_DECAYSCHEDULER_PERIOD_KEY, 999999);
+ return new DecayRpcScheduler(priorityLevels, "ns", conf);
+ }
+ /**
+ * Get the priority and increment the call count, assuming that
+ * {@link DefaultCostProvider} is in use.
+ */
+ private int getPriorityIncrementCallCount(String callId) {
+ Schedulable mockCall = mockCall(callId);
+ int priority = scheduler.getPriorityLevel(mockCall);
+ // The DefaultCostProvider uses a cost of 1 for all calls, ignoring
+ // the processing details, so an empty one is fine
+ ProcessingDetails emptyProcessingDetails =
+ new ProcessingDetails(TimeUnit.MILLISECONDS);
+ scheduler.addResponseTime("ignored", mockCall, emptyProcessingDetails);
+ return priority;
}
}
\ No newline at end of file
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestFairCallQueue.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestFairCallQueue.java
index 21e2018854cde..e6a5f5e564c1f 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestFairCallQueue.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestFairCallQueue.java
@@ -28,9 +28,16 @@
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.times;
+import org.apache.hadoop.fs.CommonConfigurationKeys;
import org.junit.Before;
import org.junit.Test;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
import javax.management.MBeanServer;
import javax.management.ObjectName;
@@ -49,6 +56,8 @@
import org.apache.hadoop.ipc.CallQueueManager.CallQueueOverflowException;
import org.apache.hadoop.ipc.protobuf.RpcHeaderProtos.RpcResponseHeaderProto.RpcStatusProto;
+import static org.assertj.core.api.Assertions.assertThat;
+
public class TestFairCallQueue {
private FairCallQueue fcq;
@@ -84,17 +93,17 @@ public void testTotalCapacityOfSubQueues() {
Configuration conf = new Configuration();
FairCallQueue fairCallQueue;
fairCallQueue = new FairCallQueue(1, 1000, "ns", conf);
- assertEquals(fairCallQueue.remainingCapacity(), 1000);
+ assertThat(fairCallQueue.remainingCapacity()).isEqualTo(1000);
fairCallQueue = new FairCallQueue(4, 1000, "ns", conf);
- assertEquals(fairCallQueue.remainingCapacity(), 1000);
+ assertThat(fairCallQueue.remainingCapacity()).isEqualTo(1000);
fairCallQueue = new FairCallQueue(7, 1000, "ns", conf);
- assertEquals(fairCallQueue.remainingCapacity(), 1000);
+ assertThat(fairCallQueue.remainingCapacity()).isEqualTo(1000);
fairCallQueue = new FairCallQueue(1, 1025, "ns", conf);
- assertEquals(fairCallQueue.remainingCapacity(), 1025);
+ assertThat(fairCallQueue.remainingCapacity()).isEqualTo(1025);
fairCallQueue = new FairCallQueue(4, 1025, "ns", conf);
- assertEquals(fairCallQueue.remainingCapacity(), 1025);
+ assertThat(fairCallQueue.remainingCapacity()).isEqualTo(1025);
fairCallQueue = new FairCallQueue(7, 1025, "ns", conf);
- assertEquals(fairCallQueue.remainingCapacity(), 1025);
+ assertThat(fairCallQueue.remainingCapacity()).isEqualTo(1025);
}
@Test
@@ -148,6 +157,65 @@ public int getAndAdvanceCurrentIndex() {
assertNull(fcq.poll());
}
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testInsertionWithFailover() {
+ Configuration conf = new Configuration();
+ // Config for server to throw StandbyException instead of the
+ // regular RetriableException if call queue is full.
+ conf.setBoolean(
+ "ns." + CommonConfigurationKeys.IPC_CALLQUEUE_SERVER_FAILOVER_ENABLE,
+ true);
+ // 3 queues, 2 slots each.
+ fcq = Mockito.spy(new FairCallQueue<>(3, 6, "ns", conf));
+
+ Schedulable p0 = mockCall("a", 0);
+ Schedulable p1 = mockCall("b", 1);
+
+ // add to first queue.
+ addToQueueAndVerify(p0, 1, 0, 0);
+ // 0:x- 1:-- 2:--
+
+ // add to second queue.
+ addToQueueAndVerify(p1, 0, 1, 0);
+ // 0:x- 1:x- 2:--
+
+ // add to first queue.
+ addToQueueAndVerify(p0, 1, 0, 0);
+ // 0:xx 1:x- 2:--
+
+ // add to first full queue spills over to second.
+ addToQueueAndVerify(p0, 1, 1, 0);
+ // 0:xx 1:xx 2:--
+
+ // add to second full queue spills over to third.
+ addToQueueAndVerify(p1, 0, 1, 1);
+ // 0:xx 1:xx 2:x-
+
+ // add to first and second full queue spills over to third.
+ addToQueueAndVerify(p0, 1, 1, 1);
+ // 0:xx 1:xx 2:xx
+
+ // adding non-lowest priority with all queues full throws a
+ // standby exception for client to try another server.
+ Mockito.reset(fcq);
+ try {
+ fcq.add(p0);
+ fail("didn't fail");
+ } catch (IllegalStateException ise) {
+ checkOverflowException(ise, RpcStatusProto.FATAL, true);
+ }
+ }
+
+ private void addToQueueAndVerify(Schedulable call, int expectedQueue0,
+ int expectedQueue1, int expectedQueue2) {
+ Mockito.reset(fcq);
+ fcq.add(call);
+ Mockito.verify(fcq, times(expectedQueue0)).offerQueue(0, call);
+ Mockito.verify(fcq, times(expectedQueue1)).offerQueue(1, call);
+ Mockito.verify(fcq, times(expectedQueue2)).offerQueue(2, call);
+ }
+
@SuppressWarnings("unchecked") // for mock reset.
@Test
public void testInsertion() throws Exception {
@@ -215,7 +283,7 @@ public void testInsertion() throws Exception {
fcq.add(p0);
fail("didn't fail");
} catch (IllegalStateException ise) {
- checkOverflowException(ise, RpcStatusProto.ERROR);
+ checkOverflowException(ise, RpcStatusProto.ERROR, false);
}
Mockito.verify(fcq, times(1)).offerQueue(0, p0);
Mockito.verify(fcq, times(1)).offerQueue(1, p0);
@@ -228,7 +296,7 @@ public void testInsertion() throws Exception {
fcq.add(p1);
fail("didn't fail");
} catch (IllegalStateException ise) {
- checkOverflowException(ise, RpcStatusProto.ERROR);
+ checkOverflowException(ise, RpcStatusProto.ERROR, false);
}
Mockito.verify(fcq, times(0)).offerQueue(0, p1);
Mockito.verify(fcq, times(1)).offerQueue(1, p1);
@@ -241,7 +309,7 @@ public void testInsertion() throws Exception {
fcq.add(p2);
fail("didn't fail");
} catch (IllegalStateException ise) {
- checkOverflowException(ise, RpcStatusProto.FATAL);
+ checkOverflowException(ise, RpcStatusProto.FATAL, false);
}
Mockito.verify(fcq, times(0)).offerQueue(0, p2);
Mockito.verify(fcq, times(0)).offerQueue(1, p2);
@@ -280,7 +348,8 @@ public void testInsertion() throws Exception {
Mockito.verify(fcq, times(1)).putQueue(2, p2);
}
- private void checkOverflowException(Exception ex, RpcStatusProto status) {
+ private void checkOverflowException(Exception ex, RpcStatusProto status,
+ boolean failOverTriggered) {
// should be an overflow exception
assertTrue(ex.getClass().getName() + " != CallQueueOverflowException",
ex instanceof CallQueueOverflowException);
@@ -289,10 +358,15 @@ private void checkOverflowException(Exception ex, RpcStatusProto status) {
assertTrue(ioe.getClass().getName() + " != RpcServerException",
ioe instanceof RpcServerException);
RpcServerException rse = (RpcServerException)ioe;
- // check error/fatal status and if it embeds a retriable ex.
+ // check error/fatal status and if it embeds a retriable ex or standby ex.
assertEquals(status, rse.getRpcStatusProto());
- assertTrue(rse.getClass().getName() + " != RetriableException",
- rse.getCause() instanceof RetriableException);
+ if (failOverTriggered) {
+ assertTrue(rse.getClass().getName() + " != RetriableException",
+ rse.getCause() instanceof StandbyException);
+ } else {
+ assertTrue(rse.getClass().getName() + " != RetriableException",
+ rse.getCause() instanceof RetriableException);
+ }
}
//
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestIPC.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestIPC.java
index 1c1ad00451d9a..82540637a2004 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestIPC.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestIPC.java
@@ -24,7 +24,6 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
@@ -106,6 +105,8 @@
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;
+import static org.assertj.core.api.Assertions.assertThat;
+
/** Unit tests for IPC. */
public class TestIPC {
public static final Logger LOG = LoggerFactory.getLogger(TestIPC.class);
@@ -1274,7 +1275,7 @@ public void testNoRetryOnInvalidToken() throws IOException {
retryProxy.dummyRun();
} finally {
// Check if dummyRun called only once
- Assert.assertEquals(handler.invocations, 1);
+ assertThat(handler.invocations).isOne();
Client.setCallIdAndRetryCount(0, 0, null);
client.stop();
server.stop();
@@ -1455,7 +1456,7 @@ public void run() {
@Test
public void testClientGetTimeout() throws IOException {
Configuration config = new Configuration();
- assertEquals(Client.getTimeout(config), -1);
+ assertThat(Client.getTimeout(config)).isEqualTo(-1);
}
@Test(timeout=60000)
@@ -1582,11 +1583,10 @@ public void testRpcResponseLimit() throws Throwable {
try {
call(client, 0, addr, conf);
} catch (IOException ioe) {
- Throwable t = ioe.getCause();
- Assert.assertNotNull(t);
- Assert.assertEquals(RpcException.class, t.getClass());
+ Assert.assertNotNull(ioe);
+ Assert.assertEquals(RpcException.class, ioe.getClass());
Assert.assertEquals("RPC response exceeds maximum data length",
- t.getMessage());
+ ioe.getMessage());
return;
}
Assert.fail("didn't get limit exceeded");
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestProcessingDetails.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestProcessingDetails.java
new file mode 100644
index 0000000000000..0ecc741b014b3
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestProcessingDetails.java
@@ -0,0 +1,61 @@
+/**
+ * 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.ipc;
+
+import org.junit.Test;
+
+import java.util.concurrent.TimeUnit;
+
+import static org.apache.hadoop.ipc.ProcessingDetails.Timing;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Unit tests for ProcessingDetails time unit conversion and output.
+ */
+public class TestProcessingDetails {
+
+ /**
+ * Test that the conversion of time values in various units in and out of the
+ * details are done properly.
+ */
+ @Test
+ public void testTimeConversion() {
+ ProcessingDetails details = new ProcessingDetails(TimeUnit.MICROSECONDS);
+
+ details.set(Timing.ENQUEUE, 10);
+ assertEquals(10, details.get(Timing.ENQUEUE));
+ assertEquals(10_000, details.get(Timing.ENQUEUE, TimeUnit.NANOSECONDS));
+
+ details.set(Timing.QUEUE, 20, TimeUnit.MILLISECONDS);
+ details.add(Timing.QUEUE, 20, TimeUnit.MICROSECONDS);
+ assertEquals(20_020, details.get(Timing.QUEUE));
+ assertEquals(0, details.get(Timing.QUEUE, TimeUnit.SECONDS));
+ }
+
+ @Test
+ public void testToString() {
+ ProcessingDetails details = new ProcessingDetails(TimeUnit.MICROSECONDS);
+ details.set(Timing.ENQUEUE, 10);
+ details.set(Timing.QUEUE, 20, TimeUnit.MILLISECONDS);
+
+ assertEquals("enqueueTime=10 queueTime=20000 handlerTime=0 " +
+ "processingTime=0 lockfreeTime=0 lockwaitTime=0 locksharedTime=0 " +
+ "lockexclusiveTime=0 responseTime=0", details.toString());
+ }
+}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestProtoBufRpc.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestProtoBufRpc.java
index 5fbd957312072..3053f87511885 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestProtoBufRpc.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestProtoBufRpc.java
@@ -34,18 +34,19 @@
import org.apache.hadoop.ipc.protobuf.TestRpcServiceProtos.TestProtobufRpcProto;
import org.apache.hadoop.metrics2.MetricsRecordBuilder;
import org.apache.hadoop.net.NetUtils;
+import org.apache.hadoop.test.GenericTestUtils;
import org.junit.After;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.net.URISyntaxException;
+import java.util.concurrent.TimeoutException;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.apache.hadoop.test.MetricsAsserts.assertCounterGt;
import static org.apache.hadoop.test.MetricsAsserts.getMetrics;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
/**
* Test for testing protocol buffer based RPC mechanism.
@@ -141,19 +142,19 @@ public static void testProtoBufRpc(TestRpcService client) throws Exception {
EchoRequestProto echoRequest = EchoRequestProto.newBuilder()
.setMessage("hello").build();
EchoResponseProto echoResponse = client.echo(null, echoRequest);
- Assert.assertEquals(echoResponse.getMessage(), "hello");
+ assertThat(echoResponse.getMessage()).isEqualTo("hello");
// Test error method - error should be thrown as RemoteException
try {
client.error(null, newEmptyRequest());
- Assert.fail("Expected exception is not thrown");
+ fail("Expected exception is not thrown");
} catch (ServiceException e) {
RemoteException re = (RemoteException)e.getCause();
RpcServerException rse = (RpcServerException) re
.unwrapRemoteException(RpcServerException.class);
- Assert.assertNotNull(rse);
- Assert.assertTrue(re.getErrorCode().equals(
- RpcErrorCodeProto.ERROR_RPC_SERVER));
+ assertThat(rse).isNotNull();
+ assertThat(re.getErrorCode())
+ .isEqualTo(RpcErrorCodeProto.ERROR_RPC_SERVER);
}
}
@@ -167,7 +168,7 @@ public void testProtoBufRpc2() throws Exception {
// Test echo method
EchoResponseProto echoResponse = client.echo2(null,
newEchoRequest("hello"));
- Assert.assertEquals(echoResponse.getMessage(), "hello");
+ assertThat(echoResponse.getMessage()).isEqualTo("hello");
// Ensure RPC metrics are updated
MetricsRecordBuilder rpcMetrics = getMetrics(server.getRpcMetrics().name());
@@ -186,13 +187,13 @@ public void testProtoBufRandomException() throws Exception {
try {
client.error2(null, newEmptyRequest());
} catch (ServiceException se) {
- Assert.assertTrue(se.getCause() instanceof RemoteException);
+ assertThat(se.getCause()).isInstanceOf(RemoteException.class);
RemoteException re = (RemoteException) se.getCause();
- Assert.assertTrue(re.getClassName().equals(
- URISyntaxException.class.getName()));
- Assert.assertTrue(re.getMessage().contains("testException"));
- Assert.assertTrue(
- re.getErrorCode().equals(RpcErrorCodeProto.ERROR_APPLICATION));
+ assertThat(re.getClassName())
+ .isEqualTo(URISyntaxException.class.getName());
+ assertThat(re.getMessage()).contains("testException");
+ assertThat(re.getErrorCode())
+ .isEqualTo(RpcErrorCodeProto.ERROR_APPLICATION);
}
}
@@ -203,19 +204,20 @@ public void testExtraLongRpc() throws Exception {
// short message goes through
EchoResponseProto echoResponse = client.echo2(null,
newEchoRequest(shortString));
- Assert.assertEquals(shortString, echoResponse.getMessage());
+ assertThat(echoResponse.getMessage()).isEqualTo(shortString);
final String longString = StringUtils.repeat("X", 4096);
try {
client.echo2(null, newEchoRequest(longString));
- Assert.fail("expected extra-long RPC to fail");
+ fail("expected extra-long RPC to fail");
} catch (ServiceException se) {
// expected
}
}
@Test(timeout = 12000)
- public void testLogSlowRPC() throws IOException, ServiceException {
+ public void testLogSlowRPC() throws IOException, ServiceException,
+ TimeoutException, InterruptedException {
TestRpcService2 client = getClient2();
// make 10 K fast calls
for (int x = 0; x < 10000; x++) {
@@ -228,15 +230,15 @@ public void testLogSlowRPC() throws IOException, ServiceException {
// Ensure RPC metrics are updated
RpcMetrics rpcMetrics = server.getRpcMetrics();
- assertTrue(rpcMetrics.getProcessingSampleCount() > 999L);
+ assertThat(rpcMetrics.getProcessingSampleCount()).isGreaterThan(999L);
long before = rpcMetrics.getRpcSlowCalls();
// make a really slow call. Sleep sleeps for 1000ms
client.sleep(null, newSleepRequest(SLEEP_DURATION * 3));
- long after = rpcMetrics.getRpcSlowCalls();
// Ensure slow call is logged.
- Assert.assertEquals(before + 1L, after);
+ GenericTestUtils.waitFor(()
+ -> rpcMetrics.getRpcSlowCalls() == before + 1L, 10, 1000);
}
@Test(timeout = 12000)
@@ -252,7 +254,7 @@ public void testEnsureNoLogIfDisabled() throws IOException, ServiceException {
// Ensure RPC metrics are updated
RpcMetrics rpcMetrics = server.getRpcMetrics();
- assertTrue(rpcMetrics.getProcessingSampleCount() > 999L);
+ assertThat(rpcMetrics.getProcessingSampleCount()).isGreaterThan(999L);
long before = rpcMetrics.getRpcSlowCalls();
// make a really slow call. Sleep sleeps for 1000ms
@@ -261,6 +263,6 @@ public void testEnsureNoLogIfDisabled() throws IOException, ServiceException {
long after = rpcMetrics.getRpcSlowCalls();
// make sure we never called into Log slow RPC routine.
- assertEquals(before, after);
+ assertThat(before).isEqualTo(after);
}
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestRPC.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestRPC.java
index 36a8885c9cfc8..0da0b47529f99 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestRPC.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestRPC.java
@@ -18,7 +18,6 @@
package org.apache.hadoop.ipc;
-import com.google.common.base.Supplier;
import com.google.protobuf.ServiceException;
import org.apache.hadoop.HadoopIllegalArgumentException;
import org.apache.hadoop.conf.Configuration;
@@ -85,8 +84,11 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.apache.hadoop.test.MetricsAsserts.assertCounter;
import static org.apache.hadoop.test.MetricsAsserts.assertCounterGt;
+import static org.apache.hadoop.test.MetricsAsserts.assertGauge;
+import static org.apache.hadoop.test.MetricsAsserts.getDoubleGauge;
import static org.apache.hadoop.test.MetricsAsserts.getLongCounter;
import static org.apache.hadoop.test.MetricsAsserts.getMetrics;
import static org.junit.Assert.assertEquals;
@@ -485,14 +487,14 @@ private void testCallsInternal(Configuration myConf) throws Exception {
.setParam2(2).build();
TestProtos.AddResponseProto addResponse =
proxy.add(null, addRequest);
- assertEquals(addResponse.getResult(), 3);
+ assertThat(addResponse.getResult()).isEqualTo(3);
Integer[] integers = new Integer[] {1, 2};
TestProtos.AddRequestProto2 addRequest2 =
TestProtos.AddRequestProto2.newBuilder().addAllParams(
Arrays.asList(integers)).build();
addResponse = proxy.add2(null, addRequest2);
- assertEquals(addResponse.getResult(), 3);
+ assertThat(addResponse.getResult()).isEqualTo(3);
boolean caught = false;
try {
@@ -1072,10 +1074,14 @@ public TestRpcService run() {
}
MetricsRecordBuilder rpcMetrics =
getMetrics(server.getRpcMetrics().name());
- assertTrue("Expected non-zero rpc queue time",
- getLongCounter("RpcQueueTimeNumOps", rpcMetrics) > 0);
- assertTrue("Expected non-zero rpc processing time",
- getLongCounter("RpcProcessingTimeNumOps", rpcMetrics) > 0);
+ assertEquals("Expected correct rpc queue count",
+ 3000, getLongCounter("RpcQueueTimeNumOps", rpcMetrics));
+ assertEquals("Expected correct rpc processing count",
+ 3000, getLongCounter("RpcProcessingTimeNumOps", rpcMetrics));
+ assertEquals("Expected correct rpc lock wait count",
+ 3000, getLongCounter("RpcLockWaitTimeNumOps", rpcMetrics));
+ assertEquals("Expected zero rpc lock wait time",
+ 0, getDoubleGauge("RpcLockWaitTimeAvgTime", rpcMetrics), 0.001);
MetricsAsserts.assertQuantileGauges("RpcQueueTime" + interval + "s",
rpcMetrics);
MetricsAsserts.assertQuantileGauges("RpcProcessingTime" + interval + "s",
@@ -1086,6 +1092,10 @@ public TestRpcService run() {
UserGroupInformation.getCurrentUser().getShortUserName();
assertTrue(actualUserVsCon.contains("\"" + proxyUser + "\":1"));
assertTrue(actualUserVsCon.contains("\"" + testUser + "\":1"));
+
+ proxy.lockAndSleep(null, newSleepRequest(5));
+ rpcMetrics = getMetrics(server.getRpcMetrics().name());
+ assertGauge("RpcLockWaitTimeAvgTime", 10000.0, rpcMetrics);
} finally {
if (proxy2 != null) {
RPC.stopProxy(proxy2);
@@ -1185,15 +1195,6 @@ public void testClientBackOffByResponseTime() throws Exception {
Exception lastException = null;
proxy = getClient(addr, conf);
- MetricsRecordBuilder rb1 =
- getMetrics("DecayRpcSchedulerMetrics2." + ns);
- final long beginDecayedCallVolume = MetricsAsserts.getLongCounter(
- "DecayedCallVolume", rb1);
- final long beginRawCallVolume = MetricsAsserts.getLongCounter(
- "CallVolume", rb1);
- final int beginUniqueCaller = MetricsAsserts.getIntCounter("UniqueCallers",
- rb1);
-
try {
// start a sleep RPC call that sleeps 3s.
for (int i = 0; i < numClients; i++) {
@@ -1221,41 +1222,6 @@ public Void call() throws ServiceException, InterruptedException {
} else {
lastException = unwrapExeption;
}
-
- // Lets Metric system update latest metrics
- GenericTestUtils.waitFor(new Supplier() {
- @Override
- public Boolean get() {
- MetricsRecordBuilder rb2 =
- getMetrics("DecayRpcSchedulerMetrics2." + ns);
- long decayedCallVolume1 = MetricsAsserts.getLongCounter(
- "DecayedCallVolume", rb2);
- long rawCallVolume1 = MetricsAsserts.getLongCounter(
- "CallVolume", rb2);
- int uniqueCaller1 = MetricsAsserts.getIntCounter(
- "UniqueCallers", rb2);
- long callVolumePriority0 = MetricsAsserts.getLongGauge(
- "Priority.0.CompletedCallVolume", rb2);
- long callVolumePriority1 = MetricsAsserts.getLongGauge(
- "Priority.1.CompletedCallVolume", rb2);
- double avgRespTimePriority0 = MetricsAsserts.getDoubleGauge(
- "Priority.0.AvgResponseTime", rb2);
- double avgRespTimePriority1 = MetricsAsserts.getDoubleGauge(
- "Priority.1.AvgResponseTime", rb2);
-
- LOG.info("DecayedCallVolume: " + decayedCallVolume1);
- LOG.info("CallVolume: " + rawCallVolume1);
- LOG.info("UniqueCaller: " + uniqueCaller1);
- LOG.info("Priority.0.CompletedCallVolume: " + callVolumePriority0);
- LOG.info("Priority.1.CompletedCallVolume: " + callVolumePriority1);
- LOG.info("Priority.0.AvgResponseTime: " + avgRespTimePriority0);
- LOG.info("Priority.1.AvgResponseTime: " + avgRespTimePriority1);
-
- return decayedCallVolume1 > beginDecayedCallVolume &&
- rawCallVolume1 > beginRawCallVolume &&
- uniqueCaller1 > beginUniqueCaller;
- }
- }, 30, 60000);
}
} finally {
executorService.shutdown();
@@ -1267,6 +1233,63 @@ public Boolean get() {
assertTrue("RetriableException not received", succeeded);
}
+ /** Test that the metrics for DecayRpcScheduler are updated. */
+ @Test (timeout=30000)
+ public void testDecayRpcSchedulerMetrics() throws Exception {
+ final String ns = CommonConfigurationKeys.IPC_NAMESPACE + ".0";
+ Server server = setupDecayRpcSchedulerandTestServer(ns + ".");
+
+ MetricsRecordBuilder rb1 =
+ getMetrics("DecayRpcSchedulerMetrics2." + ns);
+ final long beginDecayedCallVolume = MetricsAsserts.getLongCounter(
+ "DecayedCallVolume", rb1);
+ final long beginRawCallVolume = MetricsAsserts.getLongCounter(
+ "CallVolume", rb1);
+ final int beginUniqueCaller = MetricsAsserts.getIntCounter("UniqueCallers",
+ rb1);
+
+ TestRpcService proxy = getClient(addr, conf);
+ try {
+ for (int i = 0; i < 2; i++) {
+ proxy.sleep(null, newSleepRequest(100));
+ }
+
+ // Lets Metric system update latest metrics
+ GenericTestUtils.waitFor(() -> {
+ MetricsRecordBuilder rb2 =
+ getMetrics("DecayRpcSchedulerMetrics2." + ns);
+ long decayedCallVolume1 = MetricsAsserts.getLongCounter(
+ "DecayedCallVolume", rb2);
+ long rawCallVolume1 = MetricsAsserts.getLongCounter(
+ "CallVolume", rb2);
+ int uniqueCaller1 = MetricsAsserts.getIntCounter(
+ "UniqueCallers", rb2);
+ long callVolumePriority0 = MetricsAsserts.getLongGauge(
+ "Priority.0.CompletedCallVolume", rb2);
+ long callVolumePriority1 = MetricsAsserts.getLongGauge(
+ "Priority.1.CompletedCallVolume", rb2);
+ double avgRespTimePriority0 = MetricsAsserts.getDoubleGauge(
+ "Priority.0.AvgResponseTime", rb2);
+ double avgRespTimePriority1 = MetricsAsserts.getDoubleGauge(
+ "Priority.1.AvgResponseTime", rb2);
+
+ LOG.info("DecayedCallVolume: {}", decayedCallVolume1);
+ LOG.info("CallVolume: {}", rawCallVolume1);
+ LOG.info("UniqueCaller: {}", uniqueCaller1);
+ LOG.info("Priority.0.CompletedCallVolume: {}", callVolumePriority0);
+ LOG.info("Priority.1.CompletedCallVolume: {}", callVolumePriority1);
+ LOG.info("Priority.0.AvgResponseTime: {}", avgRespTimePriority0);
+ LOG.info("Priority.1.AvgResponseTime: {}", avgRespTimePriority1);
+
+ return decayedCallVolume1 > beginDecayedCallVolume &&
+ rawCallVolume1 > beginRawCallVolume &&
+ uniqueCaller1 > beginUniqueCaller;
+ }, 30, 60000);
+ } finally {
+ stop(server, proxy);
+ }
+ }
+
private Server setupDecayRpcSchedulerandTestServer(String ns)
throws Exception {
final int queueSizePerHandler = 3;
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestRpcBase.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestRpcBase.java
index 0d2f975c1d676..2f2d36f7b45d7 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestRpcBase.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestRpcBase.java
@@ -21,12 +21,16 @@
import com.google.protobuf.BlockingService;
import com.google.protobuf.RpcController;
import com.google.protobuf.ServiceException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.ipc.protobuf.TestProtos;
import org.apache.hadoop.ipc.protobuf.TestRpcServiceProtos;
import org.apache.hadoop.net.NetUtils;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.token.SecretManager;
+import org.apache.hadoop.util.Time;
import org.junit.Assert;
import org.apache.hadoop.io.Text;
@@ -278,6 +282,7 @@ public interface TestRpcService
public static class PBServerImpl implements TestRpcService {
CountDownLatch fastPingCounter = new CountDownLatch(2);
private List postponedCalls = new ArrayList<>();
+ private final Lock lock = new ReentrantLock();
@Override
public TestProtos.EmptyResponseProto ping(RpcController unused,
@@ -388,6 +393,29 @@ public TestProtos.EmptyResponseProto sleep(
return TestProtos.EmptyResponseProto.newBuilder().build();
}
+ @Override
+ public TestProtos.EmptyResponseProto lockAndSleep(
+ RpcController controller, TestProtos.SleepRequestProto request)
+ throws ServiceException {
+ ProcessingDetails details =
+ Server.getCurCall().get().getProcessingDetails();
+ lock.lock();
+ long startNanos = Time.monotonicNowNanos();
+ try {
+ Thread.sleep(request.getMilliSeconds());
+ } catch (InterruptedException ignore) {
+ // ignore
+ } finally {
+ lock.unlock();
+ }
+ // Add some arbitrary large lock wait time since in any test scenario
+ // the lock wait time will probably actually be too small to notice
+ details.add(ProcessingDetails.Timing.LOCKWAIT, 10, TimeUnit.SECONDS);
+ details.add(ProcessingDetails.Timing.LOCKEXCLUSIVE,
+ Time.monotonicNowNanos() - startNanos, TimeUnit.NANOSECONDS);
+ return TestProtos.EmptyResponseProto.newBuilder().build();
+ }
+
@Override
public TestProtos.AuthMethodResponseProto getAuthMethod(
RpcController controller, TestProtos.EmptyRequestProto request)
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestSocketFactory.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestSocketFactory.java
index ce481dc73dd32..1bad29e7750d1 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestSocketFactory.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestSocketFactory.java
@@ -33,23 +33,20 @@
import javax.net.SocketFactory;
-import org.junit.Assert;
-
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.CommonConfigurationKeys;
import org.apache.hadoop.net.NetUtils;
import org.apache.hadoop.net.SocksSocketFactory;
import org.apache.hadoop.net.StandardSocketFactory;
import org.junit.After;
-import org.junit.Before;
import org.junit.Test;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;
+import static org.assertj.core.api.Assertions.assertThat;
+
/**
* test StandardSocketFactory and SocksSocketFactory NetUtils
*
@@ -111,10 +108,12 @@ public void testSocketFactoryAsKeyInMap() {
.getDefaultSocketFactory(conf);
dummyCache.put(defaultSocketFactory, toBeCached2);
- Assert
- .assertEquals("The cache contains two elements", 2, dummyCache.size());
- Assert.assertEquals("Equals of both socket factory shouldn't be same",
- defaultSocketFactory.equals(dummySocketFactory), false);
+ assertThat(dummyCache.size())
+ .withFailMessage("The cache contains two elements")
+ .isEqualTo(2);
+ assertThat(defaultSocketFactory)
+ .withFailMessage("Equals of both socket factory shouldn't be same")
+ .isNotEqualTo(dummySocketFactory);
assertSame(toBeCached2, dummyCache.remove(defaultSocketFactory));
dummyCache.put(defaultSocketFactory, toBeCached2);
@@ -184,14 +183,13 @@ public void testProxy() throws Exception {
"localhost", 0));
SocksSocketFactory templateWithProxy = new SocksSocketFactory(proxy);
- assertFalse(templateWithoutProxy.equals(templateWithProxy));
+ assertThat(templateWithoutProxy).isNotEqualTo(templateWithProxy);
Configuration configuration = new Configuration();
configuration.set("hadoop.socks.server", "localhost:0");
templateWithoutProxy.setConf(configuration);
- assertTrue(templateWithoutProxy.equals(templateWithProxy));
-
+ assertThat(templateWithoutProxy).isEqualTo(templateWithProxy);
}
private void checkSocket(Socket socket) throws Exception {
@@ -200,8 +198,7 @@ private void checkSocket(Socket socket) throws Exception {
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
out.writeBytes("test\n");
String answer = input.readLine();
- assertEquals("TEST", answer);
-
+ assertThat(answer).isEqualTo("TEST");
}
/**
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestWeightedRoundRobinMultiplexer.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestWeightedRoundRobinMultiplexer.java
index d4bc06ad3c3a1..11e2a9d917a19 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestWeightedRoundRobinMultiplexer.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestWeightedRoundRobinMultiplexer.java
@@ -18,7 +18,8 @@
package org.apache.hadoop.ipc;
-import static org.junit.Assert.assertEquals;
+import static org.assertj.core.api.Assertions.assertThat;
+
import org.junit.Test;
import org.apache.hadoop.conf.Configuration;
@@ -68,47 +69,47 @@ public void testDefaultPattern() {
// Mux of size 1: 0 0 0 0 0, etc
mux = new WeightedRoundRobinMultiplexer(1, "", new Configuration());
for(int i = 0; i < 10; i++) {
- assertEquals(mux.getAndAdvanceCurrentIndex(), 0);
+ assertThat(mux.getAndAdvanceCurrentIndex()).isZero();
}
// Mux of size 2: 0 0 1 0 0 1 0 0 1, etc
mux = new WeightedRoundRobinMultiplexer(2, "", new Configuration());
- assertEquals(mux.getAndAdvanceCurrentIndex(), 0);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 0);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 1);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 0);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 0);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 1);
+ assertThat(mux.getAndAdvanceCurrentIndex()).isZero();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isZero();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isOne();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isZero();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isZero();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isOne();
// Size 3: 4x0 2x1 1x2, etc
mux = new WeightedRoundRobinMultiplexer(3, "", new Configuration());
- assertEquals(mux.getAndAdvanceCurrentIndex(), 0);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 0);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 0);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 0);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 1);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 1);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 2);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 0);
+ assertThat(mux.getAndAdvanceCurrentIndex()).isZero();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isZero();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isZero();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isZero();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isOne();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isOne();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isEqualTo(2);
+ assertThat(mux.getAndAdvanceCurrentIndex()).isZero();
// Size 4: 8x0 4x1 2x2 1x3
mux = new WeightedRoundRobinMultiplexer(4, "", new Configuration());
- assertEquals(mux.getAndAdvanceCurrentIndex(), 0);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 0);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 0);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 0);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 0);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 0);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 0);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 0);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 1);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 1);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 1);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 1);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 2);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 2);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 3);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 0);
+ assertThat(mux.getAndAdvanceCurrentIndex()).isZero();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isZero();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isZero();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isZero();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isZero();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isZero();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isZero();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isZero();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isOne();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isOne();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isOne();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isOne();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isEqualTo(2);
+ assertThat(mux.getAndAdvanceCurrentIndex()).isEqualTo(2);
+ assertThat(mux.getAndAdvanceCurrentIndex()).isEqualTo(3);
+ assertThat(mux.getAndAdvanceCurrentIndex()).isZero();
}
@Test
@@ -119,10 +120,10 @@ public void testCustomPattern() {
"1", "1");
mux = new WeightedRoundRobinMultiplexer(2, "test.custom", conf);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 0);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 1);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 0);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 1);
+ assertThat(mux.getAndAdvanceCurrentIndex()).isZero();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isOne();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isZero();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isOne();
// 1x0 3x1 2x2
conf.setStrings("test.custom." + IPC_CALLQUEUE_WRRMUX_WEIGHTS_KEY,
@@ -131,12 +132,12 @@ public void testCustomPattern() {
mux = new WeightedRoundRobinMultiplexer(3, "test.custom", conf);
for(int i = 0; i < 5; i++) {
- assertEquals(mux.getAndAdvanceCurrentIndex(), 0);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 1);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 1);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 1);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 2);
- assertEquals(mux.getAndAdvanceCurrentIndex(), 2);
+ assertThat(mux.getAndAdvanceCurrentIndex()).isZero();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isOne();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isOne();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isOne();
+ assertThat(mux.getAndAdvanceCurrentIndex()).isEqualTo(2);
+ assertThat(mux.getAndAdvanceCurrentIndex()).isEqualTo(2);
} // Ensure pattern repeats
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestWeightedTimeCostProvider.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestWeightedTimeCostProvider.java
new file mode 100644
index 0000000000000..4f4a72b99ab4a
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestWeightedTimeCostProvider.java
@@ -0,0 +1,86 @@
+/**
+ * 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.ipc;
+
+import java.util.concurrent.TimeUnit;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.ipc.ProcessingDetails.Timing;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.apache.hadoop.ipc.WeightedTimeCostProvider.DEFAULT_LOCKEXCLUSIVE_WEIGHT;
+import static org.apache.hadoop.ipc.WeightedTimeCostProvider.DEFAULT_LOCKFREE_WEIGHT;
+import static org.apache.hadoop.ipc.WeightedTimeCostProvider.DEFAULT_LOCKSHARED_WEIGHT;
+import static org.junit.Assert.assertEquals;
+
+/** Tests for {@link WeightedTimeCostProvider}. */
+public class TestWeightedTimeCostProvider {
+
+ private static final int QUEUE_TIME = 3;
+ private static final int LOCKFREE_TIME = 5;
+ private static final int LOCKSHARED_TIME = 7;
+ private static final int LOCKEXCLUSIVE_TIME = 11;
+
+ private WeightedTimeCostProvider costProvider;
+ private ProcessingDetails processingDetails;
+
+ @Before
+ public void setup() {
+ costProvider = new WeightedTimeCostProvider();
+ processingDetails = new ProcessingDetails(TimeUnit.MILLISECONDS);
+ processingDetails.set(Timing.QUEUE, QUEUE_TIME);
+ processingDetails.set(Timing.LOCKFREE, LOCKFREE_TIME);
+ processingDetails.set(Timing.LOCKSHARED, LOCKSHARED_TIME);
+ processingDetails.set(Timing.LOCKEXCLUSIVE, LOCKEXCLUSIVE_TIME);
+ }
+
+ @Test(expected = AssertionError.class)
+ public void testGetCostBeforeInit() {
+ costProvider.getCost(null);
+ }
+
+ @Test
+ public void testGetCostDefaultWeights() {
+ costProvider.init("foo", new Configuration());
+ long actualCost = costProvider.getCost(processingDetails);
+ long expectedCost = DEFAULT_LOCKFREE_WEIGHT * LOCKFREE_TIME
+ + DEFAULT_LOCKSHARED_WEIGHT * LOCKSHARED_TIME
+ + DEFAULT_LOCKEXCLUSIVE_WEIGHT * LOCKEXCLUSIVE_TIME;
+ assertEquals(expectedCost, actualCost);
+ }
+
+ @Test
+ public void testGetCostConfiguredWeights() {
+ Configuration conf = new Configuration();
+ int queueWeight = 1000;
+ int lockfreeWeight = 10000;
+ int locksharedWeight = 100000;
+ conf.setInt("foo.weighted-cost.queue", queueWeight);
+ conf.setInt("foo.weighted-cost.lockfree", lockfreeWeight);
+ conf.setInt("foo.weighted-cost.lockshared", locksharedWeight);
+ conf.setInt("bar.weighted-cost.lockexclusive", 0); // should not apply
+ costProvider.init("foo", conf);
+ long actualCost = costProvider.getCost(processingDetails);
+ long expectedCost = queueWeight * QUEUE_TIME
+ + lockfreeWeight * LOCKFREE_TIME
+ + locksharedWeight * LOCKSHARED_TIME
+ + DEFAULT_LOCKEXCLUSIVE_WEIGHT * LOCKEXCLUSIVE_TIME;
+ assertEquals(expectedCost, actualCost);
+ }
+}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/metrics/TestRpcMetrics.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/metrics/TestRpcMetrics.java
new file mode 100644
index 0000000000000..1716433411181
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/metrics/TestRpcMetrics.java
@@ -0,0 +1,60 @@
+/**
+ * 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.ipc.metrics;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.io.LongWritable;
+import org.apache.hadoop.io.Writable;
+import org.apache.hadoop.ipc.RPC;
+import org.apache.hadoop.ipc.Server;
+import org.apache.hadoop.metrics2.MetricsSystem;
+import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
+import org.junit.Test;
+
+public class TestRpcMetrics {
+
+ @Test
+ public void metricsAreUnregistered() throws Exception {
+
+ Configuration conf = new Configuration();
+ Server server = new Server("0.0.0.0", 0, LongWritable.class, 1, conf) {
+ @Override
+ public Writable call(
+ RPC.RpcKind rpcKind, String protocol, Writable param,
+ long receiveTime) throws Exception {
+ return null;
+ }
+ };
+ MetricsSystem metricsSystem = DefaultMetricsSystem.instance();
+ RpcMetrics rpcMetrics = server.getRpcMetrics();
+ RpcDetailedMetrics rpcDetailedMetrics = server.getRpcDetailedMetrics();
+
+ assertNotNull(metricsSystem.getSource(rpcMetrics.name()));
+ assertNotNull(metricsSystem.getSource(rpcDetailedMetrics.name()));
+
+ server.stop();
+
+ assertNull(metricsSystem.getSource(rpcMetrics.name()));
+ assertNull(metricsSystem.getSource(rpcDetailedMetrics.name()));
+
+ }
+
+}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/log/TestLogLevel.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/log/TestLogLevel.java
index fd30b50141f28..3af70e95548ba 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/log/TestLogLevel.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/log/TestLogLevel.java
@@ -34,6 +34,7 @@
import org.apache.hadoop.log.LogLevel.CLI;
import org.apache.hadoop.minikdc.KerberosSecurityTestcase;
import org.apache.hadoop.net.NetUtils;
+import org.apache.hadoop.security.AuthenticationFilterInitializer;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.authentication.KerberosTestUtils;
import org.apache.hadoop.security.authentication.client.KerberosAuthenticator;
@@ -73,6 +74,7 @@ public class TestLogLevel extends KerberosSecurityTestcase {
private final Logger log = ((Log4JLogger)testlog).getLogger();
private final static String PRINCIPAL = "loglevel.principal";
private final static String KEYTAB = "loglevel.keytab";
+ private static final String PREFIX = "hadoop.http.authentication.";
@BeforeClass
public static void setUp() throws Exception {
@@ -262,6 +264,13 @@ private void testDynamicLogLevel(final String bindProtocol,
conf.set(KEYTAB, KerberosTestUtils.getKeytabFile());
conf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION,
"kerberos");
+ conf.set(PREFIX + "type", "kerberos");
+ conf.set(PREFIX + "kerberos.keytab", KerberosTestUtils.getKeytabFile());
+ conf.set(PREFIX + "kerberos.principal",
+ KerberosTestUtils.getServerPrincipal());
+ conf.set(HttpServer2.FILTER_INITIALIZER_PROPERTY,
+ AuthenticationFilterInitializer.class.getName());
+
conf.setBoolean(CommonConfigurationKeys.HADOOP_SECURITY_AUTHORIZATION,
true);
UserGroupInformation.setConfiguration(conf);
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/metrics2/lib/TestMutableMetrics.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/metrics2/lib/TestMutableMetrics.java
index 29d47cfab05ac..b5f62b189040e 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/metrics2/lib/TestMutableMetrics.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/metrics2/lib/TestMutableMetrics.java
@@ -274,6 +274,23 @@ private static void snapshotMutableRatesWithAggregation(
}
}
+ @Test
+ public void testDuplicateMetrics() {
+ MutableRatesWithAggregation rates = new MutableRatesWithAggregation();
+ MutableRatesWithAggregation deferredRpcRates =
+ new MutableRatesWithAggregation();
+ Class> protocol = Long.class;
+ rates.init(protocol);
+ deferredRpcRates.init(protocol, "Deferred");
+ MetricsRecordBuilder rb = mockMetricsRecordBuilder();
+ rates.snapshot(rb, true);
+ deferredRpcRates.snapshot(rb, true);
+ verify(rb, times(1))
+ .addCounter(info("GetLongNumOps", "Number of ops for getLong"), 0L);
+ verify(rb, times(1)).addCounter(
+ info("GetLongDeferredNumOps", "Number of ops for getLongDeferred"), 0L);
+ }
+
/**
* Tests that when using {@link MutableStat#add(long, long)}, even with a high
* sample count, the mean does not lose accuracy.
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/metrics2/sink/TestPrometheusMetricsSink.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/metrics2/sink/TestPrometheusMetricsSink.java
new file mode 100644
index 0000000000000..3fc4aa4cc3430
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/metrics2/sink/TestPrometheusMetricsSink.java
@@ -0,0 +1,133 @@
+/**
+ * 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.metrics2.sink;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+
+import org.apache.hadoop.metrics2.MetricsSystem;
+import org.apache.hadoop.metrics2.annotation.Metric;
+import org.apache.hadoop.metrics2.annotation.Metrics;
+import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
+import org.apache.hadoop.metrics2.lib.MutableCounterLong;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+/**
+ * Test prometheus Sink.
+ */
+public class TestPrometheusMetricsSink {
+
+ @Test
+ public void testPublish() throws IOException {
+ //GIVEN
+ MetricsSystem metrics = DefaultMetricsSystem.instance();
+
+ metrics.init("test");
+ PrometheusMetricsSink sink = new PrometheusMetricsSink();
+ metrics.register("Prometheus", "Prometheus", sink);
+ TestMetrics testMetrics = metrics
+ .register("TestMetrics", "Testing metrics", new TestMetrics());
+
+ metrics.start();
+ testMetrics.numBucketCreateFails.incr();
+ metrics.publishMetricsNow();
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ OutputStreamWriter writer = new OutputStreamWriter(stream, UTF_8);
+
+ //WHEN
+ sink.writeMetrics(writer);
+ writer.flush();
+
+ //THEN
+ String writtenMetrics = stream.toString(UTF_8.name());
+ System.out.println(writtenMetrics);
+ Assert.assertTrue(
+ "The expected metric line is missing from prometheus metrics output",
+ writtenMetrics.contains(
+ "test_metrics_num_bucket_create_fails{context=\"dfs\"")
+ );
+
+ metrics.stop();
+ metrics.shutdown();
+ }
+
+ @Test
+ public void testNamingCamelCase() {
+ PrometheusMetricsSink sink = new PrometheusMetricsSink();
+
+ Assert.assertEquals("rpc_time_some_metrics",
+ sink.prometheusName("RpcTime", "SomeMetrics"));
+
+ Assert.assertEquals("om_rpc_time_om_info_keys",
+ sink.prometheusName("OMRpcTime", "OMInfoKeys"));
+
+ Assert.assertEquals("rpc_time_small",
+ sink.prometheusName("RpcTime", "small"));
+ }
+
+ @Test
+ public void testNamingPipeline() {
+ PrometheusMetricsSink sink = new PrometheusMetricsSink();
+
+ String recordName = "SCMPipelineMetrics";
+ String metricName = "NumBlocksAllocated-"
+ + "RATIS-THREE-47659e3d-40c9-43b3-9792-4982fc279aba";
+ Assert.assertEquals(
+ "scm_pipeline_metrics_"
+ + "num_blocks_allocated_"
+ + "ratis_three_47659e3d_40c9_43b3_9792_4982fc279aba",
+ sink.prometheusName(recordName, metricName));
+ }
+
+ @Test
+ public void testNamingPeriods() {
+ PrometheusMetricsSink sink = new PrometheusMetricsSink();
+
+ String recordName = "org.apache.hadoop.hdfs.server.datanode.fsdataset.impl.FsDatasetImpl";
+ String metricName = "DfsUsed";
+ Assert.assertEquals(
+ "org_apache_hadoop_hdfs_server_datanode_fsdataset_impl_fs_dataset_impl_dfs_used",
+ sink.prometheusName(recordName, metricName));
+ }
+
+ @Test
+ public void testNamingWhitespaces() {
+ PrometheusMetricsSink sink = new PrometheusMetricsSink();
+
+ String recordName = "JvmMetrics";
+ String metricName = "GcCount" + "G1 Old Generation";
+ Assert.assertEquals(
+ "jvm_metrics_gc_count_g1_old_generation",
+ sink.prometheusName(recordName, metricName));
+ }
+
+ /**
+ * Example metric pojo.
+ */
+ @Metrics(about = "Test Metrics", context = "dfs")
+ private static class TestMetrics {
+
+ @Metric
+ private MutableCounterLong numBucketCreateFails;
+ }
+}
\ No newline at end of file
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/metrics2/util/TestSampleQuantiles.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/metrics2/util/TestSampleQuantiles.java
index 5c5f0368c04cf..c7d8f60b181d2 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/metrics2/util/TestSampleQuantiles.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/metrics2/util/TestSampleQuantiles.java
@@ -18,8 +18,6 @@
package org.apache.hadoop.metrics2.util;
-import static org.junit.Assert.*;
-
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
@@ -29,6 +27,8 @@
import org.junit.Before;
import org.junit.Test;
+import static org.assertj.core.api.Assertions.assertThat;
+
public class TestSampleQuantiles {
static final Quantile[] quantiles = { new Quantile(0.50, 0.050),
@@ -49,24 +49,24 @@ public void init() {
@Test
public void testCount() throws IOException {
// Counts start off zero
- assertEquals(estimator.getCount(), 0);
- assertEquals(estimator.getSampleCount(), 0);
+ assertThat(estimator.getCount()).isZero();
+ assertThat(estimator.getSampleCount()).isZero();
// Snapshot should be null if there are no entries.
- assertNull(estimator.snapshot());
+ assertThat(estimator.snapshot()).isNull();
// Count increment correctly by 1
estimator.insert(1337);
- assertEquals(estimator.getCount(), 1);
+ assertThat(estimator.getCount()).isOne();
estimator.snapshot();
- assertEquals(estimator.getSampleCount(), 1);
+ assertThat(estimator.getSampleCount()).isOne();
- assertEquals(
+ assertThat(estimator.toString()).isEqualTo(
"50.00 %ile +/- 5.00%: 1337\n" +
"75.00 %ile +/- 2.50%: 1337\n" +
"90.00 %ile +/- 1.00%: 1337\n" +
"95.00 %ile +/- 0.50%: 1337\n" +
- "99.00 %ile +/- 0.10%: 1337", estimator.toString());
+ "99.00 %ile +/- 0.10%: 1337");
}
/**
@@ -79,9 +79,9 @@ public void testClear() throws IOException {
estimator.insert(i);
}
estimator.clear();
- assertEquals(estimator.getCount(), 0);
- assertEquals(estimator.getSampleCount(), 0);
- assertNull(estimator.snapshot());
+ assertThat(estimator.getCount()).isZero();
+ assertThat(estimator.getSampleCount()).isZero();
+ assertThat(estimator.snapshot()).isNull();
}
/**
@@ -113,8 +113,8 @@ public void testQuantileError() throws IOException {
System.out
.println(String.format("Expected %d with error %d, estimated %d",
actual, error, estimate));
- assertTrue(estimate <= actual + error);
- assertTrue(estimate >= actual - error);
+ assertThat(estimate <= actual + error).isTrue();
+ assertThat(estimate >= actual - error).isTrue();
}
}
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/net/TestNetUtils.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/net/TestNetUtils.java
index 62bd1b142e2da..b11b1e96ded59 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/net/TestNetUtils.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/net/TestNetUtils.java
@@ -279,11 +279,9 @@ public void testWrapKerbAuthException() throws Throwable {
@Test
public void testWrapIOEWithNoStringConstructor() throws Throwable {
IOException e = new CharacterCodingException();
- IOException wrapped = verifyExceptionClass(e, IOException.class);
- assertInException(wrapped, "Failed on local exception");
- assertNotInException(wrapped, NetUtils.HADOOP_WIKI);
- assertInException(wrapped, "Host Details ");
- assertRemoteDetailsIncluded(wrapped);
+ IOException wrapped =
+ verifyExceptionClass(e, CharacterCodingException.class);
+ assertEquals(null, wrapped.getMessage());
}
@Test
@@ -295,11 +293,8 @@ private TestIOException(String cause){
}
}
IOException e = new TestIOException();
- IOException wrapped = verifyExceptionClass(e, IOException.class);
- assertInException(wrapped, "Failed on local exception");
- assertNotInException(wrapped, NetUtils.HADOOP_WIKI);
- assertInException(wrapped, "Host Details ");
- assertRemoteDetailsIncluded(wrapped);
+ IOException wrapped = verifyExceptionClass(e, TestIOException.class);
+ assertEquals(null, wrapped.getMessage());
}
@Test
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestGroupsCaching.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestGroupsCaching.java
index bba81522a4138..4c471da4e8c35 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestGroupsCaching.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestGroupsCaching.java
@@ -42,11 +42,10 @@
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.CommonConfigurationKeys;
-import org.apache.hadoop.security.Groups;
-import org.apache.hadoop.security.ShellBasedUnixGroupsMapping;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static org.assertj.core.api.Assertions.assertThat;
public class TestGroupsCaching {
public static final Logger TESTLOG =
@@ -494,7 +493,7 @@ public void testThreadNotBlockedWhenExpiredEntryExistsWithBackgroundRefresh()
// Now get the cache entry - it should return immediately
// with the old value and the cache will not have completed
// a request to getGroups yet.
- assertEquals(groups.getGroups("me").size(), 2);
+ assertThat(groups.getGroups("me").size()).isEqualTo(2);
assertEquals(startingRequestCount, FakeGroupMapping.getRequestCount());
// Now sleep for over the delay time and the request count should
@@ -502,7 +501,7 @@ public void testThreadNotBlockedWhenExpiredEntryExistsWithBackgroundRefresh()
Thread.sleep(110);
assertEquals(startingRequestCount + 1, FakeGroupMapping.getRequestCount());
// Another call to get groups should give 3 groups instead of 2
- assertEquals(groups.getGroups("me").size(), 3);
+ assertThat(groups.getGroups("me").size()).isEqualTo(3);
}
@Test
@@ -532,7 +531,7 @@ public void testThreadBlockedWhenExpiredEntryExistsWithoutBackgroundRefresh()
// Now get the cache entry - it should block and return the new
// 3 group value
- assertEquals(groups.getGroups("me").size(), 3);
+ assertThat(groups.getGroups("me").size()).isEqualTo(3);
assertEquals(startingRequestCount + 1, FakeGroupMapping.getRequestCount());
}
@@ -567,7 +566,7 @@ public void testExceptionOnBackgroundRefreshHandled() throws Exception {
// Now get the cache entry - it should return immediately
// with the old value and the cache will not have completed
// a request to getGroups yet.
- assertEquals(groups.getGroups("me").size(), 2);
+ assertThat(groups.getGroups("me").size()).isEqualTo(2);
assertEquals(startingRequestCount, FakeGroupMapping.getRequestCount());
// Resume the getGroups operation and the cache can get refreshed
FakeGroupMapping.resume();
@@ -577,14 +576,14 @@ public void testExceptionOnBackgroundRefreshHandled() throws Exception {
waitForGroupCounters(groups, 0, 0, 0, 1);
FakeGroupMapping.setThrowException(false);
assertEquals(startingRequestCount + 1, FakeGroupMapping.getRequestCount());
- assertEquals(groups.getGroups("me").size(), 2);
+ assertThat(groups.getGroups("me").size()).isEqualTo(2);
// Now the 3rd call to getGroups above will have kicked off
// another refresh that updates the cache, since it no longer gives
// exception, we now expect the counter for success is 1.
waitForGroupCounters(groups, 0, 0, 1, 1);
assertEquals(startingRequestCount + 2, FakeGroupMapping.getRequestCount());
- assertEquals(groups.getGroups("me").size(), 3);
+ assertThat(groups.getGroups("me").size()).isEqualTo(3);
}
@@ -613,7 +612,7 @@ public void testEntriesExpireIfBackgroundRefreshFails() throws Exception {
// be triggered which will fail to update the key, but the keys old value
// will be retrievable until it is evicted after about 10 seconds.
for(int i=0; i<9; i++) {
- assertEquals(groups.getGroups("me").size(), 2);
+ assertThat(groups.getGroups("me").size()).isEqualTo(2);
timer.advance(1 * 1000);
}
// Wait until the 11th second. The call to getGroups should throw
@@ -631,7 +630,7 @@ public void testEntriesExpireIfBackgroundRefreshFails() throws Exception {
// Finally check groups are retrieve again after FakeGroupMapping
// stops throw exceptions
FakeGroupMapping.setThrowException(false);
- assertEquals(groups.getGroups("me").size(), 2);
+ assertThat(groups.getGroups("me").size()).isEqualTo(2);
}
@Test
@@ -725,14 +724,14 @@ public void testExceptionCallingLoadWithoutBackgroundRefreshReturnsOldValue()
FakeGroupMapping.clearBlackList();
// First populate the cash
- assertEquals(groups.getGroups("me").size(), 2);
+ assertThat(groups.getGroups("me").size()).isEqualTo(2);
// Advance the timer so a refresh is required
timer.advance(2 * 1000);
// This call should throw an exception
FakeGroupMapping.setThrowException(true);
- assertEquals(groups.getGroups("me").size(), 2);
+ assertThat(groups.getGroups("me").size()).isEqualTo(2);
}
@Test
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestShellBasedIdMapping.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestShellBasedIdMapping.java
index d589c3a34677e..e6fdc2bcdfbd4 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestShellBasedIdMapping.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestShellBasedIdMapping.java
@@ -35,6 +35,8 @@
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
+import static org.assertj.core.api.Assertions.assertThat;
+
public class TestShellBasedIdMapping {
private static final Map EMPTY_PASS_THROUGH_MAP =
@@ -295,18 +297,19 @@ public void testIdOutOfIntegerRange() throws IOException {
@Test
public void testUserUpdateSetting() throws IOException {
ShellBasedIdMapping iug = new ShellBasedIdMapping(new Configuration());
- assertEquals(iug.getTimeout(),
+ assertThat(iug.getTimeout()).isEqualTo(
IdMappingConstant.USERGROUPID_UPDATE_MILLIS_DEFAULT);
Configuration conf = new Configuration();
conf.setLong(IdMappingConstant.USERGROUPID_UPDATE_MILLIS_KEY, 0);
iug = new ShellBasedIdMapping(conf);
- assertEquals(iug.getTimeout(), IdMappingConstant.USERGROUPID_UPDATE_MILLIS_MIN);
+ assertThat(iug.getTimeout()).isEqualTo(
+ IdMappingConstant.USERGROUPID_UPDATE_MILLIS_MIN);
conf.setLong(IdMappingConstant.USERGROUPID_UPDATE_MILLIS_KEY,
IdMappingConstant.USERGROUPID_UPDATE_MILLIS_DEFAULT * 2);
iug = new ShellBasedIdMapping(conf);
- assertEquals(iug.getTimeout(),
+ assertThat(iug.getTimeout()).isEqualTo(
IdMappingConstant.USERGROUPID_UPDATE_MILLIS_DEFAULT * 2);
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestUGIWithSecurityOn.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestUGIWithSecurityOn.java
deleted file mode 100644
index 028cc38f1b358..0000000000000
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestUGIWithSecurityOn.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/**
- * 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.security;
-
-import java.io.IOException;
-import java.security.PrivilegedAction;
-import java.util.Set;
-
-import javax.security.auth.kerberos.KerberosPrincipal;
-
-import org.junit.Assert;
-import static org.junit.Assert.*;
-
-
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
-import org.junit.Assume;
-import org.junit.Before;
-import org.junit.Test;
-
-public class TestUGIWithSecurityOn {
-
- public static boolean isKdcRunning() {
- String startKdc = System.getProperty("startKdc");
- if(startKdc == null || !startKdc.equals("true")) {
- return false;
- }
- return true;
- }
-
- @Before
- public void testKdcRunning() {
- //Tests are skipped if KDC is not running
- Assume.assumeTrue(isKdcRunning());
- }
- @Test
- public void testLogin() throws IOException {
- String nn1keyTabFilepath = System.getProperty("kdc.resource.dir")
- + "/keytabs/nn1.keytab";
- String user1keyTabFilepath = System.getProperty("kdc.resource.dir")
- + "/keytabs/user1.keytab";
- Configuration conf = new Configuration();
- SecurityUtil.setAuthenticationMethod(AuthenticationMethod.KERBEROS, conf);
- UserGroupInformation.setConfiguration(conf);
-
- UserGroupInformation ugiNn = UserGroupInformation
- .loginUserFromKeytabAndReturnUGI("nn1/localhost@EXAMPLE.COM",
- nn1keyTabFilepath);
- UserGroupInformation ugiDn = UserGroupInformation
- .loginUserFromKeytabAndReturnUGI("user1@EXAMPLE.COM",
- user1keyTabFilepath);
-
- Assert.assertEquals(AuthenticationMethod.KERBEROS,
- ugiNn.getAuthenticationMethod());
- Assert.assertEquals(AuthenticationMethod.KERBEROS,
- ugiDn.getAuthenticationMethod());
-
- try {
- UserGroupInformation
- .loginUserFromKeytabAndReturnUGI("bogus@EXAMPLE.COM",
- nn1keyTabFilepath);
- Assert.fail("Login should have failed");
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- }
-
- @Test
- public void testGetUGIFromKerberosSubject() throws IOException {
- String user1keyTabFilepath = System.getProperty("kdc.resource.dir")
- + "/keytabs/user1.keytab";
-
- UserGroupInformation ugi = UserGroupInformation
- .loginUserFromKeytabAndReturnUGI("user1@EXAMPLE.COM",
- user1keyTabFilepath);
- Set principals = ugi.getSubject().getPrincipals(
- KerberosPrincipal.class);
- if (principals.isEmpty()) {
- Assert.fail("There should be a kerberos principal in the subject.");
- }
- else {
- UserGroupInformation ugi2 = UserGroupInformation.getUGIFromSubject(
- ugi.getSubject());
- if (ugi2 != null) {
- ugi2.doAs(new PrivilegedAction() {
-
- @Override
- public Object run() {
- try {
- UserGroupInformation ugi3 = UserGroupInformation.getCurrentUser();
- String doAsUserName = ugi3.getUserName();
- assertEquals(doAsUserName, "user1@EXAMPLE.COM");
- System.out.println("DO AS USERNAME: " + doAsUserName);
- } catch (IOException e) {
- e.printStackTrace();
- }
- return null;
- }
- });
- }
- }
- }
-}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/alias/TestCredShell.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/alias/TestCredShell.java
index 569fe738a01e1..bf72b52b32066 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/alias/TestCredShell.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/alias/TestCredShell.java
@@ -32,6 +32,7 @@
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.security.ProviderUtils;
import org.apache.hadoop.test.GenericTestUtils;
+import org.assertj.core.api.Assertions;
import org.junit.Before;
import org.junit.Test;
@@ -43,6 +44,11 @@ public class TestCredShell {
/* The default JCEKS provider - for testing purposes */
private String jceksProvider;
+ private void assertOutputContains(String expected) {
+ Assertions.assertThat(outContent.toString())
+ .contains(expected);
+ }
+
@Before
public void setup() throws Exception {
System.setOut(new PrintStream(outContent));
@@ -172,15 +178,28 @@ public void testPromptForCredential() throws Exception {
shell.setPasswordReader(new MockPasswordReader(passwords));
rc = shell.run(args1);
assertEquals(0, rc);
- assertTrue(outContent.toString().contains("credential1 has been successfully " +
- "created."));
-
- String[] args2 = {"delete", "credential1", "-f", "-provider",
+ assertOutputContains("credential1 has been successfully created.");
+
+ String[] args2 = {"check", "credential1", "-provider",
jceksProvider};
+ ArrayList password = new ArrayList();
+ password.add("p@ssw0rd");
+ shell.setPasswordReader(new MockPasswordReader(password));
rc = shell.run(args2);
assertEquals(0, rc);
- assertTrue(outContent.toString().contains("credential1 has been successfully " +
- "deleted."));
+ assertOutputContains("Password match success for credential1.");
+ ArrayList passwordError = new ArrayList();
+ passwordError.add("p@ssw0rderr");
+ shell.setPasswordReader(new MockPasswordReader(password));
+ rc = shell.run(args2);
+ assertEquals(0, rc);
+ assertOutputContains("Password match failed for credential1.");
+
+ String[] args3 = {"delete", "credential1", "-f", "-provider",
+ jceksProvider};
+ rc = shell.run(args3);
+ assertEquals(0, rc);
+ assertOutputContains("credential1 has been successfully deleted.");
}
public class MockPasswordReader extends CredentialShell.PasswordReader {
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/authentication/server/TestProxyUserAuthenticationFilter.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/authentication/server/TestProxyUserAuthenticationFilter.java
new file mode 100644
index 0000000000000..16c0e1eb112ac
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/authentication/server/TestProxyUserAuthenticationFilter.java
@@ -0,0 +1,125 @@
+/**
+ * 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.security.authentication.server;
+
+import java.security.Principal;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.FilterConfig;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletResponse;
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import org.glassfish.grizzly.servlet.HttpServletResponseImpl;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+
+/**
+ * Test ProxyUserAuthenticationFilter with doAs Request Parameter.
+ */
+public class TestProxyUserAuthenticationFilter {
+
+ private String actualUser;
+
+ private static class DummyFilterConfig implements FilterConfig {
+ private final Map map;
+
+ DummyFilterConfig(Map map) {
+ this.map = map;
+ }
+
+ @Override
+ public String getFilterName() {
+ return "dummy";
+ }
+
+ @Override
+ public String getInitParameter(String param) {
+ return map.get(param);
+ }
+
+ @Override
+ public Enumeration getInitParameterNames() {
+ return Collections.enumeration(map.keySet());
+ }
+
+ @Override
+ public ServletContext getServletContext() {
+ ServletContext context = Mockito.mock(ServletContext.class);
+ Mockito.when(context.getAttribute(
+ AuthenticationFilter.SIGNER_SECRET_PROVIDER_ATTRIBUTE))
+ .thenReturn(null);
+ return context;
+ }
+ }
+
+ private class HttpServletResponseForTest extends HttpServletResponseImpl {
+
+ }
+
+
+ @Test(timeout = 10000)
+ public void testFilter() throws Exception {
+ Map params = new HashMap();
+ params.put("proxyuser.knox.users", "testuser");
+ params.put("proxyuser.knox.hosts", "127.0.0.1");
+ params.put("type", "simple");
+
+ FilterConfig config = new DummyFilterConfig(params);
+
+ FilterChain chain = new FilterChain() {
+ @Override
+ public void doFilter(ServletRequest servletRequest,
+ ServletResponse servletResponse) {
+ HttpServletRequest request = (HttpServletRequest) servletRequest;
+ actualUser = request.getRemoteUser();
+ }
+ };
+
+ ProxyUserAuthenticationFilter testFilter =
+ new ProxyUserAuthenticationFilter();
+ testFilter.init(config);
+
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ Mockito.when(request.getRemoteUser()).thenReturn("knox");
+ Mockito.when(request.getParameter("doas")).thenReturn("testuser");
+ Mockito.when(request.getRemoteAddr()).thenReturn("127.0.0.1");
+ Mockito.when(request.getUserPrincipal()).thenReturn(new Principal() {
+ @Override
+ public String getName() {
+ return "knox@EXAMPLE.COM";
+ }
+ });
+
+ HttpServletResponseForTest response = new HttpServletResponseForTest();
+
+ testFilter.doFilter(chain, request, response);
+
+ assertThat(actualUser).isEqualTo("testuser");
+ }
+
+
+}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/authorize/TestAccessControlList.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/authorize/TestAccessControlList.java
index 7039001b8fe45..8e1b82bea9605 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/authorize/TestAccessControlList.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/authorize/TestAccessControlList.java
@@ -17,9 +17,7 @@
*/
package org.apache.hadoop.security.authorize;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.Collection;
@@ -37,6 +35,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -187,29 +186,29 @@ public void testAclString() {
AccessControlList acl;
acl = new AccessControlList("*");
- assertEquals("All users are allowed", acl.toString());
+ assertThat(acl.toString()).isEqualTo("All users are allowed");
validateGetAclString(acl);
acl = new AccessControlList(" ");
- assertEquals("No users are allowed", acl.toString());
+ assertThat(acl.toString()).isEqualTo("No users are allowed");
acl = new AccessControlList("user1,user2");
- assertEquals("Users [user1, user2] are allowed", acl.toString());
+ assertThat(acl.toString()).isEqualTo("Users [user1, user2] are allowed");
validateGetAclString(acl);
acl = new AccessControlList("user1,user2 ");// with space
- assertEquals("Users [user1, user2] are allowed", acl.toString());
+ assertThat(acl.toString()).isEqualTo("Users [user1, user2] are allowed");
validateGetAclString(acl);
acl = new AccessControlList(" group1,group2");
- assertTrue(acl.toString().equals(
- "Members of the groups [group1, group2] are allowed"));
+ assertThat(acl.toString()).isEqualTo(
+ "Members of the groups [group1, group2] are allowed");
validateGetAclString(acl);
acl = new AccessControlList("user1,user2 group1,group2");
- assertTrue(acl.toString().equals(
+ assertThat(acl.toString()).isEqualTo(
"Users [user1, user2] and " +
- "members of the groups [group1, group2] are allowed"));
+ "members of the groups [group1, group2] are allowed");
validateGetAclString(acl);
}
@@ -228,45 +227,45 @@ public void testAccessControlList() throws Exception {
acl = new AccessControlList("drwho tardis");
users = acl.getUsers();
- assertEquals(users.size(), 1);
- assertEquals(users.iterator().next(), "drwho");
+ assertThat(users.size()).isOne();
+ assertThat(users.iterator().next()).isEqualTo("drwho");
groups = acl.getGroups();
- assertEquals(groups.size(), 1);
- assertEquals(groups.iterator().next(), "tardis");
+ assertThat(groups.size()).isOne();
+ assertThat(groups.iterator().next()).isEqualTo("tardis");
acl = new AccessControlList("drwho");
users = acl.getUsers();
- assertEquals(users.size(), 1);
- assertEquals(users.iterator().next(), "drwho");
+ assertThat(users.size()).isOne();
+ assertThat(users.iterator().next()).isEqualTo("drwho");
groups = acl.getGroups();
- assertEquals(groups.size(), 0);
+ assertThat(groups.size()).isZero();
acl = new AccessControlList("drwho ");
users = acl.getUsers();
- assertEquals(users.size(), 1);
- assertEquals(users.iterator().next(), "drwho");
+ assertThat(users.size()).isOne();
+ assertThat(users.iterator().next()).isEqualTo("drwho");
groups = acl.getGroups();
- assertEquals(groups.size(), 0);
+ assertThat(groups.size()).isZero();
acl = new AccessControlList(" tardis");
users = acl.getUsers();
- assertEquals(users.size(), 0);
+ assertThat(users.size()).isZero();
groups = acl.getGroups();
- assertEquals(groups.size(), 1);
- assertEquals(groups.iterator().next(), "tardis");
+ assertThat(groups.size()).isOne();
+ assertThat(groups.iterator().next()).isEqualTo("tardis");
Iterator iter;
acl = new AccessControlList("drwho,joe tardis, users");
users = acl.getUsers();
- assertEquals(users.size(), 2);
+ assertThat(users.size()).isEqualTo(2);
iter = users.iterator();
- assertEquals(iter.next(), "drwho");
- assertEquals(iter.next(), "joe");
+ assertThat(iter.next()).isEqualTo("drwho");
+ assertThat(iter.next()).isEqualTo("joe");
groups = acl.getGroups();
- assertEquals(groups.size(), 2);
+ assertThat(groups.size()).isEqualTo(2);
iter = groups.iterator();
- assertEquals(iter.next(), "tardis");
- assertEquals(iter.next(), "users");
+ assertThat(iter.next()).isEqualTo("tardis");
+ assertThat(iter.next()).isEqualTo("users");
}
/**
@@ -278,58 +277,58 @@ public void testAddRemoveAPI() {
Collection users;
Collection groups;
acl = new AccessControlList(" ");
- assertEquals(0, acl.getUsers().size());
- assertEquals(0, acl.getGroups().size());
- assertEquals(" ", acl.getAclString());
+ assertThat(acl.getUsers().size()).isZero();
+ assertThat(acl.getGroups().size()).isZero();
+ assertThat(acl.getAclString()).isEqualTo(" ");
acl.addUser("drwho");
users = acl.getUsers();
- assertEquals(users.size(), 1);
- assertEquals(users.iterator().next(), "drwho");
- assertEquals("drwho ", acl.getAclString());
+ assertThat(users.size()).isOne();
+ assertThat(users.iterator().next()).isEqualTo("drwho");
+ assertThat(acl.getAclString()).isEqualTo("drwho ");
acl.addGroup("tardis");
groups = acl.getGroups();
- assertEquals(groups.size(), 1);
- assertEquals(groups.iterator().next(), "tardis");
- assertEquals("drwho tardis", acl.getAclString());
+ assertThat(groups.size()).isOne();
+ assertThat(groups.iterator().next()).isEqualTo("tardis");
+ assertThat(acl.getAclString()).isEqualTo("drwho tardis");
acl.addUser("joe");
acl.addGroup("users");
users = acl.getUsers();
- assertEquals(users.size(), 2);
+ assertThat(users.size()).isEqualTo(2);
Iterator iter = users.iterator();
- assertEquals(iter.next(), "drwho");
- assertEquals(iter.next(), "joe");
+ assertThat(iter.next()).isEqualTo("drwho");
+ assertThat(iter.next()).isEqualTo("joe");
groups = acl.getGroups();
- assertEquals(groups.size(), 2);
+ assertThat(groups.size()).isEqualTo(2);
iter = groups.iterator();
- assertEquals(iter.next(), "tardis");
- assertEquals(iter.next(), "users");
- assertEquals("drwho,joe tardis,users", acl.getAclString());
+ assertThat(iter.next()).isEqualTo("tardis");
+ assertThat(iter.next()).isEqualTo("users");
+ assertThat(acl.getAclString()).isEqualTo("drwho,joe tardis,users");
acl.removeUser("joe");
acl.removeGroup("users");
users = acl.getUsers();
- assertEquals(users.size(), 1);
+ assertThat(users.size()).isOne();
assertFalse(users.contains("joe"));
groups = acl.getGroups();
- assertEquals(groups.size(), 1);
+ assertThat(groups.size()).isOne();
assertFalse(groups.contains("users"));
- assertEquals("drwho tardis", acl.getAclString());
+ assertThat(acl.getAclString()).isEqualTo("drwho tardis");
acl.removeGroup("tardis");
groups = acl.getGroups();
- assertEquals(0, groups.size());
+ assertThat(groups.size()).isZero();
assertFalse(groups.contains("tardis"));
- assertEquals("drwho ", acl.getAclString());
+ assertThat(acl.getAclString()).isEqualTo("drwho ");
acl.removeUser("drwho");
- assertEquals(0, users.size());
+ assertThat(users.size()).isZero();
assertFalse(users.contains("drwho"));
- assertEquals(0, acl.getGroups().size());
- assertEquals(0, acl.getUsers().size());
- assertEquals(" ", acl.getAclString());
+ assertThat(acl.getGroups().size()).isZero();
+ assertThat(acl.getUsers().size()).isZero();
+ assertThat(acl.getAclString()).isEqualTo(" ");
}
/**
@@ -345,8 +344,8 @@ public void testAddRemoveWildCard() {
} catch (Throwable t) {
th = t;
}
- assertNotNull(th);
- assertTrue(th instanceof IllegalArgumentException);
+ assertThat(th).isNotNull();
+ assertThat(th).isInstanceOf(IllegalArgumentException.class);
th = null;
try {
@@ -354,24 +353,24 @@ public void testAddRemoveWildCard() {
} catch (Throwable t) {
th = t;
}
- assertNotNull(th);
- assertTrue(th instanceof IllegalArgumentException);
+ assertThat(th).isNotNull();
+ assertThat(th).isInstanceOf(IllegalArgumentException.class);
th = null;
try {
acl.removeUser(" * ");
} catch (Throwable t) {
th = t;
}
- assertNotNull(th);
- assertTrue(th instanceof IllegalArgumentException);
+ assertThat(th).isNotNull();
+ assertThat(th).isInstanceOf(IllegalArgumentException.class);
th = null;
try {
acl.removeGroup(" * ");
} catch (Throwable t) {
th = t;
}
- assertNotNull(th);
- assertTrue(th instanceof IllegalArgumentException);
+ assertThat(th).isNotNull();
+ assertThat(th).isInstanceOf(IllegalArgumentException.class);
}
/**
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/authorize/TestServiceAuthorization.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/authorize/TestServiceAuthorization.java
index c473c502da824..d02fe604d79e3 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/authorize/TestServiceAuthorization.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/authorize/TestServiceAuthorization.java
@@ -20,13 +20,18 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
+import java.lang.annotation.Annotation;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.CommonConfigurationKeys;
import org.apache.hadoop.ipc.TestRPC.TestProtocol;
+import org.apache.hadoop.security.KerberosInfo;
+import org.apache.hadoop.security.SecurityInfo;
+import org.apache.hadoop.security.SecurityUtil;
import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.security.token.TokenInfo;
import org.junit.Test;
public class TestServiceAuthorization {
@@ -52,6 +57,53 @@ public Service[] getServices() {
}
}
+ private static class CustomSecurityInfo extends SecurityInfo {
+ @Override
+ public KerberosInfo getKerberosInfo(Class> protocol,
+ Configuration conf) {
+ return new KerberosInfo() {
+ @Override
+ public Class extends Annotation> annotationType() {
+ return null;
+ }
+ @Override
+ public String serverPrincipal() {
+ return null;
+ }
+ @Override
+ public String clientPrincipal() {
+ return "dfs.datanode.kerberos.principal";
+ }
+ };
+ }
+
+ @Override
+ public TokenInfo getTokenInfo(Class> protocol, Configuration conf) {
+ return null;
+ }
+ }
+
+ @Test
+ public void testWithClientPrincipalOnUnsecureMode()
+ throws UnknownHostException {
+ UserGroupInformation hdfsUser = UserGroupInformation.createUserForTesting(
+ "hdfs", new String[] {"hadoop"});
+ ServiceAuthorizationManager serviceAuthorizationManager =
+ new ServiceAuthorizationManager();
+ SecurityUtil.setSecurityInfoProviders(new CustomSecurityInfo());
+
+ Configuration conf = new Configuration();
+ conf.set("dfs.datanode.kerberos.principal", "dn/_HOST@EXAMPLE.COM");
+ conf.set(ACL_CONFIG, "user1 hadoop");
+ serviceAuthorizationManager.refresh(conf, new TestPolicyProvider());
+ try {
+ serviceAuthorizationManager.authorize(hdfsUser, TestProtocol.class, conf,
+ InetAddress.getByName(ADDRESS));
+ } catch (AuthorizationException e) {
+ fail();
+ }
+ }
+
@Test
public void testDefaultAcl() {
ServiceAuthorizationManager serviceAuthorizationManager =
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/http/TestXFrameOptionsFilter.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/http/TestXFrameOptionsFilter.java
index 1c1d97d7cac7c..0f9f691322e70 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/http/TestXFrameOptionsFilter.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/http/TestXFrameOptionsFilter.java
@@ -31,6 +31,7 @@
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
/**
@@ -84,8 +85,9 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
filter.doFilter(request, response, chain);
- Assert.assertEquals("X-Frame-Options count not equal to 1.",
- headers.size(), 1);
+ assertThat(headers.size())
+ .withFailMessage("X-Frame-Options count not equal to 1.")
+ .isOne();
}
@Test
@@ -138,10 +140,12 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
filter.doFilter(request, response, chain);
- Assert.assertEquals("X-Frame-Options count not equal to 1.",
- headers.size(), 1);
+ assertThat(headers.size())
+ .withFailMessage("X-Frame-Options count not equal to 1.")
+ .isOne();
- Assert.assertEquals("X-Frame-Options count not equal to 1.",
- headers.toArray()[0], "SAMEORIGIN");
+ assertThat(headers.toArray()[0])
+ .withFailMessage("X-Frame-Options count not equal to 1.")
+ .isEqualTo("SAMEORIGIN");
}
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/ssl/TestDelegatingSSLSocketFactory.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/ssl/TestDelegatingSSLSocketFactory.java
new file mode 100644
index 0000000000000..f19f65b18cfe6
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/ssl/TestDelegatingSSLSocketFactory.java
@@ -0,0 +1,57 @@
+/*
+ * 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.security.ssl;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.apache.hadoop.util.NativeCodeLoader;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assume.assumeTrue;
+
+/**
+ * Tests for {@link DelegatingSSLSocketFactory}.
+ */
+public class TestDelegatingSSLSocketFactory {
+
+ @Test
+ public void testOpenSSL() throws IOException {
+ assumeTrue("Unable to load native libraries",
+ NativeCodeLoader.isNativeCodeLoaded());
+ assumeTrue("Build was not compiled with support for OpenSSL",
+ NativeCodeLoader.buildSupportsOpenssl());
+ DelegatingSSLSocketFactory.initializeDefaultFactory(
+ DelegatingSSLSocketFactory.SSLChannelMode.OpenSSL);
+ assertThat(DelegatingSSLSocketFactory.getDefaultFactory()
+ .getProviderName()).contains("openssl");
+ }
+
+ @Test
+ public void testJSEENoGCMJava8() throws IOException {
+ assumeTrue("Not running on Java 8",
+ System.getProperty("java.version").startsWith("1.8"));
+ DelegatingSSLSocketFactory.initializeDefaultFactory(
+ DelegatingSSLSocketFactory.SSLChannelMode.Default_JSSE);
+ assertThat(Arrays.stream(DelegatingSSLSocketFactory.getDefaultFactory()
+ .getSupportedCipherSuites())).noneMatch("GCM"::contains);
+ }
+}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/ssl/TestOpenSSLSocketFactory.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/ssl/TestOpenSSLSocketFactory.java
deleted file mode 100644
index ea881e990b934..0000000000000
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/ssl/TestOpenSSLSocketFactory.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.security.ssl;
-
-import java.io.IOException;
-import java.util.Arrays;
-
-import org.junit.Test;
-
-import org.apache.hadoop.util.NativeCodeLoader;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assume.assumeTrue;
-
-/**
- * Tests for {@link OpenSSLSocketFactory}.
- */
-public class TestOpenSSLSocketFactory {
-
- @Test
- public void testOpenSSL() throws IOException {
- assumeTrue(NativeCodeLoader.buildSupportsOpenssl());
- OpenSSLSocketFactory.initializeDefaultFactory(
- OpenSSLSocketFactory.SSLChannelMode.OpenSSL);
- assertThat(OpenSSLSocketFactory.getDefaultFactory()
- .getProviderName()).contains("openssl");
- }
-
- @Test
- public void testJSEEJava8() throws IOException {
- assumeTrue(System.getProperty("java.version").startsWith("1.8"));
- OpenSSLSocketFactory.initializeDefaultFactory(
- OpenSSLSocketFactory.SSLChannelMode.Default_JSSE);
- assertThat(Arrays.stream(OpenSSLSocketFactory.getDefaultFactory()
- .getSupportedCipherSuites())).noneMatch("GCM"::contains);
- }
-}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/TestDelegationToken.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/TestDelegationToken.java
index df685cf681a2d..8bc881ae5d1da 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/TestDelegationToken.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/TestDelegationToken.java
@@ -50,6 +50,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.*;
public class TestDelegationToken {
@@ -266,17 +267,17 @@ public void testDelegationTokenCount() throws Exception {
3*1000, 1*1000, 3600000);
try {
dtSecretManager.startThreads();
- Assert.assertEquals(dtSecretManager.getCurrentTokensSize(), 0);
+ assertThat(dtSecretManager.getCurrentTokensSize()).isZero();
final Token token1 =
generateDelegationToken(dtSecretManager, "SomeUser", "JobTracker");
- Assert.assertEquals(dtSecretManager.getCurrentTokensSize(), 1);
+ assertThat(dtSecretManager.getCurrentTokensSize()).isOne();
final Token token2 =
generateDelegationToken(dtSecretManager, "SomeUser", "JobTracker");
- Assert.assertEquals(dtSecretManager.getCurrentTokensSize(), 2);
+ assertThat(dtSecretManager.getCurrentTokensSize()).isEqualTo(2);
dtSecretManager.cancelToken(token1, "JobTracker");
- Assert.assertEquals(dtSecretManager.getCurrentTokensSize(), 1);
+ assertThat(dtSecretManager.getCurrentTokensSize()).isOne();
dtSecretManager.cancelToken(token2, "JobTracker");
- Assert.assertEquals(dtSecretManager.getCurrentTokensSize(), 0);
+ assertThat(dtSecretManager.getCurrentTokensSize()).isZero();
} finally {
dtSecretManager.stopThreads();
}
@@ -386,7 +387,7 @@ public void testRollMasterKey() throws Exception {
//after rolling, the length of the keys list must increase
int currNumKeys = dtSecretManager.getAllKeys().length;
- Assert.assertEquals((currNumKeys - prevNumKeys) >= 1, true);
+ assertThat(currNumKeys - prevNumKeys).isGreaterThanOrEqualTo(1);
//after rolling, the token that was generated earlier must
//still be valid (retrievePassword will fail if the token
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/web/TestWebDelegationToken.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/web/TestWebDelegationToken.java
index 1fcc6faac646a..9b5bd22dbe6ac 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/web/TestWebDelegationToken.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/web/TestWebDelegationToken.java
@@ -22,6 +22,7 @@
import org.apache.hadoop.io.Text;
import org.apache.hadoop.minikdc.MiniKdc;
import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.security.authentication.KerberosTestUtils;
import org.apache.hadoop.security.authentication.client.AuthenticationException;
import org.apache.hadoop.security.authentication.client.KerberosAuthenticator;
import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
@@ -743,12 +744,6 @@ private void testKerberosDelegationTokenAuthenticator(
final boolean doAs) throws Exception {
final String doAsUser = doAs ? OK_USER : null;
- // setting hadoop security to kerberos
- org.apache.hadoop.conf.Configuration conf =
- new org.apache.hadoop.conf.Configuration();
- conf.set("hadoop.security.authentication", "kerberos");
- UserGroupInformation.setConfiguration(conf);
-
File testDir = new File("target/" + UUID.randomUUID().toString());
Assert.assertTrue(testDir.mkdirs());
MiniKdc kdc = new MiniKdc(MiniKdc.createConf(), testDir);
@@ -759,6 +754,10 @@ private void testKerberosDelegationTokenAuthenticator(
context.addFilter(new FilterHolder(KDTAFilter.class), "/*",
EnumSet.of(DispatcherType.REQUEST));
context.addServlet(new ServletHolder(UserServlet.class), "/bar");
+ org.apache.hadoop.conf.Configuration conf =
+ new org.apache.hadoop.conf.Configuration();
+ conf.set("hadoop.security.authentication", "kerberos");
+ conf.set("java.security.krb5.realm", KerberosTestUtils.getRealm());
try {
kdc.start();
File keytabFile = new File(testDir, "test.keytab");
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/test/LambdaTestUtils.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/test/LambdaTestUtils.java
index c1b6cc4081e5c..db36154c158ac 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/test/LambdaTestUtils.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/test/LambdaTestUtils.java
@@ -575,6 +575,9 @@ private static String robustToString(Object o) {
if (o == null) {
return NULL_RESULT;
} else {
+ if (o instanceof String) {
+ return '"' + (String)o + '"';
+ }
try {
return o.toString();
} catch (Exception e) {
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestLightWeightResizableGSet.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestLightWeightResizableGSet.java
index 19f213d31a12b..c043d1e590e5d 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestLightWeightResizableGSet.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestLightWeightResizableGSet.java
@@ -27,7 +27,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import static org.junit.Assert.*;
+import static org.assertj.core.api.Assertions.assertThat;
/** Testing {@link LightWeightResizableGSet} */
public class TestLightWeightResizableGSet {
@@ -132,23 +132,23 @@ public void testBasicOperations() {
final LightWeightResizableGSet set =
new LightWeightResizableGSet();
- assertEquals(set.size(), 0);
+ assertThat(set.size()).isZero();
// put all elements
for (int i = 0; i < elements.length; i++) {
TestElement element = set.put(elements[i]);
- assertTrue(element == null);
+ assertThat(element).isNull();
}
// check the set size
- assertEquals(set.size(), elements.length);
+ assertThat(set.size()).isEqualTo(elements.length);
// check all elements exist in the set and the data is correct
for (int i = 0; i < elements.length; i++) {
- assertTrue(set.contains(elements[i]));
+ assertThat(set.contains(elements[i])).isTrue();
TestElement element = set.get(elements[i]);
- assertEquals(elements[i].getData(), element.getData());
+ assertThat(elements[i].getData()).isEqualTo(element.getData());
}
TestKey[] keys = getKeys(elements);
@@ -157,39 +157,38 @@ public void testBasicOperations() {
// update the set
for (int i = 0; i < newElements.length; i++) {
TestElement element = set.put(newElements[i]);
- assertTrue(element != null);
+ assertThat(element).isNotNull();
}
// check the set size
- assertEquals(set.size(), elements.length);
+ assertThat(set.size()).isEqualTo(elements.length);
// check all elements exist in the set and the data is updated to new value
for (int i = 0; i < keys.length; i++) {
- assertTrue(set.contains(keys[i]));
+ assertThat(set.contains(keys[i])).isTrue();
TestElement element = set.get(keys[i]);
- assertEquals(newElements[i].getData(), element.getData());
+ assertThat(newElements[i].getData()).isEqualTo(element.getData());
}
// test LightWeightHashGSet#values
Collection cElements = set.values();
- assertEquals(cElements.size(), elements.length);
+ assertThat(cElements.size()).isEqualTo(elements.length);
for (TestElement element : cElements) {
- assertTrue(set.contains(element));
+ assertThat(set.contains(element)).isTrue();
}
// remove elements
for (int i = 0; i < keys.length; i++) {
TestElement element = set.remove(keys[i]);
-
- assertTrue(element != null);
+ assertThat(element).isNotNull();
// the element should not exist after remove
- assertFalse(set.contains(keys[i]));
+ assertThat(set.contains(keys[i])).isFalse();
}
// check the set size
- assertEquals(set.size(), 0);
+ assertThat(set.size()).isZero();
}
@Test(timeout = 60000)
@@ -198,33 +197,33 @@ public void testRemoveAll() {
final LightWeightResizableGSet set =
new LightWeightResizableGSet();
- assertEquals(set.size(), 0);
+ assertThat(set.size()).isZero();
// put all elements
for (int i = 0; i < elements.length; i++) {
TestElement element = set.put(elements[i]);
- assertTrue(element == null);
+ assertThat(element).isNull();
}
// check the set size
- assertEquals(set.size(), elements.length);
+ assertThat(set.size()).isEqualTo(elements.length);
// remove all through clear
{
set.clear();
- assertEquals(set.size(), 0);
+ assertThat(set.size()).isZero();
// check all elements removed
for (int i = 0; i < elements.length; i++) {
- assertFalse(set.contains(elements[i]));
+ assertThat(set.contains(elements[i])).isFalse();
}
- assertFalse(set.iterator().hasNext());
+ assertThat(set.iterator().hasNext()).isFalse();
}
// put all elements back
for (int i = 0; i < elements.length; i++) {
TestElement element = set.put(elements[i]);
- assertTrue(element == null);
+ assertThat(element).isNull();
}
// remove all through iterator
@@ -232,22 +231,22 @@ public void testRemoveAll() {
for (Iterator iter = set.iterator(); iter.hasNext(); ) {
TestElement element = iter.next();
// element should be there before removing
- assertTrue(set.contains(element));
+ assertThat(set.contains(element)).isTrue();
iter.remove();
// element should not be there now
- assertFalse(set.contains(element));
+ assertThat(set.contains(element)).isFalse();
}
// the deleted elements should not be there
for (int i = 0; i < elements.length; i++) {
- assertFalse(set.contains(elements[i]));
+ assertThat(set.contains(elements[i])).isFalse();
}
// iterator should not have next
- assertFalse(set.iterator().hasNext());
+ assertThat(set.iterator().hasNext()).isFalse();
// check the set size
- assertEquals(set.size(), 0);
+ assertThat(set.size()).isZero();
}
}
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestNodeHealthScriptRunner.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestNodeHealthScriptRunner.java
index 8fc64d10a2952..2748c0b581a88 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestNodeHealthScriptRunner.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestNodeHealthScriptRunner.java
@@ -94,6 +94,8 @@ public void testNodeHealthScript() throws Exception {
String timeOutScript =
Shell.WINDOWS ? "@echo off\nping -n 4 127.0.0.1 >nul\necho \"I am fine\""
: "sleep 4\necho \"I am fine\"";
+ String exitCodeScript = "exit 127";
+
Configuration conf = new Configuration();
writeNodeHealthScriptFile(normalScript, true);
NodeHealthScriptRunner nodeHealthScriptRunner = new NodeHealthScriptRunner(
@@ -132,5 +134,12 @@ public void testNodeHealthScript() throws Exception {
Assert.assertEquals(
NodeHealthScriptRunner.NODE_HEALTH_SCRIPT_TIMED_OUT_MSG,
nodeHealthScriptRunner.getHealthReport());
+
+ // Exit code 127
+ writeNodeHealthScriptFile(exitCodeScript, true);
+ timerTask.run();
+ Assert.assertTrue("Node health status reported unhealthy",
+ nodeHealthScriptRunner.isHealthy());
+ Assert.assertEquals("", nodeHealthScriptRunner.getHealthReport());
}
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestProtoUtil.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestProtoUtil.java
index ab891b8f200d6..6b72089faab84 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestProtoUtil.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestProtoUtil.java
@@ -69,7 +69,7 @@ public void testVarInt() throws IOException {
private void doVarIntTest(int value) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
CodedOutputStream cout = CodedOutputStream.newInstance(baos);
- cout.writeRawVarint32(value);
+ cout.writeUInt32NoTag(value);
cout.flush();
DataInputStream dis = new DataInputStream(
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestShutdownHookManager.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestShutdownHookManager.java
index 03fa903170f2f..59430e8bd9453 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestShutdownHookManager.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestShutdownHookManager.java
@@ -21,7 +21,6 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
-import org.junit.After;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -43,13 +42,10 @@ public class TestShutdownHookManager {
LoggerFactory.getLogger(TestShutdownHookManager.class.getName());
/**
- * remove all the shutdown hooks so that they never get invoked later
- * on in this test process.
+ * A new instance of ShutdownHookManager to ensure parallel tests
+ * don't have shared context.
*/
- @After
- public void clearShutdownHooks() {
- ShutdownHookManager.get().clearShutdownHooks();
- }
+ private final ShutdownHookManager mgr = new ShutdownHookManager();
/**
* Verify hook registration, then execute the hook callback stage
@@ -58,7 +54,6 @@ public void clearShutdownHooks() {
*/
@Test
public void shutdownHookManager() {
- ShutdownHookManager mgr = ShutdownHookManager.get();
assertNotNull("No ShutdownHookManager", mgr);
assertEquals(0, mgr.getShutdownHooksInOrder().size());
Hook hook1 = new Hook("hook1", 0, false);
@@ -119,7 +114,7 @@ public void shutdownHookManager() {
// now execute the hook shutdown sequence
INVOCATION_COUNT.set(0);
LOG.info("invoking executeShutdown()");
- int timeouts = ShutdownHookManager.executeShutdown();
+ int timeouts = mgr.executeShutdown();
LOG.info("Shutdown completed");
assertEquals("Number of timed out hooks", 1, timeouts);
@@ -193,7 +188,6 @@ public void testShutdownTimeoutBadConfiguration() throws Throwable {
*/
@Test
public void testDuplicateRegistration() throws Throwable {
- ShutdownHookManager mgr = ShutdownHookManager.get();
Hook hook = new Hook("hook1", 0, false);
// add the hook
@@ -222,6 +216,21 @@ public void testDuplicateRegistration() throws Throwable {
}
+ @Test
+ public void testShutdownRemove() throws Throwable {
+ assertNotNull("No ShutdownHookManager", mgr);
+ assertEquals(0, mgr.getShutdownHooksInOrder().size());
+ Hook hook1 = new Hook("hook1", 0, false);
+ Hook hook2 = new Hook("hook2", 0, false);
+ mgr.addShutdownHook(hook1, 9); // create Hook1 with priority 9
+ assertTrue("No hook1", mgr.hasShutdownHook(hook1)); // hook1 lookup works
+ assertEquals(1, mgr.getShutdownHooksInOrder().size()); // 1 hook
+ assertFalse("Delete hook2 should not be allowed",
+ mgr.removeShutdownHook(hook2));
+ assertTrue("Can't delete hook1", mgr.removeShutdownHook(hook1));
+ assertEquals(0, mgr.getShutdownHooksInOrder().size());
+ }
+
private static final AtomicInteger INVOCATION_COUNT = new AtomicInteger();
/**
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/curator/TestChildReaper.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/curator/TestChildReaper.java
index 11b254fc697eb..960471841948c 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/curator/TestChildReaper.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/curator/TestChildReaper.java
@@ -26,13 +26,14 @@
import org.apache.curator.test.Timing;
import org.apache.zookeeper.data.Stat;
import org.junit.After;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.net.BindException;
import java.util.Random;
+import static org.assertj.core.api.Assertions.assertThat;
+
/**
* This is a copy of Curator 2.7.1's TestChildReaper class, with minor
* modifications to make it work with JUnit (some setup code taken from
@@ -90,7 +91,7 @@ public void testSomeNodes() throws Exception
timing.forWaiting().sleepABit();
Stat stat = client.checkExists().forPath("/test");
- Assert.assertEquals(stat.getNumChildren(), nonEmptyNodes);
+ assertThat(stat.getNumChildren()).isEqualTo(nonEmptyNodes);
}
finally
{
@@ -120,7 +121,7 @@ public void testSimple() throws Exception
timing.forWaiting().sleepABit();
Stat stat = client.checkExists().forPath("/test");
- Assert.assertEquals(stat.getNumChildren(), 0);
+ assertThat(stat.getNumChildren()).isZero();
}
finally
{
@@ -153,11 +154,11 @@ public void testMultiPath() throws Exception
timing.forWaiting().sleepABit();
Stat stat = client.checkExists().forPath("/test1");
- Assert.assertEquals(stat.getNumChildren(), 0);
+ assertThat(stat.getNumChildren()).isZero();
stat = client.checkExists().forPath("/test2");
- Assert.assertEquals(stat.getNumChildren(), 0);
+ assertThat(stat.getNumChildren()).isZero();
stat = client.checkExists().forPath("/test3");
- Assert.assertEquals(stat.getNumChildren(), 10);
+ assertThat(stat.getNumChildren()).isEqualTo(10);
}
finally
{
@@ -193,11 +194,11 @@ public void testNamespace() throws Exception
timing.forWaiting().sleepABit();
Stat stat = client.checkExists().forPath("/test");
- Assert.assertEquals(stat.getNumChildren(), 0);
+ assertThat(stat.getNumChildren()).isZero();
stat = client.usingNamespace(null).checkExists().forPath("/foo/test");
- Assert.assertNotNull(stat);
- Assert.assertEquals(stat.getNumChildren(), 0);
+ assertThat(stat).isNotNull();
+ assertThat(stat.getNumChildren()).isZero();
}
finally
{
diff --git a/hadoop-common-project/hadoop-common/src/test/proto/test.proto b/hadoop-common-project/hadoop-common/src/test/proto/test.proto
index 37e9a0bf7aacd..2c41aa2bc7c67 100644
--- a/hadoop-common-project/hadoop-common/src/test/proto/test.proto
+++ b/hadoop-common-project/hadoop-common/src/test/proto/test.proto
@@ -15,7 +15,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
+syntax = "proto2";
option java_package = "org.apache.hadoop.ipc.protobuf";
option java_outer_classname = "TestProtos";
option java_generate_equals_and_hash = true;
diff --git a/hadoop-common-project/hadoop-common/src/test/proto/test_rpc_service.proto b/hadoop-common-project/hadoop-common/src/test/proto/test_rpc_service.proto
index 3746411c90b3f..f699027914061 100644
--- a/hadoop-common-project/hadoop-common/src/test/proto/test_rpc_service.proto
+++ b/hadoop-common-project/hadoop-common/src/test/proto/test_rpc_service.proto
@@ -15,6 +15,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+syntax = "proto2";
option java_package = "org.apache.hadoop.ipc.protobuf";
option java_outer_classname = "TestRpcServiceProtos";
option java_generic_services = true;
@@ -39,6 +40,7 @@ service TestProtobufRpcProto {
rpc testServerGet(EmptyRequestProto) returns (EmptyResponseProto);
rpc exchange(ExchangeRequestProto) returns (ExchangeResponseProto);
rpc sleep(SleepRequestProto) returns (EmptyResponseProto);
+ rpc lockAndSleep(SleepRequestProto) returns (EmptyResponseProto);
rpc getAuthMethod(EmptyRequestProto) returns (AuthMethodResponseProto);
rpc getAuthUser(EmptyRequestProto) returns (UserResponseProto);
rpc echoPostponed(EchoRequestProto) returns (EchoResponseProto);
diff --git a/hadoop-common-project/hadoop-common/src/test/resources/kdc/killKdc.sh b/hadoop-common-project/hadoop-common/src/test/resources/kdc/killKdc.sh
deleted file mode 100644
index a6a3d77a3e570..0000000000000
--- a/hadoop-common-project/hadoop-common/src/test/resources/kdc/killKdc.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/sh
-# 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.
-
-ps -ef | grep apacheds | grep -v grep | awk '{printf $2"\n"}' | xargs -t --no-run-if-empty kill -9
-
diff --git a/hadoop-common-project/hadoop-common/src/test/resources/kdc/ldif/users.ldif b/hadoop-common-project/hadoop-common/src/test/resources/kdc/ldif/users.ldif
deleted file mode 100644
index a3d2704949c44..0000000000000
--- a/hadoop-common-project/hadoop-common/src/test/resources/kdc/ldif/users.ldif
+++ /dev/null
@@ -1,78 +0,0 @@
-dn: dc=example,dc=com
-objectClass: dcObject
-objectClass: organization
-objectClass: top
-dc: example
-o: example.com
-
-dn: ou=Users,dc=example,dc=com
-objectClass: organizationalUnit
-objectClass: top
-ou: Users
-
-dn: uid=user1,ou=Users,dc=example,dc=com
-objectClass: top
-objectClass: person
-objectClass: inetOrgPerson
-objectClass: krb5principal
-objectClass: krb5kdcentry
-cn: user1 Service
-sn: Service
-uid: user1
-userPassword: secret
-krb5PrincipalName: user1@EXAMPLE.COM
-krb5KeyVersionNumber: 0
-
-dn: uid=krbtgt,ou=Users,dc=example,dc=com
-objectClass: top
-objectClass: person
-objectClass: inetOrgPerson
-objectClass: krb5principal
-objectClass: krb5kdcentry
-cn: KDC Service
-sn: Service
-uid: krbtgt
-userPassword: secret
-krb5PrincipalName: krbtgt/EXAMPLE.COM@EXAMPLE.COM
-krb5KeyVersionNumber: 0
-
-dn: uid=ldap,ou=Users,dc=example,dc=com
-objectClass: top
-objectClass: person
-objectClass: inetOrgPerson
-objectClass: krb5principal
-objectClass: krb5kdcentry
-cn: LDAP
-sn: Service
-uid: ldap
-userPassword: randall
-krb5PrincipalName: ldap/localhost@EXAMPLE.COM
-krb5KeyVersionNumber: 0
-
-dn: uid=nn1,ou=Users,dc=example,dc=com
-objectClass: top
-objectClass: person
-objectClass: inetOrgPerson
-objectClass: krb5principal
-objectClass: krb5kdcentry
-cn: NameNode Service
-sn: Service
-uid: nn1
-userPassword: secret
-krb5PrincipalName: nn1/localhost@EXAMPLE.COM
-krb5KeyVersionNumber: 0
-
-dn: uid=dn1,ou=Users,dc=example,dc=com
-objectClass: top
-objectClass: person
-objectClass: inetOrgPerson
-objectClass: krb5principal
-objectClass: krb5kdcentry
-cn: DataNode Service
-sn: Service
-uid: dn1
-userPassword: secret
-krb5PrincipalName: dn1/localhost@EXAMPLE.COM
-krb5KeyVersionNumber: 0
-
-
diff --git a/hadoop-common-project/hadoop-common/src/test/resources/kdc/server.xml b/hadoop-common-project/hadoop-common/src/test/resources/kdc/server.xml
deleted file mode 100644
index bb8c52a9976ad..0000000000000
--- a/hadoop-common-project/hadoop-common/src/test/resources/kdc/server.xml
+++ /dev/null
@@ -1,258 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- #directoryService
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- #directoryService
-
-
-
-
-
-
-
-
-
-
-
-
-
- example.com
- apache.org
-
-
-
-
-
-
-
-
-
-
-
-
-
- #ldapServer
-
-
-
-
-
diff --git a/hadoop-common-project/hadoop-common/src/test/resources/testConf.xml b/hadoop-common-project/hadoop-common/src/test/resources/testConf.xml
index e38c2592f8573..392d39170d5fe 100644
--- a/hadoop-common-project/hadoop-common/src/test/resources/testConf.xml
+++ b/hadoop-common-project/hadoop-common/src/test/resources/testConf.xml
@@ -923,7 +923,7 @@
RegexpComparator
- ^-test -\[defsz\] <path> :\s*
+ ^-test -\[defswrz\] <path> :\s*RegexpComparator
@@ -931,7 +931,7 @@
RegexpComparator
- ^\s*-[defsz]\s+return 0 if .*
+ ^\s*-[defswrz]\s+return 0 if .*
diff --git a/hadoop-common-project/hadoop-kms/pom.xml b/hadoop-common-project/hadoop-kms/pom.xml
index 0eed09a256fa4..6f4ff09952ac4 100644
--- a/hadoop-common-project/hadoop-kms/pom.xml
+++ b/hadoop-common-project/hadoop-kms/pom.xml
@@ -17,7 +17,7 @@
+ https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0org.apache.hadoop
diff --git a/hadoop-common-project/hadoop-kms/src/main/java/org/apache/hadoop/crypto/key/kms/server/KeyAuthorizationKeyProvider.java b/hadoop-common-project/hadoop-kms/src/main/java/org/apache/hadoop/crypto/key/kms/server/KeyAuthorizationKeyProvider.java
index 868db765c2edd..101591b0310d2 100644
--- a/hadoop-common-project/hadoop-kms/src/main/java/org/apache/hadoop/crypto/key/kms/server/KeyAuthorizationKeyProvider.java
+++ b/hadoop-common-project/hadoop-kms/src/main/java/org/apache/hadoop/crypto/key/kms/server/KeyAuthorizationKeyProvider.java
@@ -402,7 +402,7 @@ protected KeyProvider getKeyProvider() {
@Override
public String toString() {
- return provider.toString();
+ return this.getClass().getName()+": "+provider.toString();
}
}
diff --git a/hadoop-common-project/hadoop-kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/TestKMSMDCFilter.java b/hadoop-common-project/hadoop-kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/TestKMSMDCFilter.java
new file mode 100644
index 0000000000000..42d1dc0672ea0
--- /dev/null
+++ b/hadoop-common-project/hadoop-kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/TestKMSMDCFilter.java
@@ -0,0 +1,88 @@
+/**
+ * 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.crypto.key.kms.server;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+/**
+ * Test for {@link KMSMDCFilter}.
+ *
+ */
+public class TestKMSMDCFilter {
+
+ private static final String REMOTE_ADDRESS = "192.168.100.100";
+ private static final String URL = "/admin";
+ private static final String METHOD = "GET";
+
+ private KMSMDCFilter filter;
+ private HttpServletRequest httpRequest;
+ private HttpServletResponse httpResponse;
+
+ @Before
+ public void setUp() throws IOException {
+ filter = new KMSMDCFilter();
+ httpRequest = Mockito.mock(HttpServletRequest.class);
+ httpResponse = Mockito.mock(HttpServletResponse.class);
+ KMSMDCFilter.setContext(null, null, null, null);
+ }
+
+ @Test
+ public void testFilter() throws IOException, ServletException {
+ when(httpRequest.getMethod()).thenReturn(METHOD);
+ when(httpRequest.getRequestURL()).thenReturn(new StringBuffer(URL));
+ when(httpRequest.getRemoteAddr()).thenReturn(REMOTE_ADDRESS);
+
+ FilterChain filterChain = new FilterChain() {
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response)
+ throws IOException, ServletException {
+ assertEquals("filter.remoteClientAddress", REMOTE_ADDRESS,
+ KMSMDCFilter.getRemoteClientAddress());
+ assertEquals("filter.method", METHOD, KMSMDCFilter.getMethod());
+ assertEquals("filter.url", URL, KMSMDCFilter.getURL());
+ }
+ };
+
+ checkMDCValuesAreEmpty();
+ filter.doFilter(httpRequest, httpResponse, filterChain);
+ checkMDCValuesAreEmpty();
+ }
+
+ private void checkMDCValuesAreEmpty() {
+ assertNull("getRemoteClientAddress", KMSMDCFilter.getRemoteClientAddress());
+ assertNull("getMethod", KMSMDCFilter.getMethod());
+ assertNull("getURL", KMSMDCFilter.getURL());
+ assertNull("getUgi", KMSMDCFilter.getUgi());
+ }
+
+}
diff --git a/hadoop-common-project/hadoop-minikdc/pom.xml b/hadoop-common-project/hadoop-minikdc/pom.xml
index f1566f1f1c69b..adbd6e32bee58 100644
--- a/hadoop-common-project/hadoop-minikdc/pom.xml
+++ b/hadoop-common-project/hadoop-minikdc/pom.xml
@@ -14,7 +14,7 @@
-->
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
org.apache.hadoophadoop-project
diff --git a/hadoop-common-project/hadoop-nfs/pom.xml b/hadoop-common-project/hadoop-nfs/pom.xml
index fb3fe68ba9d42..e0fedaf1434e6 100644
--- a/hadoop-common-project/hadoop-nfs/pom.xml
+++ b/hadoop-common-project/hadoop-nfs/pom.xml
@@ -15,7 +15,7 @@
+ https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0org.apache.hadoop
@@ -97,6 +97,11 @@
com.google.guavaguava
+
+ org.assertj
+ assertj-core
+ test
+
diff --git a/hadoop-common-project/hadoop-nfs/src/test/java/org/apache/hadoop/nfs/nfs3/TestFileHandle.java b/hadoop-common-project/hadoop-nfs/src/test/java/org/apache/hadoop/nfs/nfs3/TestFileHandle.java
index 53916641e7ee5..70875c2913dd3 100644
--- a/hadoop-common-project/hadoop-nfs/src/test/java/org/apache/hadoop/nfs/nfs3/TestFileHandle.java
+++ b/hadoop-common-project/hadoop-nfs/src/test/java/org/apache/hadoop/nfs/nfs3/TestFileHandle.java
@@ -17,24 +17,23 @@
*/
package org.apache.hadoop.nfs.nfs3;
-import org.junit.Assert;
-
-import org.apache.hadoop.nfs.nfs3.FileHandle;
import org.apache.hadoop.oncrpc.XDR;
import org.junit.Test;
+import static org.assertj.core.api.Assertions.assertThat;
+
public class TestFileHandle {
@Test
public void testConstructor() {
FileHandle handle = new FileHandle(1024);
XDR xdr = new XDR();
handle.serialize(xdr);
- Assert.assertEquals(handle.getFileId(), 1024);
+ assertThat(handle.getFileId()).isEqualTo(1024);
// Deserialize it back
FileHandle handle2 = new FileHandle();
handle2.deserialize(xdr.asReadOnlyWrap());
- Assert.assertEquals("Failed: Assert 1024 is id ", 1024,
- handle.getFileId());
+ assertThat(handle.getFileId())
+ .withFailMessage("Failed: Assert 1024 is id ").isEqualTo(1024);
}
}
diff --git a/hadoop-common-project/hadoop-registry/pom.xml b/hadoop-common-project/hadoop-registry/pom.xml
index 7ca1c9e7a8a8c..dc45309dca296 100644
--- a/hadoop-common-project/hadoop-registry/pom.xml
+++ b/hadoop-common-project/hadoop-registry/pom.xml
@@ -15,7 +15,7 @@
+ https://maven.apache.org/xsd/maven-4.0.0.xsd">
hadoop-projectorg.apache.hadoop
diff --git a/hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/client/impl/zk/RegistrySecurity.java b/hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/client/impl/zk/RegistrySecurity.java
index dac11353a4aee..c3cb021fb53f3 100644
--- a/hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/client/impl/zk/RegistrySecurity.java
+++ b/hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/client/impl/zk/RegistrySecurity.java
@@ -32,6 +32,7 @@
import org.apache.hadoop.util.ZKUtil;
import org.apache.zookeeper.Environment;
import org.apache.zookeeper.ZooDefs;
+import org.apache.zookeeper.client.ZKClientConfig;
import org.apache.zookeeper.client.ZooKeeperSaslClient;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Id;
@@ -769,19 +770,19 @@ public void applySecurityEnvironment(CuratorFrameworkFactory.Builder
JaasConfiguration jconf =
new JaasConfiguration(jaasClientEntry, principal, keytab);
javax.security.auth.login.Configuration.setConfiguration(jconf);
- setSystemPropertyIfUnset(ZooKeeperSaslClient.ENABLE_CLIENT_SASL_KEY,
- "true");
- setSystemPropertyIfUnset(ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY,
- jaasClientEntry);
+ setSystemPropertyIfUnset(ZKClientConfig.ENABLE_CLIENT_SASL_KEY,
+ "true");
+ setSystemPropertyIfUnset(ZKClientConfig.LOGIN_CONTEXT_NAME_KEY,
+ jaasClientEntry);
} else {
// in this case, jaas config is specified so we will not change it
LOG.info("Using existing ZK sasl configuration: " +
- "jaasClientEntry = " + System.getProperty(
- ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY, "Client") +
- ", sasl client = " + System.getProperty(
- ZooKeeperSaslClient.ENABLE_CLIENT_SASL_KEY,
- ZooKeeperSaslClient.ENABLE_CLIENT_SASL_DEFAULT) +
- ", jaas = " + existingJaasConf);
+ "jaasClientEntry = " + System.getProperty(
+ ZKClientConfig.LOGIN_CONTEXT_NAME_KEY, "Client") +
+ ", sasl client = " + System.getProperty(
+ ZKClientConfig.ENABLE_CLIENT_SASL_KEY,
+ ZKClientConfig.ENABLE_CLIENT_SASL_DEFAULT) +
+ ", jaas = " + existingJaasConf);
}
break;
@@ -926,7 +927,7 @@ public void logCurrentHadoopUser() {
UserGroupInformation realUser = currentUser.getRealUser();
LOG.info("Real User = {}" , realUser);
} catch (IOException e) {
- LOG.warn("Failed to get current user {}, {}", e);
+ LOG.warn("Failed to get current user, {}", e);
}
}
diff --git a/hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/client/impl/zk/ZookeeperConfigOptions.java b/hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/client/impl/zk/ZookeeperConfigOptions.java
index edcf0859fc345..115af3237abc0 100644
--- a/hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/client/impl/zk/ZookeeperConfigOptions.java
+++ b/hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/client/impl/zk/ZookeeperConfigOptions.java
@@ -18,7 +18,7 @@
package org.apache.hadoop.registry.client.impl.zk;
-import org.apache.zookeeper.client.ZooKeeperSaslClient;
+import org.apache.zookeeper.client.ZKClientConfig;
import org.apache.zookeeper.server.ZooKeeperSaslServer;
/**
@@ -62,10 +62,10 @@ public interface ZookeeperConfigOptions {
*
*
* Default value is derived from
- * {@link ZooKeeperSaslClient#LOGIN_CONTEXT_NAME_KEY}
+ * {@link ZKClientConfig#LOGIN_CONTEXT_NAME_KEY}
*/
String PROP_ZK_SASL_CLIENT_CONTEXT =
- ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY;
+ ZKClientConfig.LOGIN_CONTEXT_NAME_KEY;
/**
* The SASL client username: {@value}.
diff --git a/hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/server/services/MicroZookeeperService.java b/hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/server/services/MicroZookeeperService.java
index b6cf9fc519121..a7e2611b3df9d 100644
--- a/hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/server/services/MicroZookeeperService.java
+++ b/hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/server/services/MicroZookeeperService.java
@@ -42,6 +42,7 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.InetSocketAddress;
+import java.net.ServerSocket;
import java.net.UnknownHostException;
/**
@@ -121,7 +122,7 @@ public InetSocketAddress getConnectionAddress() {
* @throws UnknownHostException if the server cannot resolve the host
*/
private InetSocketAddress getAddress(int port) throws UnknownHostException {
- return new InetSocketAddress(host, port < 0 ? 0 : port);
+ return new InetSocketAddress(host, port <= 0 ? getRandomAvailablePort() : port);
}
/**
@@ -227,10 +228,8 @@ protected void serviceStart() throws Exception {
setupSecurity();
- ZooKeeperServer zkServer = new ZooKeeperServer();
FileTxnSnapLog ftxn = new FileTxnSnapLog(dataDir, dataDir);
- zkServer.setTxnLogFactory(ftxn);
- zkServer.setTickTime(tickTime);
+ ZooKeeperServer zkServer = new ZooKeeperServer(ftxn, tickTime);
LOG.info("Starting Local Zookeeper service");
factory = ServerCnxnFactory.createFactory();
@@ -245,7 +244,7 @@ protected void serviceStart() throws Exception {
PrintWriter pw = new PrintWriter(sw);
zkServer.dumpConf(pw);
pw.flush();
- LOG.debug(sw.toString());
+ LOG.debug("ZooKeeper config:\n" + sw.toString());
}
binding = new BindingInformation();
binding.ensembleProvider = new FixedEnsembleProvider(connectString);
@@ -279,4 +278,20 @@ public BindingInformation supplyBindingInformation() {
"Service is not started: binding information undefined");
return binding;
}
+
+ /**
+ * Returns with a random open port can be used to set as server port for ZooKeeper.
+ * @return a random open port or 0 (in case of error)
+ */
+ private int getRandomAvailablePort() {
+ port = 0;
+ try {
+ final ServerSocket s = new ServerSocket(0);
+ port = s.getLocalPort();
+ s.close();
+ } catch (IOException e) {
+ LOG.warn("ERROR during selecting random port for ZooKeeper server to bind." , e);
+ }
+ return port;
+ }
}
diff --git a/hadoop-common-project/hadoop-registry/src/test/java/org/apache/hadoop/registry/secure/TestSecureRegistry.java b/hadoop-common-project/hadoop-registry/src/test/java/org/apache/hadoop/registry/secure/TestSecureRegistry.java
index 9d5848ea03497..27d32ea9d2672 100644
--- a/hadoop-common-project/hadoop-registry/src/test/java/org/apache/hadoop/registry/secure/TestSecureRegistry.java
+++ b/hadoop-common-project/hadoop-registry/src/test/java/org/apache/hadoop/registry/secure/TestSecureRegistry.java
@@ -24,16 +24,12 @@
import org.apache.hadoop.registry.client.impl.zk.CuratorService;
import org.apache.hadoop.registry.client.impl.zk.RegistrySecurity;
import org.apache.zookeeper.CreateMode;
-import org.apache.zookeeper.Login;
-import org.apache.zookeeper.server.ZooKeeperSaslServer;
-import org.apache.zookeeper.server.auth.SaslServerCallbackHandler;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.LoginContext;
import static org.apache.hadoop.registry.client.api.RegistryConstants.*;
@@ -58,36 +54,6 @@ public void afterTestSecureZKService() throws Throwable {
RegistrySecurity.clearZKSaslClientProperties();
}
- /**
- * this is a cut and paste of some of the ZK internal code that was
- * failing on windows and swallowing its exceptions
- */
- @Test
- public void testLowlevelZKSaslLogin() throws Throwable {
- RegistrySecurity.bindZKToServerJAASContext(ZOOKEEPER_SERVER_CONTEXT);
- String serverSection =
- System.getProperty(ZooKeeperSaslServer.LOGIN_CONTEXT_NAME_KEY,
- ZooKeeperSaslServer.DEFAULT_LOGIN_CONTEXT_NAME);
- assertEquals(ZOOKEEPER_SERVER_CONTEXT, serverSection);
-
- AppConfigurationEntry entries[];
- entries = javax.security.auth.login.Configuration.getConfiguration()
- .getAppConfigurationEntry(
- serverSection);
-
- assertNotNull("null entries", entries);
-
- SaslServerCallbackHandler saslServerCallbackHandler =
- new SaslServerCallbackHandler(
- javax.security.auth.login.Configuration.getConfiguration());
- Login login = new Login(serverSection, saslServerCallbackHandler);
- try {
- login.startThreadIfNeeded();
- } finally {
- login.shutdown();
- }
- }
-
@Test
public void testCreateSecureZK() throws Throwable {
startSecureZK();
diff --git a/hadoop-common-project/pom.xml b/hadoop-common-project/pom.xml
index e96d1ba9e1608..8be2593c21ffd 100644
--- a/hadoop-common-project/pom.xml
+++ b/hadoop-common-project/pom.xml
@@ -15,7 +15,7 @@
+ https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0org.apache.hadoop
diff --git a/hadoop-dist/pom.xml b/hadoop-dist/pom.xml
index 1d3db65930845..07aa7b10a8320 100644
--- a/hadoop-dist/pom.xml
+++ b/hadoop-dist/pom.xml
@@ -15,7 +15,7 @@
+ https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0org.apache.hadoop
diff --git a/hadoop-hdds/client/pom.xml b/hadoop-hdds/client/pom.xml
index 040332e504ddf..673af41aeef0d 100644
--- a/hadoop-hdds/client/pom.xml
+++ b/hadoop-hdds/client/pom.xml
@@ -15,7 +15,7 @@
+https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0org.apache.hadoop
@@ -41,4 +41,4 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd">
-
\ No newline at end of file
+
diff --git a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientGrpc.java b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientGrpc.java
index a535c9f3f2aa4..04a8a1aaa1db3 100644
--- a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientGrpc.java
+++ b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientGrpc.java
@@ -31,6 +31,7 @@
import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
import org.apache.hadoop.hdds.scm.client.HddsClientUtils;
import org.apache.hadoop.hdds.scm.pipeline.Pipeline;
+import org.apache.hadoop.hdds.scm.storage.CheckedBiFunction;
import org.apache.hadoop.hdds.security.exception.SCMSecurityException;
import org.apache.hadoop.hdds.security.x509.SecurityConfig;
import org.apache.hadoop.hdds.tracing.GrpcClientInterceptor;
@@ -51,8 +52,9 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
import java.io.IOException;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -62,13 +64,13 @@
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-import java.util.stream.Collectors;
/**
- * A Client for the storageContainer protocol.
+ * A Client for the storageContainer protocol for read object data.
*/
public class XceiverClientGrpc extends XceiverClientSpi {
static final Logger LOG = LoggerFactory.getLogger(XceiverClientGrpc.class);
+ private static final String COMPONENT = "dn";
private final Pipeline pipeline;
private final Configuration config;
private Map asyncStubs;
@@ -77,47 +79,70 @@ public class XceiverClientGrpc extends XceiverClientSpi {
private final Semaphore semaphore;
private boolean closed = false;
private SecurityConfig secConfig;
+ private final boolean topologyAwareRead;
+ private X509Certificate caCert;
/**
* Constructs a client that can communicate with the Container framework on
* data nodes.
*
* @param pipeline - Pipeline that defines the machines.
- * @param config -- Ozone Config
+ * @param config -- Ozone Config
+ * @param caCert - SCM ca certificate.
*/
- public XceiverClientGrpc(Pipeline pipeline, Configuration config) {
+ public XceiverClientGrpc(Pipeline pipeline, Configuration config,
+ X509Certificate caCert) {
super();
Preconditions.checkNotNull(pipeline);
Preconditions.checkNotNull(config);
this.pipeline = pipeline;
this.config = config;
- this.secConfig = new SecurityConfig(config);
+ this.secConfig = new SecurityConfig(config);
this.semaphore =
new Semaphore(HddsClientUtils.getMaxOutstandingRequests(config));
this.metrics = XceiverClientManager.getXceiverClientMetrics();
this.channels = new HashMap<>();
this.asyncStubs = new HashMap<>();
+ this.topologyAwareRead = config.getBoolean(
+ OzoneConfigKeys.OZONE_NETWORK_TOPOLOGY_AWARE_READ_KEY,
+ OzoneConfigKeys.OZONE_NETWORK_TOPOLOGY_AWARE_READ_DEFAULT);
+ this.caCert = caCert;
+ }
+
+ /**
+ * Constructs a client that can communicate with the Container framework on
+ * data nodes.
+ *
+ * @param pipeline - Pipeline that defines the machines.
+ * @param config -- Ozone Config
+ */
+ public XceiverClientGrpc(Pipeline pipeline, Configuration config) {
+ this(pipeline, config, null);
}
/**
* To be used when grpc token is not enabled.
- * */
+ */
@Override
public void connect() throws Exception {
- // leader by default is the 1st datanode in the datanode list of pipleline
- DatanodeDetails dn = this.pipeline.getFirstNode();
- // just make a connection to the 1st datanode at the beginning
+ // connect to the closest node, if closest node doesn't exist, delegate to
+ // first node, which is usually the leader in the pipeline.
+ DatanodeDetails dn = topologyAwareRead ? this.pipeline.getClosestNode() :
+ this.pipeline.getFirstNode();
+ // just make a connection to the picked datanode at the beginning
connectToDatanode(dn, null);
}
/**
* Passed encoded token to GRPC header when security is enabled.
- * */
+ */
@Override
public void connect(String encodedToken) throws Exception {
- // leader by default is the 1st datanode in the datanode list of pipleline
- DatanodeDetails dn = this.pipeline.getFirstNode();
- // just make a connection to the 1st datanode at the beginning
+ // connect to the closest node, if closest node doesn't exist, delegate to
+ // first node, which is usually the leader in the pipeline.
+ DatanodeDetails dn = topologyAwareRead ? this.pipeline.getClosestNode() :
+ this.pipeline.getFirstNode();
+ // just make a connection to the picked datanode at the beginning
connectToDatanode(dn, encodedToken);
}
@@ -132,28 +157,21 @@ private void connectToDatanode(DatanodeDetails dn, String encodedToken)
}
// Add credential context to the client call
- String userName = UserGroupInformation.getCurrentUser()
- .getShortUserName();
- LOG.debug("Connecting to server Port : " + dn.getIpAddress());
- NettyChannelBuilder channelBuilder = NettyChannelBuilder.forAddress(dn
- .getIpAddress(), port).usePlaintext()
+ String userName = UserGroupInformation.getCurrentUser().getShortUserName();
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Nodes in pipeline : {}", pipeline.getNodes().toString());
+ LOG.debug("Connecting to server : {}", dn.getIpAddress());
+ }
+ NettyChannelBuilder channelBuilder =
+ NettyChannelBuilder.forAddress(dn.getIpAddress(), port).usePlaintext()
.maxInboundMessageSize(OzoneConsts.OZONE_SCM_CHUNK_MAX_SIZE)
.intercept(new ClientCredentialInterceptor(userName, encodedToken),
new GrpcClientInterceptor());
if (secConfig.isGrpcTlsEnabled()) {
- File trustCertCollectionFile = secConfig.getTrustStoreFile();
- File privateKeyFile = secConfig.getClientPrivateKeyFile();
- File clientCertChainFile = secConfig.getClientCertChainFile();
-
SslContextBuilder sslContextBuilder = GrpcSslContexts.forClient();
- if (trustCertCollectionFile != null) {
- sslContextBuilder.trustManager(trustCertCollectionFile);
- }
- if (secConfig.isGrpcMutualTlsRequired() && clientCertChainFile != null &&
- privateKeyFile != null) {
- sslContextBuilder.keyManager(clientCertChainFile, privateKeyFile);
+ if (caCert != null) {
+ sslContextBuilder.trustManager(caCert);
}
-
if (secConfig.useTestCert()) {
channelBuilder.overrideAuthority("localhost");
}
@@ -216,67 +234,85 @@ public ContainerCommandResponseProto sendCommand(
}
@Override
- public XceiverClientReply sendCommand(
- ContainerCommandRequestProto request, List excludeDns)
+ public ContainerCommandResponseProto sendCommand(
+ ContainerCommandRequestProto request, List validators)
throws IOException {
- Preconditions.checkState(HddsUtils.isReadOnly(request));
- return sendCommandWithTraceIDAndRetry(request, excludeDns);
+ try {
+ XceiverClientReply reply;
+ reply = sendCommandWithTraceIDAndRetry(request, validators);
+ ContainerCommandResponseProto responseProto = reply.getResponse().get();
+ return responseProto;
+ } catch (ExecutionException | InterruptedException e) {
+ throw new IOException("Failed to execute command " + request, e);
+ }
}
private XceiverClientReply sendCommandWithTraceIDAndRetry(
- ContainerCommandRequestProto request, List excludeDns)
+ ContainerCommandRequestProto request, List validators)
throws IOException {
try (Scope scope = GlobalTracer.get()
.buildSpan("XceiverClientGrpc." + request.getCmdType().name())
.startActive(true)) {
ContainerCommandRequestProto finalPayload =
ContainerCommandRequestProto.newBuilder(request)
- .setTraceID(TracingUtil.exportCurrentSpan())
- .build();
- return sendCommandWithRetry(finalPayload, excludeDns);
+ .setTraceID(TracingUtil.exportCurrentSpan()).build();
+ return sendCommandWithRetry(finalPayload, validators);
}
}
private XceiverClientReply sendCommandWithRetry(
- ContainerCommandRequestProto request, List excludeDns)
+ ContainerCommandRequestProto request, List validators)
throws IOException {
ContainerCommandResponseProto responseProto = null;
+ IOException ioException = null;
// In case of an exception or an error, we will try to read from the
// datanodes in the pipeline in a round robin fashion.
// TODO: cache the correct leader info in here, so that any subsequent calls
// should first go to leader
- List dns = pipeline.getNodes();
- List healthyDns =
- excludeDns != null ? dns.stream().filter(dnId -> {
- for (DatanodeDetails excludeId : excludeDns) {
- if (dnId.equals(excludeId)) {
- return false;
- }
- }
- return true;
- }).collect(Collectors.toList()) : dns;
XceiverClientReply reply = new XceiverClientReply(null);
- for (DatanodeDetails dn : healthyDns) {
+ List datanodeList;
+ if ((request.getCmdType() == ContainerProtos.Type.ReadChunk ||
+ request.getCmdType() == ContainerProtos.Type.GetSmallFile) &&
+ topologyAwareRead) {
+ datanodeList = pipeline.getNodesInOrder();
+ } else {
+ datanodeList = pipeline.getNodes();
+ // Shuffle datanode list so that clients do not read in the same order
+ // every time.
+ Collections.shuffle(datanodeList);
+ }
+ for (DatanodeDetails dn : datanodeList) {
try {
- LOG.debug("Executing command " + request + " on datanode " + dn);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Executing command " + request + " on datanode " + dn);
+ }
// In case the command gets retried on a 2nd datanode,
// sendCommandAsyncCall will create a new channel and async stub
// in case these don't exist for the specific datanode.
reply.addDatanode(dn);
responseProto = sendCommandAsync(request, dn).getResponse().get();
- if (responseProto.getResult() == ContainerProtos.Result.SUCCESS) {
- break;
+ if (validators != null && !validators.isEmpty()) {
+ for (CheckedBiFunction validator : validators) {
+ validator.apply(request, responseProto);
+ }
}
- } catch (ExecutionException | InterruptedException e) {
- LOG.debug("Failed to execute command " + request + " on datanode " + dn
+ break;
+ } catch (ExecutionException | InterruptedException | IOException e) {
+ LOG.error("Failed to execute command " + request + " on datanode " + dn
.getUuidString(), e);
- if (Status.fromThrowable(e.getCause()).getCode()
- == Status.UNAUTHENTICATED.getCode()) {
- throw new SCMSecurityException("Failed to authenticate with "
- + "GRPC XceiverServer with Ozone block token.");
+ if (!(e instanceof IOException)) {
+ if (Status.fromThrowable(e.getCause()).getCode()
+ == Status.UNAUTHENTICATED.getCode()) {
+ throw new SCMSecurityException("Failed to authenticate with "
+ + "GRPC XceiverServer with Ozone block token.");
+ }
+ ioException = new IOException(e);
+ } else {
+ ioException = (IOException) e;
}
+ responseProto = null;
}
}
@@ -284,9 +320,10 @@ private XceiverClientReply sendCommandWithRetry(
reply.setResponse(CompletableFuture.completedFuture(responseProto));
return reply;
} else {
- throw new IOException(
- "Failed to execute command " + request + " on the pipeline "
- + pipeline.getId());
+ Preconditions.checkNotNull(ioException);
+ LOG.error("Failed to execute command {} on the pipeline {}.", request,
+ pipeline);
+ throw ioException;
}
}
@@ -311,8 +348,13 @@ public XceiverClientReply sendCommandAsync(
try (Scope scope = GlobalTracer.get()
.buildSpan("XceiverClientGrpc." + request.getCmdType().name())
.startActive(true)) {
+
+ ContainerCommandRequestProto finalPayload =
+ ContainerCommandRequestProto.newBuilder(request)
+ .setTraceID(TracingUtil.exportCurrentSpan())
+ .build();
XceiverClientReply asyncReply =
- sendCommandAsync(request, pipeline.getFirstNode());
+ sendCommandAsync(finalPayload, pipeline.getFirstNode());
// TODO : for now make this API sync in nature as async requests are
// served out of order over XceiverClientGrpc. This needs to be fixed
// if this API is to be used for I/O path. Currently, this is not
@@ -339,7 +381,10 @@ private XceiverClientReply sendCommandAsync(
if (!isConnected(channel)) {
reconnect(dn, token);
}
-
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Send command {} to datanode {}",
+ request.getCmdType().toString(), dn.getNetworkFullPath());
+ }
final CompletableFuture replyFuture =
new CompletableFuture<>();
semaphore.acquire();
diff --git a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientManager.java b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientManager.java
index f9b5e6d05cb8f..b15828a153098 100644
--- a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientManager.java
+++ b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientManager.java
@@ -25,24 +25,33 @@
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;
import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hdds.conf.Config;
+import org.apache.hadoop.hdds.conf.ConfigGroup;
+import org.apache.hadoop.hdds.conf.ConfigType;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.scm.pipeline.Pipeline;
import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
+import org.apache.hadoop.hdds.security.exception.SCMSecurityException;
+import org.apache.hadoop.hdds.security.x509.certificate.utils.CertificateCodec;
+import org.apache.hadoop.ozone.OzoneConfigKeys;
import org.apache.hadoop.ozone.OzoneSecurityUtil;
import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.ratis.thirdparty.com.google.protobuf.ByteString;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.io.Closeable;
import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
-import static org.apache.hadoop.hdds.scm.ScmConfigKeys
- .SCM_CONTAINER_CLIENT_MAX_SIZE_DEFAULT;
-import static org.apache.hadoop.hdds.scm.ScmConfigKeys
- .SCM_CONTAINER_CLIENT_MAX_SIZE_KEY;
-import static org.apache.hadoop.hdds.scm.ScmConfigKeys
- .SCM_CONTAINER_CLIENT_STALE_THRESHOLD_DEFAULT;
-import static org.apache.hadoop.hdds.scm.ScmConfigKeys
- .SCM_CONTAINER_CLIENT_STALE_THRESHOLD_KEY;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static org.apache.hadoop.hdds.conf.ConfigTag.OZONE;
+import static org.apache.hadoop.hdds.conf.ConfigTag.PERFORMANCE;
/**
* XceiverClientManager is responsible for the lifecycle of XceiverClient
@@ -57,34 +66,52 @@
* not being used for a period of time.
*/
public class XceiverClientManager implements Closeable {
-
+ private static final Logger LOG =
+ LoggerFactory.getLogger(XceiverClientManager.class);
//TODO : change this to SCM configuration class
private final Configuration conf;
private final Cache clientCache;
private final boolean useRatis;
+ private X509Certificate caCert;
private static XceiverClientMetrics metrics;
private boolean isSecurityEnabled;
+ private final boolean topologyAwareRead;
/**
- * Creates a new XceiverClientManager.
+ * Creates a new XceiverClientManager for non secured ozone cluster.
+ * For security enabled ozone cluster, client should use the other constructor
+ * with a valid ca certificate in pem string format.
*
* @param conf configuration
*/
- public XceiverClientManager(Configuration conf) {
+ public XceiverClientManager(Configuration conf) throws IOException {
+ this(conf, OzoneConfiguration.of(conf).getObject(ScmClientConfig.class),
+ null);
+ }
+
+ public XceiverClientManager(Configuration conf, ScmClientConfig clientConf,
+ String caCertPem) throws IOException {
+ Preconditions.checkNotNull(clientConf);
Preconditions.checkNotNull(conf);
- int maxSize = conf.getInt(SCM_CONTAINER_CLIENT_MAX_SIZE_KEY,
- SCM_CONTAINER_CLIENT_MAX_SIZE_DEFAULT);
- long staleThresholdMs = conf.getTimeDuration(
- SCM_CONTAINER_CLIENT_STALE_THRESHOLD_KEY,
- SCM_CONTAINER_CLIENT_STALE_THRESHOLD_DEFAULT, TimeUnit.MILLISECONDS);
+ long staleThresholdMs = clientConf.getStaleThreshold(MILLISECONDS);
this.useRatis = conf.getBoolean(
ScmConfigKeys.DFS_CONTAINER_RATIS_ENABLED_KEY,
ScmConfigKeys.DFS_CONTAINER_RATIS_ENABLED_DEFAULT);
this.conf = conf;
this.isSecurityEnabled = OzoneSecurityUtil.isSecurityEnabled(conf);
+ if (isSecurityEnabled) {
+ Preconditions.checkNotNull(caCertPem);
+ try {
+ this.caCert = CertificateCodec.getX509Cert(caCertPem);
+ } catch (CertificateException ex) {
+ throw new SCMSecurityException("Error: Fail to get SCM CA certificate",
+ ex);
+ }
+ }
+
this.clientCache = CacheBuilder.newBuilder()
- .expireAfterAccess(staleThresholdMs, TimeUnit.MILLISECONDS)
- .maximumSize(maxSize)
+ .expireAfterAccess(staleThresholdMs, MILLISECONDS)
+ .maximumSize(clientConf.getMaxSize())
.removalListener(
new RemovalListener() {
@Override
@@ -98,6 +125,9 @@ public void onRemoval(
}
}
}).build();
+ topologyAwareRead = conf.getBoolean(
+ OzoneConfigKeys.OZONE_NETWORK_TOPOLOGY_AWARE_READ_KEY,
+ OzoneConfigKeys.OZONE_NETWORK_TOPOLOGY_AWARE_READ_DEFAULT);
}
@VisibleForTesting
@@ -118,12 +148,32 @@ public Cache getClientCache() {
*/
public XceiverClientSpi acquireClient(Pipeline pipeline)
throws IOException {
+ return acquireClient(pipeline, false);
+ }
+
+ /**
+ * Acquires a XceiverClientSpi connected to a container for read.
+ *
+ * If there is already a cached XceiverClientSpi, simply return
+ * the cached otherwise create a new one.
+ *
+ * @param pipeline the container pipeline for the client connection
+ * @return XceiverClientSpi connected to a container
+ * @throws IOException if a XceiverClientSpi cannot be acquired
+ */
+ public XceiverClientSpi acquireClientForReadData(Pipeline pipeline)
+ throws IOException {
+ return acquireClient(pipeline, true);
+ }
+
+ private XceiverClientSpi acquireClient(Pipeline pipeline, boolean read)
+ throws IOException {
Preconditions.checkNotNull(pipeline);
Preconditions.checkArgument(pipeline.getNodes() != null);
Preconditions.checkArgument(!pipeline.getNodes().isEmpty());
synchronized (clientCache) {
- XceiverClientSpi info = getClient(pipeline);
+ XceiverClientSpi info = getClient(pipeline, read);
info.incrementReference();
return info;
}
@@ -136,12 +186,28 @@ public XceiverClientSpi acquireClient(Pipeline pipeline)
* @param invalidateClient if true, invalidates the client in cache
*/
public void releaseClient(XceiverClientSpi client, boolean invalidateClient) {
+ releaseClient(client, invalidateClient, false);
+ }
+
+ /**
+ * Releases a read XceiverClientSpi after use.
+ *
+ * @param client client to release
+ * @param invalidateClient if true, invalidates the client in cache
+ */
+ public void releaseClientForReadData(XceiverClientSpi client,
+ boolean invalidateClient) {
+ releaseClient(client, invalidateClient, true);
+ }
+
+ private void releaseClient(XceiverClientSpi client, boolean invalidateClient,
+ boolean read) {
Preconditions.checkNotNull(client);
synchronized (clientCache) {
client.decrementReference();
if (invalidateClient) {
Pipeline pipeline = client.getPipeline();
- String key = pipeline.getId().getId().toString() + pipeline.getType();
+ String key = getPipelineCacheKey(pipeline, read);
XceiverClientSpi cachedClient = clientCache.getIfPresent(key);
if (cachedClient == client) {
clientCache.invalidate(key);
@@ -150,11 +216,13 @@ public void releaseClient(XceiverClientSpi client, boolean invalidateClient) {
}
}
- private XceiverClientSpi getClient(Pipeline pipeline)
+ private XceiverClientSpi getClient(Pipeline pipeline, boolean forRead)
throws IOException {
HddsProtos.ReplicationType type = pipeline.getType();
try {
- String key = pipeline.getId().getId().toString() + type;
+ // create different client for read different pipeline node based on
+ // network topology
+ String key = getPipelineCacheKey(pipeline, forRead);
// Append user short name to key to prevent a different user
// from using same instance of xceiverClient.
key = isSecurityEnabled ?
@@ -165,11 +233,12 @@ public XceiverClientSpi call() throws Exception {
XceiverClientSpi client = null;
switch (type) {
case RATIS:
- client = XceiverClientRatis.newXceiverClientRatis(pipeline, conf);
+ client = XceiverClientRatis.newXceiverClientRatis(pipeline, conf,
+ caCert);
client.connect();
break;
case STAND_ALONE:
- client = new XceiverClientGrpc(pipeline, conf);
+ client = new XceiverClientGrpc(pipeline, conf, caCert);
break;
case CHAINED:
default:
@@ -184,6 +253,19 @@ public XceiverClientSpi call() throws Exception {
}
}
+ private String getPipelineCacheKey(Pipeline pipeline, boolean forRead) {
+ String key = pipeline.getId().getId().toString() + pipeline.getType();
+ if (topologyAwareRead && forRead) {
+ try {
+ key += pipeline.getClosestNode().getHostName();
+ } catch (IOException e) {
+ LOG.error("Failed to get closest node to create pipeline cache key:" +
+ e.getMessage());
+ }
+ }
+ return key;
+ }
+
/**
* Close and remove all the cached clients.
*/
@@ -230,6 +312,10 @@ public HddsProtos.ReplicationType getType() {
return HddsProtos.ReplicationType.STAND_ALONE;
}
+ public Function byteBufferToByteStringConversion(){
+ return ByteStringConversion.createByteBufferConversion(conf);
+ }
+
/**
* Get xceiver client metric.
*/
@@ -240,4 +326,65 @@ public synchronized static XceiverClientMetrics getXceiverClientMetrics() {
return metrics;
}
+
+ /**
+ * Configuration for HDDS client.
+ */
+ @ConfigGroup(prefix = "scm.container.client")
+ public static class ScmClientConfig {
+
+ private int maxSize;
+ private long staleThreshold;
+ private int maxOutstandingRequests;
+
+ public long getStaleThreshold(TimeUnit unit) {
+ return unit.convert(staleThreshold, MILLISECONDS);
+ }
+
+ @Config(key = "idle.threshold",
+ type = ConfigType.TIME, timeUnit = MILLISECONDS,
+ defaultValue = "10s",
+ tags = { OZONE, PERFORMANCE },
+ description =
+ "In the standalone pipelines, the SCM clients use netty to "
+ + " communicate with the container. It also uses connection pooling"
+ + " to reduce client side overheads. This allows a connection to"
+ + " stay idle for a while before the connection is closed."
+ )
+ public void setStaleThreshold(long staleThreshold) {
+ this.staleThreshold = staleThreshold;
+ }
+
+ public int getMaxSize() {
+ return maxSize;
+ }
+
+ @Config(key = "max.size",
+ defaultValue = "256",
+ tags = { OZONE, PERFORMANCE },
+ description =
+ "Controls the maximum number of connections that are cached via"
+ + " client connection pooling. If the number of connections"
+ + " exceed this count, then the oldest idle connection is evicted."
+ )
+ public void setMaxSize(int maxSize) {
+ this.maxSize = maxSize;
+ }
+
+ public int getMaxOutstandingRequests() {
+ return maxOutstandingRequests;
+ }
+
+ @Config(key = "max.outstanding.requests",
+ defaultValue = "100",
+ tags = { OZONE, PERFORMANCE },
+ description =
+ "Controls the maximum number of outstanding async requests that can"
+ + " be handled by the Standalone as well as Ratis client."
+ )
+ public void setMaxOutstandingRequests(int maxOutstandingRequests) {
+ this.maxOutstandingRequests = maxOutstandingRequests;
+ }
+ }
+
}
diff --git a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientMetrics.java b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientMetrics.java
index 6c40921c174a0..5d43c5ef22585 100644
--- a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientMetrics.java
+++ b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientMetrics.java
@@ -69,6 +69,7 @@ public XceiverClientMetrics() {
}
public static XceiverClientMetrics create() {
+ DefaultMetricsSystem.initialize(SOURCE_NAME);
MetricsSystem ms = DefaultMetricsSystem.instance();
return ms.register(SOURCE_NAME, "Storage Container Client Metrics",
new XceiverClientMetrics());
diff --git a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientRatis.java b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientRatis.java
index efd82bce7bbd5..04fababf50447 100644
--- a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientRatis.java
+++ b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/XceiverClientRatis.java
@@ -18,52 +18,55 @@
package org.apache.hadoop.hdds.scm;
-import com.google.common.annotations.VisibleForTesting;
+import java.io.IOException;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.OptionalLong;
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
+
+import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hdds.HddsUtils;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos;
+import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos.ContainerCommandRequestProto;
+import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos.ContainerCommandResponseProto;
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
+import org.apache.hadoop.hdds.ratis.ContainerCommandRequestMessage;
+import org.apache.hadoop.hdds.scm.client.HddsClientUtils;
+import org.apache.hadoop.hdds.scm.pipeline.Pipeline;
import org.apache.hadoop.hdds.security.x509.SecurityConfig;
-
-import io.opentracing.Scope;
-import io.opentracing.util.GlobalTracer;
+import org.apache.hadoop.hdds.tracing.TracingUtil;
import org.apache.hadoop.util.Time;
+import org.apache.hadoop.hdds.ratis.RatisHelper;
+import org.apache.ratis.client.RaftClient;
import org.apache.ratis.grpc.GrpcTlsConfig;
import org.apache.ratis.proto.RaftProtos;
import org.apache.ratis.protocol.GroupMismatchException;
-import org.apache.ratis.protocol.RaftRetryFailureException;
-import org.apache.ratis.retry.RetryPolicy;
-import org.apache.ratis.thirdparty.com.google.protobuf
- .InvalidProtocolBufferException;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.hdds.scm.client.HddsClientUtils;
-import org.apache.hadoop.hdds.scm.pipeline.Pipeline;
-import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos
- .ContainerCommandRequestProto;
-import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos
- .ContainerCommandResponseProto;
-import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
-import org.apache.hadoop.hdds.tracing.TracingUtil;
-
-import org.apache.ratis.RatisHelper;
-import org.apache.ratis.client.RaftClient;
import org.apache.ratis.protocol.RaftClientReply;
+import org.apache.ratis.protocol.RaftException;
+import org.apache.ratis.retry.RetryPolicy;
import org.apache.ratis.rpc.RpcType;
import org.apache.ratis.rpc.SupportedRpcType;
-import org.apache.ratis.thirdparty.com.google.protobuf.ByteString;
+import org.apache.ratis.thirdparty.com.google.protobuf.InvalidProtocolBufferException;
import org.apache.ratis.util.TimeDuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-import java.util.*;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.stream.Collectors;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+
+import io.opentracing.Scope;
+import io.opentracing.util.GlobalTracer;
/**
* An abstract implementation of {@link XceiverClientSpi} using Ratis.
@@ -76,6 +79,12 @@ public final class XceiverClientRatis extends XceiverClientSpi {
public static XceiverClientRatis newXceiverClientRatis(
org.apache.hadoop.hdds.scm.pipeline.Pipeline pipeline,
Configuration ozoneConf) {
+ return newXceiverClientRatis(pipeline, ozoneConf, null);
+ }
+
+ public static XceiverClientRatis newXceiverClientRatis(
+ org.apache.hadoop.hdds.scm.pipeline.Pipeline pipeline,
+ Configuration ozoneConf, X509Certificate caCert) {
final String rpcType = ozoneConf
.get(ScmConfigKeys.DFS_CONTAINER_RATIS_RPC_TYPE_KEY,
ScmConfigKeys.DFS_CONTAINER_RATIS_RPC_TYPE_DEFAULT);
@@ -85,7 +94,7 @@ public static XceiverClientRatis newXceiverClientRatis(
HddsClientUtils.getMaxOutstandingRequests(ozoneConf);
final RetryPolicy retryPolicy = RatisHelper.createRetryPolicy(ozoneConf);
final GrpcTlsConfig tlsConfig = RatisHelper.createTlsClientConfig(new
- SecurityConfig(ozoneConf));
+ SecurityConfig(ozoneConf), caCert);
return new XceiverClientRatis(pipeline,
SupportedRpcType.valueOfIgnoreCase(rpcType), maxOutstandingRequests,
retryPolicy, tlsConfig, clientRequestTimeout);
@@ -161,8 +170,10 @@ public Pipeline getPipeline() {
@Override
public void connect() throws Exception {
- LOG.debug("Connecting to pipeline:{} datanode:{}", getPipeline().getId(),
- RatisHelper.toRaftPeerId(pipeline.getFirstNode()));
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Connecting to pipeline:{} datanode:{}", getPipeline().getId(),
+ RatisHelper.toRaftPeerId(pipeline.getFirstNode()));
+ }
// TODO : XceiverClient ratis should pass the config value of
// maxOutstandingRequests so as to set the upper bound on max no of async
// requests to be handled by raft client
@@ -210,16 +221,20 @@ private CompletableFuture sendRequestAsync(
try (Scope scope = GlobalTracer.get()
.buildSpan("XceiverClientRatis." + request.getCmdType().name())
.startActive(true)) {
- ContainerCommandRequestProto finalPayload =
- ContainerCommandRequestProto.newBuilder(request)
- .setTraceID(TracingUtil.exportCurrentSpan())
- .build();
- boolean isReadOnlyRequest = HddsUtils.isReadOnly(finalPayload);
- ByteString byteString = finalPayload.toByteString();
- LOG.debug("sendCommandAsync {} {}", isReadOnlyRequest, finalPayload);
- return isReadOnlyRequest ?
- getClient().sendReadOnlyAsync(() -> byteString) :
- getClient().sendAsync(() -> byteString);
+ final ContainerCommandRequestMessage message
+ = ContainerCommandRequestMessage.toMessage(
+ request, TracingUtil.exportCurrentSpan());
+ if (HddsUtils.isReadOnly(request)) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("sendCommandAsync ReadOnly {}", message);
+ }
+ return getClient().sendReadOnlyAsync(message);
+ } else {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("sendCommandAsync {}", message);
+ }
+ return getClient().sendAsync(message);
+ }
}
}
@@ -249,7 +264,9 @@ public XceiverClientReply watchForCommit(long index, long timeout)
clientReply.setLogIndex(commitIndex);
return clientReply;
}
- LOG.debug("commit index : {} watch timeout : {}", index, timeout);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("commit index : {} watch timeout : {}", index, timeout);
+ }
RaftClientReply reply;
try {
CompletableFuture replyFuture = getClient()
@@ -257,7 +274,7 @@ public XceiverClientReply watchForCommit(long index, long timeout)
replyFuture.get(timeout, TimeUnit.MILLISECONDS);
} catch (Exception e) {
Throwable t = HddsClientUtils.checkForException(e);
- LOG.warn("3 way commit failed ", e);
+ LOG.warn("3 way commit failed on pipeline {}", pipeline, e);
if (t instanceof GroupMismatchException) {
throw e;
}
@@ -276,8 +293,9 @@ public XceiverClientReply watchForCommit(long index, long timeout)
// replication.
commitInfoMap.remove(address);
LOG.info(
- "Could not commit " + index + " to all the nodes. Server " + address
- + " has failed." + " Committed by majority.");
+ "Could not commit index {} on pipeline {} to all the nodes. " +
+ "Server {} has failed. Committed by majority.",
+ index, pipeline, address);
});
}
clientReply.setLogIndex(index);
@@ -300,19 +318,18 @@ public XceiverClientReply sendCommandAsync(
metrics.incrPendingContainerOpsMetrics(request.getCmdType());
CompletableFuture containerCommandResponse =
raftClientReply.whenComplete((reply, e) -> {
- LOG.debug("received reply {} for request: cmdType={} containerID={}"
- + " pipelineID={} traceID={} exception: {}", reply,
- request.getCmdType(), request.getContainerID(),
- request.getPipelineID(), request.getTraceID(), e);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("received reply {} for request: cmdType={} containerID={}"
+ + " pipelineID={} traceID={} exception: {}", reply,
+ request.getCmdType(), request.getContainerID(),
+ request.getPipelineID(), request.getTraceID(), e);
+ }
metrics.decrPendingContainerOpsMetrics(request.getCmdType());
metrics.addContainerOpsLatency(request.getCmdType(),
Time.monotonicNowNanos() - requestTime);
}).thenApply(reply -> {
try {
- // we need to handle RaftRetryFailure Exception
- RaftRetryFailureException raftRetryFailureException =
- reply.getRetryFailureException();
- if (raftRetryFailureException != null) {
+ if (!reply.isSuccess()) {
// in case of raft retry failure, the raft client is
// not able to connect to the leader hence the pipeline
// can not be used but this instance of RaftClient will close
@@ -324,7 +341,10 @@ public XceiverClientReply sendCommandAsync(
// to SCM as in this case, it is the raft client which is not
// able to connect to leader in the pipeline, though the
// pipeline can still be functional.
- throw new CompletionException(raftRetryFailureException);
+ RaftException exception = reply.getException();
+ Preconditions.checkNotNull(exception, "Raft reply failure but " +
+ "no exception propagated.");
+ throw new CompletionException(exception);
}
ContainerCommandResponseProto response =
ContainerCommandResponseProto
diff --git a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/client/ContainerOperationClient.java b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/client/ContainerOperationClient.java
index b0be34dd9bfff..982fb8ea1eec6 100644
--- a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/client/ContainerOperationClient.java
+++ b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/client/ContainerOperationClient.java
@@ -37,7 +37,6 @@
import java.io.IOException;
import java.util.List;
-import java.util.UUID;
/**
* This class provides the client-facing APIs of container operations.
@@ -113,8 +112,7 @@ public ContainerWithPipeline createContainer(String owner)
*/
public void createContainer(XceiverClientSpi client,
long containerId) throws IOException {
- String traceID = UUID.randomUUID().toString();
- ContainerProtocolCalls.createContainer(client, containerId, traceID, null);
+ ContainerProtocolCalls.createContainer(client, containerId, null);
// Let us log this info after we let SCM know that we have completed the
// creation state.
@@ -167,8 +165,10 @@ private void createPipeline(XceiverClientSpi client, Pipeline pipeline)
// TODO : Should we change the state on the client side ??
// That makes sense, but it is not needed for the client to work.
- LOG.debug("Pipeline creation successful. Pipeline: {}",
- pipeline.toString());
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Pipeline creation successful. Pipeline: {}",
+ pipeline.toString());
+ }
}
@Override
@@ -228,6 +228,18 @@ public List listPipelines() throws IOException {
return storageContainerLocationClient.listPipelines();
}
+ @Override
+ public void activatePipeline(HddsProtos.PipelineID pipelineID)
+ throws IOException {
+ storageContainerLocationClient.activatePipeline(pipelineID);
+ }
+
+ @Override
+ public void deactivatePipeline(HddsProtos.PipelineID pipelineID)
+ throws IOException {
+ storageContainerLocationClient.deactivatePipeline(pipelineID);
+ }
+
@Override
public void closePipeline(HddsProtos.PipelineID pipelineID)
throws IOException {
@@ -257,9 +269,8 @@ public void deleteContainer(long containerId, Pipeline pipeline,
XceiverClientSpi client = null;
try {
client = xceiverClientManager.acquireClient(pipeline);
- String traceID = UUID.randomUUID().toString();
ContainerProtocolCalls
- .deleteContainer(client, containerId, force, traceID, null);
+ .deleteContainer(client, containerId, force, null);
storageContainerLocationClient
.deleteContainer(containerId);
if (LOG.isDebugEnabled()) {
@@ -307,10 +318,8 @@ public ContainerDataProto readContainer(long containerID,
XceiverClientSpi client = null;
try {
client = xceiverClientManager.acquireClient(pipeline);
- String traceID = UUID.randomUUID().toString();
ReadContainerResponseProto response =
- ContainerProtocolCalls.readContainer(client, containerID, traceID,
- null);
+ ContainerProtocolCalls.readContainer(client, containerID, null);
if (LOG.isDebugEnabled()) {
LOG.debug("Read container {}, machines: {} ", containerID,
pipeline.getNodes());
@@ -372,7 +381,9 @@ public void closeContainer(long containerId, Pipeline pipeline)
throws IOException {
XceiverClientSpi client = null;
try {
- LOG.debug("Close container {}", pipeline);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Close container {}", pipeline);
+ }
/*
TODO: two orders here, revisit this later:
1. close on SCM first, then on data node
@@ -393,7 +404,6 @@ public void closeContainer(long containerId, Pipeline pipeline)
*/
// Actually close the container on Datanode
client = xceiverClientManager.acquireClient(pipeline);
- String traceID = UUID.randomUUID().toString();
storageContainerLocationClient.notifyObjectStageChange(
ObjectStageChangeRequestProto.Type.container,
@@ -401,7 +411,7 @@ public void closeContainer(long containerId, Pipeline pipeline)
ObjectStageChangeRequestProto.Op.close,
ObjectStageChangeRequestProto.Stage.begin);
- ContainerProtocolCalls.closeContainer(client, containerId, traceID,
+ ContainerProtocolCalls.closeContainer(client, containerId,
null);
// Notify SCM to close the container
storageContainerLocationClient.notifyObjectStageChange(
@@ -465,4 +475,21 @@ public boolean inSafeMode() throws IOException {
public boolean forceExitSafeMode() throws IOException {
return storageContainerLocationClient.forceExitSafeMode();
}
+
+ @Override
+ public void startReplicationManager() throws IOException {
+ storageContainerLocationClient.startReplicationManager();
+ }
+
+ @Override
+ public void stopReplicationManager() throws IOException {
+ storageContainerLocationClient.stopReplicationManager();
+ }
+
+ @Override
+ public boolean getReplicationManagerStatus() throws IOException {
+ return storageContainerLocationClient.getReplicationManagerStatus();
+ }
+
+
}
diff --git a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/client/HddsClientUtils.java b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/client/HddsClientUtils.java
index 97b8f95b87e51..d3bb31aa69878 100644
--- a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/client/HddsClientUtils.java
+++ b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/client/HddsClientUtils.java
@@ -27,8 +27,8 @@
import org.apache.hadoop.hdds.protocol.SCMSecurityProtocol;
import org.apache.hadoop.hdds.protocolPB.SCMSecurityProtocolClientSideTranslatorPB;
import org.apache.hadoop.hdds.protocolPB.SCMSecurityProtocolPB;
-import org.apache.hadoop.hdds.scm.ScmConfigKeys;
-import org.apache.hadoop.hdds.scm.container.common.helpers.ContainerNotOpenException;
+import org.apache.hadoop.hdds.scm.XceiverClientManager.ScmClientConfig;
+import org.apache.hadoop.hdds.scm.container.common.helpers.StorageContainerException;
import org.apache.hadoop.hdds.scm.protocol.ScmBlockLocationProtocol;
import org.apache.hadoop.hdds.scm.protocolPB.ScmBlockLocationProtocolPB;
import org.apache.hadoop.io.retry.RetryPolicies;
@@ -86,7 +86,7 @@ private HddsClientUtils() {
private static final List> EXCEPTION_LIST =
new ArrayList>() {{
add(TimeoutException.class);
- add(ContainerNotOpenException.class);
+ add(StorageContainerException.class);
add(RaftRetryFailureException.class);
add(AlreadyClosedException.class);
add(GroupMismatchException.class);
@@ -126,8 +126,6 @@ public static long formatDateTime(String date) throws ParseException {
.toInstant().toEpochMilli();
}
-
-
/**
* verifies that bucket name / volume name is a valid DNS name.
*
@@ -137,27 +135,26 @@ public static long formatDateTime(String date) throws ParseException {
*/
public static void verifyResourceName(String resName)
throws IllegalArgumentException {
-
if (resName == null) {
throw new IllegalArgumentException("Bucket or Volume name is null");
}
- if ((resName.length() < OzoneConsts.OZONE_MIN_BUCKET_NAME_LENGTH) ||
- (resName.length() > OzoneConsts.OZONE_MAX_BUCKET_NAME_LENGTH)) {
+ if (resName.length() < OzoneConsts.OZONE_MIN_BUCKET_NAME_LENGTH ||
+ resName.length() > OzoneConsts.OZONE_MAX_BUCKET_NAME_LENGTH) {
throw new IllegalArgumentException(
- "Bucket or Volume length is illegal, " +
- "valid length is 3-63 characters");
+ "Bucket or Volume length is illegal, "
+ + "valid length is 3-63 characters");
}
- if ((resName.charAt(0) == '.') || (resName.charAt(0) == '-')) {
+ if (resName.charAt(0) == '.' || resName.charAt(0) == '-') {
throw new IllegalArgumentException(
"Bucket or Volume name cannot start with a period or dash");
}
- if ((resName.charAt(resName.length() - 1) == '.') ||
- (resName.charAt(resName.length() - 1) == '-')) {
- throw new IllegalArgumentException(
- "Bucket or Volume name cannot end with a period or dash");
+ if (resName.charAt(resName.length() - 1) == '.' ||
+ resName.charAt(resName.length() - 1) == '-') {
+ throw new IllegalArgumentException("Bucket or Volume name "
+ + "cannot end with a period or dash");
}
boolean isIPv4 = true;
@@ -165,36 +162,30 @@ public static void verifyResourceName(String resName)
for (int index = 0; index < resName.length(); index++) {
char currChar = resName.charAt(index);
-
if (currChar != '.') {
isIPv4 = ((currChar >= '0') && (currChar <= '9')) && isIPv4;
}
-
if (currChar > 'A' && currChar < 'Z') {
throw new IllegalArgumentException(
"Bucket or Volume name does not support uppercase characters");
}
-
- if ((currChar != '.') && (currChar != '-')) {
- if ((currChar < '0') || (currChar > '9' && currChar < 'a') ||
- (currChar > 'z')) {
+ if (currChar != '.' && currChar != '-') {
+ if (currChar < '0' || (currChar > '9' && currChar < 'a') ||
+ currChar > 'z') {
throw new IllegalArgumentException("Bucket or Volume name has an " +
"unsupported character : " +
currChar);
}
}
-
- if ((prev == '.') && (currChar == '.')) {
+ if (prev == '.' && currChar == '.') {
throw new IllegalArgumentException("Bucket or Volume name should not " +
"have two contiguous periods");
}
-
- if ((prev == '-') && (currChar == '.')) {
+ if (prev == '-' && currChar == '.') {
throw new IllegalArgumentException(
"Bucket or Volume name should not have period after dash");
}
-
- if ((prev == '.') && (currChar == '-')) {
+ if (prev == '.' && currChar == '-') {
throw new IllegalArgumentException(
"Bucket or Volume name should not have dash after period");
}
@@ -285,10 +276,9 @@ public static CloseableHttpClient newHttpClient(Configuration conf) {
* Standalone and Ratis client.
*/
public static int getMaxOutstandingRequests(Configuration config) {
- return config
- .getInt(ScmConfigKeys.SCM_CONTAINER_CLIENT_MAX_OUTSTANDING_REQUESTS,
- ScmConfigKeys
- .SCM_CONTAINER_CLIENT_MAX_OUTSTANDING_REQUESTS_DEFAULT);
+ return OzoneConfiguration.of(config)
+ .getObject(ScmClientConfig.class)
+ .getMaxOutstandingRequests();
}
/**
@@ -314,7 +304,7 @@ public static SCMSecurityProtocol getScmSecurityClient(
return scmSecurityClient;
}
- public static Throwable checkForException(Exception e) throws IOException {
+ public static Throwable checkForException(Exception e) {
Throwable t = e;
while (t != null) {
for (Class extends Exception> cls : getExceptionList()) {
@@ -324,8 +314,7 @@ public static Throwable checkForException(Exception e) throws IOException {
}
t = t.getCause();
}
-
- throw e instanceof IOException ? (IOException)e : new IOException(e);
+ return t;
}
public static RetryPolicy createRetryPolicy(int maxRetryCount,
diff --git a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/storage/BlockInputStream.java b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/storage/BlockInputStream.java
index bb4a5b05633d9..40bbd93b16f1e 100644
--- a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/storage/BlockInputStream.java
+++ b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/storage/BlockInputStream.java
@@ -19,491 +19,370 @@
package org.apache.hadoop.hdds.scm.storage;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import org.apache.hadoop.hdds.protocol.DatanodeDetails;
-import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos;
-import org.apache.hadoop.hdds.scm.XceiverClientReply;
-import org.apache.hadoop.hdds.scm.container.common.helpers
- .StorageContainerException;
-import org.apache.hadoop.ozone.common.Checksum;
-import org.apache.hadoop.ozone.common.ChecksumData;
-import org.apache.ratis.thirdparty.com.google.protobuf.ByteString;
+
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
+import org.apache.hadoop.hdds.scm.pipeline.Pipeline;
+import org.apache.hadoop.hdds.security.token.OzoneBlockTokenIdentifier;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.security.token.Token;
import org.apache.hadoop.fs.Seekable;
import org.apache.hadoop.hdds.scm.XceiverClientManager;
import org.apache.hadoop.hdds.scm.XceiverClientSpi;
import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos.ChunkInfo;
-import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos
- .ReadChunkResponseProto;
import org.apache.hadoop.hdds.client.BlockID;
+import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos.DatanodeBlockID;
+import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos.GetBlockResponseProto;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
-import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import java.util.concurrent.ExecutionException;
/**
- * An {@link InputStream} used by the REST service in combination with the
- * SCMClient to read the value of a key from a sequence
- * of container chunks. All bytes of the key value are stored in container
- * chunks. Each chunk may contain multiple underlying {@link ByteBuffer}
- * instances. This class encapsulates all state management for iterating
- * through the sequence of chunks and the sequence of buffers within each chunk.
+ * An {@link InputStream} called from KeyInputStream to read a block from the
+ * container.
+ * This class encapsulates all state management for iterating
+ * through the sequence of chunks through {@link ChunkInputStream}.
*/
public class BlockInputStream extends InputStream implements Seekable {
+ private static final Logger LOG =
+ LoggerFactory.getLogger(BlockInputStream.class);
+
private static final int EOF = -1;
private final BlockID blockID;
- private final String traceID;
+ private final long length;
+ private Pipeline pipeline;
+ private final Token token;
+ private final boolean verifyChecksum;
private XceiverClientManager xceiverClientManager;
private XceiverClientSpi xceiverClient;
- private List chunks;
- // ChunkIndex points to the index current chunk in the buffers or the the
- // index of chunk which will be read next into the buffers in
- // readChunkFromContainer().
+ private boolean initialized = false;
+
+ // List of ChunkInputStreams, one for each chunk in the block
+ private List chunkStreams;
+
+ // chunkOffsets[i] stores the index of the first data byte in
+ // chunkStream i w.r.t the block data.
+ // Let’s say we have chunk size as 40 bytes. And let's say the parent
+ // block stores data from index 200 and has length 400.
+ // The first 40 bytes of this block will be stored in chunk[0], next 40 in
+ // chunk[1] and so on. But since the chunkOffsets are w.r.t the block only
+ // and not the key, the values in chunkOffsets will be [0, 40, 80,....].
+ private long[] chunkOffsets = null;
+
+ // Index of the chunkStream corresponding to the current position of the
+ // BlockInputStream i.e offset of the data to be read next from this block
private int chunkIndex;
- // ChunkIndexOfCurrentBuffer points to the index of chunk read into the
- // buffers or index of the last chunk in the buffers. It is updated only
- // when a new chunk is read from container into the buffers.
- private int chunkIndexOfCurrentBuffer;
- private long[] chunkOffset;
- private List buffers;
- private int bufferIndex;
- private long bufferPosition;
- private final boolean verifyChecksum;
- /**
- * Creates a new BlockInputStream.
- *
- * @param blockID block ID of the chunk
- * @param xceiverClientManager client manager that controls client
- * @param xceiverClient client to perform container calls
- * @param chunks list of chunks to read
- * @param traceID container protocol call traceID
- * @param verifyChecksum verify checksum
- * @param initialPosition the initial position of the stream pointer. This
- * position is seeked now if the up-stream was seeked
- * before this was created.
- */
- public BlockInputStream(
- BlockID blockID, XceiverClientManager xceiverClientManager,
- XceiverClientSpi xceiverClient, List chunks, String traceID,
- boolean verifyChecksum, long initialPosition) throws IOException {
- this.blockID = blockID;
- this.traceID = traceID;
- this.xceiverClientManager = xceiverClientManager;
- this.xceiverClient = xceiverClient;
- this.chunks = chunks;
- this.chunkIndex = 0;
- this.chunkIndexOfCurrentBuffer = -1;
- // chunkOffset[i] stores offset at which chunk i stores data in
- // BlockInputStream
- this.chunkOffset = new long[this.chunks.size()];
- initializeChunkOffset();
- this.buffers = null;
- this.bufferIndex = 0;
- this.bufferPosition = -1;
+ // Position of the BlockInputStream is maintainted by this variable till
+ // the stream is initialized. This position is w.r.t to the block only and
+ // not the key.
+ // For the above example, if we seek to position 240 before the stream is
+ // initialized, then value of blockPosition will be set to 40.
+ // Once, the stream is initialized, the position of the stream
+ // will be determined by the current chunkStream and its position.
+ private long blockPosition = 0;
+
+ // Tracks the chunkIndex corresponding to the last blockPosition so that it
+ // can be reset if a new position is seeked.
+ private int chunkIndexOfPrevPosition;
+
+ public BlockInputStream(BlockID blockId, long blockLen, Pipeline pipeline,
+ Token token, boolean verifyChecksum,
+ XceiverClientManager xceiverClientManager) {
+ this.blockID = blockId;
+ this.length = blockLen;
+ this.pipeline = pipeline;
+ this.token = token;
this.verifyChecksum = verifyChecksum;
- if (initialPosition > 0) {
- // The stream was seeked to a position before the stream was
- // initialized. So seeking to the position now.
- seek(initialPosition);
- }
+ this.xceiverClientManager = xceiverClientManager;
}
- private void initializeChunkOffset() {
- long tempOffset = 0;
- for (int i = 0; i < chunks.size(); i++) {
- chunkOffset[i] = tempOffset;
- tempOffset += chunks.get(i).getLen();
+ /**
+ * Initialize the BlockInputStream. Get the BlockData (list of chunks) from
+ * the Container and create the ChunkInputStreams for each Chunk in the Block.
+ */
+ public synchronized void initialize() throws IOException {
+
+ // Pre-check that the stream has not been intialized already
+ if (initialized) {
+ return;
}
- }
- @Override
- public synchronized int read()
- throws IOException {
- checkOpen();
- int available = prepareRead(1);
- int dataout = EOF;
+ List chunks = getChunkInfos();
+ if (chunks != null && !chunks.isEmpty()) {
+ // For each chunk in the block, create a ChunkInputStream and compute
+ // its chunkOffset
+ this.chunkOffsets = new long[chunks.size()];
+ long tempOffset = 0;
+
+ this.chunkStreams = new ArrayList<>(chunks.size());
+ for (int i = 0; i < chunks.size(); i++) {
+ addStream(chunks.get(i));
+ chunkOffsets[i] = tempOffset;
+ tempOffset += chunks.get(i).getLen();
+ }
- if (available == EOF) {
- Preconditions
- .checkState(buffers == null); //should have released by now, see below
- } else {
- dataout = Byte.toUnsignedInt(buffers.get(bufferIndex).get());
- }
+ initialized = true;
+ this.chunkIndex = 0;
- if (blockStreamEOF()) {
- // consumer might use getPos to determine EOF,
- // so release buffers when serving the last byte of data
- releaseBuffers();
+ if (blockPosition > 0) {
+ // Stream was seeked to blockPosition before initialization. Seek to the
+ // blockPosition now.
+ seek(blockPosition);
+ }
}
-
- return dataout;
}
- @Override
- public synchronized int read(byte[] b, int off, int len) throws IOException {
- // According to the JavaDocs for InputStream, it is recommended that
- // subclasses provide an override of bulk read if possible for performance
- // reasons. In addition to performance, we need to do it for correctness
- // reasons. The Ozone REST service uses PipedInputStream and
- // PipedOutputStream to relay HTTP response data between a Jersey thread and
- // a Netty thread. It turns out that PipedInputStream/PipedOutputStream
- // have a subtle dependency (bug?) on the wrapped stream providing separate
- // implementations of single-byte read and bulk read. Without this, get key
- // responses might close the connection before writing all of the bytes
- // advertised in the Content-Length.
- if (b == null) {
- throw new NullPointerException();
- }
- if (off < 0 || len < 0 || len > b.length - off) {
- throw new IndexOutOfBoundsException();
- }
- if (len == 0) {
- return 0;
+ /**
+ * Send RPC call to get the block info from the container.
+ * @return List of chunks in this block.
+ */
+ protected List getChunkInfos() throws IOException {
+ // irrespective of the container state, we will always read via Standalone
+ // protocol.
+ if (pipeline.getType() != HddsProtos.ReplicationType.STAND_ALONE) {
+ pipeline = Pipeline.newBuilder(pipeline)
+ .setType(HddsProtos.ReplicationType.STAND_ALONE).build();
}
- checkOpen();
- int total = 0;
- while (len > 0) {
- int available = prepareRead(len);
- if (available == EOF) {
- Preconditions
- .checkState(buffers == null); //should have been released by now
- return total != 0 ? total : EOF;
+ xceiverClient = xceiverClientManager.acquireClientForReadData(pipeline);
+ boolean success = false;
+ List chunks;
+ try {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Initializing BlockInputStream for get key to access {}",
+ blockID.getContainerID());
}
- buffers.get(bufferIndex).get(b, off + total, available);
- len -= available;
- total += available;
- }
- if (blockStreamEOF()) {
- // smart consumers determine EOF by calling getPos()
- // so we release buffers when serving the final bytes of data
- releaseBuffers();
+ if (token != null) {
+ UserGroupInformation.getCurrentUser().addToken(token);
+ }
+ DatanodeBlockID datanodeBlockID = blockID
+ .getDatanodeBlockIDProtobuf();
+ GetBlockResponseProto response = ContainerProtocolCalls
+ .getBlock(xceiverClient, datanodeBlockID);
+
+ chunks = response.getBlockData().getChunksList();
+ success = true;
+ } finally {
+ if (!success) {
+ xceiverClientManager.releaseClientForReadData(xceiverClient, false);
+ }
}
- return total;
+ return chunks;
}
/**
- * Determines if all data in the stream has been consumed.
- *
- * @return true if EOF, false if more data is available
+ * Append another ChunkInputStream to the end of the list. Note that the
+ * ChunkInputStream is only created here. The chunk will be read from the
+ * Datanode only when a read operation is performed on for that chunk.
*/
- protected boolean blockStreamEOF() {
- if (buffersHaveData() || chunksRemaining()) {
- return false;
- } else {
- // if there are any chunks, we better be at the last chunk for EOF
- Preconditions.checkState(((chunks == null) || chunks.isEmpty() ||
- chunkIndex == (chunks.size() - 1)),
- "EOF detected, but not at the last chunk");
- return true;
- }
- }
-
- private void releaseBuffers() {
- //ashes to ashes, dust to dust
- buffers = null;
- bufferIndex = 0;
+ protected synchronized void addStream(ChunkInfo chunkInfo) {
+ chunkStreams.add(new ChunkInputStream(chunkInfo, blockID,
+ xceiverClient, verifyChecksum));
}
- @Override
- public synchronized void close() {
- if (xceiverClientManager != null && xceiverClient != null) {
- xceiverClientManager.releaseClient(xceiverClient, false);
- xceiverClientManager = null;
- xceiverClient = null;
- }
+ public synchronized long getRemaining() throws IOException {
+ return length - getPos();
}
/**
- * Checks if the stream is open. If not, throws an exception.
- *
- * @throws IOException if stream is closed
+ * {@inheritDoc}
*/
- private synchronized void checkOpen() throws IOException {
- if (xceiverClient == null) {
- throw new IOException("BlockInputStream has been closed.");
+ @Override
+ public synchronized int read() throws IOException {
+ byte[] buf = new byte[1];
+ if (read(buf, 0, 1) == EOF) {
+ return EOF;
}
+ return Byte.toUnsignedInt(buf[0]);
}
/**
- * Prepares to read by advancing through chunks and buffers as needed until it
- * finds data to return or encounters EOF.
- *
- * @param len desired length of data to read
- * @return length of data available to read, possibly less than desired length
+ * {@inheritDoc}
*/
- private synchronized int prepareRead(int len) throws IOException {
- for (;;) {
- if (!buffersAllocated()) {
- // The current chunk at chunkIndex has not been read from the
- // container. Read the chunk and put the data into buffers.
- readChunkFromContainer();
- }
- if (buffersHaveData()) {
- // Data is available from buffers
- ByteBuffer bb = buffers.get(bufferIndex);
- return len > bb.remaining() ? bb.remaining() : len;
- } else if (chunksRemaining()) {
- // There are additional chunks available.
- // Read the next chunk in the block.
- chunkIndex += 1;
- readChunkFromContainer();
- } else {
- // All available input has been consumed.
- return EOF;
- }
+ @Override
+ public synchronized int read(byte[] b, int off, int len) throws IOException {
+ if (b == null) {
+ throw new NullPointerException();
}
- }
-
- private boolean buffersAllocated() {
- if (buffers == null || buffers.isEmpty()) {
- return false;
+ if (off < 0 || len < 0 || len > b.length - off) {
+ throw new IndexOutOfBoundsException();
}
- return true;
- }
-
- private boolean buffersHaveData() {
- boolean hasData = false;
-
- if (buffersAllocated()) {
- while (bufferIndex < (buffers.size())) {
- if (buffers.get(bufferIndex).hasRemaining()) {
- // current buffer has data
- hasData = true;
- break;
- } else {
- if (buffersRemaining()) {
- // move to next available buffer
- ++bufferIndex;
- Preconditions.checkState(bufferIndex < buffers.size());
- } else {
- // no more buffers remaining
- break;
- }
- }
- }
+ if (len == 0) {
+ return 0;
}
- return hasData;
- }
+ if (!initialized) {
+ initialize();
+ }
- private boolean buffersRemaining() {
- return (bufferIndex < (buffers.size() - 1));
- }
+ checkOpen();
+ int totalReadLen = 0;
+ while (len > 0) {
+ // if we are at the last chunk and have read the entire chunk, return
+ if (chunkStreams.size() == 0 ||
+ (chunkStreams.size() - 1 <= chunkIndex &&
+ chunkStreams.get(chunkIndex)
+ .getRemaining() == 0)) {
+ return totalReadLen == 0 ? EOF : totalReadLen;
+ }
- private boolean chunksRemaining() {
- if ((chunks == null) || chunks.isEmpty()) {
- return false;
- }
- // Check if more chunks are remaining in the stream after chunkIndex
- if (chunkIndex < (chunks.size() - 1)) {
- return true;
+ // Get the current chunkStream and read data from it
+ ChunkInputStream current = chunkStreams.get(chunkIndex);
+ int numBytesToRead = Math.min(len, (int)current.getRemaining());
+ int numBytesRead = current.read(b, off, numBytesToRead);
+ if (numBytesRead != numBytesToRead) {
+ // This implies that there is either data loss or corruption in the
+ // chunk entries. Even EOF in the current stream would be covered in
+ // this case.
+ throw new IOException(String.format(
+ "Inconsistent read for chunkName=%s length=%d numBytesRead=%d",
+ current.getChunkName(), current.getLength(), numBytesRead));
+ }
+ totalReadLen += numBytesRead;
+ off += numBytesRead;
+ len -= numBytesRead;
+ if (current.getRemaining() <= 0 &&
+ ((chunkIndex + 1) < chunkStreams.size())) {
+ chunkIndex += 1;
+ }
}
- // ChunkIndex is the last chunk in the stream. Check if this chunk has
- // been read from container or not. Return true if chunkIndex has not
- // been read yet and false otherwise.
- return chunkIndexOfCurrentBuffer != chunkIndex;
+ return totalReadLen;
}
/**
- * Attempts to read the chunk at the specified offset in the chunk list. If
- * successful, then the data of the read chunk is saved so that its bytes can
- * be returned from subsequent read calls.
+ * Seeks the BlockInputStream to the specified position. If the stream is
+ * not initialized, save the seeked position via blockPosition. Otherwise,
+ * update the position in 2 steps:
+ * 1. Updating the chunkIndex to the chunkStream corresponding to the
+ * seeked position.
+ * 2. Seek the corresponding chunkStream to the adjusted position.
*
- * @throws IOException if there is an I/O error while performing the call
+ * Let’s say we have chunk size as 40 bytes. And let's say the parent block
+ * stores data from index 200 and has length 400. If the key was seeked to
+ * position 90, then this block will be seeked to position 90.
+ * When seek(90) is called on this blockStream, then
+ * 1. chunkIndex will be set to 2 (as indices 80 - 120 reside in chunk[2]).
+ * 2. chunkStream[2] will be seeked to position 10
+ * (= 90 - chunkOffset[2] (= 80)).
*/
- private synchronized void readChunkFromContainer() throws IOException {
- // Read the chunk at chunkIndex
- final ChunkInfo chunkInfo = chunks.get(chunkIndex);
- List excludeDns = null;
- ByteString byteString;
- List dnList = getDatanodeList();
- while (true) {
- List dnListFromReadChunkCall = new ArrayList<>();
- byteString = readChunk(chunkInfo, excludeDns, dnListFromReadChunkCall);
- try {
- if (byteString.size() != chunkInfo.getLen()) {
- // Bytes read from chunk should be equal to chunk size.
- throw new IOException(String
- .format("Inconsistent read for chunk=%s len=%d bytesRead=%d",
- chunkInfo.getChunkName(), chunkInfo.getLen(),
- byteString.size()));
- }
- ChecksumData checksumData =
- ChecksumData.getFromProtoBuf(chunkInfo.getChecksumData());
- if (verifyChecksum) {
- Checksum.verifyChecksum(byteString, checksumData);
- }
- break;
- } catch (IOException ioe) {
- // we will end up in this situation only if the checksum mismatch
- // happens or the length of the chunk mismatches.
- // In this case, read should be retried on a different replica.
- // TODO: Inform SCM of a possible corrupt container replica here
- if (excludeDns == null) {
- excludeDns = new ArrayList<>();
- }
- excludeDns.addAll(dnListFromReadChunkCall);
- if (excludeDns.size() == dnList.size()) {
- throw ioe;
- }
- }
+ @Override
+ public synchronized void seek(long pos) throws IOException {
+ if (!initialized) {
+ // Stream has not been initialized yet. Save the position so that it
+ // can be seeked when the stream is initialized.
+ blockPosition = pos;
+ return;
}
- buffers = byteString.asReadOnlyByteBufferList();
- bufferIndex = 0;
- chunkIndexOfCurrentBuffer = chunkIndex;
-
- // The bufferIndex and position might need to be adjusted if seek() was
- // called on the stream before. This needs to be done so that the buffer
- // position can be advanced to the 'seeked' position.
- adjustBufferIndex();
- }
-
- /**
- * Send RPC call to get the chunk from the container.
- */
- @VisibleForTesting
- protected ByteString readChunk(final ChunkInfo chunkInfo,
- List excludeDns, List dnListFromReply)
- throws IOException {
- XceiverClientReply reply;
- ReadChunkResponseProto readChunkResponse = null;
- try {
- reply = ContainerProtocolCalls
- .readChunk(xceiverClient, chunkInfo, blockID, traceID, excludeDns);
- ContainerProtos.ContainerCommandResponseProto response;
- response = reply.getResponse().get();
- ContainerProtocolCalls.validateContainerResponse(response);
- readChunkResponse = response.getReadChunk();
- dnListFromReply.addAll(reply.getDatanodes());
- } catch (IOException e) {
- if (e instanceof StorageContainerException) {
- throw e;
+ checkOpen();
+ if (pos < 0 || pos >= length) {
+ if (pos == 0) {
+ // It is possible for length and pos to be zero in which case
+ // seek should return instead of throwing exception
+ return;
}
- throw new IOException("Unexpected OzoneException: " + e.toString(), e);
- } catch (ExecutionException | InterruptedException e) {
- throw new IOException(
- "Failed to execute ReadChunk command for chunk " + chunkInfo
- .getChunkName(), e);
- }
- return readChunkResponse.getData();
- }
-
- @VisibleForTesting
- protected List getDatanodeList() {
- return xceiverClient.getPipeline().getNodes();
- }
-
- @Override
- public synchronized void seek(long pos) throws IOException {
- if (pos < 0 || (chunks.size() == 0 && pos > 0)
- || pos >= chunkOffset[chunks.size() - 1] + chunks.get(chunks.size() - 1)
- .getLen()) {
- throw new EOFException("EOF encountered pos: " + pos + " container key: "
- + blockID.getLocalID());
+ throw new EOFException(
+ "EOF encountered at pos: " + pos + " for block: " + blockID);
}
- if (pos < chunkOffset[chunkIndex]) {
- chunkIndex = Arrays.binarySearch(chunkOffset, 0, chunkIndex, pos);
- } else if (pos >= chunkOffset[chunkIndex] + chunks.get(chunkIndex)
- .getLen()) {
+ if (chunkIndex >= chunkStreams.size()) {
+ chunkIndex = Arrays.binarySearch(chunkOffsets, pos);
+ } else if (pos < chunkOffsets[chunkIndex]) {
chunkIndex =
- Arrays.binarySearch(chunkOffset, chunkIndex + 1, chunks.size(), pos);
+ Arrays.binarySearch(chunkOffsets, 0, chunkIndex, pos);
+ } else if (pos >= chunkOffsets[chunkIndex] + chunkStreams
+ .get(chunkIndex).getLength()) {
+ chunkIndex = Arrays.binarySearch(chunkOffsets,
+ chunkIndex + 1, chunkStreams.size(), pos);
}
if (chunkIndex < 0) {
// Binary search returns -insertionPoint - 1 if element is not present
// in the array. insertionPoint is the point at which element would be
// inserted in the sorted array. We need to adjust the chunkIndex
// accordingly so that chunkIndex = insertionPoint - 1
- chunkIndex = -chunkIndex -2;
+ chunkIndex = -chunkIndex - 2;
}
- // The bufferPosition should be adjusted to account for the chunk offset
- // of the chunk the the pos actually points to.
- bufferPosition = pos - chunkOffset[chunkIndex];
+ // Reset the previous chunkStream's position
+ chunkStreams.get(chunkIndexOfPrevPosition).resetPosition();
- // Check if current buffers correspond to the chunk index being seeked
- // and if the buffers have any data.
- if (chunkIndex == chunkIndexOfCurrentBuffer && buffersAllocated()) {
- // Position the buffer to the seeked position.
- adjustBufferIndex();
- } else {
- // Release the current buffers. The next readChunkFromContainer will
- // read the required chunk and position the buffer to the seeked
- // position.
- releaseBuffers();
- }
+ // seek to the proper offset in the ChunkInputStream
+ chunkStreams.get(chunkIndex).seek(pos - chunkOffsets[chunkIndex]);
+ chunkIndexOfPrevPosition = chunkIndex;
}
- private void adjustBufferIndex() {
- if (bufferPosition == -1) {
- // The stream has not been seeked to a position. No need to adjust the
- // buffer Index and position.
- return;
+ @Override
+ public synchronized long getPos() throws IOException {
+ if (length == 0) {
+ return 0;
}
- // The bufferPosition is w.r.t the buffers for current chunk.
- // Adjust the bufferIndex and position to the seeked position.
- long tempOffest = 0;
- for (int i = 0; i < buffers.size(); i++) {
- if (bufferPosition - tempOffest >= buffers.get(i).capacity()) {
- tempOffest += buffers.get(i).capacity();
- } else {
- bufferIndex = i;
- break;
- }
+
+ if (!initialized) {
+ // The stream is not initialized yet. Return the blockPosition
+ return blockPosition;
+ } else {
+ return chunkOffsets[chunkIndex] + chunkStreams.get(chunkIndex).getPos();
}
- buffers.get(bufferIndex).position((int) (bufferPosition - tempOffest));
- // Reset the bufferPosition as the seek() operation has been completed.
- bufferPosition = -1;
}
@Override
- public synchronized long getPos() throws IOException {
- // position = chunkOffset of current chunk (at chunkIndex) + position of
- // the buffer corresponding to the chunk.
- long bufferPos = 0;
-
- if (bufferPosition >= 0) {
- // seek has been called but the buffers were empty. Hence, the buffer
- // position will be advanced after the buffers are filled.
- // We return the chunkOffset + bufferPosition here as that will be the
- // position of the buffer pointer after reading the chunk file.
- bufferPos = bufferPosition;
-
- } else if (blockStreamEOF()) {
- // all data consumed, buffers have been released.
- // get position from the chunk offset and chunk length of last chunk
- bufferPos = chunks.get(chunkIndex).getLen();
-
- } else if (buffersAllocated()) {
- // get position from available buffers of current chunk
- bufferPos = buffers.get(bufferIndex).position();
+ public boolean seekToNewSource(long targetPos) throws IOException {
+ return false;
+ }
+ @Override
+ public synchronized void close() {
+ if (xceiverClientManager != null && xceiverClient != null) {
+ xceiverClientManager.releaseClient(xceiverClient, false);
+ xceiverClientManager = null;
+ xceiverClient = null;
}
+ }
- return chunkOffset[chunkIndex] + bufferPos;
+ public synchronized void resetPosition() {
+ this.blockPosition = 0;
}
- @Override
- public boolean seekToNewSource(long targetPos) throws IOException {
- return false;
+ /**
+ * Checks if the stream is open. If not, throw an exception.
+ *
+ * @throws IOException if stream is closed
+ */
+ protected synchronized void checkOpen() throws IOException {
+ if (xceiverClient == null) {
+ throw new IOException("BlockInputStream has been closed.");
+ }
}
public BlockID getBlockID() {
return blockID;
}
+ public long getLength() {
+ return length;
+ }
+
@VisibleForTesting
- protected int getChunkIndex() {
+ synchronized int getChunkIndex() {
return chunkIndex;
}
+
+ @VisibleForTesting
+ synchronized long getBlockPosition() {
+ return blockPosition;
+ }
+
+ @VisibleForTesting
+ synchronized List getChunkStreams() {
+ return chunkStreams;
+ }
}
diff --git a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/storage/BlockOutputStream.java b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/storage/BlockOutputStream.java
index 5ca32630c87c4..b15ca3f6c85fc 100644
--- a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/storage/BlockOutputStream.java
+++ b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/storage/BlockOutputStream.java
@@ -21,7 +21,6 @@
import com.google.common.base.Preconditions;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos;
-import org.apache.hadoop.hdds.scm.ByteStringHelper;
import org.apache.hadoop.hdds.scm.XceiverClientReply;
import org.apache.hadoop.hdds.scm.container.common.helpers.StorageContainerException;
import org.apache.hadoop.hdds.scm.pipeline.Pipeline;
@@ -29,7 +28,6 @@
import org.apache.hadoop.ozone.common.ChecksumData;
import org.apache.hadoop.ozone.common.OzoneChecksumException;
import org.apache.ratis.thirdparty.com.google.protobuf.ByteString;
-import org.apache.commons.codec.digest.DigestUtils;
import org.apache.hadoop.hdds.scm.XceiverClientManager;
import org.apache.hadoop.hdds.scm.XceiverClientSpi;
import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos.ChecksumType;
@@ -43,8 +41,6 @@
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
-import java.util.Collections;
-import java.util.UUID;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
@@ -81,14 +77,12 @@ public class BlockOutputStream extends OutputStream {
LoggerFactory.getLogger(BlockOutputStream.class);
private volatile BlockID blockID;
- private final String key;
- private final String traceID;
+
private final BlockData.Builder containerBlockData;
private XceiverClientManager xceiverClientManager;
private XceiverClientSpi xceiverClient;
private final ContainerProtos.ChecksumType checksumType;
private final int bytesPerChecksum;
- private final String streamId;
private int chunkIndex;
private int chunkSize;
private final long streamBufferFlushSize;
@@ -125,10 +119,8 @@ public class BlockOutputStream extends OutputStream {
* Creates a new BlockOutputStream.
*
* @param blockID block ID
- * @param key chunk key
* @param xceiverClientManager client manager that controls client
* @param pipeline pipeline where block will be written
- * @param traceID container protocol call args
* @param chunkSize chunk size
* @param bufferPool pool of buffers
* @param streamBufferFlushSize flush size
@@ -138,15 +130,13 @@ public class BlockOutputStream extends OutputStream {
* @param bytesPerChecksum Bytes per checksum
*/
@SuppressWarnings("parameternumber")
- public BlockOutputStream(BlockID blockID, String key,
+ public BlockOutputStream(BlockID blockID,
XceiverClientManager xceiverClientManager, Pipeline pipeline,
- String traceID, int chunkSize, long streamBufferFlushSize,
- long streamBufferMaxSize, long watchTimeout, BufferPool bufferPool,
- ChecksumType checksumType, int bytesPerChecksum)
+ int chunkSize, long streamBufferFlushSize, long streamBufferMaxSize,
+ long watchTimeout, BufferPool bufferPool, ChecksumType checksumType,
+ int bytesPerChecksum)
throws IOException {
this.blockID = blockID;
- this.key = key;
- this.traceID = traceID;
this.chunkSize = chunkSize;
KeyValue keyValue =
KeyValue.newBuilder().setKey("TYPE").setValue("KEY").build();
@@ -155,7 +145,6 @@ public BlockOutputStream(BlockID blockID, String key,
.addMetadata(keyValue);
this.xceiverClientManager = xceiverClientManager;
this.xceiverClient = xceiverClientManager.acquireClient(pipeline);
- this.streamId = UUID.randomUUID().toString();
this.chunkIndex = 0;
this.streamBufferFlushSize = streamBufferFlushSize;
this.streamBufferMaxSize = streamBufferMaxSize;
@@ -169,7 +158,7 @@ public BlockOutputStream(BlockID blockID, String key,
bufferList = null;
totalDataFlushedLength = 0;
writtenDataLength = 0;
- failedServers = Collections.emptyList();
+ failedServers = new ArrayList<>(0);
ioException = new AtomicReference<>(null);
}
@@ -358,9 +347,10 @@ private void watchForCommit(boolean bufferFull) throws IOException {
if (reply != null) {
List dnList = reply.getDatanodes();
if (!dnList.isEmpty()) {
- if (failedServers.isEmpty()) {
- failedServers = new ArrayList<>();
- }
+ Pipeline pipe = xceiverClient.getPipeline();
+
+ LOG.warn("Failed to commit BlockId {} on {}. Failed nodes: {}",
+ blockID, pipe, dnList);
failedServers.addAll(dnList);
}
}
@@ -379,13 +369,12 @@ ContainerCommandResponseProto> executePutBlock()
List byteBufferList = bufferList;
bufferList = null;
Preconditions.checkNotNull(byteBufferList);
- String requestId =
- traceID + ContainerProtos.Type.PutBlock + chunkIndex + blockID;
+
CompletableFuture flushFuture;
try {
XceiverClientReply asyncReply =
- putBlockAsync(xceiverClient, containerBlockData.build(), requestId);
+ putBlockAsync(xceiverClient, containerBlockData.build());
CompletableFuture future =
asyncReply.getResponse();
flushFuture = future.thenApplyAsync(e -> {
@@ -402,22 +391,26 @@ ContainerCommandResponseProto> executePutBlock()
.equals(responseBlockID.getContainerBlockID()));
// updates the bcsId of the block
blockID = responseBlockID;
- LOG.debug(
- "Adding index " + asyncReply.getLogIndex() + " commitMap size "
- + commitWatcher.getCommitInfoMapSize() + " flushLength "
- + flushPos + " numBuffers " + byteBufferList.size()
- + " blockID " + blockID + " bufferPool size" + bufferPool
- .getSize() + " currentBufferIndex " + bufferPool
- .getCurrentBufferIndex());
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(
+ "Adding index " + asyncReply.getLogIndex() + " commitMap size "
+ + commitWatcher.getCommitInfoMapSize() + " flushLength "
+ + flushPos + " numBuffers " + byteBufferList.size()
+ + " blockID " + blockID + " bufferPool size" + bufferPool
+ .getSize() + " currentBufferIndex " + bufferPool
+ .getCurrentBufferIndex());
+ }
// for standalone protocol, logIndex will always be 0.
commitWatcher
.updateCommitInfoMap(asyncReply.getLogIndex(), byteBufferList);
}
return e;
}, responseExecutor).exceptionally(e -> {
- LOG.debug(
- "putBlock failed for blockID " + blockID + " with exception " + e
- .getLocalizedMessage());
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(
+ "putBlock failed for blockID " + blockID + " with exception " + e
+ .getLocalizedMessage());
+ }
CompletionException ce = new CompletionException(e);
setIoException(ce);
throw ce;
@@ -596,23 +589,19 @@ public boolean isClosed() {
*/
private void writeChunkToContainer(ByteBuffer chunk) throws IOException {
int effectiveChunkSize = chunk.remaining();
- ByteString data = ByteStringHelper.getByteString(chunk);
+ ByteString data = bufferPool.byteStringConversion().apply(chunk);
Checksum checksum = new Checksum(checksumType, bytesPerChecksum);
ChecksumData checksumData = checksum.computeChecksum(chunk);
ChunkInfo chunkInfo = ChunkInfo.newBuilder()
- .setChunkName(DigestUtils.md5Hex(key) + "_stream_" + streamId +
- "_chunk_" + ++chunkIndex)
+ .setChunkName(blockID.getLocalID() + "_chunk_" + ++chunkIndex)
.setOffset(0)
.setLen(effectiveChunkSize)
.setChecksumData(checksumData.getProtoBufMessage())
.build();
- // generate a unique requestId
- String requestId =
- traceID + ContainerProtos.Type.WriteChunk + chunkIndex + chunkInfo
- .getChunkName();
+
try {
XceiverClientReply asyncReply =
- writeChunkAsync(xceiverClient, chunkInfo, blockID, data, requestId);
+ writeChunkAsync(xceiverClient, chunkInfo, blockID, data);
CompletableFuture future =
asyncReply.getResponse();
future.thenApplyAsync(e -> {
@@ -623,9 +612,11 @@ private void writeChunkToContainer(ByteBuffer chunk) throws IOException {
}
return e;
}, responseExecutor).exceptionally(e -> {
- LOG.debug(
- "writing chunk failed " + chunkInfo.getChunkName() + " blockID "
- + blockID + " with exception " + e.getLocalizedMessage());
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(
+ "writing chunk failed " + chunkInfo.getChunkName() + " blockID "
+ + blockID + " with exception " + e.getLocalizedMessage());
+ }
CompletionException ce = new CompletionException(e);
setIoException(ce);
throw ce;
@@ -634,9 +625,11 @@ private void writeChunkToContainer(ByteBuffer chunk) throws IOException {
throw new IOException(
"Unexpected Storage Container Exception: " + e.toString(), e);
}
- LOG.debug(
- "writing chunk " + chunkInfo.getChunkName() + " blockID " + blockID
- + " length " + effectiveChunkSize);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(
+ "writing chunk " + chunkInfo.getChunkName() + " blockID " + blockID
+ + " length " + effectiveChunkSize);
+ }
containerBlockData.addChunks(chunkInfo);
}
diff --git a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/storage/BufferPool.java b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/storage/BufferPool.java
index 17788c70a6c67..6d534579c8605 100644
--- a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/storage/BufferPool.java
+++ b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/storage/BufferPool.java
@@ -19,10 +19,13 @@
package org.apache.hadoop.hdds.scm.storage;
import com.google.common.base.Preconditions;
+import org.apache.hadoop.hdds.scm.ByteStringConversion;
+import org.apache.ratis.thirdparty.com.google.protobuf.ByteString;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Function;
/**
* This class creates and manages pool of n buffers.
@@ -33,12 +36,24 @@ public class BufferPool {
private int currentBufferIndex;
private final int bufferSize;
private final int capacity;
+ private final Function byteStringConversion;
public BufferPool(int bufferSize, int capacity) {
+ this(bufferSize, capacity,
+ ByteStringConversion.createByteBufferConversion(null));
+ }
+
+ public BufferPool(int bufferSize, int capacity,
+ Function byteStringConversion){
this.capacity = capacity;
this.bufferSize = bufferSize;
bufferList = new ArrayList<>(capacity);
currentBufferIndex = -1;
+ this.byteStringConversion = byteStringConversion;
+ }
+
+ public Function byteStringConversion(){
+ return byteStringConversion;
}
public ByteBuffer getCurrentBuffer() {
diff --git a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/storage/ChunkInputStream.java b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/storage/ChunkInputStream.java
new file mode 100644
index 0000000000000..f94d2d87340be
--- /dev/null
+++ b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/storage/ChunkInputStream.java
@@ -0,0 +1,544 @@
+/*
+ * 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.hdds.scm.storage;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import org.apache.hadoop.fs.Seekable;
+import org.apache.hadoop.hdds.client.BlockID;
+import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos.ContainerCommandRequestProto;
+import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos.ContainerCommandResponseProto;
+import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos.ChunkInfo;
+import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos.ReadChunkResponseProto;
+import org.apache.hadoop.hdds.scm.XceiverClientSpi;
+import org.apache.hadoop.hdds.scm.container.common.helpers.StorageContainerException;
+import org.apache.hadoop.ozone.common.Checksum;
+import org.apache.hadoop.ozone.common.ChecksumData;
+import org.apache.hadoop.ozone.common.OzoneChecksumException;
+import org.apache.ratis.thirdparty.com.google.protobuf.ByteString;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+/**
+ * An {@link InputStream} called from BlockInputStream to read a chunk from the
+ * container. Each chunk may contain multiple underlying {@link ByteBuffer}
+ * instances.
+ */
+public class ChunkInputStream extends InputStream implements Seekable {
+
+ private ChunkInfo chunkInfo;
+ private final long length;
+ private final BlockID blockID;
+ private XceiverClientSpi xceiverClient;
+ private boolean verifyChecksum;
+ private boolean allocated = false;
+
+ // Buffer to store the chunk data read from the DN container
+ private List buffers;
+
+ // Index of the buffers corresponding to the current position of the buffers
+ private int bufferIndex;
+
+ // The offset of the current data residing in the buffers w.r.t the start
+ // of chunk data
+ private long bufferOffset;
+
+ // The number of bytes of chunk data residing in the buffers currently
+ private long bufferLength;
+
+ // Position of the ChunkInputStream is maintained by this variable (if a
+ // seek is performed. This position is w.r.t to the chunk only and not the
+ // block or key. This variable is set only if either the buffers are not
+ // yet allocated or the if the allocated buffers do not cover the seeked
+ // position. Once the chunk is read, this variable is reset.
+ private long chunkPosition = -1;
+
+ private static final int EOF = -1;
+
+ ChunkInputStream(ChunkInfo chunkInfo, BlockID blockId,
+ XceiverClientSpi xceiverClient, boolean verifyChecksum) {
+ this.chunkInfo = chunkInfo;
+ this.length = chunkInfo.getLen();
+ this.blockID = blockId;
+ this.xceiverClient = xceiverClient;
+ this.verifyChecksum = verifyChecksum;
+ }
+
+ public synchronized long getRemaining() throws IOException {
+ return length - getPos();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public synchronized int read() throws IOException {
+ checkOpen();
+ int available = prepareRead(1);
+ int dataout = EOF;
+
+ if (available == EOF) {
+ // There is no more data in the chunk stream. The buffers should have
+ // been released by now
+ Preconditions.checkState(buffers == null);
+ } else {
+ dataout = Byte.toUnsignedInt(buffers.get(bufferIndex).get());
+ }
+
+ if (chunkStreamEOF()) {
+ // consumer might use getPos to determine EOF,
+ // so release buffers when serving the last byte of data
+ releaseBuffers();
+ }
+
+ return dataout;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public synchronized int read(byte[] b, int off, int len) throws IOException {
+ // According to the JavaDocs for InputStream, it is recommended that
+ // subclasses provide an override of bulk read if possible for performance
+ // reasons. In addition to performance, we need to do it for correctness
+ // reasons. The Ozone REST service uses PipedInputStream and
+ // PipedOutputStream to relay HTTP response data between a Jersey thread and
+ // a Netty thread. It turns out that PipedInputStream/PipedOutputStream
+ // have a subtle dependency (bug?) on the wrapped stream providing separate
+ // implementations of single-byte read and bulk read. Without this, get key
+ // responses might close the connection before writing all of the bytes
+ // advertised in the Content-Length.
+ if (b == null) {
+ throw new NullPointerException();
+ }
+ if (off < 0 || len < 0 || len > b.length - off) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (len == 0) {
+ return 0;
+ }
+ checkOpen();
+ int total = 0;
+ while (len > 0) {
+ int available = prepareRead(len);
+ if (available == EOF) {
+ // There is no more data in the chunk stream. The buffers should have
+ // been released by now
+ Preconditions.checkState(buffers == null);
+ return total != 0 ? total : EOF;
+ }
+ buffers.get(bufferIndex).get(b, off + total, available);
+ len -= available;
+ total += available;
+ }
+
+ if (chunkStreamEOF()) {
+ // smart consumers determine EOF by calling getPos()
+ // so we release buffers when serving the final bytes of data
+ releaseBuffers();
+ }
+
+ return total;
+ }
+
+ /**
+ * Seeks the ChunkInputStream to the specified position. This is done by
+ * updating the chunkPosition to the seeked position in case the buffers
+ * are not allocated or buffers do not contain the data corresponding to
+ * the seeked position (determined by buffersHavePosition()). Otherwise,
+ * the buffers position is updated to the seeked position.
+ */
+ @Override
+ public synchronized void seek(long pos) throws IOException {
+ if (pos < 0 || pos >= length) {
+ if (pos == 0) {
+ // It is possible for length and pos to be zero in which case
+ // seek should return instead of throwing exception
+ return;
+ }
+ throw new EOFException("EOF encountered at pos: " + pos + " for chunk: "
+ + chunkInfo.getChunkName());
+ }
+
+ if (buffersHavePosition(pos)) {
+ // The bufferPosition is w.r.t the current chunk.
+ // Adjust the bufferIndex and position to the seeked position.
+ adjustBufferPosition(pos - bufferOffset);
+ } else {
+ chunkPosition = pos;
+ }
+ }
+
+ @Override
+ public synchronized long getPos() throws IOException {
+ if (chunkPosition >= 0) {
+ return chunkPosition;
+ }
+ if (chunkStreamEOF()) {
+ return length;
+ }
+ if (buffersHaveData()) {
+ return bufferOffset + buffers.get(bufferIndex).position();
+ }
+ if (buffersAllocated()) {
+ return bufferOffset + bufferLength;
+ }
+ return 0;
+ }
+
+ @Override
+ public boolean seekToNewSource(long targetPos) throws IOException {
+ return false;
+ }
+
+ @Override
+ public synchronized void close() {
+ if (xceiverClient != null) {
+ xceiverClient = null;
+ }
+ }
+
+ /**
+ * Checks if the stream is open. If not, throw an exception.
+ *
+ * @throws IOException if stream is closed
+ */
+ protected synchronized void checkOpen() throws IOException {
+ if (xceiverClient == null) {
+ throw new IOException("BlockInputStream has been closed.");
+ }
+ }
+
+ /**
+ * Prepares to read by advancing through buffers or allocating new buffers,
+ * as needed until it finds data to return, or encounters EOF.
+ * @param len desired lenght of data to read
+ * @return length of data available to read, possibly less than desired length
+ */
+ private synchronized int prepareRead(int len) throws IOException {
+ for (;;) {
+ if (chunkPosition >= 0) {
+ if (buffersHavePosition(chunkPosition)) {
+ // The current buffers have the seeked position. Adjust the buffer
+ // index and position to point to the chunkPosition.
+ adjustBufferPosition(chunkPosition - bufferOffset);
+ } else {
+ // Read a required chunk data to fill the buffers with seeked
+ // position data
+ readChunkFromContainer(len);
+ }
+ }
+ if (buffersHaveData()) {
+ // Data is available from buffers
+ ByteBuffer bb = buffers.get(bufferIndex);
+ return len > bb.remaining() ? bb.remaining() : len;
+ } else if (dataRemainingInChunk()) {
+ // There is more data in the chunk stream which has not
+ // been read into the buffers yet.
+ readChunkFromContainer(len);
+ } else {
+ // All available input from this chunk stream has been consumed.
+ return EOF;
+ }
+ }
+ }
+
+ /**
+ * Reads full or partial Chunk from DN Container based on the current
+ * position of the ChunkInputStream, the number of bytes of data to read
+ * and the checksum boundaries.
+ * If successful, then the read data in saved in the buffers so that
+ * subsequent read calls can utilize it.
+ * @param len number of bytes of data to be read
+ * @throws IOException if there is an I/O error while performing the call
+ * to Datanode
+ */
+ private synchronized void readChunkFromContainer(int len) throws IOException {
+
+ // index of first byte to be read from the chunk
+ long startByteIndex;
+ if (chunkPosition >= 0) {
+ // If seek operation was called to advance the buffer position, the
+ // chunk should be read from that position onwards.
+ startByteIndex = chunkPosition;
+ } else {
+ // Start reading the chunk from the last chunkPosition onwards.
+ startByteIndex = bufferOffset + bufferLength;
+ }
+
+ if (verifyChecksum) {
+ // Update the bufferOffset and bufferLength as per the checksum
+ // boundary requirement.
+ computeChecksumBoundaries(startByteIndex, len);
+ } else {
+ // Read from the startByteIndex
+ bufferOffset = startByteIndex;
+ bufferLength = len;
+ }
+
+ // Adjust the chunkInfo so that only the required bytes are read from
+ // the chunk.
+ final ChunkInfo adjustedChunkInfo = ChunkInfo.newBuilder(chunkInfo)
+ .setOffset(bufferOffset)
+ .setLen(bufferLength)
+ .build();
+
+ ByteString byteString = readChunk(adjustedChunkInfo);
+
+ buffers = byteString.asReadOnlyByteBufferList();
+ bufferIndex = 0;
+ allocated = true;
+
+ // If the stream was seeked to position before, then the buffer
+ // position should be adjusted as the reads happen at checksum boundaries.
+ // The buffers position might need to be adjusted for the following
+ // scenarios:
+ // 1. Stream was seeked to a position before the chunk was read
+ // 2. Chunk was read from index < the current position to account for
+ // checksum boundaries.
+ adjustBufferPosition(startByteIndex - bufferOffset);
+ }
+
+ /**
+ * Send RPC call to get the chunk from the container.
+ */
+ @VisibleForTesting
+ protected ByteString readChunk(ChunkInfo readChunkInfo) throws IOException {
+ ReadChunkResponseProto readChunkResponse;
+
+ try {
+ List validators =
+ ContainerProtocolCalls.getValidatorList();
+ validators.add(validator);
+
+ readChunkResponse = ContainerProtocolCalls.readChunk(xceiverClient,
+ readChunkInfo, blockID, validators);
+
+ } catch (IOException e) {
+ if (e instanceof StorageContainerException) {
+ throw e;
+ }
+ throw new IOException("Unexpected OzoneException: " + e.toString(), e);
+ }
+
+ return readChunkResponse.getData();
+ }
+
+ private CheckedBiFunction validator =
+ (request, response) -> {
+ final ChunkInfo reqChunkInfo =
+ request.getReadChunk().getChunkData();
+
+ ReadChunkResponseProto readChunkResponse = response.getReadChunk();
+ ByteString byteString = readChunkResponse.getData();
+
+ if (byteString.size() != reqChunkInfo.getLen()) {
+ // Bytes read from chunk should be equal to chunk size.
+ throw new OzoneChecksumException(String
+ .format("Inconsistent read for chunk=%s len=%d bytesRead=%d",
+ reqChunkInfo.getChunkName(), reqChunkInfo.getLen(),
+ byteString.size()));
+ }
+
+ if (verifyChecksum) {
+ ChecksumData checksumData = ChecksumData.getFromProtoBuf(
+ chunkInfo.getChecksumData());
+
+ // ChecksumData stores checksum for each 'numBytesPerChecksum'
+ // number of bytes in a list. Compute the index of the first
+ // checksum to match with the read data
+
+ int checkumStartIndex = (int) (reqChunkInfo.getOffset() /
+ checksumData.getBytesPerChecksum());
+ Checksum.verifyChecksum(
+ byteString, checksumData, checkumStartIndex);
+ }
+ };
+
+ /**
+ * Return the offset and length of bytes that need to be read from the
+ * chunk file to cover the checksum boundaries covering the actual start and
+ * end of the chunk index to be read.
+ * For example, lets say the client is reading from index 120 to 450 in the
+ * chunk. And let's say checksum is stored for every 100 bytes in the chunk
+ * i.e. the first checksum is for bytes from index 0 to 99, the next for
+ * bytes from index 100 to 199 and so on. To verify bytes from 120 to 450,
+ * we would need to read from bytes 100 to 499 so that checksum
+ * verification can be done.
+ *
+ * @param startByteIndex the first byte index to be read by client
+ * @param dataLen number of bytes to be read from the chunk
+ */
+ private void computeChecksumBoundaries(long startByteIndex, int dataLen) {
+
+ int bytesPerChecksum = chunkInfo.getChecksumData().getBytesPerChecksum();
+ // index of the last byte to be read from chunk, inclusively.
+ final long endByteIndex = startByteIndex + dataLen - 1;
+
+ bufferOffset = (startByteIndex / bytesPerChecksum)
+ * bytesPerChecksum; // inclusive
+ final long endIndex = ((endByteIndex / bytesPerChecksum) + 1)
+ * bytesPerChecksum; // exclusive
+ bufferLength = Math.min(endIndex, length) - bufferOffset;
+ }
+
+ /**
+ * Adjust the buffers position to account for seeked position and/ or checksum
+ * boundary reads.
+ * @param bufferPosition the position to which the buffers must be advanced
+ */
+ private void adjustBufferPosition(long bufferPosition) {
+ // The bufferPosition is w.r.t the current chunk.
+ // Adjust the bufferIndex and position to the seeked chunkPosition.
+ long tempOffest = 0;
+ for (int i = 0; i < buffers.size(); i++) {
+ if (bufferPosition - tempOffest >= buffers.get(i).capacity()) {
+ tempOffest += buffers.get(i).capacity();
+ } else {
+ bufferIndex = i;
+ break;
+ }
+ }
+ buffers.get(bufferIndex).position((int) (bufferPosition - tempOffest));
+
+ // Reset the chunkPosition as chunk stream has been initialized i.e. the
+ // buffers have been allocated.
+ resetPosition();
+ }
+
+ /**
+ * Check if the buffers have been allocated data and false otherwise.
+ */
+ private boolean buffersAllocated() {
+ return buffers != null && !buffers.isEmpty();
+ }
+
+ /**
+ * Check if the buffers have any data remaining between the current
+ * position and the limit.
+ */
+ private boolean buffersHaveData() {
+ boolean hasData = false;
+
+ if (buffersAllocated()) {
+ while (bufferIndex < (buffers.size())) {
+ if (buffers.get(bufferIndex).hasRemaining()) {
+ // current buffer has data
+ hasData = true;
+ break;
+ } else {
+ if (buffersRemaining()) {
+ // move to next available buffer
+ ++bufferIndex;
+ Preconditions.checkState(bufferIndex < buffers.size());
+ } else {
+ // no more buffers remaining
+ break;
+ }
+ }
+ }
+ }
+
+ return hasData;
+ }
+
+ private boolean buffersRemaining() {
+ return (bufferIndex < (buffers.size() - 1));
+ }
+
+ /**
+ * Check if curernt buffers have the data corresponding to the input position.
+ */
+ private boolean buffersHavePosition(long pos) {
+ // Check if buffers have been allocated
+ if (buffersAllocated()) {
+ // Check if the current buffers cover the input position
+ return pos >= bufferOffset &&
+ pos < bufferOffset + bufferLength;
+ }
+ return false;
+ }
+
+ /**
+ * Check if there is more data in the chunk which has not yet been read
+ * into the buffers.
+ */
+ private boolean dataRemainingInChunk() {
+ long bufferPos;
+ if (chunkPosition >= 0) {
+ bufferPos = chunkPosition;
+ } else {
+ bufferPos = bufferOffset + bufferLength;
+ }
+
+ return bufferPos < length;
+ }
+
+ /**
+ * Check if end of chunkStream has been reached.
+ */
+ private boolean chunkStreamEOF() {
+ if (!allocated) {
+ // Chunk data has not been read yet
+ return false;
+ }
+
+ if (buffersHaveData() || dataRemainingInChunk()) {
+ return false;
+ } else {
+ Preconditions.checkState(bufferOffset + bufferLength == length,
+ "EOF detected, but not at the last byte of the chunk");
+ return true;
+ }
+ }
+
+ /**
+ * If EOF is reached, release the buffers.
+ */
+ private void releaseBuffers() {
+ buffers = null;
+ bufferIndex = 0;
+ }
+
+ /**
+ * Reset the chunkPosition once the buffers are allocated.
+ */
+ void resetPosition() {
+ this.chunkPosition = -1;
+ }
+
+ String getChunkName() {
+ return chunkInfo.getChunkName();
+ }
+
+ protected long getLength() {
+ return length;
+ }
+
+ @VisibleForTesting
+ protected long getChunkPosition() {
+ return chunkPosition;
+ }
+}
diff --git a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/storage/CommitWatcher.java b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/storage/CommitWatcher.java
index d4606b514c461..1d9d55bfbfbb6 100644
--- a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/storage/CommitWatcher.java
+++ b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/storage/CommitWatcher.java
@@ -131,7 +131,9 @@ public XceiverClientReply watchOnFirstIndex() throws IOException {
long index =
commitIndex2flushedDataMap.keySet().stream().mapToLong(v -> v).min()
.getAsLong();
- LOG.debug("waiting for first index " + index + " to catch up");
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("waiting for first index " + index + " to catch up");
+ }
return watchForCommit(index);
} else {
return null;
@@ -153,7 +155,9 @@ public XceiverClientReply watchOnLastIndex()
long index =
commitIndex2flushedDataMap.keySet().stream().mapToLong(v -> v).max()
.getAsLong();
- LOG.debug("waiting for last flush Index " + index + " to catch up");
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("waiting for last flush Index " + index + " to catch up");
+ }
return watchForCommit(index);
} else {
return null;
diff --git a/hadoop-hdds/client/src/test/java/org/apache/hadoop/hdds/scm/storage/TestBlockInputStream.java b/hadoop-hdds/client/src/test/java/org/apache/hadoop/hdds/scm/storage/TestBlockInputStream.java
index 35c102257f4b4..042bfd941743e 100644
--- a/hadoop-hdds/client/src/test/java/org/apache/hadoop/hdds/scm/storage/TestBlockInputStream.java
+++ b/hadoop-hdds/client/src/test/java/org/apache/hadoop/hdds/scm/storage/TestBlockInputStream.java
@@ -1,32 +1,33 @@
-/**
- * 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
- *
- * 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.
+/*
+ * 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.hdds.scm.storage;
+import com.google.common.primitives.Bytes;
import org.apache.hadoop.hdds.client.BlockID;
import org.apache.hadoop.hdds.client.ContainerBlockID;
-import org.apache.hadoop.hdds.protocol.DatanodeDetails;
-import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos
- .ChecksumData;
-import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos
- .ChecksumType;
+import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos.ChecksumType;
import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos.ChunkInfo;
import org.apache.hadoop.hdds.scm.XceiverClientManager;
-import org.apache.hadoop.hdds.scm.XceiverClientSpi;
-import org.apache.ratis.thirdparty.com.google.protobuf.ByteString;
+import org.apache.hadoop.hdds.scm.pipeline.Pipeline;
+import org.apache.hadoop.hdds.security.token.OzoneBlockTokenIdentifier;
+import org.apache.hadoop.ozone.common.Checksum;
+import org.apache.hadoop.security.token.Token;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -34,107 +35,126 @@
import java.io.EOFException;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Random;
-import java.util.UUID;
+
+import static org.apache.hadoop.hdds.scm.storage.TestChunkInputStream.generateRandomData;
/**
- * Tests {@link BlockInputStream}.
+ * Tests for {@link BlockInputStream}'s functionality.
*/
public class TestBlockInputStream {
- private static BlockInputStream blockInputStream;
- private static List chunks;
- private static int blockSize;
+ private static final int CHUNK_SIZE = 100;
+ private static Checksum checksum;
- private static final int CHUNK_SIZE = 20;
+ private BlockInputStream blockStream;
+ private byte[] blockData;
+ private int blockSize;
+ private List chunks;
+ private Map chunkDataMap;
@Before
public void setup() throws Exception {
BlockID blockID = new BlockID(new ContainerBlockID(1, 1));
- chunks = createChunkList(10);
- String traceID = UUID.randomUUID().toString();
- blockInputStream = new DummyBlockInputStream(blockID, null, null, chunks,
- traceID, false, 0);
-
- blockSize = 0;
- for (ChunkInfo chunk : chunks) {
- blockSize += chunk.getLen();
- }
+ checksum = new Checksum(ChecksumType.NONE, CHUNK_SIZE);
+ createChunkList(5);
+
+ blockStream = new DummyBlockInputStream(blockID, blockSize, null, null,
+ false, null);
}
/**
* Create a mock list of chunks. The first n-1 chunks of length CHUNK_SIZE
* and the last chunk with length CHUNK_SIZE/2.
- * @param numChunks
- * @return
*/
- private static List createChunkList(int numChunks) {
- ChecksumData dummyChecksumData = ChecksumData.newBuilder()
- .setType(ChecksumType.NONE)
- .setBytesPerChecksum(100)
- .build();
- List chunkList = new ArrayList<>(numChunks);
- int i;
- for (i = 0; i < numChunks - 1; i++) {
- String chunkName = "chunk-" + i;
+ private void createChunkList(int numChunks)
+ throws Exception {
+
+ chunks = new ArrayList<>(numChunks);
+ chunkDataMap = new HashMap<>();
+ blockData = new byte[0];
+ int i, chunkLen;
+ byte[] byteData;
+ String chunkName;
+
+ for (i = 0; i < numChunks; i++) {
+ chunkName = "chunk-" + i;
+ chunkLen = CHUNK_SIZE;
+ if (i == numChunks - 1) {
+ chunkLen = CHUNK_SIZE / 2;
+ }
+ byteData = generateRandomData(chunkLen);
ChunkInfo chunkInfo = ChunkInfo.newBuilder()
.setChunkName(chunkName)
.setOffset(0)
- .setLen(CHUNK_SIZE)
- .setChecksumData(dummyChecksumData)
+ .setLen(chunkLen)
+ .setChecksumData(checksum.computeChecksum(
+ byteData, 0, chunkLen).getProtoBufMessage())
.build();
- chunkList.add(chunkInfo);
+
+ chunkDataMap.put(chunkName, byteData);
+ chunks.add(chunkInfo);
+
+ blockSize += chunkLen;
+ blockData = Bytes.concat(blockData, byteData);
}
- ChunkInfo chunkInfo = ChunkInfo.newBuilder()
- .setChunkName("chunk-" + i)
- .setOffset(0)
- .setLen(CHUNK_SIZE/2)
- .setChecksumData(dummyChecksumData)
- .build();
- chunkList.add(chunkInfo);
-
- return chunkList;
}
/**
- * A dummy BlockInputStream to test the functionality of BlockInputStream.
+ * A dummy BlockInputStream to mock read block call to DN.
*/
- private static class DummyBlockInputStream extends BlockInputStream {
+ private class DummyBlockInputStream extends BlockInputStream {
- DummyBlockInputStream(BlockID blockID,
- XceiverClientManager xceiverClientManager,
- XceiverClientSpi xceiverClient,
- List chunks,
- String traceID,
+ DummyBlockInputStream(BlockID blockId,
+ long blockLen,
+ Pipeline pipeline,
+ Token token,
boolean verifyChecksum,
- long initialPosition) throws IOException {
- super(blockID, xceiverClientManager, xceiverClient, chunks, traceID,
- verifyChecksum, initialPosition);
+ XceiverClientManager xceiverClientManager) {
+ super(blockId, blockLen, pipeline, token, verifyChecksum,
+ xceiverClientManager);
}
@Override
- protected ByteString readChunk(final ChunkInfo chunkInfo,
- List excludeDns, List dnListFromReply)
- throws IOException {
- return getByteString(chunkInfo.getChunkName(), (int) chunkInfo.getLen());
+ protected List getChunkInfos() {
+ return chunks;
}
@Override
- protected List getDatanodeList() {
- // return an empty dummy list of size 10
- return new ArrayList<>(10);
+ protected void addStream(ChunkInfo chunkInfo) {
+ TestChunkInputStream testChunkInputStream = new TestChunkInputStream();
+ getChunkStreams().add(testChunkInputStream.new DummyChunkInputStream(
+ chunkInfo, null, null, false,
+ chunkDataMap.get(chunkInfo.getChunkName()).clone()));
}
- /**
- * Create ByteString with the input data to return when a readChunk call is
- * placed.
- */
- private static ByteString getByteString(String data, int length) {
- while (data.length() < length) {
- data = data + "0";
- }
- return ByteString.copyFrom(data.getBytes(), 0, length);
+ @Override
+ protected synchronized void checkOpen() throws IOException {
+ // No action needed
+ }
+ }
+
+ private void seekAndVerify(int pos) throws Exception {
+ blockStream.seek(pos);
+ Assert.assertEquals("Current position of buffer does not match with the " +
+ "seeked position", pos, blockStream.getPos());
+ }
+
+ /**
+ * Match readData with the chunkData byte-wise.
+ * @param readData Data read through ChunkInputStream
+ * @param inputDataStartIndex first index (inclusive) in chunkData to compare
+ * with read data
+ * @param length the number of bytes of data to match starting from
+ * inputDataStartIndex
+ */
+ private void matchWithInputData(byte[] readData, int inputDataStartIndex,
+ int length) {
+ for (int i = inputDataStartIndex; i < inputDataStartIndex + length; i++) {
+ Assert.assertEquals(blockData[i], readData[i - inputDataStartIndex]);
}
}
@@ -144,17 +164,26 @@ public void testSeek() throws Exception {
int pos = 0;
seekAndVerify(pos);
Assert.assertEquals("ChunkIndex is incorrect", 0,
- blockInputStream.getChunkIndex());
+ blockStream.getChunkIndex());
+ // Before BlockInputStream is initialized (initialization happens during
+ // read operation), seek should update the BlockInputStream#blockPosition
pos = CHUNK_SIZE;
seekAndVerify(pos);
+ Assert.assertEquals("ChunkIndex is incorrect", 0,
+ blockStream.getChunkIndex());
+ Assert.assertEquals(pos, blockStream.getBlockPosition());
+
+ // Initialize the BlockInputStream. After initializtion, the chunkIndex
+ // should be updated to correspond to the seeked position.
+ blockStream.initialize();
Assert.assertEquals("ChunkIndex is incorrect", 1,
- blockInputStream.getChunkIndex());
+ blockStream.getChunkIndex());
- pos = (CHUNK_SIZE * 5) + 5;
+ pos = (CHUNK_SIZE * 4) + 5;
seekAndVerify(pos);
- Assert.assertEquals("ChunkIndex is incorrect", 5,
- blockInputStream.getChunkIndex());
+ Assert.assertEquals("ChunkIndex is incorrect", 4,
+ blockStream.getChunkIndex());
try {
// Try seeking beyond the blockSize.
@@ -162,7 +191,7 @@ public void testSeek() throws Exception {
seekAndVerify(pos);
Assert.fail("Seek to position beyond block size should fail.");
} catch (EOFException e) {
- // Expected
+ System.out.println(e);
}
// Seek to random positions between 0 and the block size.
@@ -174,20 +203,32 @@ public void testSeek() throws Exception {
}
@Test
- public void testBlockEOF() throws Exception {
- // Seek to some position < blockSize and verify EOF is not reached.
- seekAndVerify(CHUNK_SIZE);
- Assert.assertFalse(blockInputStream.blockStreamEOF());
-
- // Seek to blockSize-1 and verify that EOF is not reached as the chunk
- // has not been read from container yet.
- seekAndVerify(blockSize-1);
- Assert.assertFalse(blockInputStream.blockStreamEOF());
+ public void testRead() throws Exception {
+ // read 200 bytes of data starting from position 50. Chunk0 contains
+ // indices 0 to 99, chunk1 from 100 to 199 and chunk3 from 200 to 299. So
+ // the read should result in 3 ChunkInputStream reads
+ seekAndVerify(50);
+ byte[] b = new byte[200];
+ blockStream.read(b, 0, 200);
+ matchWithInputData(b, 50, 200);
+
+ // The new position of the blockInputStream should be the last index read
+ // + 1.
+ Assert.assertEquals(250, blockStream.getPos());
+ Assert.assertEquals(2, blockStream.getChunkIndex());
}
- private void seekAndVerify(int pos) throws Exception {
- blockInputStream.seek(pos);
- Assert.assertEquals("Current position of buffer does not match with the " +
- "seeked position", pos, blockInputStream.getPos());
+ @Test
+ public void testSeekAndRead() throws Exception {
+ // Seek to a position and read data
+ seekAndVerify(50);
+ byte[] b1 = new byte[100];
+ blockStream.read(b1, 0, 100);
+ matchWithInputData(b1, 50, 100);
+
+ // Next read should start from the position of the last read + 1 i.e. 100
+ byte[] b2 = new byte[100];
+ blockStream.read(b2, 0, 100);
+ matchWithInputData(b2, 150, 100);
}
}
diff --git a/hadoop-hdds/client/src/test/java/org/apache/hadoop/hdds/scm/storage/TestChunkInputStream.java b/hadoop-hdds/client/src/test/java/org/apache/hadoop/hdds/scm/storage/TestChunkInputStream.java
new file mode 100644
index 0000000000000..a5fe26b5619ab
--- /dev/null
+++ b/hadoop-hdds/client/src/test/java/org/apache/hadoop/hdds/scm/storage/TestChunkInputStream.java
@@ -0,0 +1,222 @@
+/*
+ * 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.hdds.scm.storage;
+
+import org.apache.hadoop.hdds.client.BlockID;
+import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos.ChecksumType;
+import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos.ChunkInfo;
+import org.apache.hadoop.hdds.scm.XceiverClientSpi;
+import org.apache.hadoop.ozone.OzoneConfigKeys;
+import org.apache.hadoop.ozone.common.Checksum;
+import org.apache.hadoop.test.GenericTestUtils;
+import org.apache.ratis.thirdparty.com.google.protobuf.ByteString;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.EOFException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * Tests for {@link ChunkInputStream}'s functionality.
+ */
+public class TestChunkInputStream {
+
+ private static final int CHUNK_SIZE = 100;
+ private static final int BYTES_PER_CHECKSUM = 20;
+ private static final String CHUNK_NAME = "dummyChunk";
+ private static final Random RANDOM = new Random();
+ private static Checksum checksum;
+
+ private DummyChunkInputStream chunkStream;
+ private ChunkInfo chunkInfo;
+ private byte[] chunkData;
+
+ @Before
+ public void setup() throws Exception {
+ checksum = new Checksum(ChecksumType.valueOf(
+ OzoneConfigKeys.OZONE_CLIENT_CHECKSUM_TYPE_DEFAULT),
+ BYTES_PER_CHECKSUM);
+
+ chunkData = generateRandomData(CHUNK_SIZE);
+
+ chunkInfo = ChunkInfo.newBuilder()
+ .setChunkName(CHUNK_NAME)
+ .setOffset(0)
+ .setLen(CHUNK_SIZE)
+ .setChecksumData(checksum.computeChecksum(
+ chunkData, 0, CHUNK_SIZE).getProtoBufMessage())
+ .build();
+
+ chunkStream = new DummyChunkInputStream(chunkInfo, null, null, true);
+ }
+
+ static byte[] generateRandomData(int length) {
+ byte[] bytes = new byte[length];
+ RANDOM.nextBytes(bytes);
+ return bytes;
+ }
+
+ /**
+ * A dummy ChunkInputStream to mock read chunk calls to DN.
+ */
+ public class DummyChunkInputStream extends ChunkInputStream {
+
+ // Stores the read chunk data in each readChunk call
+ private List readByteBuffers = new ArrayList<>();
+
+ DummyChunkInputStream(ChunkInfo chunkInfo,
+ BlockID blockId,
+ XceiverClientSpi xceiverClient,
+ boolean verifyChecksum) {
+ super(chunkInfo, blockId, xceiverClient, verifyChecksum);
+ }
+
+ public DummyChunkInputStream(ChunkInfo chunkInfo,
+ BlockID blockId,
+ XceiverClientSpi xceiverClient,
+ boolean verifyChecksum,
+ byte[] data) {
+ super(chunkInfo, blockId, xceiverClient, verifyChecksum);
+ chunkData = data;
+ }
+
+ @Override
+ protected ByteString readChunk(ChunkInfo readChunkInfo) {
+ ByteString byteString = ByteString.copyFrom(chunkData,
+ (int) readChunkInfo.getOffset(),
+ (int) readChunkInfo.getLen());
+ readByteBuffers.add(byteString);
+ return byteString;
+ }
+
+ @Override
+ protected void checkOpen() {
+ // No action needed
+ }
+ }
+
+ /**
+ * Match readData with the chunkData byte-wise.
+ * @param readData Data read through ChunkInputStream
+ * @param inputDataStartIndex first index (inclusive) in chunkData to compare
+ * with read data
+ * @param length the number of bytes of data to match starting from
+ * inputDataStartIndex
+ */
+ private void matchWithInputData(byte[] readData, int inputDataStartIndex,
+ int length) {
+ for (int i = inputDataStartIndex; i < inputDataStartIndex + length; i++) {
+ Assert.assertEquals(chunkData[i], readData[i - inputDataStartIndex]);
+ }
+ }
+
+ /**
+ * Seek to a position and verify through getPos().
+ */
+ private void seekAndVerify(int pos) throws Exception {
+ chunkStream.seek(pos);
+ Assert.assertEquals("Current position of buffer does not match with the " +
+ "seeked position", pos, chunkStream.getPos());
+ }
+
+ @Test
+ public void testFullChunkRead() throws Exception {
+ byte[] b = new byte[CHUNK_SIZE];
+ chunkStream.read(b, 0, CHUNK_SIZE);
+
+ matchWithInputData(b, 0, CHUNK_SIZE);
+ }
+
+ @Test
+ public void testPartialChunkRead() throws Exception {
+ int len = CHUNK_SIZE / 2;
+ byte[] b = new byte[len];
+
+ chunkStream.read(b, 0, len);
+
+ matchWithInputData(b, 0, len);
+
+ // To read chunk data from index 0 to 49 (len = 50), we need to read
+ // chunk from offset 0 to 60 as the checksum boundary is at every 20
+ // bytes. Verify that 60 bytes of chunk data are read and stored in the
+ // buffers.
+ matchWithInputData(chunkStream.readByteBuffers.get(0).toByteArray(),
+ 0, 60);
+
+ }
+
+ @Test
+ public void testSeek() throws Exception {
+ seekAndVerify(0);
+
+ try {
+ seekAndVerify(CHUNK_SIZE);
+ Assert.fail("Seeking to Chunk Length should fail.");
+ } catch (EOFException e) {
+ GenericTestUtils.assertExceptionContains("EOF encountered at pos: "
+ + CHUNK_SIZE + " for chunk: " + CHUNK_NAME, e);
+ }
+
+ // Seek before read should update the ChunkInputStream#chunkPosition
+ seekAndVerify(25);
+ Assert.assertEquals(25, chunkStream.getChunkPosition());
+
+ // Read from the seeked position.
+ // Reading from index 25 to 54 should result in the ChunkInputStream
+ // copying chunk data from index 20 to 59 into the buffers (checksum
+ // boundaries).
+ byte[] b = new byte[30];
+ chunkStream.read(b, 0, 30);
+ matchWithInputData(b, 25, 30);
+ matchWithInputData(chunkStream.readByteBuffers.get(0).toByteArray(),
+ 20, 40);
+
+ // After read, the position of the chunkStream is evaluated from the
+ // buffers and the chunkPosition should be reset to -1.
+ Assert.assertEquals(-1, chunkStream.getChunkPosition());
+
+ // Seek to a position within the current buffers. Current buffers contain
+ // data from index 20 to 59. ChunkPosition should still not be used to
+ // set the position.
+ seekAndVerify(35);
+ Assert.assertEquals(-1, chunkStream.getChunkPosition());
+
+ // Seek to a position outside the current buffers. In this case, the
+ // chunkPosition should be updated to the seeked position.
+ seekAndVerify(75);
+ Assert.assertEquals(75, chunkStream.getChunkPosition());
+ }
+
+ @Test
+ public void testSeekAndRead() throws Exception {
+ // Seek to a position and read data
+ seekAndVerify(50);
+ byte[] b1 = new byte[20];
+ chunkStream.read(b1, 0, 20);
+ matchWithInputData(b1, 50, 20);
+
+ // Next read should start from the position of the last read + 1 i.e. 70
+ byte[] b2 = new byte[20];
+ chunkStream.read(b2, 0, 20);
+ matchWithInputData(b2, 70, 20);
+ }
+}
\ No newline at end of file
diff --git a/hadoop-hdds/common/dev-support/findbugsExcludeFile.xml b/hadoop-hdds/common/dev-support/findbugsExcludeFile.xml
index c7db6794cc0e0..4441b69d8683e 100644
--- a/hadoop-hdds/common/dev-support/findbugsExcludeFile.xml
+++ b/hadoop-hdds/common/dev-support/findbugsExcludeFile.xml
@@ -25,4 +25,9 @@
+
+
+
+
+
diff --git a/hadoop-hdds/common/pom.xml b/hadoop-hdds/common/pom.xml
index 51560ca3af92d..9af807f8b9eb0 100644
--- a/hadoop-hdds/common/pom.xml
+++ b/hadoop-hdds/common/pom.xml
@@ -15,7 +15,7 @@
+https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0org.apache.hadoop
@@ -88,7 +88,7 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd">
org.rocksdbrocksdbjni
- 5.14.2
+ 6.0.1org.apache.hadoop
@@ -135,7 +135,7 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd">
io.jaegertracingjaeger-client
- 0.33.1
+ ${jaeger.version}io.opentracing
@@ -258,9 +258,6 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd">
${protobuf.version}${protoc.path}
-
- ${basedir}/../../hadoop-common-project/hadoop-common/src/main/proto
-
${basedir}/src/main/proto
@@ -277,8 +274,8 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd">
- org.codehaus.mojo
- findbugs-maven-plugin
+ com.github.spotbugs
+ spotbugs-maven-plugin${basedir}/dev-support/findbugsExcludeFile.xml
diff --git a/hadoop-hdds/common/src/main/bin/hadoop-config.cmd b/hadoop-hdds/common/src/main/bin/hadoop-config.cmd
new file mode 100644
index 0000000000000..d77dc5346a1fc
--- /dev/null
+++ b/hadoop-hdds/common/src/main/bin/hadoop-config.cmd
@@ -0,0 +1,317 @@
+@echo off
+@rem Licensed to the Apache Software Foundation (ASF) under one or more
+@rem contributor license agreements. See the NOTICE file distributed with
+@rem this work for additional information regarding copyright ownership.
+@rem The ASF licenses this file to You under the Apache License, Version 2.0
+@rem (the "License"); you may not use this file except in compliance with
+@rem the License. You may obtain a copy of the License at
+@rem
+@rem http://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+
+@rem included in all the hadoop scripts with source command
+@rem should not be executable directly
+@rem also should not be passed any arguments, since we need original %*
+
+if not defined HADOOP_COMMON_DIR (
+ set HADOOP_COMMON_DIR=share\hadoop\common
+)
+if not defined HADOOP_COMMON_LIB_JARS_DIR (
+ set HADOOP_COMMON_LIB_JARS_DIR=share\hadoop\common\lib
+)
+if not defined HADOOP_COMMON_LIB_NATIVE_DIR (
+ set HADOOP_COMMON_LIB_NATIVE_DIR=lib\native
+)
+if not defined HDFS_DIR (
+ set HDFS_DIR=share\hadoop\hdfs
+)
+if not defined HDFS_LIB_JARS_DIR (
+ set HDFS_LIB_JARS_DIR=share\hadoop\hdfs\lib
+)
+if not defined YARN_DIR (
+ set YARN_DIR=share\hadoop\yarn
+)
+if not defined YARN_LIB_JARS_DIR (
+ set YARN_LIB_JARS_DIR=share\hadoop\yarn\lib
+)
+if not defined MAPRED_DIR (
+ set MAPRED_DIR=share\hadoop\mapreduce
+)
+if not defined MAPRED_LIB_JARS_DIR (
+ set MAPRED_LIB_JARS_DIR=share\hadoop\mapreduce\lib
+)
+
+@rem the root of the Hadoop installation
+set HADOOP_HOME=%~dp0
+for %%i in (%HADOOP_HOME%.) do (
+ set HADOOP_HOME=%%~dpi
+)
+if "%HADOOP_HOME:~-1%" == "\" (
+ set HADOOP_HOME=%HADOOP_HOME:~0,-1%
+)
+
+if not exist %HADOOP_HOME%\share\hadoop\common\hadoop-common-*.jar (
+ @echo +================================================================+
+ @echo ^| Error: HADOOP_HOME is not set correctly ^|
+ @echo +----------------------------------------------------------------+
+ @echo ^| Please set your HADOOP_HOME variable to the absolute path of ^|
+ @echo ^| the directory that contains the hadoop distribution ^|
+ @echo +================================================================+
+ exit /b 1
+)
+
+if not defined HADOOP_CONF_DIR (
+ set HADOOP_CONF_DIR=%HADOOP_HOME%\etc\hadoop
+)
+
+@rem
+@rem Allow alternate conf dir location.
+@rem
+
+if "%1" == "--config" (
+ set HADOOP_CONF_DIR=%2
+ shift
+ shift
+)
+
+@rem
+@rem check to see it is specified whether to use the workers or the
+@rem masters file
+@rem
+
+if "%1" == "--hosts" (
+ set HADOOP_WORKERS=%HADOOP_CONF_DIR%\%2
+ shift
+ shift
+)
+
+@rem
+@rem Set log level. Default to INFO.
+@rem
+
+if "%1" == "--loglevel" (
+ set HADOOP_LOGLEVEL=%2
+ shift
+ shift
+)
+
+if exist %HADOOP_CONF_DIR%\hadoop-env.cmd (
+ call %HADOOP_CONF_DIR%\hadoop-env.cmd
+)
+
+@rem
+@rem setup java environment variables
+@rem
+
+if not defined JAVA_HOME (
+ echo Error: JAVA_HOME is not set.
+ goto :eof
+)
+
+if not exist %JAVA_HOME%\bin\java.exe (
+ echo Error: JAVA_HOME is incorrectly set.
+ echo Please update %HADOOP_CONF_DIR%\hadoop-env.cmd
+ goto :eof
+)
+
+set JAVA=%JAVA_HOME%\bin\java
+@rem some Java parameters
+set JAVA_HEAP_MAX=-Xmx1000m
+
+@rem
+@rem check envvars which might override default args
+@rem
+
+if defined HADOOP_HEAPSIZE (
+ set JAVA_HEAP_MAX=-Xmx%HADOOP_HEAPSIZE%m
+)
+
+@rem
+@rem CLASSPATH initially contains %HADOOP_CONF_DIR%
+@rem
+
+set CLASSPATH=%HADOOP_CONF_DIR%
+
+if not defined HADOOP_COMMON_HOME (
+ if exist %HADOOP_HOME%\share\hadoop\common (
+ set HADOOP_COMMON_HOME=%HADOOP_HOME%
+ )
+)
+
+@rem
+@rem for releases, add core hadoop jar & webapps to CLASSPATH
+@rem
+
+if exist %HADOOP_COMMON_HOME%\%HADOOP_COMMON_DIR%\webapps (
+ set CLASSPATH=!CLASSPATH!;%HADOOP_COMMON_HOME%\%HADOOP_COMMON_DIR%
+)
+
+if exist %HADOOP_COMMON_HOME%\%HADOOP_COMMON_LIB_JARS_DIR% (
+ set CLASSPATH=!CLASSPATH!;%HADOOP_COMMON_HOME%\%HADOOP_COMMON_LIB_JARS_DIR%\*
+)
+
+set CLASSPATH=!CLASSPATH!;%HADOOP_COMMON_HOME%\%HADOOP_COMMON_DIR%\*
+
+@rem
+@rem default log directory % file
+@rem
+
+if not defined HADOOP_LOG_DIR (
+ set HADOOP_LOG_DIR=%HADOOP_HOME%\logs
+)
+
+if not defined HADOOP_LOGFILE (
+ set HADOOP_LOGFILE=hadoop.log
+)
+
+if not defined HADOOP_LOGLEVEL (
+ set HADOOP_LOGLEVEL=INFO
+)
+
+if not defined HADOOP_ROOT_LOGGER (
+ set HADOOP_ROOT_LOGGER=%HADOOP_LOGLEVEL%,console
+)
+
+@rem
+@rem default policy file for service-level authorization
+@rem
+
+if not defined HADOOP_POLICYFILE (
+ set HADOOP_POLICYFILE=hadoop-policy.xml
+)
+
+@rem
+@rem Determine the JAVA_PLATFORM
+@rem
+
+for /f "delims=" %%A in ('%JAVA% -Xmx32m %HADOOP_JAVA_PLATFORM_OPTS% -classpath "%CLASSPATH%" org.apache.hadoop.util.PlatformName') do set JAVA_PLATFORM=%%A
+@rem replace space with underscore
+set JAVA_PLATFORM=%JAVA_PLATFORM: =_%
+
+@rem
+@rem setup 'java.library.path' for native hadoop code if necessary
+@rem
+
+@rem Check if we're running hadoop directly from the build
+if exist %HADOOP_COMMON_HOME%\target\bin (
+ if defined JAVA_LIBRARY_PATH (
+ set JAVA_LIBRARY_PATH=%JAVA_LIBRARY_PATH%;%HADOOP_COMMON_HOME%\target\bin
+ ) else (
+ set JAVA_LIBRARY_PATH=%HADOOP_COMMON_HOME%\target\bin
+ )
+)
+
+@rem For the distro case, check the bin folder
+if exist %HADOOP_COMMON_HOME%\bin (
+ if defined JAVA_LIBRARY_PATH (
+ set JAVA_LIBRARY_PATH=%JAVA_LIBRARY_PATH%;%HADOOP_COMMON_HOME%\bin
+ ) else (
+ set JAVA_LIBRARY_PATH=%HADOOP_COMMON_HOME%\bin
+ )
+)
+
+@rem
+@rem setup a default TOOL_PATH
+@rem
+set TOOL_PATH=%HADOOP_HOME%\share\hadoop\tools\lib\*
+
+set HADOOP_OPTS=%HADOOP_OPTS% -Dhadoop.log.dir=%HADOOP_LOG_DIR%
+set HADOOP_OPTS=%HADOOP_OPTS% -Dhadoop.log.file=%HADOOP_LOGFILE%
+set HADOOP_OPTS=%HADOOP_OPTS% -Dhadoop.home.dir=%HADOOP_HOME%
+set HADOOP_OPTS=%HADOOP_OPTS% -Dhadoop.id.str=%HADOOP_IDENT_STRING%
+set HADOOP_OPTS=%HADOOP_OPTS% -Dhadoop.root.logger=%HADOOP_ROOT_LOGGER%
+
+if defined JAVA_LIBRARY_PATH (
+ set HADOOP_OPTS=%HADOOP_OPTS% -Djava.library.path=%JAVA_LIBRARY_PATH%
+)
+set HADOOP_OPTS=%HADOOP_OPTS% -Dhadoop.policy.file=%HADOOP_POLICYFILE%
+
+@rem
+@rem Disable ipv6 as it can cause issues
+@rem
+
+set HADOOP_OPTS=%HADOOP_OPTS% -Djava.net.preferIPv4Stack=true
+
+@rem
+@rem put hdfs in classpath if present
+@rem
+
+if not defined HADOOP_HDFS_HOME (
+ if exist %HADOOP_HOME%\%HDFS_DIR% (
+ set HADOOP_HDFS_HOME=%HADOOP_HOME%
+ )
+)
+
+if exist %HADOOP_HDFS_HOME%\%HDFS_DIR%\webapps (
+ set CLASSPATH=!CLASSPATH!;%HADOOP_HDFS_HOME%\%HDFS_DIR%
+)
+
+if exist %HADOOP_HDFS_HOME%\%HDFS_LIB_JARS_DIR% (
+ set CLASSPATH=!CLASSPATH!;%HADOOP_HDFS_HOME%\%HDFS_LIB_JARS_DIR%\*
+)
+
+set CLASSPATH=!CLASSPATH!;%HADOOP_HDFS_HOME%\%HDFS_DIR%\*
+
+@rem
+@rem put yarn in classpath if present
+@rem
+
+if not defined HADOOP_YARN_HOME (
+ if exist %HADOOP_HOME%\%YARN_DIR% (
+ set HADOOP_YARN_HOME=%HADOOP_HOME%
+ )
+)
+
+if exist %HADOOP_YARN_HOME%\%YARN_DIR%\webapps (
+ set CLASSPATH=!CLASSPATH!;%HADOOP_YARN_HOME%\%YARN_DIR%
+)
+
+if exist %HADOOP_YARN_HOME%\%YARN_LIB_JARS_DIR% (
+ set CLASSPATH=!CLASSPATH!;%HADOOP_YARN_HOME%\%YARN_LIB_JARS_DIR%\*
+)
+
+set CLASSPATH=!CLASSPATH!;%HADOOP_YARN_HOME%\%YARN_DIR%\*
+
+@rem
+@rem put mapred in classpath if present AND different from YARN
+@rem
+
+if not defined HADOOP_MAPRED_HOME (
+ if exist %HADOOP_HOME%\%MAPRED_DIR% (
+ set HADOOP_MAPRED_HOME=%HADOOP_HOME%
+ )
+)
+
+if not "%HADOOP_MAPRED_HOME%\%MAPRED_DIR%" == "%HADOOP_YARN_HOME%\%YARN_DIR%" (
+
+ if exist %HADOOP_MAPRED_HOME%\%MAPRED_DIR%\webapps (
+ set CLASSPATH=!CLASSPATH!;%HADOOP_MAPRED_HOME%\%MAPRED_DIR%
+ )
+
+ if exist %HADOOP_MAPRED_HOME%\%MAPRED_LIB_JARS_DIR% (
+ set CLASSPATH=!CLASSPATH!;%HADOOP_MAPRED_HOME%\%MAPRED_LIB_JARS_DIR%\*
+ )
+
+ set CLASSPATH=!CLASSPATH!;%HADOOP_MAPRED_HOME%\%MAPRED_DIR%\*
+)
+
+@rem
+@rem add user-specified CLASSPATH last
+@rem
+
+if defined HADOOP_CLASSPATH (
+ if not defined HADOOP_USE_CLIENT_CLASSLOADER (
+ if defined HADOOP_USER_CLASSPATH_FIRST (
+ set CLASSPATH=%HADOOP_CLASSPATH%;%CLASSPATH%;
+ ) else (
+ set CLASSPATH=%CLASSPATH%;%HADOOP_CLASSPATH%;
+ )
+ )
+)
+
+:eof
diff --git a/hadoop-hdds/common/src/main/bin/hadoop-config.sh b/hadoop-hdds/common/src/main/bin/hadoop-config.sh
new file mode 100755
index 0000000000000..444b79a362953
--- /dev/null
+++ b/hadoop-hdds/common/src/main/bin/hadoop-config.sh
@@ -0,0 +1,165 @@
+#!/usr/bin/env bash
+#
+# 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.
+
+####
+# IMPORTANT
+####
+
+## The hadoop-config.sh tends to get executed by non-Hadoop scripts.
+## Those parts expect this script to parse/manipulate $@. In order
+## to maintain backward compatibility, this means a surprising
+## lack of functions for bits that would be much better off in
+## a function.
+##
+## In other words, yes, there is some bad things happen here and
+## unless we break the rest of the ecosystem, we can't change it. :(
+
+
+# included in all the hadoop scripts with source command
+# should not be executable directly
+# also should not be passed any arguments, since we need original $*
+#
+# after doing more config, caller should also exec finalize
+# function to finish last minute/default configs for
+# settings that might be different between daemons & interactive
+
+# you must be this high to ride the ride
+if [[ -z "${BASH_VERSINFO[0]}" ]] \
+ || [[ "${BASH_VERSINFO[0]}" -lt 3 ]] \
+ || [[ "${BASH_VERSINFO[0]}" -eq 3 && "${BASH_VERSINFO[1]}" -lt 2 ]]; then
+ echo "bash v3.2+ is required. Sorry."
+ exit 1
+fi
+
+# In order to get partially bootstrapped, we need to figure out where
+# we are located. Chances are good that our caller has already done
+# this work for us, but just in case...
+
+if [[ -z "${HADOOP_LIBEXEC_DIR}" ]]; then
+ _hadoop_common_this="${BASH_SOURCE-$0}"
+ HADOOP_LIBEXEC_DIR=$(cd -P -- "$(dirname -- "${_hadoop_common_this}")" >/dev/null && pwd -P)
+fi
+
+# get our functions defined for usage later
+if [[ -n "${HADOOP_COMMON_HOME}" ]] &&
+ [[ -e "${HADOOP_COMMON_HOME}/libexec/hadoop-functions.sh" ]]; then
+ # shellcheck source=./hadoop-common-project/hadoop-common/src/main/bin/hadoop-functions.sh
+ . "${HADOOP_COMMON_HOME}/libexec/hadoop-functions.sh"
+elif [[ -e "${HADOOP_LIBEXEC_DIR}/hadoop-functions.sh" ]]; then
+ # shellcheck source=./hadoop-common-project/hadoop-common/src/main/bin/hadoop-functions.sh
+ . "${HADOOP_LIBEXEC_DIR}/hadoop-functions.sh"
+else
+ echo "ERROR: Unable to exec ${HADOOP_LIBEXEC_DIR}/hadoop-functions.sh." 1>&2
+ exit 1
+fi
+
+hadoop_deprecate_envvar HADOOP_PREFIX HADOOP_HOME
+
+# allow overrides of the above and pre-defines of the below
+if [[ -n "${HADOOP_COMMON_HOME}" ]] &&
+ [[ -e "${HADOOP_COMMON_HOME}/libexec/hadoop-layout.sh" ]]; then
+ # shellcheck source=./hadoop-common-project/hadoop-common/src/main/bin/hadoop-layout.sh.example
+ . "${HADOOP_COMMON_HOME}/libexec/hadoop-layout.sh"
+elif [[ -e "${HADOOP_LIBEXEC_DIR}/hadoop-layout.sh" ]]; then
+ # shellcheck source=./hadoop-common-project/hadoop-common/src/main/bin/hadoop-layout.sh.example
+ . "${HADOOP_LIBEXEC_DIR}/hadoop-layout.sh"
+fi
+
+#
+# IMPORTANT! We are not executing user provided code yet!
+#
+
+# Let's go! Base definitions so we can move forward
+hadoop_bootstrap
+
+# let's find our conf.
+#
+# first, check and process params passed to us
+# we process this in-line so that we can directly modify $@
+# if something downstream is processing that directly,
+# we need to make sure our params have been ripped out
+# note that we do many of them here for various utilities.
+# this provides consistency and forces a more consistent
+# user experience
+
+
+# save these off in case our caller needs them
+# shellcheck disable=SC2034
+HADOOP_USER_PARAMS=("$@")
+
+hadoop_parse_args "$@"
+shift "${HADOOP_PARSE_COUNTER}"
+
+#
+# Setup the base-line environment
+#
+hadoop_find_confdir
+hadoop_exec_hadoopenv
+hadoop_import_shellprofiles
+hadoop_exec_userfuncs
+
+#
+# IMPORTANT! User provided code is now available!
+#
+
+hadoop_exec_user_hadoopenv
+hadoop_verify_confdir
+
+hadoop_deprecate_envvar HADOOP_SLAVES HADOOP_WORKERS
+hadoop_deprecate_envvar HADOOP_SLAVE_NAMES HADOOP_WORKER_NAMES
+hadoop_deprecate_envvar HADOOP_SLAVE_SLEEP HADOOP_WORKER_SLEEP
+
+# do all the OS-specific startup bits here
+# this allows us to get a decent JAVA_HOME,
+# call crle for LD_LIBRARY_PATH, etc.
+hadoop_os_tricks
+
+hadoop_java_setup
+
+hadoop_basic_init
+
+# inject any sub-project overrides, defaults, etc.
+if declare -F hadoop_subproject_init >/dev/null ; then
+ hadoop_subproject_init
+fi
+
+hadoop_shellprofiles_init
+
+# get the native libs in there pretty quick
+hadoop_add_javalibpath "${HADOOP_HOME}/build/native"
+hadoop_add_javalibpath "${HADOOP_HOME}/${HADOOP_COMMON_LIB_NATIVE_DIR}"
+
+hadoop_shellprofiles_nativelib
+
+# get the basic java class path for these subprojects
+# in as quickly as possible since other stuff
+# will definitely depend upon it.
+
+hadoop_add_common_to_classpath
+hadoop_shellprofiles_classpath
+
+# user API commands can now be run since the runtime
+# environment has been configured
+hadoop_exec_hadooprc
+
+#
+# backwards compatibility. new stuff should
+# call this when they are ready
+#
+if [[ -z "${HADOOP_NEW_CONFIG}" ]]; then
+ hadoop_finalize
+fi
diff --git a/hadoop-hdds/common/src/main/bin/hadoop-daemons.sh b/hadoop-hdds/common/src/main/bin/hadoop-daemons.sh
new file mode 100755
index 0000000000000..55304916ad1f7
--- /dev/null
+++ b/hadoop-hdds/common/src/main/bin/hadoop-daemons.sh
@@ -0,0 +1,77 @@
+#!/usr/bin/env bash
+
+# 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.
+
+
+# Run a Hadoop command on all slave hosts.
+
+function hadoop_usage
+{
+ echo "Usage: hadoop-daemons.sh [--config confdir] [--hosts hostlistfile] (start|stop|status) "
+}
+
+this="${BASH_SOURCE-$0}"
+bin=$(cd -P -- "$(dirname -- "${this}")" >/dev/null && pwd -P)
+
+# let's locate libexec...
+if [[ -n "${HADOOP_HOME}" ]]; then
+ HADOOP_DEFAULT_LIBEXEC_DIR="${HADOOP_HOME}/libexec"
+else
+ HADOOP_DEFAULT_LIBEXEC_DIR="${bin}/../libexec"
+fi
+
+HADOOP_LIBEXEC_DIR="${HADOOP_LIBEXEC_DIR:-$HADOOP_DEFAULT_LIBEXEC_DIR}"
+# shellcheck disable=SC2034
+HADOOP_NEW_CONFIG=true
+if [[ -f "${HADOOP_LIBEXEC_DIR}/hdfs-config.sh" ]]; then
+ . "${HADOOP_LIBEXEC_DIR}/hdfs-config.sh"
+else
+ echo "ERROR: Cannot execute ${HADOOP_LIBEXEC_DIR}/hdfs-config.sh." 2>&1
+ exit 1
+fi
+
+if [[ $# = 0 ]]; then
+ hadoop_exit_with_usage 1
+fi
+
+daemonmode=$1
+shift
+
+if [[ -z "${HADOOP_HDFS_HOME}" ]]; then
+ hdfsscript="${HADOOP_HOME}/bin/hdfs"
+else
+ hdfsscript="${HADOOP_HDFS_HOME}/bin/hdfs"
+fi
+
+hadoop_error "WARNING: Use of this script to ${daemonmode} HDFS daemons is deprecated."
+hadoop_error "WARNING: Attempting to execute replacement \"hdfs --workers --daemon ${daemonmode}\" instead."
+
+#
+# Original input was usually:
+# hadoop-daemons.sh (shell options) (start|stop) (datanode|...) (daemon options)
+# we're going to turn this into
+# hdfs --workers --daemon (start|stop) (rest of options)
+#
+for (( i = 0; i < ${#HADOOP_USER_PARAMS[@]}; i++ ))
+do
+ if [[ "${HADOOP_USER_PARAMS[$i]}" =~ ^start$ ]] ||
+ [[ "${HADOOP_USER_PARAMS[$i]}" =~ ^stop$ ]] ||
+ [[ "${HADOOP_USER_PARAMS[$i]}" =~ ^status$ ]]; then
+ unset HADOOP_USER_PARAMS[$i]
+ fi
+done
+
+${hdfsscript} --workers --daemon "${daemonmode}" "${HADOOP_USER_PARAMS[@]}"
diff --git a/hadoop-hdds/common/src/main/bin/hadoop-functions.sh b/hadoop-hdds/common/src/main/bin/hadoop-functions.sh
new file mode 100755
index 0000000000000..484fe2302f9ba
--- /dev/null
+++ b/hadoop-hdds/common/src/main/bin/hadoop-functions.sh
@@ -0,0 +1,2732 @@
+#!/usr/bin/env bash
+# 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.
+
+# we need to declare this globally as an array, which can only
+# be done outside of a function
+declare -a HADOOP_SUBCMD_USAGE
+declare -a HADOOP_OPTION_USAGE
+declare -a HADOOP_SUBCMD_USAGE_TYPES
+
+## @description Print a message to stderr
+## @audience public
+## @stability stable
+## @replaceable no
+## @param string
+function hadoop_error
+{
+ echo "$*" 1>&2
+}
+
+## @description Print a message to stderr if --debug is turned on
+## @audience public
+## @stability stable
+## @replaceable no
+## @param string
+function hadoop_debug
+{
+ if [[ -n "${HADOOP_SHELL_SCRIPT_DEBUG}" ]]; then
+ echo "DEBUG: $*" 1>&2
+ fi
+}
+
+## @description Given a filename or dir, return the absolute version of it
+## @description This works as an alternative to readlink, which isn't
+## @description portable.
+## @audience public
+## @stability stable
+## @param fsobj
+## @replaceable no
+## @return 0 success
+## @return 1 failure
+## @return stdout abspath
+function hadoop_abs
+{
+ declare obj=$1
+ declare dir
+ declare fn
+ declare dirret
+
+ if [[ ! -e ${obj} ]]; then
+ return 1
+ elif [[ -d ${obj} ]]; then
+ dir=${obj}
+ else
+ dir=$(dirname -- "${obj}")
+ fn=$(basename -- "${obj}")
+ fn="/${fn}"
+ fi
+
+ dir=$(cd -P -- "${dir}" >/dev/null 2>/dev/null && pwd -P)
+ dirret=$?
+ if [[ ${dirret} = 0 ]]; then
+ echo "${dir}${fn}"
+ return 0
+ fi
+ return 1
+}
+
+## @description Given variable $1 delete $2 from it
+## @audience public
+## @stability stable
+## @replaceable no
+function hadoop_delete_entry
+{
+ if [[ ${!1} =~ \ ${2}\ ]] ; then
+ hadoop_debug "Removing ${2} from ${1}"
+ eval "${1}"=\""${!1// ${2} }"\"
+ fi
+}
+
+## @description Given variable $1 add $2 to it
+## @audience public
+## @stability stable
+## @replaceable no
+function hadoop_add_entry
+{
+ if [[ ! ${!1} =~ \ ${2}\ ]] ; then
+ hadoop_debug "Adding ${2} to ${1}"
+ #shellcheck disable=SC2140
+ eval "${1}"=\""${!1} ${2} "\"
+ fi
+}
+
+## @description Given variable $1 determine if $2 is in it
+## @audience public
+## @stability stable
+## @replaceable no
+## @return 0 = yes, 1 = no
+function hadoop_verify_entry
+{
+ # this unfortunately can't really be tested by bats. :(
+ # so if this changes, be aware that unit tests effectively
+ # do this function in them
+ [[ ${!1} =~ \ ${2}\ ]]
+}
+
+## @description Check if an array has a given value
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param element
+## @param array
+## @returns 0 = yes
+## @returns 1 = no
+function hadoop_array_contains
+{
+ declare element=$1
+ shift
+ declare val
+
+ if [[ "$#" -eq 0 ]]; then
+ return 1
+ fi
+
+ for val in "${@}"; do
+ if [[ "${val}" == "${element}" ]]; then
+ return 0
+ fi
+ done
+ return 1
+}
+
+## @description Add the `appendstring` if `checkstring` is not
+## @description present in the given array
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param envvar
+## @param appendstring
+function hadoop_add_array_param
+{
+ declare arrname=$1
+ declare add=$2
+
+ declare arrref="${arrname}[@]"
+ declare array=("${!arrref}")
+
+ if ! hadoop_array_contains "${add}" "${array[@]}"; then
+ #shellcheck disable=SC1083,SC2086
+ eval ${arrname}=\(\"\${array[@]}\" \"${add}\" \)
+ hadoop_debug "$1 accepted $2"
+ else
+ hadoop_debug "$1 declined $2"
+ fi
+}
+
+## @description Sort an array (must not contain regexps)
+## @description present in the given array
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param arrayvar
+function hadoop_sort_array
+{
+ declare arrname=$1
+ declare arrref="${arrname}[@]"
+ declare array=("${!arrref}")
+ declare oifs
+
+ declare globstatus
+ declare -a sa
+
+ globstatus=$(set -o | grep noglob | awk '{print $NF}')
+
+ set -f
+ oifs=${IFS}
+
+ # shellcheck disable=SC2034
+ IFS=$'\n' sa=($(sort <<<"${array[*]}"))
+
+ # shellcheck disable=SC1083
+ eval "${arrname}"=\(\"\${sa[@]}\"\)
+
+ IFS=${oifs}
+ if [[ "${globstatus}" = off ]]; then
+ set +f
+ fi
+}
+
+## @description Check if we are running with priv
+## @description by default, this implementation looks for
+## @description EUID=0. For OSes that have true priv
+## @description separation, this should be something more complex
+## @audience private
+## @stability evolving
+## @replaceable yes
+## @return 1 = no priv
+## @return 0 = priv
+function hadoop_privilege_check
+{
+ [[ "${EUID}" = 0 ]]
+}
+
+## @description Execute a command via su when running as root
+## @description if the given user is found or exit with
+## @description failure if not.
+## @description otherwise just run it. (This is intended to
+## @description be used by the start-*/stop-* scripts.)
+## @audience private
+## @stability evolving
+## @replaceable yes
+## @param user
+## @param commandstring
+## @return exitstatus
+function hadoop_su
+{
+ declare user=$1
+ shift
+
+ if hadoop_privilege_check; then
+ if hadoop_verify_user_resolves user; then
+ su -l "${user}" -- "$@"
+ else
+ hadoop_error "ERROR: Refusing to run as root: ${user} account is not found. Aborting."
+ return 1
+ fi
+ else
+ "$@"
+ fi
+}
+
+## @description Execute a command via su when running as root
+## @description with extra support for commands that might
+## @description legitimately start as root (e.g., datanode)
+## @description (This is intended to
+## @description be used by the start-*/stop-* scripts.)
+## @audience private
+## @stability evolving
+## @replaceable no
+## @param user
+## @param commandstring
+## @return exitstatus
+function hadoop_uservar_su
+{
+
+ ## startup matrix:
+ #
+ # if $EUID != 0, then exec
+ # if $EUID =0 then
+ # if hdfs_subcmd_user is defined, call hadoop_su to exec
+ # if hdfs_subcmd_user is not defined, error
+ #
+ # For secure daemons, this means both the secure and insecure env vars need to be
+ # defined. e.g., HDFS_DATANODE_USER=root HDFS_DATANODE_SECURE_USER=hdfs
+ # This function will pick up the "normal" var, switch to that user, then
+ # execute the command which will then pick up the "secure" version.
+ #
+
+ declare program=$1
+ declare command=$2
+ shift 2
+
+ declare uprogram
+ declare ucommand
+ declare uvar
+ declare svar
+
+ if hadoop_privilege_check; then
+ uvar=$(hadoop_build_custom_subcmd_var "${program}" "${command}" USER)
+
+ svar=$(hadoop_build_custom_subcmd_var "${program}" "${command}" SECURE_USER)
+
+ if [[ -n "${!uvar}" ]]; then
+ hadoop_su "${!uvar}" "$@"
+ elif [[ -n "${!svar}" ]]; then
+ ## if we are here, then SECURE_USER with no USER defined
+ ## we are already privileged, so just run the command and hope
+ ## for the best
+ "$@"
+ else
+ hadoop_error "ERROR: Attempting to operate on ${program} ${command} as root"
+ hadoop_error "ERROR: but there is no ${uvar} defined. Aborting operation."
+ return 1
+ fi
+ else
+ "$@"
+ fi
+}
+
+## @description Add a subcommand to the usage output
+## @audience private
+## @stability evolving
+## @replaceable no
+## @param subcommand
+## @param subcommandtype
+## @param subcommanddesc
+function hadoop_add_subcommand
+{
+ declare subcmd=$1
+ declare subtype=$2
+ declare text=$3
+
+ hadoop_debug "${subcmd} as a ${subtype}"
+
+ hadoop_add_array_param HADOOP_SUBCMD_USAGE_TYPES "${subtype}"
+
+ # done in this order so that sort works later
+ HADOOP_SUBCMD_USAGE[${HADOOP_SUBCMD_USAGE_COUNTER}]="${subcmd}@${subtype}@${text}"
+ ((HADOOP_SUBCMD_USAGE_COUNTER=HADOOP_SUBCMD_USAGE_COUNTER+1))
+}
+
+## @description Add an option to the usage output
+## @audience private
+## @stability evolving
+## @replaceable no
+## @param subcommand
+## @param subcommanddesc
+function hadoop_add_option
+{
+ local option=$1
+ local text=$2
+
+ HADOOP_OPTION_USAGE[${HADOOP_OPTION_USAGE_COUNTER}]="${option}@${text}"
+ ((HADOOP_OPTION_USAGE_COUNTER=HADOOP_OPTION_USAGE_COUNTER+1))
+}
+
+## @description Reset the usage information to blank
+## @audience private
+## @stability evolving
+## @replaceable no
+function hadoop_reset_usage
+{
+ HADOOP_SUBCMD_USAGE=()
+ HADOOP_OPTION_USAGE=()
+ HADOOP_SUBCMD_USAGE_TYPES=()
+ HADOOP_SUBCMD_USAGE_COUNTER=0
+ HADOOP_OPTION_USAGE_COUNTER=0
+}
+
+## @description Print a screen-size aware two-column output
+## @description if reqtype is not null, only print those requested
+## @audience private
+## @stability evolving
+## @replaceable no
+## @param reqtype
+## @param array
+function hadoop_generic_columnprinter
+{
+ declare reqtype=$1
+ shift
+ declare -a input=("$@")
+ declare -i i=0
+ declare -i counter=0
+ declare line
+ declare text
+ declare option
+ declare giventext
+ declare -i maxoptsize
+ declare -i foldsize
+ declare -a tmpa
+ declare numcols
+ declare brup
+
+ if [[ -n "${COLUMNS}" ]]; then
+ numcols=${COLUMNS}
+ else
+ numcols=$(tput cols) 2>/dev/null
+ COLUMNS=${numcols}
+ fi
+
+ if [[ -z "${numcols}"
+ || ! "${numcols}" =~ ^[0-9]+$ ]]; then
+ numcols=75
+ else
+ ((numcols=numcols-5))
+ fi
+
+ while read -r line; do
+ tmpa[${counter}]=${line}
+ ((counter=counter+1))
+ IFS='@' read -ra brup <<< "${line}"
+ option="${brup[0]}"
+ if [[ ${#option} -gt ${maxoptsize} ]]; then
+ maxoptsize=${#option}
+ fi
+ done < <(for text in "${input[@]}"; do
+ echo "${text}"
+ done | sort)
+
+ i=0
+ ((foldsize=numcols-maxoptsize))
+
+ until [[ $i -eq ${#tmpa[@]} ]]; do
+ IFS='@' read -ra brup <<< "${tmpa[$i]}"
+
+ option="${brup[0]}"
+ cmdtype="${brup[1]}"
+ giventext="${brup[2]}"
+
+ if [[ -n "${reqtype}" ]]; then
+ if [[ "${cmdtype}" != "${reqtype}" ]]; then
+ ((i=i+1))
+ continue
+ fi
+ fi
+
+ if [[ -z "${giventext}" ]]; then
+ giventext=${cmdtype}
+ fi
+
+ while read -r line; do
+ printf "%-${maxoptsize}s %-s\n" "${option}" "${line}"
+ option=" "
+ done < <(echo "${giventext}"| fold -s -w ${foldsize})
+ ((i=i+1))
+ done
+}
+
+## @description generate standard usage output
+## @description and optionally takes a class
+## @audience private
+## @stability evolving
+## @replaceable no
+## @param execname
+## @param true|false
+## @param [text to use in place of SUBCOMMAND]
+function hadoop_generate_usage
+{
+ declare cmd=$1
+ declare takesclass=$2
+ declare subcmdtext=${3:-"SUBCOMMAND"}
+ declare haveoptions
+ declare optstring
+ declare havesubs
+ declare subcmdstring
+ declare cmdtype
+
+ cmd=${cmd##*/}
+
+ if [[ -n "${HADOOP_OPTION_USAGE_COUNTER}"
+ && "${HADOOP_OPTION_USAGE_COUNTER}" -gt 0 ]]; then
+ haveoptions=true
+ optstring=" [OPTIONS]"
+ fi
+
+ if [[ -n "${HADOOP_SUBCMD_USAGE_COUNTER}"
+ && "${HADOOP_SUBCMD_USAGE_COUNTER}" -gt 0 ]]; then
+ havesubs=true
+ subcmdstring=" ${subcmdtext} [${subcmdtext} OPTIONS]"
+ fi
+
+ echo "Usage: ${cmd}${optstring}${subcmdstring}"
+ if [[ ${takesclass} = true ]]; then
+ echo " or ${cmd}${optstring} CLASSNAME [CLASSNAME OPTIONS]"
+ echo " where CLASSNAME is a user-provided Java class"
+ fi
+
+ if [[ "${haveoptions}" = true ]]; then
+ echo ""
+ echo " OPTIONS is none or any of:"
+ echo ""
+
+ hadoop_generic_columnprinter "" "${HADOOP_OPTION_USAGE[@]}"
+ fi
+
+ if [[ "${havesubs}" = true ]]; then
+ echo ""
+ echo " ${subcmdtext} is one of:"
+ echo ""
+
+ if [[ "${#HADOOP_SUBCMD_USAGE_TYPES[@]}" -gt 0 ]]; then
+
+ hadoop_sort_array HADOOP_SUBCMD_USAGE_TYPES
+ for subtype in "${HADOOP_SUBCMD_USAGE_TYPES[@]}"; do
+ #shellcheck disable=SC2086
+ cmdtype="$(tr '[:lower:]' '[:upper:]' <<< ${subtype:0:1})${subtype:1}"
+ printf "\n %s Commands:\n\n" "${cmdtype}"
+ hadoop_generic_columnprinter "${subtype}" "${HADOOP_SUBCMD_USAGE[@]}"
+ done
+ else
+ hadoop_generic_columnprinter "" "${HADOOP_SUBCMD_USAGE[@]}"
+ fi
+ echo ""
+ echo "${subcmdtext} may print help when invoked w/o parameters or with -h."
+ fi
+}
+
+## @description Replace `oldvar` with `newvar` if `oldvar` exists.
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param oldvar
+## @param newvar
+function hadoop_deprecate_envvar
+{
+ local oldvar=$1
+ local newvar=$2
+ local oldval=${!oldvar}
+ local newval=${!newvar}
+
+ if [[ -n "${oldval}" ]]; then
+ hadoop_error "WARNING: ${oldvar} has been replaced by ${newvar}. Using value of ${oldvar}."
+ # shellcheck disable=SC2086
+ eval ${newvar}=\"${oldval}\"
+
+ # shellcheck disable=SC2086
+ newval=${oldval}
+
+ # shellcheck disable=SC2086
+ eval ${newvar}=\"${newval}\"
+ fi
+}
+
+## @description Declare `var` being used and print its value.
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param var
+function hadoop_using_envvar
+{
+ local var=$1
+ local val=${!var}
+
+ if [[ -n "${val}" ]]; then
+ hadoop_debug "${var} = ${val}"
+ fi
+}
+
+## @description Create the directory 'dir'.
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param dir
+function hadoop_mkdir
+{
+ local dir=$1
+
+ if [[ ! -w "${dir}" ]] && [[ ! -d "${dir}" ]]; then
+ hadoop_error "WARNING: ${dir} does not exist. Creating."
+ if ! mkdir -p "${dir}"; then
+ hadoop_error "ERROR: Unable to create ${dir}. Aborting."
+ exit 1
+ fi
+ fi
+}
+
+## @description Bootstraps the Hadoop shell environment
+## @audience private
+## @stability evolving
+## @replaceable no
+function hadoop_bootstrap
+{
+ # the root of the Hadoop installation
+ # See HADOOP-6255 for the expected directory structure layout
+
+ if [[ -n "${DEFAULT_LIBEXEC_DIR}" ]]; then
+ hadoop_error "WARNING: DEFAULT_LIBEXEC_DIR ignored. It has been replaced by HADOOP_DEFAULT_LIBEXEC_DIR."
+ fi
+
+ # By now, HADOOP_LIBEXEC_DIR should have been defined upstream
+ # We can piggyback off of that to figure out where the default
+ # HADOOP_FREFIX should be. This allows us to run without
+ # HADOOP_HOME ever being defined by a human! As a consequence
+ # HADOOP_LIBEXEC_DIR now becomes perhaps the single most powerful
+ # env var within Hadoop.
+ if [[ -z "${HADOOP_LIBEXEC_DIR}" ]]; then
+ hadoop_error "HADOOP_LIBEXEC_DIR is not defined. Exiting."
+ exit 1
+ fi
+ HADOOP_DEFAULT_PREFIX=$(cd -P -- "${HADOOP_LIBEXEC_DIR}/.." >/dev/null && pwd -P)
+ HADOOP_HOME=${HADOOP_HOME:-$HADOOP_DEFAULT_PREFIX}
+ export HADOOP_HOME
+
+ #
+ # short-cuts. vendors may redefine these as well, preferably
+ # in hadoop-layout.sh
+ #
+ HADOOP_COMMON_DIR=${HADOOP_COMMON_DIR:-"share/hadoop/common"}
+ HADOOP_COMMON_LIB_JARS_DIR=${HADOOP_COMMON_LIB_JARS_DIR:-"share/hadoop/common/lib"}
+ HADOOP_COMMON_LIB_NATIVE_DIR=${HADOOP_COMMON_LIB_NATIVE_DIR:-"lib/native"}
+ HDFS_DIR=${HDFS_DIR:-"share/hadoop/hdfs"}
+ HDFS_LIB_JARS_DIR=${HDFS_LIB_JARS_DIR:-"share/hadoop/hdfs/lib"}
+ YARN_DIR=${YARN_DIR:-"share/hadoop/yarn"}
+ YARN_LIB_JARS_DIR=${YARN_LIB_JARS_DIR:-"share/hadoop/yarn/lib"}
+ MAPRED_DIR=${MAPRED_DIR:-"share/hadoop/mapreduce"}
+ MAPRED_LIB_JARS_DIR=${MAPRED_LIB_JARS_DIR:-"share/hadoop/mapreduce/lib"}
+ HDDS_DIR=${HDDS_DIR:-"share/hadoop/hdds"}
+ HDDS_LIB_JARS_DIR=${HDDS_LIB_JARS_DIR:-"share/hadoop/hdds/lib"}
+ OZONE_DIR=${OZONE_DIR:-"share/hadoop/ozone"}
+ OZONE_LIB_JARS_DIR=${OZONE_LIB_JARS_DIR:-"share/hadoop/ozone/lib"}
+ OZONEFS_DIR=${OZONEFS_DIR:-"share/hadoop/ozonefs"}
+
+ HADOOP_TOOLS_HOME=${HADOOP_TOOLS_HOME:-${HADOOP_HOME}}
+ HADOOP_TOOLS_DIR=${HADOOP_TOOLS_DIR:-"share/hadoop/tools"}
+ HADOOP_TOOLS_LIB_JARS_DIR=${HADOOP_TOOLS_LIB_JARS_DIR:-"${HADOOP_TOOLS_DIR}/lib"}
+
+ # by default, whatever we are about to run doesn't support
+ # daemonization
+ HADOOP_SUBCMD_SUPPORTDAEMONIZATION=false
+
+ # by default, we have not been self-re-execed
+ HADOOP_REEXECED_CMD=false
+
+ HADOOP_SUBCMD_SECURESERVICE=false
+
+ # This is the default we claim in hadoop-env.sh
+ JSVC_HOME=${JSVC_HOME:-"/usr/bin"}
+
+ # usage output set to zero
+ hadoop_reset_usage
+
+ export HADOOP_OS_TYPE=${HADOOP_OS_TYPE:-$(uname -s)}
+
+ # defaults
+ export HADOOP_OPTS=${HADOOP_OPTS:-"-Djava.net.preferIPv4Stack=true"}
+ hadoop_debug "Initial HADOOP_OPTS=${HADOOP_OPTS}"
+}
+
+## @description Locate Hadoop's configuration directory
+## @audience private
+## @stability evolving
+## @replaceable no
+function hadoop_find_confdir
+{
+ local conf_dir
+
+ # An attempt at compatibility with some Hadoop 1.x
+ # installs.
+ if [[ -e "${HADOOP_HOME}/conf/hadoop-env.sh" ]]; then
+ conf_dir="conf"
+ else
+ conf_dir="etc/hadoop"
+ fi
+ export HADOOP_CONF_DIR="${HADOOP_CONF_DIR:-${HADOOP_HOME}/${conf_dir}}"
+
+ hadoop_debug "HADOOP_CONF_DIR=${HADOOP_CONF_DIR}"
+}
+
+## @description Validate ${HADOOP_CONF_DIR}
+## @audience public
+## @stability stable
+## @replaceable yes
+## @return will exit on failure conditions
+function hadoop_verify_confdir
+{
+ # Check only log4j.properties by default.
+ # --loglevel does not work without logger settings in log4j.log4j.properties.
+ if [[ ! -f "${HADOOP_CONF_DIR}/log4j.properties" ]]; then
+ hadoop_error "WARNING: log4j.properties is not found. HADOOP_CONF_DIR may be incomplete."
+ fi
+}
+
+## @description Import the hadoop-env.sh settings
+## @audience private
+## @stability evolving
+## @replaceable no
+function hadoop_exec_hadoopenv
+{
+ if [[ -z "${HADOOP_ENV_PROCESSED}" ]]; then
+ if [[ -f "${HADOOP_CONF_DIR}/hadoop-env.sh" ]]; then
+ export HADOOP_ENV_PROCESSED=true
+ # shellcheck source=./hadoop-common-project/hadoop-common/src/main/conf/hadoop-env.sh
+ . "${HADOOP_CONF_DIR}/hadoop-env.sh"
+ fi
+ fi
+}
+
+## @description Import the replaced functions
+## @audience private
+## @stability evolving
+## @replaceable no
+function hadoop_exec_userfuncs
+{
+ if [[ -e "${HADOOP_CONF_DIR}/hadoop-user-functions.sh" ]]; then
+ # shellcheck disable=SC1090
+ . "${HADOOP_CONF_DIR}/hadoop-user-functions.sh"
+ fi
+}
+
+## @description Read the user's settings. This provides for users to
+## @description override and/or append hadoop-env.sh. It is not meant
+## @description as a complete system override.
+## @audience private
+## @stability evolving
+## @replaceable yes
+function hadoop_exec_user_hadoopenv
+{
+ if [[ -f "${HOME}/.hadoop-env" ]]; then
+ hadoop_debug "Applying the user's .hadoop-env"
+ # shellcheck disable=SC1090
+ . "${HOME}/.hadoop-env"
+ fi
+}
+
+## @description Read the user's settings. This provides for users to
+## @description run Hadoop Shell API after system bootstrap
+## @audience private
+## @stability evolving
+## @replaceable yes
+function hadoop_exec_hadooprc
+{
+ if [[ -f "${HOME}/.hadooprc" ]]; then
+ hadoop_debug "Applying the user's .hadooprc"
+ # shellcheck disable=SC1090
+ . "${HOME}/.hadooprc"
+ fi
+}
+
+## @description Import shellprofile.d content
+## @audience private
+## @stability evolving
+## @replaceable yes
+function hadoop_import_shellprofiles
+{
+ local i
+ local files1
+ local files2
+
+ if [[ -d "${HADOOP_LIBEXEC_DIR}/shellprofile.d" ]]; then
+ files1=(${HADOOP_LIBEXEC_DIR}/shellprofile.d/*.sh)
+ hadoop_debug "shellprofiles: ${files1[*]}"
+ else
+ hadoop_error "WARNING: ${HADOOP_LIBEXEC_DIR}/shellprofile.d doesn't exist. Functionality may not work."
+ fi
+
+ if [[ -d "${HADOOP_CONF_DIR}/shellprofile.d" ]]; then
+ files2=(${HADOOP_CONF_DIR}/shellprofile.d/*.sh)
+ fi
+
+ # enable bundled shellprofiles that come
+ # from hadoop-tools. This converts the user-facing HADOOP_OPTIONAL_TOOLS
+ # to the HADOOP_TOOLS_OPTIONS that the shell profiles expect.
+ # See dist-tools-hooks-maker for how the example HADOOP_OPTIONAL_TOOLS
+ # gets populated into hadoop-env.sh
+
+ for i in ${HADOOP_OPTIONAL_TOOLS//,/ }; do
+ hadoop_add_entry HADOOP_TOOLS_OPTIONS "${i}"
+ done
+
+ for i in "${files1[@]}" "${files2[@]}"
+ do
+ if [[ -n "${i}"
+ && -f "${i}" ]]; then
+ hadoop_debug "Profiles: importing ${i}"
+ # shellcheck disable=SC1090
+ . "${i}"
+ fi
+ done
+}
+
+## @description Initialize the registered shell profiles
+## @audience private
+## @stability evolving
+## @replaceable yes
+function hadoop_shellprofiles_init
+{
+ local i
+
+ for i in ${HADOOP_SHELL_PROFILES}
+ do
+ if declare -F _${i}_hadoop_init >/dev/null ; then
+ hadoop_debug "Profiles: ${i} init"
+ # shellcheck disable=SC2086
+ _${i}_hadoop_init
+ fi
+ done
+}
+
+## @description Apply the shell profile classpath additions
+## @audience private
+## @stability evolving
+## @replaceable yes
+function hadoop_shellprofiles_classpath
+{
+ local i
+
+ for i in ${HADOOP_SHELL_PROFILES}
+ do
+ if declare -F _${i}_hadoop_classpath >/dev/null ; then
+ hadoop_debug "Profiles: ${i} classpath"
+ # shellcheck disable=SC2086
+ _${i}_hadoop_classpath
+ fi
+ done
+}
+
+## @description Apply the shell profile native library additions
+## @audience private
+## @stability evolving
+## @replaceable yes
+function hadoop_shellprofiles_nativelib
+{
+ local i
+
+ for i in ${HADOOP_SHELL_PROFILES}
+ do
+ if declare -F _${i}_hadoop_nativelib >/dev/null ; then
+ hadoop_debug "Profiles: ${i} nativelib"
+ # shellcheck disable=SC2086
+ _${i}_hadoop_nativelib
+ fi
+ done
+}
+
+## @description Apply the shell profile final configuration
+## @audience private
+## @stability evolving
+## @replaceable yes
+function hadoop_shellprofiles_finalize
+{
+ local i
+
+ for i in ${HADOOP_SHELL_PROFILES}
+ do
+ if declare -F _${i}_hadoop_finalize >/dev/null ; then
+ hadoop_debug "Profiles: ${i} finalize"
+ # shellcheck disable=SC2086
+ _${i}_hadoop_finalize
+ fi
+ done
+}
+
+## @description Initialize the Hadoop shell environment, now that
+## @description user settings have been imported
+## @audience private
+## @stability evolving
+## @replaceable no
+function hadoop_basic_init
+{
+ # Some of these are also set in hadoop-env.sh.
+ # we still set them here just in case hadoop-env.sh is
+ # broken in some way, set up defaults, etc.
+ #
+ # but it is important to note that if you update these
+ # you also need to update hadoop-env.sh as well!!!
+
+ CLASSPATH=""
+ hadoop_debug "Initialize CLASSPATH"
+
+ if [[ -z "${HADOOP_COMMON_HOME}" ]] &&
+ [[ -d "${HADOOP_HOME}/${HADOOP_COMMON_DIR}" ]]; then
+ export HADOOP_COMMON_HOME="${HADOOP_HOME}"
+ fi
+
+ # default policy file for service-level authorization
+ HADOOP_POLICYFILE=${HADOOP_POLICYFILE:-"hadoop-policy.xml"}
+
+ # define HADOOP_HDFS_HOME
+ if [[ -z "${HADOOP_HDFS_HOME}" ]] &&
+ [[ -d "${HADOOP_HOME}/${HDFS_DIR}" ]]; then
+ export HADOOP_HDFS_HOME="${HADOOP_HOME}"
+ fi
+
+ # define HADOOP_YARN_HOME
+ if [[ -z "${HADOOP_YARN_HOME}" ]] &&
+ [[ -d "${HADOOP_HOME}/${YARN_DIR}" ]]; then
+ export HADOOP_YARN_HOME="${HADOOP_HOME}"
+ fi
+
+ # define HADOOP_MAPRED_HOME
+ if [[ -z "${HADOOP_MAPRED_HOME}" ]] &&
+ [[ -d "${HADOOP_HOME}/${MAPRED_DIR}" ]]; then
+ export HADOOP_MAPRED_HOME="${HADOOP_HOME}"
+ fi
+
+ if [[ ! -d "${HADOOP_COMMON_HOME}" ]]; then
+ hadoop_error "ERROR: Invalid HADOOP_COMMON_HOME"
+ exit 1
+ fi
+
+ if [[ ! -d "${HADOOP_HDFS_HOME}" ]]; then
+ hadoop_error "ERROR: Invalid HADOOP_HDFS_HOME"
+ exit 1
+ fi
+
+ if [[ ! -d "${HADOOP_YARN_HOME}" ]]; then
+ hadoop_error "ERROR: Invalid HADOOP_YARN_HOME"
+ exit 1
+ fi
+
+ if [[ ! -d "${HADOOP_MAPRED_HOME}" ]]; then
+ hadoop_error "ERROR: Invalid HADOOP_MAPRED_HOME"
+ exit 1
+ fi
+
+ # if for some reason the shell doesn't have $USER defined
+ # (e.g., ssh'd in to execute a command)
+ # let's get the effective username and use that
+ USER=${USER:-$(id -nu)}
+ HADOOP_IDENT_STRING=${HADOOP_IDENT_STRING:-$USER}
+ HADOOP_LOG_DIR=${HADOOP_LOG_DIR:-"${HADOOP_HOME}/logs"}
+ HADOOP_LOGFILE=${HADOOP_LOGFILE:-hadoop.log}
+ HADOOP_LOGLEVEL=${HADOOP_LOGLEVEL:-INFO}
+ HADOOP_NICENESS=${HADOOP_NICENESS:-0}
+ HADOOP_STOP_TIMEOUT=${HADOOP_STOP_TIMEOUT:-5}
+ HADOOP_PID_DIR=${HADOOP_PID_DIR:-/tmp}
+ HADOOP_ROOT_LOGGER=${HADOOP_ROOT_LOGGER:-${HADOOP_LOGLEVEL},console}
+ HADOOP_DAEMON_ROOT_LOGGER=${HADOOP_DAEMON_ROOT_LOGGER:-${HADOOP_LOGLEVEL},RFA}
+ HADOOP_SECURITY_LOGGER=${HADOOP_SECURITY_LOGGER:-INFO,NullAppender}
+ HADOOP_SSH_OPTS=${HADOOP_SSH_OPTS-"-o BatchMode=yes -o StrictHostKeyChecking=no -o ConnectTimeout=10s"}
+ HADOOP_SECURE_LOG_DIR=${HADOOP_SECURE_LOG_DIR:-${HADOOP_LOG_DIR}}
+ HADOOP_SECURE_PID_DIR=${HADOOP_SECURE_PID_DIR:-${HADOOP_PID_DIR}}
+ HADOOP_SSH_PARALLEL=${HADOOP_SSH_PARALLEL:-10}
+}
+
+## @description Set the worker support information to the contents
+## @description of `filename`
+## @audience public
+## @stability stable
+## @replaceable no
+## @param filename
+## @return will exit if file does not exist
+function hadoop_populate_workers_file
+{
+ local workersfile=$1
+ shift
+ if [[ -f "${workersfile}" ]]; then
+ HADOOP_WORKERS="${workersfile}"
+ elif [[ -f "${HADOOP_CONF_DIR}/${workersfile}" ]]; then
+ HADOOP_WORKERS="${HADOOP_CONF_DIR}/${workersfile}"
+ else
+ hadoop_error "ERROR: Cannot find hosts file \"${workersfile}\""
+ hadoop_exit_with_usage 1
+ fi
+}
+
+## @description Rotates the given `file` until `number` of
+## @description files exist.
+## @audience public
+## @stability stable
+## @replaceable no
+## @param filename
+## @param [number]
+## @return $? will contain last mv's return value
+function hadoop_rotate_log
+{
+ #
+ # Users are likely to replace this one for something
+ # that gzips or uses dates or who knows what.
+ #
+ # be aware that &1 and &2 might go through here
+ # so don't do anything too crazy...
+ #
+ local log=$1;
+ local num=${2:-5};
+
+ if [[ -f "${log}" ]]; then # rotate logs
+ while [[ ${num} -gt 1 ]]; do
+ #shellcheck disable=SC2086
+ let prev=${num}-1
+ if [[ -f "${log}.${prev}" ]]; then
+ mv "${log}.${prev}" "${log}.${num}"
+ fi
+ num=${prev}
+ done
+ mv "${log}" "${log}.${num}"
+ fi
+}
+
+## @description Via ssh, log into `hostname` and run `command`
+## @audience private
+## @stability evolving
+## @replaceable yes
+## @param hostname
+## @param command
+## @param [...]
+function hadoop_actual_ssh
+{
+ # we are passing this function to xargs
+ # should get hostname followed by rest of command line
+ local worker=$1
+ shift
+
+ # shellcheck disable=SC2086
+ ssh ${HADOOP_SSH_OPTS} ${worker} $"${@// /\\ }" 2>&1 | sed "s/^/$worker: /"
+}
+
+## @description Connect to ${HADOOP_WORKERS} or ${HADOOP_WORKER_NAMES}
+## @description and execute command.
+## @audience private
+## @stability evolving
+## @replaceable yes
+## @param command
+## @param [...]
+function hadoop_connect_to_hosts
+{
+ # shellcheck disable=SC2124
+ local params="$@"
+ local worker_file
+ local tmpslvnames
+
+ #
+ # ssh (or whatever) to a host
+ #
+ # User can specify hostnames or a file where the hostnames are (not both)
+ if [[ -n "${HADOOP_WORKERS}" && -n "${HADOOP_WORKER_NAMES}" ]] ; then
+ hadoop_error "ERROR: Both HADOOP_WORKERS and HADOOP_WORKER_NAMES were defined. Aborting."
+ exit 1
+ elif [[ -z "${HADOOP_WORKER_NAMES}" ]]; then
+ if [[ -n "${HADOOP_WORKERS}" ]]; then
+ worker_file=${HADOOP_WORKERS}
+ elif [[ -f "${HADOOP_CONF_DIR}/workers" ]]; then
+ worker_file=${HADOOP_CONF_DIR}/workers
+ elif [[ -f "${HADOOP_CONF_DIR}/slaves" ]]; then
+ hadoop_error "WARNING: 'slaves' file has been deprecated. Please use 'workers' file instead."
+ worker_file=${HADOOP_CONF_DIR}/slaves
+ fi
+ fi
+
+ # if pdsh is available, let's use it. otherwise default
+ # to a loop around ssh. (ugh)
+ if [[ -e '/usr/bin/pdsh' ]]; then
+ if [[ -z "${HADOOP_WORKER_NAMES}" ]] ; then
+ # if we were given a file, just let pdsh deal with it.
+ # shellcheck disable=SC2086
+ PDSH_SSH_ARGS_APPEND="${HADOOP_SSH_OPTS}" pdsh \
+ -f "${HADOOP_SSH_PARALLEL}" -w ^"${worker_file}" $"${@// /\\ }" 2>&1
+ else
+ # no spaces allowed in the pdsh arg host list
+ # shellcheck disable=SC2086
+ tmpslvnames=$(echo ${HADOOP_WORKER_NAMES} | tr -s ' ' ,)
+ PDSH_SSH_ARGS_APPEND="${HADOOP_SSH_OPTS}" pdsh \
+ -f "${HADOOP_SSH_PARALLEL}" \
+ -w "${tmpslvnames}" $"${@// /\\ }" 2>&1
+ fi
+ else
+ if [[ -z "${HADOOP_WORKER_NAMES}" ]]; then
+ HADOOP_WORKER_NAMES=$(sed 's/#.*$//;/^$/d' "${worker_file}")
+ fi
+ hadoop_connect_to_hosts_without_pdsh "${params}"
+ fi
+}
+
+## @description Connect to ${HADOOP_WORKER_NAMES} and execute command
+## @description under the environment which does not support pdsh.
+## @audience private
+## @stability evolving
+## @replaceable yes
+## @param command
+## @param [...]
+function hadoop_connect_to_hosts_without_pdsh
+{
+ # shellcheck disable=SC2124
+ local params="$@"
+ local workers=(${HADOOP_WORKER_NAMES})
+ for (( i = 0; i < ${#workers[@]}; i++ ))
+ do
+ if (( i != 0 && i % HADOOP_SSH_PARALLEL == 0 )); then
+ wait
+ fi
+ # shellcheck disable=SC2086
+ hadoop_actual_ssh "${workers[$i]}" ${params} &
+ done
+ wait
+}
+
+## @description Utility routine to handle --workers mode
+## @audience private
+## @stability evolving
+## @replaceable yes
+## @param commandarray
+function hadoop_common_worker_mode_execute
+{
+ #
+ # input should be the command line as given by the user
+ # in the form of an array
+ #
+ local argv=("$@")
+
+ # if --workers is still on the command line, remove it
+ # to prevent loops
+ # Also remove --hostnames and --hosts along with arg values
+ local argsSize=${#argv[@]};
+ for (( i = 0; i < argsSize; i++ ))
+ do
+ if [[ "${argv[$i]}" =~ ^--workers$ ]]; then
+ unset argv[$i]
+ elif [[ "${argv[$i]}" =~ ^--hostnames$ ]] ||
+ [[ "${argv[$i]}" =~ ^--hosts$ ]]; then
+ unset argv[$i];
+ let i++;
+ unset argv[$i];
+ fi
+ done
+ if [[ ${QATESTMODE} = true ]]; then
+ echo "${argv[@]}"
+ return
+ fi
+ hadoop_connect_to_hosts -- "${argv[@]}"
+}
+
+## @description Verify that a shell command was passed a valid
+## @description class name
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param classname
+## @return 0 = success
+## @return 1 = failure w/user message
+function hadoop_validate_classname
+{
+ local class=$1
+ shift 1
+
+ if [[ ! ${class} =~ \. ]]; then
+ # assuming the arg is typo of command if it does not conatain ".".
+ # class belonging to no package is not allowed as a result.
+ hadoop_error "ERROR: ${class} is not COMMAND nor fully qualified CLASSNAME."
+ return 1
+ fi
+ return 0
+}
+
+## @description Append the `appendstring` if `checkstring` is not
+## @description present in the given `envvar`
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param envvar
+## @param checkstring
+## @param appendstring
+function hadoop_add_param
+{
+ #
+ # general param dedupe..
+ # $1 is what we are adding to
+ # $2 is the name of what we want to add (key)
+ # $3 is the key+value of what we're adding
+ #
+ # doing it this way allows us to support all sorts of
+ # different syntaxes, just so long as they are space
+ # delimited
+ #
+ if [[ ! ${!1} =~ $2 ]] ; then
+ #shellcheck disable=SC2140
+ eval "$1"="'${!1} $3'"
+ if [[ ${!1:0:1} = ' ' ]]; then
+ #shellcheck disable=SC2140
+ eval "$1"="'${!1# }'"
+ fi
+ hadoop_debug "$1 accepted $3"
+ else
+ hadoop_debug "$1 declined $3"
+ fi
+}
+
+## @description Register the given `shellprofile` to the Hadoop
+## @description shell subsystem
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param shellprofile
+function hadoop_add_profile
+{
+ # shellcheck disable=SC2086
+ hadoop_add_param HADOOP_SHELL_PROFILES $1 $1
+}
+
+## @description Add a file system object (directory, file,
+## @description wildcard, ...) to the classpath. Optionally provide
+## @description a hint as to where in the classpath it should go.
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param object
+## @param [before|after]
+## @return 0 = success (added or duplicate)
+## @return 1 = failure (doesn't exist or some other reason)
+function hadoop_add_classpath
+{
+ # However, with classpath (& JLP), we can do dedupe
+ # along with some sanity checking (e.g., missing directories)
+ # since we have a better idea of what is legal
+ #
+ # for wildcard at end, we can
+ # at least check the dir exists
+ if [[ $1 =~ ^.*\*$ ]]; then
+ local mp
+ mp=$(dirname "$1")
+ if [[ ! -d "${mp}" ]]; then
+ hadoop_debug "Rejected CLASSPATH: $1 (not a dir)"
+ return 1
+ fi
+
+ # no wildcard in the middle, so check existence
+ # (doesn't matter *what* it is)
+ elif [[ ! $1 =~ ^.*\*.*$ ]] && [[ ! -e "$1" ]]; then
+ hadoop_debug "Rejected CLASSPATH: $1 (does not exist)"
+ return 1
+ fi
+ if [[ -z "${CLASSPATH}" ]]; then
+ CLASSPATH=$1
+ hadoop_debug "Initial CLASSPATH=$1"
+ elif [[ ":${CLASSPATH}:" != *":$1:"* ]]; then
+ if [[ "$2" = "before" ]]; then
+ CLASSPATH="$1:${CLASSPATH}"
+ hadoop_debug "Prepend CLASSPATH: $1"
+ else
+ CLASSPATH+=:$1
+ hadoop_debug "Append CLASSPATH: $1"
+ fi
+ else
+ hadoop_debug "Dupe CLASSPATH: $1"
+ fi
+ return 0
+}
+
+## @description Add a file system object (directory, file,
+## @description wildcard, ...) to the colonpath. Optionally provide
+## @description a hint as to where in the colonpath it should go.
+## @description Prior to adding, objects are checked for duplication
+## @description and check for existence. Many other functions use
+## @description this function as their base implementation
+## @description including `hadoop_add_javalibpath` and `hadoop_add_ldlibpath`.
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param envvar
+## @param object
+## @param [before|after]
+## @return 0 = success (added or duplicate)
+## @return 1 = failure (doesn't exist or some other reason)
+function hadoop_add_colonpath
+{
+ # this is CLASSPATH, JLP, etc but with dedupe but no
+ # other checking
+ if [[ -d "${2}" ]] && [[ ":${!1}:" != *":$2:"* ]]; then
+ if [[ -z "${!1}" ]]; then
+ # shellcheck disable=SC2086
+ eval $1="'$2'"
+ hadoop_debug "Initial colonpath($1): $2"
+ elif [[ "$3" = "before" ]]; then
+ # shellcheck disable=SC2086
+ eval $1="'$2:${!1}'"
+ hadoop_debug "Prepend colonpath($1): $2"
+ else
+ # shellcheck disable=SC2086
+ eval $1+=":'$2'"
+ hadoop_debug "Append colonpath($1): $2"
+ fi
+ return 0
+ fi
+ hadoop_debug "Rejected colonpath($1): $2"
+ return 1
+}
+
+## @description Add a file system object (directory, file,
+## @description wildcard, ...) to the Java JNI path. Optionally
+## @description provide a hint as to where in the Java JNI path
+## @description it should go.
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param object
+## @param [before|after]
+## @return 0 = success (added or duplicate)
+## @return 1 = failure (doesn't exist or some other reason)
+function hadoop_add_javalibpath
+{
+ # specialized function for a common use case
+ hadoop_add_colonpath JAVA_LIBRARY_PATH "$1" "$2"
+}
+
+## @description Add a file system object (directory, file,
+## @description wildcard, ...) to the LD_LIBRARY_PATH. Optionally
+## @description provide a hint as to where in the LD_LIBRARY_PATH
+## @description it should go.
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param object
+## @param [before|after]
+## @return 0 = success (added or duplicate)
+## @return 1 = failure (doesn't exist or some other reason)
+function hadoop_add_ldlibpath
+{
+ local status
+ # specialized function for a common use case
+ hadoop_add_colonpath LD_LIBRARY_PATH "$1" "$2"
+ status=$?
+
+ # note that we export this
+ export LD_LIBRARY_PATH
+ return ${status}
+}
+
+## @description Add the common/core Hadoop components to the
+## @description environment
+## @audience private
+## @stability evolving
+## @replaceable yes
+## @returns 1 on failure, may exit
+## @returns 0 on success
+function hadoop_add_common_to_classpath
+{
+ #
+ # get all of the common jars+config in the path
+ #
+
+ if [[ -z "${HADOOP_COMMON_HOME}"
+ || -z "${HADOOP_COMMON_DIR}"
+ || -z "${HADOOP_COMMON_LIB_JARS_DIR}" ]]; then
+ hadoop_debug "COMMON_HOME=${HADOOP_COMMON_HOME}"
+ hadoop_debug "COMMON_DIR=${HADOOP_COMMON_DIR}"
+ hadoop_debug "COMMON_LIB_JARS_DIR=${HADOOP_COMMON_LIB_JARS_DIR}"
+ hadoop_error "ERROR: HADOOP_COMMON_HOME or related vars are not configured."
+ exit 1
+ fi
+
+ # developers
+ if [[ -n "${HADOOP_ENABLE_BUILD_PATHS}" ]]; then
+ hadoop_add_classpath "${HADOOP_COMMON_HOME}/hadoop-common/target/classes"
+ fi
+
+ hadoop_add_classpath "${HADOOP_COMMON_HOME}/${HADOOP_COMMON_LIB_JARS_DIR}"'/*'
+ hadoop_add_classpath "${HADOOP_COMMON_HOME}/${HADOOP_COMMON_DIR}"'/*'
+}
+
+## @description Run libexec/tools/module.sh to add to the classpath
+## @description environment
+## @audience private
+## @stability evolving
+## @replaceable yes
+## @param module
+function hadoop_add_to_classpath_tools
+{
+ declare module=$1
+
+ if [[ -f "${HADOOP_LIBEXEC_DIR}/tools/${module}.sh" ]]; then
+ # shellcheck disable=SC1090
+ . "${HADOOP_LIBEXEC_DIR}/tools/${module}.sh"
+ else
+ hadoop_error "ERROR: Tools helper ${HADOOP_LIBEXEC_DIR}/tools/${module}.sh was not found."
+ fi
+
+ if declare -f hadoop_classpath_tools_${module} >/dev/null 2>&1; then
+ "hadoop_classpath_tools_${module}"
+ fi
+}
+
+## @description Add the user's custom classpath settings to the
+## @description environment
+## @audience private
+## @stability evolving
+## @replaceable yes
+function hadoop_add_to_classpath_userpath
+{
+ # Add the user-specified HADOOP_CLASSPATH to the
+ # official CLASSPATH env var if HADOOP_USE_CLIENT_CLASSLOADER
+ # is not set.
+ # Add it first or last depending on if user has
+ # set env-var HADOOP_USER_CLASSPATH_FIRST
+ # we'll also dedupe it, because we're cool like that.
+ #
+ declare -a array
+ declare -i c=0
+ declare -i j
+ declare -i i
+ declare idx
+
+ if [[ -n "${HADOOP_CLASSPATH}" ]]; then
+ # I wonder if Java runs on VMS.
+ for idx in $(echo "${HADOOP_CLASSPATH}" | tr : '\n'); do
+ array[${c}]=${idx}
+ ((c=c+1))
+ done
+
+ # bats gets confused by j getting set to 0
+ ((j=c-1)) || ${QATESTMODE}
+
+ if [[ -z "${HADOOP_USE_CLIENT_CLASSLOADER}" ]]; then
+ if [[ -z "${HADOOP_USER_CLASSPATH_FIRST}" ]]; then
+ for ((i=0; i<=j; i++)); do
+ hadoop_add_classpath "${array[$i]}" after
+ done
+ else
+ for ((i=j; i>=0; i--)); do
+ hadoop_add_classpath "${array[$i]}" before
+ done
+ fi
+ fi
+ fi
+}
+
+## @description Routine to configure any OS-specific settings.
+## @audience public
+## @stability stable
+## @replaceable yes
+## @return may exit on failure conditions
+function hadoop_os_tricks
+{
+ local bindv6only
+
+ HADOOP_IS_CYGWIN=false
+ case ${HADOOP_OS_TYPE} in
+ Darwin)
+ if [[ -z "${JAVA_HOME}" ]]; then
+ if [[ -x /usr/libexec/java_home ]]; then
+ JAVA_HOME="$(/usr/libexec/java_home)"
+ export JAVA_HOME
+ else
+ JAVA_HOME=/Library/Java/Home
+ export JAVA_HOME
+ fi
+ fi
+ ;;
+ Linux)
+
+ # Newer versions of glibc use an arena memory allocator that
+ # causes virtual # memory usage to explode. This interacts badly
+ # with the many threads that we use in Hadoop. Tune the variable
+ # down to prevent vmem explosion.
+ export MALLOC_ARENA_MAX=${MALLOC_ARENA_MAX:-4}
+ # we put this in QA test mode off so that non-Linux can test
+ if [[ "${QATESTMODE}" = true ]]; then
+ return
+ fi
+
+ # NOTE! HADOOP_ALLOW_IPV6 is a developer hook. We leave it
+ # undocumented in hadoop-env.sh because we don't want users to
+ # shoot themselves in the foot while devs make IPv6 work.
+
+ bindv6only=$(/sbin/sysctl -n net.ipv6.bindv6only 2> /dev/null)
+
+ if [[ -n "${bindv6only}" ]] &&
+ [[ "${bindv6only}" -eq "1" ]] &&
+ [[ "${HADOOP_ALLOW_IPV6}" != "yes" ]]; then
+ hadoop_error "ERROR: \"net.ipv6.bindv6only\" is set to 1 "
+ hadoop_error "ERROR: Hadoop networking could be broken. Aborting."
+ hadoop_error "ERROR: For more info: http://wiki.apache.org/hadoop/HadoopIPv6"
+ exit 1
+ fi
+ ;;
+ CYGWIN*)
+ # Flag that we're running on Cygwin to trigger path translation later.
+ HADOOP_IS_CYGWIN=true
+ ;;
+ esac
+}
+
+## @description Configure/verify ${JAVA_HOME}
+## @audience public
+## @stability stable
+## @replaceable yes
+## @return may exit on failure conditions
+function hadoop_java_setup
+{
+ # Bail if we did not detect it
+ if [[ -z "${JAVA_HOME}" ]]; then
+ hadoop_error "ERROR: JAVA_HOME is not set and could not be found."
+ exit 1
+ fi
+
+ if [[ ! -d "${JAVA_HOME}" ]]; then
+ hadoop_error "ERROR: JAVA_HOME ${JAVA_HOME} does not exist."
+ exit 1
+ fi
+
+ JAVA="${JAVA_HOME}/bin/java"
+
+ if [[ ! -x "$JAVA" ]]; then
+ hadoop_error "ERROR: $JAVA is not executable."
+ exit 1
+ fi
+}
+
+## @description Finish Java JNI paths prior to execution
+## @audience private
+## @stability evolving
+## @replaceable yes
+function hadoop_finalize_libpaths
+{
+ if [[ -n "${JAVA_LIBRARY_PATH}" ]]; then
+ hadoop_translate_cygwin_path JAVA_LIBRARY_PATH
+ hadoop_add_param HADOOP_OPTS java.library.path \
+ "-Djava.library.path=${JAVA_LIBRARY_PATH}"
+ export LD_LIBRARY_PATH
+ fi
+}
+
+## @description Finish Java heap parameters prior to execution
+## @audience private
+## @stability evolving
+## @replaceable yes
+function hadoop_finalize_hadoop_heap
+{
+ if [[ -n "${HADOOP_HEAPSIZE_MAX}" ]]; then
+ if [[ "${HADOOP_HEAPSIZE_MAX}" =~ ^[0-9]+$ ]]; then
+ HADOOP_HEAPSIZE_MAX="${HADOOP_HEAPSIZE_MAX}m"
+ fi
+ hadoop_add_param HADOOP_OPTS Xmx "-Xmx${HADOOP_HEAPSIZE_MAX}"
+ fi
+
+ # backwards compatibility
+ if [[ -n "${HADOOP_HEAPSIZE}" ]]; then
+ if [[ "${HADOOP_HEAPSIZE}" =~ ^[0-9]+$ ]]; then
+ HADOOP_HEAPSIZE="${HADOOP_HEAPSIZE}m"
+ fi
+ hadoop_add_param HADOOP_OPTS Xmx "-Xmx${HADOOP_HEAPSIZE}"
+ fi
+
+ if [[ -n "${HADOOP_HEAPSIZE_MIN}" ]]; then
+ if [[ "${HADOOP_HEAPSIZE_MIN}" =~ ^[0-9]+$ ]]; then
+ HADOOP_HEAPSIZE_MIN="${HADOOP_HEAPSIZE_MIN}m"
+ fi
+ hadoop_add_param HADOOP_OPTS Xms "-Xms${HADOOP_HEAPSIZE_MIN}"
+ fi
+}
+
+## @description Converts the contents of the variable name
+## @description `varnameref` into the equivalent Windows path.
+## @description If the second parameter is true, then `varnameref`
+## @description is treated as though it was a path list.
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param varnameref
+## @param [true]
+function hadoop_translate_cygwin_path
+{
+ if [[ "${HADOOP_IS_CYGWIN}" = "true" ]]; then
+ if [[ "$2" = "true" ]]; then
+ #shellcheck disable=SC2016
+ eval "$1"='$(cygpath -p -w "${!1}" 2>/dev/null)'
+ else
+ #shellcheck disable=SC2016
+ eval "$1"='$(cygpath -w "${!1}" 2>/dev/null)'
+ fi
+ fi
+}
+
+## @description Adds the HADOOP_CLIENT_OPTS variable to
+## @description HADOOP_OPTS if HADOOP_SUBCMD_SUPPORTDAEMONIZATION is false
+## @audience public
+## @stability stable
+## @replaceable yes
+function hadoop_add_client_opts
+{
+ if [[ "${HADOOP_SUBCMD_SUPPORTDAEMONIZATION}" = false
+ || -z "${HADOOP_SUBCMD_SUPPORTDAEMONIZATION}" ]]; then
+ hadoop_debug "Appending HADOOP_CLIENT_OPTS onto HADOOP_OPTS"
+ HADOOP_OPTS="${HADOOP_OPTS} ${HADOOP_CLIENT_OPTS}"
+ fi
+}
+
+## @description Finish configuring Hadoop specific system properties
+## @description prior to executing Java
+## @audience private
+## @stability evolving
+## @replaceable yes
+function hadoop_finalize_hadoop_opts
+{
+ hadoop_translate_cygwin_path HADOOP_LOG_DIR
+ hadoop_add_param HADOOP_OPTS hadoop.log.dir "-Dhadoop.log.dir=${HADOOP_LOG_DIR}"
+ hadoop_add_param HADOOP_OPTS hadoop.log.file "-Dhadoop.log.file=${HADOOP_LOGFILE}"
+ hadoop_translate_cygwin_path HADOOP_HOME
+ export HADOOP_HOME
+ hadoop_add_param HADOOP_OPTS hadoop.home.dir "-Dhadoop.home.dir=${HADOOP_HOME}"
+ hadoop_add_param HADOOP_OPTS hadoop.id.str "-Dhadoop.id.str=${HADOOP_IDENT_STRING}"
+ hadoop_add_param HADOOP_OPTS hadoop.root.logger "-Dhadoop.root.logger=${HADOOP_ROOT_LOGGER}"
+ hadoop_add_param HADOOP_OPTS hadoop.policy.file "-Dhadoop.policy.file=${HADOOP_POLICYFILE}"
+ hadoop_add_param HADOOP_OPTS hadoop.security.logger "-Dhadoop.security.logger=${HADOOP_SECURITY_LOGGER}"
+}
+
+## @description Finish Java classpath prior to execution
+## @audience private
+## @stability evolving
+## @replaceable yes
+function hadoop_finalize_classpath
+{
+ hadoop_add_classpath "${HADOOP_CONF_DIR}" before
+
+ # user classpath gets added at the last minute. this allows
+ # override of CONF dirs and more
+ hadoop_add_to_classpath_userpath
+ hadoop_translate_cygwin_path CLASSPATH true
+}
+
+## @description Finish all the remaining environment settings prior
+## @description to executing Java. This is a wrapper that calls
+## @description the other `finalize` routines.
+## @audience private
+## @stability evolving
+## @replaceable yes
+function hadoop_finalize
+{
+ hadoop_shellprofiles_finalize
+
+ hadoop_finalize_classpath
+ hadoop_finalize_libpaths
+ hadoop_finalize_hadoop_heap
+ hadoop_finalize_hadoop_opts
+
+ hadoop_translate_cygwin_path HADOOP_HOME
+ hadoop_translate_cygwin_path HADOOP_CONF_DIR
+ hadoop_translate_cygwin_path HADOOP_COMMON_HOME
+ hadoop_translate_cygwin_path HADOOP_HDFS_HOME
+ hadoop_translate_cygwin_path HADOOP_YARN_HOME
+ hadoop_translate_cygwin_path HADOOP_MAPRED_HOME
+}
+
+## @description Print usage information and exit with the passed
+## @description `exitcode`
+## @audience public
+## @stability stable
+## @replaceable no
+## @param exitcode
+## @return This function will always exit.
+function hadoop_exit_with_usage
+{
+ local exitcode=$1
+ if [[ -z $exitcode ]]; then
+ exitcode=1
+ fi
+ # shellcheck disable=SC2034
+ if declare -F hadoop_usage >/dev/null ; then
+ hadoop_usage
+ elif [[ -x /usr/bin/cowsay ]]; then
+ /usr/bin/cowsay -f elephant "Sorry, no help available."
+ else
+ hadoop_error "Sorry, no help available."
+ fi
+ exit $exitcode
+}
+
+## @description Verify that prerequisites have been met prior to
+## @description excuting a privileged program.
+## @audience private
+## @stability evolving
+## @replaceable yes
+## @return This routine may exit.
+function hadoop_verify_secure_prereq
+{
+ # if you are on an OS like Illumos that has functional roles
+ # and you are using pfexec, you'll probably want to change
+ # this.
+
+ if ! hadoop_privilege_check && [[ -z "${HADOOP_SECURE_COMMAND}" ]]; then
+ hadoop_error "ERROR: You must be a privileged user in order to run a secure service."
+ exit 1
+ else
+ return 0
+ fi
+}
+
+## @audience private
+## @stability evolving
+## @replaceable yes
+function hadoop_setup_secure_service
+{
+ # need a more complicated setup? replace me!
+
+ HADOOP_PID_DIR=${HADOOP_SECURE_PID_DIR}
+ HADOOP_LOG_DIR=${HADOOP_SECURE_LOG_DIR}
+}
+
+## @audience private
+## @stability evolving
+## @replaceable yes
+function hadoop_verify_piddir
+{
+ if [[ -z "${HADOOP_PID_DIR}" ]]; then
+ hadoop_error "No pid directory defined."
+ exit 1
+ fi
+ hadoop_mkdir "${HADOOP_PID_DIR}"
+ touch "${HADOOP_PID_DIR}/$$" >/dev/null 2>&1
+ if [[ $? -gt 0 ]]; then
+ hadoop_error "ERROR: Unable to write in ${HADOOP_PID_DIR}. Aborting."
+ exit 1
+ fi
+ rm "${HADOOP_PID_DIR}/$$" >/dev/null 2>&1
+}
+
+## @audience private
+## @stability evolving
+## @replaceable yes
+function hadoop_verify_logdir
+{
+ if [[ -z "${HADOOP_LOG_DIR}" ]]; then
+ hadoop_error "No log directory defined."
+ exit 1
+ fi
+ hadoop_mkdir "${HADOOP_LOG_DIR}"
+ touch "${HADOOP_LOG_DIR}/$$" >/dev/null 2>&1
+ if [[ $? -gt 0 ]]; then
+ hadoop_error "ERROR: Unable to write in ${HADOOP_LOG_DIR}. Aborting."
+ exit 1
+ fi
+ rm "${HADOOP_LOG_DIR}/$$" >/dev/null 2>&1
+}
+
+## @description Determine the status of the daemon referenced
+## @description by `pidfile`
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param pidfile
+## @return (mostly) LSB 4.1.0 compatible status
+function hadoop_status_daemon
+{
+ #
+ # LSB 4.1.0 compatible status command (1)
+ #
+ # 0 = program is running
+ # 1 = dead, but still a pid (2)
+ # 2 = (not used by us)
+ # 3 = not running
+ #
+ # 1 - this is not an endorsement of the LSB
+ #
+ # 2 - technically, the specification says /var/run/pid, so
+ # we should never return this value, but we're giving
+ # them the benefit of a doubt and returning 1 even if
+ # our pid is not in in /var/run .
+ #
+
+ local pidfile=$1
+ shift
+
+ local pid
+ local pspid
+
+ if [[ -f "${pidfile}" ]]; then
+ pid=$(cat "${pidfile}")
+ if pspid=$(ps -o args= -p"${pid}" 2>/dev/null); then
+ # this is to check that the running process we found is actually the same
+ # daemon that we're interested in
+ if [[ ${pspid} =~ -Dproc_${daemonname} ]]; then
+ return 0
+ fi
+ fi
+ return 1
+ fi
+ return 3
+}
+
+## @description Execute the Java `class`, passing along any `options`.
+## @description Additionally, set the Java property -Dproc_`command`.
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param command
+## @param class
+## @param [options]
+function hadoop_java_exec
+{
+ # run a java command. this is used for
+ # non-daemons
+
+ local command=$1
+ local class=$2
+ shift 2
+
+ hadoop_debug "Final CLASSPATH: ${CLASSPATH}"
+ hadoop_debug "Final HADOOP_OPTS: ${HADOOP_OPTS}"
+ hadoop_debug "Final JAVA_HOME: ${JAVA_HOME}"
+ hadoop_debug "java: ${JAVA}"
+ hadoop_debug "Class name: ${class}"
+ hadoop_debug "Command line options: $*"
+
+ export CLASSPATH
+ #shellcheck disable=SC2086
+ exec "${JAVA}" "-Dproc_${command}" ${HADOOP_OPTS} "${class}" "$@"
+}
+
+## @description Start a non-privileged daemon in the foreground.
+## @audience private
+## @stability evolving
+## @replaceable yes
+## @param command
+## @param class
+## @param pidfile
+## @param [options]
+function hadoop_start_daemon
+{
+ # this is our non-privileged daemon starter
+ # that fires up a daemon in the *foreground*
+ # so complex! so wow! much java!
+ local command=$1
+ local class=$2
+ local pidfile=$3
+ shift 3
+
+ hadoop_debug "Final CLASSPATH: ${CLASSPATH}"
+ hadoop_debug "Final HADOOP_OPTS: ${HADOOP_OPTS}"
+ hadoop_debug "Final JAVA_HOME: ${JAVA_HOME}"
+ hadoop_debug "java: ${JAVA}"
+ hadoop_debug "Class name: ${class}"
+ hadoop_debug "Command line options: $*"
+
+ # this is for the non-daemon pid creation
+ #shellcheck disable=SC2086
+ echo $$ > "${pidfile}" 2>/dev/null
+ if [[ $? -gt 0 ]]; then
+ hadoop_error "ERROR: Cannot write ${command} pid ${pidfile}."
+ fi
+
+ export CLASSPATH
+ #shellcheck disable=SC2086
+ exec "${JAVA}" "-Dproc_${command}" ${HADOOP_OPTS} "${class}" "$@"
+}
+
+## @description Start a non-privileged daemon in the background.
+## @audience private
+## @stability evolving
+## @replaceable yes
+## @param command
+## @param class
+## @param pidfile
+## @param outfile
+## @param [options]
+function hadoop_start_daemon_wrapper
+{
+ local daemonname=$1
+ local class=$2
+ local pidfile=$3
+ local outfile=$4
+ shift 4
+
+ local counter
+
+ hadoop_rotate_log "${outfile}"
+
+ hadoop_start_daemon "${daemonname}" \
+ "$class" \
+ "${pidfile}" \
+ "$@" >> "${outfile}" 2>&1 < /dev/null &
+
+ # we need to avoid a race condition here
+ # so let's wait for the fork to finish
+ # before overriding with the daemonized pid
+ (( counter=0 ))
+ while [[ ! -f ${pidfile} && ${counter} -le 5 ]]; do
+ sleep 1
+ (( counter++ ))
+ done
+
+ # this is for daemon pid creation
+ #shellcheck disable=SC2086
+ echo $! > "${pidfile}" 2>/dev/null
+ if [[ $? -gt 0 ]]; then
+ hadoop_error "ERROR: Cannot write ${daemonname} pid ${pidfile}."
+ fi
+
+ # shellcheck disable=SC2086
+ renice "${HADOOP_NICENESS}" $! >/dev/null 2>&1
+ if [[ $? -gt 0 ]]; then
+ hadoop_error "ERROR: Cannot set priority of ${daemonname} process $!"
+ fi
+
+ # shellcheck disable=SC2086
+ disown %+ >/dev/null 2>&1
+ if [[ $? -gt 0 ]]; then
+ hadoop_error "ERROR: Cannot disconnect ${daemonname} process $!"
+ fi
+ sleep 1
+
+ # capture the ulimit output
+ ulimit -a >> "${outfile}" 2>&1
+
+ # shellcheck disable=SC2086
+ if ! ps -p $! >/dev/null 2>&1; then
+ return 1
+ fi
+ return 0
+}
+
+## @description Start a privileged daemon in the foreground.
+## @audience private
+## @stability evolving
+## @replaceable yes
+## @param command
+## @param class
+## @param daemonpidfile
+## @param daemonoutfile
+## @param daemonerrfile
+## @param wrapperpidfile
+## @param [options]
+function hadoop_start_secure_daemon
+{
+ # this is used to launch a secure daemon in the *foreground*
+ #
+ local daemonname=$1
+ local class=$2
+
+ # pid file to create for our daemon
+ local daemonpidfile=$3
+
+ # where to send stdout. jsvc has bad habits so this *may* be &1
+ # which means you send it to stdout!
+ local daemonoutfile=$4
+
+ # where to send stderr. same thing, except &2 = stderr
+ local daemonerrfile=$5
+ local privpidfile=$6
+ shift 6
+
+ hadoop_rotate_log "${daemonoutfile}"
+ hadoop_rotate_log "${daemonerrfile}"
+
+ # shellcheck disable=SC2153
+ jsvc="${JSVC_HOME}/jsvc"
+ if [[ ! -f "${jsvc}" ]]; then
+ hadoop_error "JSVC_HOME is not set or set incorrectly. jsvc is required to run secure"
+ hadoop_error "or privileged daemons. Please download and install jsvc from "
+ hadoop_error "http://archive.apache.org/dist/commons/daemon/binaries/ "
+ hadoop_error "and set JSVC_HOME to the directory containing the jsvc binary."
+ exit 1
+ fi
+
+ # note that shellcheck will throw a
+ # bogus for-our-use-case 2086 here.
+ # it doesn't properly support multi-line situations
+
+ hadoop_debug "Final CLASSPATH: ${CLASSPATH}"
+ hadoop_debug "Final HADOOP_OPTS: ${HADOOP_OPTS}"
+ hadoop_debug "Final JSVC_HOME: ${JSVC_HOME}"
+ hadoop_debug "jsvc: ${jsvc}"
+ hadoop_debug "Final HADOOP_DAEMON_JSVC_EXTRA_OPTS: ${HADOOP_DAEMON_JSVC_EXTRA_OPTS}"
+ hadoop_debug "Class name: ${class}"
+ hadoop_debug "Command line options: $*"
+
+ #shellcheck disable=SC2086
+ echo $$ > "${privpidfile}" 2>/dev/null
+ if [[ $? -gt 0 ]]; then
+ hadoop_error "ERROR: Cannot write ${daemonname} pid ${privpidfile}."
+ fi
+
+ # shellcheck disable=SC2086
+ exec "${jsvc}" \
+ "-Dproc_${daemonname}" \
+ ${HADOOP_DAEMON_JSVC_EXTRA_OPTS} \
+ -outfile "${daemonoutfile}" \
+ -errfile "${daemonerrfile}" \
+ -pidfile "${daemonpidfile}" \
+ -nodetach \
+ -user "${HADOOP_SECURE_USER}" \
+ -cp "${CLASSPATH}" \
+ ${HADOOP_OPTS} \
+ "${class}" "$@"
+}
+
+## @description Start a privileged daemon in the background.
+## @audience private
+## @stability evolving
+## @replaceable yes
+## @param command
+## @param class
+## @param daemonpidfile
+## @param daemonoutfile
+## @param wrapperpidfile
+## @param warpperoutfile
+## @param daemonerrfile
+## @param [options]
+function hadoop_start_secure_daemon_wrapper
+{
+ # this wraps hadoop_start_secure_daemon to take care
+ # of the dirty work to launch a daemon in the background!
+ local daemonname=$1
+ local class=$2
+
+ # same rules as hadoop_start_secure_daemon except we
+ # have some additional parameters
+
+ local daemonpidfile=$3
+
+ local daemonoutfile=$4
+
+ # the pid file of the subprocess that spawned our
+ # secure launcher
+ local jsvcpidfile=$5
+
+ # the output of the subprocess that spawned our secure
+ # launcher
+ local jsvcoutfile=$6
+
+ local daemonerrfile=$7
+ shift 7
+
+ local counter
+
+ hadoop_rotate_log "${jsvcoutfile}"
+
+ hadoop_start_secure_daemon \
+ "${daemonname}" \
+ "${class}" \
+ "${daemonpidfile}" \
+ "${daemonoutfile}" \
+ "${daemonerrfile}" \
+ "${jsvcpidfile}" "$@" >> "${jsvcoutfile}" 2>&1 < /dev/null &
+
+ # we need to avoid a race condition here
+ # so let's wait for the fork to finish
+ # before overriding with the daemonized pid
+ (( counter=0 ))
+ while [[ ! -f ${daemonpidfile} && ${counter} -le 5 ]]; do
+ sleep 1
+ (( counter++ ))
+ done
+
+ #shellcheck disable=SC2086
+ if ! echo $! > "${jsvcpidfile}"; then
+ hadoop_error "ERROR: Cannot write ${daemonname} pid ${jsvcpidfile}."
+ fi
+
+ sleep 1
+ #shellcheck disable=SC2086
+ renice "${HADOOP_NICENESS}" $! >/dev/null 2>&1
+ if [[ $? -gt 0 ]]; then
+ hadoop_error "ERROR: Cannot set priority of ${daemonname} process $!"
+ fi
+ if [[ -f "${daemonpidfile}" ]]; then
+ #shellcheck disable=SC2046
+ renice "${HADOOP_NICENESS}" $(cat "${daemonpidfile}" 2>/dev/null) >/dev/null 2>&1
+ if [[ $? -gt 0 ]]; then
+ hadoop_error "ERROR: Cannot set priority of ${daemonname} process $(cat "${daemonpidfile}" 2>/dev/null)"
+ fi
+ fi
+ #shellcheck disable=SC2046
+ disown %+ >/dev/null 2>&1
+ if [[ $? -gt 0 ]]; then
+ hadoop_error "ERROR: Cannot disconnect ${daemonname} process $!"
+ fi
+ # capture the ulimit output
+ su "${HADOOP_SECURE_USER}" -c 'bash -c "ulimit -a"' >> "${jsvcoutfile}" 2>&1
+ #shellcheck disable=SC2086
+ if ! ps -p $! >/dev/null 2>&1; then
+ return 1
+ fi
+ return 0
+}
+
+## @description Wait till process dies or till timeout
+## @audience private
+## @stability evolving
+## @param pid
+## @param timeout
+function wait_process_to_die_or_timeout
+{
+ local pid=$1
+ local timeout=$2
+
+ # Normalize timeout
+ # Round up or down
+ timeout=$(printf "%.0f\n" "${timeout}")
+ if [[ ${timeout} -lt 1 ]]; then
+ # minimum 1 second
+ timeout=1
+ fi
+
+ # Wait to see if it's still alive
+ for (( i=0; i < "${timeout}"; i++ ))
+ do
+ if kill -0 "${pid}" > /dev/null 2>&1; then
+ sleep 1
+ else
+ break
+ fi
+ done
+}
+
+## @description Stop the non-privileged `command` daemon with that
+## @description that is running at `pidfile`.
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param command
+## @param pidfile
+function hadoop_stop_daemon
+{
+ local cmd=$1
+ local pidfile=$2
+ shift 2
+
+ local pid
+ local cur_pid
+
+ if [[ -f "${pidfile}" ]]; then
+ pid=$(cat "$pidfile")
+
+ kill "${pid}" >/dev/null 2>&1
+
+ wait_process_to_die_or_timeout "${pid}" "${HADOOP_STOP_TIMEOUT}"
+
+ if kill -0 "${pid}" > /dev/null 2>&1; then
+ hadoop_error "WARNING: ${cmd} did not stop gracefully after ${HADOOP_STOP_TIMEOUT} seconds: Trying to kill with kill -9"
+ kill -9 "${pid}" >/dev/null 2>&1
+ fi
+ wait_process_to_die_or_timeout "${pid}" "${HADOOP_STOP_TIMEOUT}"
+ if ps -p "${pid}" > /dev/null 2>&1; then
+ hadoop_error "ERROR: Unable to kill ${pid}"
+ else
+ cur_pid=$(cat "$pidfile")
+ if [[ "${pid}" = "${cur_pid}" ]]; then
+ rm -f "${pidfile}" >/dev/null 2>&1
+ else
+ hadoop_error "WARNING: pid has changed for ${cmd}, skip deleting pid file"
+ fi
+ fi
+ fi
+}
+
+## @description Stop the privileged `command` daemon with that
+## @description that is running at `daemonpidfile` and launched with
+## @description the wrapper at `wrapperpidfile`.
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param command
+## @param daemonpidfile
+## @param wrapperpidfile
+function hadoop_stop_secure_daemon
+{
+ local command=$1
+ local daemonpidfile=$2
+ local privpidfile=$3
+ shift 3
+ local ret
+
+ local daemon_pid
+ local priv_pid
+ local cur_daemon_pid
+ local cur_priv_pid
+
+ daemon_pid=$(cat "$daemonpidfile")
+ priv_pid=$(cat "$privpidfile")
+
+ hadoop_stop_daemon "${command}" "${daemonpidfile}"
+ ret=$?
+
+ cur_daemon_pid=$(cat "$daemonpidfile")
+ cur_priv_pid=$(cat "$privpidfile")
+
+ if [[ "${daemon_pid}" = "${cur_daemon_pid}" ]]; then
+ rm -f "${daemonpidfile}" >/dev/null 2>&1
+ else
+ hadoop_error "WARNING: daemon pid has changed for ${command}, skip deleting daemon pid file"
+ fi
+
+ if [[ "${priv_pid}" = "${cur_priv_pid}" ]]; then
+ rm -f "${privpidfile}" >/dev/null 2>&1
+ else
+ hadoop_error "WARNING: priv pid has changed for ${command}, skip deleting priv pid file"
+ fi
+ return ${ret}
+}
+
+## @description Manage a non-privileged daemon.
+## @audience private
+## @stability evolving
+## @replaceable yes
+## @param [start|stop|status|default]
+## @param command
+## @param class
+## @param daemonpidfile
+## @param daemonoutfile
+## @param [options]
+function hadoop_daemon_handler
+{
+ local daemonmode=$1
+ local daemonname=$2
+ local class=$3
+ local daemon_pidfile=$4
+ local daemon_outfile=$5
+ shift 5
+
+ case ${daemonmode} in
+ status)
+ hadoop_status_daemon "${daemon_pidfile}"
+ exit $?
+ ;;
+
+ stop)
+ hadoop_stop_daemon "${daemonname}" "${daemon_pidfile}"
+ exit $?
+ ;;
+
+ ##COMPAT -- older hadoops would also start daemons by default
+ start|default)
+ hadoop_verify_piddir
+ hadoop_verify_logdir
+ hadoop_status_daemon "${daemon_pidfile}"
+ if [[ $? == 0 ]]; then
+ hadoop_error "${daemonname} is running as process $(cat "${daemon_pidfile}"). Stop it first."
+ exit 1
+ else
+ # stale pid file, so just remove it and continue on
+ rm -f "${daemon_pidfile}" >/dev/null 2>&1
+ fi
+ ##COMPAT - differenticate between --daemon start and nothing
+ # "nothing" shouldn't detach
+ if [[ "$daemonmode" = "default" ]]; then
+ hadoop_start_daemon "${daemonname}" "${class}" "${daemon_pidfile}" "$@"
+ else
+ hadoop_start_daemon_wrapper "${daemonname}" \
+ "${class}" "${daemon_pidfile}" "${daemon_outfile}" "$@"
+ fi
+ ;;
+ esac
+}
+
+## @description Manage a privileged daemon.
+## @audience private
+## @stability evolving
+## @replaceable yes
+## @param [start|stop|status|default]
+## @param command
+## @param class
+## @param daemonpidfile
+## @param daemonoutfile
+## @param wrapperpidfile
+## @param wrapperoutfile
+## @param wrappererrfile
+## @param [options]
+function hadoop_secure_daemon_handler
+{
+ local daemonmode=$1
+ local daemonname=$2
+ local classname=$3
+ local daemon_pidfile=$4
+ local daemon_outfile=$5
+ local priv_pidfile=$6
+ local priv_outfile=$7
+ local priv_errfile=$8
+ shift 8
+
+ case ${daemonmode} in
+ status)
+ hadoop_status_daemon "${daemon_pidfile}"
+ exit $?
+ ;;
+
+ stop)
+ hadoop_stop_secure_daemon "${daemonname}" \
+ "${daemon_pidfile}" "${priv_pidfile}"
+ exit $?
+ ;;
+
+ ##COMPAT -- older hadoops would also start daemons by default
+ start|default)
+ hadoop_verify_piddir
+ hadoop_verify_logdir
+ hadoop_status_daemon "${daemon_pidfile}"
+ if [[ $? == 0 ]]; then
+ hadoop_error "${daemonname} is running as process $(cat "${daemon_pidfile}"). Stop it first."
+ exit 1
+ else
+ # stale pid file, so just remove it and continue on
+ rm -f "${daemon_pidfile}" >/dev/null 2>&1
+ fi
+
+ ##COMPAT - differenticate between --daemon start and nothing
+ # "nothing" shouldn't detach
+ if [[ "${daemonmode}" = "default" ]]; then
+ hadoop_start_secure_daemon "${daemonname}" "${classname}" \
+ "${daemon_pidfile}" "${daemon_outfile}" \
+ "${priv_errfile}" "${priv_pidfile}" "$@"
+ else
+ hadoop_start_secure_daemon_wrapper "${daemonname}" "${classname}" \
+ "${daemon_pidfile}" "${daemon_outfile}" \
+ "${priv_pidfile}" "${priv_outfile}" "${priv_errfile}" "$@"
+ fi
+ ;;
+ esac
+}
+
+## @description autodetect whether this is a priv subcmd
+## @description by whether or not a priv user var exists
+## @description and if HADOOP_SECURE_CLASSNAME is defined
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param command
+## @param subcommand
+## @return 1 = not priv
+## @return 0 = priv
+function hadoop_detect_priv_subcmd
+{
+ declare program=$1
+ declare command=$2
+
+ if [[ -z "${HADOOP_SECURE_CLASSNAME}" ]]; then
+ hadoop_debug "No secure classname defined."
+ return 1
+ fi
+
+ uvar=$(hadoop_build_custom_subcmd_var "${program}" "${command}" SECURE_USER)
+ if [[ -z "${!uvar}" ]]; then
+ hadoop_debug "No secure user defined."
+ return 1
+ fi
+ return 0
+}
+
+## @description Build custom subcommand var
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param command
+## @param subcommand
+## @param customid
+## @return string
+function hadoop_build_custom_subcmd_var
+{
+ declare program=$1
+ declare command=$2
+ declare custom=$3
+ declare uprogram
+ declare ucommand
+
+ if [[ -z "${BASH_VERSINFO[0]}" ]] \
+ || [[ "${BASH_VERSINFO[0]}" -lt 4 ]]; then
+ uprogram=$(echo "${program}" | tr '[:lower:]' '[:upper:]')
+ ucommand=$(echo "${command}" | tr '[:lower:]' '[:upper:]')
+ else
+ uprogram=${program^^}
+ ucommand=${command^^}
+ fi
+
+ echo "${uprogram}_${ucommand}_${custom}"
+}
+
+## @description Verify that username in a var converts to user id
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param userstring
+## @return 0 for success
+## @return 1 for failure
+function hadoop_verify_user_resolves
+{
+ declare userstr=$1
+
+ if [[ -z ${userstr} || -z ${!userstr} ]] ; then
+ return 1
+ fi
+
+ id -u "${!userstr}" >/dev/null 2>&1
+}
+
+## @description Verify that ${USER} is allowed to execute the
+## @description given subcommand.
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param command
+## @param subcommand
+## @return return 0 on success
+## @return exit 1 on failure
+function hadoop_verify_user_perm
+{
+ declare program=$1
+ declare command=$2
+ declare uvar
+
+ if [[ ${command} =~ \. ]]; then
+ return 1
+ fi
+
+ uvar=$(hadoop_build_custom_subcmd_var "${program}" "${command}" USER)
+
+ if [[ -n ${!uvar} ]]; then
+ if [[ ${!uvar} != "${USER}" ]]; then
+ hadoop_error "ERROR: ${command} can only be executed by ${!uvar}."
+ exit 1
+ fi
+ fi
+ return 0
+}
+
+## @description Verify that ${USER} is allowed to execute the
+## @description given subcommand.
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param subcommand
+## @return 1 on no re-exec needed
+## @return 0 on need to re-exec
+function hadoop_need_reexec
+{
+ declare program=$1
+ declare command=$2
+ declare uvar
+
+ # we've already been re-execed, bail
+
+ if [[ "${HADOOP_REEXECED_CMD}" = true ]]; then
+ return 1
+ fi
+
+ if [[ ${command} =~ \. ]]; then
+ return 1
+ fi
+
+ # if we have privilege, and the _USER is defined, and _USER is
+ # set to someone who isn't us, then yes, we should re-exec.
+ # otherwise no, don't re-exec and let the system deal with it.
+
+ if hadoop_privilege_check; then
+ uvar=$(hadoop_build_custom_subcmd_var "${program}" "${command}" USER)
+ if [[ -n ${!uvar} ]]; then
+ if [[ ${!uvar} != "${USER}" ]]; then
+ return 0
+ fi
+ fi
+ fi
+ return 1
+}
+
+## @description Add custom (program)_(command)_OPTS to HADOOP_OPTS.
+## @description Also handles the deprecated cases from pre-3.x.
+## @audience public
+## @stability evolving
+## @replaceable yes
+## @param program
+## @param subcommand
+## @return will exit on failure conditions
+function hadoop_subcommand_opts
+{
+ declare program=$1
+ declare command=$2
+ declare uvar
+ declare depvar
+ declare uprogram
+ declare ucommand
+
+ if [[ -z "${program}" || -z "${command}" ]]; then
+ return 1
+ fi
+
+ if [[ ${command} =~ \. ]]; then
+ return 1
+ fi
+
+ # bash 4 and up have built-in ways to upper and lower
+ # case the contents of vars. This is faster than
+ # calling tr.
+
+ ## We don't call hadoop_build_custom_subcmd_var here
+ ## since we need to construct this for the deprecation
+ ## cases. For Hadoop 4.x, this needs to get cleaned up.
+
+ if [[ -z "${BASH_VERSINFO[0]}" ]] \
+ || [[ "${BASH_VERSINFO[0]}" -lt 4 ]]; then
+ uprogram=$(echo "${program}" | tr '[:lower:]' '[:upper:]')
+ ucommand=$(echo "${command}" | tr '[:lower:]' '[:upper:]')
+ else
+ uprogram=${program^^}
+ ucommand=${command^^}
+ fi
+
+ uvar="${uprogram}_${ucommand}_OPTS"
+
+ # Let's handle all of the deprecation cases early
+ # HADOOP_NAMENODE_OPTS -> HDFS_NAMENODE_OPTS
+
+ depvar="HADOOP_${ucommand}_OPTS"
+
+ if [[ "${depvar}" != "${uvar}" ]]; then
+ if [[ -n "${!depvar}" ]]; then
+ hadoop_deprecate_envvar "${depvar}" "${uvar}"
+ fi
+ fi
+
+ if [[ -n ${!uvar} ]]; then
+ hadoop_debug "Appending ${uvar} onto HADOOP_OPTS"
+ HADOOP_OPTS="${HADOOP_OPTS} ${!uvar}"
+ return 0
+ fi
+}
+
+## @description Add custom (program)_(command)_SECURE_EXTRA_OPTS to HADOOP_OPTS.
+## @description This *does not* handle the pre-3.x deprecated cases
+## @audience public
+## @stability stable
+## @replaceable yes
+## @param program
+## @param subcommand
+## @return will exit on failure conditions
+function hadoop_subcommand_secure_opts
+{
+ declare program=$1
+ declare command=$2
+ declare uvar
+ declare uprogram
+ declare ucommand
+
+ if [[ -z "${program}" || -z "${command}" ]]; then
+ return 1
+ fi
+
+ # HDFS_DATANODE_SECURE_EXTRA_OPTS
+ # HDFS_NFS3_SECURE_EXTRA_OPTS
+ # ...
+ uvar=$(hadoop_build_custom_subcmd_var "${program}" "${command}" SECURE_EXTRA_OPTS)
+
+ if [[ -n ${!uvar} ]]; then
+ hadoop_debug "Appending ${uvar} onto HADOOP_OPTS"
+ HADOOP_OPTS="${HADOOP_OPTS} ${!uvar}"
+ return 0
+ fi
+}
+
+## @description Perform the 'hadoop classpath', etc subcommand with the given
+## @description parameters
+## @audience private
+## @stability evolving
+## @replaceable yes
+## @param [parameters]
+## @return will print & exit with no params
+function hadoop_do_classpath_subcommand
+{
+ if [[ "$#" -gt 1 ]]; then
+ eval "$1"=org.apache.hadoop.util.Classpath
+ else
+ hadoop_finalize
+ echo "${CLASSPATH}"
+ exit 0
+ fi
+}
+
+## @description generic shell script option parser. sets
+## @description HADOOP_PARSE_COUNTER to set number the
+## @description caller should shift
+## @audience private
+## @stability evolving
+## @replaceable yes
+## @param [parameters, typically "$@"]
+function hadoop_parse_args
+{
+ HADOOP_DAEMON_MODE="default"
+ HADOOP_PARSE_COUNTER=0
+
+ # not all of the options supported here are supported by all commands
+ # however these are:
+ hadoop_add_option "--config dir" "Hadoop config directory"
+ hadoop_add_option "--debug" "turn on shell script debug mode"
+ hadoop_add_option "--help" "usage information"
+
+ while true; do
+ hadoop_debug "hadoop_parse_args: processing $1"
+ case $1 in
+ --buildpaths)
+ HADOOP_ENABLE_BUILD_PATHS=true
+ shift
+ ((HADOOP_PARSE_COUNTER=HADOOP_PARSE_COUNTER+1))
+ ;;
+ --config)
+ shift
+ confdir=$1
+ shift
+ ((HADOOP_PARSE_COUNTER=HADOOP_PARSE_COUNTER+2))
+ if [[ -d "${confdir}" ]]; then
+ HADOOP_CONF_DIR="${confdir}"
+ elif [[ -z "${confdir}" ]]; then
+ hadoop_error "ERROR: No parameter provided for --config "
+ hadoop_exit_with_usage 1
+ else
+ hadoop_error "ERROR: Cannot find configuration directory \"${confdir}\""
+ hadoop_exit_with_usage 1
+ fi
+ ;;
+ --daemon)
+ shift
+ HADOOP_DAEMON_MODE=$1
+ shift
+ ((HADOOP_PARSE_COUNTER=HADOOP_PARSE_COUNTER+2))
+ if [[ -z "${HADOOP_DAEMON_MODE}" || \
+ ! "${HADOOP_DAEMON_MODE}" =~ ^st(art|op|atus)$ ]]; then
+ hadoop_error "ERROR: --daemon must be followed by either \"start\", \"stop\", or \"status\"."
+ hadoop_exit_with_usage 1
+ fi
+ ;;
+ --debug)
+ shift
+ HADOOP_SHELL_SCRIPT_DEBUG=true
+ ((HADOOP_PARSE_COUNTER=HADOOP_PARSE_COUNTER+1))
+ ;;
+ --help|-help|-h|help|--h|--\?|-\?|\?)
+ hadoop_exit_with_usage 0
+ ;;
+ --hostnames)
+ shift
+ HADOOP_WORKER_NAMES="$1"
+ shift
+ ((HADOOP_PARSE_COUNTER=HADOOP_PARSE_COUNTER+2))
+ ;;
+ --hosts)
+ shift
+ hadoop_populate_workers_file "$1"
+ shift
+ ((HADOOP_PARSE_COUNTER=HADOOP_PARSE_COUNTER+2))
+ ;;
+ --loglevel)
+ shift
+ # shellcheck disable=SC2034
+ HADOOP_LOGLEVEL="$1"
+ shift
+ ((HADOOP_PARSE_COUNTER=HADOOP_PARSE_COUNTER+2))
+ ;;
+ --reexec)
+ shift
+ if [[ "${HADOOP_REEXECED_CMD}" = true ]]; then
+ hadoop_error "ERROR: re-exec fork bomb prevention: --reexec already called"
+ exit 1
+ fi
+ HADOOP_REEXECED_CMD=true
+ ((HADOOP_PARSE_COUNTER=HADOOP_PARSE_COUNTER+1))
+ ;;
+ --workers)
+ shift
+ # shellcheck disable=SC2034
+ HADOOP_WORKER_MODE=true
+ ((HADOOP_PARSE_COUNTER=HADOOP_PARSE_COUNTER+1))
+ ;;
+ *)
+ break
+ ;;
+ esac
+ done
+
+ hadoop_debug "hadoop_parse: asking caller to skip ${HADOOP_PARSE_COUNTER}"
+}
+
+## @description Handle subcommands from main program entries
+## @audience private
+## @stability evolving
+## @replaceable yes
+function hadoop_generic_java_subcmd_handler
+{
+ declare priv_outfile
+ declare priv_errfile
+ declare priv_pidfile
+ declare daemon_outfile
+ declare daemon_pidfile
+ declare secureuser
+
+ # The default/expected way to determine if a daemon is going to run in secure
+ # mode is defined by hadoop_detect_priv_subcmd. If this returns true
+ # then setup the secure user var and tell the world we're in secure mode
+
+ if hadoop_detect_priv_subcmd "${HADOOP_SHELL_EXECNAME}" "${HADOOP_SUBCMD}"; then
+ HADOOP_SUBCMD_SECURESERVICE=true
+ secureuser=$(hadoop_build_custom_subcmd_var "${HADOOP_SHELL_EXECNAME}" "${HADOOP_SUBCMD}" SECURE_USER)
+
+ if ! hadoop_verify_user_resolves "${secureuser}"; then
+ hadoop_error "ERROR: User defined in ${secureuser} (${!secureuser}) does not exist. Aborting."
+ exit 1
+ fi
+
+ HADOOP_SECURE_USER="${!secureuser}"
+ fi
+
+ # check if we're running in secure mode.
+ # breaking this up from the above lets 3rd parties
+ # do things a bit different
+ # secure services require some extra setup
+ # if yes, then we need to define all of the priv and daemon stuff
+ # if not, then we just need to define daemon stuff.
+ # note the daemon vars are purposefully different between the two
+
+ if [[ "${HADOOP_SUBCMD_SECURESERVICE}" = true ]]; then
+
+ hadoop_subcommand_secure_opts "${HADOOP_SHELL_EXECNAME}" "${HADOOP_SUBCMD}"
+
+ hadoop_verify_secure_prereq
+ hadoop_setup_secure_service
+ priv_outfile="${HADOOP_LOG_DIR}/privileged-${HADOOP_IDENT_STRING}-${HADOOP_SUBCMD}-${HOSTNAME}.out"
+ priv_errfile="${HADOOP_LOG_DIR}/privileged-${HADOOP_IDENT_STRING}-${HADOOP_SUBCMD}-${HOSTNAME}.err"
+ priv_pidfile="${HADOOP_PID_DIR}/privileged-${HADOOP_IDENT_STRING}-${HADOOP_SUBCMD}.pid"
+ daemon_outfile="${HADOOP_LOG_DIR}/hadoop-${HADOOP_SECURE_USER}-${HADOOP_IDENT_STRING}-${HADOOP_SUBCMD}-${HOSTNAME}.out"
+ daemon_pidfile="${HADOOP_PID_DIR}/hadoop-${HADOOP_SECURE_USER}-${HADOOP_IDENT_STRING}-${HADOOP_SUBCMD}.pid"
+ else
+ daemon_outfile="${HADOOP_LOG_DIR}/hadoop-${HADOOP_IDENT_STRING}-${HADOOP_SUBCMD}-${HOSTNAME}.out"
+ daemon_pidfile="${HADOOP_PID_DIR}/hadoop-${HADOOP_IDENT_STRING}-${HADOOP_SUBCMD}.pid"
+ fi
+
+ # are we actually in daemon mode?
+ # if yes, use the daemon logger and the appropriate log file.
+ if [[ "${HADOOP_DAEMON_MODE}" != "default" ]]; then
+ HADOOP_ROOT_LOGGER="${HADOOP_DAEMON_ROOT_LOGGER}"
+ if [[ "${HADOOP_SUBCMD_SECURESERVICE}" = true ]]; then
+ HADOOP_LOGFILE="hadoop-${HADOOP_SECURE_USER}-${HADOOP_IDENT_STRING}-${HADOOP_SUBCMD}-${HOSTNAME}.log"
+ else
+ HADOOP_LOGFILE="hadoop-${HADOOP_IDENT_STRING}-${HADOOP_SUBCMD}-${HOSTNAME}.log"
+ fi
+ fi
+
+ # finish defining the environment: system properties, env vars, class paths, etc.
+ hadoop_finalize
+
+ # do the hard work of launching a daemon or just executing our interactive
+ # java class
+ if [[ "${HADOOP_SUBCMD_SUPPORTDAEMONIZATION}" = true ]]; then
+ if [[ "${HADOOP_SUBCMD_SECURESERVICE}" = true ]]; then
+ hadoop_secure_daemon_handler \
+ "${HADOOP_DAEMON_MODE}" \
+ "${HADOOP_SUBCMD}" \
+ "${HADOOP_SECURE_CLASSNAME}" \
+ "${daemon_pidfile}" \
+ "${daemon_outfile}" \
+ "${priv_pidfile}" \
+ "${priv_outfile}" \
+ "${priv_errfile}" \
+ "${HADOOP_SUBCMD_ARGS[@]}"
+ else
+ hadoop_daemon_handler \
+ "${HADOOP_DAEMON_MODE}" \
+ "${HADOOP_SUBCMD}" \
+ "${HADOOP_CLASSNAME}" \
+ "${daemon_pidfile}" \
+ "${daemon_outfile}" \
+ "${HADOOP_SUBCMD_ARGS[@]}"
+ fi
+ exit $?
+ else
+ hadoop_java_exec "${HADOOP_SUBCMD}" "${HADOOP_CLASSNAME}" "${HADOOP_SUBCMD_ARGS[@]}"
+ fi
+}
diff --git a/hadoop-hdds/common/src/main/bin/workers.sh b/hadoop-hdds/common/src/main/bin/workers.sh
new file mode 100755
index 0000000000000..05bc5fd8f0fe0
--- /dev/null
+++ b/hadoop-hdds/common/src/main/bin/workers.sh
@@ -0,0 +1,59 @@
+#!/usr/bin/env bash
+
+# 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.
+
+
+# Run a shell command on all worker hosts.
+#
+# Environment Variables
+#
+# HADOOP_WORKERS File naming remote hosts.
+# Default is ${HADOOP_CONF_DIR}/workers.
+# HADOOP_CONF_DIR Alternate conf dir. Default is ${HADOOP_HOME}/conf.
+# HADOOP_WORKER_SLEEP Seconds to sleep between spawning remote commands.
+# HADOOP_SSH_OPTS Options passed to ssh when running remote commands.
+##
+
+function hadoop_usage
+{
+ echo "Usage: workers.sh [--config confdir] command..."
+}
+
+# let's locate libexec...
+if [[ -n "${HADOOP_HOME}" ]]; then
+ HADOOP_DEFAULT_LIBEXEC_DIR="${HADOOP_HOME}/libexec"
+else
+ this="${BASH_SOURCE-$0}"
+ bin=$(cd -P -- "$(dirname -- "${this}")" >/dev/null && pwd -P)
+ HADOOP_DEFAULT_LIBEXEC_DIR="${bin}/../libexec"
+fi
+
+HADOOP_LIBEXEC_DIR="${HADOOP_LIBEXEC_DIR:-$HADOOP_DEFAULT_LIBEXEC_DIR}"
+# shellcheck disable=SC2034
+HADOOP_NEW_CONFIG=true
+if [[ -f "${HADOOP_LIBEXEC_DIR}/hadoop-config.sh" ]]; then
+ . "${HADOOP_LIBEXEC_DIR}/hadoop-config.sh"
+else
+ echo "ERROR: Cannot execute ${HADOOP_LIBEXEC_DIR}/hadoop-config.sh." 2>&1
+ exit 1
+fi
+
+# if no args specified, show usage
+if [[ $# -le 0 ]]; then
+ hadoop_exit_with_usage 1
+fi
+
+hadoop_connect_to_hosts "$@"
diff --git a/hadoop-hdds/common/src/main/conf/core-site.xml b/hadoop-hdds/common/src/main/conf/core-site.xml
new file mode 100644
index 0000000000000..d2ddf893e49eb
--- /dev/null
+++ b/hadoop-hdds/common/src/main/conf/core-site.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
diff --git a/hadoop-hdds/common/src/main/conf/hadoop-env.cmd b/hadoop-hdds/common/src/main/conf/hadoop-env.cmd
new file mode 100644
index 0000000000000..971869597f529
--- /dev/null
+++ b/hadoop-hdds/common/src/main/conf/hadoop-env.cmd
@@ -0,0 +1,90 @@
+@echo off
+@rem Licensed to the Apache Software Foundation (ASF) under one or more
+@rem contributor license agreements. See the NOTICE file distributed with
+@rem this work for additional information regarding copyright ownership.
+@rem The ASF licenses this file to You under the Apache License, Version 2.0
+@rem (the "License"); you may not use this file except in compliance with
+@rem the License. You may obtain a copy of the License at
+@rem
+@rem http://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+
+@rem Set Hadoop-specific environment variables here.
+
+@rem The only required environment variable is JAVA_HOME. All others are
+@rem optional. When running a distributed configuration it is best to
+@rem set JAVA_HOME in this file, so that it is correctly defined on
+@rem remote nodes.
+
+@rem The java implementation to use. Required.
+set JAVA_HOME=%JAVA_HOME%
+
+@rem The jsvc implementation to use. Jsvc is required to run secure datanodes.
+@rem set JSVC_HOME=%JSVC_HOME%
+
+@rem set HADOOP_CONF_DIR=
+
+@rem Extra Java CLASSPATH elements. Automatically insert capacity-scheduler.
+if exist %HADOOP_HOME%\contrib\capacity-scheduler (
+ if not defined HADOOP_CLASSPATH (
+ set HADOOP_CLASSPATH=%HADOOP_HOME%\contrib\capacity-scheduler\*.jar
+ ) else (
+ set HADOOP_CLASSPATH=%HADOOP_CLASSPATH%;%HADOOP_HOME%\contrib\capacity-scheduler\*.jar
+ )
+)
+
+@rem The maximum amount of heap to use, in MB. Default is 1000.
+@rem set HADOOP_HEAPSIZE=
+@rem set HADOOP_NAMENODE_INIT_HEAPSIZE=""
+
+@rem Extra Java runtime options. Empty by default.
+@rem set HADOOP_OPTS=%HADOOP_OPTS% -Djava.net.preferIPv4Stack=true
+
+@rem Command specific options appended to HADOOP_OPTS when specified
+if not defined HADOOP_SECURITY_LOGGER (
+ set HADOOP_SECURITY_LOGGER=INFO,RFAS
+)
+if not defined HDFS_AUDIT_LOGGER (
+ set HDFS_AUDIT_LOGGER=INFO,NullAppender
+)
+
+set HADOOP_NAMENODE_OPTS=-Dhadoop.security.logger=%HADOOP_SECURITY_LOGGER% -Dhdfs.audit.logger=%HDFS_AUDIT_LOGGER% %HADOOP_NAMENODE_OPTS%
+set HADOOP_DATANODE_OPTS=-Dhadoop.security.logger=ERROR,RFAS %HADOOP_DATANODE_OPTS%
+set HADOOP_SECONDARYNAMENODE_OPTS=-Dhadoop.security.logger=%HADOOP_SECURITY_LOGGER% -Dhdfs.audit.logger=%HDFS_AUDIT_LOGGER% %HADOOP_SECONDARYNAMENODE_OPTS%
+
+@rem The following applies to multiple commands (fs, dfs, fsck, distcp etc)
+set HADOOP_CLIENT_OPTS=-Xmx512m %HADOOP_CLIENT_OPTS%
+@rem set HADOOP_JAVA_PLATFORM_OPTS="-XX:-UsePerfData %HADOOP_JAVA_PLATFORM_OPTS%"
+
+@rem On secure datanodes, user to run the datanode as after dropping privileges
+set HADOOP_SECURE_DN_USER=%HADOOP_SECURE_DN_USER%
+
+@rem Where log files are stored. %HADOOP_HOME%/logs by default.
+@rem set HADOOP_LOG_DIR=%HADOOP_LOG_DIR%\%USERNAME%
+
+@rem Where log files are stored in the secure data environment.
+set HADOOP_SECURE_DN_LOG_DIR=%HADOOP_LOG_DIR%\%HADOOP_HDFS_USER%
+
+@rem
+@rem Router-based HDFS Federation specific parameters
+@rem Specify the JVM options to be used when starting the RBF Routers.
+@rem These options will be appended to the options specified as HADOOP_OPTS
+@rem and therefore may override any similar flags set in HADOOP_OPTS
+@rem
+@rem set HADOOP_DFSROUTER_OPTS=""
+@rem
+
+@rem The directory where pid files are stored. /tmp by default.
+@rem NOTE: this should be set to a directory that can only be written to by
+@rem the user that will run the hadoop daemons. Otherwise there is the
+@rem potential for a symlink attack.
+set HADOOP_PID_DIR=%HADOOP_PID_DIR%
+set HADOOP_SECURE_DN_PID_DIR=%HADOOP_PID_DIR%
+
+@rem A string representing this instance of hadoop. %USERNAME% by default.
+set HADOOP_IDENT_STRING=%USERNAME%
diff --git a/hadoop-hdds/common/src/main/conf/hadoop-env.sh b/hadoop-hdds/common/src/main/conf/hadoop-env.sh
new file mode 100644
index 0000000000000..e43cd95b047ee
--- /dev/null
+++ b/hadoop-hdds/common/src/main/conf/hadoop-env.sh
@@ -0,0 +1,439 @@
+#
+# 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.
+
+# Set Hadoop-specific environment variables here.
+
+##
+## THIS FILE ACTS AS THE MASTER FILE FOR ALL HADOOP PROJECTS.
+## SETTINGS HERE WILL BE READ BY ALL HADOOP COMMANDS. THEREFORE,
+## ONE CAN USE THIS FILE TO SET YARN, HDFS, AND MAPREDUCE
+## CONFIGURATION OPTIONS INSTEAD OF xxx-env.sh.
+##
+## Precedence rules:
+##
+## {yarn-env.sh|hdfs-env.sh} > hadoop-env.sh > hard-coded defaults
+##
+## {YARN_xyz|HDFS_xyz} > HADOOP_xyz > hard-coded defaults
+##
+
+# Many of the options here are built from the perspective that users
+# may want to provide OVERWRITING values on the command line.
+# For example:
+#
+# JAVA_HOME=/usr/java/testing hdfs dfs -ls
+#
+# Therefore, the vast majority (BUT NOT ALL!) of these defaults
+# are configured for substitution and not append. If append
+# is preferable, modify this file accordingly.
+
+###
+# Generic settings for HADOOP
+###
+
+# Technically, the only required environment variable is JAVA_HOME.
+# All others are optional. However, the defaults are probably not
+# preferred. Many sites configure these options outside of Hadoop,
+# such as in /etc/profile.d
+
+# The java implementation to use. By default, this environment
+# variable is REQUIRED on ALL platforms except OS X!
+# export JAVA_HOME=
+
+# Location of Hadoop. By default, Hadoop will attempt to determine
+# this location based upon its execution path.
+# export HADOOP_HOME=
+
+# Location of Hadoop's configuration information. i.e., where this
+# file is living. If this is not defined, Hadoop will attempt to
+# locate it based upon its execution path.
+#
+# NOTE: It is recommend that this variable not be set here but in
+# /etc/profile.d or equivalent. Some options (such as
+# --config) may react strangely otherwise.
+#
+# export HADOOP_CONF_DIR=${HADOOP_HOME}/etc/hadoop
+
+# The maximum amount of heap to use (Java -Xmx). If no unit
+# is provided, it will be converted to MB. Daemons will
+# prefer any Xmx setting in their respective _OPT variable.
+# There is no default; the JVM will autoscale based upon machine
+# memory size.
+# export HADOOP_HEAPSIZE_MAX=
+
+# The minimum amount of heap to use (Java -Xms). If no unit
+# is provided, it will be converted to MB. Daemons will
+# prefer any Xms setting in their respective _OPT variable.
+# There is no default; the JVM will autoscale based upon machine
+# memory size.
+# export HADOOP_HEAPSIZE_MIN=
+
+# Enable extra debugging of Hadoop's JAAS binding, used to set up
+# Kerberos security.
+# export HADOOP_JAAS_DEBUG=true
+
+# Extra Java runtime options for all Hadoop commands. We don't support
+# IPv6 yet/still, so by default the preference is set to IPv4.
+# export HADOOP_OPTS="-Djava.net.preferIPv4Stack=true"
+# For Kerberos debugging, an extended option set logs more information
+# export HADOOP_OPTS="-Djava.net.preferIPv4Stack=true -Dsun.security.krb5.debug=true -Dsun.security.spnego.debug"
+
+# Some parts of the shell code may do special things dependent upon
+# the operating system. We have to set this here. See the next
+# section as to why....
+export HADOOP_OS_TYPE=${HADOOP_OS_TYPE:-$(uname -s)}
+
+# Extra Java runtime options for some Hadoop commands
+# and clients (i.e., hdfs dfs -blah). These get appended to HADOOP_OPTS for
+# such commands. In most cases, # this should be left empty and
+# let users supply it on the command line.
+# export HADOOP_CLIENT_OPTS=""
+
+#
+# A note about classpaths.
+#
+# By default, Apache Hadoop overrides Java's CLASSPATH
+# environment variable. It is configured such
+# that it starts out blank with new entries added after passing
+# a series of checks (file/dir exists, not already listed aka
+# de-deduplication). During de-deduplication, wildcards and/or
+# directories are *NOT* expanded to keep it simple. Therefore,
+# if the computed classpath has two specific mentions of
+# awesome-methods-1.0.jar, only the first one added will be seen.
+# If two directories are in the classpath that both contain
+# awesome-methods-1.0.jar, then Java will pick up both versions.
+
+# An additional, custom CLASSPATH. Site-wide configs should be
+# handled via the shellprofile functionality, utilizing the
+# hadoop_add_classpath function for greater control and much
+# harder for apps/end-users to accidentally override.
+# Similarly, end users should utilize ${HOME}/.hadooprc .
+# This variable should ideally only be used as a short-cut,
+# interactive way for temporary additions on the command line.
+# export HADOOP_CLASSPATH="/some/cool/path/on/your/machine"
+
+# Should HADOOP_CLASSPATH be first in the official CLASSPATH?
+# export HADOOP_USER_CLASSPATH_FIRST="yes"
+
+# If HADOOP_USE_CLIENT_CLASSLOADER is set, the classpath along
+# with the main jar are handled by a separate isolated
+# client classloader when 'hadoop jar', 'yarn jar', or 'mapred job'
+# is utilized. If it is set, HADOOP_CLASSPATH and
+# HADOOP_USER_CLASSPATH_FIRST are ignored.
+# export HADOOP_USE_CLIENT_CLASSLOADER=true
+
+# HADOOP_CLIENT_CLASSLOADER_SYSTEM_CLASSES overrides the default definition of
+# system classes for the client classloader when HADOOP_USE_CLIENT_CLASSLOADER
+# is enabled. Names ending in '.' (period) are treated as package names, and
+# names starting with a '-' are treated as negative matches. For example,
+# export HADOOP_CLIENT_CLASSLOADER_SYSTEM_CLASSES="-org.apache.hadoop.UserClass,java.,javax.,org.apache.hadoop."
+
+# Enable optional, bundled Hadoop features
+# This is a comma delimited list. It may NOT be overridden via .hadooprc
+# Entries may be added/removed as needed.
+# export HADOOP_OPTIONAL_TOOLS="@@@HADOOP_OPTIONAL_TOOLS@@@"
+
+###
+# Options for remote shell connectivity
+###
+
+# There are some optional components of hadoop that allow for
+# command and control of remote hosts. For example,
+# start-dfs.sh will attempt to bring up all NNs, DNS, etc.
+
+# Options to pass to SSH when one of the "log into a host and
+# start/stop daemons" scripts is executed
+# export HADOOP_SSH_OPTS="-o BatchMode=yes -o StrictHostKeyChecking=no -o ConnectTimeout=10s"
+
+# The built-in ssh handler will limit itself to 10 simultaneous connections.
+# For pdsh users, this sets the fanout size ( -f )
+# Change this to increase/decrease as necessary.
+# export HADOOP_SSH_PARALLEL=10
+
+# Filename which contains all of the hosts for any remote execution
+# helper scripts # such as workers.sh, start-dfs.sh, etc.
+# export HADOOP_WORKERS="${HADOOP_CONF_DIR}/workers"
+
+###
+# Options for all daemons
+###
+#
+
+#
+# Many options may also be specified as Java properties. It is
+# very common, and in many cases, desirable, to hard-set these
+# in daemon _OPTS variables. Where applicable, the appropriate
+# Java property is also identified. Note that many are re-used
+# or set differently in certain contexts (e.g., secure vs
+# non-secure)
+#
+
+# Where (primarily) daemon log files are stored.
+# ${HADOOP_HOME}/logs by default.
+# Java property: hadoop.log.dir
+# export HADOOP_LOG_DIR=${HADOOP_HOME}/logs
+
+# A string representing this instance of hadoop. $USER by default.
+# This is used in writing log and pid files, so keep that in mind!
+# Java property: hadoop.id.str
+# export HADOOP_IDENT_STRING=$USER
+
+# How many seconds to pause after stopping a daemon
+# export HADOOP_STOP_TIMEOUT=5
+
+# Where pid files are stored. /tmp by default.
+# export HADOOP_PID_DIR=/tmp
+
+# Default log4j setting for interactive commands
+# Java property: hadoop.root.logger
+# export HADOOP_ROOT_LOGGER=INFO,console
+
+# Default log4j setting for daemons spawned explicitly by
+# --daemon option of hadoop, hdfs, mapred and yarn command.
+# Java property: hadoop.root.logger
+# export HADOOP_DAEMON_ROOT_LOGGER=INFO,RFA
+
+# Default log level and output location for security-related messages.
+# You will almost certainly want to change this on a per-daemon basis via
+# the Java property (i.e., -Dhadoop.security.logger=foo). (Note that the
+# defaults for the NN and 2NN override this by default.)
+# Java property: hadoop.security.logger
+# export HADOOP_SECURITY_LOGGER=INFO,NullAppender
+
+# Default process priority level
+# Note that sub-processes will also run at this level!
+# export HADOOP_NICENESS=0
+
+# Default name for the service level authorization file
+# Java property: hadoop.policy.file
+# export HADOOP_POLICYFILE="hadoop-policy.xml"
+
+#
+# NOTE: this is not used by default! <-----
+# You can define variables right here and then re-use them later on.
+# For example, it is common to use the same garbage collection settings
+# for all the daemons. So one could define:
+#
+# export HADOOP_GC_SETTINGS="-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps"
+#
+# .. and then use it as per the b option under the namenode.
+
+###
+# Secure/privileged execution
+###
+
+#
+# Out of the box, Hadoop uses jsvc from Apache Commons to launch daemons
+# on privileged ports. This functionality can be replaced by providing
+# custom functions. See hadoop-functions.sh for more information.
+#
+
+# The jsvc implementation to use. Jsvc is required to run secure datanodes
+# that bind to privileged ports to provide authentication of data transfer
+# protocol. Jsvc is not required if SASL is configured for authentication of
+# data transfer protocol using non-privileged ports.
+# export JSVC_HOME=/usr/bin
+
+#
+# This directory contains pids for secure and privileged processes.
+#export HADOOP_SECURE_PID_DIR=${HADOOP_PID_DIR}
+
+#
+# This directory contains the logs for secure and privileged processes.
+# Java property: hadoop.log.dir
+# export HADOOP_SECURE_LOG=${HADOOP_LOG_DIR}
+
+#
+# When running a secure daemon, the default value of HADOOP_IDENT_STRING
+# ends up being a bit bogus. Therefore, by default, the code will
+# replace HADOOP_IDENT_STRING with HADOOP_xx_SECURE_USER. If one wants
+# to keep HADOOP_IDENT_STRING untouched, then uncomment this line.
+# export HADOOP_SECURE_IDENT_PRESERVE="true"
+
+###
+# NameNode specific parameters
+###
+
+# Default log level and output location for file system related change
+# messages. For non-namenode daemons, the Java property must be set in
+# the appropriate _OPTS if one wants something other than INFO,NullAppender
+# Java property: hdfs.audit.logger
+# export HDFS_AUDIT_LOGGER=INFO,NullAppender
+
+# Specify the JVM options to be used when starting the NameNode.
+# These options will be appended to the options specified as HADOOP_OPTS
+# and therefore may override any similar flags set in HADOOP_OPTS
+#
+# a) Set JMX options
+# export HDFS_NAMENODE_OPTS="-Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=1026"
+#
+# b) Set garbage collection logs
+# export HDFS_NAMENODE_OPTS="${HADOOP_GC_SETTINGS} -Xloggc:${HADOOP_LOG_DIR}/gc-rm.log-$(date +'%Y%m%d%H%M')"
+#
+# c) ... or set them directly
+# export HDFS_NAMENODE_OPTS="-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:${HADOOP_LOG_DIR}/gc-rm.log-$(date +'%Y%m%d%H%M')"
+
+# this is the default:
+# export HDFS_NAMENODE_OPTS="-Dhadoop.security.logger=INFO,RFAS"
+
+###
+# SecondaryNameNode specific parameters
+###
+# Specify the JVM options to be used when starting the SecondaryNameNode.
+# These options will be appended to the options specified as HADOOP_OPTS
+# and therefore may override any similar flags set in HADOOP_OPTS
+#
+# This is the default:
+# export HDFS_SECONDARYNAMENODE_OPTS="-Dhadoop.security.logger=INFO,RFAS"
+
+###
+# DataNode specific parameters
+###
+# Specify the JVM options to be used when starting the DataNode.
+# These options will be appended to the options specified as HADOOP_OPTS
+# and therefore may override any similar flags set in HADOOP_OPTS
+#
+# This is the default:
+# export HDFS_DATANODE_OPTS="-Dhadoop.security.logger=ERROR,RFAS"
+
+# On secure datanodes, user to run the datanode as after dropping privileges.
+# This **MUST** be uncommented to enable secure HDFS if using privileged ports
+# to provide authentication of data transfer protocol. This **MUST NOT** be
+# defined if SASL is configured for authentication of data transfer protocol
+# using non-privileged ports.
+# This will replace the hadoop.id.str Java property in secure mode.
+# export HDFS_DATANODE_SECURE_USER=hdfs
+
+# Supplemental options for secure datanodes
+# By default, Hadoop uses jsvc which needs to know to launch a
+# server jvm.
+# export HDFS_DATANODE_SECURE_EXTRA_OPTS="-jvm server"
+
+###
+# NFS3 Gateway specific parameters
+###
+# Specify the JVM options to be used when starting the NFS3 Gateway.
+# These options will be appended to the options specified as HADOOP_OPTS
+# and therefore may override any similar flags set in HADOOP_OPTS
+#
+# export HDFS_NFS3_OPTS=""
+
+# Specify the JVM options to be used when starting the Hadoop portmapper.
+# These options will be appended to the options specified as HADOOP_OPTS
+# and therefore may override any similar flags set in HADOOP_OPTS
+#
+# export HDFS_PORTMAP_OPTS="-Xmx512m"
+
+# Supplemental options for priviliged gateways
+# By default, Hadoop uses jsvc which needs to know to launch a
+# server jvm.
+# export HDFS_NFS3_SECURE_EXTRA_OPTS="-jvm server"
+
+# On privileged gateways, user to run the gateway as after dropping privileges
+# This will replace the hadoop.id.str Java property in secure mode.
+# export HDFS_NFS3_SECURE_USER=nfsserver
+
+###
+# ZKFailoverController specific parameters
+###
+# Specify the JVM options to be used when starting the ZKFailoverController.
+# These options will be appended to the options specified as HADOOP_OPTS
+# and therefore may override any similar flags set in HADOOP_OPTS
+#
+# export HDFS_ZKFC_OPTS=""
+
+###
+# QuorumJournalNode specific parameters
+###
+# Specify the JVM options to be used when starting the QuorumJournalNode.
+# These options will be appended to the options specified as HADOOP_OPTS
+# and therefore may override any similar flags set in HADOOP_OPTS
+#
+# export HDFS_JOURNALNODE_OPTS=""
+
+###
+# HDFS Balancer specific parameters
+###
+# Specify the JVM options to be used when starting the HDFS Balancer.
+# These options will be appended to the options specified as HADOOP_OPTS
+# and therefore may override any similar flags set in HADOOP_OPTS
+#
+# export HDFS_BALANCER_OPTS=""
+
+###
+# HDFS Mover specific parameters
+###
+# Specify the JVM options to be used when starting the HDFS Mover.
+# These options will be appended to the options specified as HADOOP_OPTS
+# and therefore may override any similar flags set in HADOOP_OPTS
+#
+# export HDFS_MOVER_OPTS=""
+
+###
+# Router-based HDFS Federation specific parameters
+# Specify the JVM options to be used when starting the RBF Routers.
+# These options will be appended to the options specified as HADOOP_OPTS
+# and therefore may override any similar flags set in HADOOP_OPTS
+#
+# export HDFS_DFSROUTER_OPTS=""
+
+###
+# Ozone Manager specific parameters
+###
+# Specify the JVM options to be used when starting the Ozone Manager.
+# These options will be appended to the options specified as HADOOP_OPTS
+# and therefore may override any similar flags set in HADOOP_OPTS
+#
+# export HDFS_OM_OPTS=""
+
+###
+# HDFS StorageContainerManager specific parameters
+###
+# Specify the JVM options to be used when starting the HDFS Storage Container Manager.
+# These options will be appended to the options specified as HADOOP_OPTS
+# and therefore may override any similar flags set in HADOOP_OPTS
+#
+# export HDFS_STORAGECONTAINERMANAGER_OPTS=""
+
+###
+# Advanced Users Only!
+###
+
+#
+# When building Hadoop, one can add the class paths to the commands
+# via this special env var:
+# export HADOOP_ENABLE_BUILD_PATHS="true"
+
+#
+# To prevent accidents, shell commands be (superficially) locked
+# to only allow certain users to execute certain subcommands.
+# It uses the format of (command)_(subcommand)_USER.
+#
+# For example, to limit who can execute the namenode command,
+# export HDFS_NAMENODE_USER=hdfs
+
+
+###
+# Registry DNS specific parameters
+###
+# For privileged registry DNS, user to run as after dropping privileges
+# This will replace the hadoop.id.str Java property in secure mode.
+# export HADOOP_REGISTRYDNS_SECURE_USER=yarn
+
+# Supplemental options for privileged registry DNS
+# By default, Hadoop uses jsvc which needs to know to launch a
+# server jvm.
+# export HADOOP_REGISTRYDNS_SECURE_EXTRA_OPTS="-jvm server"
diff --git a/hadoop-hdds/common/src/main/conf/hadoop-metrics2.properties b/hadoop-hdds/common/src/main/conf/hadoop-metrics2.properties
new file mode 100644
index 0000000000000..f67bf8e4c5b1f
--- /dev/null
+++ b/hadoop-hdds/common/src/main/conf/hadoop-metrics2.properties
@@ -0,0 +1,99 @@
+# 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.
+
+# syntax: [prefix].[source|sink].[instance].[options]
+# See javadoc of package-info.java for org.apache.hadoop.metrics2 for details
+
+*.sink.file.class=org.apache.hadoop.metrics2.sink.FileSink
+# default sampling period, in seconds
+*.period=10
+
+# The namenode-metrics.out will contain metrics from all context
+#namenode.sink.file.filename=namenode-metrics.out
+# Specifying a special sampling period for namenode:
+#namenode.sink.*.period=8
+
+#datanode.sink.file.filename=datanode-metrics.out
+
+#resourcemanager.sink.file.filename=resourcemanager-metrics.out
+
+#nodemanager.sink.file.filename=nodemanager-metrics.out
+
+#mrappmaster.sink.file.filename=mrappmaster-metrics.out
+
+#jobhistoryserver.sink.file.filename=jobhistoryserver-metrics.out
+
+# the following example split metrics of different
+# context to different sinks (in this case files)
+#nodemanager.sink.file_jvm.class=org.apache.hadoop.metrics2.sink.FileSink
+#nodemanager.sink.file_jvm.context=jvm
+#nodemanager.sink.file_jvm.filename=nodemanager-jvm-metrics.out
+#nodemanager.sink.file_mapred.class=org.apache.hadoop.metrics2.sink.FileSink
+#nodemanager.sink.file_mapred.context=mapred
+#nodemanager.sink.file_mapred.filename=nodemanager-mapred-metrics.out
+
+#
+# Below are for sending metrics to Ganglia
+#
+# for Ganglia 3.0 support
+# *.sink.ganglia.class=org.apache.hadoop.metrics2.sink.ganglia.GangliaSink30
+#
+# for Ganglia 3.1 support
+# *.sink.ganglia.class=org.apache.hadoop.metrics2.sink.ganglia.GangliaSink31
+
+# *.sink.ganglia.period=10
+
+# default for supportsparse is false
+# *.sink.ganglia.supportsparse=true
+
+#*.sink.ganglia.slope=jvm.metrics.gcCount=zero,jvm.metrics.memHeapUsedM=both
+#*.sink.ganglia.dmax=jvm.metrics.threadsBlocked=70,jvm.metrics.memHeapUsedM=40
+
+# Tag values to use for the ganglia prefix. If not defined no tags are used.
+# If '*' all tags are used. If specifying multiple tags separate them with
+# commas. Note that the last segment of the property name is the context name.
+#
+# A typical use of tags is separating the metrics by the HDFS rpc port
+# and HDFS service rpc port.
+# For example:
+# With following HDFS configuration:
+# dfs.namenode.rpc-address is set as namenodeAddress:9110
+# dfs.namenode.servicerpc-address is set as namenodeAddress:9111
+# If no tags are used, following metric would be gathered:
+# rpc.rpc.NumOpenConnections
+# If using "*.sink.ganglia.tagsForPrefix.rpc=port",
+# following metrics would be gathered:
+# rpc.rpc.port=9110.NumOpenConnections
+# rpc.rpc.port=9111.NumOpenConnections
+#
+#*.sink.ganglia.tagsForPrefix.jvm=ProcessName
+#*.sink.ganglia.tagsForPrefix.dfs=HAState,IsOutOfSync
+#*.sink.ganglia.tagsForPrefix.rpc=port
+#*.sink.ganglia.tagsForPrefix.rpcdetailed=port
+#*.sink.ganglia.tagsForPrefix.metricssystem=*
+#*.sink.ganglia.tagsForPrefix.ugi=*
+#*.sink.ganglia.tagsForPrefix.mapred=
+
+#namenode.sink.ganglia.servers=yourgangliahost_1:8649,yourgangliahost_2:8649
+
+#datanode.sink.ganglia.servers=yourgangliahost_1:8649,yourgangliahost_2:8649
+
+#resourcemanager.sink.ganglia.servers=yourgangliahost_1:8649,yourgangliahost_2:8649
+
+#nodemanager.sink.ganglia.servers=yourgangliahost_1:8649,yourgangliahost_2:8649
+
+#mrappmaster.sink.ganglia.servers=yourgangliahost_1:8649,yourgangliahost_2:8649
+
+#jobhistoryserver.sink.ganglia.servers=yourgangliahost_1:8649,yourgangliahost_2:8649
diff --git a/hadoop-hdds/common/src/main/conf/hadoop-policy.xml b/hadoop-hdds/common/src/main/conf/hadoop-policy.xml
new file mode 100644
index 0000000000000..85e4975a78628
--- /dev/null
+++ b/hadoop-hdds/common/src/main/conf/hadoop-policy.xml
@@ -0,0 +1,275 @@
+
+
+
+
+
+
+
+
+ security.client.protocol.acl
+ *
+ ACL for ClientProtocol, which is used by user code
+ via the DistributedFileSystem.
+ The ACL is a comma-separated list of user and group names. The user and
+ group list is separated by a blank. For e.g. "alice,bob users,wheel".
+ A special value of "*" means all users are allowed.
+
+
+
+ security.client.datanode.protocol.acl
+ *
+ ACL for ClientDatanodeProtocol, the client-to-datanode protocol
+ for block recovery.
+ The ACL is a comma-separated list of user and group names. The user and
+ group list is separated by a blank. For e.g. "alice,bob users,wheel".
+ A special value of "*" means all users are allowed.
+
+
+
+ security.datanode.protocol.acl
+ *
+ ACL for DatanodeProtocol, which is used by datanodes to
+ communicate with the namenode.
+ The ACL is a comma-separated list of user and group names. The user and
+ group list is separated by a blank. For e.g. "alice,bob users,wheel".
+ A special value of "*" means all users are allowed.
+
+
+
+ security.inter.datanode.protocol.acl
+ *
+ ACL for InterDatanodeProtocol, the inter-datanode protocol
+ for updating generation timestamp.
+ The ACL is a comma-separated list of user and group names. The user and
+ group list is separated by a blank. For e.g. "alice,bob users,wheel".
+ A special value of "*" means all users are allowed.
+
+
+
+ security.namenode.protocol.acl
+ *
+ ACL for NamenodeProtocol, the protocol used by the secondary
+ namenode to communicate with the namenode.
+ The ACL is a comma-separated list of user and group names. The user and
+ group list is separated by a blank. For e.g. "alice,bob users,wheel".
+ A special value of "*" means all users are allowed.
+
+
+
+ security.admin.operations.protocol.acl
+ *
+ ACL for AdminOperationsProtocol. Used for admin commands.
+ The ACL is a comma-separated list of user and group names. The user and
+ group list is separated by a blank. For e.g. "alice,bob users,wheel".
+ A special value of "*" means all users are allowed.
+
+
+
+ security.refresh.user.mappings.protocol.acl
+ *
+ ACL for RefreshUserMappingsProtocol. Used to refresh
+ users mappings. The ACL is a comma-separated list of user and
+ group names. The user and group list is separated by a blank. For
+ e.g. "alice,bob users,wheel". A special value of "*" means all
+ users are allowed.
+
+
+
+ security.refresh.policy.protocol.acl
+ *
+ ACL for RefreshAuthorizationPolicyProtocol, used by the
+ dfsadmin and mradmin commands to refresh the security policy in-effect.
+ The ACL is a comma-separated list of user and group names. The user and
+ group list is separated by a blank. For e.g. "alice,bob users,wheel".
+ A special value of "*" means all users are allowed.
+
+
+
+ security.ha.service.protocol.acl
+ *
+ ACL for HAService protocol used by HAAdmin to manage the
+ active and stand-by states of namenode.
+
+
+
+ security.router.admin.protocol.acl
+ *
+ ACL for RouterAdmin Protocol. The ACL is a comma-separated
+ list of user and group names. The user and
+ group list is separated by a blank. For e.g. "alice,bob users,wheel".
+ A special value of "*" means all users are allowed.
+
+
+
+
+ security.zkfc.protocol.acl
+ *
+ ACL for access to the ZK Failover Controller
+
+
+
+
+ security.qjournal.service.protocol.acl
+ *
+ ACL for QJournalProtocol, used by the NN to communicate with
+ JNs when using the QuorumJournalManager for edit logs.
+
+
+
+ security.interqjournal.service.protocol.acl
+ *
+ ACL for InterQJournalProtocol, used by the JN to
+ communicate with other JN
+
+
+
+
+ security.mrhs.client.protocol.acl
+ *
+ ACL for HSClientProtocol, used by job clients to
+ communciate with the MR History Server job status etc.
+ The ACL is a comma-separated list of user and group names. The user and
+ group list is separated by a blank. For e.g. "alice,bob users,wheel".
+ A special value of "*" means all users are allowed.
+
+
+
+
+
+ security.resourcetracker.protocol.acl
+ *
+ ACL for ResourceTrackerProtocol, used by the
+ ResourceManager and NodeManager to communicate with each other.
+ The ACL is a comma-separated list of user and group names. The user and
+ group list is separated by a blank. For e.g. "alice,bob users,wheel".
+ A special value of "*" means all users are allowed.
+
+
+
+ security.resourcemanager-administration.protocol.acl
+ *
+ ACL for ResourceManagerAdministrationProtocol, for admin commands.
+ The ACL is a comma-separated list of user and group names. The user and
+ group list is separated by a blank. For e.g. "alice,bob users,wheel".
+ A special value of "*" means all users are allowed.
+
+
+
+ security.applicationclient.protocol.acl
+ *
+ ACL for ApplicationClientProtocol, used by the ResourceManager
+ and applications submission clients to communicate with each other.
+ The ACL is a comma-separated list of user and group names. The user and
+ group list is separated by a blank. For e.g. "alice,bob users,wheel".
+ A special value of "*" means all users are allowed.
+
+
+
+ security.applicationmaster.protocol.acl
+ *
+ ACL for ApplicationMasterProtocol, used by the ResourceManager
+ and ApplicationMasters to communicate with each other.
+ The ACL is a comma-separated list of user and group names. The user and
+ group list is separated by a blank. For e.g. "alice,bob users,wheel".
+ A special value of "*" means all users are allowed.
+
+
+
+ security.containermanagement.protocol.acl
+ *
+ ACL for ContainerManagementProtocol protocol, used by the NodeManager
+ and ApplicationMasters to communicate with each other.
+ The ACL is a comma-separated list of user and group names. The user and
+ group list is separated by a blank. For e.g. "alice,bob users,wheel".
+ A special value of "*" means all users are allowed.
+
+
+
+ security.resourcelocalizer.protocol.acl
+ *
+ ACL for ResourceLocalizer protocol, used by the NodeManager
+ and ResourceLocalizer to communicate with each other.
+ The ACL is a comma-separated list of user and group names. The user and
+ group list is separated by a blank. For e.g. "alice,bob users,wheel".
+ A special value of "*" means all users are allowed.
+
+
+
+ security.job.task.protocol.acl
+ *
+ ACL for TaskUmbilicalProtocol, used by the map and reduce
+ tasks to communicate with the parent tasktracker.
+ The ACL is a comma-separated list of user and group names. The user and
+ group list is separated by a blank. For e.g. "alice,bob users,wheel".
+ A special value of "*" means all users are allowed.
+
+
+
+ security.job.client.protocol.acl
+ *
+ ACL for MRClientProtocol, used by job clients to
+ communciate with the MR ApplicationMaster to query job status etc.
+ The ACL is a comma-separated list of user and group names. The user and
+ group list is separated by a blank. For e.g. "alice,bob users,wheel".
+ A special value of "*" means all users are allowed.
+
+
+
+ security.applicationhistory.protocol.acl
+ *
+ ACL for ApplicationHistoryProtocol, used by the timeline
+ server and the generic history service client to communicate with each other.
+ The ACL is a comma-separated list of user and group names. The user and
+ group list is separated by a blank. For e.g. "alice,bob users,wheel".
+ A special value of "*" means all users are allowed.
+
+
+
+ security.collector-nodemanager.protocol.acl
+ *
+ ACL for CollectorNodemanagerProtocol, used by nodemanager
+ if timeline service v2 is enabled, for the timeline collector and nodemanager
+ to communicate with each other.
+ The ACL is a comma-separated list of user and group names. The user and
+ group list is separated by a blank. For e.g. "alice,bob users,wheel".
+ A special value of "*" means all users are allowed.
+
+
+
+ security.applicationmaster-nodemanager.applicationmaster.protocol.acl
+ *
+ ACL for ApplicationMasterProtocol, used by the Nodemanager
+ and ApplicationMasters to communicate.
+ The ACL is a comma-separated list of user and group names. The user and
+ group list is separated by a blank. For e.g. "alice,bob users,wheel".
+ A special value of "*" means all users are allowed.
+
+
+
+ security.distributedscheduling.protocol.acl
+ *
+ ACL for DistributedSchedulingAMProtocol, used by the Nodemanager
+ and Resourcemanager to communicate.
+ The ACL is a comma-separated list of user and group names. The user and
+ group list is separated by a blank. For e.g. "alice,bob users,wheel".
+ A special value of "*" means all users are allowed.
+
+
diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java
index 83e270b3bb309..99972ae900389 100644
--- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java
@@ -16,7 +16,7 @@
*/
package org.apache.hadoop.hdds;
-import org.apache.hadoop.utils.db.DBProfile;
+import org.apache.hadoop.hdds.utils.db.DBProfile;
/**
* This class contains constants for configuration keys and default values
@@ -65,15 +65,12 @@ public final class HddsConfigKeys {
public static final float HDDS_CONTAINER_CLOSE_THRESHOLD_DEFAULT = 0.9f;
public static final String HDDS_SCM_SAFEMODE_ENABLED =
"hdds.scm.safemode.enabled";
- public static final String HDDS_CONTAINERSCRUB_ENABLED =
- "hdds.containerscrub.enabled";
- public static final boolean HDDS_CONTAINERSCRUB_ENABLED_DEFAULT = false;
+
public static final boolean HDDS_SCM_SAFEMODE_ENABLED_DEFAULT = true;
public static final String HDDS_SCM_SAFEMODE_MIN_DATANODE =
"hdds.scm.safemode.min.datanode";
public static final int HDDS_SCM_SAFEMODE_MIN_DATANODE_DEFAULT = 1;
-
public static final String
HDDS_SCM_WAIT_TIME_AFTER_SAFE_MODE_EXIT =
"hdds.scm.wait.time.after.safemode.exit";
@@ -179,34 +176,18 @@ public final class HddsConfigKeys {
private HddsConfigKeys() {
}
+ // Enable TLS for GRPC clients/server in ozone.
public static final String HDDS_GRPC_TLS_ENABLED = "hdds.grpc.tls.enabled";
public static final boolean HDDS_GRPC_TLS_ENABLED_DEFAULT = false;
- public static final String HDDS_GRPC_MUTUAL_TLS_REQUIRED =
- "hdds.grpc.mutual.tls.required";
- public static final boolean HDDS_GRPC_MUTUAL_TLS_REQUIRED_DEFAULT = false;
-
+ // Choose TLS provider the default is set to OPENSSL for better performance.
public static final String HDDS_GRPC_TLS_PROVIDER = "hdds.grpc.tls.provider";
public static final String HDDS_GRPC_TLS_PROVIDER_DEFAULT = "OPENSSL";
- public static final String HDDS_TRUST_STORE_FILE_NAME =
- "hdds.trust.cert.collection.file.name";
- public static final String HDDS_TRUST_STORE_FILE_NAME_DEFAULT = "ca.crt";
-
- public static final String
- HDDS_SERVER_CERTIFICATE_CHAIN_FILE_NAME =
- "hdds.server.cert.chain.file.name";
- public static final String
- HDDS_SERVER_CERTIFICATE_CHAIN_FILE_NAME_DEFAULT = "server.crt";
-
- public static final String
- HDDS_CLIENT_CERTIFICATE_CHAIN_FILE_NAME =
- "hdds.client.cert.chain.file.name";
- public static final String
- HDDS_CLIENT_CERTIFICATE_CHAIN_FILE_NAME_DEFAULT = "client.crt";
-
+ // Test only settings for using test signed certificate, authority assume to
+ // be localhost.
public static final String HDDS_GRPC_TLS_TEST_CERT = "hdds.grpc.tls" +
- ".test_cert";
+ ".test.cert";
public static final boolean HDDS_GRPC_TLS_TEST_CERT_DEFAULT = false;
// Comma separated acls (users, groups) allowing clients accessing
@@ -238,6 +219,16 @@ private HddsConfigKeys() {
public static final String HDDS_SECURITY_CLIENT_SCM_CERTIFICATE_PROTOCOL_ACL =
"hdds.security.client.scm.certificate.protocol.acl";
+ // Determines if the Container Chunk Manager will write user data to disk
+ // Set to false only for specific performance tests
+ public static final String HDDS_CONTAINER_PERSISTDATA =
+ "hdds.container.chunk.persistdata";
+ public static final boolean HDDS_CONTAINER_PERSISTDATA_DEFAULT = true;
+
+ public static final String HDDS_CONTAINER_SCRUB_ENABLED =
+ "hdds.container.scrub.enabled";
+ public static final boolean HDDS_CONTAINER_SCRUB_ENABLED_DEFAULT = false;
+
public static final String HDDS_DATANODE_HTTP_ENABLED_KEY =
"hdds.datanode.http.enabled";
public static final String HDDS_DATANODE_HTTP_BIND_HOST_KEY =
diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsUtils.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsUtils.java
index 92ed9b61630c9..d7b20fdd9172c 100644
--- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsUtils.java
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsUtils.java
@@ -30,6 +30,7 @@
import java.util.Map;
import java.util.Optional;
import java.util.TimeZone;
+import java.util.concurrent.TimeUnit;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
@@ -42,9 +43,15 @@
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.protocol.SCMSecurityProtocol;
import org.apache.hadoop.hdds.scm.protocolPB.ScmBlockLocationProtocolPB;
+import org.apache.hadoop.hdfs.DFSConfigKeys;
+import org.apache.hadoop.io.retry.RetryPolicies;
+import org.apache.hadoop.io.retry.RetryPolicy;
import org.apache.hadoop.ipc.Client;
import org.apache.hadoop.ipc.ProtobufRpcEngine;
import org.apache.hadoop.ipc.RPC;
+import org.apache.hadoop.metrics2.MetricsSystem;
+import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
+import org.apache.hadoop.metrics2.source.JvmMetrics;
import org.apache.hadoop.metrics2.util.MBeans;
import org.apache.hadoop.net.DNS;
import org.apache.hadoop.net.NetUtils;
@@ -173,23 +180,27 @@ public static InetSocketAddress getScmAddressForBlockClients(
/**
* Create a scm security client.
* @param conf - Ozone configuration.
- * @param address - inet socket address of scm.
*
* @return {@link SCMSecurityProtocol}
* @throws IOException
*/
- public static SCMSecurityProtocol getScmSecurityClient(
- OzoneConfiguration conf, InetSocketAddress address) throws IOException {
+ public static SCMSecurityProtocolClientSideTranslatorPB getScmSecurityClient(
+ OzoneConfiguration conf) throws IOException {
RPC.setProtocolEngine(conf, SCMSecurityProtocolPB.class,
ProtobufRpcEngine.class);
long scmVersion =
RPC.getProtocolVersion(ScmBlockLocationProtocolPB.class);
+ InetSocketAddress address =
+ getScmAddressForSecurityProtocol(conf);
+ RetryPolicy retryPolicy =
+ RetryPolicies.retryForeverWithFixedSleep(
+ 1000, TimeUnit.MILLISECONDS);
SCMSecurityProtocolClientSideTranslatorPB scmSecurityClient =
new SCMSecurityProtocolClientSideTranslatorPB(
- RPC.getProxy(SCMSecurityProtocolPB.class, scmVersion,
+ RPC.getProtocolProxy(SCMSecurityProtocolPB.class, scmVersion,
address, UserGroupInformation.getCurrentUser(),
conf, NetUtils.getDefaultSocketFactory(conf),
- Client.getRpcTimeout(conf)));
+ Client.getRpcTimeout(conf), retryPolicy).getProxy());
return scmSecurityClient;
}
@@ -226,7 +237,12 @@ public static Optional getHostName(String value) {
if ((value == null) || value.isEmpty()) {
return Optional.empty();
}
- return Optional.of(HostAndPort.fromString(value).getHostText());
+ String hostname = value.replaceAll("\\:[0-9]+$", "");
+ if (hostname.length() == 0) {
+ return Optional.empty();
+ } else {
+ return Optional.of(hostname);
+ }
}
/**
@@ -407,8 +423,10 @@ public static ObjectName registerWithJmxProperties(
InvocationTargetException e) {
// Fallback
- LOG.trace("Registering MBean {} without additional properties {}",
- mBeanName, jmxProperties);
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Registering MBean {} without additional properties {}",
+ mBeanName, jmxProperties);
+ }
return MBeans.register(serviceName, mBeanName, mBean);
}
}
@@ -470,4 +488,18 @@ public static InetSocketAddress getScmAddressForSecurityProtocol(
.orElse(ScmConfigKeys.OZONE_SCM_SECURITY_SERVICE_PORT_DEFAULT));
}
+ /**
+ * Initialize hadoop metrics system for Ozone servers.
+ * @param configuration OzoneConfiguration to use.
+ * @param serverName The logical name of the server components.
+ * @return
+ */
+ public static MetricsSystem initializeMetrics(
+ OzoneConfiguration configuration, String serverName) {
+ MetricsSystem metricsSystem = DefaultMetricsSystem.initialize(serverName);
+ JvmMetrics.create(serverName,
+ configuration.get(DFSConfigKeys.DFS_METRICS_SESSION_ID_KEY),
+ DefaultMetricsSystem.instance());
+ return metricsSystem;
+ }
}
diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/cli/HddsVersionProvider.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/cli/HddsVersionProvider.java
index ef7a56e6b2b6b..2f4ac4f170a83 100644
--- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/cli/HddsVersionProvider.java
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/cli/HddsVersionProvider.java
@@ -17,7 +17,7 @@
*/
package org.apache.hadoop.hdds.cli;
-import org.apache.hadoop.utils.HddsVersionInfo;
+import org.apache.hadoop.hdds.utils.HddsVersionInfo;
import picocli.CommandLine.IVersionProvider;
diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/client/ReplicationFactor.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/client/ReplicationFactor.java
index 0215964ab8e77..044bd6f8334cd 100644
--- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/client/ReplicationFactor.java
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/client/ReplicationFactor.java
@@ -18,6 +18,8 @@
package org.apache.hadoop.hdds.client;
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
+
/**
* The replication factor to be used while writing key into ozone.
*/
@@ -53,6 +55,22 @@ public static ReplicationFactor valueOf(int value) {
throw new IllegalArgumentException("Unsupported value: " + value);
}
+ public static ReplicationFactor fromProto(
+ HddsProtos.ReplicationFactor replicationFactor) {
+ if (replicationFactor == null) {
+ return null;
+ }
+ switch (replicationFactor) {
+ case ONE:
+ return ReplicationFactor.ONE;
+ case THREE:
+ return ReplicationFactor.THREE;
+ default:
+ throw new IllegalArgumentException(
+ "Unsupported ProtoBuf replication factor: " + replicationFactor);
+ }
+ }
+
/**
* Returns integer representation of ReplicationFactor.
* @return replication value
diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/client/ReplicationType.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/client/ReplicationType.java
index 259a1a2931742..c63896e9e1d13 100644
--- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/client/ReplicationType.java
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/client/ReplicationType.java
@@ -18,11 +18,31 @@
package org.apache.hadoop.hdds.client;
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
+
/**
* The replication type to be used while writing key into ozone.
*/
public enum ReplicationType {
RATIS,
STAND_ALONE,
- CHAINED
+ CHAINED;
+
+ public static ReplicationType fromProto(
+ HddsProtos.ReplicationType replicationType) {
+ if (replicationType == null) {
+ return null;
+ }
+ switch (replicationType) {
+ case RATIS:
+ return ReplicationType.RATIS;
+ case STAND_ALONE:
+ return ReplicationType.STAND_ALONE;
+ case CHAINED:
+ return ReplicationType.CHAINED;
+ default:
+ throw new IllegalArgumentException(
+ "Unsupported ProtoBuf replication type: " + replicationType);
+ }
+ }
}
diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/conf/HddsConfServlet.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/conf/HddsConfServlet.java
index 712e8d37e0462..8beac1663b2b7 100644
--- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/conf/HddsConfServlet.java
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/conf/HddsConfServlet.java
@@ -171,7 +171,9 @@ private void processConfigTagRequest(HttpServletRequest request,
Properties properties = config.getAllPropertiesByTag(tag);
propMap.put(tag, properties);
} else {
- LOG.debug("Not a valid tag" + tag);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Not a valid tag" + tag);
+ }
}
}
out.write(gson.toJsonTree(propMap).toString());
diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/conf/OzoneConfiguration.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/conf/OzoneConfiguration.java
index b32ad63353553..c0486335cdd2a 100644
--- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/conf/OzoneConfiguration.java
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/conf/OzoneConfiguration.java
@@ -34,6 +34,7 @@
import java.util.List;
import java.util.Properties;
+import com.google.common.base.Preconditions;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.conf.Configuration;
@@ -46,6 +47,14 @@ public class OzoneConfiguration extends Configuration {
activate();
}
+ public static OzoneConfiguration of(Configuration conf) {
+ Preconditions.checkNotNull(conf);
+
+ return conf instanceof OzoneConfiguration
+ ? (OzoneConfiguration) conf
+ : new OzoneConfiguration(conf);
+ }
+
public OzoneConfiguration() {
OzoneConfiguration.activate();
loadDefaults();
diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/function/FunctionWithServiceException.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/function/FunctionWithServiceException.java
new file mode 100644
index 0000000000000..b9d7bceb48f95
--- /dev/null
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/function/FunctionWithServiceException.java
@@ -0,0 +1,36 @@
+/**
+ * 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
+ *