/*++ BUILD Version: 0000    // Increment this if a change has global effects

Copyright (c) Microsoft Corporation. All rights reserved. 

You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.


Module Name:

    Lfs.h

Abstract:

    This module contains the public data structures and procedure
    prototypes for the Log File Service.

--*/

#ifndef _LFS_
#define _LFS_

//
// The Multi-Sector Header and Update Sequence Array provide detection of
// incomplete multi-sector transfers for devices which either have a
// physical sector size equal to the Sequence Number Stride or greater, or
// which do not transfer sectors out of order.  If a device exists which has
// a sector size smaller than the Sequence Number Stride *and* it sometimes
// transfers sectors out of order, then the Update Sequence Array will not
// provide absolute detection of incomplete transfers.  The Sequence Number
// Stride is set to a small enough number to provide absolute protection for
// all known hard disks.  It is not set any smaller, in order to avoid
// excessive run time and space overhead.
//
// The Multi-Sector Header contains space for a four-byte signature for the
// convenience of its user.  It then provides the offset to and length of the
// the Update Sequence Array.  The Update Sequence Array consists of an array
// of n saved USHORTs, where n is the size of the structure being protected
// divided by the sequence number stride.  (The size of structure being
// protected must be a nonzero power of 2 times the Sequence Number Stride,
// and less than or equal to the physical page size of the machine.)  The
// first word of the Update Sequence Array contains the Update Sequence Number,
// which is a cyclical counter (however 0 is not used) of the number of times
// the containing structure has been written to disk.  Following the Update
// Sequence Number are the n saved USHORTs which were overwritten by the
// Update Sequence Number the last time the containing structure was
// written to disk.
//
// In detail, just prior to each time the protected structure is written to
// disk, the last word in each Sequence Number Stride is saved to its
// respective position in the Sequence Number Array, and then it is overwritten
// with the next Update Sequence Number.  Just after this write, or whenever
// reading the structure, the saved word from the Sequence Number Array is
// restored to its actual position in the structure.  Before restoring the
// saved words on reads, all of the sequence numbers at the end of each
// stride are compared with the actual sequence number at the start of the
// array.  If any of these compares come up not equal, then a failed
// multi-sector transfer has been detected.
//
// The size of the array is determined by the size of the containing structure.
// As a C detail, the array is declared here with a size of 1, since its
// actual size can only be determined at runtime.
//
// The Update Sequence Array should be included at the end of the header of
// the structure it is protecting, since it is variable size.  Its user must
// ensure that the correct size is reserved for it, namely:
//
//      (sizeof-structure / SEQUENCE_NUMBER_STRIDE + 1) * sizeof(USHORT)
//

#define SEQUENCE_NUMBER_STRIDE           (512)

typedef USHORT UPDATE_SEQUENCE_NUMBER, *PUPDATE_SEQUENCE_NUMBER;

//
// This structure must be allocated at the start of the structure being
// protected.
//

#if !defined( _AUTOCHECK_ )

typedef struct _MULTI_SECTOR_HEADER {

    //
    // Space for a four-character signature
    //

    UCHAR Signature[4];

    //
    // Offset to Update Sequence Array, from start of structure.  The Update
    // Sequence Array must end before the last USHORT in the first "sector"
    // of size SEQUENCE_NUMBER_STRIDE.  (I.e., with the current constants,
    // the sum of the next two fields must be <= 510.)
    //

    USHORT UpdateSequenceArrayOffset;

    //
    // Size of Update Sequence Array (from above formula)
    //

    USHORT UpdateSequenceArraySize;

} MULTI_SECTOR_HEADER, *PMULTI_SECTOR_HEADER;

#endif

//
// This array must be present at the offset described above.
//

typedef UPDATE_SEQUENCE_NUMBER UPDATE_SEQUENCE_ARRAY[1];

typedef UPDATE_SEQUENCE_ARRAY *PUPDATE_SEQUENCE_ARRAY;

//
//  The following structure is allocated in the file system's Vcb and
//  its address is passed to Lfs during log file initialization.  It
//  contains the offset of the current write as well as the system
//  page size being used by Lfs.
//

