|
@@ -156,12 +156,7 @@ import org.apache.hadoop.hdfs.security.token.block.BlockTokenSecretManager;
|
|
import org.apache.hadoop.hdfs.security.token.block.BlockTokenSecretManager.AccessMode;
|
|
import org.apache.hadoop.hdfs.security.token.block.BlockTokenSecretManager.AccessMode;
|
|
import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenIdentifier;
|
|
import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenIdentifier;
|
|
import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenSecretManager;
|
|
import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenSecretManager;
|
|
-import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfo;
|
|
|
|
-import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoUnderConstruction;
|
|
|
|
-import org.apache.hadoop.hdfs.server.blockmanagement.BlockManager;
|
|
|
|
-import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeDescriptor;
|
|
|
|
-import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeManager;
|
|
|
|
-import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeStatistics;
|
|
|
|
|
|
+import org.apache.hadoop.hdfs.server.blockmanagement.*;
|
|
import org.apache.hadoop.hdfs.server.common.GenerationStamp;
|
|
import org.apache.hadoop.hdfs.server.common.GenerationStamp;
|
|
import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.BlockUCState;
|
|
import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.BlockUCState;
|
|
import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.NamenodeRole;
|
|
import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.NamenodeRole;
|
|
@@ -364,9 +359,32 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
|
|
private final long maxBlocksPerFile; // maximum # of blocks per file
|
|
private final long maxBlocksPerFile; // maximum # of blocks per file
|
|
|
|
|
|
/**
|
|
/**
|
|
- * The global generation stamp for this file system.
|
|
|
|
|
|
+ * The global generation stamp for legacy blocks with randomly
|
|
|
|
+ * generated block IDs.
|
|
*/
|
|
*/
|
|
- private final GenerationStamp generationStamp = new GenerationStamp();
|
|
|
|
|
|
+ private final GenerationStamp generationStampV1 = new GenerationStamp();
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * The global generation stamp for this file system.
|
|
|
|
+ */
|
|
|
|
+ private final GenerationStamp generationStampV2 = new GenerationStamp();
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * The value of the generation stamp when the first switch to sequential
|
|
|
|
+ * block IDs was made. Blocks with generation stamps below this value
|
|
|
|
+ * have randomly allocated block IDs. Blocks with generation stamps above
|
|
|
|
+ * this value had sequentially allocated block IDs. Read from the fsImage
|
|
|
|
+ * (or initialized as an offset from the V1 (legacy) generation stamp on
|
|
|
|
+ * upgrade).
|
|
|
|
+ */
|
|
|
|
+ private long generationStampV1Limit =
|
|
|
|
+ GenerationStamp.GRANDFATHER_GENERATION_STAMP;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * The global block ID space for this file system.
|
|
|
|
+ */
|
|
|
|
+ @VisibleForTesting
|
|
|
|
+ private final SequentialBlockIdGenerator blockIdGenerator;
|
|
|
|
|
|
// precision of access times.
|
|
// precision of access times.
|
|
private final long accessTimePrecision;
|
|
private final long accessTimePrecision;
|
|
@@ -426,7 +444,11 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
|
|
void clear() {
|
|
void clear() {
|
|
dir.reset();
|
|
dir.reset();
|
|
dtSecretManager.reset();
|
|
dtSecretManager.reset();
|
|
- generationStamp.setCurrentValue(GenerationStamp.LAST_RESERVED_STAMP);
|
|
|
|
|
|
+ generationStampV1.setCurrentValue(GenerationStamp.LAST_RESERVED_STAMP);
|
|
|
|
+ generationStampV2.setCurrentValue(GenerationStamp.LAST_RESERVED_STAMP);
|
|
|
|
+ blockIdGenerator.setCurrentValue(
|
|
|
|
+ SequentialBlockIdGenerator.LAST_RESERVED_BLOCK_ID);
|
|
|
|
+ generationStampV1Limit = GenerationStamp.GRANDFATHER_GENERATION_STAMP;
|
|
leaseManager.removeAllLeases();
|
|
leaseManager.removeAllLeases();
|
|
inodeId.setCurrentValue(INodeId.LAST_RESERVED_ID);
|
|
inodeId.setCurrentValue(INodeId.LAST_RESERVED_ID);
|
|
}
|
|
}
|
|
@@ -528,9 +550,9 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
|
|
*
|
|
*
|
|
* Note that this does not load any data off of disk -- if you would
|
|
* Note that this does not load any data off of disk -- if you would
|
|
* like that behavior, use {@link #loadFromDisk(Configuration)}
|
|
* like that behavior, use {@link #loadFromDisk(Configuration)}
|
|
-
|
|
|
|
- * @param fnImage The FSImage to associate with
|
|
|
|
|
|
+ *
|
|
* @param conf configuration
|
|
* @param conf configuration
|
|
|
|
+ * @param fsImage The FSImage to associate with
|
|
* @throws IOException on bad configuration
|
|
* @throws IOException on bad configuration
|
|
*/
|
|
*/
|
|
FSNamesystem(Configuration conf, FSImage fsImage) throws IOException {
|
|
FSNamesystem(Configuration conf, FSImage fsImage) throws IOException {
|
|
@@ -541,6 +563,7 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
|
|
|
|
|
|
this.blockManager = new BlockManager(this, this, conf);
|
|
this.blockManager = new BlockManager(this, this, conf);
|
|
this.datanodeStatistics = blockManager.getDatanodeManager().getDatanodeStatistics();
|
|
this.datanodeStatistics = blockManager.getDatanodeManager().getDatanodeStatistics();
|
|
|
|
+ this.blockIdGenerator = new SequentialBlockIdGenerator(this.blockManager);
|
|
|
|
|
|
this.fsOwner = UserGroupInformation.getCurrentUser();
|
|
this.fsOwner = UserGroupInformation.getCurrentUser();
|
|
this.fsOwnerShortUserName = fsOwner.getShortUserName();
|
|
this.fsOwnerShortUserName = fsOwner.getShortUserName();
|
|
@@ -2658,9 +2681,9 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
|
|
*/
|
|
*/
|
|
Block createNewBlock() throws IOException {
|
|
Block createNewBlock() throws IOException {
|
|
assert hasWriteLock();
|
|
assert hasWriteLock();
|
|
- Block b = new Block(getFSImage().getUniqueBlockId(), 0, 0);
|
|
|
|
|
|
+ Block b = new Block(nextBlockId(), 0, 0);
|
|
// Increment the generation stamp for every new block.
|
|
// Increment the generation stamp for every new block.
|
|
- b.setGenerationStamp(nextGenerationStamp());
|
|
|
|
|
|
+ b.setGenerationStamp(nextGenerationStamp(false));
|
|
return b;
|
|
return b;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -3356,7 +3379,7 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
|
|
uc.setExpectedLocations(blockManager.getNodes(lastBlock));
|
|
uc.setExpectedLocations(blockManager.getNodes(lastBlock));
|
|
}
|
|
}
|
|
// start recovery of the last block for this file
|
|
// start recovery of the last block for this file
|
|
- long blockRecoveryId = nextGenerationStamp();
|
|
|
|
|
|
+ long blockRecoveryId = nextGenerationStamp(isLegacyBlock(uc));
|
|
lease = reassignLease(lease, src, recoveryLeaseHolder, pendingFile);
|
|
lease = reassignLease(lease, src, recoveryLeaseHolder, pendingFile);
|
|
uc.initializeBlockRecovery(blockRecoveryId);
|
|
uc.initializeBlockRecovery(blockRecoveryId);
|
|
leaseManager.renewLease(lease);
|
|
leaseManager.renewLease(lease);
|
|
@@ -5007,34 +5030,164 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Sets the generation stamp for this filesystem
|
|
|
|
|
|
+ * Sets the current generation stamp for legacy blocks
|
|
|
|
+ */
|
|
|
|
+ void setGenerationStampV1(long stamp) {
|
|
|
|
+ generationStampV1.setCurrentValue(stamp);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Gets the current generation stamp for legacy blocks
|
|
|
|
+ */
|
|
|
|
+ long getGenerationStampV1() {
|
|
|
|
+ return generationStampV1.getCurrentValue();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Gets the current generation stamp for this filesystem
|
|
|
|
+ */
|
|
|
|
+ void setGenerationStampV2(long stamp) {
|
|
|
|
+ generationStampV2.setCurrentValue(stamp);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Gets the current generation stamp for this filesystem
|
|
|
|
+ */
|
|
|
|
+ long getGenerationStampV2() {
|
|
|
|
+ return generationStampV2.getCurrentValue();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Upgrades the generation stamp for the filesystem
|
|
|
|
+ * by reserving a sufficient range for all existing blocks.
|
|
|
|
+ * Should be invoked only during the first upgrade to
|
|
|
|
+ * sequential block IDs.
|
|
|
|
+ */
|
|
|
|
+ long upgradeGenerationStampToV2() {
|
|
|
|
+ Preconditions.checkState(generationStampV2.getCurrentValue() ==
|
|
|
|
+ GenerationStamp.LAST_RESERVED_STAMP);
|
|
|
|
+
|
|
|
|
+ generationStampV2.skipTo(
|
|
|
|
+ generationStampV1.getCurrentValue() +
|
|
|
|
+ HdfsConstants.RESERVED_GENERATION_STAMPS_V1);
|
|
|
|
+
|
|
|
|
+ generationStampV1Limit = generationStampV2.getCurrentValue();
|
|
|
|
+ return generationStampV2.getCurrentValue();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Sets the generation stamp that delineates random and sequentially
|
|
|
|
+ * allocated block IDs.
|
|
|
|
+ * @param stamp
|
|
|
|
+ */
|
|
|
|
+ void setGenerationStampV1Limit(long stamp) {
|
|
|
|
+ Preconditions.checkState(generationStampV1Limit ==
|
|
|
|
+ GenerationStamp.GRANDFATHER_GENERATION_STAMP);
|
|
|
|
+ generationStampV1Limit = stamp;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Gets the value of the generation stamp that delineates sequential
|
|
|
|
+ * and random block IDs.
|
|
*/
|
|
*/
|
|
- void setGenerationStamp(long stamp) {
|
|
|
|
- generationStamp.setCurrentValue(stamp);
|
|
|
|
|
|
+ long getGenerationStampAtblockIdSwitch() {
|
|
|
|
+ return generationStampV1Limit;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @VisibleForTesting
|
|
|
|
+ SequentialBlockIdGenerator getBlockIdGenerator() {
|
|
|
|
+ return blockIdGenerator;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Sets the maximum allocated block ID for this filesystem. This is
|
|
|
|
+ * the basis for allocating new block IDs.
|
|
|
|
+ */
|
|
|
|
+ void setLastAllocatedBlockId(long blockId) {
|
|
|
|
+ blockIdGenerator.skipTo(blockId);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Gets the generation stamp for this filesystem
|
|
|
|
|
|
+ * Gets the maximum sequentially allocated block ID for this filesystem
|
|
*/
|
|
*/
|
|
- long getGenerationStamp() {
|
|
|
|
- return generationStamp.getCurrentValue();
|
|
|
|
|
|
+ long getLastAllocatedBlockId() {
|
|
|
|
+ return blockIdGenerator.getCurrentValue();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
* Increments, logs and then returns the stamp
|
|
* Increments, logs and then returns the stamp
|
|
*/
|
|
*/
|
|
- private long nextGenerationStamp() throws SafeModeException {
|
|
|
|
|
|
+ long nextGenerationStamp(boolean legacyBlock)
|
|
|
|
+ throws IOException, SafeModeException {
|
|
assert hasWriteLock();
|
|
assert hasWriteLock();
|
|
if (isInSafeMode()) {
|
|
if (isInSafeMode()) {
|
|
throw new SafeModeException(
|
|
throw new SafeModeException(
|
|
"Cannot get next generation stamp", safeMode);
|
|
"Cannot get next generation stamp", safeMode);
|
|
}
|
|
}
|
|
- final long gs = generationStamp.nextValue();
|
|
|
|
- getEditLog().logGenerationStamp(gs);
|
|
|
|
|
|
+
|
|
|
|
+ long gs;
|
|
|
|
+ if (legacyBlock) {
|
|
|
|
+ gs = getNextGenerationStampV1();
|
|
|
|
+ getEditLog().logGenerationStampV1(gs);
|
|
|
|
+ } else {
|
|
|
|
+ gs = getNextGenerationStampV2();
|
|
|
|
+ getEditLog().logGenerationStampV2(gs);
|
|
|
|
+ }
|
|
|
|
+
|
|
// NB: callers sync the log
|
|
// NB: callers sync the log
|
|
return gs;
|
|
return gs;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ @VisibleForTesting
|
|
|
|
+ long getNextGenerationStampV1() throws IOException {
|
|
|
|
+ long genStampV1 = generationStampV1.nextValue();
|
|
|
|
+
|
|
|
|
+ if (genStampV1 >= generationStampV1Limit) {
|
|
|
|
+ // We ran out of generation stamps for legacy blocks. In practice, it
|
|
|
|
+ // is extremely unlikely as we reserved 1T v1 generation stamps. The
|
|
|
|
+ // result is that we can no longer append to the legacy blocks that
|
|
|
|
+ // were created before the upgrade to sequential block IDs.
|
|
|
|
+ throw new OutOfV1GenerationStampsException();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return genStampV1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @VisibleForTesting
|
|
|
|
+ long getNextGenerationStampV2() {
|
|
|
|
+ return generationStampV2.nextValue();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ long getGenerationStampV1Limit() {
|
|
|
|
+ return generationStampV1Limit;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Determine whether the block ID was randomly generated (legacy) or
|
|
|
|
+ * sequentially generated. The generation stamp value is used to
|
|
|
|
+ * make the distinction.
|
|
|
|
+ * @param block
|
|
|
|
+ * @return true if the block ID was randomly generated, false otherwise.
|
|
|
|
+ */
|
|
|
|
+ boolean isLegacyBlock(Block block) {
|
|
|
|
+ return block.getGenerationStamp() < getGenerationStampV1Limit();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Increments, logs and then returns the block ID
|
|
|
|
+ */
|
|
|
|
+ private long nextBlockId() throws SafeModeException {
|
|
|
|
+ assert hasWriteLock();
|
|
|
|
+ if (isInSafeMode()) {
|
|
|
|
+ throw new SafeModeException(
|
|
|
|
+ "Cannot get next block ID", safeMode);
|
|
|
|
+ }
|
|
|
|
+ final long blockId = blockIdGenerator.nextValue();
|
|
|
|
+ getEditLog().logAllocateBlockId(blockId);
|
|
|
|
+ // NB: callers sync the log
|
|
|
|
+ return blockId;
|
|
|
|
+ }
|
|
|
|
+
|
|
private INodeFileUnderConstruction checkUCBlock(ExtendedBlock block,
|
|
private INodeFileUnderConstruction checkUCBlock(ExtendedBlock block,
|
|
String clientName) throws IOException {
|
|
String clientName) throws IOException {
|
|
assert hasWriteLock();
|
|
assert hasWriteLock();
|
|
@@ -5115,7 +5268,8 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
|
|
checkUCBlock(block, clientName);
|
|
checkUCBlock(block, clientName);
|
|
|
|
|
|
// get a new generation stamp and an access token
|
|
// get a new generation stamp and an access token
|
|
- block.setGenerationStamp(nextGenerationStamp());
|
|
|
|
|
|
+ block.setGenerationStamp(
|
|
|
|
+ nextGenerationStamp(isLegacyBlock(block.getLocalBlock())));
|
|
locatedBlock = new LocatedBlock(block, new DatanodeInfo[0]);
|
|
locatedBlock = new LocatedBlock(block, new DatanodeInfo[0]);
|
|
blockManager.setBlockToken(locatedBlock, AccessMode.WRITE);
|
|
blockManager.setBlockToken(locatedBlock, AccessMode.WRITE);
|
|
} finally {
|
|
} finally {
|
|
@@ -5130,7 +5284,7 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
|
|
* Update a pipeline for a block under construction
|
|
* Update a pipeline for a block under construction
|
|
*
|
|
*
|
|
* @param clientName the name of the client
|
|
* @param clientName the name of the client
|
|
- * @param oldblock and old block
|
|
|
|
|
|
+ * @param oldBlock and old block
|
|
* @param newBlock a new block with a new generation stamp and length
|
|
* @param newBlock a new block with a new generation stamp and length
|
|
* @param newNodes datanodes in the pipeline
|
|
* @param newNodes datanodes in the pipeline
|
|
* @throws IOException if any error occurs
|
|
* @throws IOException if any error occurs
|
|
@@ -5917,9 +6071,14 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|
|
- public boolean isGenStampInFuture(long genStamp) {
|
|
|
|
- return (genStamp > getGenerationStamp());
|
|
|
|
|
|
+ public boolean isGenStampInFuture(Block block) {
|
|
|
|
+ if (isLegacyBlock(block)) {
|
|
|
|
+ return block.getGenerationStamp() > getGenerationStampV1();
|
|
|
|
+ } else {
|
|
|
|
+ return block.getGenerationStamp() > getGenerationStampV2();
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+
|
|
@VisibleForTesting
|
|
@VisibleForTesting
|
|
public EditLogTailer getEditLogTailer() {
|
|
public EditLogTailer getEditLogTailer() {
|
|
return editLogTailer;
|
|
return editLogTailer;
|