HDFS-4595. Merging 1456047 from trunk.
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-2@1456048 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
7f75863029
commit
e81ffd1705
|
@ -74,6 +74,9 @@ Release 2.0.5-beta - UNRELEASED
|
||||||
HDFS-4484. libwebhdfs compilation broken with gcc 4.6.2. (Colin Patrick
|
HDFS-4484. libwebhdfs compilation broken with gcc 4.6.2. (Colin Patrick
|
||||||
McCabe via atm)
|
McCabe via atm)
|
||||||
|
|
||||||
|
HDFS-4595. When short circuit read is fails, DFSClient does not fallback
|
||||||
|
to regular reads. (suresh)
|
||||||
|
|
||||||
Release 2.0.4-alpha - UNRELEASED
|
Release 2.0.4-alpha - UNRELEASED
|
||||||
|
|
||||||
INCOMPATIBLE CHANGES
|
INCOMPATIBLE CHANGES
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.security.PrivilegedExceptionAction;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
@ -31,6 +32,7 @@ import java.util.Map;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.fs.FileSystem;
|
||||||
import org.apache.hadoop.hdfs.protocol.BlockLocalPathInfo;
|
import org.apache.hadoop.hdfs.protocol.BlockLocalPathInfo;
|
||||||
import org.apache.hadoop.hdfs.protocol.ClientDatanodeProtocol;
|
import org.apache.hadoop.hdfs.protocol.ClientDatanodeProtocol;
|
||||||
import org.apache.hadoop.hdfs.protocol.DatanodeInfo;
|
import org.apache.hadoop.hdfs.protocol.DatanodeInfo;
|
||||||
|
@ -41,6 +43,7 @@ import org.apache.hadoop.hdfs.server.datanode.BlockMetadataHeader;
|
||||||
import org.apache.hadoop.hdfs.util.DirectBufferPool;
|
import org.apache.hadoop.hdfs.util.DirectBufferPool;
|
||||||
import org.apache.hadoop.ipc.RPC;
|
import org.apache.hadoop.ipc.RPC;
|
||||||
import org.apache.hadoop.io.IOUtils;
|
import org.apache.hadoop.io.IOUtils;
|
||||||
|
import org.apache.hadoop.security.UserGroupInformation;
|
||||||
import org.apache.hadoop.security.token.Token;
|
import org.apache.hadoop.security.token.Token;
|
||||||
import org.apache.hadoop.util.DataChecksum;
|
import org.apache.hadoop.util.DataChecksum;
|
||||||
|
|
||||||
|
@ -86,11 +89,21 @@ class BlockReaderLocal implements BlockReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized ClientDatanodeProtocol getDatanodeProxy(
|
private synchronized ClientDatanodeProtocol getDatanodeProxy(
|
||||||
DatanodeInfo node, Configuration conf, int socketTimeout,
|
UserGroupInformation ugi, final DatanodeInfo node,
|
||||||
boolean connectToDnViaHostname) throws IOException {
|
final Configuration conf, final int socketTimeout,
|
||||||
|
final boolean connectToDnViaHostname) throws IOException {
|
||||||
if (proxy == null) {
|
if (proxy == null) {
|
||||||
proxy = DFSUtil.createClientDatanodeProtocolProxy(node, conf,
|
try {
|
||||||
socketTimeout, connectToDnViaHostname);
|
proxy = ugi.doAs(new PrivilegedExceptionAction<ClientDatanodeProtocol>() {
|
||||||
|
@Override
|
||||||
|
public ClientDatanodeProtocol run() throws Exception {
|
||||||
|
return DFSUtil.createClientDatanodeProtocolProxy(node, conf,
|
||||||
|
socketTimeout, connectToDnViaHostname);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
LOG.warn("encountered exception ", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
@ -154,17 +167,18 @@ class BlockReaderLocal implements BlockReader {
|
||||||
/**
|
/**
|
||||||
* The only way this object can be instantiated.
|
* The only way this object can be instantiated.
|
||||||
*/
|
*/
|
||||||
static BlockReaderLocal newBlockReader(Configuration conf, String file,
|
static BlockReaderLocal newBlockReader(UserGroupInformation ugi,
|
||||||
ExtendedBlock blk, Token<BlockTokenIdentifier> token, DatanodeInfo node,
|
Configuration conf, String file, ExtendedBlock blk,
|
||||||
int socketTimeout, long startOffset, long length,
|
Token<BlockTokenIdentifier> token, DatanodeInfo node, int socketTimeout,
|
||||||
boolean connectToDnViaHostname) throws IOException {
|
long startOffset, long length, boolean connectToDnViaHostname)
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
LocalDatanodeInfo localDatanodeInfo = getLocalDatanodeInfo(node
|
LocalDatanodeInfo localDatanodeInfo = getLocalDatanodeInfo(node
|
||||||
.getIpcPort());
|
.getIpcPort());
|
||||||
// check the cache first
|
// check the cache first
|
||||||
BlockLocalPathInfo pathinfo = localDatanodeInfo.getBlockLocalPathInfo(blk);
|
BlockLocalPathInfo pathinfo = localDatanodeInfo.getBlockLocalPathInfo(blk);
|
||||||
if (pathinfo == null) {
|
if (pathinfo == null) {
|
||||||
pathinfo = getBlockPathInfo(blk, node, conf, socketTimeout, token,
|
pathinfo = getBlockPathInfo(ugi, blk, node, conf, socketTimeout, token,
|
||||||
connectToDnViaHostname);
|
connectToDnViaHostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,13 +255,13 @@ class BlockReaderLocal implements BlockReader {
|
||||||
return ldInfo;
|
return ldInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BlockLocalPathInfo getBlockPathInfo(ExtendedBlock blk,
|
private static BlockLocalPathInfo getBlockPathInfo(UserGroupInformation ugi,
|
||||||
DatanodeInfo node, Configuration conf, int timeout,
|
ExtendedBlock blk, DatanodeInfo node, Configuration conf, int timeout,
|
||||||
Token<BlockTokenIdentifier> token, boolean connectToDnViaHostname)
|
Token<BlockTokenIdentifier> token, boolean connectToDnViaHostname)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
LocalDatanodeInfo localDatanodeInfo = getLocalDatanodeInfo(node.getIpcPort());
|
LocalDatanodeInfo localDatanodeInfo = getLocalDatanodeInfo(node.getIpcPort());
|
||||||
BlockLocalPathInfo pathinfo = null;
|
BlockLocalPathInfo pathinfo = null;
|
||||||
ClientDatanodeProtocol proxy = localDatanodeInfo.getDatanodeProxy(node,
|
ClientDatanodeProtocol proxy = localDatanodeInfo.getDatanodeProxy(ugi, node,
|
||||||
conf, timeout, connectToDnViaHostname);
|
conf, timeout, connectToDnViaHostname);
|
||||||
try {
|
try {
|
||||||
// make RPC to local datanode to find local pathnames of blocks
|
// make RPC to local datanode to find local pathnames of blocks
|
||||||
|
|
|
@ -414,6 +414,7 @@ public class DFSClient implements java.io.Closeable {
|
||||||
"null URI");
|
"null URI");
|
||||||
NameNodeProxies.ProxyAndInfo<ClientProtocol> proxyInfo =
|
NameNodeProxies.ProxyAndInfo<ClientProtocol> proxyInfo =
|
||||||
NameNodeProxies.createProxy(conf, nameNodeUri, ClientProtocol.class);
|
NameNodeProxies.createProxy(conf, nameNodeUri, ClientProtocol.class);
|
||||||
|
|
||||||
this.dtService = proxyInfo.getDelegationTokenService();
|
this.dtService = proxyInfo.getDelegationTokenService();
|
||||||
this.namenode = proxyInfo.getProxy();
|
this.namenode = proxyInfo.getProxy();
|
||||||
}
|
}
|
||||||
|
@ -782,12 +783,13 @@ public class DFSClient implements java.io.Closeable {
|
||||||
/**
|
/**
|
||||||
* Get {@link BlockReader} for short circuited local reads.
|
* Get {@link BlockReader} for short circuited local reads.
|
||||||
*/
|
*/
|
||||||
static BlockReader getLocalBlockReader(Configuration conf,
|
static BlockReader getLocalBlockReader(UserGroupInformation ugi,
|
||||||
String src, ExtendedBlock blk, Token<BlockTokenIdentifier> accessToken,
|
Configuration conf, String src, ExtendedBlock blk,
|
||||||
DatanodeInfo chosenNode, int socketTimeout, long offsetIntoBlock,
|
Token<BlockTokenIdentifier> accessToken, DatanodeInfo chosenNode,
|
||||||
boolean connectToDnViaHostname) throws InvalidToken, IOException {
|
int socketTimeout, long offsetIntoBlock, boolean connectToDnViaHostname)
|
||||||
|
throws InvalidToken, IOException {
|
||||||
try {
|
try {
|
||||||
return BlockReaderLocal.newBlockReader(conf, src, blk, accessToken,
|
return BlockReaderLocal.newBlockReader(ugi, conf, src, blk, accessToken,
|
||||||
chosenNode, socketTimeout, offsetIntoBlock, blk.getNumBytes()
|
chosenNode, socketTimeout, offsetIntoBlock, blk.getNumBytes()
|
||||||
- offsetIntoBlock, connectToDnViaHostname);
|
- offsetIntoBlock, connectToDnViaHostname);
|
||||||
} catch (RemoteException re) {
|
} catch (RemoteException re) {
|
||||||
|
@ -1638,7 +1640,7 @@ public class DFSClient implements java.io.Closeable {
|
||||||
* @param socketFactory to create sockets to connect to DNs
|
* @param socketFactory to create sockets to connect to DNs
|
||||||
* @param socketTimeout timeout to use when connecting and waiting for a response
|
* @param socketTimeout timeout to use when connecting and waiting for a response
|
||||||
* @param encryptionKey the key needed to communicate with DNs in this cluster
|
* @param encryptionKey the key needed to communicate with DNs in this cluster
|
||||||
* @param connectToDnViaHostname {@see #connectToDnViaHostname()}
|
* @param connectToDnViaHostname {@link #connectToDnViaHostname()}
|
||||||
* @return The checksum
|
* @return The checksum
|
||||||
*/
|
*/
|
||||||
static MD5MD5CRC32FileChecksum getFileChecksum(String src,
|
static MD5MD5CRC32FileChecksum getFileChecksum(String src,
|
||||||
|
@ -2250,6 +2252,12 @@ public class DFSClient implements java.io.Closeable {
|
||||||
}
|
}
|
||||||
|
|
||||||
void disableShortCircuit() {
|
void disableShortCircuit() {
|
||||||
|
LOG.info("Short circuit is disabled");
|
||||||
shortCircuitLocalReads = false;
|
shortCircuitLocalReads = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
boolean getShortCircuitLocalReads() {
|
||||||
|
return shortCircuitLocalReads;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -460,6 +460,10 @@ public class DFSInputStream extends FSInputStream implements ByteBufferReadable
|
||||||
" for " + blk);
|
" for " + blk);
|
||||||
}
|
}
|
||||||
return chosenNode;
|
return chosenNode;
|
||||||
|
} catch (AccessControlException ex) {
|
||||||
|
DFSClient.LOG.warn("Short circuit access failed " + ex);
|
||||||
|
dfsClient.disableShortCircuit();
|
||||||
|
continue;
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
if (ex instanceof InvalidEncryptionKeyException && refetchEncryptionKey > 0) {
|
if (ex instanceof InvalidEncryptionKeyException && refetchEncryptionKey > 0) {
|
||||||
DFSClient.LOG.info("Will fetch a new encryption key and retry, "
|
DFSClient.LOG.info("Will fetch a new encryption key and retry, "
|
||||||
|
@ -806,7 +810,7 @@ public class DFSInputStream extends FSInputStream implements ByteBufferReadable
|
||||||
// we want to remember what we have tried
|
// we want to remember what we have tried
|
||||||
addIntoCorruptedBlockMap(block.getBlock(), chosenNode, corruptedBlockMap);
|
addIntoCorruptedBlockMap(block.getBlock(), chosenNode, corruptedBlockMap);
|
||||||
} catch (AccessControlException ex) {
|
} catch (AccessControlException ex) {
|
||||||
DFSClient.LOG.warn("Short circuit access failed ", ex);
|
DFSClient.LOG.warn("Short circuit access failed " + ex);
|
||||||
dfsClient.disableShortCircuit();
|
dfsClient.disableShortCircuit();
|
||||||
continue;
|
continue;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -885,9 +889,9 @@ public class DFSInputStream extends FSInputStream implements ByteBufferReadable
|
||||||
// Can't local read a block under construction, see HDFS-2757
|
// Can't local read a block under construction, see HDFS-2757
|
||||||
if (dfsClient.shouldTryShortCircuitRead(dnAddr) &&
|
if (dfsClient.shouldTryShortCircuitRead(dnAddr) &&
|
||||||
!blockUnderConstruction()) {
|
!blockUnderConstruction()) {
|
||||||
return DFSClient.getLocalBlockReader(dfsClient.conf, src, block,
|
return DFSClient.getLocalBlockReader(dfsClient.ugi, dfsClient.conf,
|
||||||
blockToken, chosenNode, dfsClient.hdfsTimeout, startOffset,
|
src, block, blockToken, chosenNode, dfsClient.hdfsTimeout,
|
||||||
dfsClient.connectToDnViaHostname());
|
startOffset, dfsClient.connectToDnViaHostname());
|
||||||
}
|
}
|
||||||
|
|
||||||
IOException err = null;
|
IOException err = null;
|
||||||
|
@ -1027,8 +1031,8 @@ public class DFSInputStream extends FSInputStream implements ByteBufferReadable
|
||||||
* only report if the total number of replica is 1. We do not
|
* only report if the total number of replica is 1. We do not
|
||||||
* report otherwise since this maybe due to the client is a handicapped client
|
* report otherwise since this maybe due to the client is a handicapped client
|
||||||
* (who can not read).
|
* (who can not read).
|
||||||
* @param corruptedBlockMap, map of corrupted blocks
|
* @param corruptedBlockMap map of corrupted blocks
|
||||||
* @param dataNodeCount, number of data nodes who contains the block replicas
|
* @param dataNodeCount number of data nodes who contains the block replicas
|
||||||
*/
|
*/
|
||||||
private void reportCheckSumFailure(
|
private void reportCheckSumFailure(
|
||||||
Map<ExtendedBlock, Set<DatanodeInfo>> corruptedBlockMap,
|
Map<ExtendedBlock, Set<DatanodeInfo>> corruptedBlockMap,
|
||||||
|
|
|
@ -67,6 +67,8 @@ import org.apache.hadoop.security.token.SecretManager.InvalidToken;
|
||||||
import org.apache.hadoop.security.token.Token;
|
import org.apache.hadoop.security.token.Token;
|
||||||
import org.apache.hadoop.util.Progressable;
|
import org.apache.hadoop.util.Progressable;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************
|
/****************************************************************
|
||||||
* Implementation of the abstract FileSystem for the DFS system.
|
* Implementation of the abstract FileSystem for the DFS system.
|
||||||
|
@ -564,9 +566,8 @@ public class DistributedFileSystem extends FileSystem {
|
||||||
return "DFS[" + dfs + "]";
|
return "DFS[" + dfs + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @deprecated DFSClient should not be accessed directly. */
|
|
||||||
@InterfaceAudience.Private
|
@InterfaceAudience.Private
|
||||||
@Deprecated
|
@VisibleForTesting
|
||||||
public DFSClient getClient() {
|
public DFSClient getClient() {
|
||||||
return dfs;
|
return dfs;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,11 @@
|
||||||
package org.apache.hadoop.hdfs;
|
package org.apache.hadoop.hdfs;
|
||||||
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.security.PrivilegedExceptionAction;
|
import java.security.PrivilegedExceptionAction;
|
||||||
|
|
||||||
|
@ -32,6 +34,7 @@ import org.apache.hadoop.fs.Path;
|
||||||
import org.apache.hadoop.hdfs.DFSClient.DFSDataInputStream;
|
import org.apache.hadoop.hdfs.DFSClient.DFSDataInputStream;
|
||||||
import org.apache.hadoop.hdfs.protocol.BlockLocalPathInfo;
|
import org.apache.hadoop.hdfs.protocol.BlockLocalPathInfo;
|
||||||
import org.apache.hadoop.hdfs.protocol.ClientDatanodeProtocol;
|
import org.apache.hadoop.hdfs.protocol.ClientDatanodeProtocol;
|
||||||
|
import org.apache.hadoop.hdfs.protocol.DatanodeID;
|
||||||
import org.apache.hadoop.hdfs.protocol.DatanodeInfo;
|
import org.apache.hadoop.hdfs.protocol.DatanodeInfo;
|
||||||
import org.apache.hadoop.hdfs.protocol.ExtendedBlock;
|
import org.apache.hadoop.hdfs.protocol.ExtendedBlock;
|
||||||
import org.apache.hadoop.hdfs.protocol.LocatedBlocks;
|
import org.apache.hadoop.hdfs.protocol.LocatedBlocks;
|
||||||
|
@ -85,9 +88,20 @@ public class TestShortCircuitLocalRead {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getCurrentUser() throws IOException {
|
||||||
|
return UserGroupInformation.getCurrentUser().getShortUserName();
|
||||||
|
}
|
||||||
|
|
||||||
static void checkFileContent(FileSystem fs, Path name, byte[] expected,
|
/** Check file content, reading as user {@code readingUser} */
|
||||||
int readOffset) throws IOException {
|
static void checkFileContent(URI uri, Path name, byte[] expected,
|
||||||
|
int readOffset, String readingUser, Configuration conf,
|
||||||
|
boolean shortCircuitFails)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
// Ensure short circuit is enabled
|
||||||
|
DistributedFileSystem fs = getFileSystem(readingUser, uri, conf);
|
||||||
|
assertTrue(fs.getClient().getShortCircuitLocalReads());
|
||||||
|
|
||||||
FSDataInputStream stm = fs.open(name);
|
FSDataInputStream stm = fs.open(name);
|
||||||
byte[] actual = new byte[expected.length-readOffset];
|
byte[] actual = new byte[expected.length-readOffset];
|
||||||
stm.readFully(readOffset, actual);
|
stm.readFully(readOffset, actual);
|
||||||
|
@ -112,6 +126,11 @@ public class TestShortCircuitLocalRead {
|
||||||
nread += nbytes;
|
nread += nbytes;
|
||||||
}
|
}
|
||||||
checkData(actual, readOffset, expected, "Read 3");
|
checkData(actual, readOffset, expected, "Read 3");
|
||||||
|
|
||||||
|
if (shortCircuitFails) {
|
||||||
|
// short circuit should be disabled due to failure
|
||||||
|
assertFalse(fs.getClient().getShortCircuitLocalReads());
|
||||||
|
}
|
||||||
stm.close();
|
stm.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,11 +142,15 @@ public class TestShortCircuitLocalRead {
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Check the file content, reading as user {@code readingUser} */
|
||||||
* Verifies that reading a file with the direct read(ByteBuffer) api gives the expected set of bytes.
|
static void checkFileContentDirect(URI uri, Path name, byte[] expected,
|
||||||
*/
|
int readOffset, String readingUser, Configuration conf,
|
||||||
static void checkFileContentDirect(FileSystem fs, Path name, byte[] expected,
|
boolean shortCircuitFails)
|
||||||
int readOffset) throws IOException {
|
throws IOException, InterruptedException {
|
||||||
|
// Ensure short circuit is enabled
|
||||||
|
DistributedFileSystem fs = getFileSystem(readingUser, uri, conf);
|
||||||
|
assertTrue(fs.getClient().getShortCircuitLocalReads());
|
||||||
|
|
||||||
DFSDataInputStream stm = (DFSDataInputStream)fs.open(name);
|
DFSDataInputStream stm = (DFSDataInputStream)fs.open(name);
|
||||||
|
|
||||||
ByteBuffer actual = ByteBuffer.allocateDirect(expected.length - readOffset);
|
ByteBuffer actual = ByteBuffer.allocateDirect(expected.length - readOffset);
|
||||||
|
@ -157,21 +180,33 @@ public class TestShortCircuitLocalRead {
|
||||||
nread += nbytes;
|
nread += nbytes;
|
||||||
}
|
}
|
||||||
checkData(arrayFromByteBuffer(actual), readOffset, expected, "Read 3");
|
checkData(arrayFromByteBuffer(actual), readOffset, expected, "Read 3");
|
||||||
|
if (shortCircuitFails) {
|
||||||
|
// short circuit should be disabled due to failure
|
||||||
|
assertFalse(fs.getClient().getShortCircuitLocalReads());
|
||||||
|
}
|
||||||
stm.close();
|
stm.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void doTestShortCircuitRead(boolean ignoreChecksum, int size,
|
||||||
|
int readOffset) throws IOException, InterruptedException {
|
||||||
|
String shortCircuitUser = getCurrentUser();
|
||||||
|
doTestShortCircuitRead(ignoreChecksum, size, readOffset, shortCircuitUser,
|
||||||
|
shortCircuitUser, false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that file data can be read by reading the block file
|
* Test that file data can be read by reading the block file
|
||||||
* directly from the local store.
|
* directly from the local store.
|
||||||
*/
|
*/
|
||||||
public void doTestShortCircuitRead(boolean ignoreChecksum, int size,
|
public void doTestShortCircuitRead(boolean ignoreChecksum, int size,
|
||||||
int readOffset) throws IOException {
|
int readOffset, String shortCircuitUser, String readingUser,
|
||||||
|
boolean shortCircuitFails) throws IOException, InterruptedException {
|
||||||
Configuration conf = new Configuration();
|
Configuration conf = new Configuration();
|
||||||
conf.setBoolean(DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_KEY, true);
|
conf.setBoolean(DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_KEY, true);
|
||||||
conf.setBoolean(DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_SKIP_CHECKSUM_KEY,
|
conf.setBoolean(DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_SKIP_CHECKSUM_KEY,
|
||||||
ignoreChecksum);
|
ignoreChecksum);
|
||||||
conf.set(DFSConfigKeys.DFS_BLOCK_LOCAL_PATH_ACCESS_USER_KEY,
|
conf.set(DFSConfigKeys.DFS_BLOCK_LOCAL_PATH_ACCESS_USER_KEY,
|
||||||
UserGroupInformation.getCurrentUser().getShortUserName());
|
shortCircuitUser);
|
||||||
if (simulatedStorage) {
|
if (simulatedStorage) {
|
||||||
SimulatedFSDataset.setFactory(conf);
|
SimulatedFSDataset.setFactory(conf);
|
||||||
}
|
}
|
||||||
|
@ -184,53 +219,88 @@ public class TestShortCircuitLocalRead {
|
||||||
assertTrue("/ should be a directory", fs.getFileStatus(path)
|
assertTrue("/ should be a directory", fs.getFileStatus(path)
|
||||||
.isDirectory() == true);
|
.isDirectory() == true);
|
||||||
|
|
||||||
byte[] fileData = AppendTestUtil.randomBytes(seed, size);
|
|
||||||
// create a new file in home directory. Do not close it.
|
// create a new file in home directory. Do not close it.
|
||||||
Path file1 = new Path("filelocal.dat");
|
byte[] fileData = AppendTestUtil.randomBytes(seed, size);
|
||||||
|
Path file1 = fs.makeQualified(new Path("filelocal.dat"));
|
||||||
FSDataOutputStream stm = createFile(fs, file1, 1);
|
FSDataOutputStream stm = createFile(fs, file1, 1);
|
||||||
|
|
||||||
// write to file
|
|
||||||
stm.write(fileData);
|
stm.write(fileData);
|
||||||
stm.close();
|
stm.close();
|
||||||
checkFileContent(fs, file1, fileData, readOffset);
|
|
||||||
checkFileContentDirect(fs, file1, fileData, readOffset);
|
URI uri = cluster.getURI();
|
||||||
|
checkFileContent(uri, file1, fileData, readOffset, readingUser, conf,
|
||||||
|
shortCircuitFails);
|
||||||
|
checkFileContentDirect(uri, file1, fileData, readOffset, readingUser,
|
||||||
|
conf, shortCircuitFails);
|
||||||
} finally {
|
} finally {
|
||||||
fs.close();
|
fs.close();
|
||||||
cluster.shutdown();
|
cluster.shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test(timeout=10000)
|
||||||
public void testFileLocalReadNoChecksum() throws IOException {
|
public void testFileLocalReadNoChecksum() throws Exception {
|
||||||
doTestShortCircuitRead(true, 3*blockSize+100, 0);
|
doTestShortCircuitRead(true, 3*blockSize+100, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test(timeout=10000)
|
||||||
public void testFileLocalReadChecksum() throws IOException {
|
public void testFileLocalReadChecksum() throws Exception {
|
||||||
doTestShortCircuitRead(false, 3*blockSize+100, 0);
|
doTestShortCircuitRead(false, 3*blockSize+100, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test(timeout=10000)
|
||||||
public void testSmallFileLocalRead() throws IOException {
|
public void testSmallFileLocalRead() throws Exception {
|
||||||
doTestShortCircuitRead(false, 13, 0);
|
doTestShortCircuitRead(false, 13, 0);
|
||||||
doTestShortCircuitRead(false, 13, 5);
|
doTestShortCircuitRead(false, 13, 5);
|
||||||
doTestShortCircuitRead(true, 13, 0);
|
doTestShortCircuitRead(true, 13, 0);
|
||||||
doTestShortCircuitRead(true, 13, 5);
|
doTestShortCircuitRead(true, 13, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
/**
|
||||||
public void testReadFromAnOffset() throws IOException {
|
* Try a short circuit from a reader that is not allowed to
|
||||||
|
* to use short circuit. The test ensures reader falls back to non
|
||||||
|
* shortcircuit reads when shortcircuit is disallowed.
|
||||||
|
*/
|
||||||
|
@Test(timeout=10000)
|
||||||
|
public void testLocalReadFallback() throws Exception {
|
||||||
|
doTestShortCircuitRead(true, 13, 0, getCurrentUser(), "notallowed", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout=10000)
|
||||||
|
public void testReadFromAnOffset() throws Exception {
|
||||||
doTestShortCircuitRead(false, 3*blockSize+100, 777);
|
doTestShortCircuitRead(false, 3*blockSize+100, 777);
|
||||||
doTestShortCircuitRead(true, 3*blockSize+100, 777);
|
doTestShortCircuitRead(true, 3*blockSize+100, 777);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test(timeout=10000)
|
||||||
public void testLongFile() throws IOException {
|
public void testLongFile() throws Exception {
|
||||||
doTestShortCircuitRead(false, 10*blockSize+100, 777);
|
doTestShortCircuitRead(false, 10*blockSize+100, 777);
|
||||||
doTestShortCircuitRead(true, 10*blockSize+100, 777);
|
doTestShortCircuitRead(true, 10*blockSize+100, 777);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
private ClientDatanodeProtocol getProxy(UserGroupInformation ugi,
|
||||||
|
final DatanodeID dnInfo, final Configuration conf) throws IOException,
|
||||||
|
InterruptedException {
|
||||||
|
return ugi.doAs(new PrivilegedExceptionAction<ClientDatanodeProtocol>() {
|
||||||
|
@Override
|
||||||
|
public ClientDatanodeProtocol run() throws Exception {
|
||||||
|
return DFSUtil.createClientDatanodeProtocolProxy(dnInfo, conf, 60000,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DistributedFileSystem getFileSystem(String user, final URI uri,
|
||||||
|
final Configuration conf) throws InterruptedException, IOException {
|
||||||
|
UserGroupInformation ugi = UserGroupInformation.createRemoteUser(user);
|
||||||
|
return ugi.doAs(new PrivilegedExceptionAction<DistributedFileSystem>() {
|
||||||
|
@Override
|
||||||
|
public DistributedFileSystem run() throws Exception {
|
||||||
|
return (DistributedFileSystem)FileSystem.get(uri, conf);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout=10000)
|
||||||
public void testGetBlockLocalPathInfo() throws IOException, InterruptedException {
|
public void testGetBlockLocalPathInfo() throws IOException, InterruptedException {
|
||||||
final Configuration conf = new Configuration();
|
final Configuration conf = new Configuration();
|
||||||
conf.set(DFSConfigKeys.DFS_BLOCK_LOCAL_PATH_ACCESS_USER_KEY,
|
conf.set(DFSConfigKeys.DFS_BLOCK_LOCAL_PATH_ACCESS_USER_KEY,
|
||||||
|
@ -253,15 +323,7 @@ public class TestShortCircuitLocalRead {
|
||||||
ExtendedBlock blk = new ExtendedBlock(lb.get(0).getBlock());
|
ExtendedBlock blk = new ExtendedBlock(lb.get(0).getBlock());
|
||||||
Token<BlockTokenIdentifier> token = lb.get(0).getBlockToken();
|
Token<BlockTokenIdentifier> token = lb.get(0).getBlockToken();
|
||||||
final DatanodeInfo dnInfo = lb.get(0).getLocations()[0];
|
final DatanodeInfo dnInfo = lb.get(0).getLocations()[0];
|
||||||
ClientDatanodeProtocol proxy = aUgi1
|
ClientDatanodeProtocol proxy = getProxy(aUgi1, dnInfo, conf);
|
||||||
.doAs(new PrivilegedExceptionAction<ClientDatanodeProtocol>() {
|
|
||||||
@Override
|
|
||||||
public ClientDatanodeProtocol run() throws Exception {
|
|
||||||
return DFSUtil.createClientDatanodeProtocolProxy(dnInfo, conf,
|
|
||||||
60000, false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// This should succeed
|
// This should succeed
|
||||||
BlockLocalPathInfo blpi = proxy.getBlockLocalPathInfo(blk, token);
|
BlockLocalPathInfo blpi = proxy.getBlockLocalPathInfo(blk, token);
|
||||||
Assert.assertEquals(
|
Assert.assertEquals(
|
||||||
|
@ -269,14 +331,7 @@ public class TestShortCircuitLocalRead {
|
||||||
blpi.getBlockPath());
|
blpi.getBlockPath());
|
||||||
|
|
||||||
// Try with the other allowed user
|
// Try with the other allowed user
|
||||||
proxy = aUgi2
|
proxy = getProxy(aUgi2, dnInfo, conf);
|
||||||
.doAs(new PrivilegedExceptionAction<ClientDatanodeProtocol>() {
|
|
||||||
@Override
|
|
||||||
public ClientDatanodeProtocol run() throws Exception {
|
|
||||||
return DFSUtil.createClientDatanodeProtocolProxy(dnInfo, conf,
|
|
||||||
60000, false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// This should succeed as well
|
// This should succeed as well
|
||||||
blpi = proxy.getBlockLocalPathInfo(blk, token);
|
blpi = proxy.getBlockLocalPathInfo(blk, token);
|
||||||
|
@ -287,14 +342,7 @@ public class TestShortCircuitLocalRead {
|
||||||
// Now try with a disallowed user
|
// Now try with a disallowed user
|
||||||
UserGroupInformation bUgi = UserGroupInformation
|
UserGroupInformation bUgi = UserGroupInformation
|
||||||
.createRemoteUser("notalloweduser");
|
.createRemoteUser("notalloweduser");
|
||||||
proxy = bUgi
|
proxy = getProxy(bUgi, dnInfo, conf);
|
||||||
.doAs(new PrivilegedExceptionAction<ClientDatanodeProtocol>() {
|
|
||||||
@Override
|
|
||||||
public ClientDatanodeProtocol run() throws Exception {
|
|
||||||
return DFSUtil.createClientDatanodeProtocolProxy(dnInfo, conf,
|
|
||||||
60000, false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
try {
|
try {
|
||||||
proxy.getBlockLocalPathInfo(blk, token);
|
proxy.getBlockLocalPathInfo(blk, token);
|
||||||
Assert.fail("The call should have failed as " + bUgi.getShortUserName()
|
Assert.fail("The call should have failed as " + bUgi.getShortUserName()
|
||||||
|
@ -309,14 +357,14 @@ public class TestShortCircuitLocalRead {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test(timeout=10000)
|
||||||
public void testSkipWithVerifyChecksum() throws IOException {
|
public void testSkipWithVerifyChecksum() throws IOException {
|
||||||
int size = blockSize;
|
int size = blockSize;
|
||||||
Configuration conf = new Configuration();
|
Configuration conf = new Configuration();
|
||||||
conf.setBoolean(DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_KEY, true);
|
conf.setBoolean(DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_KEY, true);
|
||||||
conf.setBoolean(DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_SKIP_CHECKSUM_KEY, false);
|
conf.setBoolean(DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_SKIP_CHECKSUM_KEY, false);
|
||||||
conf.set(DFSConfigKeys.DFS_BLOCK_LOCAL_PATH_ACCESS_USER_KEY,
|
conf.set(DFSConfigKeys.DFS_BLOCK_LOCAL_PATH_ACCESS_USER_KEY,
|
||||||
UserGroupInformation.getCurrentUser().getShortUserName());
|
getCurrentUser());
|
||||||
if (simulatedStorage) {
|
if (simulatedStorage) {
|
||||||
SimulatedFSDataset.setFactory(conf);
|
SimulatedFSDataset.setFactory(conf);
|
||||||
}
|
}
|
||||||
|
@ -356,7 +404,7 @@ public class TestShortCircuitLocalRead {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test to run benchmarks between shortcircuit read vs regular read with
|
* Test to run benchmarks between short circuit read vs regular read with
|
||||||
* specified number of threads simultaneously reading.
|
* specified number of threads simultaneously reading.
|
||||||
* <br>
|
* <br>
|
||||||
* Run this using the following command:
|
* Run this using the following command:
|
||||||
|
@ -374,7 +422,7 @@ public class TestShortCircuitLocalRead {
|
||||||
int threadCount = Integer.valueOf(args[2]);
|
int threadCount = Integer.valueOf(args[2]);
|
||||||
|
|
||||||
// Setup create a file
|
// Setup create a file
|
||||||
Configuration conf = new Configuration();
|
final Configuration conf = new Configuration();
|
||||||
conf.setBoolean(DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_KEY, shortcircuit);
|
conf.setBoolean(DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_KEY, shortcircuit);
|
||||||
conf.setBoolean(DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_SKIP_CHECKSUM_KEY,
|
conf.setBoolean(DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_SKIP_CHECKSUM_KEY,
|
||||||
checksum);
|
checksum);
|
||||||
|
@ -400,9 +448,13 @@ public class TestShortCircuitLocalRead {
|
||||||
public void run() {
|
public void run() {
|
||||||
for (int i = 0; i < iteration; i++) {
|
for (int i = 0; i < iteration; i++) {
|
||||||
try {
|
try {
|
||||||
checkFileContent(fs, file1, dataToWrite, 0);
|
String user = getCurrentUser();
|
||||||
|
checkFileContent(fs.getUri(), file1, dataToWrite, 0, user, conf,
|
||||||
|
true);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue