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

Copyright (c) 1989  Microsoft Corporation

Module Name:

    LfsStruc.h

Abstract:

    This module defines the data structures that make up the major internal
    part of the Log File Service.

Author:

    Brian Andrew    [BrianAn]   13-June-1991

Revision History:

--*/

#ifndef _LFSSTRUC_
#define _LFSSTRUC_

typedef PVOID PBCB;     //**** Bcb's are now part of the cache module


//
//  Log Enumeration Block.  A pointer to this structure is returned to the user
//  when a client is reading a particular set of log records from the log
//  file.
//

typedef struct _LEB {

    //
    //  The type and size of this record (must be LFS_NTC_LEB)
    //

    NODE_TYPE_CODE NodeTypeCode;
    NODE_BYTE_SIZE NodeByteSize;

    //
    //  Log record header.  This is the mapped log record header and bcb
    //  for the record header of the current Lsn.
    //

    struct _LFS_RECORD_HEADER *RecordHeader;
    PBCB RecordHeaderBcb;

    //
    //  Context Mode.  This is the mode governing the log record lookup.  We
    //  can look backwards via the ClientUndoNextLsn or ClientPreviousLsn.
    //  We can also look forwards by walking through all the log records and
    //  comparing ClientId fields.
    //

    LFS_CONTEXT_MODE ContextMode;

    //
    //  Client Id.  This is the client ID for the log records being returned.
    //

    LFS_CLIENT_ID ClientId;

    //
    //  Log record pointer.  This is the address returned to the user as the
    //  log record referred to by CurrentLsn.  If we allocated a buffer to
    //  hold the record, we need to deallocate it as necessary.
    //
    //  This field is either the actual mapped log record or a pointer to
    //  an auxilary buffer allocated by the Lfs.
    //

    PVOID CurrentLogRecord;
    BOOLEAN AuxilaryBuffer;

} LEB, *PLEB;


//
//  Lfcb synchronization.  This is the synchronization structure used by the Lfcb.
//

typedef struct _LFCB_SYNC {

    //
    //  Principal Lfcb Resource.
    //

    ERESOURCE Resource;

    //
    //  Notification Event.  This event is set to the Signalled state when
    //  pages are flushed to the cache file.  Any waiters will then check
    //  to see if the Lsn they're waiting for made it to disk.
    //

    KEVENT Event;

    //
    //  User Count.  Number of clients using this structure.  We will deallocate
    //  when all clients are gone.
    //

    ULONG UserCount;

    //
    //  Mutant to guard Leb spare list
    //

    FAST_MUTEX SpareListMutex;

} LFCB_SYNC, *PLFCB_SYNC;


//
//  Log Client Structure.  The Lfs allocates one of these for each active
//  client.  The address of this structure will be returned to the user
//  as a log handle.
//

typedef struct _LCH {

    //
    //  The type and size of this record (must be LFS_NTC_LCH)
    //

    NODE_TYPE_CODE NodeTypeCode;
    NODE_BYTE_SIZE NodeByteSize;

    //
    //  Links for all the client handles on an Lfcb.
    //

    LIST_ENTRY LchLinks;

    //
    //  Log File Control Block.  This is the log file for this log handle.
    //

    struct _LFCB *Lfcb;

    //
    //  Client Id.  This refers to the client record for this client in the
    //  Lfs restart area.
    //

    LFS_CLIENT_ID ClientId;

    //
    //  The following is the number of bytes this client has asked to
    //  have reserved in the log file.  It includes the space
    //  for the log record headers.
    //

    LONGLONG ClientUndoCommitment;

    //
    //  Byte offset in the client array.
    //

    ULONG ClientArrayByteOffset;

    //
    //  Pointer to the resource in the Lfcb.  We access the resource with
    //  this pointer for the times when the lfcb has been deleted.
    //

    PLFCB_SYNC Sync;

} LCH, *PLCH;


//
//  Log Buffer Control Block.  A buffer control block is associated with
//  each of the log buffers.  They are used to serialize access to the
//  log file.
//

typedef struct _LBCB {

    //
    //  The type and size of this record (must be LFS_NTC_LBCB)
    //

    NODE_TYPE_CODE NodeTypeCode;
    NODE_BYTE_SIZE NodeByteSize;

    //
    //  Buffer Block Links.  These fields are used to link the buffer blocks
    //  together.
    //

    LIST_ENTRY WorkqueLinks;
    LIST_ENTRY ActiveLinks;

    //
    //  Log file position and length.  This is the location in the log file to write
    //  out this buffer.
    //

    LONGLONG FileOffset;
    LONGLONG Length;

    //
    //  Sequence number.  This is the sequence number for log records which
    //  begin on this page.
    //

    LONGLONG SeqNumber;

    //
    //  Next Offset.  This is the next offset to write a log record in the
    //  this log page.  Stored as a large integer to facilitate large
    //  integer operations.
    //

    LONGLONG BufferOffset;

    //
    //  Buffer.  This field points to the buffer containing the log page
    //  for this block.  For a log record page this is a pointer to
    //  a pinned cache buffer, for a log restart page, this is a pointer
    //  to an auxilary buffer.
    //

    PVOID PageHeader;

    //
    //  Bcb for Log Page Block.  This is the Bcb for the pinned data.
    //  If this buffer block describes an Lfs restart area, this field is NULL.
    //

    PBCB LogPageBcb;

    //
    //  Last Lsn.  This is the Lsn for the last log record on this page.  We delay
    //  writing it until the page is flushed, storing it here instead.
    //

    LSN LastLsn;

    //
    //  Last complete Lsn.  This is the Lsn for the last log record which ends
    //  on this page.
    //

    LSN LastEndLsn;

    //
    //  Page Flags.  These are the flags associated with this log page.
    //  We store them in the Lbcb until the page is written.  They flags
    //  to use are the same as in the log record page header.
    //
    //      LOG_PAGE_LOG_RECORD_END     -   Page contains the end of a log record
    //      LOG_PAGE_PACKED             -   Page contains packed log records
    //      LOG_PAGE_TAIL_COPY          -   Page is a copy of the log file end
    //

    ULONG Flags;

    //
    //  Lbcb flags.  These are flags used to describe this Lbcb.
    //
    //      LBCB_LOG_WRAPPED            -   Lbcb has wrapped the log file
    //      LBCB_ON_ACTIVE_QUEUE        -   Lbcb is on the active queue
    //      LBCB_NOT_EMPTY              -   Page has existing log record
    //      LBCB_FLUSH_COPY             -   Write copy of this page first
    //      LBCB_RESTART_LBCB           -   This Lbcb contains a restart page
    //

    ULONG LbcbFlags;

    //
    //  This is the thread which has locked the log page.
    //

    ERESOURCE_THREAD ResourceThread;

} LBCB, *PLBCB;

#define LBCB_LOG_WRAPPED                        (0x00000001)
#define LBCB_ON_ACTIVE_QUEUE                    (0x00000002)
#define LBCB_NOT_EMPTY                          (0x00000004)
#define LBCB_FLUSH_COPY                         (0x00000008)
#define LBCB_RESTART_LBCB                       (0x00000020)


//
//  Log file data.  This data structure is used on a per-log file basis.
//

typedef enum _LFS_IO_STATE {

    LfsNoIoInProgress = 0,
    LfsClientThreadIo

} LFS_IO_STATE;

typedef struct _LFCB {

    //
    //  The type and size of this record (must be LFS_NTC_LFCB)
    //

    NODE_TYPE_CODE NodeTypeCode;
    NODE_BYTE_SIZE NodeByteSize;

    //
    //  Lfcb Links.  The following links the file control blocks to the
    //  global data structure.
    //

    LIST_ENTRY LfcbLinks;

    //
    //  Lch Links.  The following links all of the handles for the Lfcb.
    //

    LIST_ENTRY LchLinks;

    //
    //
    //  File Object.  This is the file object for the log file.
    //

    PFILE_OBJECT FileObject;

    //
    //  Log File Size.  This is the size of the log file.
    //  The second value is the size proposed by this open.
    //

    LONGLONG FileSize;

    //
    //  Log page size, masks and shift count to do multiplication and division
    //  of log pages.
    //

    LONGLONG  LogPageSize;
    ULONG LogPageMask;
    LONG LogPageInverseMask;
    ULONG LogPageShift;

    //
    //  First log page.  This is the offset in the file of the first
    //  log page with log records.
    //

    LONGLONG FirstLogPage;

    //
    //  Next log page offset.  This is the offset of the next log page to use.
    //  If we are reusing this page we store the offset to begin with.
    //

    LONGLONG NextLogPage;
    ULONG ReusePageOffset;

    //
    //  Data Offset.  This is the offset within a log page of the data that
    //  appears on that page.  This will be the actual restart data for
    //  an Lfs restart page, or the beginning of log record data for a log
    //  record page.
    //

    ULONG RestartDataOffset;
    LONGLONG LogPageDataOffset;

    //
    //  Data Size.  This is the amount of data that may be stored on a
    //  log page.  It is included here because it is frequently used.  It
    //  is simply the log page size minus the data offset.
    //

    ULONG RestartDataSize;
    LONGLONG LogPageDataSize;

    //
    //  Record header size.  This is the size to use for the record headers
    //  when reading the log file.
    //

    USHORT RecordHeaderLength;

    //
    //  Sequence number.  This is the number of times we have cycled through
    //  the log file.  The wrap sequence number is used to confirm that we
    //  have gone through the entire file at least once.  When we write a
    //  log record page for an Lsn with this sequence number, then we have
    //  cycled through the file.
    //

    LONGLONG SeqNumber;
    LONGLONG SeqNumberForWrap;
    ULONG SeqNumberBits;
    ULONG FileDataBits;

    //
    //  Buffer Block Links.  The following links the buffer blocks for this
    //  log file.
    //

    LIST_ENTRY LbcbWorkque;
    LIST_ENTRY LbcbActive;

    PLBCB ActiveTail;
    PLBCB PrevTail;

    //
    //  The enumerated type indicates if there is an active write for
    //  this log file and whether it is being done by an Lfs or
    //  client thread.
    //

    LFS_IO_STATE LfsIoState;

    //
    //  Current Restart Area.  The following is the in-memory image of the
    //  next restart area.  We also store a pointer to the client data
    //  array in the restart area.  The client array offset is from the start of
    //  the restart area.
    //

    PLFS_RESTART_AREA RestartArea;
    PLFS_CLIENT_RECORD ClientArray;
    USHORT ClientArrayOffset;
    USHORT ClientNameOffset;

    //
    //  Restart Area size.  This is the usable size of the restart area.
    //

    ULONG RestartAreaSize;
    USHORT LogClients;

    //
    //  Initial Restart area.  If true, then the in-memory restart area is to
    //  be written to the first position on the disk.
    //

    BOOLEAN InitialRestartArea;

    //
    //  The following pseudo Lsn's are used to track when restart areas
    //  are flushed to the disk.
    //

    LSN NextRestartLsn;
    LSN LastFlushedRestartLsn;

    //
    //  The following is the earliest Lsn we will guarantee is still in the
    //  log file.
    //

    LSN OldestLsn;

    //
    //  The following is the file offset of the oldest Lsn in the system.
    //  We redundantly store it in this form since we will be constantly
    //  checking if a new log record will write over part of the file
    //  we are trying to maintain.
    //

    LONGLONG OldestLsnOffset;

    //
    //  Last Flushed Lsn.  The following is the last Lsn guaranteed to
    //  be flushed to the disk.
    //

    LSN LastFlushedLsn;

    //
    //
    //  The following fields are used to track current usage in the log file.
    //
    //      TotalAvailable - is the total number of bytes available for
    //          log records.  It is the number of log pages times the
    //          data size of each page.
    //
    //      TotalAvailInPages - is the total number of bytes in the log
    //          pages for log records.  This is TotalAvailable without
    //          subtracting the size of the page headers.
    //
    //      TotalUndoCommitment - is the number of bytes reserved for
    //          possible abort operations.  This includes space for
    //          log record headers as well.
    //
    //      MaxCurrentAvail - is the maximum available in all pages
    //          subtracting the page header and any reserved tail.
    //
    //      CurrentAvailable - is the total number of bytes available in
    //          unused pages in the log file.
    //
    //      ReservedLogPageSize - is the number of bytes on a page available
    //          for reservation.
    //

    LONGLONG TotalAvailable;
    LONGLONG TotalAvailInPages;
    LONGLONG TotalUndoCommitment;
    LONGLONG MaxCurrentAvail;
    LONGLONG CurrentAvailable;

    LONGLONG ReservedLogPageSize;

    //
    //  The following fields are used to store information about the
    //  update sequence arrays.
    //

    USHORT RestartUsaOffset;
    USHORT UsaArraySize;

    USHORT LogRecordUsaOffset;

    //
    //  Major and minor version numbers.
    //

    SHORT MajorVersion;
    SHORT MinorVersion;

    //
    //  Log File Flags.
    //
    //      LFCB_LOG_WRAPPED        -   We found an Lbcb which wraps the log file
    //      LFCB_MULTIPLE_PAGE_IO   -   Write multiple pages if possible
    //      LFCB_NO_LAST_LSN        -   There are no log records to return
    //      LFCB_PACK_LOG           -   Pack the records into the pages
    //      LFCB_REUSE_TAIL         -   We will be reusing the tail of the log file after restart
    //      LFCB_NO_OLDEST_LSN      -   There is no oldest page being reserved
    //

    ULONG Flags;

    //
    //  The following are the spare Lbcb's for the volume and a field with
    //  the count for these.
    //

    ULONG SpareLbcbCount;
    LIST_ENTRY SpareLbcbList;

    //
    //  The following are sparse LEB's to be used rather than having to allocate
    //  then when reading log records
    //

    ULONG SpareLebCount;
    LIST_ENTRY SpareLebList;

    //
    //  The following structure synchronizes access to this structure.
    //

    PLFCB_SYNC Sync;

    //
    //  Count of waiters wanting access to flush the Lfcb.
    //

    ULONG Waiters;

    //
    //  On-disk value for OpenLogCount.  This is the value we will stuff into
    //  the client handles.
    //

    ULONG CurrentOpenLogCount;

    //
    //  Maintain the flush range for this file.
    //

    PLFS_WRITE_DATA UserWriteData;

    ERESOURCE_THREAD LfsIoThread;

    //
    //  Buffer and mdls which hold down the first 4 pages at the head of the log
    //  this includes the lfs restart areas and the ping pong pages. The partial mdl
    //  is used to pin pieces of the total buffer
    //

    PMDL LogHeadMdl;
    PMDL LogHeadPartialMdl;
    PVOID LogHeadBuffer;

    //
    //  preallocated error log packet for use logging errors to the eventlog
    //

    PIO_ERROR_LOG_PACKET ErrorLogPacket;

#ifdef LFS_CLUSTER_CHECK
    LSN LsnAtMount;
    ULONG LsnRangeIndex;
#endif

    //
    //  Embedded array with enough space for SYSTEM PAGE / LOG PAGE SIZE
    //  used to facilitate flushing partial system pages
    //

    PLBCB DirtyLbcb[0];

} LFCB, *PLFCB;

