476 lines
12 KiB
C
476 lines
12 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
Write.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the user routines which write log records into
|
||
or flush portions of the log file.
|
||
|
||
Author:
|
||
|
||
Brian Andrew [BrianAn] 20-June-1991
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "lfsprocs.h"
|
||
|
||
//
|
||
// The debug trace level
|
||
//
|
||
|
||
#define Dbg (DEBUG_TRACE_WRITE)
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, LfsFlushToLsn)
|
||
#pragma alloc_text(PAGE, LfsForceWrite)
|
||
#pragma alloc_text(PAGE, LfsWrite)
|
||
#endif
|
||
|
||
|
||
BOOLEAN
|
||
LfsWrite (
|
||
IN LFS_LOG_HANDLE LogHandle,
|
||
IN ULONG NumberOfWriteEntries,
|
||
IN PLFS_WRITE_ENTRY WriteEntries,
|
||
IN LFS_RECORD_TYPE RecordType,
|
||
IN TRANSACTION_ID *TransactionId OPTIONAL,
|
||
IN LSN UndoNextLsn,
|
||
IN LSN PreviousLsn,
|
||
IN LONG UndoRequirement,
|
||
OUT PLSN Lsn
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called by a client to write a log record to the log file.
|
||
The log record is lazy written and is not guaranteed to be on the disk
|
||
until a subsequent LfsForceWrie or LfsWriteRestartArea or until
|
||
an LfsFlushtoLsn is issued withan Lsn greater-than or equal to the Lsn
|
||
returned from this service.
|
||
|
||
Arguments:
|
||
|
||
LogHandle - Pointer to private Lfs structure used to identify this
|
||
client.
|
||
|
||
NumberOfWriteEntries - Number of components of the log record.
|
||
|
||
WriteEntries - Pointer to an array of write entries.
|
||
|
||
RecordType - Lfs defined type for this log record.
|
||
|
||
TransactionId - Id value used to group log records by complete transaction.
|
||
|
||
UndoNextLsn - Lsn of a previous log record which needs to be undone in
|
||
the event of a client restart.
|
||
|
||
PreviousLsn - Lsn of the immediately previous log record for this client.
|
||
|
||
Lsn - Lsn to be associated with this log record.
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - Advisory, TRUE indicates that less than 1/4 of the log file is
|
||
available.
|
||
|
||
--*/
|
||
|
||
{
|
||
volatile NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
BOOLEAN LogFileFull = FALSE;
|
||
PLCH Lch;
|
||
|
||
PLFCB Lfcb;
|
||
|
||
PAGED_CODE();
|
||
|
||
DebugTrace( +1, Dbg, "LfsWrite: Entered\n", 0 );
|
||
DebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle );
|
||
DebugTrace( 0, Dbg, "NumberOfWriteEntries -> %08lx\n", NumberOfWriteEntries );
|
||
DebugTrace( 0, Dbg, "WriteEntries -> %08lx\n", WriteEntries );
|
||
DebugTrace( 0, Dbg, "Record Type -> %08lx\n", RecordType );
|
||
DebugTrace( 0, Dbg, "Transaction Id -> %08lx\n", TransactionId );
|
||
DebugTrace( 0, Dbg, "UndoNextLsn (Low) -> %08lx\n", UndoNextLsn.LowPart );
|
||
DebugTrace( 0, Dbg, "UndoNextLsn (High) -> %08lx\n", UndoNextLsn.HighPart );
|
||
DebugTrace( 0, Dbg, "PreviousLsn (Low) -> %08lx\n", PreviousLsn.LowPart );
|
||
DebugTrace( 0, Dbg, "PreviousLsn (High) -> %08lx\n", PreviousLsn.HighPart );
|
||
|
||
Lch = (PLCH) LogHandle;
|
||
|
||
//
|
||
// Check that the structure is a valid log handle structure.
|
||
//
|
||
|
||
LfsValidateLch( Lch );
|
||
|
||
//
|
||
// Use a try-except to catch errors.
|
||
//
|
||
|
||
try {
|
||
|
||
//
|
||
// Use a try-finally to facilitate cleanup.
|
||
//
|
||
|
||
try {
|
||
|
||
//
|
||
// Acquire the log file control block for this log file.
|
||
//
|
||
|
||
LfsAcquireLch( Lch );
|
||
Lfcb = Lch->Lfcb;
|
||
|
||
//
|
||
// If the Log file has been closed then refuse access.
|
||
//
|
||
|
||
if (Lfcb == NULL) {
|
||
|
||
ExRaiseStatus( STATUS_ACCESS_DENIED );
|
||
}
|
||
|
||
//
|
||
// Check that the client Id is valid.
|
||
//
|
||
|
||
LfsValidateClientId( Lfcb, Lch );
|
||
|
||
//
|
||
// Write the log record.
|
||
//
|
||
|
||
LogFileFull = LfsWriteLogRecordIntoLogPage( Lfcb,
|
||
Lch,
|
||
NumberOfWriteEntries,
|
||
WriteEntries,
|
||
RecordType,
|
||
TransactionId,
|
||
UndoNextLsn,
|
||
PreviousLsn,
|
||
UndoRequirement,
|
||
FALSE,
|
||
Lsn );
|
||
|
||
} finally {
|
||
|
||
DebugUnwind( LfsWrite );
|
||
|
||
//
|
||
// Release the log file control block if held.
|
||
//
|
||
|
||
LfsReleaseLch( Lch );
|
||
|
||
DebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn->LowPart );
|
||
DebugTrace( 0, Dbg, "Lsn (High) -> %08lx\n", Lsn->HighPart );
|
||
DebugTrace( -1, Dbg, "LfsWrite: Exit\n", 0 );
|
||
}
|
||
|
||
} except (LfsExceptionFilter( GetExceptionInformation() )) {
|
||
|
||
Status = GetExceptionCode();
|
||
}
|
||
|
||
if (Status != STATUS_SUCCESS) {
|
||
|
||
ExRaiseStatus( Status );
|
||
}
|
||
|
||
return LogFileFull;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
LfsForceWrite (
|
||
IN LFS_LOG_HANDLE LogHandle,
|
||
IN ULONG NumberOfWriteEntries,
|
||
IN PLFS_WRITE_ENTRY WriteEntries,
|
||
IN LFS_RECORD_TYPE RecordType,
|
||
IN TRANSACTION_ID *TransactionId,
|
||
IN LSN UndoNextLsn,
|
||
IN LSN PreviousLsn,
|
||
IN LONG UndoRequirement,
|
||
OUT PLSN Lsn
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called by a client to write a log record to the log file.
|
||
This is idendical to LfsWrite except that on return the log record is
|
||
guaranteed to be on disk.
|
||
|
||
Arguments:
|
||
|
||
LogHandle - Pointer to private Lfs structure used to identify this
|
||
client.
|
||
|
||
NumberOfWriteEntries - Number of components of the log record.
|
||
|
||
WriteEntries - Pointer to an array of write entries.
|
||
|
||
RecordType - Lfs defined type for this log record.
|
||
|
||
TransactionId - Id value used to group log records by complete transaction.
|
||
|
||
UndoNextLsn - Lsn of a previous log record which needs to be undone in
|
||
the event of a client restart.
|
||
|
||
PreviousLsn - Lsn of the immediately previous log record for this client.
|
||
|
||
Lsn - Lsn to be associated with this log record.
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - Advisory, TRUE indicates that less than 1/4 of the log file is
|
||
available.
|
||
|
||
--*/
|
||
|
||
{
|
||
volatile NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
PLCH Lch;
|
||
|
||
PLFCB Lfcb;
|
||
BOOLEAN LogFileFull = FALSE;
|
||
|
||
PAGED_CODE();
|
||
|
||
DebugTrace( +1, Dbg, "LfsForceWrite: Entered\n", 0 );
|
||
DebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle );
|
||
DebugTrace( 0, Dbg, "NumberOfWriteEntries -> %08lx\n", NumberOfWriteEntries );
|
||
DebugTrace( 0, Dbg, "WriteEntries -> %08lx\n", WriteEntries );
|
||
DebugTrace( 0, Dbg, "Record Type -> %08lx\n", RecordType );
|
||
DebugTrace( 0, Dbg, "Transaction Id -> %08lx\n", TransactionId );
|
||
DebugTrace( 0, Dbg, "UndoNextLsn (Low) -> %08lx\n", UndoNextLsn.LowPart );
|
||
DebugTrace( 0, Dbg, "UndoNextLsn (High) -> %08lx\n", UndoNextLsn.HighPart );
|
||
DebugTrace( 0, Dbg, "PreviousLsn (Low) -> %08lx\n", PreviousLsn.LowPart );
|
||
DebugTrace( 0, Dbg, "PreviousLsn (High) -> %08lx\n", PreviousLsn.HighPart );
|
||
|
||
Lch = (PLCH) LogHandle;
|
||
|
||
//
|
||
// Check that the structure is a valid log handle structure.
|
||
//
|
||
|
||
LfsValidateLch( Lch );
|
||
|
||
//
|
||
// Use a try-except to catch errors.
|
||
//
|
||
|
||
try {
|
||
|
||
//
|
||
// Use a try-finally to facilitate cleanup.
|
||
//
|
||
|
||
try {
|
||
|
||
//
|
||
// Acquire the log file control block for this log file.
|
||
//
|
||
|
||
LfsAcquireLch( Lch );
|
||
Lfcb = Lch->Lfcb;
|
||
|
||
//
|
||
// If the Log file has been closed then refuse access.
|
||
//
|
||
|
||
if (Lfcb == NULL) {
|
||
|
||
ExRaiseStatus( STATUS_ACCESS_DENIED );
|
||
}
|
||
|
||
//
|
||
// Check that the client Id is valid.
|
||
//
|
||
|
||
LfsValidateClientId( Lfcb, Lch );
|
||
|
||
//
|
||
// Write the log record.
|
||
//
|
||
|
||
LogFileFull = LfsWriteLogRecordIntoLogPage( Lfcb,
|
||
Lch,
|
||
NumberOfWriteEntries,
|
||
WriteEntries,
|
||
RecordType,
|
||
TransactionId,
|
||
UndoNextLsn,
|
||
PreviousLsn,
|
||
UndoRequirement,
|
||
TRUE,
|
||
Lsn );
|
||
|
||
//
|
||
// The call to add this lbcb to the workque is guaranteed to release
|
||
// the Lfcb if this thread may do the Io.
|
||
//
|
||
|
||
LfsFlushToLsnPriv( Lfcb, *Lsn );
|
||
|
||
} finally {
|
||
|
||
DebugUnwind( LfsForceWrite );
|
||
|
||
//
|
||
// Release the log file control block if held.
|
||
//
|
||
|
||
LfsReleaseLch( Lch );
|
||
|
||
DebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn->LowPart );
|
||
DebugTrace( 0, Dbg, "Lsn (High) -> %08lx\n", Lsn->HighPart );
|
||
DebugTrace( -1, Dbg, "LfsForceWrite: Exit\n", 0 );
|
||
}
|
||
|
||
} except (LfsExceptionFilter( GetExceptionInformation() )) {
|
||
|
||
Status = GetExceptionCode();
|
||
}
|
||
|
||
if (Status != STATUS_SUCCESS) {
|
||
|
||
ExRaiseStatus( Status );
|
||
}
|
||
|
||
return LogFileFull;
|
||
}
|
||
|
||
|
||
VOID
|
||
LfsFlushToLsn (
|
||
IN LFS_LOG_HANDLE LogHandle,
|
||
IN LSN Lsn
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called by a client to insure that all log records
|
||
to a certain point have been flushed to the file. This is done by
|
||
checking if the desired Lsn has even been written at all. If so we
|
||
check if it has been flushed to the file. If not, we simply write
|
||
the current restart area to the disk.
|
||
|
||
Arguments:
|
||
|
||
LogHandle - Pointer to private Lfs structure used to identify this
|
||
client.
|
||
|
||
Lsn - This is the Lsn that must be on the disk on return from this
|
||
routine.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
volatile NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
PLCH Lch;
|
||
|
||
PLFCB Lfcb;
|
||
|
||
PAGED_CODE();
|
||
|
||
DebugTrace( +1, Dbg, "LfsFlushToLsn: Entered\n", 0 );
|
||
DebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle );
|
||
DebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn.LowPart );
|
||
DebugTrace( 0, Dbg, "Lsn (High) -> %08lx\n", Lsn.HighPart );
|
||
|
||
Lch = (PLCH) LogHandle;
|
||
|
||
//
|
||
// Check that the structure is a valid log handle structure.
|
||
//
|
||
|
||
LfsValidateLch( Lch );
|
||
|
||
//
|
||
// Use a try-except to catch errors.
|
||
//
|
||
|
||
try {
|
||
|
||
//
|
||
// Use a try-finally to facilitate cleanup.
|
||
//
|
||
|
||
try {
|
||
|
||
//
|
||
// Acquire the log file control block for this log file.
|
||
//
|
||
|
||
LfsAcquireLch( Lch );
|
||
Lfcb = Lch->Lfcb;
|
||
|
||
//
|
||
// If the log file has been closed we will assume the Lsn has been flushed.
|
||
//
|
||
|
||
if (Lfcb != NULL) {
|
||
|
||
//
|
||
// Check that the client Id is valid.
|
||
//
|
||
|
||
LfsValidateClientId( Lfcb, Lch );
|
||
|
||
//
|
||
// Call our common routine to perform the work.
|
||
//
|
||
|
||
LfsFlushToLsnPriv( Lfcb, Lsn );
|
||
}
|
||
|
||
} finally {
|
||
|
||
DebugUnwind( LfsFlushToLsn );
|
||
|
||
//
|
||
// Release the log file control block if held.
|
||
//
|
||
|
||
LfsReleaseLch( Lch );
|
||
|
||
DebugTrace( -1, Dbg, "LfsFlushToLsn: Exit\n", 0 );
|
||
}
|
||
|
||
} except (LfsExceptionFilter( GetExceptionInformation() )) {
|
||
|
||
Status = GetExceptionCode();
|
||
}
|
||
|
||
if (Status != STATUS_SUCCESS) {
|
||
|
||
ExRaiseStatus( Status );
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
|