public LfsRecord ReadRecord(ulong lsn)
        {
            if (m_restartPage == null)
            {
                m_restartPage = ReadRestartPage();
            }

            ulong         pageOffsetInFile   = LsnToPageOffsetInFile(lsn);
            int           recordOffsetInPage = LsnToRecordOffsetInPage(lsn);
            LfsRecordPage page = ReadPage(pageOffsetInFile);

            if (page == null)
            {
                throw new InvalidDataException("LfsRecord LSN points to an uninitialized page");
            }
            int       dataOffset = m_restartPage.RestartArea.LogPageDataOffset;
            LfsRecord record     = page.ReadRecord(recordOffsetInPage);

            if (record.ThisLsn != lsn)
            {
                throw new InvalidDataException("LfsRecord LSN does not match expected value");
            }
            if (record.Length < LfsRecord.HeaderLength)
            {
                throw new InvalidDataException("LfsRecord length is invalid");
            }
            if (record.IsMultiPageRecord)
            {
                int recordLength   = (int)(LfsRecord.HeaderLength + record.ClientDataLength);
                int bytesRemaining = recordLength - (LfsRecord.HeaderLength + record.Data.Length);
                while (bytesRemaining > 0)
                {
                    pageOffsetInFile += m_restartPage.LogPageSize;
                    if (pageOffsetInFile == m_restartPage.RestartArea.FileSize)
                    {
                        pageOffsetInFile = m_restartPage.SystemPageSize * 2 + m_restartPage.LogPageSize * 2;
                    }
                    page = ReadPage(pageOffsetInFile);
                    int bytesToRead = Math.Min((int)m_restartPage.LogPageSize - dataOffset, bytesRemaining);
                    record.Data     = ByteUtils.Concatenate(record.Data, page.ReadBytes(dataOffset, bytesToRead));
                    bytesRemaining -= bytesToRead;
                }
            }
            return(record);
        }
Beispiel #2
0
        /// <summary>
        /// This method will repair the log file by copying the tail copies back to their correct location.
        /// If necessary, the restart area will be updated to reflect CurrentLsn and LastLsnDataLength.
        /// </summary>
        /// <remarks>This method will only repair the log file, further actions are needed to bring the volume back to a consistent state.</remarks>
        private void RepairLogFile()
        {
            if (m_restartPage == null)
            {
                m_restartPage = ReadRestartPage();
            }

            // Note: this implementation is not as exhaustive as it should be.
            LfsRecordPage firstTailPage  = null;
            LfsRecordPage secondTailPage = null;

            try
            {
                firstTailPage = ReadPageFromFile(m_restartPage.SystemPageSize * 2);
            }
            catch (InvalidDataException)
            {
            }

            try
            {
                secondTailPage = ReadPageFromFile(m_restartPage.SystemPageSize * 2 + m_restartPage.LogPageSize);
            }
            catch (InvalidDataException)
            {
            }

            // Find the most recent tail copy
            LfsRecordPage tailPage = null;

            if (firstTailPage != null)
            {
                tailPage = firstTailPage;
            }

            if (tailPage == null || (secondTailPage != null && secondTailPage.LastEndLsn > firstTailPage.LastEndLsn))
            {
                tailPage = secondTailPage;
            }

            if (tailPage != null)
            {
                LfsRecordPage page = null;
                try
                {
                    page = ReadPageFromFile(tailPage.LastLsnOrFileOffset);
                }
                catch (InvalidDataException)
                {
                }

                if (page == null || tailPage.LastEndLsn > page.LastLsnOrFileOffset)
                {
                    ulong pageOffsetInFile = tailPage.LastLsnOrFileOffset;
                    tailPage.LastLsnOrFileOffset = tailPage.LastEndLsn;
                    WritePage(pageOffsetInFile, tailPage);

                    if (tailPage.LastEndLsn > m_restartPage.LogRestartArea.CurrentLsn)
                    {
                        m_restartPage.LogRestartArea.CurrentLsn = tailPage.LastEndLsn;
                        int       recordOffsetInPage = LsnToRecordOffsetInPage(tailPage.LastEndLsn);
                        LfsRecord record             = tailPage.ReadRecord(recordOffsetInPage);
                        m_restartPage.LogRestartArea.LastLsnDataLength = (uint)record.Data.Length;
                        WriteRestartPage(m_restartPage);
                    }
                }
            }
        }