/*
* Copyright (c) 2020 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/recoveryJournalBlock.h#8 $
*/
#ifndef RECOVERY_JOURNAL_BLOCK_H
#define RECOVERY_JOURNAL_BLOCK_H
#include "permassert.h"
#include "packedRecoveryJournalBlock.h"
#include "recoveryJournalInternals.h"
#include "ringNode.h"
#include "types.h"
#include "waitQueue.h"
struct recoveryJournalBlock {
/** The doubly linked pointers for the free or active lists */
RingNode ringNode;
/** The waiter for the pending full block list */
Waiter writeWaiter;
/** The journal to which this block belongs */
RecoveryJournal *journal;
/** A pointer to a block-sized buffer holding the packed block data */
char *block;
/** A pointer to the current sector in the packed block buffer */
PackedJournalSector *sector;
/** The VIO for writing this block */
VIO *vio;
/** The sequence number for this block */
SequenceNumber sequenceNumber;
/** The location of this block in the on-disk journal */
PhysicalBlockNumber blockNumber;
/** Whether this block is being committed */
bool committing;
/** Whether this block has an uncommitted increment for a partial write */
bool hasPartialWriteEntry;
/** Whether this block has an uncommitted increment for a write with FUA */
bool hasFUAEntry;
/** The total number of entries in this block */
JournalEntryCount entryCount;
/** The total number of uncommitted entries (queued or committing) */
JournalEntryCount uncommittedEntryCount;
/** The number of new entries in the current commit */
JournalEntryCount entriesInCommit;
/** The queue of VIOs which will make entries for the next commit */
WaitQueue entryWaiters;
/** The queue of VIOs waiting for the current commit */
WaitQueue commitWaiters;
};
/**
* Return the block associated with a ring node.
*
* @param node The ring node to recast as a block
*
* @return The block
**/
static inline RecoveryJournalBlock *blockFromRingNode(RingNode *node)
{
STATIC_ASSERT(offsetof(RecoveryJournalBlock, ringNode) == 0);
return (RecoveryJournalBlock *) node;
}
/**
* Return the block associated with a waiter
*
* @param waiter The waiter to recast as a block
*
* @return The block
**/
static inline RecoveryJournalBlock *blockFromWaiter(Waiter *waiter)
{
return (RecoveryJournalBlock *)
((uintptr_t) waiter - offsetof(RecoveryJournalBlock, writeWaiter));
}
/**
* Check whether a recovery block is dirty, indicating it has any uncommitted
* entries, which includes both entries not written and entries written but
* not yet acknowledged.
*
* @param block The block to check
*
* @return true
if the block has any uncommitted entries
**/
__attribute__((warn_unused_result))
static inline bool isRecoveryBlockDirty(const RecoveryJournalBlock *block)
{
return (block->uncommittedEntryCount > 0);
}
/**
* Check whether a journal block is empty.
*
* @param block The block to check
*
* @return true
if the block has no entries
**/
__attribute__((warn_unused_result))
static inline bool isRecoveryBlockEmpty(const RecoveryJournalBlock *block)
{
return (block->entryCount == 0);
}
/**
* Check whether a journal block is full.
*
* @param block The block to check
*
* @return true
if the the block is full
**/
__attribute__((warn_unused_result))
static inline bool isRecoveryBlockFull(const RecoveryJournalBlock *block)
{
return ((block == NULL)
|| (block->journal->entriesPerBlock == block->entryCount));
}
/**
* Construct a journal block.
*
* @param [in] layer The layer from which to construct VIOs
* @param [in] journal The journal to which the block will belong
* @param [out] blockPtr A pointer to receive the new block
*
* @return VDO_SUCCESS or an error
**/
int makeRecoveryBlock(PhysicalLayer *layer,
RecoveryJournal *journal,
RecoveryJournalBlock **blockPtr)
__attribute__((warn_unused_result));
/**
* Free a tail block and null out the reference to it.
*
* @param blockPtr The reference to the tail block to free
**/
void freeRecoveryBlock(RecoveryJournalBlock **blockPtr);
/**
* Initialize the next active recovery journal block.
*
* @param block The journal block to initialize
**/
void initializeRecoveryBlock(RecoveryJournalBlock *block);
/**
* Enqueue a DataVIO to asynchronously encode and commit its next recovery
* journal entry in this block. The DataVIO will not be continued until the
* entry is committed to the on-disk journal. The caller is responsible for
* ensuring the block is not already full.
*
* @param block The journal block in which to make an entry
* @param dataVIO The DataVIO to enqueue
*
* @return VDO_SUCCESS or an error code if the DataVIO could not be enqueued
**/
int enqueueRecoveryBlockEntry(RecoveryJournalBlock *block, DataVIO *dataVIO)
__attribute__((warn_unused_result));
/**
* Attempt to commit a block. If the block is not the oldest block with
* uncommitted entries or if it is already being committed, nothing will be
* done.
*
* @param block The block to write
* @param callback The function to call when the write completes
* @param errorHandler The handler for flush or write errors
*
* @return VDO_SUCCESS, or an error if the write could not be launched
**/
int commitRecoveryBlock(RecoveryJournalBlock *block,
VDOAction *callback,
VDOAction *errorHandler)
__attribute__((warn_unused_result));
/**
* Dump the contents of the recovery block to the log.
*
* @param block The block to dump
**/
void dumpRecoveryBlock(const RecoveryJournalBlock *block);
/**
* Check whether a journal block can be committed.
*
* @param block The journal block in question
*
* @return true
if the block can be committed now
**/
bool canCommitRecoveryBlock(RecoveryJournalBlock *block)
__attribute__((warn_unused_result));
#endif // RECOVERY_JOURNAL_BLOCK_H