/*
* 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/slabDepot.h#12 $
*/
#ifndef SLAB_DEPOT_H
#define SLAB_DEPOT_H
#include "buffer.h"
#include "adminState.h"
#include "completion.h"
#include "fixedLayout.h"
#include "journalPoint.h"
#include "statistics.h"
#include "types.h"
#include "waitQueue.h"
/**
* A SlabDepot is responsible for managing all of the slabs and block
* allocators of a VDO. It has a single array of slabs in order to eliminate
* the need for additional math in order to compute which physical zone a PBN
* is in. It also has a BlockAllocator per zone.
*
* Load operations are required to be performed on a single thread. Normal
* operations are assumed to be performed in the appropriate zone. Allocations
* and reference count updates must be done from the thread of their physical
* zone. Requests to commit slab journal tail blocks from the recovery journal
* must be done on the journal zone thread. Save operations are required to be
* launched from the same thread as the original load operation.
**/
typedef enum {
NORMAL_LOAD,
RECOVERY_LOAD,
REBUILD_LOAD
} SlabDepotLoadType;
/**
* Calculate the number of slabs a depot would have.
*
* @param depot The depot
*
* @return The number of slabs
**/
SlabCount calculateSlabCount(SlabDepot *depot)
__attribute__((warn_unused_result));
/**
* Create a slab depot.
*
* @param [in] blockCount The number of blocks initially available
* @param [in] firstBlock The number of the first block which may be
* allocated
* @param [in] slabConfig The slab configuration
* @param [in] threadConfig The thread configuration of the VDO
* @param [in] nonce The nonce of the VDO
* @param [in] vioPoolSize The size of the VIO pool
* @param [in] layer The physical layer below this depot
* @param [in] summaryPartition The partition which holds the slab summary
* @param [in] readOnlyNotifier The context for entering read-only mode
* @param [in] recoveryJournal The recovery journal of the VDO
* @param [out] depotPtr A pointer to hold the depot
*
* @return A success or error code
**/
int makeSlabDepot(BlockCount blockCount,
PhysicalBlockNumber firstBlock,
SlabConfig slabConfig,
const ThreadConfig *threadConfig,
Nonce nonce,
BlockCount vioPoolSize,
PhysicalLayer *layer,
Partition *summaryPartition,
ReadOnlyNotifier *readOnlyNotifier,
RecoveryJournal *recoveryJournal,
SlabDepot **depotPtr)
__attribute__((warn_unused_result));
/**
* Destroy a slab depot and null out the reference to it.
*
* @param depotPtr The reference to the depot to destroy
**/
void freeSlabDepot(SlabDepot **depotPtr);
/**
* Get the size of the encoded state of a slab depot.
*
* @return The encoded size of the depot's state
**/
size_t getSlabDepotEncodedSize(void)
__attribute__((warn_unused_result));
/**
* Encode the state of a slab depot into a buffer.
*
* @param depot The depot to encode
* @param buffer The buffer to encode into
*
* @return UDS_SUCCESS or an error
**/
int encodeSlabDepot(const SlabDepot *depot, Buffer *buffer)
__attribute__((warn_unused_result));
/**
* Decode the state of a slab depot saved in a buffer.
*
* @param [in] buffer The buffer containing the saved state
* @param [in] threadConfig The thread config of the VDO
* @param [in] nonce The nonce of the VDO
* @param [in] layer The physical layer below this depot
* @param [in] summaryPartition The partition which holds the slab summary
* @param [in] readOnlyNotifier The context for entering read-only mode
* @param [in] recoveryJournal The recovery journal of the VDO
* @param [out] depotPtr A pointer to hold the depot
*
* @return A success or error code
**/
int decodeSodiumSlabDepot(Buffer *buffer,
const ThreadConfig *threadConfig,
Nonce nonce,
PhysicalLayer *layer,
Partition *summaryPartition,
ReadOnlyNotifier *readOnlyNotifier,
RecoveryJournal *recoveryJournal,
SlabDepot **depotPtr)
__attribute__((warn_unused_result));
/**
* Decode the state of a slab depot saved in a buffer.
*
* @param [in] buffer The buffer containing the saved state
* @param [in] threadConfig The thread config of the VDO
* @param [in] nonce The nonce of the VDO
* @param [in] layer The physical layer below this depot
* @param [in] summaryPartition The partition which holds the slab summary
* @param [in] readOnlyNotifier The context for entering read-only mode
* @param [in] recoveryJournal The recovery journal of the VDO
* @param [out] depotPtr A pointer to hold the depot
*
* @return A success or error code
**/
int decodeSlabDepot(Buffer *buffer,
const ThreadConfig *threadConfig,
Nonce nonce,
PhysicalLayer *layer,
Partition *summaryPartition,
ReadOnlyNotifier *readOnlyNotifier,
RecoveryJournal *recoveryJournal,
SlabDepot **depotPtr)
__attribute__((warn_unused_result));
/**
* Allocate the RefCounts for all slabs in the depot. This method may be called
* only before entering normal operation from the load thread.
*
* @param depot The depot whose RefCounts need allocation
*
* @return VDO_SUCCESS or an error
**/
int allocateSlabRefCounts(SlabDepot *depot)
__attribute__((warn_unused_result));
/**
* Get the block allocator for a specified physical zone from a depot.
*
* @param depot The depot
* @param zoneNumber The physical zone
*
* @return The block allocator for the specified zone
**/
BlockAllocator *getBlockAllocatorForZone(SlabDepot *depot,
ZoneCount zoneNumber)
__attribute__((warn_unused_result));
/**
* Get the number of the slab that contains a specified block.
*
* @param depot The slab depot
* @param pbn The physical block number
* @param slabNumberPtr A pointer to hold the slab number
*
* @return VDO_SUCCESS or an error
**/
int getSlabNumber(const SlabDepot *depot,
PhysicalBlockNumber pbn,
SlabCount *slabNumberPtr)
__attribute__((warn_unused_result));
/**
* Get the slab object for the slab that contains a specified block. Will put
* the VDO in read-only mode if the PBN is not a valid data block nor the zero
* block.
*
* @param depot The slab depot
* @param pbn The physical block number
*
* @return The slab containing the block, or NULL if the block number is the
* zero block or otherwise out of range
**/
Slab *getSlab(const SlabDepot *depot, PhysicalBlockNumber pbn)
__attribute__((warn_unused_result));
/**
* Get the slab journal for the slab that contains a specified block.
*
* @param depot The slab depot
* @param pbn The physical block number within the block depot partition
* of any block in the slab
*
* @return The slab journal of the slab containing the block, or NULL if the
* block number is for the zero block or otherwise out of range
**/
SlabJournal *getSlabJournal(const SlabDepot *depot, PhysicalBlockNumber pbn)
__attribute__((warn_unused_result));
/**
* Determine how many new references a block can acquire. This method must be
* called from the the physical zone thread of the PBN.
*
* @param depot The slab depot
* @param pbn The physical block number that is being queried
*
* @return the number of available references
**/
uint8_t getIncrementLimit(SlabDepot *depot, PhysicalBlockNumber pbn)
__attribute__((warn_unused_result));
/**
* Determine whether the given PBN refers to a data block.
*
* @param depot The depot
* @param pbn The physical block number to ask about
*
* @return <code>True</code> if the PBN corresponds to a data block
**/
bool isPhysicalDataBlock(const SlabDepot *depot, PhysicalBlockNumber pbn)
__attribute__((warn_unused_result));
/**
* Get the total number of data blocks allocated across all the slabs in the
* depot, which is the total number of blocks with a non-zero reference count.
* This may be called from any thread.
*
* @param depot The slab depot
*
* @return The total number of blocks with a non-zero reference count
**/
BlockCount getDepotAllocatedBlocks(const SlabDepot *depot)
__attribute__((warn_unused_result));
/**
* Get the total of the statistics from all the block allocators in the depot.
*
* @param depot The slab depot
*
* @return The statistics from all block allocators in the depot
**/
BlockAllocatorStatistics
getDepotBlockAllocatorStatistics(const SlabDepot *depot)
__attribute__((warn_unused_result));
/**
* Get the total number of data blocks in all the slabs in the depot. This may
* be called from any thread.
*
* @param depot The slab depot
*
* @return The total number of data blocks in all slabs
**/
BlockCount getDepotDataBlocks(const SlabDepot *depot)
__attribute__((warn_unused_result));
/**
* Get the total number of free blocks remaining in all the slabs in the
* depot, which is the total number of blocks that have a zero reference
* count. This may be called from any thread.
*
* @param depot The slab depot
*
* @return The total number of blocks with a zero reference count
**/
BlockCount getDepotFreeBlocks(const SlabDepot *depot)
__attribute__((warn_unused_result));
/**
* Get the total number of slabs in the depot
*
* @param depot The slab depot
*
* @return The total number of slabs
**/
SlabCount getDepotSlabCount(const SlabDepot *depot)
__attribute__((warn_unused_result));
/**
* Get the total number of unrecovered slabs in the depot, which is the total
* number of unrecovered slabs from all zones. This may be called from any
* thread.
*
* @param depot The slab depot
*
* @return The total number of slabs that are unrecovered
**/
SlabCount getDepotUnrecoveredSlabCount(const SlabDepot *depot)
__attribute__((warn_unused_result));
/**
* Get the aggregated slab journal statistics for the depot.
*
* @param depot The slab depot
*
* @return The aggregated statistics for all slab journals in the depot
**/
SlabJournalStatistics getDepotSlabJournalStatistics(const SlabDepot *depot)
__attribute__((warn_unused_result));
/**
* Get the cumulative RefCounts statistics for the depot.
*
* @param depot The slab depot
*
* @return The cumulative statistics for all RefCounts in the depot
**/
RefCountsStatistics getDepotRefCountsStatistics(const SlabDepot *depot)
__attribute__((warn_unused_result));
/**
* Asynchronously load any slab depot state that isn't included in the
* SuperBlock component. This method may be called only before entering normal
* operation from the load thread.
*
* @param depot The depot to load
* @param operation The type of load to perform
* @param parent The completion to finish when the load is complete
* @param context Additional context for the load operation; may be NULL
**/
void loadSlabDepot(SlabDepot *depot,
AdminStateCode operation,
VDOCompletion *parent,
void *context);
/**
* Prepare the slab depot to come online and start allocating blocks. This
* method may be called only before entering normal operation from the load
* thread. It must be called before allocation may proceed.
*
* @param depot The depot to prepare
* @param loadType The load type
* @param parent The completion to finish when the operation is complete
**/
void prepareToAllocate(SlabDepot *depot,
SlabDepotLoadType loadType,
VDOCompletion *parent);
/**
* Update the slab depot to reflect its new size in memory. This size is saved
* to disk as part of the super block.
*
* @param depot The depot to update
**/
void updateSlabDepotSize(SlabDepot *depot);
/**
* Allocate new memory needed for a resize of a slab depot to the given size.
*
* @param depot The depot to prepare to resize
* @param newSize The number of blocks in the new depot
*
* @return VDO_SUCCESS or an error
**/
int prepareToGrowSlabDepot(SlabDepot *depot, BlockCount newSize)
__attribute__((warn_unused_result));
/**
* Use the new slabs allocated for resize.
*
* @param depot The depot
* @param parent The object to notify when complete
**/
void useNewSlabs(SlabDepot *depot, VDOCompletion *parent);
/**
* Abandon any new slabs in this depot, freeing them as needed.
*
* @param depot The depot
**/
void abandonNewSlabs(SlabDepot *depot);
/**
* Drain all slab depot I/O. If saving, or flushing, all dirty depot metadata
* will be written out. If saving or suspending, the depot will be left in a
* suspended state.
*
* @param depot The depot to drain
* @param operation The drain operation (flush, rebuild, suspend, or save)
* @param parent The completion to finish when the drain is complete
**/
void drainSlabDepot(SlabDepot *depot,
AdminStateCode operation,
VDOCompletion *parent);
/**
* Resume a suspended slab depot.
*
* @param depot The depot to resume
* @param parent The completion to finish when the depot has resumed
**/
void resumeSlabDepot(SlabDepot *depot, VDOCompletion *parent);
/**
* Commit all dirty tail blocks which are locking a given recovery journal
* block. This method must be called from the journal zone thread.
*
* @param depot The depot
* @param recoveryBlockNumber The sequence number of the recovery journal
* block whose locks should be released
**/
void commitOldestSlabJournalTailBlocks(SlabDepot *depot,
SequenceNumber recoveryBlockNumber);
/**
* Get the SlabConfig of a depot.
*
* @param depot The slab depot
*
* @return The slab configuration of the specified depot
**/
const SlabConfig *getSlabConfig(const SlabDepot *depot)
__attribute__((warn_unused_result));
/**
* Get the slab summary.
*
* @param depot The slab depot
*
* @return The slab summary
**/
SlabSummary *getSlabSummary(const SlabDepot *depot)
__attribute__((warn_unused_result));
/**
* Get the portion of the slab summary for a given physical zone.
*
* @param depot The slab depot
* @param zone The zone
*
* @return The portion of the slab summary for the specified zone
**/
SlabSummaryZone *getSlabSummaryForZone(const SlabDepot *depot, ZoneCount zone)
__attribute__((warn_unused_result));
/**
* Scrub all unrecovered slabs.
*
* @param depot The depot to scrub
* @param parent The object to notify when scrubbing is complete
* @param callback The function to call when scrubbing is complete
* @param errorHandler The handler for scrubbing errors
* @param threadID The thread on which to run the callback
* @param launchParent The object to notify when scrubbing has been launched
* for all zones
**/
void scrubAllUnrecoveredSlabs(SlabDepot *depot,
void *parent,
VDOAction *callback,
VDOAction *errorHandler,
ThreadID threadID,
VDOCompletion *launchParent);
/**
* Check whether there are outstanding unrecovered slabs.
*
* @param depot The slab depot
*
* @return Whether there are outstanding unrecovered slabs
**/
bool hasUnrecoveredSlabs(SlabDepot *depot);
/**
* Get the physical size to which this depot is prepared to grow.
*
* @param depot The slab depot
*
* @return The new number of blocks the depot will be grown to, or 0 if the
* depot is not prepared to grow
**/
BlockCount getNewDepotSize(const SlabDepot *depot)
__attribute__((warn_unused_result));
/**
* Dump the slab depot, in a thread-unsafe fashion.
*
* @param depot The slab depot
**/
void dumpSlabDepot(const SlabDepot *depot);
#endif // SLAB_DEPOT_H