Blame source/uds/openChapter.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/openChapter.c#4 $
Packit Service 310c69
 */
Packit Service 310c69
Packit Service 310c69
#include "openChapter.h"
Packit Service 310c69
Packit Service 310c69
#include "compiler.h"
Packit Service 310c69
#include "logger.h"
Packit Service 310c69
#include "memoryAlloc.h"
Packit Service 310c69
#include "numeric.h"
Packit Service 310c69
#include "zone.h"
Packit Service 310c69
Packit Service 310c69
static int readOpenChapters(ReadPortal *portal);
Packit Service 310c69
static int writeOpenChapters(IndexComponent *component,
Packit Service 310c69
                             BufferedWriter *writer,
Packit Service 310c69
                             unsigned int    zone);
Packit Service 310c69
Packit Service 310c69
const IndexComponentInfo OPEN_CHAPTER_INFO = {
Packit Service 310c69
  .kind        = RL_KIND_OPEN_CHAPTER,
Packit Service 310c69
  .name        = "open chapter",
Packit Service 310c69
  .saveOnly    = true,
Packit Service 310c69
  .chapterSync = false,
Packit Service 310c69
  .multiZone   = false,
Packit Service 310c69
  .ioStorage   = true,
Packit Service 310c69
  .loader      = readOpenChapters,
Packit Service 310c69
  .saver       = writeOpenChapters,
Packit Service 310c69
  .incremental = NULL,
Packit Service 310c69
};
Packit Service 310c69
Packit Service 310c69
static const byte OPEN_CHAPTER_MAGIC[]       = "ALBOC";
Packit Service 310c69
static const byte OPEN_CHAPTER_VERSION[]     = "02.00";
Packit Service 310c69
Packit Service 310c69
enum {
Packit Service 310c69
  OPEN_CHAPTER_MAGIC_LENGTH   = sizeof(OPEN_CHAPTER_MAGIC) - 1,
Packit Service 310c69
  OPEN_CHAPTER_VERSION_LENGTH = sizeof(OPEN_CHAPTER_VERSION) - 1
Packit Service 310c69
};
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static int fillDeltaChapterIndex(OpenChapterZone **chapterZones,
Packit Service 310c69
                                 unsigned int      zoneCount,
Packit Service 310c69
                                 OpenChapterIndex *index,
Packit Service 310c69
                                 UdsChunkRecord   *collatedRecords)
