Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,10 @@ public Iterator<E> iterator() {
return new EntryIterator();
}

public Set<K> entryKeySet() {
return partitions.keySet();
}

/**
* Iterator over the elements in the set.
* Iterates first by keys, then inside the partition
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,13 @@ public class DFSConfigKeys extends CommonConfigurationKeys {
public static final String DFS_NAMENODE_INODE_ATTRIBUTES_PROVIDER_BYPASS_USERS_KEY = "dfs.namenode.inode.attributes.provider.bypass.users";
public static final String DFS_NAMENODE_INODE_ATTRIBUTES_PROVIDER_BYPASS_USERS_DEFAULT = "";

public static final String DFS_NAMENODE_INOD_NAMESPACE_KEY_DEPTH =
"dfs.namenode.inode.namespace.key.depth";
public static final int DFS_NAMENODE_INOD_NAMESPACE_KEY_DEPTH_DEFAULT = 2;
public static final String DFS_NAMENODE_INOD_NUM_RANGES =
"dfs.namenode.inode.num.ranges";
public static final long DFS_NAMENODE_INOD_NUM_RANGES_DEFAULT = 256;

public static final String DFS_DATANODE_BP_READY_TIMEOUT_KEY = "dfs.datanode.bp-ready.timeout";
public static final long DFS_DATANODE_BP_READY_TIMEOUT_DEFAULT = 20;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ public enum DirOp {
FSDirectory(FSNamesystem ns, Configuration conf) throws IOException {
this.inodeId = new INodeId();
rootDir = createRoot(ns);
inodeMap = INodeMap.newInstance(rootDir, ns);
inodeMap = INodeMap.newInstance(rootDir, ns, conf);
tempInodeMap = new HashMap<>(1000);

// add rootDir to inodeMapTemp.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@ public static long indexOf(long[] key) {
return key[0];
}
long idx = LARGE_PRIME * key[0];
idx = (idx ^ (idx >> 32)) & (INodeMap.NUM_RANGES_STATIC -1);
idx = (idx ^ (idx >> 32)) & (INodeMap.getNumRanges() -1);
return idx;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@
import java.nio.charset.StandardCharsets;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.permission.FsPermission;
import org.apache.hadoop.fs.permission.PermissionStatus;
import org.apache.hadoop.hdfs.DFSConfigKeys;
import org.apache.hadoop.hdfs.protocol.HdfsConstants;
import org.apache.hadoop.hdfs.server.blockmanagement.BlockStoragePolicySuite;
import org.apache.hadoop.util.GSet;
Expand All @@ -36,22 +39,22 @@
* and INode.
*/
public class INodeMap {
static final int NAMESPACE_KEY_DEPTH = 2;
static final int NUM_RANGES_STATIC = 256; // power of 2
private static int numSpaceKeyDepth;
private static long numRanges;

public static class INodeKeyComparator implements Comparator<INode> {
INodeKeyComparator() {
FSDirectory.LOG.info("Namespace key depth = {}", NAMESPACE_KEY_DEPTH);
FSDirectory.LOG.info("Namespace key depth = {}", numSpaceKeyDepth);
}

@Override
public int compare(INode i1, INode i2) {
if (i1 == null || i2 == null) {
throw new NullPointerException("Cannot compare null INodes");
}
long[] key1 = i1.getNamespaceKey(NAMESPACE_KEY_DEPTH);
long[] key2 = i2.getNamespaceKey(NAMESPACE_KEY_DEPTH);
for(int l = 0; l < NAMESPACE_KEY_DEPTH; l++) {
long[] key1 = i1.getNamespaceKey(numSpaceKeyDepth);
long[] key2 = i2.getNamespaceKey(numSpaceKeyDepth);
for(int l = 0; l < numSpaceKeyDepth; l++) {
if(key1[l] == key2[l]) continue;
return (key1[l] < key2[l] ? -1 : 1);
}
Expand All @@ -65,21 +68,21 @@ public int compare(INode i1, INode i2) {
*/
public static class HPINodeKeyComparator implements Comparator<INode> {
HPINodeKeyComparator() {
FSDirectory.LOG.info("Namespace key depth = {}", NAMESPACE_KEY_DEPTH);
FSDirectory.LOG.info("Namespace key depth = {}", numSpaceKeyDepth);
}

@Override
public int compare(INode i1, INode i2) {
if (i1 == null || i2 == null) {
throw new NullPointerException("Cannot compare null INodes");
}
long[] key1 = i1.getNamespaceKey(NAMESPACE_KEY_DEPTH);
long[] key2 = i2.getNamespaceKey(NAMESPACE_KEY_DEPTH);
long[] key1 = i1.getNamespaceKey(numSpaceKeyDepth);
long[] key2 = i2.getNamespaceKey(numSpaceKeyDepth);
long key1_0 = INode.indexOf(key1);
long key2_0 = INode.indexOf(key2);
if(key1_0 != key2_0)
return (key1_0 < key2_0 ? -1 : 1);
for(int l = 1; l < NAMESPACE_KEY_DEPTH; l++) {
for(int l = 1; l < numSpaceKeyDepth; l++) {
if(key1[l] == key2[l]) continue;
return (key1[l] < key2[l] ? -1 : 1);
}
Expand All @@ -99,6 +102,14 @@ public int compare(INode i1, INode i2) {
}
}

public static long getNumRanges() {
return numRanges;
}

public static int getNumSpaceKeyDepth() {
return numSpaceKeyDepth;
}

public class INodeMapLock extends LatchLock<ReentrantReadWriteLock> {
private ReentrantReadWriteLock childLock;

Expand Down Expand Up @@ -179,8 +190,8 @@ protected LatchLock<ReentrantReadWriteLock> clone() {
}

static INodeMap newInstance(INodeDirectory rootDir,
FSNamesystem ns) {
return new INodeMap(rootDir, ns);
FSNamesystem ns, Configuration conf) {
return new INodeMap(rootDir, ns, conf);
}

/** Synchronized by external lock. */
Expand All @@ -191,8 +202,45 @@ public Iterator<INodeWithAdditionalFields> getMapIterator() {
return map.iterator();
}

private INodeMap(INodeDirectory rootDir, FSNamesystem ns) {
public Set<INode> rangeKeys() {
return ((PartitionedGSet)map).entryKeySet();
}

/**
* Check if a number is a power of two.
* @param n The number to be checked.
* @return true if it is a power of two, else false.
*/
private static boolean checkPowerOfTwo(long n) {
if (n < 1) {
return false;
}
return (n&(n - 1)) == 0;
}

private static void setStaticField(Configuration conf) {
numSpaceKeyDepth = conf.getInt(DFSConfigKeys.DFS_NAMENODE_INOD_NAMESPACE_KEY_DEPTH,
DFSConfigKeys.DFS_NAMENODE_INOD_NAMESPACE_KEY_DEPTH_DEFAULT);
if (numSpaceKeyDepth < 1) {
numSpaceKeyDepth = DFSConfigKeys.DFS_NAMENODE_INOD_NAMESPACE_KEY_DEPTH_DEFAULT;
}

numRanges = conf.getLong(DFSConfigKeys.DFS_NAMENODE_INOD_NUM_RANGES,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a check here to make sure numRanges is power of 2? thanks,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @xinglin for the comment.
I will update it later.

DFSConfigKeys.DFS_NAMENODE_INOD_NUM_RANGES_DEFAULT);
boolean isPowerOfTwo = checkPowerOfTwo(numRanges);
if (!isPowerOfTwo) {
FSDirectory.LOG.warn("Num of ranges = {}. It should be a power of two.",
numRanges);
}
if ((numRanges < 1) || !isPowerOfTwo) {
numRanges = DFSConfigKeys.DFS_NAMENODE_INOD_NUM_RANGES_DEFAULT;
}
}

private INodeMap(INodeDirectory rootDir, FSNamesystem ns, Configuration conf) {
this.namesystem = ns;
setStaticField(conf);

// Compute the map capacity by allocating 1% of total memory
int capacity = LightWeightGSet.computeCapacity(1, "INodeMap");
this.map = new PartitionedGSet<>(capacity, new INodeKeyComparator(),
Expand All @@ -203,10 +251,18 @@ private INodeMap(INodeDirectory rootDir, FSNamesystem ns) {
(PartitionedGSet<INode, INodeWithAdditionalFields>) map;
PermissionStatus perm = new PermissionStatus(
"", "", new FsPermission((short) 0));
for(int p = 0; p < NUM_RANGES_STATIC; p++) {
for(int p = 0; p < numRanges; p++) {
INodeDirectory key = new INodeDirectory(INodeId.ROOT_INODE_ID,
"range key".getBytes(StandardCharsets.UTF_8), perm, 0);
key.setParent(new INodeDirectory((long)p, null, perm, 0));
INodeDirectory ppKey = key;
if (numSpaceKeyDepth > 2) {
for (int pp = 0; pp < (numSpaceKeyDepth - 2); pp++) {
INodeDirectory tmpKey = new INodeDirectory((long)0, null, perm, 0);
ppKey.setParent(tmpKey);
ppKey = tmpKey;
}
}
ppKey.setParent(new INodeDirectory((long)p, null, perm, 0));
pgs.addNewPartition(key);
}

Expand Down Expand Up @@ -262,10 +318,18 @@ public INode get(long id) {
PermissionStatus perm =
new PermissionStatus("", "", new FsPermission((short) 0));
// TODO: create a static array, to avoid creation of keys each time.
for (int p = 0; p < NUM_RANGES_STATIC; p++) {
for (int p = 0; p < numRanges; p++) {
INodeDirectory key = new INodeDirectory(INodeId.ROOT_INODE_ID,
"range key".getBytes(StandardCharsets.UTF_8), perm, 0);
key.setParent(new INodeDirectory((long)p, null, perm, 0));
INodeDirectory ppKey = key;
if (numSpaceKeyDepth > 2) {
for (int pp = 0; pp < (numSpaceKeyDepth - 2); pp++) {
INodeDirectory tmpKey = new INodeDirectory((long)0, null, perm, 0);
ppKey.setParent(tmpKey);
ppKey = tmpKey;
}
}
ppKey.setParent(new INodeDirectory((long)p, null, perm, 0));
PartitionedGSet.PartitionEntry e = pgs.getPartition(key);

if (e.contains(inode)) {
Expand All @@ -279,18 +343,18 @@ public INode get(long id) {
public INode get(INode inode) {

/*
* Check whether the Inode has (NAMESPACE_KEY_DEPTH - 1) levels of parent
* Check whether the Inode has (numSpaceKeyDepth - 1) levels of parent
* dirs
*/
int i = NAMESPACE_KEY_DEPTH - 1;
int i = numSpaceKeyDepth - 1;
INode tmpInode = inode;
while (i > 0 && tmpInode.getParent() != null) {
tmpInode = tmpInode.getParent();
i--;
}

/*
* If the Inode has (NAMESPACE_KEY_DEPTH - 1) levels of parent dirs,
* If the Inode has (numSpaceKeyDepth - 1) levels of parent dirs,
* use map.get(); else, fall back to get INode based on Inode ID.
*/
if (i == 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5152,6 +5152,25 @@
</description>
</property>

<property>
<name>dfs.namenode.inode.namespace.key.depth</name>
<value>2</value>
<description>
Defines a finite number of parent keys for INodeIdKey.
For example, if the value is 2, INodeIdKey can be represented as :
'{RootINodeId, parentINodeId, selfINodeId}'.
</description>
</property>

<property>
<name>dfs.namenode.inode.num.ranges</name>
<value>256</value>
<description>
Defines the initial number of PartitionedEntries that a PartitionedGSet
contains, usually a power of 2.
</description>
</property>

<property>
<name>dfs.namenode.max-num-blocks-to-log</name>
<value>1000</value>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* 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 org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hdfs.DFSConfigKeys;
import org.apache.hadoop.hdfs.HdfsConfiguration;
import org.apache.hadoop.hdfs.MiniDFSCluster;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Iterator;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

/**
* Test {@link INodeMap}.
*/
public class TestINodeMap {
public static final Logger LOG =
LoggerFactory.getLogger(TestINodeMap.class);

@Test
public void testSpaceKeyDepthAndNumRanges() throws Exception {
Configuration conf = new HdfsConfiguration();
conf.setInt(DFSConfigKeys.DFS_NAMENODE_INOD_NAMESPACE_KEY_DEPTH, 3);
conf.setLong(DFSConfigKeys.DFS_NAMENODE_INOD_NUM_RANGES, 128);
MiniDFSCluster cluster = null;
try {
cluster = new MiniDFSCluster.Builder(conf).numDataNodes(3).build();
cluster.waitActive();
FSNamesystem fsn = cluster.getNamesystem();
FSDirectory fsDirectory = new FSDirectory(fsn, conf);
assertTrue(fsDirectory.getINodeMap() != null);
assertEquals(INodeMap.getNumRanges(), 128);
assertEquals(INodeMap.getNumSpaceKeyDepth(), 3);
} finally {
if (cluster != null) {
cluster.shutdown();
}
}
}

@Test
public void testRangeKeys() throws Exception {
Configuration conf = new HdfsConfiguration();
conf.setInt(DFSConfigKeys.DFS_NAMENODE_INOD_NAMESPACE_KEY_DEPTH, 4);
conf.setLong(DFSConfigKeys.DFS_NAMENODE_INOD_NUM_RANGES, 8);
MiniDFSCluster cluster = null;
try {
cluster = new MiniDFSCluster.Builder(conf).numDataNodes(3).build();
cluster.waitActive();
FSNamesystem fsn = cluster.getNamesystem();
FSDirectory fsDirectory = new FSDirectory(fsn, conf);
INodeMap iNodeMap = fsDirectory.getINodeMap();
int level = 0;
for (Iterator<INode> it = iNodeMap.rangeKeys().iterator(); it.hasNext();) {
INode inode = it.next();
long[] namespaceKey = inode.getNamespaceKey(4);
assertEquals(level, namespaceKey[0]);
assertEquals(0, namespaceKey[1]);
assertEquals(0, namespaceKey[2]);
assertEquals(INodeId.ROOT_INODE_ID, namespaceKey[3]);
level++;
}
} finally {
if (cluster != null) {
cluster.shutdown();
}
}
}
}