HDFS-13173. Replace ArrayList with DirectoryDiffList(SnapshotSkipList) to store DirectoryDiffs. Contributed by Shashikant Banerjee
This commit is contained in:
parent
90d2bdcb75
commit
ba82e5c488
|
@ -419,6 +419,15 @@ public class DFSConfigKeys extends CommonConfigurationKeys {
|
||||||
"dfs.namenode.snapshot.max.limit";
|
"dfs.namenode.snapshot.max.limit";
|
||||||
|
|
||||||
public static final int DFS_NAMENODE_SNAPSHOT_MAX_LIMIT_DEFAULT = 65536;
|
public static final int DFS_NAMENODE_SNAPSHOT_MAX_LIMIT_DEFAULT = 65536;
|
||||||
|
public static final String DFS_NAMENODE_SNAPSHOT_SKIPLIST_SKIP_INTERVAL =
|
||||||
|
"dfs.namenode.snapshot.skiplist.interval";
|
||||||
|
public static final int DFS_NAMENODE_SNAPSHOT_SKIPLIST_SKIP_INTERVAL_DEFAULT =
|
||||||
|
10;
|
||||||
|
public static final String DFS_NAMENODE_SNAPSHOT_SKIPLIST_MAX_LEVELS =
|
||||||
|
"dfs.namenode.snapshot.skiplist.max.levels";
|
||||||
|
public static final int
|
||||||
|
DFS_NAMENODE_SNAPSHOT_SKIPLIST_MAX_SKIP_LEVELS_DEFAULT = 0;
|
||||||
|
|
||||||
// Whether to enable datanode's stale state detection and usage for reads
|
// Whether to enable datanode's stale state detection and usage for reads
|
||||||
public static final String DFS_NAMENODE_AVOID_STALE_DATANODE_FOR_READ_KEY = "dfs.namenode.avoid.read.stale.datanode";
|
public static final String DFS_NAMENODE_AVOID_STALE_DATANODE_FOR_READ_KEY = "dfs.namenode.avoid.read.stale.datanode";
|
||||||
public static final boolean DFS_NAMENODE_AVOID_STALE_DATANODE_FOR_READ_DEFAULT = false;
|
public static final boolean DFS_NAMENODE_AVOID_STALE_DATANODE_FOR_READ_DEFAULT = false;
|
||||||
|
|
|
@ -138,10 +138,14 @@ abstract class AbstractINodeDiffList<N extends INode,
|
||||||
return n == 0 ? null : diffs.get(n - 1);
|
return n == 0 ? null : diffs.get(n - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DiffList<D> newDiffs() {
|
||||||
|
return new DiffListByArrayList<>(
|
||||||
|
INodeDirectory.DEFAULT_FILES_PER_DIRECTORY);
|
||||||
|
}
|
||||||
|
|
||||||
private void createDiffsIfNeeded() {
|
private void createDiffsIfNeeded() {
|
||||||
if (diffs == null) {
|
if (diffs == null) {
|
||||||
diffs =
|
diffs = newDiffs();
|
||||||
new DiffListByArrayList<>(INodeDirectory.DEFAULT_FILES_PER_DIRECTORY);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,9 +68,9 @@ import java.util.concurrent.ThreadLocalRandom;
|
||||||
* <p>
|
* <p>
|
||||||
* Once a snapshot gets deleted, the list needs to be balanced.
|
* Once a snapshot gets deleted, the list needs to be balanced.
|
||||||
*/
|
*/
|
||||||
public class DirectoryDiffList implements DiffList<DirectoryDiff> {
|
public class DiffListBySkipList implements DiffList<DirectoryDiff> {
|
||||||
public static final Logger LOG =
|
public static final Logger LOG =
|
||||||
LoggerFactory.getLogger(DirectoryDiffList.class);
|
LoggerFactory.getLogger(DiffListBySkipList.class);
|
||||||
|
|
||||||
private static class SkipDiff {
|
private static class SkipDiff {
|
||||||
/**
|
/**
|
||||||
|
@ -240,7 +240,7 @@ public class DirectoryDiffList implements DiffList<DirectoryDiff> {
|
||||||
/**
|
/**
|
||||||
* Constructs a new, empty instance of SkipList.
|
* Constructs a new, empty instance of SkipList.
|
||||||
*/
|
*/
|
||||||
public DirectoryDiffList(int capacity, int interval, int skipLevel) {
|
public DiffListBySkipList(int capacity, int interval, int skipLevel) {
|
||||||
skipNodeList = new ArrayList<>(capacity);
|
skipNodeList = new ArrayList<>(capacity);
|
||||||
head = new SkipListNode(null, 0);
|
head = new SkipListNode(null, 0);
|
||||||
this.maxSkipLevels = skipLevel;
|
this.maxSkipLevels = skipLevel;
|
|
@ -0,0 +1,46 @@
|
||||||
|
/**
|
||||||
|
* 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.snapshot;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.snapshot.DirectoryWithSnapshotFeature.DirectoryDiff;
|
||||||
|
|
||||||
|
import java.util.function.IntFunction;
|
||||||
|
|
||||||
|
/** For creating {@link DiffList} for {@link DirectoryDiff}. */
|
||||||
|
public abstract class DirectoryDiffListFactory {
|
||||||
|
public static DiffList<DirectoryDiff> createDiffList(int capacity) {
|
||||||
|
return constructor.apply(capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void init(int skipInterval, int maxLevels, Log log) {
|
||||||
|
if (maxLevels > 0) {
|
||||||
|
constructor = c -> new DiffListBySkipList(c, skipInterval, maxLevels);
|
||||||
|
log.info("SkipList is enabled with skipInterval=" + skipInterval
|
||||||
|
+ ", maxLevels=" + maxLevels);
|
||||||
|
} else {
|
||||||
|
constructor = c -> new DiffListByArrayList<>(c);
|
||||||
|
log.info("SkipList is disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static volatile IntFunction<DiffList<DirectoryDiff>> constructor
|
||||||
|
= c -> new DiffListByArrayList<>(c);
|
||||||
|
|
||||||
|
private DirectoryDiffListFactory() {}
|
||||||
|
}
|
|
@ -334,6 +334,12 @@ public class DirectoryWithSnapshotFeature implements INode.Feature {
|
||||||
: new INodeDirectoryAttributes.SnapshotCopy(currentDir);
|
: new INodeDirectoryAttributes.SnapshotCopy(currentDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
DiffList<DirectoryDiff> newDiffs() {
|
||||||
|
return DirectoryDiffListFactory
|
||||||
|
.createDiffList(INodeDirectory.DEFAULT_FILES_PER_DIRECTORY);
|
||||||
|
}
|
||||||
|
|
||||||
/** Replace the given child in the created/deleted list, if there is any. */
|
/** Replace the given child in the created/deleted list, if there is any. */
|
||||||
public boolean replaceChild(final ListType type, final INode oldChild,
|
public boolean replaceChild(final ListType type, final INode oldChild,
|
||||||
final INode newChild) {
|
final INode newChild) {
|
||||||
|
|
|
@ -127,6 +127,14 @@ public class SnapshotManager implements SnapshotStatsMXBean {
|
||||||
+ snapshotDiffAllowSnapRootDescendant
|
+ snapshotDiffAllowSnapRootDescendant
|
||||||
+ ", maxSnapshotLimit: "
|
+ ", maxSnapshotLimit: "
|
||||||
+ maxSnapshotLimit);
|
+ maxSnapshotLimit);
|
||||||
|
|
||||||
|
final int maxLevels = conf.getInt(
|
||||||
|
DFSConfigKeys.DFS_NAMENODE_SNAPSHOT_SKIPLIST_MAX_LEVELS,
|
||||||
|
DFSConfigKeys.DFS_NAMENODE_SNAPSHOT_SKIPLIST_MAX_SKIP_LEVELS_DEFAULT);
|
||||||
|
final int skipInterval = conf.getInt(
|
||||||
|
DFSConfigKeys.DFS_NAMENODE_SNAPSHOT_SKIPLIST_SKIP_INTERVAL,
|
||||||
|
DFSConfigKeys.DFS_NAMENODE_SNAPSHOT_SKIPLIST_SKIP_INTERVAL_DEFAULT);
|
||||||
|
DirectoryDiffListFactory.init(skipInterval, maxLevels, LOG);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
|
|
|
@ -4362,7 +4362,6 @@
|
||||||
across to the client within one rpc call.
|
across to the client within one rpc call.
|
||||||
</description>
|
</description>
|
||||||
</property>
|
</property>
|
||||||
|
|
||||||
<property>
|
<property>
|
||||||
<name>dfs.namenode.snapshot.max.limit</name>
|
<name>dfs.namenode.snapshot.max.limit</name>
|
||||||
<value>65536</value>
|
<value>65536</value>
|
||||||
|
@ -4373,6 +4372,24 @@
|
||||||
</description>
|
</description>
|
||||||
</property>
|
</property>
|
||||||
|
|
||||||
|
<property>
|
||||||
|
<name>dfs.namenode.snapshot.skiplist.max.levels</name>
|
||||||
|
<value>0</value>
|
||||||
|
<description>
|
||||||
|
Maximum no of the skip levels to be maintained in the skip list for
|
||||||
|
storing directory snapshot diffs. By default, it is set to 0 and a linear
|
||||||
|
list will be used to store the directory snapshot diffs.
|
||||||
|
</description>
|
||||||
|
</property>
|
||||||
|
<property>
|
||||||
|
<name>dfs.namenode.snapshot.skiplist.interval</name>
|
||||||
|
<value>10</value>
|
||||||
|
<description>
|
||||||
|
The interval after which the skip levels will be formed in the skip list
|
||||||
|
for storing directory snapshot diffs. By default, value is set to 10.
|
||||||
|
</description>
|
||||||
|
</property>
|
||||||
|
|
||||||
<property>
|
<property>
|
||||||
<name>dfs.pipeline.ecn</name>
|
<name>dfs.pipeline.ecn</name>
|
||||||
<value>false</value>
|
<value>false</value>
|
||||||
|
|
|
@ -41,7 +41,7 @@ import java.util.function.IntFunction;
|
||||||
/**
|
/**
|
||||||
* This class tests the DirectoryDiffList API's.
|
* This class tests the DirectoryDiffList API's.
|
||||||
*/
|
*/
|
||||||
public class TestDirectoryDiffList{
|
public class TestDiffListBySkipList {
|
||||||
static final int NUM_SNAPSHOTS = 100;
|
static final int NUM_SNAPSHOTS = 100;
|
||||||
static {
|
static {
|
||||||
SnapshotTestHelper.disableLogs();
|
SnapshotTestHelper.disableLogs();
|
||||||
|
@ -78,7 +78,7 @@ public class TestDirectoryDiffList{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void verifyChildrenList(DirectoryDiffList skip, INodeDirectory dir) {
|
static void verifyChildrenList(DiffListBySkipList skip, INodeDirectory dir) {
|
||||||
final int n = skip.size();
|
final int n = skip.size();
|
||||||
for (int i = 0; i < skip.size(); i++) {
|
for (int i = 0; i < skip.size(); i++) {
|
||||||
final List<INode> expected = ReadOnlyList.Util.asList(
|
final List<INode> expected = ReadOnlyList.Util.asList(
|
||||||
|
@ -95,7 +95,7 @@ public class TestDirectoryDiffList{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void verifyChildrenList(
|
static void verifyChildrenList(
|
||||||
DiffList<DirectoryDiff> array, DirectoryDiffList skip,
|
DiffList<DirectoryDiff> array, DiffListBySkipList skip,
|
||||||
INodeDirectory dir, List<INode> childrenList) {
|
INodeDirectory dir, List<INode> childrenList) {
|
||||||
final int n = array.size();
|
final int n = array.size();
|
||||||
Assert.assertEquals(n, skip.size());
|
Assert.assertEquals(n, skip.size());
|
||||||
|
@ -144,13 +144,13 @@ public class TestDirectoryDiffList{
|
||||||
|
|
||||||
static void testAddLast(int n) throws Exception {
|
static void testAddLast(int n) throws Exception {
|
||||||
final Path root = new Path("/testAddLast" + n);
|
final Path root = new Path("/testAddLast" + n);
|
||||||
DirectoryDiffList.LOG.info("run " + root);
|
DiffListBySkipList.LOG.info("run " + root);
|
||||||
|
|
||||||
final DirectoryDiffList skipList = new DirectoryDiffList(0, 3, 5);
|
final DiffListBySkipList skipList = new DiffListBySkipList(0, 3, 5);
|
||||||
final DiffList<DirectoryDiff> arrayList = new DiffListByArrayList<>(0);
|
final DiffList<DirectoryDiff> arrayList = new DiffListByArrayList<>(0);
|
||||||
INodeDirectory dir = addDiff(n, skipList, arrayList, root);
|
INodeDirectory dir = addDiff(n, skipList, arrayList, root);
|
||||||
// verify that the both the children list obtained from hdfs and
|
// verify that the both the children list obtained from hdfs and
|
||||||
// DirectoryDiffList are same
|
// DiffListBySkipList are same
|
||||||
verifyChildrenList(skipList, dir);
|
verifyChildrenList(skipList, dir);
|
||||||
verifyChildrenList(arrayList, skipList, dir, Collections.emptyList());
|
verifyChildrenList(arrayList, skipList, dir, Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
@ -163,7 +163,7 @@ public class TestDirectoryDiffList{
|
||||||
|
|
||||||
static void testAddFirst(int n) throws Exception {
|
static void testAddFirst(int n) throws Exception {
|
||||||
final Path root = new Path("/testAddFirst" + n);
|
final Path root = new Path("/testAddFirst" + n);
|
||||||
DirectoryDiffList.LOG.info("run " + root);
|
DiffListBySkipList.LOG.info("run " + root);
|
||||||
|
|
||||||
hdfs.mkdirs(root);
|
hdfs.mkdirs(root);
|
||||||
for (int i = 1; i < n; i++) {
|
for (int i = 1; i < n; i++) {
|
||||||
|
@ -180,7 +180,7 @@ public class TestDirectoryDiffList{
|
||||||
DiffList<DirectoryDiff> diffs = dir.getDiffs().asList();
|
DiffList<DirectoryDiff> diffs = dir.getDiffs().asList();
|
||||||
List<INode> childrenList = ReadOnlyList.Util.asList(dir.getChildrenList(
|
List<INode> childrenList = ReadOnlyList.Util.asList(dir.getChildrenList(
|
||||||
diffs.get(0).getSnapshotId()));
|
diffs.get(0).getSnapshotId()));
|
||||||
final DirectoryDiffList skipList = new DirectoryDiffList(0, 3, 5);
|
final DiffListBySkipList skipList = new DiffListBySkipList(0, 3, 5);
|
||||||
final DiffList<DirectoryDiff> arrayList = new DiffListByArrayList<>(0);
|
final DiffList<DirectoryDiff> arrayList = new DiffListByArrayList<>(0);
|
||||||
for (int i = diffs.size() - 1; i >= 0; i--) {
|
for (int i = diffs.size() - 1; i >= 0; i--) {
|
||||||
final DirectoryDiff d = diffs.get(i);
|
final DirectoryDiff d = diffs.get(i);
|
||||||
|
@ -188,7 +188,7 @@ public class TestDirectoryDiffList{
|
||||||
arrayList.addFirst(d);
|
arrayList.addFirst(d);
|
||||||
}
|
}
|
||||||
// verify that the both the children list obtained from hdfs and
|
// verify that the both the children list obtained from hdfs and
|
||||||
// DirectoryDiffList are same
|
// DiffListBySkipList are same
|
||||||
verifyChildrenList(skipList, dir);
|
verifyChildrenList(skipList, dir);
|
||||||
verifyChildrenList(arrayList, skipList, dir, childrenList);
|
verifyChildrenList(arrayList, skipList, dir, childrenList);
|
||||||
}
|
}
|
||||||
|
@ -231,9 +231,9 @@ public class TestDirectoryDiffList{
|
||||||
static void testRemove(String name, int n, IntFunction<Integer> indexFunction)
|
static void testRemove(String name, int n, IntFunction<Integer> indexFunction)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
final Path root = new Path("/testRemove" + name + n);
|
final Path root = new Path("/testRemove" + name + n);
|
||||||
DirectoryDiffList.LOG.info("run " + root);
|
DiffListBySkipList.LOG.info("run " + root);
|
||||||
|
|
||||||
final DirectoryDiffList skipList = new DirectoryDiffList(0, 3, 5);
|
final DiffListBySkipList skipList = new DiffListBySkipList(0, 3, 5);
|
||||||
final DiffList<DirectoryDiff> arrayList = new DiffListByArrayList<>(0);
|
final DiffList<DirectoryDiff> arrayList = new DiffListByArrayList<>(0);
|
||||||
final INodeDirectory dir = addDiff(n, skipList, arrayList, root);
|
final INodeDirectory dir = addDiff(n, skipList, arrayList, root);
|
||||||
Assert.assertEquals(n, arrayList.size());
|
Assert.assertEquals(n, arrayList.size());
|
||||||
|
@ -248,9 +248,9 @@ public class TestDirectoryDiffList{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static DirectoryDiff remove(int i, DirectoryDiffList skip,
|
static DirectoryDiff remove(int i, DiffListBySkipList skip,
|
||||||
DiffList<DirectoryDiff> array) {
|
DiffList<DirectoryDiff> array) {
|
||||||
DirectoryDiffList.LOG.info("remove " + i);
|
DiffListBySkipList.LOG.info("remove " + i);
|
||||||
final DirectoryDiff expected = array.remove(i);
|
final DirectoryDiff expected = array.remove(i);
|
||||||
final DirectoryDiff computed = skip.remove(i);
|
final DirectoryDiff computed = skip.remove(i);
|
||||||
assertDirectoryDiff(expected, computed);
|
assertDirectoryDiff(expected, computed);
|
Loading…
Reference in New Issue