/*
* 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/blockAllocatorInternals.h#11 $
*/
#ifndef BLOCK_ALLOCATOR_INTERNALS_H
#define BLOCK_ALLOCATOR_INTERNALS_H
#include "adminState.h"
#include "atomic.h"
#include "blockAllocator.h"
#include "priorityTable.h"
#include "ringNode.h"
#include "slabScrubber.h"
#include "vioPool.h"
enum {
/*
* The number of VIOs in the VIO pool is proportional to the throughput of
* the VDO.
*/
VIO_POOL_SIZE = 128,
};
typedef enum {
DRAIN_ALLOCATOR_START = 0,
DRAIN_ALLOCATOR_STEP_SCRUBBER,
DRAIN_ALLOCATOR_STEP_SLABS,
DRAIN_ALLOCATOR_STEP_SUMMARY,
DRAIN_ALLOCATOR_STEP_FINISHED,
} BlockAllocatorDrainStep;
/**
* A sub-structure for applying actions in parallel to all an allocator's
* slabs.
**/
typedef struct {
/** The number of slabs performing a slab action */
SlabCount slabActionCount;
/** The method to call when a slab action has been completed by all slabs */
VDOAction *callback;
} SlabActor;
/**
* These fields are only modified by the physical zone thread, but are queried
* by other threads.
**/
typedef struct atomicAllocatorStatistics {
/** The count of allocated blocks in this zone */
Atomic64 allocatedBlocks;
/** The number of slabs from which blocks have ever been allocated */
Atomic64 slabsOpened;
/** The number of times since loading that a slab been re-opened */
Atomic64 slabsReopened;
} AtomicAllocatorStatistics;
/**
* The statistics for all the slab journals in the slabs owned by this
* allocator. These fields are all mutated only by the physical zone thread,
* but are read by other threads when gathering statistics for the entire
* depot.
**/
typedef struct atomicSlabJournalStatistics {
/** Number of times the on-disk journal was full */
Atomic64 diskFullCount;
/** Number of times an entry was added over the flush threshold */
Atomic64 flushCount;
/** Number of times an entry was added over the block threshold */
Atomic64 blockedCount;
/** Number of times the tail block was written */
Atomic64 blocksWritten;
/** Number of times we had to wait for the tail block commit */
Atomic64 tailBusyCount;
} AtomicSlabJournalStatistics;
/**
* The statistics for all the RefCounts in the slabs owned by this
* allocator. These fields are all mutated only by the physical zone thread,
* but are read by other threads when gathering statistics for the entire
* depot.
**/
typedef struct atomicRefCountStatistics {
/** Number of blocks written */
Atomic64 blocksWritten;
} AtomicRefCountStatistics;
struct blockAllocator {
VDOCompletion completion;
/** The slab depot for this allocator */
SlabDepot *depot;
/** The slab summary zone for this allocator */
SlabSummaryZone *summary;
/** The notifier for entering read-only mode */
ReadOnlyNotifier *readOnlyNotifier;
/** The nonce of the VDO */
Nonce nonce;
/** The physical zone number of this allocator */
ZoneCount zoneNumber;
/** The thread ID for this allocator's physical zone */
ThreadID threadID;
/** The number of slabs in this allocator */
SlabCount slabCount;
/** The number of the last slab owned by this allocator */
SlabCount lastSlab;
/** The reduced priority level used to preserve unopened slabs */
unsigned int unopenedSlabPriority;
/** The state of this allocator */
AdminState state;
/** The actor for applying an action to all slabs */
SlabActor slabActor;
/** The slab from which blocks are currently being allocated */
Slab *openSlab;
/** A priority queue containing all slabs available for allocation */
PriorityTable *prioritizedSlabs;
/** The slab scrubber */
SlabScrubber *slabScrubber;
/** What phase of the close operation the allocator is to perform */
BlockAllocatorDrainStep drainStep;
/** Statistics for this block allocator */
AtomicAllocatorStatistics statistics;
/** Cumulative statistics for the slab journals in this zone */
AtomicSlabJournalStatistics slabJournalStatistics;
/** Cumulative statistics for the RefCounts in this zone */
AtomicRefCountStatistics refCountStatistics;
/**
* This is the head of a queue of slab journals which have entries in their
* tail blocks which have not yet started to commit. When the recovery
* journal is under space pressure, slab journals which have uncommitted
* entries holding a lock on the recovery journal head are forced to commit
* their blocks early. This list is kept in order, with the tail containing
* the slab journal holding the most recent recovery journal lock.
**/
RingNode dirtySlabJournals;
/** The VIO pool for reading and writing block allocator metadata */
VIOPool *vioPool;
};
/**
* Construct allocator metadata VIOs. Exposed for unit tests.
*
* Implements VIOConstructor
**/
int makeAllocatorPoolVIOs(PhysicalLayer *layer,
void *parent,
void *buffer,
VIO **vioPtr)
__attribute__((warn_unused_result));
/**
* Replace the VIO pool in a block allocator. This method exists for unit
* tests.
*
* @param allocator The block allocator
* @param size The number of entries in the pool
* @param layer The physical layer from which to allocate VIOs
*
* @return VDO_SUCCESS or an error
**/
int replaceVIOPool(BlockAllocator *allocator,
size_t size,
PhysicalLayer *layer)
__attribute__((warn_unused_result));
/**
* Prepare slabs for allocation or scrubbing. This method is exposed for
* testing.
*
* @param allocator The allocator to prepare
*
* @return VDO_SUCCESS or an error code
**/
int prepareSlabsForAllocation(BlockAllocator *allocator)
__attribute__((warn_unused_result));
/**
* Start allocating from the highest numbered slab.
*
* @param allocator The allocator
**/
void allocateFromAllocatorLastSlab(BlockAllocator *allocator);
#endif // BLOCK_ALLOCATOR_INTERNALS_H