/*
* 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/packerInternals.h#4 $
*/
#ifndef PACKER_INTERNALS_H
#define PACKER_INTERNALS_H
#include "packer.h"
#include "atomic.h"
#include "adminState.h"
#include "compressedBlock.h"
#include "header.h"
#include "types.h"
#include "waitQueue.h"
/**
* Each InputBin holds an incomplete batch of DataVIOs that only partially fill
* a compressed block. The InputBins are kept in a ring sorted by the amount of
* unused space so the first bin with enough space to hold a newly-compressed
* DataVIO can easily be found. When the bin fills up or is flushed, the
* incoming DataVIOs are moved to the Packer's batchedDataVIOs queue, from
* which they will eventually be routed to an idle OutputBin.
*
* There is one special input bin which is used to hold DataVIOs which have
* been canceled and removed from their input bin by the packer. These DataVIOs
* need to wait for the canceller to rendezvous with them (VDO-2809) and so
* they sit in this special bin.
**/
struct inputBin {
/** List links for Packer.sortedBins */
RingNode ring;
/** The number of items in the bin */
SlotNumber slotsUsed;
/** The number of compressed block bytes remaining in the current batch */
size_t freeSpace;
/** The current partial batch of DataVIOs, waiting for more */
DataVIO *incoming[];
};
/**
* Each OutputBin allows a single compressed block to be packed and written.
* When it is not idle, it holds a batch of DataVIOs that have been packed
* into the compressed block, written asynchronously, and are waiting for the
* write to complete.
**/
typedef struct {
/** List links for Packer.outputBins */
RingNode ring;
/** The storage for encoding the compressed block representation */
CompressedBlock *block;
/** The AllocatingVIO wrapping the compressed block for writing */
AllocatingVIO *writer;
/** The number of compression slots used in the compressed block */
SlotNumber slotsUsed;
/** The DataVIOs packed into the block, waiting for the write to complete */
WaitQueue outgoing;
} OutputBin;
/**
* A counted array holding a batch of DataVIOs that should be packed into an
* output bin.
**/
typedef struct {
size_t slotsUsed;
DataVIO *slots[MAX_COMPRESSION_SLOTS];
} OutputBatch;
struct packer {
/** The ID of the packer's callback thread */
ThreadID threadID;
/** The selector for determining which physical zone to allocate from */
AllocationSelector *selector;
/** The number of input bins */
BlockCount size;
/** The block size minus header size */
size_t binDataSize;
/** The number of compression slots */
size_t maxSlots;
/** A ring of all InputBins, kept sorted by freeSpace */
RingNode inputBins;
/** A ring of all OutputBins */
RingNode outputBins;
/**
* A bin to hold DataVIOs which were canceled out of the packer and are
* waiting to rendezvous with the canceling DataVIO.
**/
InputBin *canceledBin;
/** The current flush generation */
SequenceNumber flushGeneration;
/** The administrative state of the packer */
AdminState state;
/** True when writing batched DataVIOs */
bool writingBatches;
// Atomic counters corresponding to the fields of PackerStatistics:
/** Number of compressed data items written since startup */
Atomic64 fragmentsWritten;
/** Number of blocks containing compressed items written since startup */
Atomic64 blocksWritten;
/** Number of DataVIOs that are pending in the packer */
Atomic64 fragmentsPending;
/** Queue of batched DataVIOs waiting to be packed */
WaitQueue batchedDataVIOs;
/** The total number of output bins allocated */
size_t outputBinCount;
/** The number of idle output bins on the stack */
size_t idleOutputBinCount;
/** The stack of idle output bins (0=bottom) */
OutputBin *idleOutputBins[];
};
/**
* This returns the first bin in the freeSpace-sorted list.
**/
InputBin *getFullestBin(const Packer *packer);
/**
* This returns the next bin in the freeSpace-sorted list.
**/
InputBin *nextBin(const Packer *packer, InputBin *bin);
/**
* Change the maxiumum number of compression slots the packer will use. The new
* number of slots must be less than or equal to MAX_COMPRESSION_SLOTS. Bins
* which already have fragments will not be resized until they are next written
* out.
*
* @param packer The packer
* @param slots The new number of slots
**/
void resetSlotCount(Packer *packer, CompressedFragmentCount slots);
/**
* Remove a DataVIO from the packer. This method is exposed for testing.
*
* @param dataVIO The DataVIO to remove
**/
void removeFromPacker(DataVIO *dataVIO);
#endif /* PACKER_INTERNALS_H */