diff options
Diffstat (limited to 'private/ntos/lfs/logrcsup.c')
-rw-r--r-- | private/ntos/lfs/logrcsup.c | 658 |
1 files changed, 658 insertions, 0 deletions
diff --git a/private/ntos/lfs/logrcsup.c b/private/ntos/lfs/logrcsup.c new file mode 100644 index 000000000..76f8de3a2 --- /dev/null +++ b/private/ntos/lfs/logrcsup.c @@ -0,0 +1,658 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + LogRcSup.c + +Abstract: + + This module implements support for dealing with log records, both + writing and recovering them. + +Author: + + Brian Andrew [BrianAn] 20-June-1991 + +Revision History: + +--*/ + +#include "lfsprocs.h" + +// +// The debug trace level +// + +#define Dbg (DEBUG_TRACE_LOG_RECORD_SUP) + +VOID +LfsPrepareLfcbForLogRecord ( + IN OUT PLFCB Lfcb, + IN ULONG RemainingLogBytes + ); + +VOID +LfsTransferLogBytes ( + IN PLBCB Lbcb, + IN OUT PLFS_WRITE_ENTRY *ThisWriteEntry, + IN OUT PCHAR *CurrentBuffer, + IN OUT PULONG CurrentByteCount, + IN OUT PULONG PadBytes, + IN OUT PULONG RemainingPageBytes, + IN OUT PULONG RemainingLogBytes + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, LfsPrepareLfcbForLogRecord) +#pragma alloc_text(PAGE, LfsTransferLogBytes) +#pragma alloc_text(PAGE, LfsWriteLogRecordIntoLogPage) +#endif + + +BOOLEAN +LfsWriteLogRecordIntoLogPage ( + IN PLFCB Lfcb, + IN PLCH Lch, + IN ULONG NumberOfWriteEntries, + IN PLFS_WRITE_ENTRY WriteEntries, + IN LFS_RECORD_TYPE RecordType, + IN TRANSACTION_ID *TransactionId OPTIONAL, + IN LSN ClientUndoNextLsn OPTIONAL, + IN LSN ClientPreviousLsn OPTIONAL, + IN LONG UndoRequirement, + IN BOOLEAN ForceToDisk, + OUT PLSN Lsn + ) + +/*++ + +Routine Description: + + This routine is called to write a log record into the log file + using the cache manager. If there is room in the current log + page it is added to that. Otherwise we allocate a new log page + and write the log record header for this log page. We then + write the log record into the remaining bytes of this page and + into any subsequent pages if needed. + +Arguments: + + Lfcb - File control block for this log file. + + Lch - This is the client handle, we may update the undo space for this + client. + + NumberOfWriteEntries - Number of components of the log record. + + WriteEntries - Pointer to an array of write entries. + + UndoRequirement - Signed value indicating the requirement to write + an abort log record for this log record. A negative + value indicates that this is the abort record. + + RecordType - The Lfs-defined type of this log record. + + TransactionId - Pointer to the transaction structure containing the + Id for transaction containing this operation. + + ClientUndoNextLsn - This is the Lsn provided by the client for use + in his restart. Will be the zero Lsn for + a restart log record. + + ClientPreviousLsn - This is the Lsn provided by the client for use + in his restart. Will the the zero Lsn for a + restart log record. + + UndoRequirement - This is the data size for the undo record for + this log record. + + ForceToDisk - Indicates if this log record will be flushed immediately + to disk. + + Lsn - A pointer to store the Lsn for this log record. + +Return Value: + + BOOLEAN - Advisory, TRUE indicates that less than 1/4 of the log file is + available. + +--*/ + +{ + PLFS_WRITE_ENTRY ThisWriteEntry; + + ULONG RemainingLogBytes; + ULONG OriginalLogBytes; + + ULONG RemainingPageBytes; + ULONG HeaderAdjust; + + PLBCB ThisLbcb; + + LSN NextLsn; + + PLFS_RECORD_HEADER RecordHeader; + + PCHAR CurrentBuffer; + ULONG CurrentByteCount; + ULONG PadBytes; + + BOOLEAN LogFileFull = FALSE; + + PAGED_CODE(); + + DebugTrace( +1, Dbg, "LfsWriteLogRecordIntoLogPage: Entered\n", 0 ); + DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb ); + DebugTrace( 0, Dbg, "Lch -> %08lx\n", Lch ); + DebugTrace( 0, Dbg, "Number of Write Entries -> %08lx\n", NumberOfWriteEntries ); + DebugTrace( 0, Dbg, "Write Entries -> %08lx\n", WriteEntries ); + DebugTrace( 0, Dbg, "Record Type -> %08lx\n", RecordType ); + DebugTrace( 0, Dbg, "Transaction Id -> %08lx\n", TransactionId ); + DebugTrace( 0, Dbg, "ClientUndoNextLsn (Low) -> %08lx\n", ClientUndoNextLsn.LowPart ); + DebugTrace( 0, Dbg, "ClientUndoNextLsn (High) -> %08lx\n", ClientUndoNextLsn.HighPart ); + DebugTrace( 0, Dbg, "ClientPreviousLsn (Low) -> %08lx\n", ClientPreviousLsn.LowPart ); + DebugTrace( 0, Dbg, "ClientPreviousLsn (High) -> %08lx\n", ClientPreviousLsn.HighPart ); + DebugTrace( 0, Dbg, "UndoRequirement -> %08lx\n", UndoRequirement ); + DebugTrace( 0, Dbg, "ForceToDisk -> %04x\n", ForceToDisk ); + + // + // We compute the size of this log record. + // + + ThisWriteEntry = WriteEntries; + + RemainingLogBytes = 0; + + while (NumberOfWriteEntries--) { + + RemainingLogBytes += QuadAlign( ThisWriteEntry->ByteLength ); + + ThisWriteEntry++; + } + + OriginalLogBytes = RemainingLogBytes; + + ThisWriteEntry = WriteEntries; + + LogFileFull = LfsVerifyLogSpaceAvail( Lfcb, + Lch, + RemainingLogBytes, + UndoRequirement, + ForceToDisk ); + + // + // We update the Lfcb so that we can start putting the log record into + // the top of the Lbcb active list. + // + + LfsPrepareLfcbForLogRecord( Lfcb, + RemainingLogBytes + Lfcb->RecordHeaderLength ); + + ThisLbcb = CONTAINING_RECORD( Lfcb->LbcbActive.Flink, + LBCB, + ActiveLinks ); + + RemainingPageBytes = (ULONG)Lfcb->LogPageSize - (ULONG)ThisLbcb->BufferOffset; + + // + // Compute the Lsn starting in the next log buffer. + // + + NextLsn.QuadPart = LfsComputeLsnFromLbcb( Lfcb, ThisLbcb ); + + // + // We get a pointer to the log record header and the start of the + // log record in the pinned buffer. + // + + RecordHeader = Add2Ptr( ThisLbcb->PageHeader, + (ULONG)ThisLbcb->BufferOffset, + PLFS_RECORD_HEADER ); + + // + // We update the record header. + // + + // + // Zero out the structure initially. + // + + RtlZeroMemory( RecordHeader, Lfcb->RecordHeaderLength ); + + // + // Update all the fields. + // + + RecordHeader->ThisLsn = NextLsn; + RecordHeader->ClientPreviousLsn = ClientPreviousLsn; + RecordHeader->ClientUndoNextLsn = ClientUndoNextLsn; + + if (TransactionId != NULL) { + RecordHeader->TransactionId = *TransactionId; + } + + RecordHeader->ClientDataLength = RemainingLogBytes; + RecordHeader->ClientId = Lch->ClientId; + RecordHeader->RecordType = RecordType; + + // + // Check if this is a multi-page record. + // + + if (RemainingLogBytes + Lfcb->RecordHeaderLength > RemainingPageBytes) { + + SetFlag( RecordHeader->Flags, LOG_RECORD_MULTI_PAGE ); + } + + RemainingPageBytes -= Lfcb->RecordHeaderLength; + + // + // Update the buffer position in the Lbcb + // + + (ULONG)ThisLbcb->BufferOffset += Lfcb->RecordHeaderLength; + HeaderAdjust = Lfcb->RecordHeaderLength; + + // + // Remember the values in the current write entry. + // + + CurrentBuffer = ThisWriteEntry->Buffer; + CurrentByteCount = ThisWriteEntry->ByteLength; + + PadBytes = (8 - (CurrentByteCount & ~(0xfffffff8))) & ~(0xfffffff8); + + // + // Continue to transfer bytes until all the client's data has + // been transferred. + // + + while (RemainingLogBytes != 0) { + + PLFS_RECORD_PAGE_HEADER PageHeader; + + PageHeader = (PLFS_RECORD_PAGE_HEADER) ThisLbcb->PageHeader; + + // + // If the Lbcb is empty and we are about to store data into it we + // subtract the data size of the page from the available space. + // Update all the information we want to put in the header. + // + + if (!FlagOn( ThisLbcb->LbcbFlags, LBCB_NOT_EMPTY )) { + + // + // We subtract this page from the available pages only if + // we are at the beginning of the page. Otherwise this + // could be a reuse page. In that case it has already + // been subtracted. + // + + if ((ULONG)ThisLbcb->BufferOffset - HeaderAdjust == (ULONG)Lfcb->LogPageDataOffset) { + + + Lfcb->CurrentAvailable = Lfcb->CurrentAvailable - Lfcb->ReservedLogPageSize; //**** xxSub( Lfcb->CurrentAvailable, Lfcb->ReservedLogPageSize ); + } + + InsertTailList( &Lfcb->LbcbWorkque, &ThisLbcb->WorkqueLinks ); + SetFlag( ThisLbcb->LbcbFlags, LBCB_NOT_EMPTY ); + } + + HeaderAdjust = 0; + + // + // Compute the number of transfer bytes. Update the remaining + // page bytes, remaining log bytes and position in the write + // buffer array. This routine also copies the bytes into the buffer. + // + + LfsTransferLogBytes( ThisLbcb, + &ThisWriteEntry, + &CurrentBuffer, + &CurrentByteCount, + &PadBytes, + &RemainingPageBytes, + &RemainingLogBytes ); + + // + // This log record ends on this page. Update the fields for the + // ending Lsn. + // + + if (RemainingLogBytes == 0) { + + SetFlag( ThisLbcb->Flags, LOG_PAGE_LOG_RECORD_END ); + ThisLbcb->LastEndLsn = NextLsn; + + if (FlagOn( Lfcb->Flags, LFCB_PACK_LOG )) { + + PageHeader->Header.Packed.LastEndLsn = NextLsn; + PageHeader->Header.Packed.NextRecordOffset = (USHORT)ThisLbcb->BufferOffset; + } + } + + // + // We are done with this page, update the fields in the page header. + // + + if (RemainingPageBytes == 0 + || RemainingLogBytes == 0) { + + // + // We are done with this page. Update the Lbcb and page header. + // + + ThisLbcb->LastLsn = PageHeader->Copy.LastLsn = NextLsn; + PageHeader->Flags = ThisLbcb->Flags; + + // + // We can't put any more log records on this page. Remove + // it from the active queue. + // + + if (RemainingPageBytes < Lfcb->RecordHeaderLength) { + + RemoveHeadList( &Lfcb->LbcbActive ); + ClearFlag( ThisLbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE ); + + // + // If there are more log bytes then get the next Lbcb. + // + + if (RemainingLogBytes != 0) { + + ThisLbcb = CONTAINING_RECORD( Lfcb->LbcbActive.Flink, + LBCB, + ActiveLinks ); + + RemainingPageBytes = (ULONG)Lfcb->LogPageSize + - (ULONG)ThisLbcb->BufferOffset; + } + } + } + } + + *Lsn = NextLsn; + + Lfcb->RestartArea->CurrentLsn = NextLsn; + + Lfcb->RestartArea->LastLsnDataLength = OriginalLogBytes; + + ClearFlag( Lfcb->Flags, LFCB_NO_LAST_LSN ); + + DebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn->LowPart ); + DebugTrace( 0, Dbg, "Lsn (High) -> %08lx\n", Lsn->HighPart ); + DebugTrace( -1, Dbg, "LfsWriteLogRecordIntoLogPage: Exit\n", 0 ); + + return LogFileFull; +} + + +// +// Local support routine. +// + +VOID +LfsPrepareLfcbForLogRecord ( + IN OUT PLFCB Lfcb, + IN ULONG RemainingLogBytes + ) + +/*++ + +Routine Description: + + This routine is called to insure that the Lfcb has a Lbcb in the + active queue to perform the next log record transfer. + This condition is met when there is a least one buffer block and + the log record data will fit entirely on this page or this buffer + block contains no other data in the unpacked case. For the packed + case we just need to make sure that there are sufficient Lbcb's. + +Arguments: + + Lfcb - File control block for this log file. + + RemainingLogBytes - The number of bytes remaining for this log record. + +Return Value: + + None + +--*/ + +{ + PLBCB ThisLbcb; + ULONG RemainingPageBytes; + PLIST_ENTRY LbcbLinks; + + PAGED_CODE(); + + DebugTrace( +1, Dbg, "LfsPrepareLfcbForLogRecord: Entered\n", 0 ); + DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb ); + DebugTrace( 0, Dbg, "RemainingLogBytes -> %08lx\n", RemainingLogBytes ); + + // + // If there is no Lbcb in the active queue, we don't check it for size. + // + + if (!IsListEmpty( &Lfcb->LbcbActive )) { + + // + // If the log record won't fit in the remaining bytes of this page, + // we queue this log buffer. + // + + ThisLbcb = CONTAINING_RECORD( Lfcb->LbcbActive.Flink, + LBCB, + ActiveLinks ); + + RemainingPageBytes = (ULONG)Lfcb->LogPageSize + - (ULONG)ThisLbcb->BufferOffset; + + // + // This log page won't do if the remaining bytes won't hold the data + // unless this is the first log record in the page or we are packing + // the log file. + // + + if (RemainingLogBytes > RemainingPageBytes + && !FlagOn( Lfcb->Flags, LFCB_PACK_LOG ) + && (ULONG)ThisLbcb->BufferOffset != (ULONG)Lfcb->LogPageDataOffset) { + + RemoveHeadList( &Lfcb->LbcbActive ); + ClearFlag( ThisLbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE ); + } + } + + // + // We now make sure we can allocate enough Lbcb's for all of the log pages + // we will need. We now include the bytes for the log record reader. + // + + LbcbLinks = Lfcb->LbcbActive.Flink; + + while (TRUE) { + + // + // If the Lbcb link we have is the head of the list, we will need another + // Lbcb. + // + + if (LbcbLinks == &Lfcb->LbcbActive) { + + ThisLbcb = LfsGetLbcb( Lfcb ); + + } else { + + ThisLbcb = CONTAINING_RECORD( LbcbLinks, + LBCB, + ActiveLinks ); + } + + // + // Remember the bytes remaining on this page. This will always be quad + // aligned. + // + + RemainingPageBytes = (ULONG)Lfcb->LogPageSize - (ULONG)ThisLbcb->BufferOffset; + + if (RemainingPageBytes >= RemainingLogBytes) { + + break; + } + + // + // Move to the next log record. + // + + RemainingLogBytes -= RemainingPageBytes; + + LbcbLinks = ThisLbcb->ActiveLinks.Flink; + } + + DebugTrace( -1, Dbg, "LfsPrepareLfcbForLogRecord: Exit\n", 0 ); + + return; +} + + +VOID +LfsTransferLogBytes ( + IN PLBCB Lbcb, + IN OUT PLFS_WRITE_ENTRY *ThisWriteEntry, + IN OUT PCHAR *CurrentBuffer, + IN OUT PULONG CurrentByteCount, + IN OUT PULONG PadBytes, + IN OUT PULONG RemainingPageBytes, + IN OUT PULONG RemainingLogBytes + ) + +/*++ + +Routine Description: + + This routine is called to transfer the next block of bytes into + a log page. It is given a pointer to the current position in the + current Lfs write entry and the number of bytes remaining on that + log page. It will transfer as many of the client's bytes from the + current buffer that will fit and update various pointers. + +Arguments: + + Lbcb - This is the buffer block for this log page. + + ThisWriteEntry - This is a pointer to a pointer to the current Lfs + write entry. + + CurrentBuffer - This is a pointer to a pointer to the current position + in the current write entry buffer. If this points to a NULL + value it means to put zero bytes into the log. + + CurrentByteCount - This is a pointer to the number of bytes remaining + in the current buffer. + + PadBytes - This is a pointer to the number of padding byes for + this write entry. + + RemainingPageBytes - This is pointer to the number of bytes remaining + in this page. + + RemainingLogBytes - This is the number of bytes remaining to transfer + for this log record. + +Return Value: + + None + +--*/ + +{ + PCHAR CurrentLogPagePosition; + PCHAR CurrentClientPosition; + + ULONG TransferBytes; + ULONG ThisPadBytes; + + PAGED_CODE(); + + DebugTrace( +1, Dbg, "LfsTransferLogBytes: Entered\n", 0 ); + DebugTrace( 0, Dbg, "Lbcb -> %08lx\n", Lbcb ); + DebugTrace( 0, Dbg, "ThisWriteEntry -> %08lx\n", *ThisWriteEntry ); + DebugTrace( 0, Dbg, "CurrentBuffer -> %08lx\n", *CurrentBuffer ); + DebugTrace( 0, Dbg, "CurrentByteCount -> %08lx\n", *CurrentByteCount ); + DebugTrace( 0, Dbg, "RemainingPageBytes -> %08lx\n", *RemainingPageBytes ); + DebugTrace( 0, Dbg, "RemainingLogBytes -> %08lx\n", *RemainingLogBytes ); + + // + // Remember the current client buffer position and current position + // in log page. + // + + CurrentLogPagePosition = Add2Ptr( Lbcb->PageHeader, (ULONG)Lbcb->BufferOffset, PCHAR ); + CurrentClientPosition = *CurrentBuffer; + + // + // The limiting factor is either the number of bytes remaining in a + // write entry or the number remaining in the log page. + // + + if (*CurrentByteCount <= *RemainingPageBytes) { + + TransferBytes = *CurrentByteCount; + + ThisPadBytes = *PadBytes; + + if (*RemainingLogBytes != (*CurrentByteCount + *PadBytes) ) { + + (*ThisWriteEntry)++; + + *CurrentBuffer = (*ThisWriteEntry)->Buffer; + *CurrentByteCount = (*ThisWriteEntry)->ByteLength; + + *PadBytes = (8 - (*CurrentByteCount & ~(0xfffffff8))) & ~(0xfffffff8); + } + + } else { + + TransferBytes = *RemainingPageBytes; + + ThisPadBytes = 0; + + *CurrentByteCount -= TransferBytes; + + if (*CurrentBuffer != NULL) { + + *CurrentBuffer += TransferBytes; + } + } + + // + // Transfer the requested bytes. + // + + if (CurrentClientPosition != NULL) { + + RtlCopyMemory( CurrentLogPagePosition, CurrentClientPosition, TransferBytes ); + + } else { + + RtlZeroMemory( CurrentLogPagePosition, TransferBytes ); + } + + // + // Reduce the remaining page and log bytes by the transfer amount and + // move forward in the log page. + // + + *RemainingLogBytes -= (TransferBytes + ThisPadBytes); + *RemainingPageBytes -= (TransferBytes + ThisPadBytes); + + (ULONG)Lbcb->BufferOffset += (TransferBytes + ThisPadBytes); + + DebugTrace( -1, Dbg, "LfsTransferLogBytes: Exit\n", 0 ); + + return; +} |