Packit Service 310c69
{
Packit Service 310c69
  // Find a record to replace any deleted records, and fill the chapter if
Packit Service 310c69
  // it was closed early. The last record in any filled zone is guaranteed
Packit Service 310c69
  // to not have been deleted in this chapter, so use one of those.
Packit Service 310c69
  OpenChapterZone *fillChapterZone = NULL;
Packit Service 310c69
  UdsChunkRecord  *fillRecord      = NULL;
Packit Service 310c69
  unsigned int z;
Packit Service 310c69
  for (z = 0; z < zoneCount; ++z) {
Packit Service 310c69
    fillChapterZone = chapterZones[z];
Packit Service 310c69
    if (fillChapterZone->size == fillChapterZone->capacity) {
Packit Service 310c69
      fillRecord = &fillChapterZone->records[fillChapterZone->size];
Packit Service 310c69
      break;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
  int result = ASSERT((fillRecord != NULL),
Packit Service 310c69
                      "some open chapter zone filled");
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = ASSERT(!fillChapterZone->slots[fillChapterZone->size].recordDeleted,
Packit Service 310c69
                  "chapter fill record not deleted");
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  const Geometry *geometry     = index->geometry;
Packit Service 310c69
  unsigned int pagesPerChapter = geometry->recordPagesPerChapter;
Packit Service 310c69
  unsigned int recordsPerPage  = geometry->recordsPerPage;
Packit Service 310c69
  int          overflowCount   = 0;
Packit Service 310c69
  unsigned int recordsAdded    = 0;
Packit Service 310c69
  unsigned int zone            = 0;
Packit Service 310c69
Packit Service 310c69
  unsigned int page;
Packit Service 310c69
  for (page = 0; page < pagesPerChapter; page++) {
Packit Service 310c69
    unsigned int i;
Packit Service 310c69
    for (i = 0;
Packit Service 310c69
         i < recordsPerPage;
Packit Service 310c69
         i++, recordsAdded++, zone = (zone + 1) % zoneCount) {
Packit Service 310c69
Packit Service 310c69
      // The record arrays are 1-based.
Packit Service 310c69
      unsigned int recordNumber = 1 + (recordsAdded / zoneCount);
Packit Service 310c69
Packit Service 310c69
      // If the zone has been exhausted, or the record was deleted,
Packit Service 310c69
      // add the fill record to the chapter.
Packit Service 310c69
      if (recordNumber > chapterZones[zone]->size
Packit Service 310c69
          || chapterZones[zone]->slots[recordNumber].recordDeleted) {
Packit Service 310c69
        collatedRecords[1 + recordsAdded] = *fillRecord;
Packit Service 310c69
        continue;
Packit Service 310c69
      }
Packit Service 310c69
Packit Service 310c69
      UdsChunkRecord *nextRecord = &chapterZones[zone]->records[recordNumber];
Packit Service 310c69
      collatedRecords[1 + recordsAdded] = *nextRecord;
Packit Service 310c69
Packit Service 310c69
      int result = putOpenChapterIndexRecord(index, &nextRecord->name, page);
Packit Service 310c69
      switch (result) {
Packit Service 310c69
      case UDS_SUCCESS:
Packit Service 310c69
        break;
Packit Service 310c69
      case UDS_OVERFLOW:
Packit Service 310c69
        overflowCount++;
Packit Service 310c69
        break;
Packit Service 310c69
      default:
Packit Service 310c69
        logErrorWithStringError(result, "failed to build open chapter index");
Packit Service 310c69
        return result;
Packit Service 310c69
      }
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
  if (overflowCount > 0) {
Packit Service 310c69
    logWarning("Failed to add %d entries to chapter index", overflowCount);
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int closeOpenChapter(OpenChapterZone  **chapterZones,
Packit Service 310c69
                     unsigned int       zoneCount,
Packit Service 310c69
                     Volume            *volume,
Packit Service 310c69
                     OpenChapterIndex  *chapterIndex,
Packit Service 310c69
                     UdsChunkRecord    *collatedRecords,
Packit Service 310c69
                     uint64_t           virtualChapterNumber)
Packit Service 310c69
{
Packit Service 310c69
  // Empty the delta chapter index, and prepare it for the new virtual chapter.
Packit Service 310c69
  emptyOpenChapterIndex(chapterIndex, virtualChapterNumber);
Packit Service 310c69
Packit Service 310c69
  // Map each non-deleted record name to its record page number in the delta
Packit Service 310c69
  // chapter index.
Packit Service 310c69
  int result = fillDeltaChapterIndex(chapterZones, zoneCount, chapterIndex,
Packit Service 310c69
                                     collatedRecords);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Pass the populated chapter index and the records to the volume, which
Packit Service 310c69
  // will generate and write the index and record pages for the chapter.
Packit Service 310c69
  return writeChapter(volume, chapterIndex, collatedRecords);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int saveOpenChapters(Index *index, BufferedWriter *writer)
Packit Service 310c69
{
Packit Service 310c69
  int result = writeToBufferedWriter(writer, OPEN_CHAPTER_MAGIC,
Packit Service 310c69
                                     OPEN_CHAPTER_MAGIC_LENGTH);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = writeToBufferedWriter(writer, OPEN_CHAPTER_VERSION,
Packit Service 310c69
                                 OPEN_CHAPTER_VERSION_LENGTH);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  uint32_t totalRecords = 0;
Packit Service 310c69
  unsigned int i;
Packit Service 310c69
  for (i = 0; i < index->zoneCount; i++) {
Packit Service 310c69
    totalRecords += openChapterSize(index->zones[i]->openChapter);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Store the record count in little-endian order.
Packit Service 310c69
  byte totalRecordData[sizeof(totalRecords)];
Packit Service 310c69
  storeUInt32LE(totalRecordData, totalRecords);
Packit Service 310c69
Packit Service 310c69
  result = writeToBufferedWriter(writer, totalRecordData,
Packit Service 310c69
                                 sizeof(totalRecordData));
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Only write out the records that have been added and not deleted.
Packit Service 310c69
  uint32_t recordsAdded = 0;
Packit Service 310c69
  unsigned int recordIndex = 1;
Packit Service 310c69
  while(recordsAdded < totalRecords) {
Packit Service 310c69
    unsigned int i;
Packit Service 310c69
    for (i = 0; i < index->zoneCount; i++) {
Packit Service 310c69
      if (recordIndex > index->zones[i]->openChapter->size) {
Packit Service 310c69
        continue;
Packit Service 310c69
      }
Packit Service 310c69
      if (index->zones[i]->openChapter->slots[recordIndex].recordDeleted) {
Packit Service 310c69
        continue;
Packit Service 310c69
      }
Packit Service 310c69
      UdsChunkRecord *record
Packit Service 310c69
        = &index->zones[i]->openChapter->records[recordIndex];
Packit Service 310c69
      result = writeToBufferedWriter(writer, record, sizeof(UdsChunkRecord));
Packit Service 310c69
      if (result != UDS_SUCCESS) {
Packit Service 310c69
        return result;
Packit Service 310c69
      }
Packit Service 310c69
      recordsAdded++;
Packit Service 310c69
    }
Packit Service 310c69
    recordIndex++;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return flushBufferedWriter(writer);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
uint64_t computeSavedOpenChapterSize(Geometry *geometry)
Packit Service 310c69
{
Packit Service 310c69
  return OPEN_CHAPTER_MAGIC_LENGTH + OPEN_CHAPTER_VERSION_LENGTH +
Packit Service 310c69
    sizeof(uint32_t) + geometry->recordsPerChapter * sizeof(UdsChunkRecord);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static int writeOpenChapters(IndexComponent *component,
Packit Service 310c69
                             BufferedWriter *writer,
Packit Service 310c69
                             unsigned int    zone)
Packit Service 310c69
{
Packit Service 310c69
  int result = ASSERT((zone == 0), "open chapter write not zoned");
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  Index *index = indexComponentData(component);
Packit Service 310c69
  return saveOpenChapters(index, writer);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Read the version field from a buffered reader, checking whether it is a
Packit Service 310c69
 * supported version. Returns (via a pointer parameter) the matching
Packit Service 310c69
 * version constant, which can be used by comparing to the version
Packit Service 310c69
 * constants using simple pointer equality.
Packit Service 310c69
 *
Packit Service 310c69
 * @param [in]  reader  A buffered reader.
Packit Service 310c69
 * @param [out] version The version constant that was matched.
Packit Service 310c69
 *
Packit Service 310c69
 * @return UDS_SUCCESS or an error code if the file could not be read or
Packit Service 310c69
 *         the version is invalid or unsupported
Packit Service 310c69
 **/
Packit Service 310c69
static int readVersion(BufferedReader *reader, const byte **version)
Packit Service 310c69
{
Packit Service 310c69
  byte buffer[OPEN_CHAPTER_VERSION_LENGTH];
Packit Service 310c69
  int result = readFromBufferedReader(reader, buffer, sizeof(buffer));
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  if (memcmp(OPEN_CHAPTER_VERSION, buffer, sizeof(buffer)) != 0) {
Packit Service 310c69
    return logErrorWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                   "Invalid open chapter version: %.*s",
Packit Service 310c69
                                   (int) sizeof(buffer), buffer);
Packit Service 310c69
  }
Packit Service 310c69
  *version = OPEN_CHAPTER_VERSION;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static int loadVersion20(Index *index, BufferedReader *reader)
Packit Service 310c69
{
Packit Service 310c69
  byte numRecordsData[sizeof(uint32_t)];
Packit Service 310c69
  int result
Packit Service 310c69
    = readFromBufferedReader(reader, &numRecordsData, sizeof(numRecordsData));
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  uint32_t numRecords = getUInt32LE(numRecordsData);
Packit Service 310c69
Packit Service 310c69
  // Keep track of which zones cannot accept any more records.
Packit Service 310c69
  bool fullFlags[MAX_ZONES] = { false, };
Packit Service 310c69
Packit Service 310c69
  // Assign records to the correct zones.
Packit Service 310c69
  UdsChunkRecord record;
Packit Service 310c69
  uint32_t records;
Packit Service 310c69
  for (records = 0; records < numRecords; records++) {
Packit Service 310c69
    result = readFromBufferedReader(reader, &record, sizeof(UdsChunkRecord));
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    unsigned int zone = 0;
Packit Service 310c69
    if (index->zoneCount > 1) {
Packit Service 310c69
      // A read-only index has no master index, but it also has only one zone.
Packit Service 310c69
      zone = getMasterIndexZone(index->masterIndex, &record.name);
Packit Service 310c69
    }
Packit Service 310c69
    // Add records until the open chapter zone almost runs out of space.
Packit Service 310c69
    // The chapter can't be closed here, so don't add the last record.
Packit Service 310c69
    if (!fullFlags[zone]) {
Packit Service 310c69
      unsigned int remaining;
Packit Service 310c69
      result = putOpenChapter(index->zones[zone]->openChapter,
Packit Service 310c69
                              &record.name, &record.data, &remaining);
Packit Service 310c69
      fullFlags[zone] = (remaining <= 1);
Packit Service 310c69
      if (result != UDS_SUCCESS) {
Packit Service 310c69
        return result;
Packit Service 310c69
      }
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int loadOpenChapters(Index *index, BufferedReader *reader)
Packit Service 310c69
{
Packit Service 310c69
  // Read and check the magic number.
Packit Service 310c69
  int result =
Packit Service 310c69
    verifyBufferedData(reader, OPEN_CHAPTER_MAGIC, OPEN_CHAPTER_MAGIC_LENGTH);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Read and check the version.
Packit Service 310c69
  const byte *version = NULL;
Packit Service 310c69
  result = readVersion(reader, &version);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return loadVersion20(index, reader);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int readOpenChapters(ReadPortal *portal)
Packit Service 310c69
{
Packit Service 310c69
  Index *index = indexComponentData(portal->component);
Packit Service 310c69
Packit Service 310c69
  BufferedReader *reader;
Packit Service 310c69
  int result = getBufferedReaderForPortal(portal, 0, &reader);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  return loadOpenChapters(index, reader);
Packit Service 310c69
}