You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
724 lines
21 KiB
724 lines
21 KiB
/*++
|
|
|
|
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;
|
|
|
|
LFS_WAITER LfsWaiter;
|
|
|
|
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'd absolutely hate for this to happen on a read only volume.
|
|
//
|
|
|
|
ASSERT( !(FlagOn( Lfcb->Flags, LFCB_READ_ONLY )));
|
|
|
|
//
|
|
// We compute the size of this log record.
|
|
//
|
|
|
|
ThisWriteEntry = WriteEntries;
|
|
|
|
RemainingLogBytes = 0;
|
|
|
|
while (NumberOfWriteEntries--) {
|
|
|
|
RemainingLogBytes += QuadAlign( ThisWriteEntry->ByteLength );
|
|
|
|
ThisWriteEntry++;
|
|
}
|
|
|
|
OriginalLogBytes = RemainingLogBytes;
|
|
|
|
ThisWriteEntry = WriteEntries;
|
|
|
|
//
|
|
// Loop until we have the Lbcb and we know it is not part of
|
|
// a partial page transfer. We need to make sure we have
|
|
// a Bcb for this page.
|
|
//
|
|
|
|
while (TRUE) {
|
|
|
|
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 );
|
|
|
|
#ifdef BENL_DBG
|
|
ASSERT( ThisLbcb->BufferOffset < 0x1000 );
|
|
#endif
|
|
|
|
//
|
|
// If there is a Bcb then we are golden.
|
|
//
|
|
|
|
if (ThisLbcb->LogPageBcb != NULL) { break; }
|
|
|
|
//
|
|
// Otherwise we want to drop the Lfcb and wait for the IO to complete.
|
|
//
|
|
|
|
Lfcb->Waiters += 1;
|
|
|
|
KeInitializeEvent( &LfsWaiter.Event, SynchronizationEvent, FALSE );
|
|
LfsWaiter.Lsn.QuadPart = 0;
|
|
|
|
//
|
|
// Setup a lfs waiter to be signalled if io is ongoing - since
|
|
// the lfcb is owned exclusive we don't need to use the sync fast mutex
|
|
//
|
|
|
|
if (Lfcb->Sync->LfsIoState == LfsNoIoInProgress) {
|
|
LfsWaiter.Waiters.Flink = NULL;
|
|
} else {
|
|
InsertHeadList( &Lfcb->WaiterList, &LfsWaiter.Waiters );
|
|
}
|
|
|
|
LfsReleaseLfcb( Lfcb );
|
|
|
|
//
|
|
// If we really found i/o ongoing then wait on the event
|
|
//
|
|
|
|
if (LfsWaiter.Waiters.Flink != NULL) {
|
|
KeWaitForSingleObject( &LfsWaiter.Event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL );
|
|
}
|
|
|
|
LfsAcquireLfcbExclusive( Lfcb );
|
|
Lfcb->Waiters -= 1;
|
|
}
|
|
|
|
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 = NextLsn;
|
|
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->LfsRestartBias = 1;
|
|
|
|
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;
|
|
}
|