断点调试
[hadoop@hadoop1 hadoop]$ hdfs ec -setPolicy -path /ec1 -policy RS-3-2-1024k
源码如下:
//FSDirErasureCodingOp#setErasureCodingPolicy
static FileStatus setErasureCodingPolicy(final FSNamesystem fsn,
final String srcArg, final String ecPolicyName,
final FSPermissionChecker pc, final boolean logRetryCache)
throws IOException, AccessControlException {
assert fsn.hasWriteLock();
String src = srcArg;
FSDirectory fsd = fsn.getFSDirectory();
final INodesInPath iip;
List<XAttr> xAttrs;
fsd.writeLock();
try {
ErasureCodingPolicy ecPolicy = getErasureCodingPolicyByName(fsn,
ecPolicyName);
iip = fsd.resolvePath(pc, src, DirOp.WRITE_LINK);
// Write access is required to set erasure coding policy
if (fsd.isPermissionEnabled()) {
fsd.checkPathAccess(pc, iip, FsAction.WRITE);
}
src = iip.getPath();
xAttrs = setErasureCodingPolicyXAttr(fsn, iip, ecPolicy);
} finally {
fsd.writeUnlock();
}
fsn.getEditLog().logSetXAttrs(src, xAttrs, logRetryCache);
return fsd.getAuditFileInfo(iip);
}
可以看到,主要流程:
根据名称解析到ec策略 --> 获得iip --> 在iip上设置特性 --> 记录到editlog
调试如下:
通过ec名称解析到的ECPolicy:
通过path获得INodeInPath:iip
INodesInPath: path = /ec1
inodes = [, ec1], length=2
isSnapshot = false
snapshotId = 2147483646
srcPath 和 iip 之间可以相互转化。
进入setErasureCodingPolicyXAttr
代码:
private static List<XAttr> setErasureCodingPolicyXAttr(final FSNamesystem fsn,
final INodesInPath srcIIP, ErasureCodingPolicy ecPolicy) throws IOException {
FSDirectory fsd = fsn.getFSDirectory();
assert fsd.hasWriteLock();
Preconditions.checkNotNull(srcIIP, "INodes cannot be null");
Preconditions.checkNotNull(ecPolicy, "EC policy cannot be null");
String src = srcIIP.getPath();
//从iip中得到最后一个node节点,设置属性实则设置在最后一个节点上
final INode inode = srcIIP.getLastINode();
if (inode == null) {
throw new FileNotFoundException("Path not found: " + srcIIP.getPath());
}
if (!inode.isDirectory()) {
throw new IOException("Attempt to set an erasure coding policy " +
"for a file " + src);
}
final XAttr ecXAttr;
DataOutputStream dOut = null;
try {
//这里关键 通过名称转化为XATTR
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
dOut = new DataOutputStream(bOut);
WritableUtils.writeString(dOut, ecPolicy.getName());
ecXAttr = XAttrHelper.buildXAttr(XATTR_ERASURECODING_POLICY,
bOut.toByteArray());
} finally {
IOUtils.closeStream(dOut);
}
// check whether the directory already has an erasure coding policy
// directly on itself.
final Boolean hasEcXAttr =
getErasureCodingPolicyXAttrForINode(fsn, inode) == null ? false : true;
final List<XAttr> xattrs = Lists.newArrayListWithCapacity(1);
xattrs.add(ecXAttr);
final EnumSet<XAttrSetFlag> flag = hasEcXAttr ?
EnumSet.of(XAttrSetFlag.REPLACE) : EnumSet.of(XAttrSetFlag.CREATE);
FSDirXAttrOp.unprotectedSetXAttrs(fsd, srcIIP, xattrs, flag);
return xattrs;
}
INode的属性是INodeDirectory:
新加入的XAttr内容为:
XAttr [ns=SYSTEM, name=hdfs.erasurecoding.policy, value=[0, 0, 0, 12, 82, 83, 45, 51, 45, 50, 45, 49, 48, 50, 52, 107]]
检查inode是否已经设置了其他EC属性。如果没有,这给创建标识;如果有,则给替换标识。
final Boolean hasEcXAttr =
getErasureCodingPolicyXAttrForINode(fsn, inode) == null ? false : true;
final List<XAttr> xattrs = Lists.newArrayListWithCapacity(1);
xattrs.add(ecXAttr);
final EnumSet<XAttrSetFlag> flag = hasEcXAttr ?
EnumSet.of(XAttrSetFlag.REPLACE) : EnumSet.of(XAttrSetFlag.CREATE);
FSDirXAttrOp.unprotectedSetXAttrs(fsd, srcIIP, xattrs, flag);
return xattrs;
设置属性 FSDirXAttrOp.unprotectedSetXAttrs(fsd, srcIIP, xattrs, flag);
代码如下:
static INode unprotectedSetXAttrs(
FSDirectory fsd, final INodesInPath iip, final List<XAttr> xAttrs,
final EnumSet<XAttrSetFlag> flag)
throws IOException {
assert fsd.hasWriteLock();
INode inode = FSDirectory.resolveLastINode(iip);
//查询这个节点已经存在的扩展特性
List<XAttr> existingXAttrs = XAttrStorage.readINodeXAttrs(inode);
List<XAttr> newXAttrs = setINodeXAttrs(fsd, existingXAttrs, xAttrs, flag);
final boolean isFile = inode.isFile();
//遍历每个属性
for (XAttr xattr : newXAttrs) {
final String xaName = XAttrHelper.getPrefixedName(xattr);
/*
* If we're adding the encryption zone xattr, then add src to the list
* of encryption zones.
*/
//如果是ozone相关额外做些工作
if (CRYPTO_XATTR_ENCRYPTION_ZONE.equals(xaName)) {
final HdfsProtos.ZoneEncryptionInfoProto ezProto =
HdfsProtos.ZoneEncryptionInfoProto.parseFrom(xattr.getValue());
fsd.ezManager.addEncryptionZone(inode.getId(),
PBHelperClient.convert(ezProto.getSuite()),
PBHelperClient.convert(ezProto.getCryptoProtocolVersion()),
ezProto.getKeyName());
if (ezProto.hasReencryptionProto()) {
ReencryptionInfoProto reProto = ezProto.getReencryptionProto();
fsd.ezManager.getReencryptionStatus()
.updateZoneStatus(inode.getId(), iip.getPath(), reProto);
}
}
// Add inode id to movement queue if xattrs contain satisfy xattr.
if (XATTR_SATISFY_STORAGE_POLICY.equals(xaName)) {
FSDirSatisfyStoragePolicyOp.unprotectedSatisfyStoragePolicy(inode, fsd);
continue;
}
if (!isFile && SECURITY_XATTR_UNREADABLE_BY_SUPERUSER.equals(xaName)) {
throw new IOException("Can only set '" +
SECURITY_XATTR_UNREADABLE_BY_SUPERUSER + "' on a file.");
}
}
XAttrStorage.updateINodeXAttrs(inode, newXAttrs, iip.getLatestSnapshotId());
return inode;
}
需要设置的属性是xAttrs,如下:
现存的属性existingXAttrs为空。
通过调用XAttrStorage.updateINodeXAttrs
,将新的属性集合设置到inode上。
public static void updateINodeXAttrs(INode inode,
List<XAttr> xAttrs, int snapshotId) throws QuotaExceededException {
if (inode.getXAttrFeature() != null) {
inode.removeXAttrFeature(snapshotId);
}
if (xAttrs == null || xAttrs.isEmpty()) {
return;
}
inode.addXAttrFeature(new XAttrFeature(xAttrs), snapshotId);
}
通过XAttr来构建 XAttrFeature
, 然后INode来添加属性。
XAttr被格式化成Bytes类型。
// INodeWithAdditionalFields
protected void addFeature(Feature f) {
int size = features.length;
Feature[] arr = new Feature[size + 1];
if (size != 0) {
System.arraycopy(features, 0, arr, 0, size);
}
arr[size] = f;
features = arr;
}
原来的feature为0,现在有了1个,所以一共是1个。
为什么XAttr里面还有两个属性,一个是attrs,一个是xAttrs呢?并且为什么xAttrs=null,不是应该有值才对吗???