/*
* 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/refCounts.h#7 $
*/
#ifndef REF_COUNTS_H
#define REF_COUNTS_H
#include "completion.h"
#include "journalPoint.h"
#include "slab.h"
#include "types.h"
/**
* Create a reference counting object.
*
* <p>A reference counting object can keep a reference count for every physical
* block in the VDO configuration. Since we expect the vast majority of the
* blocks to have 0 or 1 reference counts, the structure is optimized for that
* situation.
*
* @param [in] blockCount The number of physical blocks that can be
* referenced
* @param [in] slab The slab of the ref counts object
* @param [in] origin The layer PBN at which to save RefCounts
* @param [in] readOnlyNotifier The context for tracking read-only mode
* @param [out] refCountsPtr The pointer to hold the new ref counts object
*
* @return a success or error code
**/
int makeRefCounts(BlockCount blockCount,
Slab *slab,
PhysicalBlockNumber origin,
ReadOnlyNotifier *readOnlyNotifier,
RefCounts **refCountsPtr)
__attribute__((warn_unused_result));
/**
* Free a reference counting object and null out the reference to it.
*
* @param refCountsPtr The reference to the reference counting object to free
**/
void freeRefCounts(RefCounts **refCountsPtr);
/**
* Check whether a RefCounts is active.
*
* @param refCounts The RefCounts to check
**/
bool areRefCountsActive(RefCounts *refCounts)
__attribute__((warn_unused_result));
/**
* Get the stored count of the number of blocks that are currently free.
*
* @param refCounts The RefCounts object
*
* @return the number of blocks with a reference count of zero
**/
BlockCount getUnreferencedBlockCount(RefCounts *refCounts)
__attribute__((warn_unused_result));
/**
* Determine how many times a reference count can be incremented without
* overflowing.
*
* @param refCounts The RefCounts object
* @param pbn The physical block number
*
* @return the number of increments that can be performed
**/
uint8_t getAvailableReferences(RefCounts *refCounts, PhysicalBlockNumber pbn)
__attribute__((warn_unused_result));
/**
* Adjust the reference count of a block.
*
* @param [in] refCounts The refcounts object
* @param [in] operation The operation to perform
* @param [in] slabJournalPoint The slab journal entry for this adjustment
* @param [out] freeStatusChanged A pointer which will be set to true if the
* free status of the block changed
*
*
* @return A success or error code, specifically:
* VDO_REF_COUNT_INVALID if a decrement would result in a negative
* reference count, or an increment in a
* count greater than MAXIMUM_REFS
*
**/
int adjustReferenceCount(RefCounts *refCounts,
ReferenceOperation operation,
const JournalPoint *slabJournalPoint,
bool *freeStatusChanged)
__attribute__((warn_unused_result));
/**
* Adjust the reference count of a block during rebuild.
*
* @param refCounts The refcounts object
* @param pbn The number of the block to adjust
* @param operation The operation to perform on the count
*
* @return VDO_SUCCESS or an error
**/
int adjustReferenceCountForRebuild(RefCounts *refCounts,
PhysicalBlockNumber pbn,
JournalOperation operation)
__attribute__((warn_unused_result));
/**
* Replay the reference count adjustment from a slab journal entry into the
* reference count for a block. The adjustment will be ignored if it was already
* recorded in the reference count.
*
* @param refCounts The refcounts object
* @param entryPoint The slab journal point for the entry
* @param entry The slab journal entry being replayed
*
* @return VDO_SUCCESS or an error code
**/
int replayReferenceCountChange(RefCounts *refCounts,
const JournalPoint *entryPoint,
SlabJournalEntry entry)
__attribute__((warn_unused_result));
/**
* Check whether two reference counters are equivalent. This method is
* used for unit testing.
*
* @param counterA The first counter to compare
* @param counterB The second counter to compare
*
* @return <code>true</code> if the two counters are equivalent
**/
bool areEquivalentReferenceCounters(RefCounts *counterA, RefCounts *counterB)
__attribute__((warn_unused_result));
/**
* Find a block with a reference count of zero in the range of physical block
* numbers tracked by the reference counter. If a free block is found, that
* block is allocated by marking it as provisionally referenced, and the
* allocated block number is returned.
*
* @param [in] refCounts The reference counters to scan
* @param [out] allocatedPtr A pointer to hold the physical block number of
* the block that was found and allocated
*
* @return VDO_SUCCESS if a free block was found and allocated;
* VDO_NO_SPACE if there are no unreferenced blocks;
* otherwise an error code
**/
int allocateUnreferencedBlock(RefCounts *refCounts,
PhysicalBlockNumber *allocatedPtr)
__attribute__((warn_unused_result));
/**
* Provisionally reference a block if it is unreferenced.
*
* @param refCounts The reference counters
* @param pbn The PBN to reference
* @param lock The PBNLock on the block (may be NULL)
*
* @return VDO_SUCCESS or an error
**/
int provisionallyReferenceBlock(RefCounts *refCounts,
PhysicalBlockNumber pbn,
PBNLock *lock)
__attribute__((warn_unused_result));
/**
* Count all unreferenced blocks in a range [startBlock, endBlock) of physical
* block numbers.
*
* @param refCounts The reference counters to scan
* @param startPBN The physical block number at which to start
* scanning (included in the scan)
* @param endPBN The physical block number at which to stop
* scanning (excluded from the scan)
*
* @return The number of unreferenced blocks
**/
BlockCount countUnreferencedBlocks(RefCounts *refCounts,
PhysicalBlockNumber startPBN,
PhysicalBlockNumber endPBN)
__attribute__((warn_unused_result));
/**
* Get the number of blocks required to save a reference counts state covering
* the specified number of data blocks.
*
* @param blockCount The number of physical data blocks that can be referenced
*
* @return The number of blocks required to save reference counts with the
* given block count
**/
BlockCount getSavedReferenceCountSize(BlockCount blockCount)
__attribute__((warn_unused_result));
/**
* Request a RefCounts save several dirty blocks asynchronously. This function
* currently writes 1 / flushDivisor of the dirty blocks.
*
* @param refCounts The RefCounts object to notify
* @param flushDivisor The inverse fraction of the dirty blocks to write
**/
void saveSeveralReferenceBlocks(RefCounts *refCounts, size_t flushDivisor);
/**
* Ask a RefCounts to save all its dirty blocks asynchronously.
*
* @param refCounts The RefCounts object to notify
**/
void saveDirtyReferenceBlocks(RefCounts *refCounts);
/**
* Mark all reference count blocks as dirty.
*
* @param refCounts The RefCounts of the reference blocks
**/
void dirtyAllReferenceBlocks(RefCounts *refCounts);
/**
* Drain all reference count I/O. Depending upon the type of drain being
* performed (as recorded in the RefCount's Slab), the reference blocks may
* be loaded from disk or dirty reference blocks may be written out.
*
* @param refCounts The reference counts to drain
**/
void drainRefCounts(RefCounts *refCounts);
/**
* Mark all reference count blocks dirty and cause them to hold locks on slab
* journal block 1.
*
* @param refCounts The RefCounts of the reference blocks
**/
void acquireDirtyBlockLocks(RefCounts *refCounts);
/**
* Dump information about this RefCounts structure.
*
* @param refCounts The RefCounts to dump
**/
void dumpRefCounts(const RefCounts *refCounts);
#endif // REF_COUNTS_H