typedef struct _LFS_WRITE_DATA {

    LONGLONG FileOffset;
    ULONG Length;
    ULONG LfsStructureSize;
    PVOID Lfcb;

} LFS_WRITE_DATA, *PLFS_WRITE_DATA;

//
//  The following structure is used to identify a log record by a log
//  sequence number.
//

typedef LARGE_INTEGER LSN, *PLSN;

//
//  The following Lsn will never occur in a file, it is used to indicate
//  a non-lsn.
//

extern LSN LfsZeroLsn;

//
//  We set the default page size to 4K
//

#define LFS_DEFAULT_LOG_PAGE_SIZE           (0x1000)

//
//  The following type defines the different log record types.
//

typedef enum _LFS_RECORD_TYPE {

    LfsClientRecord = 1,
    LfsClientRestart

} LFS_RECORD_TYPE, *PLFS_RECORD_TYPE;

//
//  The following search modes are supported.
//

typedef enum _LFS_CONTEXT_MODE {

    LfsContextUndoNext = 1,
    LfsContextPrevious,
    LfsContextForward

} LFS_CONTEXT_MODE, *PLFS_CONTEXT_MODE;

typedef ULONG TRANSACTION_ID, *PTRANSACTION_ID;

typedef enum _TRANSACTION_STATE {

    TransactionUninitialized = 0,
    TransactionActive,
    TransactionPrepared,
    TransactionCommitted

} TRANSACTION_STATE, *PTRANSACTION_STATE;

//
//  Information conduit back and forth between
//  LFS and its client.
//

typedef enum _LFS_CLIENT_INFO {

    LfsUseUsa = 1,
    LfsPackLog,
    LfsFixedPageSize

} LFS_CLIENT_INFO;

typedef struct _LFS_INFO {

    LOGICAL ReadOnly;
    LOGICAL InRestart;
    LOGICAL BadRestart;
    LFS_CLIENT_INFO LfsClientInfo;

} LFS_INFO, *PLFS_INFO;

typedef PVOID LFS_LOG_HANDLE, *PLFS_LOG_HANDLE;

typedef PVOID LFS_LOG_CONTEXT, *PLFS_LOG_CONTEXT;

//
//  Write Entry for LfsWrite and LfsForceWrite.  The interface to these
//  routines takes a pointer to a Write Entry along with a count of how
//  many Write Entries to expect to describe pieces of the caller's buffer
//  which are supposed to be copied in sequence to the log file.
//

typedef struct _LFS_WRITE_ENTRY {

    PVOID Buffer;
    ULONG ByteLength;

} LFS_WRITE_ENTRY, *PLFS_WRITE_ENTRY;


//
// Global Maintenance routines
//

BOOLEAN
LfsInitializeLogFileService (
    VOID
    );

//
//  Log File Registration routines
//

typedef struct _LOG_FILE_INFORMATION {

    //
    //  This is the total useable space in the log file after space for
    //  headers and Lfs Restart Areas.
    //

    LONGLONG TotalAvailable;

    //
    //  This is the useable space in the log file from the current position
    //  in the log file to the lowest BaseLsn.  This total as returned is not
    //  yet reduced for undo commitments, returned separately below.
    //

    LONGLONG CurrentAvailable;

    //
    //  This is the total undo commitment for all clients of the log file.
    //  LfsWrite requests are refused when the sum of the write size of the
    //  request plus the UndoRequirement for the request plus the TotalUndoCommitment
    //  are greater than the CurrentAvailable.
    //

    LONGLONG TotalUndoCommitment;

    //
    //  This is the total undo commitment for this client.
    //

    LONGLONG ClientUndoCommitment;

    //
    //  Current system Lsn's.  Includes the Oldest, LastFlushed and current
    //  Lsn.
    //

    LSN OldestLsn;
    LSN LastFlushedLsn;
    LSN LastLsn;

} LOG_FILE_INFORMATION, *PLOG_FILE_INFORMATION;

VOID
LfsInitializeLogFile (
    IN PFILE_OBJECT LogFile,
    IN USHORT MaximumClients,
    IN ULONG LogPageSize OPTIONAL,
    IN LONGLONG FileSize,
    OUT PLFS_WRITE_DATA WriteData
    );

