/// <exception cref="System.IO.IOException"/> internal virtual void CheckConsistentNamespace(NamespaceInfo nsInfo) { if (nsInfo.GetNamespaceID() != GetNamespaceID()) { throw new IOException("Incompatible namespaceID for journal " + this.sd + ": NameNode has nsId " + nsInfo.GetNamespaceID() + " but storage has nsId " + GetNamespaceID()); } if (!nsInfo.GetClusterID().Equals(GetClusterID())) { throw new IOException("Incompatible clusterID for journal " + this.sd + ": NameNode has clusterId '" + nsInfo.GetClusterID() + "' but storage has clusterId '" + GetClusterID() + "'" ); } }
/// <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>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); }
/// <exception cref="System.IO.IOException"/> private void CheckEnv() { lock (this) { if (!initialized) { try { Stat versionStat = zkc.Exists(versionPath, false); if (versionStat == null) { throw new IOException("Environment not initialized. " + "Have you forgotten to format?" ); } byte[] d = zkc.GetData(versionPath, false, versionStat); BKJournalProtos.VersionProto.Builder builder = BKJournalProtos.VersionProto.NewBuilder (); TextFormat.Merge(new string(d, Charsets.Utf8), builder); if (!builder.IsInitialized()) { throw new IOException("Invalid/Incomplete data in znode"); } BKJournalProtos.VersionProto vp = ((BKJournalProtos.VersionProto)builder.Build()); // There's only one version at the moment System.Diagnostics.Debug.Assert(vp.GetLayoutVersion() == BkjmLayoutVersion); NamespaceInfo readns = PBHelper.Convert(vp.GetNamespaceInfo()); if (nsInfo.GetNamespaceID() != readns.GetNamespaceID() || !nsInfo.clusterID.Equals (readns.GetClusterID()) || !nsInfo.GetBlockPoolID().Equals(readns.GetBlockPoolID ())) { string err = string.Format("Environment mismatch. Running process %s" + ", stored in ZK %s" , nsInfo, readns); Log.Error(err); throw new IOException(err); } ci.Init(); initialized = true; } catch (KeeperException ke) { throw new IOException("Cannot access ZooKeeper", ke); } catch (Exception ie) { Sharpen.Thread.CurrentThread().Interrupt(); throw new IOException("Interrupted while checking environment", ie); } } } }
/// <summary>Called by the BPServiceActors when they handshake to a NN.</summary> /// <remarks> /// Called by the BPServiceActors when they handshake to a NN. /// If this is the first NN connection, this sets the namespace info /// for this BPOfferService. If it's a connection to a new NN, it /// verifies that this namespace matches (eg to prevent a misconfiguration /// where a StandbyNode from a different cluster is specified) /// </remarks> /// <exception cref="System.IO.IOException"/> internal virtual void VerifyAndSetNamespaceInfo(NamespaceInfo nsInfo) { WriteLock(); try { if (this.bpNSInfo == null) { this.bpNSInfo = nsInfo; bool success = false; // Now that we know the namespace ID, etc, we can pass this to the DN. // The DN can now initialize its local storage if we are the // first BP to handshake, etc. try { dn.InitBlockPool(this); success = true; } finally { if (!success) { // The datanode failed to initialize the BP. We need to reset // the namespace info so that other BPService actors still have // a chance to set it, and re-initialize the datanode. this.bpNSInfo = null; } } } else { CheckNSEquality(bpNSInfo.GetBlockPoolID(), nsInfo.GetBlockPoolID(), "Blockpool ID" ); CheckNSEquality(bpNSInfo.GetNamespaceID(), nsInfo.GetNamespaceID(), "Namespace ID" ); CheckNSEquality(bpNSInfo.GetClusterID(), nsInfo.GetClusterID(), "Cluster ID"); } } finally { WriteUnlock(); } }
/// <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()); }