Fix potential FSImage corruption. Contributed by Daryn Sharp and Vinayakumar B.
(cherry picked from commit f1996ccbaee734d423caa9d47a571cfff98ef42c)
This commit is contained in:
parent
4167275e89
commit
96cedb87b9
|
@ -26,6 +26,10 @@ import java.io.Serializable;
|
||||||
public class LongBitFormat implements Serializable {
|
public class LongBitFormat implements Serializable {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public interface Enum {
|
||||||
|
int getLength();
|
||||||
|
}
|
||||||
|
|
||||||
private final String NAME;
|
private final String NAME;
|
||||||
/** Bit offset */
|
/** Bit offset */
|
||||||
private final int OFFSET;
|
private final int OFFSET;
|
||||||
|
@ -69,4 +73,8 @@ public class LongBitFormat implements Serializable {
|
||||||
public long getMin() {
|
public long getMin() {
|
||||||
return MIN;
|
return MIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getLength() {
|
||||||
|
return LENGTH;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -794,6 +794,12 @@ public class DFSConfigKeys extends CommonConfigurationKeys {
|
||||||
public static final long DFS_IMAGE_TRANSFER_BOOTSTRAP_STANDBY_RATE_DEFAULT =
|
public static final long DFS_IMAGE_TRANSFER_BOOTSTRAP_STANDBY_RATE_DEFAULT =
|
||||||
0; //no throttling
|
0; //no throttling
|
||||||
|
|
||||||
|
// String table in the fsimage utilizes an expanded bit range.
|
||||||
|
public static final String DFS_IMAGE_EXPANDED_STRING_TABLES_KEY =
|
||||||
|
"dfs.image.string-tables.expanded";
|
||||||
|
public static final boolean DFS_IMAGE_EXPANDED_STRING_TABLES_DEFAULT =
|
||||||
|
false;
|
||||||
|
|
||||||
// Image transfer timeout
|
// Image transfer timeout
|
||||||
public static final String DFS_IMAGE_TRANSFER_TIMEOUT_KEY = "dfs.image.transfer.timeout";
|
public static final String DFS_IMAGE_TRANSFER_TIMEOUT_KEY = "dfs.image.transfer.timeout";
|
||||||
public static final int DFS_IMAGE_TRANSFER_TIMEOUT_DEFAULT = 60 * 1000;
|
public static final int DFS_IMAGE_TRANSFER_TIMEOUT_DEFAULT = 60 * 1000;
|
||||||
|
|
|
@ -31,25 +31,23 @@ import com.google.common.collect.ImmutableList;
|
||||||
/**
|
/**
|
||||||
* Class to pack an AclEntry into an integer. <br>
|
* Class to pack an AclEntry into an integer. <br>
|
||||||
* An ACL entry is represented by a 32-bit integer in Big Endian format. <br>
|
* An ACL entry is represented by a 32-bit integer in Big Endian format. <br>
|
||||||
* The bits can be divided in four segments: <br>
|
*
|
||||||
* [0:1) || [1:3) || [3:6) || [6:7) || [7:32) <br>
|
* Note: this format is used both in-memory and on-disk. Changes will be
|
||||||
* <br>
|
* incompatible.
|
||||||
* [0:1) -- the scope of the entry (AclEntryScope) <br>
|
*
|
||||||
* [1:3) -- the type of the entry (AclEntryType) <br>
|
|
||||||
* [3:6) -- the permission of the entry (FsAction) <br>
|
|
||||||
* [6:7) -- A flag to indicate whether Named entry or not <br>
|
|
||||||
* [7:8) -- Reserved <br>
|
|
||||||
* [8:32) -- the name of the entry, which is an ID that points to a <br>
|
|
||||||
* string in the StringTableSection. <br>
|
|
||||||
*/
|
*/
|
||||||
public enum AclEntryStatusFormat {
|
public enum AclEntryStatusFormat implements LongBitFormat.Enum {
|
||||||
|
|
||||||
SCOPE(null, 1),
|
PERMISSION(null, 3),
|
||||||
TYPE(SCOPE.BITS, 2),
|
TYPE(PERMISSION.BITS, 2),
|
||||||
PERMISSION(TYPE.BITS, 3),
|
SCOPE(TYPE.BITS, 1),
|
||||||
NAMED_ENTRY_CHECK(PERMISSION.BITS, 1),
|
NAME(SCOPE.BITS, 24);
|
||||||
RESERVED(NAMED_ENTRY_CHECK.BITS, 1),
|
|
||||||
NAME(RESERVED.BITS, 24);
|
private static final FsAction[] FSACTION_VALUES = FsAction.values();
|
||||||
|
private static final AclEntryScope[] ACL_ENTRY_SCOPE_VALUES =
|
||||||
|
AclEntryScope.values();
|
||||||
|
private static final AclEntryType[] ACL_ENTRY_TYPE_VALUES =
|
||||||
|
AclEntryType.values();
|
||||||
|
|
||||||
private final LongBitFormat BITS;
|
private final LongBitFormat BITS;
|
||||||
|
|
||||||
|
@ -59,30 +57,29 @@ public enum AclEntryStatusFormat {
|
||||||
|
|
||||||
static AclEntryScope getScope(int aclEntry) {
|
static AclEntryScope getScope(int aclEntry) {
|
||||||
int ordinal = (int) SCOPE.BITS.retrieve(aclEntry);
|
int ordinal = (int) SCOPE.BITS.retrieve(aclEntry);
|
||||||
return AclEntryScope.values()[ordinal];
|
return ACL_ENTRY_SCOPE_VALUES[ordinal];
|
||||||
}
|
}
|
||||||
|
|
||||||
static AclEntryType getType(int aclEntry) {
|
static AclEntryType getType(int aclEntry) {
|
||||||
int ordinal = (int) TYPE.BITS.retrieve(aclEntry);
|
int ordinal = (int) TYPE.BITS.retrieve(aclEntry);
|
||||||
return AclEntryType.values()[ordinal];
|
return ACL_ENTRY_TYPE_VALUES[ordinal];
|
||||||
}
|
}
|
||||||
|
|
||||||
static FsAction getPermission(int aclEntry) {
|
static FsAction getPermission(int aclEntry) {
|
||||||
int ordinal = (int) PERMISSION.BITS.retrieve(aclEntry);
|
int ordinal = (int) PERMISSION.BITS.retrieve(aclEntry);
|
||||||
return FsAction.values()[ordinal];
|
return FSACTION_VALUES[ordinal];
|
||||||
}
|
}
|
||||||
|
|
||||||
static String getName(int aclEntry) {
|
static String getName(int aclEntry) {
|
||||||
int nameExists = (int) NAMED_ENTRY_CHECK.BITS.retrieve(aclEntry);
|
return getName(aclEntry, null);
|
||||||
if (nameExists == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
int id = (int) NAME.BITS.retrieve(aclEntry);
|
|
||||||
AclEntryType type = getType(aclEntry);
|
static String getName(int aclEntry,
|
||||||
if (type == AclEntryType.USER) {
|
SerialNumberManager.StringTable stringTable) {
|
||||||
return SerialNumberManager.INSTANCE.getUser(id);
|
SerialNumberManager snm = getSerialNumberManager(getType(aclEntry));
|
||||||
} else if (type == AclEntryType.GROUP) {
|
if (snm != null) {
|
||||||
return SerialNumberManager.INSTANCE.getGroup(id);
|
int nid = (int)NAME.BITS.retrieve(aclEntry);
|
||||||
|
return snm.getString(nid, stringTable);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -94,29 +91,26 @@ public enum AclEntryStatusFormat {
|
||||||
aclEntryInt = TYPE.BITS.combine(aclEntry.getType().ordinal(), aclEntryInt);
|
aclEntryInt = TYPE.BITS.combine(aclEntry.getType().ordinal(), aclEntryInt);
|
||||||
aclEntryInt = PERMISSION.BITS.combine(aclEntry.getPermission().ordinal(),
|
aclEntryInt = PERMISSION.BITS.combine(aclEntry.getPermission().ordinal(),
|
||||||
aclEntryInt);
|
aclEntryInt);
|
||||||
if (aclEntry.getName() != null) {
|
SerialNumberManager snm = getSerialNumberManager(aclEntry.getType());
|
||||||
aclEntryInt = NAMED_ENTRY_CHECK.BITS.combine(1, aclEntryInt);
|
if (snm != null) {
|
||||||
if (aclEntry.getType() == AclEntryType.USER) {
|
int nid = snm.getSerialNumber(aclEntry.getName());
|
||||||
int userId = SerialNumberManager.INSTANCE.getUserSerialNumber(aclEntry
|
aclEntryInt = NAME.BITS.combine(nid, aclEntryInt);
|
||||||
.getName());
|
|
||||||
aclEntryInt = NAME.BITS.combine(userId, aclEntryInt);
|
|
||||||
} else if (aclEntry.getType() == AclEntryType.GROUP) {
|
|
||||||
int groupId = SerialNumberManager.INSTANCE
|
|
||||||
.getGroupSerialNumber(aclEntry.getName());
|
|
||||||
aclEntryInt = NAME.BITS.combine(groupId, aclEntryInt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return (int) aclEntryInt;
|
return (int) aclEntryInt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static AclEntry toAclEntry(int aclEntry) {
|
static AclEntry toAclEntry(int aclEntry) {
|
||||||
AclEntry.Builder builder = new AclEntry.Builder();
|
return toAclEntry(aclEntry, null);
|
||||||
builder.setScope(getScope(aclEntry)).setType(getType(aclEntry))
|
|
||||||
.setPermission(getPermission(aclEntry));
|
|
||||||
if (getName(aclEntry) != null) {
|
|
||||||
builder.setName(getName(aclEntry));
|
|
||||||
}
|
}
|
||||||
return builder.build();
|
|
||||||
|
static AclEntry toAclEntry(int aclEntry,
|
||||||
|
SerialNumberManager.StringTable stringTable) {
|
||||||
|
return new AclEntry.Builder()
|
||||||
|
.setScope(getScope(aclEntry))
|
||||||
|
.setType(getType(aclEntry))
|
||||||
|
.setPermission(getPermission(aclEntry))
|
||||||
|
.setName(getName(aclEntry, stringTable))
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int[] toInt(List<AclEntry> aclEntries) {
|
public static int[] toInt(List<AclEntry> aclEntries) {
|
||||||
|
@ -127,12 +121,19 @@ public enum AclEntryStatusFormat {
|
||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ImmutableList<AclEntry> toAclEntries(int[] entries) {
|
private static SerialNumberManager getSerialNumberManager(AclEntryType type) {
|
||||||
ImmutableList.Builder<AclEntry> b = new ImmutableList.Builder<AclEntry>();
|
switch (type) {
|
||||||
for (int entry : entries) {
|
case USER:
|
||||||
AclEntry aclEntry = toAclEntry(entry);
|
return SerialNumberManager.USER;
|
||||||
b.add(aclEntry);
|
case GROUP:
|
||||||
}
|
return SerialNumberManager.GROUP;
|
||||||
return b.build();
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLength() {
|
||||||
|
return BITS.getLength();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -265,6 +265,8 @@ public class FSDirectory implements Closeable {
|
||||||
};
|
};
|
||||||
|
|
||||||
FSDirectory(FSNamesystem ns, Configuration conf) throws IOException {
|
FSDirectory(FSNamesystem ns, Configuration conf) throws IOException {
|
||||||
|
// used to enable/disable the use of expanded string tables.
|
||||||
|
SerialNumberManager.initialize(conf);
|
||||||
this.dirLock = new ReentrantReadWriteLock(true); // fair
|
this.dirLock = new ReentrantReadWriteLock(true); // fair
|
||||||
this.inodeId = new INodeId();
|
this.inodeId = new INodeId();
|
||||||
rootDir = createRoot(ns);
|
rootDir = createRoot(ns);
|
||||||
|
|
|
@ -31,10 +31,6 @@ import org.apache.commons.logging.LogFactory;
|
||||||
import org.apache.hadoop.HadoopIllegalArgumentException;
|
import org.apache.hadoop.HadoopIllegalArgumentException;
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.fs.permission.AclEntry;
|
import org.apache.hadoop.fs.permission.AclEntry;
|
||||||
import org.apache.hadoop.fs.permission.AclEntryScope;
|
|
||||||
import org.apache.hadoop.fs.permission.AclEntryType;
|
|
||||||
import org.apache.hadoop.fs.permission.FsAction;
|
|
||||||
import org.apache.hadoop.fs.permission.FsPermission;
|
|
||||||
import org.apache.hadoop.fs.permission.PermissionStatus;
|
import org.apache.hadoop.fs.permission.PermissionStatus;
|
||||||
import org.apache.hadoop.fs.StorageType;
|
import org.apache.hadoop.fs.StorageType;
|
||||||
import org.apache.hadoop.fs.XAttr;
|
import org.apache.hadoop.fs.XAttr;
|
||||||
|
@ -60,6 +56,8 @@ import org.apache.hadoop.hdfs.server.namenode.FsImageProto.INodeSection.XAttrCom
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.INodeSection.XAttrFeatureProto;
|
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.INodeSection.XAttrFeatureProto;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.INodeSection.QuotaByStorageTypeEntryProto;
|
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.INodeSection.QuotaByStorageTypeEntryProto;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.INodeSection.QuotaByStorageTypeFeatureProto;
|
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.INodeSection.QuotaByStorageTypeFeatureProto;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.INodeWithAdditionalFields.PermissionStatusFormat;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.SerialNumberManager.StringTable;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.snapshot.Snapshot;
|
import org.apache.hadoop.hdfs.server.namenode.snapshot.Snapshot;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.startupprogress.Phase;
|
import org.apache.hadoop.hdfs.server.namenode.startupprogress.Phase;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.startupprogress.StartupProgress;
|
import org.apache.hadoop.hdfs.server.namenode.startupprogress.StartupProgress;
|
||||||
|
@ -74,22 +72,11 @@ import com.google.protobuf.ByteString;
|
||||||
|
|
||||||
@InterfaceAudience.Private
|
@InterfaceAudience.Private
|
||||||
public final class FSImageFormatPBINode {
|
public final class FSImageFormatPBINode {
|
||||||
private final static long USER_GROUP_STRID_MASK = (1 << 24) - 1;
|
|
||||||
private final static int USER_STRID_OFFSET = 40;
|
|
||||||
private final static int GROUP_STRID_OFFSET = 16;
|
|
||||||
|
|
||||||
public static final int ACL_ENTRY_NAME_MASK = (1 << 24) - 1;
|
public static final int ACL_ENTRY_NAME_MASK = (1 << 24) - 1;
|
||||||
public static final int ACL_ENTRY_NAME_OFFSET = 6;
|
public static final int ACL_ENTRY_NAME_OFFSET = 6;
|
||||||
public static final int ACL_ENTRY_TYPE_OFFSET = 3;
|
public static final int ACL_ENTRY_TYPE_OFFSET = 3;
|
||||||
public static final int ACL_ENTRY_SCOPE_OFFSET = 5;
|
public static final int ACL_ENTRY_SCOPE_OFFSET = 5;
|
||||||
public static final int ACL_ENTRY_PERM_MASK = 7;
|
public static final int ACL_ENTRY_PERM_MASK = 7;
|
||||||
private static final int ACL_ENTRY_TYPE_MASK = 3;
|
|
||||||
private static final int ACL_ENTRY_SCOPE_MASK = 1;
|
|
||||||
private static final FsAction[] FSACTION_VALUES = FsAction.values();
|
|
||||||
private static final AclEntryScope[] ACL_ENTRY_SCOPE_VALUES = AclEntryScope
|
|
||||||
.values();
|
|
||||||
private static final AclEntryType[] ACL_ENTRY_TYPE_VALUES = AclEntryType
|
|
||||||
.values();
|
|
||||||
|
|
||||||
public static final int XATTR_NAMESPACE_MASK = 3;
|
public static final int XATTR_NAMESPACE_MASK = 3;
|
||||||
public static final int XATTR_NAMESPACE_OFFSET = 30;
|
public static final int XATTR_NAMESPACE_OFFSET = 30;
|
||||||
|
@ -100,55 +87,35 @@ public final class FSImageFormatPBINode {
|
||||||
public static final int XATTR_NAMESPACE_EXT_OFFSET = 5;
|
public static final int XATTR_NAMESPACE_EXT_OFFSET = 5;
|
||||||
public static final int XATTR_NAMESPACE_EXT_MASK = 1;
|
public static final int XATTR_NAMESPACE_EXT_MASK = 1;
|
||||||
|
|
||||||
private static final XAttr.NameSpace[] XATTR_NAMESPACE_VALUES =
|
|
||||||
XAttr.NameSpace.values();
|
|
||||||
|
|
||||||
|
|
||||||
private static final Log LOG = LogFactory.getLog(FSImageFormatPBINode.class);
|
private static final Log LOG = LogFactory.getLog(FSImageFormatPBINode.class);
|
||||||
|
|
||||||
|
// the loader must decode all fields referencing serial number based fields
|
||||||
|
// via to<Item> methods with the string table.
|
||||||
public final static class Loader {
|
public final static class Loader {
|
||||||
public static PermissionStatus loadPermission(long id,
|
public static PermissionStatus loadPermission(long id,
|
||||||
final String[] stringTable) {
|
final StringTable stringTable) {
|
||||||
short perm = (short) (id & ((1 << GROUP_STRID_OFFSET) - 1));
|
return PermissionStatusFormat.toPermissionStatus(id, stringTable);
|
||||||
int gsid = (int) ((id >> GROUP_STRID_OFFSET) & USER_GROUP_STRID_MASK);
|
|
||||||
int usid = (int) ((id >> USER_STRID_OFFSET) & USER_GROUP_STRID_MASK);
|
|
||||||
return new PermissionStatus(stringTable[usid], stringTable[gsid],
|
|
||||||
new FsPermission(perm));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ImmutableList<AclEntry> loadAclEntries(
|
public static ImmutableList<AclEntry> loadAclEntries(
|
||||||
AclFeatureProto proto, final String[] stringTable) {
|
AclFeatureProto proto, final StringTable stringTable) {
|
||||||
ImmutableList.Builder<AclEntry> b = ImmutableList.builder();
|
ImmutableList.Builder<AclEntry> b = ImmutableList.builder();
|
||||||
for (int v : proto.getEntriesList()) {
|
for (int v : proto.getEntriesList()) {
|
||||||
int p = v & ACL_ENTRY_PERM_MASK;
|
b.add(AclEntryStatusFormat.toAclEntry(v, stringTable));
|
||||||
int t = (v >> ACL_ENTRY_TYPE_OFFSET) & ACL_ENTRY_TYPE_MASK;
|
|
||||||
int s = (v >> ACL_ENTRY_SCOPE_OFFSET) & ACL_ENTRY_SCOPE_MASK;
|
|
||||||
int nid = (v >> ACL_ENTRY_NAME_OFFSET) & ACL_ENTRY_NAME_MASK;
|
|
||||||
String name = stringTable[nid];
|
|
||||||
b.add(new AclEntry.Builder().setName(name)
|
|
||||||
.setPermission(FSACTION_VALUES[p])
|
|
||||||
.setScope(ACL_ENTRY_SCOPE_VALUES[s])
|
|
||||||
.setType(ACL_ENTRY_TYPE_VALUES[t]).build());
|
|
||||||
}
|
}
|
||||||
return b.build();
|
return b.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<XAttr> loadXAttrs(
|
public static List<XAttr> loadXAttrs(
|
||||||
XAttrFeatureProto proto, final String[] stringTable) {
|
XAttrFeatureProto proto, final StringTable stringTable) {
|
||||||
List<XAttr> b = new ArrayList<>();
|
List<XAttr> b = new ArrayList<>();
|
||||||
for (XAttrCompactProto xAttrCompactProto : proto.getXAttrsList()) {
|
for (XAttrCompactProto xAttrCompactProto : proto.getXAttrsList()) {
|
||||||
int v = xAttrCompactProto.getName();
|
int v = xAttrCompactProto.getName();
|
||||||
int nid = (v >> XATTR_NAME_OFFSET) & XATTR_NAME_MASK;
|
|
||||||
int ns = (v >> XATTR_NAMESPACE_OFFSET) & XATTR_NAMESPACE_MASK;
|
|
||||||
ns |=
|
|
||||||
((v >> XATTR_NAMESPACE_EXT_OFFSET) & XATTR_NAMESPACE_EXT_MASK) << 2;
|
|
||||||
String name = stringTable[nid];
|
|
||||||
byte[] value = null;
|
byte[] value = null;
|
||||||
if (xAttrCompactProto.getValue() != null) {
|
if (xAttrCompactProto.getValue() != null) {
|
||||||
value = xAttrCompactProto.getValue().toByteArray();
|
value = xAttrCompactProto.getValue().toByteArray();
|
||||||
}
|
}
|
||||||
b.add(new XAttr.Builder().setNameSpace(XATTR_NAMESPACE_VALUES[ns])
|
b.add(XAttrFormat.toXAttr(v, value, stringTable));
|
||||||
.setName(name).setValue(value).build());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return b;
|
return b;
|
||||||
|
@ -438,46 +405,30 @@ public final class FSImageFormatPBINode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the saver can directly write out fields referencing serial numbers.
|
||||||
|
// the serial number maps will be compacted when loading.
|
||||||
public final static class Saver {
|
public final static class Saver {
|
||||||
private long numImageErrors;
|
private long numImageErrors;
|
||||||
|
|
||||||
private static long buildPermissionStatus(INodeAttributes n,
|
private static long buildPermissionStatus(INodeAttributes n) {
|
||||||
final SaverContext.DeduplicationMap<String> stringMap) {
|
return n.getPermissionLong();
|
||||||
long userId = stringMap.getId(n.getUserName());
|
|
||||||
long groupId = stringMap.getId(n.getGroupName());
|
|
||||||
return ((userId & USER_GROUP_STRID_MASK) << USER_STRID_OFFSET)
|
|
||||||
| ((groupId & USER_GROUP_STRID_MASK) << GROUP_STRID_OFFSET)
|
|
||||||
| n.getFsPermissionShort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AclFeatureProto.Builder buildAclEntries(AclFeature f,
|
private static AclFeatureProto.Builder buildAclEntries(AclFeature f) {
|
||||||
final SaverContext.DeduplicationMap<String> map) {
|
|
||||||
AclFeatureProto.Builder b = AclFeatureProto.newBuilder();
|
AclFeatureProto.Builder b = AclFeatureProto.newBuilder();
|
||||||
for (int pos = 0, e; pos < f.getEntriesSize(); pos++) {
|
for (int pos = 0, e; pos < f.getEntriesSize(); pos++) {
|
||||||
e = f.getEntryAt(pos);
|
e = f.getEntryAt(pos);
|
||||||
int nameId = map.getId(AclEntryStatusFormat.getName(e));
|
b.addEntries(e);
|
||||||
int v = ((nameId & ACL_ENTRY_NAME_MASK) << ACL_ENTRY_NAME_OFFSET)
|
|
||||||
| (AclEntryStatusFormat.getType(e).ordinal() << ACL_ENTRY_TYPE_OFFSET)
|
|
||||||
| (AclEntryStatusFormat.getScope(e).ordinal() << ACL_ENTRY_SCOPE_OFFSET)
|
|
||||||
| (AclEntryStatusFormat.getPermission(e).ordinal());
|
|
||||||
b.addEntries(v);
|
|
||||||
}
|
}
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static XAttrFeatureProto.Builder buildXAttrs(XAttrFeature f,
|
private static XAttrFeatureProto.Builder buildXAttrs(XAttrFeature f) {
|
||||||
final SaverContext.DeduplicationMap<String> stringMap) {
|
|
||||||
XAttrFeatureProto.Builder b = XAttrFeatureProto.newBuilder();
|
XAttrFeatureProto.Builder b = XAttrFeatureProto.newBuilder();
|
||||||
for (XAttr a : f.getXAttrs()) {
|
for (XAttr a : f.getXAttrs()) {
|
||||||
XAttrCompactProto.Builder xAttrCompactBuilder = XAttrCompactProto.
|
XAttrCompactProto.Builder xAttrCompactBuilder = XAttrCompactProto.
|
||||||
newBuilder();
|
newBuilder();
|
||||||
int nsOrd = a.getNameSpace().ordinal();
|
int v = XAttrFormat.toInt(a);
|
||||||
Preconditions.checkArgument(nsOrd < 8, "Too many namespaces.");
|
|
||||||
int v = ((nsOrd & XATTR_NAMESPACE_MASK) << XATTR_NAMESPACE_OFFSET)
|
|
||||||
| ((stringMap.getId(a.getName()) & XATTR_NAME_MASK) <<
|
|
||||||
XATTR_NAME_OFFSET);
|
|
||||||
v |= (((nsOrd >> 2) & XATTR_NAMESPACE_EXT_MASK) <<
|
|
||||||
XATTR_NAMESPACE_EXT_OFFSET);
|
|
||||||
xAttrCompactBuilder.setName(v);
|
xAttrCompactBuilder.setName(v);
|
||||||
if (a.getValue() != null) {
|
if (a.getValue() != null) {
|
||||||
xAttrCompactBuilder.setValue(PBHelperClient.getByteString(a.getValue()));
|
xAttrCompactBuilder.setValue(PBHelperClient.getByteString(a.getValue()));
|
||||||
|
@ -509,7 +460,7 @@ public final class FSImageFormatPBINode {
|
||||||
INodeSection.INodeFile.Builder b = INodeSection.INodeFile.newBuilder()
|
INodeSection.INodeFile.Builder b = INodeSection.INodeFile.newBuilder()
|
||||||
.setAccessTime(file.getAccessTime())
|
.setAccessTime(file.getAccessTime())
|
||||||
.setModificationTime(file.getModificationTime())
|
.setModificationTime(file.getModificationTime())
|
||||||
.setPermission(buildPermissionStatus(file, state.getStringMap()))
|
.setPermission(buildPermissionStatus(file))
|
||||||
.setPreferredBlockSize(file.getPreferredBlockSize())
|
.setPreferredBlockSize(file.getPreferredBlockSize())
|
||||||
.setStoragePolicyID(file.getLocalStoragePolicyID())
|
.setStoragePolicyID(file.getLocalStoragePolicyID())
|
||||||
.setBlockType(PBHelperClient.convert(file.getBlockType()));
|
.setBlockType(PBHelperClient.convert(file.getBlockType()));
|
||||||
|
@ -522,11 +473,11 @@ public final class FSImageFormatPBINode {
|
||||||
|
|
||||||
AclFeature f = file.getAclFeature();
|
AclFeature f = file.getAclFeature();
|
||||||
if (f != null) {
|
if (f != null) {
|
||||||
b.setAcl(buildAclEntries(f, state.getStringMap()));
|
b.setAcl(buildAclEntries(f));
|
||||||
}
|
}
|
||||||
XAttrFeature xAttrFeature = file.getXAttrFeature();
|
XAttrFeature xAttrFeature = file.getXAttrFeature();
|
||||||
if (xAttrFeature != null) {
|
if (xAttrFeature != null) {
|
||||||
b.setXAttrs(buildXAttrs(xAttrFeature, state.getStringMap()));
|
b.setXAttrs(buildXAttrs(xAttrFeature));
|
||||||
}
|
}
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
@ -538,7 +489,7 @@ public final class FSImageFormatPBINode {
|
||||||
.newBuilder().setModificationTime(dir.getModificationTime())
|
.newBuilder().setModificationTime(dir.getModificationTime())
|
||||||
.setNsQuota(quota.getNameSpace())
|
.setNsQuota(quota.getNameSpace())
|
||||||
.setDsQuota(quota.getStorageSpace())
|
.setDsQuota(quota.getStorageSpace())
|
||||||
.setPermission(buildPermissionStatus(dir, state.getStringMap()));
|
.setPermission(buildPermissionStatus(dir));
|
||||||
|
|
||||||
if (quota.getTypeSpaces().anyGreaterOrEqual(0)) {
|
if (quota.getTypeSpaces().anyGreaterOrEqual(0)) {
|
||||||
b.setTypeQuotas(buildQuotaByStorageTypeEntries(quota));
|
b.setTypeQuotas(buildQuotaByStorageTypeEntries(quota));
|
||||||
|
@ -546,11 +497,11 @@ public final class FSImageFormatPBINode {
|
||||||
|
|
||||||
AclFeature f = dir.getAclFeature();
|
AclFeature f = dir.getAclFeature();
|
||||||
if (f != null) {
|
if (f != null) {
|
||||||
b.setAcl(buildAclEntries(f, state.getStringMap()));
|
b.setAcl(buildAclEntries(f));
|
||||||
}
|
}
|
||||||
XAttrFeature xAttrFeature = dir.getXAttrFeature();
|
XAttrFeature xAttrFeature = dir.getXAttrFeature();
|
||||||
if (xAttrFeature != null) {
|
if (xAttrFeature != null) {
|
||||||
b.setXAttrs(buildXAttrs(xAttrFeature, state.getStringMap()));
|
b.setXAttrs(buildXAttrs(xAttrFeature));
|
||||||
}
|
}
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
@ -711,7 +662,7 @@ public final class FSImageFormatPBINode {
|
||||||
SaverContext state = parent.getSaverContext();
|
SaverContext state = parent.getSaverContext();
|
||||||
INodeSection.INodeSymlink.Builder b = INodeSection.INodeSymlink
|
INodeSection.INodeSymlink.Builder b = INodeSection.INodeSymlink
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setPermission(buildPermissionStatus(n, state.getStringMap()))
|
.setPermission(buildPermissionStatus(n))
|
||||||
.setTarget(ByteString.copyFrom(n.getSymlink()))
|
.setTarget(ByteString.copyFrom(n.getSymlink()))
|
||||||
.setModificationTime(n.getModificationTime())
|
.setModificationTime(n.getModificationTime())
|
||||||
.setAccessTime(n.getAccessTime());
|
.setAccessTime(n.getAccessTime());
|
||||||
|
|
|
@ -85,10 +85,10 @@ public final class FSImageFormatProtobuf {
|
||||||
.getLogger(FSImageFormatProtobuf.class);
|
.getLogger(FSImageFormatProtobuf.class);
|
||||||
|
|
||||||
public static final class LoaderContext {
|
public static final class LoaderContext {
|
||||||
private String[] stringTable;
|
private SerialNumberManager.StringTable stringTable;
|
||||||
private final ArrayList<INodeReference> refList = Lists.newArrayList();
|
private final ArrayList<INodeReference> refList = Lists.newArrayList();
|
||||||
|
|
||||||
public String[] getStringTable() {
|
public SerialNumberManager.StringTable getStringTable() {
|
||||||
return stringTable;
|
return stringTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,13 +129,6 @@ public final class FSImageFormatProtobuf {
|
||||||
}
|
}
|
||||||
private final ArrayList<INodeReference> refList = Lists.newArrayList();
|
private final ArrayList<INodeReference> refList = Lists.newArrayList();
|
||||||
|
|
||||||
private final DeduplicationMap<String> stringMap = DeduplicationMap
|
|
||||||
.newMap();
|
|
||||||
|
|
||||||
public DeduplicationMap<String> getStringMap() {
|
|
||||||
return stringMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList<INodeReference> getRefList() {
|
public ArrayList<INodeReference> getRefList() {
|
||||||
return refList;
|
return refList;
|
||||||
}
|
}
|
||||||
|
@ -327,11 +320,12 @@ public final class FSImageFormatProtobuf {
|
||||||
|
|
||||||
private void loadStringTableSection(InputStream in) throws IOException {
|
private void loadStringTableSection(InputStream in) throws IOException {
|
||||||
StringTableSection s = StringTableSection.parseDelimitedFrom(in);
|
StringTableSection s = StringTableSection.parseDelimitedFrom(in);
|
||||||
ctx.stringTable = new String[s.getNumEntry() + 1];
|
ctx.stringTable =
|
||||||
|
SerialNumberManager.newStringTable(s.getNumEntry(), s.getMaskBits());
|
||||||
for (int i = 0; i < s.getNumEntry(); ++i) {
|
for (int i = 0; i < s.getNumEntry(); ++i) {
|
||||||
StringTableSection.Entry e = StringTableSection.Entry
|
StringTableSection.Entry e = StringTableSection.Entry
|
||||||
.parseDelimitedFrom(in);
|
.parseDelimitedFrom(in);
|
||||||
ctx.stringTable[e.getId()] = e.getStr();
|
ctx.stringTable.put(e.getId(), e.getStr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -651,12 +645,16 @@ public final class FSImageFormatProtobuf {
|
||||||
private void saveStringTableSection(FileSummary.Builder summary)
|
private void saveStringTableSection(FileSummary.Builder summary)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
OutputStream out = sectionOutputStream;
|
OutputStream out = sectionOutputStream;
|
||||||
|
|
||||||
|
SerialNumberManager.StringTable stringTable =
|
||||||
|
SerialNumberManager.getStringTable();
|
||||||
StringTableSection.Builder b = StringTableSection.newBuilder()
|
StringTableSection.Builder b = StringTableSection.newBuilder()
|
||||||
.setNumEntry(saverContext.stringMap.size());
|
.setNumEntry(stringTable.size())
|
||||||
|
.setMaskBits(stringTable.getMaskBits());
|
||||||
b.build().writeDelimitedTo(out);
|
b.build().writeDelimitedTo(out);
|
||||||
for (Entry<String, Integer> e : saverContext.stringMap.entrySet()) {
|
for (Entry<Integer, String> e : stringTable) {
|
||||||
StringTableSection.Entry.Builder eb = StringTableSection.Entry
|
StringTableSection.Entry.Builder eb = StringTableSection.Entry
|
||||||
.newBuilder().setId(e.getValue()).setStr(e.getKey());
|
.newBuilder().setId(e.getKey()).setStr(e.getValue());
|
||||||
eb.build().writeDelimitedTo(out);
|
eb.build().writeDelimitedTo(out);
|
||||||
}
|
}
|
||||||
commitSection(summary, SectionName.STRING_TABLE);
|
commitSection(summary, SectionName.STRING_TABLE);
|
||||||
|
|
|
@ -33,7 +33,9 @@ import com.google.common.base.Preconditions;
|
||||||
@InterfaceAudience.Private
|
@InterfaceAudience.Private
|
||||||
public abstract class INodeWithAdditionalFields extends INode
|
public abstract class INodeWithAdditionalFields extends INode
|
||||||
implements LinkedElement {
|
implements LinkedElement {
|
||||||
enum PermissionStatusFormat {
|
// Note: this format is used both in-memory and on-disk. Changes will be
|
||||||
|
// incompatible.
|
||||||
|
enum PermissionStatusFormat implements LongBitFormat.Enum {
|
||||||
MODE(null, 16),
|
MODE(null, 16),
|
||||||
GROUP(MODE.BITS, 24),
|
GROUP(MODE.BITS, 24),
|
||||||
USER(GROUP.BITS, 24);
|
USER(GROUP.BITS, 24);
|
||||||
|
@ -46,12 +48,14 @@ public abstract class INodeWithAdditionalFields extends INode
|
||||||
|
|
||||||
static String getUser(long permission) {
|
static String getUser(long permission) {
|
||||||
final int n = (int)USER.BITS.retrieve(permission);
|
final int n = (int)USER.BITS.retrieve(permission);
|
||||||
return SerialNumberManager.INSTANCE.getUser(n);
|
String s = SerialNumberManager.USER.getString(n);
|
||||||
|
assert s != null;
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static String getGroup(long permission) {
|
static String getGroup(long permission) {
|
||||||
final int n = (int)GROUP.BITS.retrieve(permission);
|
final int n = (int)GROUP.BITS.retrieve(permission);
|
||||||
return SerialNumberManager.INSTANCE.getGroup(n);
|
return SerialNumberManager.GROUP.getString(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
static short getMode(long permission) {
|
static short getMode(long permission) {
|
||||||
|
@ -61,16 +65,34 @@ public abstract class INodeWithAdditionalFields extends INode
|
||||||
/** Encode the {@link PermissionStatus} to a long. */
|
/** Encode the {@link PermissionStatus} to a long. */
|
||||||
static long toLong(PermissionStatus ps) {
|
static long toLong(PermissionStatus ps) {
|
||||||
long permission = 0L;
|
long permission = 0L;
|
||||||
final int user = SerialNumberManager.INSTANCE.getUserSerialNumber(
|
final int user = SerialNumberManager.USER.getSerialNumber(
|
||||||
ps.getUserName());
|
ps.getUserName());
|
||||||
|
assert user != 0;
|
||||||
permission = USER.BITS.combine(user, permission);
|
permission = USER.BITS.combine(user, permission);
|
||||||
final int group = SerialNumberManager.INSTANCE.getGroupSerialNumber(
|
// ideally should assert on group but inodes are created with null
|
||||||
|
// group and then updated only when added to a directory.
|
||||||
|
final int group = SerialNumberManager.GROUP.getSerialNumber(
|
||||||
ps.getGroupName());
|
ps.getGroupName());
|
||||||
permission = GROUP.BITS.combine(group, permission);
|
permission = GROUP.BITS.combine(group, permission);
|
||||||
final int mode = ps.getPermission().toShort();
|
final int mode = ps.getPermission().toShort();
|
||||||
permission = MODE.BITS.combine(mode, permission);
|
permission = MODE.BITS.combine(mode, permission);
|
||||||
return permission;
|
return permission;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PermissionStatus toPermissionStatus(long id,
|
||||||
|
SerialNumberManager.StringTable stringTable) {
|
||||||
|
int uid = (int)USER.BITS.retrieve(id);
|
||||||
|
int gid = (int)GROUP.BITS.retrieve(id);
|
||||||
|
return new PermissionStatus(
|
||||||
|
SerialNumberManager.USER.getString(uid, stringTable),
|
||||||
|
SerialNumberManager.GROUP.getString(gid, stringTable),
|
||||||
|
new FsPermission(getMode(id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLength() {
|
||||||
|
return BITS.getLength();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The inode id. */
|
/** The inode id. */
|
||||||
|
@ -175,7 +197,7 @@ public abstract class INodeWithAdditionalFields extends INode
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
final void setUser(String user) {
|
final void setUser(String user) {
|
||||||
int n = SerialNumberManager.INSTANCE.getUserSerialNumber(user);
|
int n = SerialNumberManager.USER.getSerialNumber(user);
|
||||||
updatePermissionStatus(PermissionStatusFormat.USER, n);
|
updatePermissionStatus(PermissionStatusFormat.USER, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +211,7 @@ public abstract class INodeWithAdditionalFields extends INode
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
final void setGroup(String group) {
|
final void setGroup(String group) {
|
||||||
int n = SerialNumberManager.INSTANCE.getGroupSerialNumber(group);
|
int n = SerialNumberManager.GROUP.getSerialNumber(group);
|
||||||
updatePermissionStatus(PermissionStatusFormat.GROUP, n);
|
updatePermissionStatus(PermissionStatusFormat.GROUP, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,23 +17,195 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.hadoop.hdfs.server.namenode;
|
package org.apache.hadoop.hdfs.server.namenode;
|
||||||
|
|
||||||
/** Manage name-to-serial-number maps for users and groups. */
|
import org.apache.hadoop.conf.Configuration;
|
||||||
class SerialNumberManager {
|
import org.apache.hadoop.hdfs.server.namenode.INodeWithAdditionalFields.PermissionStatusFormat;
|
||||||
/** This is the only instance of {@link SerialNumberManager}.*/
|
import org.apache.hadoop.hdfs.util.LongBitFormat;
|
||||||
static final SerialNumberManager INSTANCE = new SerialNumberManager();
|
|
||||||
|
|
||||||
private final SerialNumberMap<String> usermap = new SerialNumberMap<String>();
|
import java.util.Collections;
|
||||||
private final SerialNumberMap<String> groupmap = new SerialNumberMap<String>();
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
private SerialNumberManager() {}
|
import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_IMAGE_EXPANDED_STRING_TABLES_DEFAULT;
|
||||||
|
import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_IMAGE_EXPANDED_STRING_TABLES_KEY;
|
||||||
|
|
||||||
int getUserSerialNumber(String u) {return usermap.get(u);}
|
/** Manage name-to-serial-number maps for various string tables. */
|
||||||
int getGroupSerialNumber(String g) {return groupmap.get(g);}
|
public enum SerialNumberManager {
|
||||||
String getUser(int n) {return usermap.get(n);}
|
GLOBAL(), // NEVER EVER directly access!
|
||||||
String getGroup(int n) {return groupmap.get(n);}
|
USER(PermissionStatusFormat.USER, AclEntryStatusFormat.NAME),
|
||||||
|
GROUP(PermissionStatusFormat.GROUP, AclEntryStatusFormat.NAME),
|
||||||
|
XATTR(XAttrFormat.NAME);
|
||||||
|
|
||||||
{
|
private static final SerialNumberManager[] values = values();
|
||||||
getUserSerialNumber(null);
|
private static final int maxEntryBits;
|
||||||
getGroupSerialNumber(null);
|
private static final int maxEntryNumber;
|
||||||
|
private static final int maskBits;
|
||||||
|
private static boolean initialized;
|
||||||
|
|
||||||
|
private SerialNumberMap<String> serialMap;
|
||||||
|
private int bitLength = Integer.SIZE;
|
||||||
|
private boolean enabled;
|
||||||
|
|
||||||
|
static {
|
||||||
|
maxEntryBits = Integer.numberOfLeadingZeros(values.length);
|
||||||
|
maxEntryNumber = (1 << maxEntryBits) - 1;
|
||||||
|
maskBits = Integer.SIZE - maxEntryBits;
|
||||||
|
for (SerialNumberManager snm : values) {
|
||||||
|
// account for string table mask bits.
|
||||||
|
snm.updateLength(maxEntryBits);
|
||||||
|
// find max allowed length in case global is enabled.
|
||||||
|
GLOBAL.updateLength(snm.getLength());
|
||||||
|
}
|
||||||
|
// can reinitialize once later.
|
||||||
|
initializeSerialMaps(DFS_IMAGE_EXPANDED_STRING_TABLES_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static synchronized void initialize(Configuration conf) {
|
||||||
|
boolean useExpanded = conf.getBoolean(
|
||||||
|
DFS_IMAGE_EXPANDED_STRING_TABLES_KEY,
|
||||||
|
DFS_IMAGE_EXPANDED_STRING_TABLES_DEFAULT);
|
||||||
|
if (initialized) {
|
||||||
|
if (useExpanded ^ !GLOBAL.enabled) {
|
||||||
|
throw new IllegalStateException("Cannot change serial maps");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
initializeSerialMaps(useExpanded);
|
||||||
|
for (SerialNumberManager snm : values) {
|
||||||
|
if (snm.enabled) {
|
||||||
|
FSDirectory.LOG.info(snm + " serial map: bits=" + snm.getLength() +
|
||||||
|
" maxEntries=" + snm.serialMap.getMax());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void initializeSerialMaps(boolean useExpanded) {
|
||||||
|
if (useExpanded) {
|
||||||
|
// initialize per-manager serial maps for all but global.
|
||||||
|
for (SerialNumberManager snm : values) {
|
||||||
|
snm.enabled = (snm != GLOBAL);
|
||||||
|
snm.serialMap = snm.enabled ? new SerialNumberMap<String>(snm) : null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// initialize all managers to use the global serial map.
|
||||||
|
SerialNumberMap<String> globalSerialMap = new SerialNumberMap<>(GLOBAL);
|
||||||
|
for (SerialNumberManager snm : values) {
|
||||||
|
snm.enabled = (snm == GLOBAL);
|
||||||
|
snm.serialMap = globalSerialMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SerialNumberManager(LongBitFormat.Enum... elements) {
|
||||||
|
// compute the smallest bit length registered with the serial manager.
|
||||||
|
for (LongBitFormat.Enum element : elements) {
|
||||||
|
updateLength(element.getLength());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int getLength() {
|
||||||
|
return bitLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateLength(int maxLength) {
|
||||||
|
bitLength = Math.min(bitLength, maxLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSerialNumber(String u) {
|
||||||
|
return serialMap.get(u);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString(int id) {
|
||||||
|
return serialMap.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString(int id, StringTable stringTable) {
|
||||||
|
return (stringTable != null)
|
||||||
|
? stringTable.get(this, id) : getString(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getMask(int bits) {
|
||||||
|
return ordinal() << (Integer.SIZE - bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getMaskBits() {
|
||||||
|
return GLOBAL.enabled ? 0 : maskBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int size() {
|
||||||
|
return enabled ? serialMap.size() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Iterable<Entry<Integer, String>> entrySet() {
|
||||||
|
if (!enabled) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
return serialMap.entrySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns snapshot of current values for a save.
|
||||||
|
public static StringTable getStringTable() {
|
||||||
|
// approximate size for capacity.
|
||||||
|
int size = 0;
|
||||||
|
for (final SerialNumberManager snm : values) {
|
||||||
|
size += snm.size();
|
||||||
|
}
|
||||||
|
int tableMaskBits = getMaskBits();
|
||||||
|
StringTable map = new StringTable(size, tableMaskBits);
|
||||||
|
for (final SerialNumberManager snm : values) {
|
||||||
|
final int mask = snm.getMask(tableMaskBits);
|
||||||
|
for (Entry<Integer, String> entry : snm.entrySet()) {
|
||||||
|
map.put(entry.getKey() | mask, entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns an empty table for load.
|
||||||
|
public static StringTable newStringTable(int size, int bits) {
|
||||||
|
if (bits > maskBits) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"String table bits " + bits + " > " + maskBits);
|
||||||
|
}
|
||||||
|
return new StringTable(size, bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class StringTable implements Iterable<Entry<Integer, String>> {
|
||||||
|
private final int tableMaskBits;
|
||||||
|
private final Map<Integer,String> map;
|
||||||
|
|
||||||
|
private StringTable(int size, int loadingMaskBits) {
|
||||||
|
this.tableMaskBits = loadingMaskBits;
|
||||||
|
this.map = new HashMap<>(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String get(SerialNumberManager snm, int id) {
|
||||||
|
if (tableMaskBits != 0) {
|
||||||
|
if (id > maxEntryNumber) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"serial id " + id + " > " + maxEntryNumber);
|
||||||
|
}
|
||||||
|
id |= snm.getMask(tableMaskBits);
|
||||||
|
}
|
||||||
|
return map.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(int id, String str) {
|
||||||
|
map.put(id, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<Entry<Integer, String>> iterator() {
|
||||||
|
return map.entrySet().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return map.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaskBits() {
|
||||||
|
return tableMaskBits;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -17,6 +17,10 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.hadoop.hdfs.server.namenode;
|
package org.apache.hadoop.hdfs.server.namenode;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
@ -35,21 +39,33 @@ import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
*/
|
*/
|
||||||
@InterfaceAudience.Private
|
@InterfaceAudience.Private
|
||||||
public class SerialNumberMap<T> {
|
public class SerialNumberMap<T> {
|
||||||
private final AtomicInteger max = new AtomicInteger(1);
|
private String name;
|
||||||
|
private final int max;
|
||||||
|
private final AtomicInteger current = new AtomicInteger(1);
|
||||||
private final ConcurrentMap<T, Integer> t2i =
|
private final ConcurrentMap<T, Integer> t2i =
|
||||||
new ConcurrentHashMap<T, Integer>();
|
new ConcurrentHashMap<T, Integer>();
|
||||||
private final ConcurrentMap<Integer, T> i2t =
|
private final ConcurrentMap<Integer, T> i2t =
|
||||||
new ConcurrentHashMap<Integer, T>();
|
new ConcurrentHashMap<Integer, T>();
|
||||||
|
|
||||||
|
SerialNumberMap(SerialNumberManager snm) {
|
||||||
|
this(snm.name(), snm.getLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
SerialNumberMap(String name, int bitLength) {
|
||||||
|
this.name = name;
|
||||||
|
this.max = (1 << bitLength) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
public int get(T t) {
|
public int get(T t) {
|
||||||
if (t == null) {
|
if (t == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
Integer sn = t2i.get(t);
|
Integer sn = t2i.get(t);
|
||||||
if (sn == null) {
|
if (sn == null) {
|
||||||
sn = max.getAndIncrement();
|
sn = current.getAndIncrement();
|
||||||
if (sn < 0) {
|
if (sn > max) {
|
||||||
throw new IllegalStateException("Too many elements!");
|
current.getAndDecrement();
|
||||||
|
throw new IllegalStateException(name + ": serial number map is full");
|
||||||
}
|
}
|
||||||
Integer old = t2i.putIfAbsent(t, sn);
|
Integer old = t2i.putIfAbsent(t, sn);
|
||||||
if (old != null) {
|
if (old != null) {
|
||||||
|
@ -66,14 +82,27 @@ public class SerialNumberMap<T> {
|
||||||
}
|
}
|
||||||
T t = i2t.get(i);
|
T t = i2t.get(i);
|
||||||
if (t == null) {
|
if (t == null) {
|
||||||
throw new IllegalStateException("!i2t.containsKey(" + i
|
throw new IllegalStateException(
|
||||||
+ "), this=" + this);
|
name + ": serial number " + i + " does not exist");
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getMax() {
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Map.Entry<Integer, T>> entrySet() {
|
||||||
|
return new HashSet<>(i2t.entrySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return i2t.size();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "max=" + max + ",\n t2i=" + t2i + ",\n i2t=" + i2t;
|
return "current=" + current + ",\n" +
|
||||||
|
"max=" + max + ",\n t2i=" + t2i + ",\n i2t=" + i2t;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -31,52 +31,66 @@ import org.apache.hadoop.hdfs.util.LongBitFormat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to pack XAttrs into byte[].<br>
|
* Class to pack XAttrs into byte[].<br>
|
||||||
* For each XAttr:<br>
|
*
|
||||||
* The first 4 bytes represents XAttr namespace and name<br>
|
* Note: this format is used both in-memory and on-disk. Changes will be
|
||||||
* [0:3) - XAttr namespace<br>
|
* incompatible.
|
||||||
* [3:8) - Reserved<br>
|
*
|
||||||
* [8:32) - The name of the entry, which is an ID that points to a
|
|
||||||
* string in map<br>
|
|
||||||
* The following two bytes represents the length of XAttr value<br>
|
|
||||||
* The remaining bytes is the XAttr value<br>
|
|
||||||
*/
|
*/
|
||||||
class XAttrFormat {
|
|
||||||
private enum XAttrStatusFormat {
|
|
||||||
|
|
||||||
NAMESPACE(null, 3),
|
public enum XAttrFormat implements LongBitFormat.Enum {
|
||||||
RESERVED(NAMESPACE.BITS, 5),
|
RESERVED(null, 5),
|
||||||
NAME(RESERVED.BITS, 24);
|
NS_EXT(RESERVED.BITS, 1),
|
||||||
|
NAME(NS_EXT.BITS, 24),
|
||||||
|
NS(NAME.BITS, 2);
|
||||||
|
|
||||||
|
private static final int NS_EXT_SHIFT = NS.BITS.getLength();
|
||||||
|
private static final int NS_MASK = (1 << NS_EXT_SHIFT) - 1;
|
||||||
|
|
||||||
|
private static final int XATTR_VALUE_LEN_MAX = 1 << 16;
|
||||||
|
private static final XAttr.NameSpace[] XATTR_NAMESPACE_VALUES =
|
||||||
|
XAttr.NameSpace.values();
|
||||||
|
|
||||||
private final LongBitFormat BITS;
|
private final LongBitFormat BITS;
|
||||||
|
|
||||||
XAttrStatusFormat(LongBitFormat previous, int length) {
|
XAttrFormat(LongBitFormat previous, int length) {
|
||||||
BITS = new LongBitFormat(name(), previous, length, 0);
|
BITS = new LongBitFormat(name(), previous, length, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static XAttr.NameSpace getNamespace(int xattrStatus) {
|
@Override
|
||||||
int ordinal = (int) NAMESPACE.BITS.retrieve(xattrStatus);
|
public int getLength() {
|
||||||
return XAttr.NameSpace.values()[ordinal];
|
return BITS.getLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
static String getName(int xattrStatus) {
|
static XAttr.NameSpace getNamespace(int record) {
|
||||||
int id = (int) NAME.BITS.retrieve(xattrStatus);
|
long nid = NS.BITS.retrieve(record);
|
||||||
return XAttrStorage.getName(id);
|
nid |= NS_EXT.BITS.retrieve(record) << NS_EXT_SHIFT;
|
||||||
|
return XATTR_NAMESPACE_VALUES[(int) nid];
|
||||||
}
|
}
|
||||||
|
|
||||||
static int toInt(XAttr.NameSpace namespace, String name) {
|
public static String getName(int record) {
|
||||||
long xattrStatusInt = 0;
|
int nid = (int)NAME.BITS.retrieve(record);
|
||||||
|
return SerialNumberManager.XATTR.getString(nid);
|
||||||
xattrStatusInt = NAMESPACE.BITS
|
|
||||||
.combine(namespace.ordinal(), xattrStatusInt);
|
|
||||||
int nid = XAttrStorage.getNameSerialNumber(name);
|
|
||||||
xattrStatusInt = NAME.BITS
|
|
||||||
.combine(nid, xattrStatusInt);
|
|
||||||
|
|
||||||
return (int) xattrStatusInt;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int XATTR_VALUE_LEN_MAX = 1 << 16;
|
static int toInt(XAttr a) {
|
||||||
|
int nid = SerialNumberManager.XATTR.getSerialNumber(a.getName());
|
||||||
|
int nsOrd = a.getNameSpace().ordinal();
|
||||||
|
long value = NS.BITS.combine(nsOrd & NS_MASK, 0L);
|
||||||
|
value = NS_EXT.BITS.combine(nsOrd >>> NS_EXT_SHIFT, value);
|
||||||
|
value = NAME.BITS.combine(nid, value);
|
||||||
|
return (int)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XAttr toXAttr(int record, byte[] value,
|
||||||
|
SerialNumberManager.StringTable stringTable) {
|
||||||
|
int nid = (int)NAME.BITS.retrieve(record);
|
||||||
|
String name = SerialNumberManager.XATTR.getString(nid, stringTable);
|
||||||
|
return new XAttr.Builder()
|
||||||
|
.setNameSpace(getNamespace(record))
|
||||||
|
.setName(name)
|
||||||
|
.setValue(value)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unpack byte[] to XAttrs.
|
* Unpack byte[] to XAttrs.
|
||||||
|
@ -95,8 +109,8 @@ class XAttrFormat {
|
||||||
int v = Ints.fromBytes(attrs[i], attrs[i + 1],
|
int v = Ints.fromBytes(attrs[i], attrs[i + 1],
|
||||||
attrs[i + 2], attrs[i + 3]);
|
attrs[i + 2], attrs[i + 3]);
|
||||||
i += 4;
|
i += 4;
|
||||||
builder.setNameSpace(XAttrStatusFormat.getNamespace(v));
|
builder.setNameSpace(XAttrFormat.getNamespace(v));
|
||||||
builder.setName(XAttrStatusFormat.getName(v));
|
builder.setName(XAttrFormat.getName(v));
|
||||||
int vlen = ((0xff & attrs[i]) << 8) | (0xff & attrs[i + 1]);
|
int vlen = ((0xff & attrs[i]) << 8) | (0xff & attrs[i + 1]);
|
||||||
i += 2;
|
i += 2;
|
||||||
if (vlen > 0) {
|
if (vlen > 0) {
|
||||||
|
@ -129,8 +143,8 @@ class XAttrFormat {
|
||||||
int v = Ints.fromBytes(attrs[i], attrs[i + 1],
|
int v = Ints.fromBytes(attrs[i], attrs[i + 1],
|
||||||
attrs[i + 2], attrs[i + 3]);
|
attrs[i + 2], attrs[i + 3]);
|
||||||
i += 4;
|
i += 4;
|
||||||
XAttr.NameSpace namespace = XAttrStatusFormat.getNamespace(v);
|
XAttr.NameSpace namespace = XAttrFormat.getNamespace(v);
|
||||||
String name = XAttrStatusFormat.getName(v);
|
String name = XAttrFormat.getName(v);
|
||||||
int vlen = ((0xff & attrs[i]) << 8) | (0xff & attrs[i + 1]);
|
int vlen = ((0xff & attrs[i]) << 8) | (0xff & attrs[i + 1]);
|
||||||
i += 2;
|
i += 2;
|
||||||
if (xAttr.getNameSpace() == namespace &&
|
if (xAttr.getNameSpace() == namespace &&
|
||||||
|
@ -161,7 +175,8 @@ class XAttrFormat {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
try {
|
try {
|
||||||
for (XAttr a : xAttrs) {
|
for (XAttr a : xAttrs) {
|
||||||
int v = XAttrStatusFormat.toInt(a.getNameSpace(), a.getName());
|
// big-endian
|
||||||
|
int v = XAttrFormat.toInt(a);
|
||||||
out.write(Ints.toByteArray(v));
|
out.write(Ints.toByteArray(v));
|
||||||
int vlen = a.getValue() == null ? 0 : a.getValue().length;
|
int vlen = a.getValue() == null ? 0 : a.getValue().length;
|
||||||
Preconditions.checkArgument(vlen < XATTR_VALUE_LEN_MAX,
|
Preconditions.checkArgument(vlen < XATTR_VALUE_LEN_MAX,
|
||||||
|
|
|
@ -31,17 +31,6 @@ import org.apache.hadoop.hdfs.protocol.QuotaExceededException;
|
||||||
@InterfaceAudience.Private
|
@InterfaceAudience.Private
|
||||||
public class XAttrStorage {
|
public class XAttrStorage {
|
||||||
|
|
||||||
private static final SerialNumberMap<String> NAME_MAP =
|
|
||||||
new SerialNumberMap<>();
|
|
||||||
|
|
||||||
public static int getNameSerialNumber(String name) {
|
|
||||||
return NAME_MAP.get(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getName(int n) {
|
|
||||||
return NAME_MAP.get(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the extended attribute of an inode by name with prefix.
|
* Reads the extended attribute of an inode by name with prefix.
|
||||||
* <p/>
|
* <p/>
|
||||||
|
|
|
@ -51,6 +51,7 @@ import org.apache.hadoop.hdfs.server.namenode.FsImageProto;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.INodeSection.INode;
|
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.INodeSection.INode;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INodeFile;
|
import org.apache.hadoop.hdfs.server.namenode.INodeFile;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INodeId;
|
import org.apache.hadoop.hdfs.server.namenode.INodeId;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.SerialNumberManager;
|
||||||
import org.apache.hadoop.hdfs.web.JsonUtil;
|
import org.apache.hadoop.hdfs.web.JsonUtil;
|
||||||
import org.apache.hadoop.hdfs.web.resources.XAttrEncodingParam;
|
import org.apache.hadoop.hdfs.web.resources.XAttrEncodingParam;
|
||||||
import org.apache.hadoop.io.IOUtils;
|
import org.apache.hadoop.io.IOUtils;
|
||||||
|
@ -67,7 +68,7 @@ import com.google.common.collect.Maps;
|
||||||
class FSImageLoader {
|
class FSImageLoader {
|
||||||
public static final Log LOG = LogFactory.getLog(FSImageHandler.class);
|
public static final Log LOG = LogFactory.getLog(FSImageHandler.class);
|
||||||
|
|
||||||
private final String[] stringTable;
|
private final SerialNumberManager.StringTable stringTable;
|
||||||
// byte representation of inodes, sorted by id
|
// byte representation of inodes, sorted by id
|
||||||
private final byte[][] inodes;
|
private final byte[][] inodes;
|
||||||
private final Map<Long, long[]> dirmap;
|
private final Map<Long, long[]> dirmap;
|
||||||
|
@ -93,8 +94,8 @@ class FSImageLoader {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private FSImageLoader(String[] stringTable, byte[][] inodes,
|
private FSImageLoader(SerialNumberManager.StringTable stringTable,
|
||||||
Map<Long, long[]> dirmap) {
|
byte[][] inodes, Map<Long, long[]> dirmap) {
|
||||||
this.stringTable = stringTable;
|
this.stringTable = stringTable;
|
||||||
this.inodes = inodes;
|
this.inodes = inodes;
|
||||||
this.dirmap = dirmap;
|
this.dirmap = dirmap;
|
||||||
|
@ -119,7 +120,7 @@ class FSImageLoader {
|
||||||
try (FileInputStream fin = new FileInputStream(file.getFD())) {
|
try (FileInputStream fin = new FileInputStream(file.getFD())) {
|
||||||
// Map to record INodeReference to the referred id
|
// Map to record INodeReference to the referred id
|
||||||
ImmutableList<Long> refIdList = null;
|
ImmutableList<Long> refIdList = null;
|
||||||
String[] stringTable = null;
|
SerialNumberManager.StringTable stringTable = null;
|
||||||
byte[][] inodes = null;
|
byte[][] inodes = null;
|
||||||
Map<Long, long[]> dirmap = null;
|
Map<Long, long[]> dirmap = null;
|
||||||
|
|
||||||
|
@ -242,16 +243,17 @@ class FSImageLoader {
|
||||||
return inodes;
|
return inodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static String[] loadStringTable(InputStream in) throws
|
static SerialNumberManager.StringTable loadStringTable(InputStream in)
|
||||||
IOException {
|
throws IOException {
|
||||||
FsImageProto.StringTableSection s = FsImageProto.StringTableSection
|
FsImageProto.StringTableSection s = FsImageProto.StringTableSection
|
||||||
.parseDelimitedFrom(in);
|
.parseDelimitedFrom(in);
|
||||||
LOG.info("Loading " + s.getNumEntry() + " strings");
|
LOG.info("Loading " + s.getNumEntry() + " strings");
|
||||||
String[] stringTable = new String[s.getNumEntry() + 1];
|
SerialNumberManager.StringTable stringTable =
|
||||||
|
SerialNumberManager.newStringTable(s.getNumEntry(), s.getMaskBits());
|
||||||
for (int i = 0; i < s.getNumEntry(); ++i) {
|
for (int i = 0; i < s.getNumEntry(); ++i) {
|
||||||
FsImageProto.StringTableSection.Entry e = FsImageProto
|
FsImageProto.StringTableSection.Entry e = FsImageProto
|
||||||
.StringTableSection.Entry.parseDelimitedFrom(in);
|
.StringTableSection.Entry.parseDelimitedFrom(in);
|
||||||
stringTable[e.getId()] = e.getStr();
|
stringTable.put(e.getId(), e.getStr());
|
||||||
}
|
}
|
||||||
return stringTable;
|
return stringTable;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ import org.apache.hadoop.hdfs.server.namenode.FsImageProto.FileSummary;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.INodeSection;
|
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.INodeSection;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.INodeSection.INode;
|
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.INodeSection.INode;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INodeId;
|
import org.apache.hadoop.hdfs.server.namenode.INodeId;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.SerialNumberManager;
|
||||||
import org.apache.hadoop.io.IOUtils;
|
import org.apache.hadoop.io.IOUtils;
|
||||||
import org.apache.hadoop.util.LimitInputStream;
|
import org.apache.hadoop.util.LimitInputStream;
|
||||||
import org.apache.hadoop.util.Time;
|
import org.apache.hadoop.util.Time;
|
||||||
|
@ -391,7 +392,7 @@ abstract class PBImageTextWriter implements Closeable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] stringTable;
|
private SerialNumberManager.StringTable stringTable;
|
||||||
private PrintStream out;
|
private PrintStream out;
|
||||||
private MetadataMap metadataMap = null;
|
private MetadataMap metadataMap = null;
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ import org.apache.hadoop.hdfs.server.namenode.FsImageProto.NameSystemSection;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.SecretManagerSection;
|
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.SecretManagerSection;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.SnapshotDiffSection;
|
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.SnapshotDiffSection;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.SnapshotSection;
|
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.SnapshotSection;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.StringTableSection;
|
import org.apache.hadoop.hdfs.server.namenode.SerialNumberManager;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INodeFile;
|
import org.apache.hadoop.hdfs.server.namenode.INodeFile;
|
||||||
import org.apache.hadoop.hdfs.util.XMLUtils;
|
import org.apache.hadoop.hdfs.util.XMLUtils;
|
||||||
import org.apache.hadoop.io.erasurecode.ECSchema;
|
import org.apache.hadoop.io.erasurecode.ECSchema;
|
||||||
|
@ -269,7 +269,7 @@ public final class PBImageXmlWriter {
|
||||||
private final Configuration conf;
|
private final Configuration conf;
|
||||||
private final PrintStream out;
|
private final PrintStream out;
|
||||||
private final SimpleDateFormat isoDateFormat;
|
private final SimpleDateFormat isoDateFormat;
|
||||||
private String[] stringTable;
|
private SerialNumberManager.StringTable stringTable;
|
||||||
|
|
||||||
public static SimpleDateFormat createSimpleDateFormat() {
|
public static SimpleDateFormat createSimpleDateFormat() {
|
||||||
SimpleDateFormat format =
|
SimpleDateFormat format =
|
||||||
|
@ -430,8 +430,9 @@ public final class PBImageXmlWriter {
|
||||||
((XATTR_NAMESPACE_EXT_MASK & (encodedName >> XATTR_NAMESPACE_EXT_OFFSET)) << 2);
|
((XATTR_NAMESPACE_EXT_MASK & (encodedName >> XATTR_NAMESPACE_EXT_OFFSET)) << 2);
|
||||||
o(INODE_SECTION_NS, XAttrProtos.XAttrProto.
|
o(INODE_SECTION_NS, XAttrProtos.XAttrProto.
|
||||||
XAttrNamespaceProto.valueOf(ns).toString());
|
XAttrNamespaceProto.valueOf(ns).toString());
|
||||||
o(SECTION_NAME,
|
o(SECTION_NAME, SerialNumberManager.XATTR.getString(
|
||||||
stringTable[XATTR_NAME_MASK & (encodedName >> XATTR_NAME_OFFSET)]);
|
XATTR_NAME_MASK & (encodedName >> XATTR_NAME_OFFSET),
|
||||||
|
stringTable));
|
||||||
ByteString val = xattr.getValue();
|
ByteString val = xattr.getValue();
|
||||||
if (val.isValidUtf8()) {
|
if (val.isValidUtf8()) {
|
||||||
o(INODE_SECTION_VAL, val.toStringUtf8());
|
o(INODE_SECTION_VAL, val.toStringUtf8());
|
||||||
|
@ -784,10 +785,9 @@ public final class PBImageXmlWriter {
|
||||||
.o(SNAPSHOT_DIFF_SECTION_CHILDREN_SIZE, d.getChildrenSize())
|
.o(SNAPSHOT_DIFF_SECTION_CHILDREN_SIZE, d.getChildrenSize())
|
||||||
.o(SNAPSHOT_DIFF_SECTION_IS_SNAPSHOT_ROOT, d.getIsSnapshotRoot())
|
.o(SNAPSHOT_DIFF_SECTION_IS_SNAPSHOT_ROOT, d.getIsSnapshotRoot())
|
||||||
.o(SECTION_NAME, d.getName().toStringUtf8());
|
.o(SECTION_NAME, d.getName().toStringUtf8());
|
||||||
INodeDirectory snapshotCopy = d.getSnapshotCopy();
|
if (d.hasSnapshotCopy()) {
|
||||||
if (snapshotCopy != null) {
|
|
||||||
out.print("<" + SNAPSHOT_DIFF_SECTION_SNAPSHOT_COPY + ">");
|
out.print("<" + SNAPSHOT_DIFF_SECTION_SNAPSHOT_COPY + ">");
|
||||||
dumpINodeDirectory(snapshotCopy);
|
dumpINodeDirectory(d.getSnapshotCopy());
|
||||||
out.print("</" + SNAPSHOT_DIFF_SECTION_SNAPSHOT_COPY + ">\n");
|
out.print("</" + SNAPSHOT_DIFF_SECTION_SNAPSHOT_COPY + ">\n");
|
||||||
}
|
}
|
||||||
o(SNAPSHOT_DIFF_SECTION_CREATED_LIST_SIZE, d.getCreatedListSize());
|
o(SNAPSHOT_DIFF_SECTION_CREATED_LIST_SIZE, d.getCreatedListSize());
|
||||||
|
@ -851,13 +851,7 @@ public final class PBImageXmlWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadStringTable(InputStream in) throws IOException {
|
private void loadStringTable(InputStream in) throws IOException {
|
||||||
StringTableSection s = StringTableSection.parseDelimitedFrom(in);
|
stringTable = FSImageLoader.loadStringTable(in);
|
||||||
stringTable = new String[s.getNumEntry() + 1];
|
|
||||||
for (int i = 0; i < s.getNumEntry(); ++i) {
|
|
||||||
StringTableSection.Entry e = StringTableSection.Entry
|
|
||||||
.parseDelimitedFrom(in);
|
|
||||||
stringTable[e.getId()] = e.getStr();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PBImageXmlWriter o(final String e, final Object v) {
|
private PBImageXmlWriter o(final String e, final Object v) {
|
||||||
|
|
|
@ -311,6 +311,7 @@ message StringTableSection {
|
||||||
optional string str = 2;
|
optional string str = 2;
|
||||||
}
|
}
|
||||||
optional uint32 numEntry = 1;
|
optional uint32 numEntry = 1;
|
||||||
|
optional uint32 maskBits = 2 [default = 0];
|
||||||
// repeated Entry
|
// repeated Entry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,12 +57,8 @@ public class TestCommitBlockSynchronization {
|
||||||
// set file's parent as root and put the file to inodeMap, so
|
// set file's parent as root and put the file to inodeMap, so
|
||||||
// FSNamesystem's isFileDeleted() method will return false on this file
|
// FSNamesystem's isFileDeleted() method will return false on this file
|
||||||
if (file.getParent() == null) {
|
if (file.getParent() == null) {
|
||||||
INodeDirectory mparent = mock(INodeDirectory.class);
|
INodeDirectory parent = namesystem.getFSDirectory().getRoot();
|
||||||
INodeDirectory parent = new INodeDirectory(mparent.getId(), new byte[0],
|
|
||||||
mparent.getPermissionStatus(), mparent.getAccessTime());
|
|
||||||
parent.setLocalName(new byte[0]);
|
|
||||||
parent.addChild(file);
|
parent.addChild(file);
|
||||||
file.setParent(parent);
|
|
||||||
}
|
}
|
||||||
namesystem.dir.getINodeMap().put(file);
|
namesystem.dir.getINodeMap().put(file);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue