Blame source/uds/chapterWriter.c

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
}