/* * Finalize the block pool storage by deleting <BP>/previous directory * that holds the snapshot. */ /// <exception cref="System.IO.IOException"/> internal virtual void DoFinalize(FilePath dnCurDir) { FilePath bpRoot = GetBpRoot(blockpoolID, dnCurDir); Storage.StorageDirectory bpSd = new Storage.StorageDirectory(bpRoot); // block pool level previous directory FilePath prevDir = bpSd.GetPreviousDir(); if (!prevDir.Exists()) { return; } // already finalized string dataDirPath = bpSd.GetRoot().GetCanonicalPath(); Log.Info("Finalizing upgrade for storage directory " + dataDirPath + ".\n cur LV = " + this.GetLayoutVersion() + "; cur CTime = " + this.GetCTime()); System.Diagnostics.Debug.Assert(bpSd.GetCurrentDir().Exists(), "Current directory must exist." ); // rename previous to finalized.tmp FilePath tmpDir = bpSd.GetFinalizedTmp(); Rename(prevDir, tmpDir); // delete finalized.tmp dir in a separate thread new Daemon(new _Runnable_618(tmpDir, dataDirPath)).Start(); }
/// <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" ); }
/* Flag if there is at least one storage dir that doesn't contain the newest * fstime */ /* Flag set false if there are any "previous" directories found */ // Track the name and edits dir with the latest times /// <exception cref="System.IO.IOException"/> internal override void InspectDirectory(Storage.StorageDirectory sd) { // Was the file just formatted? if (!sd.GetVersionFile().Exists()) { hasOutOfDateStorageDirs = true; return; } bool imageExists = false; bool editsExists = false; // Determine if sd is image, edits or both if (sd.GetStorageDirType().IsOfType(NNStorage.NameNodeDirType.Image)) { imageExists = NNStorage.GetStorageFile(sd, NNStorage.NameNodeFile.Image).Exists(); imageDirs.AddItem(sd.GetRoot().GetCanonicalPath()); } if (sd.GetStorageDirType().IsOfType(NNStorage.NameNodeDirType.Edits)) { editsExists = NNStorage.GetStorageFile(sd, NNStorage.NameNodeFile.Edits).Exists(); editsDirs.AddItem(sd.GetRoot().GetCanonicalPath()); } long checkpointTime = ReadCheckpointTime(sd); checkpointTimes.AddItem(checkpointTime); if (sd.GetStorageDirType().IsOfType(NNStorage.NameNodeDirType.Image) && (latestNameCheckpointTime < checkpointTime) && imageExists) { latestNameCheckpointTime = checkpointTime; latestNameSD = sd; } if (sd.GetStorageDirType().IsOfType(NNStorage.NameNodeDirType.Edits) && (latestEditsCheckpointTime < checkpointTime) && editsExists) { latestEditsCheckpointTime = checkpointTime; latestEditsSD = sd; } // check that we have a valid, non-default checkpointTime if (checkpointTime <= 0L) { hasOutOfDateStorageDirs = true; } // set finalized flag isUpgradeFinalized = isUpgradeFinalized && !sd.GetPreviousDir().Exists(); }
/// <summary> /// Rename the existing current dir to previous.tmp, and create a new empty /// current dir. /// </summary> /// <exception cref="System.IO.IOException"/> public static void RenameCurToTmp(Storage.StorageDirectory sd) { FilePath curDir = sd.GetCurrentDir(); FilePath prevDir = sd.GetPreviousDir(); FilePath tmpDir = sd.GetPreviousTmp(); Preconditions.CheckState(curDir.Exists(), "Current directory must exist for preupgrade." ); Preconditions.CheckState(!prevDir.Exists(), "Previous directory must not exist for preupgrade." ); Preconditions.CheckState(!tmpDir.Exists(), "Previous.tmp directory must not exist for preupgrade." + "Consider restarting for recovery."); // rename current to tmp NNStorage.Rename(curDir, tmpDir); if (!curDir.Mkdir()) { throw new IOException("Cannot create directory " + curDir); } }
/* * 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>Finalize the upgrade.</summary> /// <remarks> /// Finalize the upgrade. The previous dir, if any, will be renamed and /// removed. After this is completed, rollback is no longer allowed. /// </remarks> /// <param name="sd">the storage directory to finalize</param> /// <exception cref="System.IO.IOException">in the event of error</exception> internal static void DoFinalize(Storage.StorageDirectory sd) { FilePath prevDir = sd.GetPreviousDir(); if (!prevDir.Exists()) { // already discarded Log.Info("Directory " + prevDir + " does not exist."); Log.Info("Finalize upgrade for " + sd.GetRoot() + " is not required."); return; } Log.Info("Finalizing upgrade of storage directory " + sd.GetRoot()); Preconditions.CheckState(sd.GetCurrentDir().Exists(), "Current directory must exist." ); FilePath tmpDir = sd.GetFinalizedTmp(); // rename previous to tmp and remove NNStorage.Rename(prevDir, tmpDir); NNStorage.DeleteDir(tmpDir); Log.Info("Finalize upgrade for " + sd.GetRoot() + " is complete."); }
/// <summary>Perform the upgrade of the storage dir to the given storage info.</summary> /// <remarks> /// Perform the upgrade of the storage dir to the given storage info. The new /// storage info is written into the current directory, and the previous.tmp /// directory is renamed to previous. /// </remarks> /// <param name="sd">the storage directory to upgrade</param> /// <param name="storage">info about the new upgraded versions.</param> /// <exception cref="System.IO.IOException">in the event of error</exception> public static void DoUpgrade(Storage.StorageDirectory sd, Storage storage) { Log.Info("Performing upgrade of storage directory " + sd.GetRoot()); try { // Write the version file, since saveFsImage only makes the // fsimage_<txid>, and the directory is otherwise empty. storage.WriteProperties(sd); FilePath prevDir = sd.GetPreviousDir(); FilePath tmpDir = sd.GetPreviousTmp(); Preconditions.CheckState(!prevDir.Exists(), "previous directory must not exist for upgrade." ); Preconditions.CheckState(tmpDir.Exists(), "previous.tmp directory must exist for upgrade." ); // rename tmp to previous NNStorage.Rename(tmpDir, prevDir); } catch (IOException ioe) { Log.Error("Unable to rename temp to previous for " + sd.GetRoot(), ioe); throw; } }
/// <summary> /// Return true if this storage dir can roll back to the previous storage /// state, false otherwise. /// </summary> /// <remarks> /// Return true if this storage dir can roll back to the previous storage /// state, false otherwise. The NN will refuse to run the rollback operation /// unless at least one JM or fsimage storage directory can roll back. /// </remarks> /// <param name="storage">the storage info for the current state</param> /// <param name="prevStorage">the storage info for the previous (unupgraded) state</param> /// <param name="targetLayoutVersion">the layout version we intend to roll back to</param> /// <returns>true if this JM can roll back, false otherwise.</returns> /// <exception cref="System.IO.IOException">in the event of error</exception> internal static bool CanRollBack(Storage.StorageDirectory sd, StorageInfo storage , StorageInfo prevStorage, int targetLayoutVersion) { FilePath prevDir = sd.GetPreviousDir(); if (!prevDir.Exists()) { // use current directory then Log.Info("Storage directory " + sd.GetRoot() + " does not contain previous fs state." ); // read and verify consistency with other directories storage.ReadProperties(sd); return(false); } // read and verify consistency of the prev dir prevStorage.ReadPreviousVersionProperties(sd); if (prevStorage.GetLayoutVersion() != targetLayoutVersion) { throw new IOException("Cannot rollback to storage version " + prevStorage.GetLayoutVersion () + " using this version of the NameNode, which uses storage version " + targetLayoutVersion + ". " + "Please use the previous version of HDFS to perform the rollback."); } return(true); }
/// <summary>Perform rollback of the storage dir to the previous state.</summary> /// <remarks> /// Perform rollback of the storage dir to the previous state. The existing /// current dir is removed, and the previous dir is renamed to current. /// </remarks> /// <param name="sd">the storage directory to roll back.</param> /// <exception cref="System.IO.IOException">in the event of error</exception> internal static void DoRollBack(Storage.StorageDirectory sd) { FilePath prevDir = sd.GetPreviousDir(); if (!prevDir.Exists()) { return; } FilePath tmpDir = sd.GetRemovedTmp(); Preconditions.CheckState(!tmpDir.Exists(), "removed.tmp directory must not exist for rollback." + "Consider restarting for recovery."); // rename current to tmp FilePath curDir = sd.GetCurrentDir(); Preconditions.CheckState(curDir.Exists(), "Current directory must exist for rollback." ); NNStorage.Rename(curDir, tmpDir); // rename previous to current NNStorage.Rename(prevDir, curDir); // delete tmp dir NNStorage.DeleteDir(tmpDir); Log.Info("Rollback of " + sd.GetRoot() + " is complete."); }
/// <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()); }
/// <exception cref="System.IO.IOException"/> internal override void InspectDirectory(Storage.StorageDirectory sd) { // Was the directory just formatted? if (!sd.GetVersionFile().Exists()) { Log.Info("No version file in " + sd.GetRoot()); needToSave |= true; return; } // Check for a seen_txid file, which marks a minimum transaction ID that // must be included in our load plan. try { maxSeenTxId = Math.Max(maxSeenTxId, NNStorage.ReadTransactionIdFile(sd)); } catch (IOException ioe) { Log.Warn("Unable to determine the max transaction ID seen by " + sd, ioe); return; } FilePath currentDir = sd.GetCurrentDir(); FilePath[] filesInStorage; try { filesInStorage = FileUtil.ListFiles(currentDir); } catch (IOException ioe) { Log.Warn("Unable to inspect storage directory " + currentDir, ioe); return; } foreach (FilePath f in filesInStorage) { Log.Debug("Checking file " + f); string name = f.GetName(); // Check for fsimage_* Matcher imageMatch = this.MatchPattern(name); if (imageMatch != null) { if (sd.GetStorageDirType().IsOfType(NNStorage.NameNodeDirType.Image)) { try { long txid = long.Parse(imageMatch.Group(1)); foundImages.AddItem(new FSImageStorageInspector.FSImageFile(sd, f, txid)); } catch (FormatException) { Log.Error("Image file " + f + " has improperly formatted " + "transaction ID"); } } else { // skip Log.Warn("Found image file at " + f + " but storage directory is " + "not configured to contain images." ); } } } // set finalized flag isUpgradeFinalized = isUpgradeFinalized && !sd.GetPreviousDir().Exists(); }