#define LFCB_LOG_WRAPPED                (0x00000001)
#define LFCB_MULTIPLE_PAGE_IO           (0x00000002)
#define LFCB_NO_LAST_LSN                (0x00000004)
#define LFCB_PACK_LOG                   (0x00000008)
#define LFCB_REUSE_TAIL                 (0x00000010)
#define LFCB_NO_OLDEST_LSN              (0x00000020)
#define LFCB_LOG_FILE_CORRUPT           (0x00000040)
#define LFCB_FINAL_SHUTDOWN             (0x00000080)
#define LFCB_READ_FIRST_RESTART         (0x00000100)
#define LFCB_READ_SECOND_RESTART        (0x00000200)
#define LFCB_READ_ONLY                  (0x00000400)

#ifdef LFS_CLUSTER_CHECK
#define LFCB_DEVICE_OFFLINE_SEEN        (0x80000000)
#define LFCB_FLUSH_FAILED               (0x40000000)
#endif

#define LFCB_RESERVE_LBCB_COUNT         (5)
#define LFCB_MAX_LBCB_COUNT             (25)

#define LFCB_RESERVE_LEB_COUNT          (5)
#define LFCB_MAX_LEB_COUNT              (25)


//
//  Global Log Data.  The following structure has only one instance and
//  maintains global information for the entire logging service.
//

typedef struct _LFS_DATA {

    //
    //  The type and size of this record (must be LFS_NTC_DATA)
    //

    NODE_TYPE_CODE NodeTypeCode;
    NODE_BYTE_SIZE NodeByteSize;

    //
    //  The following field links all of the Log File Control Blocks for
    //  the logging system.
    //

    LIST_ENTRY LfcbLinks;

    //
    //  Flag field.
    //

    ULONG Flags;

    //
    //  The following mutex controls access to this structure.
    //

    FAST_MUTEX LfsDataLock;

    //
    //  Allocated buffers for reading spanning log records in low memory case.
    //  Flags indicate which buffers owned.
    //      LFS_BUFFER1_OWNED
    //      LFS_BUFFER2_OWNED
    //

    PVOID Buffer1;
    PVOID Buffer2;
    ERESOURCE_THREAD BufferOwner;
    ULONG BufferFlags;

    FAST_MUTEX BufferLock;
    KEVENT BufferNotification;

} LFS_DATA, *PLFS_DATA;

#define LFS_DATA_INIT_FAILED                (0x00000001)
#define LFS_DATA_INITIALIZED                (0x00000002)

#define LFS_BUFFER1_OWNED                   (0x00000001)
#define LFS_BUFFER2_OWNED                   (0x00000002)

#define LFS_BUFFER_SIZE                     (0x10000)
#endif // _LFSSTRUC_

