HDFS-7839. Erasure coding: implement facilities in NameNode to create and manage EC zones. Contributed by Zhe Zhang
This commit is contained in:
parent
578019d6a2
commit
1af8c14862
|
@ -2994,6 +2994,21 @@ public class DFSClient implements java.io.Closeable, RemotePeerFactory,
|
||||||
return new EncryptionZoneIterator(namenode, traceSampler);
|
return new EncryptionZoneIterator(namenode, traceSampler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void createErasureCodingZone(String src)
|
||||||
|
throws IOException {
|
||||||
|
checkOpen();
|
||||||
|
TraceScope scope = getPathTraceScope("createErasureCodingZone", src);
|
||||||
|
try {
|
||||||
|
namenode.createErasureCodingZone(src);
|
||||||
|
} catch (RemoteException re) {
|
||||||
|
throw re.unwrapRemoteException(AccessControlException.class,
|
||||||
|
SafeModeException.class,
|
||||||
|
UnresolvedPathException.class);
|
||||||
|
} finally {
|
||||||
|
scope.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setXAttr(String src, String name, byte[] value,
|
public void setXAttr(String src, String name, byte[] value,
|
||||||
EnumSet<XAttrSetFlag> flag) throws IOException {
|
EnumSet<XAttrSetFlag> flag) throws IOException {
|
||||||
checkOpen();
|
checkOpen();
|
||||||
|
|
|
@ -1362,6 +1362,14 @@ public interface ClientProtocol {
|
||||||
public BatchedEntries<EncryptionZone> listEncryptionZones(
|
public BatchedEntries<EncryptionZone> listEncryptionZones(
|
||||||
long prevId) throws IOException;
|
long prevId) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an erasure coding zone (currently with hardcoded schema)
|
||||||
|
* TODO: Configurable and pluggable schemas (HDFS-7337)
|
||||||
|
*/
|
||||||
|
@Idempotent
|
||||||
|
public void createErasureCodingZone(String src)
|
||||||
|
throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set xattr of a file or directory.
|
* Set xattr of a file or directory.
|
||||||
* The name must be prefixed with the namespace followed by ".". For example,
|
* The name must be prefixed with the namespace followed by ".". For example,
|
||||||
|
|
|
@ -192,6 +192,8 @@ import org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos.Update
|
||||||
import org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos.UpdateBlockForPipelineResponseProto;
|
import org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos.UpdateBlockForPipelineResponseProto;
|
||||||
import org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos.UpdatePipelineRequestProto;
|
import org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos.UpdatePipelineRequestProto;
|
||||||
import org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos.UpdatePipelineResponseProto;
|
import org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos.UpdatePipelineResponseProto;
|
||||||
|
import org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos.CreateErasureCodingZoneRequestProto;
|
||||||
|
import org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos.CreateErasureCodingZoneResponseProto;
|
||||||
import org.apache.hadoop.hdfs.protocol.proto.EncryptionZonesProtos.CreateEncryptionZoneResponseProto;
|
import org.apache.hadoop.hdfs.protocol.proto.EncryptionZonesProtos.CreateEncryptionZoneResponseProto;
|
||||||
import org.apache.hadoop.hdfs.protocol.proto.EncryptionZonesProtos.CreateEncryptionZoneRequestProto;
|
import org.apache.hadoop.hdfs.protocol.proto.EncryptionZonesProtos.CreateEncryptionZoneRequestProto;
|
||||||
import org.apache.hadoop.hdfs.protocol.proto.EncryptionZonesProtos.GetEZForPathResponseProto;
|
import org.apache.hadoop.hdfs.protocol.proto.EncryptionZonesProtos.GetEZForPathResponseProto;
|
||||||
|
@ -1390,6 +1392,18 @@ public class ClientNamenodeProtocolServerSideTranslatorPB implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CreateErasureCodingZoneResponseProto createErasureCodingZone(
|
||||||
|
RpcController controller, CreateErasureCodingZoneRequestProto req)
|
||||||
|
throws ServiceException {
|
||||||
|
try {
|
||||||
|
server.createErasureCodingZone(req.getSrc());
|
||||||
|
return CreateErasureCodingZoneResponseProto.newBuilder().build();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ServiceException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SetXAttrResponseProto setXAttr(RpcController controller,
|
public SetXAttrResponseProto setXAttr(RpcController controller,
|
||||||
SetXAttrRequestProto req) throws ServiceException {
|
SetXAttrRequestProto req) throws ServiceException {
|
||||||
|
|
|
@ -160,6 +160,8 @@ import org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos.Trunca
|
||||||
import org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos.UpdateBlockForPipelineRequestProto;
|
import org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos.UpdateBlockForPipelineRequestProto;
|
||||||
import org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos.UpdatePipelineRequestProto;
|
import org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos.UpdatePipelineRequestProto;
|
||||||
import org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos.SetStoragePolicyRequestProto;
|
import org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos.SetStoragePolicyRequestProto;
|
||||||
|
import org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos.CreateErasureCodingZoneRequestProto;
|
||||||
|
import org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos.CreateErasureCodingZoneResponseProto;
|
||||||
import org.apache.hadoop.hdfs.protocol.proto.EncryptionZonesProtos;
|
import org.apache.hadoop.hdfs.protocol.proto.EncryptionZonesProtos;
|
||||||
import org.apache.hadoop.hdfs.protocol.proto.EncryptionZonesProtos.CreateEncryptionZoneRequestProto;
|
import org.apache.hadoop.hdfs.protocol.proto.EncryptionZonesProtos.CreateEncryptionZoneRequestProto;
|
||||||
import org.apache.hadoop.hdfs.protocol.proto.EncryptionZonesProtos.GetEZForPathRequestProto;
|
import org.apache.hadoop.hdfs.protocol.proto.EncryptionZonesProtos.GetEZForPathRequestProto;
|
||||||
|
@ -1406,6 +1408,20 @@ public class ClientNamenodeProtocolTranslatorPB implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createErasureCodingZone(String src)
|
||||||
|
throws IOException {
|
||||||
|
final CreateErasureCodingZoneRequestProto.Builder builder =
|
||||||
|
CreateErasureCodingZoneRequestProto.newBuilder();
|
||||||
|
builder.setSrc(src);
|
||||||
|
CreateErasureCodingZoneRequestProto req = builder.build();
|
||||||
|
try {
|
||||||
|
rpcProxy.createErasureCodingZone(null, req);
|
||||||
|
} catch (ServiceException e) {
|
||||||
|
throw ProtobufHelper.getRemoteException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setXAttr(String src, XAttr xAttr, EnumSet<XAttrSetFlag> flag)
|
public void setXAttr(String src, XAttr xAttr, EnumSet<XAttrSetFlag> flag)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
|
@ -396,4 +396,6 @@ public interface HdfsServerConstants {
|
||||||
"raw.hdfs.crypto.file.encryption.info";
|
"raw.hdfs.crypto.file.encryption.info";
|
||||||
String SECURITY_XATTR_UNREADABLE_BY_SUPERUSER =
|
String SECURITY_XATTR_UNREADABLE_BY_SUPERUSER =
|
||||||
"security.hdfs.unreadable.by.superuser";
|
"security.hdfs.unreadable.by.superuser";
|
||||||
|
public static final String XATTR_ERASURECODING_ZONE =
|
||||||
|
"raw.hdfs.erasurecoding.zone";
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
/**
|
||||||
|
* 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.hdfs.server.namenode;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import org.apache.hadoop.fs.XAttr;
|
||||||
|
import org.apache.hadoop.fs.XAttrSetFlag;
|
||||||
|
import org.apache.hadoop.hdfs.XAttrHelper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.apache.hadoop.hdfs.server.common.HdfsServerConstants.XATTR_ERASURECODING_ZONE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages the list of erasure coding zones in the filesystem.
|
||||||
|
* <p/>
|
||||||
|
* The ErasureCodingZoneManager has its own lock, but relies on the FSDirectory
|
||||||
|
* lock being held for many operations. The FSDirectory lock should not be
|
||||||
|
* taken if the manager lock is already held.
|
||||||
|
* TODO: consolidate zone logic w/ encrypt. zones {@link EncryptionZoneManager}
|
||||||
|
*/
|
||||||
|
public class ErasureCodingZoneManager {
|
||||||
|
private final FSDirectory dir;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new ErasureCodingZoneManager.
|
||||||
|
*
|
||||||
|
* @param dir Enclosing FSDirectory
|
||||||
|
*/
|
||||||
|
public ErasureCodingZoneManager(FSDirectory dir) {
|
||||||
|
this.dir = dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean getECPolicy(INodesInPath iip) {
|
||||||
|
assert dir.hasReadLock();
|
||||||
|
Preconditions.checkNotNull(iip);
|
||||||
|
List<INode> inodes = iip.getReadOnlyINodes();
|
||||||
|
for (int i = inodes.size() - 1; i >= 0; i--) {
|
||||||
|
final INode inode = inodes.get(i);
|
||||||
|
if (inode == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final List<XAttr> xAttrs = inode.getXAttrFeature() == null ?
|
||||||
|
new ArrayList<XAttr>(0)
|
||||||
|
: inode.getXAttrFeature().getXAttrs();
|
||||||
|
for (XAttr xAttr : xAttrs) {
|
||||||
|
if (XATTR_ERASURECODING_ZONE.equals(XAttrHelper.getPrefixName(xAttr))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
XAttr createErasureCodingZone(String src)
|
||||||
|
throws IOException {
|
||||||
|
assert dir.hasWriteLock();
|
||||||
|
final INodesInPath srcIIP = dir.getINodesInPath4Write(src, false);
|
||||||
|
if (dir.isNonEmptyDirectory(srcIIP)) {
|
||||||
|
throw new IOException(
|
||||||
|
"Attempt to create an erasure coding zone for a " +
|
||||||
|
"non-empty directory.");
|
||||||
|
}
|
||||||
|
if (srcIIP != null &&
|
||||||
|
srcIIP.getLastINode() != null &&
|
||||||
|
!srcIIP.getLastINode().isDirectory()) {
|
||||||
|
throw new IOException("Attempt to create an erasure coding zone " +
|
||||||
|
"for a file.");
|
||||||
|
}
|
||||||
|
if (getECPolicy(srcIIP)) {
|
||||||
|
throw new IOException("Directory " + src + " is already in an " +
|
||||||
|
"erasure coding zone.");
|
||||||
|
}
|
||||||
|
final XAttr ecXAttr = XAttrHelper
|
||||||
|
.buildXAttr(XATTR_ERASURECODING_ZONE, null);
|
||||||
|
final List<XAttr> xattrs = Lists.newArrayListWithCapacity(1);
|
||||||
|
xattrs.add(ecXAttr);
|
||||||
|
FSDirXAttrOp.unprotectedSetXAttrs(dir, src, xattrs,
|
||||||
|
EnumSet.of(XAttrSetFlag.CREATE));
|
||||||
|
return ecXAttr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkMoveValidity(INodesInPath srcIIP, INodesInPath dstIIP, String src)
|
||||||
|
throws IOException {
|
||||||
|
assert dir.hasReadLock();
|
||||||
|
if (getECPolicy(srcIIP)
|
||||||
|
!= getECPolicy(dstIIP)) {
|
||||||
|
throw new IOException(
|
||||||
|
src + " can't be moved because the source and destination have " +
|
||||||
|
"different erasure coding policies.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -185,6 +185,7 @@ class FSDirRenameOp {
|
||||||
}
|
}
|
||||||
|
|
||||||
fsd.ezManager.checkMoveValidity(srcIIP, dstIIP, src);
|
fsd.ezManager.checkMoveValidity(srcIIP, dstIIP, src);
|
||||||
|
fsd.ecZoneManager.checkMoveValidity(srcIIP, dstIIP, src);
|
||||||
// Ensure dst has quota to accommodate rename
|
// Ensure dst has quota to accommodate rename
|
||||||
verifyFsLimitsForRename(fsd, srcIIP, dstIIP);
|
verifyFsLimitsForRename(fsd, srcIIP, dstIIP);
|
||||||
verifyQuotaForRename(fsd, srcIIP, dstIIP);
|
verifyQuotaForRename(fsd, srcIIP, dstIIP);
|
||||||
|
@ -357,6 +358,7 @@ class FSDirRenameOp {
|
||||||
|
|
||||||
BlockStoragePolicySuite bsps = fsd.getBlockStoragePolicySuite();
|
BlockStoragePolicySuite bsps = fsd.getBlockStoragePolicySuite();
|
||||||
fsd.ezManager.checkMoveValidity(srcIIP, dstIIP, src);
|
fsd.ezManager.checkMoveValidity(srcIIP, dstIIP, src);
|
||||||
|
fsd.ecZoneManager.checkMoveValidity(srcIIP, dstIIP, src);
|
||||||
final INode dstInode = dstIIP.getLastINode();
|
final INode dstInode = dstIIP.getLastINode();
|
||||||
List<INodeDirectory> snapshottableDirs = new ArrayList<>();
|
List<INodeDirectory> snapshottableDirs = new ArrayList<>();
|
||||||
if (dstInode != null) { // Destination exists
|
if (dstInode != null) { // Destination exists
|
||||||
|
|
|
@ -42,6 +42,7 @@ import org.apache.hadoop.hdfs.protocol.HdfsFileStatus;
|
||||||
import org.apache.hadoop.hdfs.protocol.LocatedBlock;
|
import org.apache.hadoop.hdfs.protocol.LocatedBlock;
|
||||||
import org.apache.hadoop.hdfs.protocol.QuotaExceededException;
|
import org.apache.hadoop.hdfs.protocol.QuotaExceededException;
|
||||||
import org.apache.hadoop.hdfs.security.token.block.BlockTokenIdentifier;
|
import org.apache.hadoop.hdfs.security.token.block.BlockTokenIdentifier;
|
||||||
|
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfo;
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoContiguous;
|
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoContiguous;
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoContiguousUnderConstruction;
|
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoContiguousUnderConstruction;
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.BlockManager;
|
import org.apache.hadoop.hdfs.server.blockmanagement.BlockManager;
|
||||||
|
@ -482,9 +483,6 @@ class FSDirWriteFileOp {
|
||||||
try {
|
try {
|
||||||
INodesInPath iip = fsd.addINode(existing, newNode);
|
INodesInPath iip = fsd.addINode(existing, newNode);
|
||||||
if (iip != null) {
|
if (iip != null) {
|
||||||
if (newNode.isStriped()) {
|
|
||||||
newNode.addStripedBlocksFeature();
|
|
||||||
}
|
|
||||||
if (aclEntries != null) {
|
if (aclEntries != null) {
|
||||||
AclStorage.updateINodeAcl(newNode, aclEntries, CURRENT_STATE_ID);
|
AclStorage.updateINodeAcl(newNode, aclEntries, CURRENT_STATE_ID);
|
||||||
}
|
}
|
||||||
|
@ -560,9 +558,6 @@ class FSDirWriteFileOp {
|
||||||
fsd.writeLock();
|
fsd.writeLock();
|
||||||
try {
|
try {
|
||||||
newiip = fsd.addINode(existing, newNode);
|
newiip = fsd.addINode(existing, newNode);
|
||||||
if (newiip != null && newNode.isStriped()) {
|
|
||||||
newNode.addStripedBlocksFeature();
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
fsd.writeUnlock();
|
fsd.writeUnlock();
|
||||||
}
|
}
|
||||||
|
@ -610,7 +605,7 @@ class FSDirWriteFileOp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final INodeFile file = fsn.checkLease(src, clientName, inode, fileId);
|
final INodeFile file = fsn.checkLease(src, clientName, inode, fileId);
|
||||||
BlockInfoContiguous lastBlockInFile = file.getLastBlock();
|
BlockInfo lastBlockInFile = file.getLastBlock();
|
||||||
if (!Block.matchingIdAndGenStamp(previousBlock, lastBlockInFile)) {
|
if (!Block.matchingIdAndGenStamp(previousBlock, lastBlockInFile)) {
|
||||||
// The block that the client claims is the current last block
|
// The block that the client claims is the current last block
|
||||||
// doesn't match up with what we think is the last block. There are
|
// doesn't match up with what we think is the last block. There are
|
||||||
|
@ -638,7 +633,7 @@ class FSDirWriteFileOp {
|
||||||
// changed the namesystem state yet.
|
// changed the namesystem state yet.
|
||||||
// We run this analysis again in Part II where case 4 is impossible.
|
// We run this analysis again in Part II where case 4 is impossible.
|
||||||
|
|
||||||
BlockInfoContiguous penultimateBlock = file.getPenultimateBlock();
|
BlockInfo penultimateBlock = file.getPenultimateBlock();
|
||||||
if (previous == null &&
|
if (previous == null &&
|
||||||
lastBlockInFile != null &&
|
lastBlockInFile != null &&
|
||||||
lastBlockInFile.getNumBytes() >= file.getPreferredBlockSize() &&
|
lastBlockInFile.getNumBytes() >= file.getPreferredBlockSize() &&
|
||||||
|
|
|
@ -205,6 +205,9 @@ public class FSDirectory implements Closeable {
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public final EncryptionZoneManager ezManager;
|
public final EncryptionZoneManager ezManager;
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public final ErasureCodingZoneManager ecZoneManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Caches frequently used file names used in {@link INode} to reuse
|
* Caches frequently used file names used in {@link INode} to reuse
|
||||||
* byte[] objects and reduce heap usage.
|
* byte[] objects and reduce heap usage.
|
||||||
|
@ -296,6 +299,7 @@ public class FSDirectory implements Closeable {
|
||||||
namesystem = ns;
|
namesystem = ns;
|
||||||
this.editLog = ns.getEditLog();
|
this.editLog = ns.getEditLog();
|
||||||
ezManager = new EncryptionZoneManager(this, conf);
|
ezManager = new EncryptionZoneManager(this, conf);
|
||||||
|
ecZoneManager = new ErasureCodingZoneManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
FSNamesystem getFSNamesystem() {
|
FSNamesystem getFSNamesystem() {
|
||||||
|
@ -1221,6 +1225,25 @@ public class FSDirectory implements Closeable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XAttr createErasureCodingZone(String src)
|
||||||
|
throws IOException {
|
||||||
|
writeLock();
|
||||||
|
try {
|
||||||
|
return ecZoneManager.createErasureCodingZone(src);
|
||||||
|
} finally {
|
||||||
|
writeUnlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getECPolicy(INodesInPath iip) {
|
||||||
|
readLock();
|
||||||
|
try {
|
||||||
|
return ecZoneManager.getECPolicy(iip);
|
||||||
|
} finally {
|
||||||
|
readUnlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static INode resolveLastINode(INodesInPath iip) throws FileNotFoundException {
|
static INode resolveLastINode(INodesInPath iip) throws FileNotFoundException {
|
||||||
INode inode = iip.getLastINode();
|
INode inode = iip.getLastINode();
|
||||||
if (inode == null) {
|
if (inode == null) {
|
||||||
|
|
|
@ -7510,6 +7510,46 @@ public class FSNamesystem implements Namesystem, FSNamesystemMBean,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an erasure coding zone on directory src.
|
||||||
|
*
|
||||||
|
* @param src the path of a directory which will be the root of the
|
||||||
|
* erasure coding zone. The directory must be empty.
|
||||||
|
* @throws AccessControlException if the caller is not the superuser.
|
||||||
|
* @throws UnresolvedLinkException if the path can't be resolved.
|
||||||
|
* @throws SafeModeException if the Namenode is in safe mode.
|
||||||
|
*/
|
||||||
|
void createErasureCodingZone(final String srcArg,
|
||||||
|
final boolean logRetryCache)
|
||||||
|
throws IOException, UnresolvedLinkException,
|
||||||
|
SafeModeException, AccessControlException {
|
||||||
|
String src = srcArg;
|
||||||
|
HdfsFileStatus resultingStat = null;
|
||||||
|
checkSuperuserPrivilege();
|
||||||
|
checkOperation(OperationCategory.WRITE);
|
||||||
|
final byte[][] pathComponents =
|
||||||
|
FSDirectory.getPathComponentsForReservedPath(src);
|
||||||
|
FSPermissionChecker pc = getPermissionChecker();
|
||||||
|
writeLock();
|
||||||
|
try {
|
||||||
|
checkSuperuserPrivilege();
|
||||||
|
checkOperation(OperationCategory.WRITE);
|
||||||
|
checkNameNodeSafeMode("Cannot create erasure coding zone on " + src);
|
||||||
|
src = dir.resolvePath(pc, src, pathComponents);
|
||||||
|
|
||||||
|
final XAttr ecXAttr = dir.createErasureCodingZone(src);
|
||||||
|
List<XAttr> xAttrs = Lists.newArrayListWithCapacity(1);
|
||||||
|
xAttrs.add(ecXAttr);
|
||||||
|
getEditLog().logSetXAttrs(src, xAttrs, logRetryCache);
|
||||||
|
final INodesInPath iip = dir.getINodesInPath4Write(src, false);
|
||||||
|
resultingStat = dir.getAuditFileInfo(iip);
|
||||||
|
} finally {
|
||||||
|
writeUnlock();
|
||||||
|
}
|
||||||
|
getEditLog().logSync();
|
||||||
|
logAuditEvent(true, "createErasureCodingZone", srcArg, null, resultingStat);
|
||||||
|
}
|
||||||
|
|
||||||
void setXAttr(String src, XAttr xAttr, EnumSet<XAttrSetFlag> flag,
|
void setXAttr(String src, XAttr xAttr, EnumSet<XAttrSetFlag> flag,
|
||||||
boolean logRetryCache)
|
boolean logRetryCache)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
|
@ -420,7 +420,7 @@ public class INodeFile extends INodeWithAdditionalFields
|
||||||
}
|
}
|
||||||
max = maxInSnapshot > max ? maxInSnapshot : max;
|
max = maxInSnapshot > max ? maxInSnapshot : max;
|
||||||
}
|
}
|
||||||
return isStriped()?
|
return isStriped() ?
|
||||||
HdfsConstants.NUM_DATA_BLOCKS + HdfsConstants.NUM_PARITY_BLOCKS : max;
|
HdfsConstants.NUM_DATA_BLOCKS + HdfsConstants.NUM_PARITY_BLOCKS : max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1114,8 +1114,7 @@ public class INodeFile extends INodeWithAdditionalFields
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@Override
|
@Override
|
||||||
// TODO: move erasure coding policy to file XAttr
|
|
||||||
public boolean isStriped() {
|
public boolean isStriped() {
|
||||||
return getStoragePolicyID() == HdfsConstants.EC_STORAGE_POLICY_ID;
|
return getStripedBlocksFeature() != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1820,6 +1820,22 @@ class NameNodeRpcServer implements NamenodeProtocols {
|
||||||
return namesystem.listEncryptionZones(prevId);
|
return namesystem.listEncryptionZones(prevId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override // ClientProtocol
|
||||||
|
public void createErasureCodingZone(String src)
|
||||||
|
throws IOException {
|
||||||
|
checkNNStartup();
|
||||||
|
final CacheEntry cacheEntry = RetryCache.waitForCompletion(retryCache);
|
||||||
|
if (cacheEntry != null && cacheEntry.isSuccess()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
boolean success = false;
|
||||||
|
try {
|
||||||
|
namesystem.createErasureCodingZone(src, cacheEntry != null);
|
||||||
|
} finally {
|
||||||
|
RetryCache.setState(cacheEntry, success);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override // ClientProtocol
|
@Override // ClientProtocol
|
||||||
public void setXAttr(String src, XAttr xAttr, EnumSet<XAttrSetFlag> flag)
|
public void setXAttr(String src, XAttr xAttr, EnumSet<XAttrSetFlag> flag)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
|
@ -714,6 +714,13 @@ message GetEditsFromTxidResponseProto {
|
||||||
required EventsListProto eventsList = 1;
|
required EventsListProto eventsList = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message CreateErasureCodingZoneRequestProto {
|
||||||
|
required string src = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CreateErasureCodingZoneResponseProto {
|
||||||
|
}
|
||||||
|
|
||||||
service ClientNamenodeProtocol {
|
service ClientNamenodeProtocol {
|
||||||
rpc getBlockLocations(GetBlockLocationsRequestProto)
|
rpc getBlockLocations(GetBlockLocationsRequestProto)
|
||||||
returns(GetBlockLocationsResponseProto);
|
returns(GetBlockLocationsResponseProto);
|
||||||
|
@ -856,6 +863,8 @@ service ClientNamenodeProtocol {
|
||||||
returns(ListEncryptionZonesResponseProto);
|
returns(ListEncryptionZonesResponseProto);
|
||||||
rpc getEZForPath(GetEZForPathRequestProto)
|
rpc getEZForPath(GetEZForPathRequestProto)
|
||||||
returns(GetEZForPathResponseProto);
|
returns(GetEZForPathResponseProto);
|
||||||
|
rpc createErasureCodingZone(CreateErasureCodingZoneRequestProto)
|
||||||
|
returns(CreateErasureCodingZoneResponseProto);
|
||||||
rpc getCurrentEditLogTxid(GetCurrentEditLogTxidRequestProto)
|
rpc getCurrentEditLogTxid(GetCurrentEditLogTxidRequestProto)
|
||||||
returns(GetCurrentEditLogTxidResponseProto);
|
returns(GetCurrentEditLogTxidResponseProto);
|
||||||
rpc getEditsFromTxid(GetEditsFromTxidRequestProto)
|
rpc getEditsFromTxid(GetEditsFromTxidRequestProto)
|
||||||
|
|
|
@ -119,9 +119,6 @@ public class TestBlockStoragePolicy {
|
||||||
expectedPolicyStrings.put(COLD,
|
expectedPolicyStrings.put(COLD,
|
||||||
"BlockStoragePolicy{COLD:" + COLD + ", storageTypes=[ARCHIVE], " +
|
"BlockStoragePolicy{COLD:" + COLD + ", storageTypes=[ARCHIVE], " +
|
||||||
"creationFallbacks=[], replicationFallbacks=[]}");
|
"creationFallbacks=[], replicationFallbacks=[]}");
|
||||||
expectedPolicyStrings.put(EC,
|
|
||||||
"BlockStoragePolicy{EC:" + EC + ", storageTypes=[DISK], " +
|
|
||||||
"creationFallbacks=[], replicationFallbacks=[ARCHIVE]}");
|
|
||||||
expectedPolicyStrings.put(WARM,
|
expectedPolicyStrings.put(WARM,
|
||||||
"BlockStoragePolicy{WARM:" + WARM + ", storageTypes=[DISK, ARCHIVE], " +
|
"BlockStoragePolicy{WARM:" + WARM + ", storageTypes=[DISK, ARCHIVE], " +
|
||||||
"creationFallbacks=[DISK, ARCHIVE], " +
|
"creationFallbacks=[DISK, ARCHIVE], " +
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
/**
|
||||||
|
* 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.hdfs;
|
||||||
|
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.fs.Path;
|
||||||
|
import org.apache.hadoop.fs.permission.FsPermission;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.FSNamesystem;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.INode;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static org.apache.hadoop.test.GenericTestUtils.assertExceptionContains;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
public class TestErasureCodingZones {
|
||||||
|
private final int NUM_OF_DATANODES = 3;
|
||||||
|
private Configuration conf;
|
||||||
|
private MiniDFSCluster cluster;
|
||||||
|
private DistributedFileSystem fs;
|
||||||
|
private static final int BLOCK_SIZE = 1024;
|
||||||
|
private FSNamesystem namesystem;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setupCluster() throws IOException {
|
||||||
|
conf = new HdfsConfiguration();
|
||||||
|
conf.setInt(DFSConfigKeys.DFS_BLOCK_SIZE_KEY, BLOCK_SIZE);
|
||||||
|
cluster = new MiniDFSCluster.Builder(conf).
|
||||||
|
numDataNodes(NUM_OF_DATANODES).build();
|
||||||
|
cluster.waitActive();
|
||||||
|
fs = cluster.getFileSystem();
|
||||||
|
namesystem = cluster.getNamesystem();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void shutdownCluster() throws IOException {
|
||||||
|
cluster.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateECZone()
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
final Path testDir = new Path("/ec");
|
||||||
|
fs.mkdir(testDir, FsPermission.getDirDefault());
|
||||||
|
|
||||||
|
/* Normal creation of an erasure coding zone */
|
||||||
|
fs.getClient().createErasureCodingZone(testDir.toString());
|
||||||
|
|
||||||
|
/* Verify files under the zone are striped */
|
||||||
|
final Path ECFilePath = new Path(testDir, "foo");
|
||||||
|
fs.create(ECFilePath);
|
||||||
|
INode inode = namesystem.getFSDirectory().getINode(ECFilePath.toString());
|
||||||
|
assertTrue(inode.asFile().isStriped());
|
||||||
|
|
||||||
|
/* Verify that EC zone cannot be created on non-empty dir */
|
||||||
|
final Path notEmpty = new Path("/nonEmpty");
|
||||||
|
fs.mkdir(notEmpty, FsPermission.getDirDefault());
|
||||||
|
fs.create(new Path(notEmpty, "foo"));
|
||||||
|
try {
|
||||||
|
fs.getClient().createErasureCodingZone(notEmpty.toString());
|
||||||
|
fail("Erasure coding zone on non-empty dir");
|
||||||
|
} catch (IOException e) {
|
||||||
|
assertExceptionContains("erasure coding zone for a non-empty directory", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify that nested EC zones cannot be created */
|
||||||
|
final Path zone1 = new Path("/zone1");
|
||||||
|
final Path zone2 = new Path(zone1, "zone2");
|
||||||
|
fs.mkdir(zone1, FsPermission.getDirDefault());
|
||||||
|
fs.getClient().createErasureCodingZone(zone1.toString());
|
||||||
|
fs.mkdir(zone2, FsPermission.getDirDefault());
|
||||||
|
try {
|
||||||
|
fs.getClient().createErasureCodingZone(zone2.toString());
|
||||||
|
fail("Nested erasure coding zones");
|
||||||
|
} catch (IOException e) {
|
||||||
|
assertExceptionContains("already in an erasure coding zone", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify that EC zone cannot be created on a file */
|
||||||
|
final Path fPath = new Path("/file");
|
||||||
|
fs.create(fPath);
|
||||||
|
try {
|
||||||
|
fs.getClient().createErasureCodingZone(fPath.toString());
|
||||||
|
fail("Erasure coding zone on file");
|
||||||
|
} catch (IOException e) {
|
||||||
|
assertExceptionContains("erasure coding zone for a file", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMoveValidity() throws IOException, InterruptedException {
|
||||||
|
final Path srcECDir = new Path("/srcEC");
|
||||||
|
final Path dstECDir = new Path("/dstEC");
|
||||||
|
fs.mkdir(srcECDir, FsPermission.getDirDefault());
|
||||||
|
fs.mkdir(dstECDir, FsPermission.getDirDefault());
|
||||||
|
fs.getClient().createErasureCodingZone(srcECDir.toString());
|
||||||
|
fs.getClient().createErasureCodingZone(dstECDir.toString());
|
||||||
|
final Path srcFile = new Path(srcECDir, "foo");
|
||||||
|
fs.create(srcFile);
|
||||||
|
|
||||||
|
/* Verify that a file can be moved between 2 EC zones */
|
||||||
|
try {
|
||||||
|
fs.rename(srcFile, dstECDir);
|
||||||
|
} catch (IOException e) {
|
||||||
|
fail("A file should be able to move between 2 EC zones " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the file back
|
||||||
|
fs.rename(new Path(dstECDir, "foo"), srcECDir);
|
||||||
|
|
||||||
|
/* Verify that a file cannot be moved from a non-EC dir to an EC zone */
|
||||||
|
final Path nonECDir = new Path("/nonEC");
|
||||||
|
fs.mkdir(nonECDir, FsPermission.getDirDefault());
|
||||||
|
try {
|
||||||
|
fs.rename(srcFile, nonECDir);
|
||||||
|
fail("A file shouldn't be able to move from a non-EC dir to an EC zone");
|
||||||
|
} catch (IOException e) {
|
||||||
|
assertExceptionContains("can't be moved because the source and " +
|
||||||
|
"destination have different erasure coding policies", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify that a file cannot be moved from an EC zone to a non-EC dir */
|
||||||
|
final Path nonECFile = new Path(nonECDir, "nonECFile");
|
||||||
|
fs.create(nonECFile);
|
||||||
|
try {
|
||||||
|
fs.rename(nonECFile, dstECDir);
|
||||||
|
} catch (IOException e) {
|
||||||
|
assertExceptionContains("can't be moved because the source and " +
|
||||||
|
"destination have different erasure coding policies", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,75 +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.hdfs.server.blockmanagement;
|
|
||||||
|
|
||||||
import org.apache.hadoop.conf.Configuration;
|
|
||||||
import org.apache.hadoop.fs.Path;
|
|
||||||
import org.apache.hadoop.fs.permission.FsPermission;
|
|
||||||
import org.apache.hadoop.hdfs.*;
|
|
||||||
import org.apache.hadoop.hdfs.client.HdfsAdmin;
|
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSNamesystem;
|
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INode;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import static org.apache.hadoop.hdfs.protocol.HdfsConstants.EC_STORAGE_POLICY_NAME;
|
|
||||||
import static org.apache.hadoop.hdfs.protocol.HdfsConstants.EC_STORAGE_POLICY_ID;
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
public class TestBlockInitialEncoding {
|
|
||||||
private final int NUM_OF_DATANODES = 3;
|
|
||||||
private Configuration conf;
|
|
||||||
private MiniDFSCluster cluster;
|
|
||||||
private DistributedFileSystem fs;
|
|
||||||
private static final int BLOCK_SIZE = 1024;
|
|
||||||
private HdfsAdmin dfsAdmin;
|
|
||||||
private FSNamesystem namesystem;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setupCluster() throws IOException {
|
|
||||||
conf = new HdfsConfiguration();
|
|
||||||
conf.setInt(DFSConfigKeys.DFS_BLOCK_SIZE_KEY, BLOCK_SIZE);
|
|
||||||
cluster = new MiniDFSCluster.Builder(conf).
|
|
||||||
numDataNodes(NUM_OF_DATANODES).build();
|
|
||||||
cluster.waitActive();
|
|
||||||
fs = cluster.getFileSystem();
|
|
||||||
dfsAdmin = new HdfsAdmin(cluster.getURI(), conf);
|
|
||||||
namesystem = cluster.getNamesystem();
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void shutdownCluster() throws IOException {
|
|
||||||
cluster.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testBlockInitialEncoding()
|
|
||||||
throws IOException, InterruptedException {
|
|
||||||
final Path testDir = new Path("/test");
|
|
||||||
fs.mkdir(testDir, FsPermission.getDirDefault());
|
|
||||||
dfsAdmin.setStoragePolicy(testDir, EC_STORAGE_POLICY_NAME);
|
|
||||||
final Path ECFilePath = new Path("/test/foo.ec");
|
|
||||||
DFSTestUtil.createFile(fs, ECFilePath, 4 * BLOCK_SIZE, (short) 3, 0);
|
|
||||||
INode inode = namesystem.getFSDirectory().getINode(ECFilePath.toString());
|
|
||||||
assertEquals(EC_STORAGE_POLICY_ID, inode.getStoragePolicyID());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -68,7 +68,7 @@ public class TestAddStripedBlocks {
|
||||||
.numDataNodes(GROUP_SIZE).build();
|
.numDataNodes(GROUP_SIZE).build();
|
||||||
cluster.waitActive();
|
cluster.waitActive();
|
||||||
dfs = cluster.getFileSystem();
|
dfs = cluster.getFileSystem();
|
||||||
dfs.setStoragePolicy(new Path("/"), HdfsConstants.EC_STORAGE_POLICY_NAME);
|
dfs.getClient().createErasureCodingZone("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|
|
@ -445,8 +445,7 @@ public class TestFSEditLogLoader {
|
||||||
|
|
||||||
//set the storage policy of the directory
|
//set the storage policy of the directory
|
||||||
fs.mkdir(new Path(testDir), new FsPermission("755"));
|
fs.mkdir(new Path(testDir), new FsPermission("755"));
|
||||||
fs.setStoragePolicy(new Path(testDir),
|
fs.getClient().getNamenode().createErasureCodingZone(testDir);
|
||||||
HdfsConstants.EC_STORAGE_POLICY_NAME);
|
|
||||||
|
|
||||||
// Create a file with striped block
|
// Create a file with striped block
|
||||||
Path p = new Path(testFilePath);
|
Path p = new Path(testFilePath);
|
||||||
|
@ -518,8 +517,7 @@ public class TestFSEditLogLoader {
|
||||||
|
|
||||||
//set the storage policy of the directory
|
//set the storage policy of the directory
|
||||||
fs.mkdir(new Path(testDir), new FsPermission("755"));
|
fs.mkdir(new Path(testDir), new FsPermission("755"));
|
||||||
fs.setStoragePolicy(new Path(testDir),
|
fs.getClient().getNamenode().createErasureCodingZone(testDir);
|
||||||
HdfsConstants.EC_STORAGE_POLICY_NAME);
|
|
||||||
|
|
||||||
//create a file with striped blocks
|
//create a file with striped blocks
|
||||||
Path p = new Path(testFilePath);
|
Path p = new Path(testFilePath);
|
||||||
|
|
|
@ -33,18 +33,14 @@ import java.io.IOException;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
|
||||||
import org.apache.hadoop.hdfs.protocol.Block;
|
import org.apache.hadoop.hdfs.protocol.Block;
|
||||||
import org.apache.hadoop.hdfs.protocol.BlockStoragePolicy;
|
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfo;
|
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfo;
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoContiguous;
|
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoContiguous;
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoStriped;
|
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoStriped;
|
||||||
import org.apache.hadoop.hdfs.server.common.HdfsServerConstants;
|
|
||||||
import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.StartupOption;
|
import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.StartupOption;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
|
||||||
import org.apache.hadoop.fs.permission.PermissionStatus;
|
import org.apache.hadoop.fs.permission.PermissionStatus;
|
||||||
import org.apache.hadoop.fs.permission.FsPermission;
|
import org.apache.hadoop.fs.permission.FsPermission;
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoContiguous;
|
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoStriped;
|
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.fs.FSDataOutputStream;
|
import org.apache.hadoop.fs.FSDataOutputStream;
|
||||||
import org.apache.hadoop.fs.FileSystem;
|
import org.apache.hadoop.fs.FileSystem;
|
||||||
|
@ -59,7 +55,6 @@ import org.apache.hadoop.hdfs.MiniDFSCluster;
|
||||||
import org.apache.hadoop.hdfs.client.HdfsDataOutputStream.SyncFlag;
|
import org.apache.hadoop.hdfs.client.HdfsDataOutputStream.SyncFlag;
|
||||||
import org.apache.hadoop.hdfs.protocol.HdfsConstants;
|
import org.apache.hadoop.hdfs.protocol.HdfsConstants;
|
||||||
import org.apache.hadoop.hdfs.protocol.HdfsConstants.SafeModeAction;
|
import org.apache.hadoop.hdfs.protocol.HdfsConstants.SafeModeAction;
|
||||||
import org.apache.hadoop.hdfs.protocol.Block;
|
|
||||||
import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.BlockUCState;
|
import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.BlockUCState;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.LeaseManager.Lease;
|
import org.apache.hadoop.hdfs.server.namenode.LeaseManager.Lease;
|
||||||
import org.apache.hadoop.hdfs.util.MD5FileUtils;
|
import org.apache.hadoop.hdfs.util.MD5FileUtils;
|
||||||
|
@ -137,9 +132,10 @@ public class TestFSImage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testSaveAndLoadINodeFile(FSNamesystem fsn, Configuration conf,
|
private void testSaveAndLoadStripedINodeFile(FSNamesystem fsn, Configuration conf,
|
||||||
boolean isUC) throws IOException{
|
boolean isUC) throws IOException{
|
||||||
// contruct a INode with StripedBlock for saving and loading
|
// contruct a INode with StripedBlock for saving and loading
|
||||||
|
fsn.createErasureCodingZone("/", false);
|
||||||
long id = 123456789;
|
long id = 123456789;
|
||||||
byte[] name = "testSaveAndLoadInodeFile_testfile".getBytes();
|
byte[] name = "testSaveAndLoadInodeFile_testfile".getBytes();
|
||||||
PermissionStatus permissionStatus = new PermissionStatus("testuser_a",
|
PermissionStatus permissionStatus = new PermissionStatus("testuser_a",
|
||||||
|
@ -149,9 +145,8 @@ public class TestFSImage {
|
||||||
BlockInfoContiguous[] blks = new BlockInfoContiguous[0];
|
BlockInfoContiguous[] blks = new BlockInfoContiguous[0];
|
||||||
short replication = 3;
|
short replication = 3;
|
||||||
long preferredBlockSize = 128*1024*1024;
|
long preferredBlockSize = 128*1024*1024;
|
||||||
byte storagePolicyID = HdfsConstants.EC_STORAGE_POLICY_ID;
|
|
||||||
INodeFile file = new INodeFile(id, name, permissionStatus, mtime, atime,
|
INodeFile file = new INodeFile(id, name, permissionStatus, mtime, atime,
|
||||||
blks, replication, preferredBlockSize, storagePolicyID);
|
blks, replication, preferredBlockSize);
|
||||||
ByteArrayOutputStream bs = new ByteArrayOutputStream();
|
ByteArrayOutputStream bs = new ByteArrayOutputStream();
|
||||||
file.addStripedBlocksFeature();
|
file.addStripedBlocksFeature();
|
||||||
|
|
||||||
|
@ -237,13 +232,13 @@ public class TestFSImage {
|
||||||
* FSImageSerialization and loaded by FSImageFormat#Loader.
|
* FSImageSerialization and loaded by FSImageFormat#Loader.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testSaveAndLoadInodeFile() throws IOException{
|
public void testSaveAndLoadStripedINodeFile() throws IOException{
|
||||||
Configuration conf = new Configuration();
|
Configuration conf = new Configuration();
|
||||||
MiniDFSCluster cluster = null;
|
MiniDFSCluster cluster = null;
|
||||||
try {
|
try {
|
||||||
cluster = new MiniDFSCluster.Builder(conf).build();
|
cluster = new MiniDFSCluster.Builder(conf).build();
|
||||||
cluster.waitActive();
|
cluster.waitActive();
|
||||||
testSaveAndLoadINodeFile(cluster.getNamesystem(), conf, false);
|
testSaveAndLoadStripedINodeFile(cluster.getNamesystem(), conf, false);
|
||||||
} finally {
|
} finally {
|
||||||
if (cluster != null) {
|
if (cluster != null) {
|
||||||
cluster.shutdown();
|
cluster.shutdown();
|
||||||
|
@ -256,14 +251,14 @@ public class TestFSImage {
|
||||||
* saved and loaded by FSImageSerialization
|
* saved and loaded by FSImageSerialization
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testSaveAndLoadInodeFileUC() throws IOException{
|
public void testSaveAndLoadStripedINodeFileUC() throws IOException{
|
||||||
// construct a INode with StripedBlock for saving and loading
|
// construct a INode with StripedBlock for saving and loading
|
||||||
Configuration conf = new Configuration();
|
Configuration conf = new Configuration();
|
||||||
MiniDFSCluster cluster = null;
|
MiniDFSCluster cluster = null;
|
||||||
try {
|
try {
|
||||||
cluster = new MiniDFSCluster.Builder(conf).build();
|
cluster = new MiniDFSCluster.Builder(conf).build();
|
||||||
cluster.waitActive();
|
cluster.waitActive();
|
||||||
testSaveAndLoadINodeFile(cluster.getNamesystem(), conf, true);
|
testSaveAndLoadStripedINodeFile(cluster.getNamesystem(), conf, true);
|
||||||
} finally {
|
} finally {
|
||||||
if (cluster != null) {
|
if (cluster != null) {
|
||||||
cluster.shutdown();
|
cluster.shutdown();
|
||||||
|
@ -402,7 +397,7 @@ public class TestFSImage {
|
||||||
.build();
|
.build();
|
||||||
cluster.waitActive();
|
cluster.waitActive();
|
||||||
DistributedFileSystem fs = cluster.getFileSystem();
|
DistributedFileSystem fs = cluster.getFileSystem();
|
||||||
fs.setStoragePolicy(new Path("/"), HdfsConstants.EC_STORAGE_POLICY_NAME);
|
fs.getClient().getNamenode().createErasureCodingZone("/");
|
||||||
Path file = new Path("/striped");
|
Path file = new Path("/striped");
|
||||||
FSDataOutputStream out = fs.create(file);
|
FSDataOutputStream out = fs.create(file);
|
||||||
byte[] bytes = DFSTestUtil.generateSequentialBytes(0, BLOCK_SIZE);
|
byte[] bytes = DFSTestUtil.generateSequentialBytes(0, BLOCK_SIZE);
|
||||||
|
|
|
@ -27,7 +27,6 @@ import org.apache.hadoop.hdfs.HdfsConfiguration;
|
||||||
import org.apache.hadoop.hdfs.MiniDFSCluster;
|
import org.apache.hadoop.hdfs.MiniDFSCluster;
|
||||||
import org.apache.hadoop.hdfs.protocol.Block;
|
import org.apache.hadoop.hdfs.protocol.Block;
|
||||||
import org.apache.hadoop.hdfs.protocol.ExtendedBlock;
|
import org.apache.hadoop.hdfs.protocol.ExtendedBlock;
|
||||||
import org.apache.hadoop.hdfs.client.HdfsAdmin;
|
|
||||||
import org.apache.hadoop.hdfs.protocol.HdfsConstants;
|
import org.apache.hadoop.hdfs.protocol.HdfsConstants;
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfo;
|
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfo;
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoStriped;
|
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoStriped;
|
||||||
|
@ -37,23 +36,19 @@ import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeDescriptor;
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeDescriptor.BlockECRecoveryInfo;
|
import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeDescriptor.BlockECRecoveryInfo;
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeStorageInfo;
|
import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeStorageInfo;
|
||||||
import org.apache.hadoop.hdfs.server.datanode.DataNode;
|
import org.apache.hadoop.hdfs.server.datanode.DataNode;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSNamesystem;
|
|
||||||
import org.apache.hadoop.hdfs.server.protocol.DatanodeStorage;
|
import org.apache.hadoop.hdfs.server.protocol.DatanodeStorage;
|
||||||
import org.apache.hadoop.hdfs.server.protocol.ReceivedDeletedBlockInfo;
|
import org.apache.hadoop.hdfs.server.protocol.ReceivedDeletedBlockInfo;
|
||||||
import org.apache.hadoop.hdfs.server.protocol.StorageReceivedDeletedBlocks;
|
import org.apache.hadoop.hdfs.server.protocol.StorageReceivedDeletedBlocks;
|
||||||
import org.apache.hadoop.io.IOUtils;
|
import org.apache.hadoop.io.IOUtils;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static org.apache.hadoop.hdfs.protocol.HdfsConstants.BLOCK_STRIPED_CHUNK_SIZE;
|
import static org.apache.hadoop.hdfs.protocol.HdfsConstants.BLOCK_STRIPED_CHUNK_SIZE;
|
||||||
import static org.apache.hadoop.hdfs.protocol.HdfsConstants.EC_STORAGE_POLICY_NAME;
|
|
||||||
import static org.apache.hadoop.hdfs.protocol.HdfsConstants.NUM_DATA_BLOCKS;
|
import static org.apache.hadoop.hdfs.protocol.HdfsConstants.NUM_DATA_BLOCKS;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
@ -93,7 +88,7 @@ public class TestRecoverStripedBlocks {
|
||||||
int numBlocks) throws Exception {
|
int numBlocks) throws Exception {
|
||||||
DistributedFileSystem dfs = cluster.getFileSystem();
|
DistributedFileSystem dfs = cluster.getFileSystem();
|
||||||
dfs.mkdirs(dir);
|
dfs.mkdirs(dir);
|
||||||
dfs.setStoragePolicy(dir, EC_STORAGE_POLICY_NAME);
|
dfs.getClient().getNamenode().createErasureCodingZone(dir.toString());
|
||||||
|
|
||||||
FSDataOutputStream out = null;
|
FSDataOutputStream out = null;
|
||||||
try {
|
try {
|
||||||
|
|
Loading…
Reference in New Issue