/// <summary>Upgrade to any release after 0.22 (0.22 included) release e.g.</summary> /// <remarks> /// Upgrade to any release after 0.22 (0.22 included) release e.g. 0.22 => 0.23 /// Upgrade procedure is as follows: /// <ol> /// <li>If <SD>/current/<bpid>/previous exists then delete it</li> /// <li>Rename <SD>/current/<bpid>/current to /// <SD>/current/bpid/current/previous.tmp</li> /// <li>Create new <SD>current/<bpid>/current directory</li> /// <ol> /// <li>Hard links for block files are created from previous.tmp to current</li> /// <li>Save new version file in current directory</li> /// </ol> /// <li>Rename previous.tmp to previous</li> </ol> /// </remarks> /// <param name="bpSd">storage directory <SD>/current/<bpid></param> /// <param name="nsInfo">Namespace Info from the namenode</param> /// <exception cref="System.IO.IOException">on error</exception> internal virtual void DoUpgrade(DataNode datanode, Storage.StorageDirectory bpSd, NamespaceInfo nsInfo) { // Upgrading is applicable only to release with federation or after if (!DataNodeLayoutVersion.Supports(LayoutVersion.Feature.Federation, layoutVersion )) { return; } Log.Info("Upgrading block pool storage directory " + bpSd.GetRoot() + ".\n old LV = " + this.GetLayoutVersion() + "; old CTime = " + this.GetCTime() + ".\n new LV = " + HdfsConstants.DatanodeLayoutVersion + "; new CTime = " + nsInfo.GetCTime()); // get <SD>/previous directory string dnRoot = GetDataNodeStorageRoot(bpSd.GetRoot().GetCanonicalPath()); Storage.StorageDirectory dnSdStorage = new Storage.StorageDirectory(new FilePath( dnRoot)); FilePath dnPrevDir = dnSdStorage.GetPreviousDir(); // If <SD>/previous directory exists delete it if (dnPrevDir.Exists()) { DeleteDir(dnPrevDir); } FilePath bpCurDir = bpSd.GetCurrentDir(); FilePath bpPrevDir = bpSd.GetPreviousDir(); System.Diagnostics.Debug.Assert(bpCurDir.Exists(), "BP level current directory must exist." ); CleanupDetachDir(new FilePath(bpCurDir, DataStorage.StorageDirDetached)); // 1. Delete <SD>/current/<bpid>/previous dir before upgrading if (bpPrevDir.Exists()) { DeleteDir(bpPrevDir); } FilePath bpTmpDir = bpSd.GetPreviousTmp(); System.Diagnostics.Debug.Assert(!bpTmpDir.Exists(), "previous.tmp directory must not exist." ); // 2. Rename <SD>/current/<bpid>/current to // <SD>/current/<bpid>/previous.tmp Rename(bpCurDir, bpTmpDir); // 3. Create new <SD>/current with block files hardlinks and VERSION LinkAllBlocks(datanode, bpTmpDir, bpCurDir); this.layoutVersion = HdfsConstants.DatanodeLayoutVersion; System.Diagnostics.Debug.Assert(this.namespaceID == nsInfo.GetNamespaceID(), "Data-node and name-node layout versions must be the same." ); this.cTime = nsInfo.GetCTime(); WriteProperties(bpSd); // 4.rename <SD>/current/<bpid>/previous.tmp to // <SD>/current/<bpid>/previous Rename(bpTmpDir, bpPrevDir); Log.Info("Upgrade of block pool " + blockpoolID + " at " + bpSd.GetRoot() + " is complete" ); }
/// <summary>Load one storage directory.</summary> /// <remarks>Load one storage directory. Recover from previous transitions if required. /// </remarks> /// <param name="datanode">datanode instance</param> /// <param name="nsInfo">namespace information</param> /// <param name="dataDir">the root path of the storage directory</param> /// <param name="startOpt">startup option</param> /// <returns>the StorageDirectory successfully loaded.</returns> /// <exception cref="System.IO.IOException"/> private Storage.StorageDirectory LoadStorageDirectory(DataNode datanode, NamespaceInfo nsInfo, FilePath dataDir, HdfsServerConstants.StartupOption startOpt) { Storage.StorageDirectory sd = new Storage.StorageDirectory(dataDir, null, true); try { Storage.StorageState curState = sd.AnalyzeStorage(startOpt, this); switch (curState) { case Storage.StorageState.Normal: { // sd is locked but not opened break; } case Storage.StorageState.NonExistent: { Log.Info("Block pool storage directory " + dataDir + " does not exist"); throw new IOException("Storage directory " + dataDir + " does not exist"); } case Storage.StorageState.NotFormatted: { // format Log.Info("Block pool storage directory " + dataDir + " is not formatted for " + nsInfo .GetBlockPoolID()); Log.Info("Formatting ..."); Format(sd, nsInfo); break; } default: { // recovery part is common sd.DoRecover(curState); break; } } // 2. Do transitions // Each storage directory is treated individually. // During startup some of them can upgrade or roll back // while others could be up-to-date for the regular startup. DoTransition(datanode, sd, nsInfo, startOpt); if (GetCTime() != nsInfo.GetCTime()) { throw new IOException("Data-node and name-node CTimes must be the same."); } // 3. Update successfully loaded storage. SetServiceLayoutVersion(GetServiceLayoutVersion()); WriteProperties(sd); return(sd); } catch (IOException ioe) { sd.Unlock(); throw; } }
/* * Roll back to old snapshot at the block pool level * If previous directory exists: * <ol> * <li>Rename <SD>/current/<bpid>/current to removed.tmp</li> * <li>Rename * <SD>/current/<bpid>/previous to current</li> * <li>Remove removed.tmp</li> * </ol> * * Do nothing if previous directory does not exist. * @param bpSd Block pool storage directory at <SD>/current/<bpid> */ /// <exception cref="System.IO.IOException"/> internal virtual void DoRollback(Storage.StorageDirectory bpSd, NamespaceInfo nsInfo ) { FilePath prevDir = bpSd.GetPreviousDir(); // regular startup if previous dir does not exist if (!prevDir.Exists()) { return; } // read attributes out of the VERSION file of previous directory Org.Apache.Hadoop.Hdfs.Server.Datanode.BlockPoolSliceStorage prevInfo = new Org.Apache.Hadoop.Hdfs.Server.Datanode.BlockPoolSliceStorage (); prevInfo.ReadPreviousVersionProperties(bpSd); // We allow rollback to a state, which is either consistent with // the namespace state or can be further upgraded to it. // In another word, we can only roll back when ( storedLV >= software LV) // && ( DN.previousCTime <= NN.ctime) if (!(prevInfo.GetLayoutVersion() >= HdfsConstants.DatanodeLayoutVersion && prevInfo .GetCTime() <= nsInfo.GetCTime())) { // cannot rollback throw new InconsistentFSStateException(bpSd.GetRoot(), "Cannot rollback to a newer state.\nDatanode previous state: LV = " + prevInfo.GetLayoutVersion() + " CTime = " + prevInfo.GetCTime() + " is newer than the namespace state: LV = " + HdfsConstants.DatanodeLayoutVersion + " CTime = " + nsInfo.GetCTime()); } Log.Info("Rolling back storage directory " + bpSd.GetRoot() + ".\n target LV = " + nsInfo.GetLayoutVersion() + "; target CTime = " + nsInfo.GetCTime()); FilePath tmpDir = bpSd.GetRemovedTmp(); System.Diagnostics.Debug.Assert(!tmpDir.Exists(), "removed.tmp directory must not exist." ); // 1. rename current to tmp FilePath curDir = bpSd.GetCurrentDir(); System.Diagnostics.Debug.Assert(curDir.Exists(), "Current directory must exist."); Rename(curDir, tmpDir); // 2. rename previous to current Rename(prevDir, curDir); // 3. delete removed.tmp dir DeleteDir(tmpDir); Log.Info("Rollback of " + bpSd.GetRoot() + " is complete"); }
/// <summary>Format a block pool slice storage.</summary> /// <param name="bpSdir">the block pool storage</param> /// <param name="nsInfo">the name space info</param> /// <exception cref="System.IO.IOException">Signals that an I/O exception has occurred. /// </exception> private void Format(Storage.StorageDirectory bpSdir, NamespaceInfo nsInfo) { Log.Info("Formatting block pool " + blockpoolID + " directory " + bpSdir.GetCurrentDir ()); bpSdir.ClearDirectory(); // create directory this.layoutVersion = HdfsConstants.DatanodeLayoutVersion; this.cTime = nsInfo.GetCTime(); this.namespaceID = nsInfo.GetNamespaceID(); this.blockpoolID = nsInfo.GetBlockPoolID(); WriteProperties(bpSdir); }
/// <summary> /// Analyze whether a transition of the BP state is required and /// perform it if necessary. /// </summary> /// <remarks> /// Analyze whether a transition of the BP state is required and /// perform it if necessary. /// <br /> /// Rollback if previousLV >= LAYOUT_VERSION && prevCTime <= namenode.cTime. /// Upgrade if this.LV > LAYOUT_VERSION || this.cTime < namenode.cTime Regular /// startup if this.LV = LAYOUT_VERSION && this.cTime = namenode.cTime /// </remarks> /// <param name="sd">storage directory <SD>/current/<bpid></param> /// <param name="nsInfo">namespace info</param> /// <param name="startOpt">startup option</param> /// <exception cref="System.IO.IOException"/> private void DoTransition(DataNode datanode, Storage.StorageDirectory sd, NamespaceInfo nsInfo, HdfsServerConstants.StartupOption startOpt) { if (startOpt == HdfsServerConstants.StartupOption.Rollback && sd.GetPreviousDir() .Exists()) { Preconditions.CheckState(!GetTrashRootDir(sd).Exists(), sd.GetPreviousDir() + " and " + GetTrashRootDir(sd) + " should not " + " both be present."); DoRollback(sd, nsInfo); } else { // rollback if applicable if (startOpt == HdfsServerConstants.StartupOption.Rollback && !sd.GetPreviousDir( ).Exists()) { // Restore all the files in the trash. The restored files are retained // during rolling upgrade rollback. They are deleted during rolling // upgrade downgrade. int restored = RestoreBlockFilesFromTrash(GetTrashRootDir(sd)); Log.Info("Restored " + restored + " block files from trash."); } } ReadProperties(sd); CheckVersionUpgradable(this.layoutVersion); System.Diagnostics.Debug.Assert(this.layoutVersion >= HdfsConstants.DatanodeLayoutVersion , "Future version is not allowed"); if (GetNamespaceID() != nsInfo.GetNamespaceID()) { throw new IOException("Incompatible namespaceIDs in " + sd.GetRoot().GetCanonicalPath () + ": namenode namespaceID = " + nsInfo.GetNamespaceID() + "; datanode namespaceID = " + GetNamespaceID()); } if (!blockpoolID.Equals(nsInfo.GetBlockPoolID())) { throw new IOException("Incompatible blockpoolIDs in " + sd.GetRoot().GetCanonicalPath () + ": namenode blockpoolID = " + nsInfo.GetBlockPoolID() + "; datanode blockpoolID = " + blockpoolID); } if (this.layoutVersion == HdfsConstants.DatanodeLayoutVersion && this.cTime == nsInfo .GetCTime()) { return; } // regular startup if (this.layoutVersion > HdfsConstants.DatanodeLayoutVersion) { int restored = RestoreBlockFilesFromTrash(GetTrashRootDir(sd)); Log.Info("Restored " + restored + " block files from trash " + "before the layout upgrade. These blocks will be moved to " + "the previous directory during the upgrade"); } if (this.layoutVersion > HdfsConstants.DatanodeLayoutVersion || this.cTime < nsInfo .GetCTime()) { DoUpgrade(datanode, sd, nsInfo); // upgrade return; } // layoutVersion == LAYOUT_VERSION && this.cTime > nsInfo.cTime // must shutdown throw new IOException("Datanode state: LV = " + this.GetLayoutVersion() + " CTime = " + this.GetCTime() + " is newer than the namespace state: LV = " + nsInfo.GetLayoutVersion () + " CTime = " + nsInfo.GetCTime()); }