|
Packit Service |
75d76b |
/*
|
|
Packit Service |
75d76b |
* Copyright (c) 2020 Red Hat, Inc.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
75d76b |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
75d76b |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
75d76b |
* of the License, or (at your option) any later version.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
75d76b |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
75d76b |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
75d76b |
* GNU General Public License for more details.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
75d76b |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
75d76b |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
75d76b |
* 02110-1301, USA.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/recoveryJournalBlock.c#13 $
|
|
Packit Service |
75d76b |
*/
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
#include "recoveryJournalBlock.h"
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
#include "logger.h"
|
|
Packit Service |
75d76b |
#include "memoryAlloc.h"
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
#include "dataVIO.h"
|
|
Packit Service |
75d76b |
#include "fixedLayout.h"
|
|
Packit Service |
75d76b |
#include "packedRecoveryJournalBlock.h"
|
|
Packit Service |
75d76b |
#include "recoveryJournalEntry.h"
|
|
Packit Service |
75d76b |
#include "recoveryJournalInternals.h"
|
|
Packit Service |
75d76b |
#include "ringNode.h"
|
|
Packit Service |
75d76b |
#include "vio.h"
|
|
Packit Service |
75d76b |
#include "waitQueue.h"
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
int makeRecoveryBlock(PhysicalLayer *layer,
|
|
Packit Service |
75d76b |
RecoveryJournal *journal,
|
|
Packit Service |
75d76b |
RecoveryJournalBlock **blockPtr)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
// Ensure that a block is large enough to store
|
|
Packit Service |
75d76b |
// RECOVERY_JOURNAL_ENTRIES_PER_BLOCK entries.
|
|
Packit Service |
75d76b |
STATIC_ASSERT(RECOVERY_JOURNAL_ENTRIES_PER_BLOCK
|
|
Packit Service |
75d76b |
<= ((VDO_BLOCK_SIZE - sizeof(PackedJournalHeader))
|
|
Packit Service |
75d76b |
/ sizeof(PackedRecoveryJournalEntry)));
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
RecoveryJournalBlock *block;
|
|
Packit Service |
75d76b |
int result = ALLOCATE(1, RecoveryJournalBlock, __func__, &block);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// Allocate a full block for the journal block even though not all of the
|
|
Packit Service |
75d76b |
// space is used since the VIO needs to write a full disk block.
|
|
Packit Service |
75d76b |
result = ALLOCATE(VDO_BLOCK_SIZE, char, "PackedJournalBlock", &block->block);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
freeRecoveryBlock(&block);
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = createVIO(layer, VIO_TYPE_RECOVERY_JOURNAL, VIO_PRIORITY_HIGH,
|
|
Packit Service |
75d76b |
block, block->block, &block->vio);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
freeRecoveryBlock(&block);
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
block->vio->completion.callbackThreadID = journal->threadID;
|
|
Packit Service |
75d76b |
initializeRing(&block->ringNode);
|
|
Packit Service |
75d76b |
block->journal = journal;
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
*blockPtr = block;
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
void freeRecoveryBlock(RecoveryJournalBlock **blockPtr)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
RecoveryJournalBlock *block = *blockPtr;
|
|
Packit Service |
75d76b |
if (block == NULL) {
|
|
Packit Service |
75d76b |
return;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
FREE(block->block);
|
|
Packit Service |
75d76b |
freeVIO(&block->vio);
|
|
Packit Service |
75d76b |
FREE(block);
|
|
Packit Service |
75d76b |
*blockPtr = NULL;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Get a pointer to the packed journal block header in the block buffer.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param block The recovery block
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @return The block's header
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static inline
|
|
Packit Service |
75d76b |
PackedJournalHeader *getBlockHeader(const RecoveryJournalBlock *block)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
return (PackedJournalHeader *) block->block;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Set the current sector of the current block and initialize it.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param block The block to update
|
|
Packit Service |
75d76b |
* @param sector A pointer to the first byte of the new sector
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static void setActiveSector(RecoveryJournalBlock *block, void *sector)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
block->sector = (PackedJournalSector *) sector;
|
|
Packit Service |
75d76b |
block->sector->checkByte = getBlockHeader(block)->fields.checkByte;
|
|
Packit Service |
75d76b |
block->sector->recoveryCount = block->journal->recoveryCount;
|
|
Packit Service |
75d76b |
block->sector->entryCount = 0;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
void initializeRecoveryBlock(RecoveryJournalBlock *block)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
memset(block->block, 0x0, VDO_BLOCK_SIZE);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
RecoveryJournal *journal = block->journal;
|
|
Packit Service |
75d76b |
block->sequenceNumber = journal->tail;
|
|
Packit Service |
75d76b |
block->entryCount = 0;
|
|
Packit Service |
75d76b |
block->uncommittedEntryCount = 0;
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
block->blockNumber = getRecoveryJournalBlockNumber(journal, journal->tail);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
RecoveryBlockHeader unpacked = {
|
|
Packit Service |
75d76b |
.metadataType = VDO_METADATA_RECOVERY_JOURNAL,
|
|
Packit Service |
75d76b |
.blockMapDataBlocks = journal->blockMapDataBlocks,
|
|
Packit Service |
75d76b |
.logicalBlocksUsed = journal->logicalBlocksUsed,
|
|
Packit Service |
75d76b |
.nonce = journal->nonce,
|
|
Packit Service |
75d76b |
.recoveryCount = journal->recoveryCount,
|
|
Packit Service |
75d76b |
.sequenceNumber = journal->tail,
|
|
Packit Service |
75d76b |
.checkByte = computeRecoveryCheckByte(journal, journal->tail),
|
|
Packit Service |
75d76b |
};
|
|
Packit Service |
75d76b |
PackedJournalHeader *header = getBlockHeader(block);
|
|
Packit Service |
75d76b |
packRecoveryBlockHeader(&unpacked, header);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
setActiveSector(block, getJournalBlockSector(header, 1));
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
int enqueueRecoveryBlockEntry(RecoveryJournalBlock *block, DataVIO *dataVIO)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
// First queued entry indicates this is a journal block we've just opened
|
|
Packit Service |
75d76b |
// or a committing block we're extending and will have to write again.
|
|
Packit Service |
75d76b |
bool newBatch = !hasWaiters(&block->entryWaiters);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// Enqueue the DataVIO to wait for its entry to commit.
|
|
Packit Service |
75d76b |
int result = enqueueDataVIO(&block->entryWaiters, dataVIO,
|
|
Packit Service |
75d76b |
THIS_LOCATION("$F($j-$js)"));
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
block->entryCount++;
|
|
Packit Service |
75d76b |
block->uncommittedEntryCount++;
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// Update stats to reflect the journal entry we're going to write.
|
|
Packit Service |
75d76b |
if (newBatch) {
|
|
Packit Service |
75d76b |
block->journal->events.blocks.started++;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
block->journal->events.entries.started++;
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Check whether the current sector of a block is full.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param block The block to check
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @return true if the sector is full
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
__attribute__((warn_unused_result))
|
|
Packit Service |
75d76b |
static bool isSectorFull(const RecoveryJournalBlock *block)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
return (block->sector->entryCount == RECOVERY_JOURNAL_ENTRIES_PER_SECTOR);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Actually add entries from the queue to the given block.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param block The journal block
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @return VDO_SUCCESS or an error code
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
__attribute__((warn_unused_result))
|
|
Packit Service |
75d76b |
static int addQueuedRecoveryEntries(RecoveryJournalBlock *block)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
while (hasWaiters(&block->entryWaiters)) {
|
|
Packit Service |
75d76b |
DataVIO *dataVIO
|
|
Packit Service |
75d76b |
= waiterAsDataVIO(dequeueNextWaiter(&block->entryWaiters));
|
|
Packit Service |
75d76b |
if (dataVIO->operation.type == DATA_INCREMENT) {
|
|
Packit Service |
75d76b |
// In order to not lose committed sectors of this partial write, we must
|
|
Packit Service |
75d76b |
// flush before the partial write entries are committed.
|
|
Packit Service |
75d76b |
block->hasPartialWriteEntry = (block->hasPartialWriteEntry
|
|
Packit Service |
75d76b |
|| dataVIO->isPartialWrite);
|
|
Packit Service |
75d76b |
/*
|
|
Packit Service |
75d76b |
* In order to not lose acknowledged writes with the FUA flag set, we
|
|
Packit Service |
75d76b |
* must issue a flush to cover the data write and also all previous
|
|
Packit Service |
75d76b |
* journal writes, and we must issue a FUA on the journal write.
|
|
Packit Service |
75d76b |
*/
|
|
Packit Service |
75d76b |
block->hasFUAEntry = (block->hasFUAEntry
|
|
Packit Service |
75d76b |
|| vioRequiresFlushAfter(dataVIOAsVIO(dataVIO)));
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// Compose and encode the entry.
|
|
Packit Service |
75d76b |
PackedRecoveryJournalEntry *packedEntry
|
|
Packit Service |
75d76b |
= &block->sector->entries[block->sector->entryCount++];
|
|
Packit Service |
75d76b |
TreeLock *lock = &dataVIO->treeLock;
|
|
Packit Service |
75d76b |
RecoveryJournalEntry newEntry = {
|
|
Packit Service |
75d76b |
.mapping = {
|
|
Packit Service |
75d76b |
.pbn = dataVIO->operation.pbn,
|
|
Packit Service |
75d76b |
.state = dataVIO->operation.state,
|
|
Packit Service |
75d76b |
},
|
|
Packit Service |
75d76b |
.operation = dataVIO->operation.type,
|
|
Packit Service |
75d76b |
.slot = lock->treeSlots[lock->height].blockMapSlot,
|
|
Packit Service |
75d76b |
};
|
|
Packit Service |
75d76b |
*packedEntry = packRecoveryJournalEntry(&newEntry);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
if (isIncrementOperation(dataVIO->operation.type)) {
|
|
Packit Service |
75d76b |
dataVIO->recoverySequenceNumber = block->sequenceNumber;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// Enqueue the DataVIO to wait for its entry to commit.
|
|
Packit Service |
75d76b |
int result = enqueueDataVIO(&block->commitWaiters, dataVIO,
|
|
Packit Service |
75d76b |
THIS_LOCATION("$F($j-$js)"));
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
continueDataVIO(dataVIO, result);
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
if (isSectorFull(block)) {
|
|
Packit Service |
75d76b |
setActiveSector(block, (char *) block->sector + VDO_SECTOR_SIZE);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
__attribute__((warn_unused_result))
|
|
Packit Service |
75d76b |
static int getRecoveryBlockPBN(RecoveryJournalBlock *block,
|
|
Packit Service |
75d76b |
PhysicalBlockNumber *pbnPtr)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
RecoveryJournal *journal = block->journal;
|
|
Packit Service |
75d76b |
int result = translateToPBN(journal->partition, block->blockNumber, pbnPtr);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
logErrorWithStringError(result,
|
|
Packit Service |
75d76b |
"Error translating recovery journal block "
|
|
Packit Service |
75d76b |
"number %llu", block->blockNumber);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
bool canCommitRecoveryBlock(RecoveryJournalBlock *block)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
// Cannot commit in read-only mode, if already committing the block, or
|
|
Packit Service |
75d76b |
// if there are no entries to commit.
|
|
Packit Service |
75d76b |
return ((block != NULL)
|
|
Packit Service |
75d76b |
&& !block->committing
|
|
Packit Service |
75d76b |
&& hasWaiters(&block->entryWaiters)
|
|
Packit Service |
75d76b |
&& !isReadOnly(block->journal->readOnlyNotifier));
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
int commitRecoveryBlock(RecoveryJournalBlock *block,
|
|
Packit Service |
75d76b |
VDOAction *callback,
|
|
Packit Service |
75d76b |
VDOAction *errorHandler)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
int result = ASSERT(canCommitRecoveryBlock(block), "should never call %s"
|
|
Packit Service |
75d76b |
" when the block can't be committed", __func__);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
PhysicalBlockNumber blockPBN;
|
|
Packit Service |
75d76b |
result = getRecoveryBlockPBN(block, &blockPBN);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
block->entriesInCommit = countWaiters(&block->entryWaiters);
|
|
Packit Service |
75d76b |
result = addQueuedRecoveryEntries(block);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
RecoveryJournal *journal = block->journal;
|
|
Packit Service |
75d76b |
PackedJournalHeader *header = getBlockHeader(block);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// Update stats to reflect the block and entries we're about to write.
|
|
Packit Service |
75d76b |
journal->pendingWriteCount += 1;
|
|
Packit Service |
75d76b |
journal->events.blocks.written += 1;
|
|
Packit Service |
75d76b |
journal->events.entries.written += block->entriesInCommit;
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
storeUInt64LE(header->fields.blockMapHead, journal->blockMapHead);
|
|
Packit Service |
75d76b |
storeUInt64LE(header->fields.slabJournalHead, journal->slabJournalHead);
|
|
Packit Service |
75d76b |
storeUInt16LE(header->fields.entryCount, block->entryCount);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
block->committing = true;
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*
|
|
Packit Service |
75d76b |
* In sync or async mode, when we are writing an increment entry for a
|
|
Packit Service |
75d76b |
* request with FUA, or when making the increment entry for a partial
|
|
Packit Service |
75d76b |
* write, we need to make sure all the data being mapped to by this block
|
|
Packit Service |
75d76b |
* is stable on disk and also that the recovery journal is stable up to
|
|
Packit Service |
75d76b |
* the current block, so we must flush before writing.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* In sync mode, and for FUA, we also need to make sure that the write we
|
|
Packit Service |
75d76b |
* are doing is stable, so we issue the write with FUA.
|
|
Packit Service |
75d76b |
*/
|
|
Packit Service |
75d76b |
PhysicalLayer *layer = vioAsCompletion(block->vio)->layer;
|
|
Packit Service |
75d76b |
bool fua = (block->hasFUAEntry
|
|
Packit Service |
75d76b |
|| (layer->getWritePolicy(layer) == WRITE_POLICY_SYNC));
|
|
Packit Service |
75d76b |
bool flush = (block->hasFUAEntry
|
|
Packit Service |
75d76b |
|| (layer->getWritePolicy(layer) != WRITE_POLICY_ASYNC_UNSAFE)
|
|
Packit Service |
75d76b |
|| block->hasPartialWriteEntry);
|
|
Packit Service |
75d76b |
block->hasFUAEntry = false;
|
|
Packit Service |
75d76b |
block->hasPartialWriteEntry = false;
|
|
Packit Service |
75d76b |
launchWriteMetadataVIOWithFlush(block->vio, blockPBN, callback, errorHandler,
|
|
Packit Service |
75d76b |
flush, fua);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
void dumpRecoveryBlock(const RecoveryJournalBlock *block)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
logInfo(" sequence number %llu; entries %" PRIu16
|
|
Packit Service |
75d76b |
"; %s; %zu entry waiters; %zu commit waiters",
|
|
Packit Service |
75d76b |
block->sequenceNumber,
|
|
Packit Service |
75d76b |
block->entryCount,
|
|
Packit Service |
75d76b |
(block->committing ? "committing" : "waiting"),
|
|
Packit Service |
75d76b |
countWaiters(&block->entryWaiters),
|
|
Packit Service |
75d76b |
countWaiters(&block->commitWaiters));
|
|
Packit Service |
75d76b |
}
|