|
@@ -17,15 +17,21 @@
|
|
*/
|
|
*/
|
|
package org.apache.hadoop.hdfs.protocol;
|
|
package org.apache.hadoop.hdfs.protocol;
|
|
|
|
|
|
|
|
+import java.util.List;
|
|
|
|
+
|
|
import org.apache.hadoop.classification.InterfaceAudience;
|
|
import org.apache.hadoop.classification.InterfaceAudience;
|
|
import org.apache.hadoop.classification.InterfaceStability;
|
|
import org.apache.hadoop.classification.InterfaceStability;
|
|
import org.apache.hadoop.hdfs.security.token.block.BlockTokenIdentifier;
|
|
import org.apache.hadoop.hdfs.security.token.block.BlockTokenIdentifier;
|
|
import org.apache.hadoop.security.token.Token;
|
|
import org.apache.hadoop.security.token.Token;
|
|
|
|
|
|
|
|
+import com.google.common.base.Preconditions;
|
|
|
|
+import com.google.common.collect.Lists;
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Associates a block with the Datanodes that contain its replicas
|
|
* Associates a block with the Datanodes that contain its replicas
|
|
* and other block metadata (E.g. the file offset associated with this
|
|
* and other block metadata (E.g. the file offset associated with this
|
|
- * block, whether it is corrupt, security token, etc).
|
|
|
|
|
|
+ * block, whether it is corrupt, a location is cached in memory,
|
|
|
|
+ * security token, etc).
|
|
*/
|
|
*/
|
|
@InterfaceAudience.Private
|
|
@InterfaceAudience.Private
|
|
@InterfaceStability.Evolving
|
|
@InterfaceStability.Evolving
|
|
@@ -39,9 +45,16 @@ public class LocatedBlock {
|
|
// their locations are not part of this object
|
|
// their locations are not part of this object
|
|
private boolean corrupt;
|
|
private boolean corrupt;
|
|
private Token<BlockTokenIdentifier> blockToken = new Token<BlockTokenIdentifier>();
|
|
private Token<BlockTokenIdentifier> blockToken = new Token<BlockTokenIdentifier>();
|
|
|
|
+ /**
|
|
|
|
+ * List of cached datanode locations
|
|
|
|
+ */
|
|
|
|
+ private DatanodeInfo[] cachedLocs;
|
|
|
|
+
|
|
|
|
+ // Used when there are no locations
|
|
|
|
+ private static final DatanodeInfo[] EMPTY_LOCS = new DatanodeInfo[0];
|
|
|
|
|
|
public LocatedBlock(ExtendedBlock b, DatanodeInfo[] locs) {
|
|
public LocatedBlock(ExtendedBlock b, DatanodeInfo[] locs) {
|
|
- this(b, locs, -1, false); // startOffset is unknown
|
|
|
|
|
|
+ this(b, locs, -1); // startOffset is unknown
|
|
}
|
|
}
|
|
|
|
|
|
public LocatedBlock(ExtendedBlock b, DatanodeInfo[] locs, long startOffset) {
|
|
public LocatedBlock(ExtendedBlock b, DatanodeInfo[] locs, long startOffset) {
|
|
@@ -50,14 +63,26 @@ public class LocatedBlock {
|
|
|
|
|
|
public LocatedBlock(ExtendedBlock b, DatanodeInfo[] locs, long startOffset,
|
|
public LocatedBlock(ExtendedBlock b, DatanodeInfo[] locs, long startOffset,
|
|
boolean corrupt) {
|
|
boolean corrupt) {
|
|
|
|
+ this(b, locs, startOffset, corrupt, EMPTY_LOCS);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public LocatedBlock(ExtendedBlock b, DatanodeInfo[] locs, long startOffset,
|
|
|
|
+ boolean corrupt, DatanodeInfo[] cachedLocs) {
|
|
this.b = b;
|
|
this.b = b;
|
|
this.offset = startOffset;
|
|
this.offset = startOffset;
|
|
this.corrupt = corrupt;
|
|
this.corrupt = corrupt;
|
|
if (locs==null) {
|
|
if (locs==null) {
|
|
- this.locs = new DatanodeInfo[0];
|
|
|
|
|
|
+ this.locs = EMPTY_LOCS;
|
|
} else {
|
|
} else {
|
|
this.locs = locs;
|
|
this.locs = locs;
|
|
}
|
|
}
|
|
|
|
+ Preconditions.checkArgument(cachedLocs != null,
|
|
|
|
+ "cachedLocs should not be null, use a different constructor");
|
|
|
|
+ if (cachedLocs.length == 0) {
|
|
|
|
+ this.cachedLocs = EMPTY_LOCS;
|
|
|
|
+ } else {
|
|
|
|
+ this.cachedLocs = cachedLocs;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
public Token<BlockTokenIdentifier> getBlockToken() {
|
|
public Token<BlockTokenIdentifier> getBlockToken() {
|
|
@@ -96,6 +121,36 @@ public class LocatedBlock {
|
|
return this.corrupt;
|
|
return this.corrupt;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Add a the location of a cached replica of the block.
|
|
|
|
+ *
|
|
|
|
+ * @param loc of datanode with the cached replica
|
|
|
|
+ */
|
|
|
|
+ public void addCachedLoc(DatanodeInfo loc) {
|
|
|
|
+ List<DatanodeInfo> cachedList = Lists.newArrayList(cachedLocs);
|
|
|
|
+ if (cachedList.contains(loc)) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ // Try to re-use a DatanodeInfo already in loc
|
|
|
|
+ for (int i=0; i<locs.length; i++) {
|
|
|
|
+ if (locs[i].equals(loc)) {
|
|
|
|
+ cachedList.add(locs[i]);
|
|
|
|
+ cachedLocs = cachedList.toArray(cachedLocs);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // Not present in loc, add it and go
|
|
|
|
+ cachedList.add(loc);
|
|
|
|
+ cachedLocs = cachedList.toArray(cachedLocs);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * @return Datanodes with a cached block replica
|
|
|
|
+ */
|
|
|
|
+ public DatanodeInfo[] getCachedLocations() {
|
|
|
|
+ return cachedLocs;
|
|
|
|
+ }
|
|
|
|
+
|
|
@Override
|
|
@Override
|
|
public String toString() {
|
|
public String toString() {
|
|
return getClass().getSimpleName() + "{" + b
|
|
return getClass().getSimpleName() + "{" + b
|