ULONG
LfsOpenLogFile (
    IN PFILE_OBJECT LogFile,
    IN UNICODE_STRING ClientName,
    IN USHORT MaximumClients,
    IN ULONG LogPageSize OPTIONAL,
    IN LONGLONG FileSize,
    IN OUT PLFS_INFO LfsInfo,
    OUT PLFS_LOG_HANDLE LogHandle,
    OUT PLFS_WRITE_DATA WriteData
    );

VOID
LfsCloseLogFile (
    IN LFS_LOG_HANDLE LogHandle
    );

VOID
LfsDeleteLogHandle (
    IN LFS_LOG_HANDLE LogHandle
    );

VOID
LfsReadLogFileInformation (
    IN LFS_LOG_HANDLE LogHandle,
    IN PLOG_FILE_INFORMATION Buffer,
    IN OUT PULONG Length
    );

BOOLEAN
LfsVerifyLogFile (
    IN LFS_LOG_HANDLE LogHandle,
    IN PVOID LogFileHeader,
    IN ULONG Length
    );

//
//  Log File Client Restart routines
//

NTSTATUS
LfsReadRestartArea (
    IN LFS_LOG_HANDLE LogHandle,
    IN OUT PULONG BufferLength,
    IN PVOID Buffer,
    OUT PLSN Lsn
    );

VOID
LfsWriteRestartArea (
    IN LFS_LOG_HANDLE LogHandle,
    IN ULONG BufferLength,
    IN PVOID Buffer,
    IN LOGICAL CleanShutdown,
    OUT PLSN Lsn
    );

VOID
LfsSetBaseLsn (
    IN LFS_LOG_HANDLE LogHandle,
    IN LSN BaseLsn
    );

//
//  If ResetTotal is positive, then NumberRecords and ResetTotal set the absolute
//  values for the client.  If ResetTotal is negative, then they are adjustments
//  to the totals for this client.
//

VOID
LfsResetUndoTotal (
    IN LFS_LOG_HANDLE LogHandle,
    IN ULONG NumberRecords,
    IN LONG ResetTotal
    );

//
//  Log File Write routines
//

VOID
LfsGetActiveLsnRange (
    IN LFS_LOG_HANDLE LogHandle,
    OUT PLSN OldestLsn,
    OUT PLSN NextLsn
    );

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,
    IN ULONG Flags,
    OUT PLSN Lsn
    );

#define LFS_WRITE_FLAG_WRITE_AT_FRONT 1

BOOLEAN
LfsForceWrite (
    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
    );

VOID
LfsFlushToLsn (
    IN LFS_LOG_HANDLE LogHandle,
    IN LSN Lsn
    );

VOID
LfsCheckWriteRange (
    IN PLFS_WRITE_DATA WriteData,
    IN OUT PLONGLONG FlushOffset,
    IN OUT PULONG FlushLength
    );

//
//  Log File Query Record routines
//

VOID
LfsReadLogRecord (
    IN LFS_LOG_HANDLE LogHandle,
    IN LSN FirstLsn,
    IN LFS_CONTEXT_MODE ContextMode,
    OUT PLFS_LOG_CONTEXT Context,
    OUT PLFS_RECORD_TYPE RecordType,
    OUT TRANSACTION_ID *TransactionId,
    OUT PLSN UndoNextLsn,
    OUT PLSN PreviousLsn,
    OUT PULONG BufferLength,
    OUT PVOID *Buffer
    );

BOOLEAN
LfsReadNextLogRecord (
    IN LFS_LOG_HANDLE LogHandle,
    IN OUT LFS_LOG_CONTEXT Context,
    OUT PLFS_RECORD_TYPE RecordType,
    OUT TRANSACTION_ID *TransactionId,
    OUT PLSN UndoNextLsn,
    OUT PLSN PreviousLsn,
    OUT PLSN Lsn,
    OUT PULONG BufferLength,
    OUT PVOID *Buffer
    );

VOID
LfsTerminateLogQuery (
    IN LFS_LOG_HANDLE LogHandle,
    IN LFS_LOG_CONTEXT Context
    );

LSN
LfsQueryLastLsn (
    IN LFS_LOG_HANDLE LogHandle
    );

#endif  // LFS

