/// <summary> /// Find the id of the last edit log transaction writen to a edit log /// ledger. /// </summary> /// <exception cref="System.IO.IOException"/> /// <exception cref="Org.Apache.Hadoop.Contrib.Bkjournal.BookKeeperJournalManager.SegmentEmptyException /// "/> private long RecoverLastTxId(EditLogLedgerMetadata l, bool fence) { LedgerHandle lh = null; try { if (fence) { lh = bkc.OpenLedger(l.GetLedgerId(), BookKeeper.DigestType.Mac, Sharpen.Runtime.GetBytesForString (digestpw, Charsets.Utf8)); } else { lh = bkc.OpenLedgerNoRecovery(l.GetLedgerId(), BookKeeper.DigestType.Mac, Sharpen.Runtime.GetBytesForString (digestpw, Charsets.Utf8)); } } catch (BKException bke) { throw new IOException("Exception opening ledger for " + l, bke); } catch (Exception ie) { Sharpen.Thread.CurrentThread().Interrupt(); throw new IOException("Interrupted opening ledger for " + l, ie); } BookKeeperEditLogInputStream @in = null; try { long lastAddConfirmed = lh.GetLastAddConfirmed(); if (lastAddConfirmed == -1) { throw new BookKeeperJournalManager.SegmentEmptyException(); } @in = new BookKeeperEditLogInputStream(lh, l, lastAddConfirmed); long endTxId = HdfsConstants.InvalidTxid; FSEditLogOp op = @in.ReadOp(); while (op != null) { if (endTxId == HdfsConstants.InvalidTxid || op.GetTransactionId() == endTxId + 1) { endTxId = op.GetTransactionId(); } op = @in.ReadOp(); } return(endTxId); } finally { if (@in != null) { @in.Close(); } } }
/// <summary>Skip forward to specified transaction id.</summary> /// <remarks> /// Skip forward to specified transaction id. /// Currently we do this by just iterating forward. /// If this proves to be too expensive, this can be reimplemented /// with a binary search over bk entries /// </remarks> /// <exception cref="System.IO.IOException"/> public virtual void SkipTo(long txId) { long numToSkip = GetFirstTxId() - txId; FSEditLogOp op = null; for (long i = 0; i < numToSkip; i++) { op = ReadOp(); } if (op != null && op.GetTransactionId() != txId - 1) { throw new IOException("Corrupt stream, expected txid " + (txId - 1) + ", got " + op.GetTransactionId()); } }
public virtual void TestExcludeInProgressStreams() { FilePath f = new FilePath(TestEditLog.TestDir + "/excludeinprogressstreams"); // Don't close the edit log once the files have been set up. NNStorage storage = TestEditLog.SetupEdits(Sharpen.Collections.SingletonList <URI> (f.ToURI()), 10, false); Storage.StorageDirectory sd = storage.DirIterator(NNStorage.NameNodeDirType.Edits ).Next(); FileJournalManager jm = new FileJournalManager(conf, sd, storage); // If we exclude the in-progess stream, we should only have 100 tx. NUnit.Framework.Assert.AreEqual(100, GetNumberOfTransactions(jm, 1, false, false) ); EditLogInputStream elis = GetJournalInputStream(jm, 90, false); try { FSEditLogOp lastReadOp = null; while ((lastReadOp = elis.ReadOp()) != null) { NUnit.Framework.Assert.IsTrue(lastReadOp.GetTransactionId() <= 100); } } finally { IOUtils.Cleanup(Log, elis); } }
/// <summary> /// Verify that the given list of streams contains exactly the range of /// transactions specified, inclusive. /// </summary> /// <exception cref="System.IO.IOException"/> public static void VerifyEdits(IList <EditLogInputStream> streams, int firstTxnId, int lastTxnId) { IEnumerator <EditLogInputStream> iter = streams.GetEnumerator(); NUnit.Framework.Assert.IsTrue(iter.HasNext()); EditLogInputStream stream = iter.Next(); for (int expected = firstTxnId; expected <= lastTxnId; expected++) { FSEditLogOp op = stream.ReadOp(); while (op == null) { NUnit.Framework.Assert.IsTrue("Expected to find txid " + expected + ", " + "but no more streams available to read from" , iter.HasNext()); stream = iter.Next(); op = stream.ReadOp(); } NUnit.Framework.Assert.AreEqual(FSEditLogOpCodes.OpMkdir, op.opCode); NUnit.Framework.Assert.AreEqual(expected, op.GetTransactionId()); } NUnit.Framework.Assert.IsNull(stream.ReadOp()); NUnit.Framework.Assert.IsFalse("Expected no more txns after " + lastTxnId + " but more streams are available" , iter.HasNext()); }
/// <summary> /// Find out how many transactions we can read from a /// FileJournalManager, starting at a given transaction ID. /// </summary> /// <param name="jm">The journal manager</param> /// <param name="fromTxId">Transaction ID to start at</param> /// <param name="inProgressOk">Should we consider edit logs that are not finalized?</param> /// <returns>The number of transactions</returns> /// <exception cref="System.IO.IOException"/> internal static long GetNumberOfTransactions(FileJournalManager jm, long fromTxId , bool inProgressOk, bool abortOnGap) { long numTransactions = 0; long txId = fromTxId; PriorityQueue <EditLogInputStream> allStreams = new PriorityQueue <EditLogInputStream >(64, JournalSet.EditLogInputStreamComparator); jm.SelectInputStreams(allStreams, fromTxId, inProgressOk); EditLogInputStream elis = null; try { while ((elis = allStreams.Poll()) != null) { try { elis.SkipUntil(txId); while (true) { FSEditLogOp op = elis.ReadOp(); if (op == null) { break; } if (abortOnGap && (op.GetTransactionId() != txId)) { Log.Info("getNumberOfTransactions: detected gap at txId " + fromTxId); return(numTransactions); } txId = op.GetTransactionId() + 1; numTransactions++; } } finally { IOUtils.Cleanup(Log, elis); } } } finally { IOUtils.Cleanup(Log, Sharpen.Collections.ToArray(allStreams, new EditLogInputStream [0])); } return(numTransactions); }
/// <summary> /// Skip edit log operations up to a given transaction ID, or until the /// end of the edit log is reached. /// </summary> /// <remarks> /// Skip edit log operations up to a given transaction ID, or until the /// end of the edit log is reached. /// After this function returns, the next call to readOp will return either /// end-of-file (null) or a transaction with a txid equal to or higher than /// the one we asked for. /// </remarks> /// <param name="txid">The transaction ID to read up until.</param> /// <returns> /// Returns true if we found a transaction ID greater than /// or equal to 'txid' in the log. /// </returns> /// <exception cref="System.IO.IOException"/> public virtual bool SkipUntil(long txid) { while (true) { FSEditLogOp op = ReadOp(); if (op == null) { return(false); } if (op.GetTransactionId() >= txid) { cachedOp = op; return(true); } } }
public virtual void TestReadFromMiddleOfEditLog() { FilePath f = new FilePath(TestEditLog.TestDir + "/readfrommiddleofeditlog"); NNStorage storage = TestEditLog.SetupEdits(Sharpen.Collections.SingletonList <URI> (f.ToURI()), 10); Storage.StorageDirectory sd = storage.DirIterator(NNStorage.NameNodeDirType.Edits ).Next(); FileJournalManager jm = new FileJournalManager(conf, sd, storage); EditLogInputStream elis = GetJournalInputStream(jm, 5, true); try { FSEditLogOp op = elis.ReadOp(); NUnit.Framework.Assert.AreEqual("read unexpected op", op.GetTransactionId(), 5); } finally { IOUtils.Cleanup(Log, elis); } }
/// <exception cref="System.IO.IOException"/> private FSEditLogOp NextOpImpl(bool skipBrokenEdits) { FSEditLogOp op = null; switch (state) { case EditLogFileInputStream.State.Uninit: { try { Init(true); } catch (Exception e) { Log.Error("caught exception initializing " + this, e); if (skipBrokenEdits) { return(null); } Throwables.PropagateIfPossible <IOException>(e); } Preconditions.CheckState(state != EditLogFileInputStream.State.Uninit); return(NextOpImpl(skipBrokenEdits)); } case EditLogFileInputStream.State.Open: { op = reader.ReadOp(skipBrokenEdits); if ((op != null) && (op.HasTransactionId())) { long txId = op.GetTransactionId(); if ((txId >= lastTxId) && (lastTxId != HdfsConstants.InvalidTxid)) { // // Sometimes, the NameNode crashes while it's writing to the // edit log. In that case, you can end up with an unfinalized edit log // which has some garbage at the end. // JournalManager#recoverUnfinalizedSegments will finalize these // unfinished edit logs, giving them a defined final transaction // ID. Then they will be renamed, so that any subsequent // readers will have this information. // // Since there may be garbage at the end of these "cleaned up" // logs, we want to be sure to skip it here if we've read everything // we were supposed to read out of the stream. // So we force an EOF on all subsequent reads. // long skipAmt = log.Length() - tracker.GetPos(); if (skipAmt > 0) { if (Log.IsDebugEnabled()) { Log.Debug("skipping " + skipAmt + " bytes at the end " + "of edit log '" + GetName () + "': reached txid " + txId + " out of " + lastTxId); } tracker.ClearLimit(); IOUtils.SkipFully(tracker, skipAmt); } } } break; } case EditLogFileInputStream.State.Closed: { break; } } // return null return(op); }
/// <exception cref="System.IO.IOException"/> protected internal override FSEditLogOp NextOp() { while (true) { switch (state) { case RedundantEditLogInputStream.State.SkipUntil: { try { if (prevTxId != HdfsConstants.InvalidTxid) { Log.Info("Fast-forwarding stream '" + streams[curIdx].GetName() + "' to transaction ID " + (prevTxId + 1)); streams[curIdx].SkipUntil(prevTxId + 1); } } catch (IOException e) { prevException = e; state = RedundantEditLogInputStream.State.StreamFailed; } state = RedundantEditLogInputStream.State.Ok; break; } case RedundantEditLogInputStream.State.Ok: { try { FSEditLogOp op = streams[curIdx].ReadOp(); if (op == null) { state = RedundantEditLogInputStream.State.Eof; if (streams[curIdx].GetLastTxId() == prevTxId) { return(null); } else { throw new RedundantEditLogInputStream.PrematureEOFException("got premature end-of-file " + "at txid " + prevTxId + "; expected file to go up to " + streams[curIdx].GetLastTxId ()); } } prevTxId = op.GetTransactionId(); return(op); } catch (IOException e) { prevException = e; state = RedundantEditLogInputStream.State.StreamFailed; } break; } case RedundantEditLogInputStream.State.StreamFailed: { if (curIdx + 1 == streams.Length) { throw prevException; } long oldLast = streams[curIdx].GetLastTxId(); long newLast = streams[curIdx + 1].GetLastTxId(); if (newLast < oldLast) { throw new IOException("We encountered an error reading " + streams[curIdx].GetName () + ". During automatic edit log " + "failover, we noticed that all of the remaining edit log " + "streams are shorter than the current one! The best " + "remaining edit log ends at transaction " + newLast + ", but we thought we could read up to transaction " + oldLast + ". If you continue, metadata will be lost forever!" ); } Log.Error("Got error reading edit log input stream " + streams[curIdx].GetName() + "; failing over to edit log " + streams[curIdx + 1].GetName(), prevException); curIdx++; state = RedundantEditLogInputStream.State.SkipUntil; break; } case RedundantEditLogInputStream.State.StreamFailedResync: { if (curIdx + 1 == streams.Length) { if (prevException is RedundantEditLogInputStream.PrematureEOFException) { // bypass early EOF check state = RedundantEditLogInputStream.State.Eof; } else { streams[curIdx].Resync(); state = RedundantEditLogInputStream.State.SkipUntil; } } else { Log.Error("failing over to edit log " + streams[curIdx + 1].GetName()); curIdx++; state = RedundantEditLogInputStream.State.SkipUntil; } break; } case RedundantEditLogInputStream.State.Eof: { return(null); } } } }
/// <exception cref="System.IO.IOException"/> internal static void RunEditLogTest(TestNameNodeRecovery.EditLogTestSetup elts) { FilePath TestLogName = new FilePath(TestDir, "test_edit_log"); FSEditLogOp.OpInstanceCache cache = new FSEditLogOp.OpInstanceCache(); EditLogFileOutputStream elfos = null; EditLogFileInputStream elfis = null; try { elfos = new EditLogFileOutputStream(new Configuration(), TestLogName, 0); elfos.Create(NameNodeLayoutVersion.CurrentLayoutVersion); elts.AddTransactionsToLog(elfos, cache); elfos.SetReadyToFlush(); elfos.FlushAndSync(true); elfos.Close(); elfos = null; elfis = new EditLogFileInputStream(TestLogName); elfis.SetMaxOpSize(elts.GetMaxOpSize()); // reading through normally will get you an exception ICollection <long> validTxIds = elts.GetValidTxIds(); FSEditLogOp op = null; long prevTxId = 0; try { while (true) { op = elfis.NextOp(); if (op == null) { break; } Log.Debug("read txid " + op.txid); if (!validTxIds.Contains(op.GetTransactionId())) { NUnit.Framework.Assert.Fail("read txid " + op.GetTransactionId() + ", which we did not expect to find." ); } validTxIds.Remove(op.GetTransactionId()); prevTxId = op.GetTransactionId(); } if (elts.GetLastValidTxId() != -1) { NUnit.Framework.Assert.Fail("failed to throw IoException as expected"); } } catch (IOException) { if (elts.GetLastValidTxId() == -1) { NUnit.Framework.Assert.Fail("expected all transactions to be valid, but got exception " + "on txid " + prevTxId); } else { NUnit.Framework.Assert.AreEqual(prevTxId, elts.GetLastValidTxId()); } } if (elts.GetLastValidTxId() != -1) { // let's skip over the bad transaction op = null; prevTxId = 0; try { while (true) { op = elfis.NextValidOp(); if (op == null) { break; } prevTxId = op.GetTransactionId(); NUnit.Framework.Assert.IsTrue(validTxIds.Remove(op.GetTransactionId())); } } catch (Exception e) { NUnit.Framework.Assert.Fail("caught IOException while trying to skip over bad " + "transaction. message was " + e.Message + "\nstack trace\n" + StringUtils.StringifyException (e)); } } // We should have read every valid transaction. NUnit.Framework.Assert.IsTrue(validTxIds.IsEmpty()); } finally { IOUtils.Cleanup(Log, elfos, elfis); } }
/// <summary>Loads edits file, uses visitor to process all elements</summary> /// <exception cref="System.IO.IOException"/> public override void LoadEdits() { try { visitor.Start(inputStream.GetVersion(true)); while (true) { try { FSEditLogOp op = inputStream.ReadOp(); if (op == null) { break; } if (fixTxIds) { if (nextTxId <= 0) { nextTxId = op.GetTransactionId(); if (nextTxId <= 0) { nextTxId = 1; } } op.SetTransactionId(nextTxId); nextTxId++; } visitor.VisitOp(op); } catch (IOException e) { if (!recoveryMode) { // Tell the visitor to clean up, then re-throw the exception Log.Error("Got IOException at position " + inputStream.GetPosition()); visitor.Close(e); throw; } Log.Error("Got IOException while reading stream! Resyncing.", e); inputStream.Resync(); } catch (RuntimeException e) { if (!recoveryMode) { // Tell the visitor to clean up, then re-throw the exception Log.Error("Got RuntimeException at position " + inputStream.GetPosition()); visitor.Close(e); throw; } Log.Error("Got RuntimeException while reading stream! Resyncing.", e); inputStream.Resync(); } } visitor.Close(null); } finally { IOUtils.Cleanup(Log, inputStream); } }
public override void EndElement(string uri, string name, string qName) { string str = XMLUtils.UnmangleXmlString(cbuf.ToString(), false).Trim(); cbuf = new StringBuilder(); switch (state) { case OfflineEditsXmlLoader.ParseState.ExpectEditsTag: { throw new XMLUtils.InvalidXmlException("expected <EDITS/>"); } case OfflineEditsXmlLoader.ParseState.ExpectVersion: { if (!name.Equals("EDITS_VERSION")) { throw new XMLUtils.InvalidXmlException("expected </EDITS_VERSION>"); } try { int version = System.Convert.ToInt32(str); visitor.Start(version); } catch (IOException e) { // Can't throw IOException from a SAX method, sigh. throw new RuntimeException(e); } state = OfflineEditsXmlLoader.ParseState.ExpectRecord; break; } case OfflineEditsXmlLoader.ParseState.ExpectRecord: { if (name.Equals("EDITS")) { state = OfflineEditsXmlLoader.ParseState.ExpectEnd; } else { if (!name.Equals("RECORD")) { throw new XMLUtils.InvalidXmlException("expected </EDITS> or </RECORD>"); } } break; } case OfflineEditsXmlLoader.ParseState.ExpectOpcode: { if (!name.Equals("OPCODE")) { throw new XMLUtils.InvalidXmlException("expected </OPCODE>"); } opCode = FSEditLogOpCodes.ValueOf(str); state = OfflineEditsXmlLoader.ParseState.ExpectData; break; } case OfflineEditsXmlLoader.ParseState.ExpectData: { throw new XMLUtils.InvalidXmlException("expected <DATA/>"); } case OfflineEditsXmlLoader.ParseState.HandleData: { stanza.SetValue(str); if (stanzaStack.Empty()) { if (!name.Equals("DATA")) { throw new XMLUtils.InvalidXmlException("expected </DATA>"); } state = OfflineEditsXmlLoader.ParseState.ExpectRecord; FSEditLogOp op = opCache.Get(opCode); opCode = null; try { op.DecodeXml(stanza); stanza = null; } finally { if (stanza != null) { System.Console.Error.WriteLine("fromXml error decoding opcode " + opCode + "\n" + stanza.ToString()); stanza = null; } } if (fixTxIds) { if (nextTxId <= 0) { nextTxId = op.GetTransactionId(); if (nextTxId <= 0) { nextTxId = 1; } } op.SetTransactionId(nextTxId); nextTxId++; } try { visitor.VisitOp(op); } catch (IOException e) { // Can't throw IOException from a SAX method, sigh. throw new RuntimeException(e); } state = OfflineEditsXmlLoader.ParseState.ExpectRecord; } else { stanza = stanzaStack.Pop(); } break; } case OfflineEditsXmlLoader.ParseState.ExpectEnd: { throw new XMLUtils.InvalidXmlException("not expecting anything after </EDITS>"); } } }