斷點調試
[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,不是應該有值纔對嗎???