|
Packit Service |
310c69 |
/*
|
|
Packit Service |
310c69 |
* Copyright (c) 2020 Red Hat, Inc.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
310c69 |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
310c69 |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
310c69 |
* of the License, or (at your option) any later version.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
310c69 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
310c69 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
310c69 |
* GNU General Public License for more details.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
310c69 |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
310c69 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
310c69 |
* 02110-1301, USA.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* $Id: //eng/uds-releases/jasper/src/uds/chapterWriter.c#2 $
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "chapterWriter.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "errors.h"
|
|
Packit Service |
310c69 |
#include "index.h"
|
|
Packit Service |
310c69 |
#include "indexCheckpoint.h"
|
|
Packit Service |
310c69 |
#include "indexComponent.h"
|
|
Packit Service |
310c69 |
#include "logger.h"
|
|
Packit Service |
310c69 |
#include "memoryAlloc.h"
|
|
Packit Service |
310c69 |
#include "openChapter.h"
|
|
Packit Service |
310c69 |
#include "threads.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
struct chapterWriter {
|
|
Packit Service |
310c69 |
/* The index to which we belong */
|
|
Packit Service |
310c69 |
Index *index;
|
|
Packit Service |
310c69 |
/* The thread to do the writing */
|
|
Packit Service |
310c69 |
Thread thread;
|
|
Packit Service |
310c69 |
/* lock protecting the following fields */
|
|
Packit Service |
310c69 |
Mutex mutex;
|
|
Packit Service |
310c69 |
/* condition signalled on state changes */
|
|
Packit Service |
310c69 |
CondVar cond;
|
|
Packit Service |
310c69 |
/* Set to true to stop the thread */
|
|
Packit Service |
310c69 |
bool stop;
|
|
Packit Service |
310c69 |
/* The result from the most recent write */
|
|
Packit Service |
310c69 |
int result;
|
|
Packit Service |
310c69 |
/* The number of bytes allocated by the chapter writer */
|
|
Packit Service |
310c69 |
size_t memoryAllocated;
|
|
Packit Service |
310c69 |
/* The number of zones which have submitted a chapter for writing */
|
|
Packit Service |
310c69 |
unsigned int zonesToWrite;
|
|
Packit Service |
310c69 |
/* Open chapter index used by closeOpenChapter() */
|
|
Packit Service |
310c69 |
OpenChapterIndex *openChapterIndex;
|
|
Packit Service |
310c69 |
/* Collated records used by closeOpenChapter() */
|
|
Packit Service |
310c69 |
UdsChunkRecord *collatedRecords;
|
|
Packit Service |
310c69 |
/* The chapters to write (one per zone) */
|
|
Packit Service |
310c69 |
OpenChapterZone *chapters[];
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* This is the driver function for the writer thread. It loops until
|
|
Packit Service |
310c69 |
* terminated, waiting for a chapter to provided to close.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void closeChapters(void *arg)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
ChapterWriter *writer = arg;
|
|
Packit Service |
310c69 |
logDebug("chapter writer starting");
|
|
Packit Service |
310c69 |
lockMutex(&writer->mutex);
|
|
Packit Service |
310c69 |
for (;;) {
|
|
Packit Service |
310c69 |
while (writer->zonesToWrite < writer->index->zoneCount) {
|
|
Packit Service |
310c69 |
if (writer->stop && (writer->zonesToWrite == 0)) {
|
|
Packit Service |
310c69 |
// We've been told to stop, and all of the zones are in the same
|
|
Packit Service |
310c69 |
// open chapter, so we can exit now.
|
|
Packit Service |
310c69 |
unlockMutex(&writer->mutex);
|
|
Packit Service |
310c69 |
logDebug("chapter writer stopping");
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
waitCond(&writer->cond, &writer->mutex);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/*
|
|
Packit Service |
310c69 |
* Release the lock while closing a chapter. We probably don't need to do
|
|
Packit Service |
310c69 |
* this, but it seems safer in principle. It's OK to access the chapter
|
|
Packit Service |
310c69 |
* and chapterNumber fields without the lock since those aren't allowed to
|
|
Packit Service |
310c69 |
* change until we're done.
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
unlockMutex(&writer->mutex);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (writer->index->hasSavedOpenChapter) {
|
|
Packit Service |
310c69 |
writer->index->hasSavedOpenChapter = false;
|
|
Packit Service |
310c69 |
/*
|
|
Packit Service |
310c69 |
* Remove the saved open chapter as that chapter is about to be written
|
|
Packit Service |
310c69 |
* to the volume. This matters the first time we close the open chapter
|
|
Packit Service |
310c69 |
* after loading from a clean shutdown, or after doing a clean save.
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
IndexComponent *oc = findIndexComponent(writer->index->state,
|
|
Packit Service |
310c69 |
&OPEN_CHAPTER_INFO);
|
|
Packit Service |
310c69 |
int result = discardIndexComponent(oc);
|
|
Packit Service |
310c69 |
if (result == UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
logDebug("Discarding saved open chapter");
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
int result = closeOpenChapter(writer->chapters,
|
|
Packit Service |
310c69 |
writer->index->zoneCount,
|
|
Packit Service |
310c69 |
writer->index->volume,
|
|
Packit Service |
310c69 |
writer->openChapterIndex,
|
|
Packit Service |
310c69 |
writer->collatedRecords,
|
|
Packit Service |
310c69 |
writer->index->newestVirtualChapter);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (result == UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
result = processChapterWriterCheckpointSaves(writer->index);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
lockMutex(&writer->mutex);
|
|
Packit Service |
310c69 |
// Note that the index is totally finished with the writing chapter
|
|
Packit Service |
310c69 |
advanceActiveChapters(writer->index);
|
|
Packit Service |
310c69 |
writer->result = result;
|
|
Packit Service |
310c69 |
writer->zonesToWrite = 0;
|
|
Packit Service |
310c69 |
broadcastCond(&writer->cond);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int makeChapterWriter(Index *index,
|
|
Packit Service |
310c69 |
const struct index_version *indexVersion,
|
|
Packit Service |
310c69 |
ChapterWriter **writerPtr)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
size_t collatedRecordsSize
|
|
Packit Service |
310c69 |
= (sizeof(UdsChunkRecord)
|
|
Packit Service |
310c69 |
* (1 + index->volume->geometry->recordsPerChapter));
|
|
Packit Service |
310c69 |
ChapterWriter *writer;
|
|
Packit Service |
310c69 |
int result = ALLOCATE_EXTENDED(ChapterWriter,
|
|
Packit Service |
310c69 |
index->zoneCount, OpenChapterZone *,
|
|
Packit Service |
310c69 |
"Chapter Writer", &writer);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
writer->index = index;
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = initMutex(&writer->mutex);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
FREE(writer);
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
result = initCond(&writer->cond);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
destroyMutex(&writer->mutex);
|
|
Packit Service |
310c69 |
FREE(writer);
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// Now that we have the mutex+cond, it is safe to call freeChapterWriter.
|
|
Packit Service |
310c69 |
result = allocateCacheAligned(collatedRecordsSize, "collated records",
|
|
Packit Service |
310c69 |
&writer->collatedRecords);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
freeChapterWriter(writer);
|
|
Packit Service |
310c69 |
return makeUnrecoverable(result);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
result = makeOpenChapterIndex(&writer->openChapterIndex,
|
|
Packit Service |
310c69 |
index->volume->geometry,
|
|
Packit Service |
310c69 |
indexVersion->chapterIndexHeaderNativeEndian,
|
|
Packit Service |
310c69 |
index->volume->nonce);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
freeChapterWriter(writer);
|
|
Packit Service |
310c69 |
return makeUnrecoverable(result);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
size_t openChapterIndexMemoryAllocated
|
|
Packit Service |
310c69 |
= getOpenChapterIndexMemoryAllocated(writer->openChapterIndex);
|
|
Packit Service |
310c69 |
writer->memoryAllocated = (sizeof(ChapterWriter)
|
|
Packit Service |
310c69 |
+ index->zoneCount * sizeof(OpenChapterZone *)
|
|
Packit Service |
310c69 |
+ collatedRecordsSize
|
|
Packit Service |
310c69 |
+ openChapterIndexMemoryAllocated);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// We're initialized, so now it's safe to start the writer thread.
|
|
Packit Service |
310c69 |
result = createThread(closeChapters, writer, "writer", &writer->thread);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
freeChapterWriter(writer);
|
|
Packit Service |
310c69 |
return makeUnrecoverable(result);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
*writerPtr = writer;
|
|
Packit Service |
310c69 |
return UDS_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void freeChapterWriter(ChapterWriter *writer)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
if (writer == NULL) {
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
int result __attribute__((unused)) = stopChapterWriter(writer);
|
|
Packit Service |
310c69 |
destroyMutex(&writer->mutex);
|
|
Packit Service |
310c69 |
destroyCond(&writer->cond);
|
|
Packit Service |
310c69 |
freeOpenChapterIndex(writer->openChapterIndex);
|
|
Packit Service |
310c69 |
FREE(writer->collatedRecords);
|
|
Packit Service |
310c69 |
FREE(writer);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
unsigned int startClosingChapter(ChapterWriter *writer,
|
|
Packit Service |
310c69 |
unsigned int zoneNumber,
|
|
Packit Service |
310c69 |
OpenChapterZone *chapter)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
lockMutex(&writer->mutex);
|
|
Packit Service |
310c69 |
unsigned int finishedZones = ++writer->zonesToWrite;
|
|
Packit Service |
310c69 |
writer->chapters[zoneNumber] = chapter;
|
|
Packit Service |
310c69 |
broadcastCond(&writer->cond);
|
|
Packit Service |
310c69 |
unlockMutex(&writer->mutex);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
return finishedZones;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int finishPreviousChapter(ChapterWriter *writer, uint64_t currentChapterNumber)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
int result;
|
|
Packit Service |
310c69 |
lockMutex(&writer->mutex);
|
|
Packit Service |
310c69 |
while (writer->index->newestVirtualChapter < currentChapterNumber) {
|
|
Packit Service |
310c69 |
waitCond(&writer->cond, &writer->mutex);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
result = writer->result;
|
|
Packit Service |
310c69 |
unlockMutex(&writer->mutex);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return logUnrecoverable(result, "Writing of previous open chapter failed");
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
return UDS_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void waitForIdleChapterWriter(ChapterWriter *writer)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
lockMutex(&writer->mutex);
|
|
Packit Service |
310c69 |
while (writer->zonesToWrite > 0) {
|
|
Packit Service |
310c69 |
// The chapter writer is probably writing a chapter. If it is not, it will
|
|
Packit Service |
310c69 |
// soon wake up and write a chapter.
|
|
Packit Service |
310c69 |
waitCond(&writer->cond, &writer->mutex);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
unlockMutex(&writer->mutex);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int stopChapterWriter(ChapterWriter *writer)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
Thread writerThread = 0;
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
lockMutex(&writer->mutex);
|
|
Packit Service |
310c69 |
if (writer->thread != 0) {
|
|
Packit Service |
310c69 |
writerThread = writer->thread;
|
|
Packit Service |
310c69 |
writer->thread = 0;
|
|
Packit Service |
310c69 |
writer->stop = true;
|
|
Packit Service |
310c69 |
broadcastCond(&writer->cond);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
int result = writer->result;
|
|
Packit Service |
310c69 |
unlockMutex(&writer->mutex);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (writerThread != 0) {
|
|
Packit Service |
310c69 |
joinThreads(writerThread);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return logUnrecoverable(result, "Writing of previous open chapter failed");
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
return UDS_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
size_t getChapterWriterMemoryAllocated(ChapterWriter *writer)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return writer->memoryAllocated;
|
|
Packit Service |
310c69 |
}
|