HDFS-4188. Add Snapshot.ID_COMPARATOR for comparing IDs and fix a bug in ReadOnlyList.Util.binarySearch(..).

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/HDFS-2802@1410027 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Tsz-wo Sze 2012-11-15 21:34:54 +00:00
parent 2116d0520e
commit 8ca8687fb2
7 changed files with 73 additions and 22 deletions

View File

@ -70,3 +70,6 @@ Branch-2802 Snapshot (Unreleased)
HDFS-4148. Disallow write/modify operations on files and directories in a HDFS-4148. Disallow write/modify operations on files and directories in a
snapshot. (Brandon Li via suresh) snapshot. (Brandon Li via suresh)
HDFS-4188. Add Snapshot.ID_COMPARATOR for comparing IDs and fix a bug in
ReadOnlyList.Util.binarySearch(..). (szetszwo)

View File

@ -19,12 +19,9 @@ package org.apache.hadoop.hdfs.server.namenode;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceAudience;
@ -49,10 +46,8 @@ import com.google.common.primitives.SignedBytes;
*/ */
@InterfaceAudience.Private @InterfaceAudience.Private
public abstract class INode implements Comparable<byte[]> { public abstract class INode implements Comparable<byte[]> {
static final List<INode> EMPTY_LIST
= Collections.unmodifiableList(new ArrayList<INode>());
static final ReadOnlyList<INode> EMPTY_READ_ONLY_LIST static final ReadOnlyList<INode> EMPTY_READ_ONLY_LIST
= ReadOnlyList.Util.asReadOnlyList(EMPTY_LIST); = ReadOnlyList.Util.emptyList();
/** /**
* The inode name is in java UTF8 encoding; * The inode name is in java UTF8 encoding;

View File

@ -586,7 +586,7 @@ public class INodeDirectory extends INode {
} }
private void updateLatestSnapshot(Snapshot s) { private void updateLatestSnapshot(Snapshot s) {
if (snapshot == null || snapshot.compareTo(s) < 0) { if (Snapshot.ID_COMPARATOR.compare(snapshot, s) < 0) {
snapshot = s; snapshot = s;
} }
} }

View File

@ -79,17 +79,11 @@ public class INodeDirectoryWithSnapshot extends INodeDirectory {
return inodes == null? -1: Collections.binarySearch(inodes, name); return inodes == null? -1: Collections.binarySearch(inodes, name);
} }
/** The ID (e.g. snapshot ID) of this object. */
final int id;
/** c-list: inode(s) created in current. */ /** c-list: inode(s) created in current. */
private List<INode> created; private List<INode> created;
/** d-list: inode(s) deleted from current. */ /** d-list: inode(s) deleted from current. */
private List<INode> deleted; private List<INode> deleted;
Diff(int id) {
this.id = id;
}
/** /**
* Insert the inode to created. * Insert the inode to created.
* @param i the insertion point defined * @param i the insertion point defined
@ -251,7 +245,7 @@ public class INodeDirectoryWithSnapshot extends INodeDirectory {
@Override @Override
public String toString() { public String toString() {
return getClass().getSimpleName() + "_" + id return getClass().getSimpleName()
+ ":\n created=" + toString(created) + ":\n created=" + toString(created)
+ "\n deleted=" + toString(deleted); + "\n deleted=" + toString(deleted);
} }
@ -261,4 +255,4 @@ public class INodeDirectoryWithSnapshot extends INodeDirectory {
super(name, dir.getPermissionStatus()); super(name, dir.getPermissionStatus());
parent = dir; parent = dir;
} }
} }

View File

@ -17,11 +17,26 @@
*/ */
package org.apache.hadoop.hdfs.server.namenode.snapshot; package org.apache.hadoop.hdfs.server.namenode.snapshot;
import java.util.Comparator;
import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceAudience;
/** Snapshot of a sub-tree in the namesystem. */ /** Snapshot of a sub-tree in the namesystem. */
@InterfaceAudience.Private @InterfaceAudience.Private
public class Snapshot implements Comparable<byte[]> { public class Snapshot implements Comparable<byte[]> {
/** Compare snapshot IDs with null <= s for any snapshot s. */
public static final Comparator<Snapshot> ID_COMPARATOR
= new Comparator<Snapshot>() {
@Override
public int compare(Snapshot left, Snapshot right) {
if (left == null) {
return right == null? 0: -1;
} else {
return right == null? 1: left.id - right.id;
}
}
};
/** Snapshot ID. */ /** Snapshot ID. */
private final int id; private final int id;
/** The root directory of the snapshot. */ /** The root directory of the snapshot. */
@ -41,11 +56,6 @@ public class Snapshot implements Comparable<byte[]> {
public int compareTo(byte[] bytes) { public int compareTo(byte[] bytes) {
return root.compareTo(bytes); return root.compareTo(bytes);
} }
/** Compare snapshot IDs. */
public int compareTo(Snapshot s) {
return id - s.id;
}
@Override @Override
public String toString() { public String toString() {

View File

@ -52,6 +52,11 @@ public interface ReadOnlyList<E> extends Iterable<E> {
* Utilities for {@link ReadOnlyList} * Utilities for {@link ReadOnlyList}
*/ */
public static class Util { public static class Util {
/** @return an empty list. */
public static <E> ReadOnlyList<E> emptyList() {
return ReadOnlyList.Util.asReadOnlyList(Collections.<E>emptyList());
}
/** /**
* The same as {@link Collections#binarySearch(List, Object)} * The same as {@link Collections#binarySearch(List, Object)}
* except that the list is a {@link ReadOnlyList}. * except that the list is a {@link ReadOnlyList}.
@ -61,7 +66,20 @@ public interface ReadOnlyList<E> extends Iterable<E> {
*/ */
public static <K, E extends Comparable<K>> int binarySearch( public static <K, E extends Comparable<K>> int binarySearch(
final ReadOnlyList<E> list, final K key) { final ReadOnlyList<E> list, final K key) {
return Collections.binarySearch(asList(list), key); int lower = 0;
for(int upper = list.size() - 1; lower <= upper; ) {
final int mid = (upper + lower) >>> 1;
final int d = list.get(mid).compareTo(key);
if (d == 0) {
return mid;
} else if (d > 0) {
upper = mid - 1;
} else {
lower = mid + 1;
}
}
return -(lower + 1);
} }
/** /**

View File

@ -81,7 +81,7 @@ public class TestINodeDirectoryWithSnapshot {
// make modifications to current and record the diff // make modifications to current and record the diff
final List<INode> current = new ArrayList<INode>(previous); final List<INode> current = new ArrayList<INode>(previous);
final Diff diff = computeDiff? new Diff(0): null; final Diff diff = computeDiff? new Diff(): null;
for(int m = 0; m < numModifications; m++) { for(int m = 0; m < numModifications; m++) {
// if current is empty, the next operation must be create; // if current is empty, the next operation must be create;
@ -228,4 +228,35 @@ public class TestINodeDirectoryWithSnapshot {
diff.modify(oldinode, newinode); diff.modify(oldinode, newinode);
} }
} }
/**
* Test {@link Snapshot#ID_COMPARATOR}.
*/
@Test
public void testIdCmp() {
final INodeDirectory dir = new INodeDirectory("foo", PERM);
final INodeDirectorySnapshottable snapshottable
= INodeDirectorySnapshottable.newInstance(dir, 100);
final Snapshot[] snapshots = {
new Snapshot(1, "s1", snapshottable),
new Snapshot(1, "s1", snapshottable),
new Snapshot(2, "s2", snapshottable),
new Snapshot(2, "s2", snapshottable),
};
Assert.assertEquals(0, Snapshot.ID_COMPARATOR.compare(null, null));
for(Snapshot s : snapshots) {
Assert.assertTrue(Snapshot.ID_COMPARATOR.compare(null, s) < 0);
Assert.assertTrue(Snapshot.ID_COMPARATOR.compare(s, null) > 0);
for(Snapshot t : snapshots) {
final int expected = s.getRoot().getLocalName().compareTo(
t.getRoot().getLocalName());
final int computed = Snapshot.ID_COMPARATOR.compare(s, t);
Assert.assertEquals(expected > 0, computed > 0);
Assert.assertEquals(expected == 0, computed == 0);
Assert.assertEquals(expected < 0, computed < 0);
}
}
}
} }