svn merge -c 1545322 merging from trunk to branch-2 to fix HDFS-5266. Datanode cannot roll back to previous layout version.

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-2@1545324 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Kihwal Lee 2013-11-25 15:36:39 +00:00
parent c0bcf404d5
commit 204a17c736
3 changed files with 76 additions and 29 deletions

View File

@ -3675,6 +3675,8 @@ Release 0.23.10 - UNRELEASED
HDFS-4329. DFSShell issues with directories with spaces in name (Cristina HDFS-4329. DFSShell issues with directories with spaces in name (Cristina
L. Abad via jeagles) L. Abad via jeagles)
HDFS-5526. Datanode cannot roll back to previous layout version (kihwal)
Release 0.23.9 - 2013-07-08 Release 0.23.9 - 2013-07-08
INCOMPATIBLE CHANGES INCOMPATIBLE CHANGES

View File

@ -299,7 +299,16 @@ public class DataStorage extends Storage {
@Override @Override
protected void setFieldsFromProperties(Properties props, StorageDirectory sd) protected void setFieldsFromProperties(Properties props, StorageDirectory sd)
throws IOException { throws IOException {
setLayoutVersion(props, sd); setFieldsFromProperties(props, sd, false, 0);
}
private void setFieldsFromProperties(Properties props, StorageDirectory sd,
boolean overrideLayoutVersion, int toLayoutVersion) throws IOException {
if (overrideLayoutVersion) {
this.layoutVersion = toLayoutVersion;
} else {
setLayoutVersion(props, sd);
}
setcTime(props, sd); setcTime(props, sd);
setStorageType(props, sd); setStorageType(props, sd);
setClusterId(props, layoutVersion, sd); setClusterId(props, layoutVersion, sd);
@ -347,13 +356,20 @@ public class DataStorage extends Storage {
return true; return true;
} }
/** Read VERSION file for rollback */
void readProperties(StorageDirectory sd, int rollbackLayoutVersion)
throws IOException {
Properties props = readPropertiesFile(sd.getVersionFile());
setFieldsFromProperties(props, sd, true, rollbackLayoutVersion);
}
/** /**
* Analize which and whether a transition of the fs state is required * Analize which and whether a transition of the fs state is required
* and perform it if necessary. * and perform it if necessary.
* *
* Rollback if previousLV >= LAYOUT_VERSION && prevCTime <= namenode.cTime * Rollback if the rollback startup option was specified.
* Upgrade if this.LV > LAYOUT_VERSION || this.cTime < namenode.cTime * Upgrade if this.LV > LAYOUT_VERSION
* Regular startup if this.LV = LAYOUT_VERSION && this.cTime = namenode.cTime * Regular startup if this.LV = LAYOUT_VERSION
* *
* @param datanode Datanode to which this storage belongs to * @param datanode Datanode to which this storage belongs to
* @param sd storage directory * @param sd storage directory
@ -393,25 +409,28 @@ public class DataStorage extends Storage {
+ nsInfo.getClusterID() + "; datanode clusterID = " + getClusterID()); + nsInfo.getClusterID() + "; datanode clusterID = " + getClusterID());
} }
// regular start up // After addition of the federation feature, ctime check is only
if (this.layoutVersion == HdfsConstants.LAYOUT_VERSION // meaningful at BlockPoolSliceStorage level.
&& this.cTime == nsInfo.getCTime())
// regular start up.
if (this.layoutVersion == HdfsConstants.LAYOUT_VERSION)
return; // regular startup return; // regular startup
// do upgrade // do upgrade
if (this.layoutVersion > HdfsConstants.LAYOUT_VERSION if (this.layoutVersion > HdfsConstants.LAYOUT_VERSION) {
|| this.cTime < nsInfo.getCTime()) {
doUpgrade(sd, nsInfo); // upgrade doUpgrade(sd, nsInfo); // upgrade
return; return;
} }
// layoutVersion == LAYOUT_VERSION && this.cTime > nsInfo.cTime // layoutVersion < LAYOUT_VERSION. I.e. stored layout version is newer
// must shutdown // than the version supported by datanode. This should have been caught
throw new IOException("Datanode state: LV = " + this.getLayoutVersion() // in readProperties(), even if rollback was not carried out or somehow
+ " CTime = " + this.getCTime() // failed.
+ " is newer than the namespace state: LV = " throw new IOException("BUG: The stored LV = " + this.getLayoutVersion()
+ nsInfo.getLayoutVersion() + " is newer than the supported LV = "
+ " CTime = " + nsInfo.getCTime()); + HdfsConstants.LAYOUT_VERSION
+ " or name node LV = "
+ nsInfo.getLayoutVersion());
} }
/** /**
@ -437,8 +456,13 @@ public class DataStorage extends Storage {
* @throws IOException on error * @throws IOException on error
*/ */
void doUpgrade(StorageDirectory sd, NamespaceInfo nsInfo) throws IOException { void doUpgrade(StorageDirectory sd, NamespaceInfo nsInfo) throws IOException {
// If the existing on-disk layout version supportes federation, simply
// update its layout version.
if (LayoutVersion.supports(Feature.FEDERATION, layoutVersion)) { if (LayoutVersion.supports(Feature.FEDERATION, layoutVersion)) {
clusterID = nsInfo.getClusterID(); // The VERSION file is already read in. Override the layoutVersion
// field and overwrite the file.
LOG.info("Updating layout version from " + layoutVersion + " to "
+ nsInfo.getLayoutVersion() + " for storage " + sd.getRoot());
layoutVersion = nsInfo.getLayoutVersion(); layoutVersion = nsInfo.getLayoutVersion();
writeProperties(sd); writeProperties(sd);
return; return;
@ -523,15 +547,32 @@ public class DataStorage extends Storage {
* <li> Remove removed.tmp </li> * <li> Remove removed.tmp </li>
* </ol> * </ol>
* *
* Do nothing, if previous directory does not exist. * If previous directory does not exist and the current version supports
* federation, perform a simple rollback of layout version. This does not
* involve saving/restoration of actual data.
*/ */
void doRollback( StorageDirectory sd, void doRollback( StorageDirectory sd,
NamespaceInfo nsInfo NamespaceInfo nsInfo
) throws IOException { ) throws IOException {
File prevDir = sd.getPreviousDir(); File prevDir = sd.getPreviousDir();
// regular startup if previous dir does not exist // This is a regular startup or a post-federation rollback
if (!prevDir.exists()) if (!prevDir.exists()) {
// The current datanode version supports federation and the layout
// version from namenode matches what the datanode supports. An invalid
// rollback may happen if namenode didn't rollback and datanode is
// running a wrong version. But this will be detected in block pool
// level and the invalid VERSION content will be overwritten when
// the error is corrected and rollback is retried.
if (LayoutVersion.supports(Feature.FEDERATION,
HdfsConstants.LAYOUT_VERSION) &&
HdfsConstants.LAYOUT_VERSION == nsInfo.getLayoutVersion()) {
readProperties(sd, nsInfo.getLayoutVersion());
writeProperties(sd);
LOG.info("Layout version rolled back to " +
nsInfo.getLayoutVersion() + " for storage " + sd.getRoot());
}
return; return;
}
DataStorage prevInfo = new DataStorage(); DataStorage prevInfo = new DataStorage();
prevInfo.readPreviousVersionProperties(sd); prevInfo.readPreviousVersionProperties(sd);

View File

@ -191,21 +191,25 @@ public class TestDFSRollback {
// Create a previous snapshot for the blockpool // Create a previous snapshot for the blockpool
UpgradeUtilities.createBlockPoolStorageDirs(dataNodeDirs, "previous", UpgradeUtilities.createBlockPoolStorageDirs(dataNodeDirs, "previous",
UpgradeUtilities.getCurrentBlockPoolID(cluster)); UpgradeUtilities.getCurrentBlockPoolID(cluster));
// Older LayoutVersion to make it rollback // Put newer layout version in current.
storageInfo = new StorageInfo( storageInfo = new StorageInfo(
UpgradeUtilities.getCurrentLayoutVersion()+1, UpgradeUtilities.getCurrentLayoutVersion()-1,
UpgradeUtilities.getCurrentNamespaceID(cluster), UpgradeUtilities.getCurrentNamespaceID(cluster),
UpgradeUtilities.getCurrentClusterID(cluster), UpgradeUtilities.getCurrentClusterID(cluster),
UpgradeUtilities.getCurrentFsscTime(cluster)); UpgradeUtilities.getCurrentFsscTime(cluster));
// Create old VERSION file for each data dir
// Overwrite VERSION file in the current directory of
// volume directories and block pool slice directories
// with a layout version from future.
File[] dataCurrentDirs = new File[dataNodeDirs.length];
for (int i=0; i<dataNodeDirs.length; i++) { for (int i=0; i<dataNodeDirs.length; i++) {
Path bpPrevPath = new Path(dataNodeDirs[i] + "/current/" dataCurrentDirs[i] = new File((new Path(dataNodeDirs[i]
+ UpgradeUtilities.getCurrentBlockPoolID(cluster)); + "/current")).toString());
UpgradeUtilities.createBlockPoolVersionFile(
new File(bpPrevPath.toString()),
storageInfo,
UpgradeUtilities.getCurrentBlockPoolID(cluster));
} }
UpgradeUtilities.createDataNodeVersionFile(
dataCurrentDirs,
storageInfo,
UpgradeUtilities.getCurrentBlockPoolID(cluster));
cluster.startDataNodes(conf, 1, false, StartupOption.ROLLBACK, null); cluster.startDataNodes(conf, 1, false, StartupOption.ROLLBACK, null);
assertTrue(cluster.isDataNodeUp()); assertTrue(cluster.isDataNodeUp());