Blame source/uds/chapterIndex.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/chapterIndex.c#5 $
Packit Service 310c69
 */
Packit Service 310c69
Packit Service 310c69
#include "chapterIndex.h"
Packit Service 310c69
Packit Service 310c69
#include "compiler.h"
Packit Service 310c69
#include "errors.h"
Packit Service 310c69
#include "hashUtils.h"
Packit Service 310c69
#include "logger.h"
Packit Service 310c69
#include "memoryAlloc.h"
Packit Service 310c69
#include "permassert.h"
Packit Service 310c69
#include "uds.h"
Packit Service 310c69
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int makeOpenChapterIndex(OpenChapterIndex **openChapterIndex,
Packit Service 310c69
                         const Geometry    *geometry,
Packit Service 310c69
                         bool               chapterIndexHeaderNativeEndian,
Packit Service 310c69
                         uint64_t           volumeNonce)
Packit Service 310c69
{
Packit Service 310c69
Packit Service 310c69
  int result = ALLOCATE(1, OpenChapterIndex, "open chapter index",
Packit Service 310c69
                        openChapterIndex);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // The delta index will rebalance delta lists when memory gets tight, so
Packit Service 310c69
  // give the chapter index one extra page.
Packit Service 310c69
  size_t memorySize
Packit Service 310c69
    = (geometry->indexPagesPerChapter + 1) * geometry->bytesPerPage;
Packit Service 310c69
  (*openChapterIndex)->geometry           = geometry;
Packit Service 310c69
  (*openChapterIndex)->volumeNonce        = volumeNonce;
Packit Service 310c69
  (*openChapterIndex)->headerNativeEndian = chapterIndexHeaderNativeEndian,
Packit Service 310c69
  result = initializeDeltaIndex(&(*openChapterIndex)->deltaIndex, 1,
Packit Service 310c69
                                geometry->deltaListsPerChapter,
Packit Service 310c69
                                geometry->chapterMeanDelta,
Packit Service 310c69
                                geometry->chapterPayloadBits, memorySize);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    FREE(*openChapterIndex);
Packit Service 310c69
    *openChapterIndex                     = NULL;
Packit Service 310c69
  }
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void freeOpenChapterIndex(OpenChapterIndex *openChapterIndex)
Packit Service 310c69
{
Packit Service 310c69
  if (openChapterIndex == NULL) {
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
Packit Service 310c69
  uninitializeDeltaIndex(&openChapterIndex->deltaIndex);
Packit Service 310c69
  FREE(openChapterIndex);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void emptyOpenChapterIndex(OpenChapterIndex *openChapterIndex,
Packit Service 310c69
                           uint64_t          virtualChapterNumber)
Packit Service 310c69
{
Packit Service 310c69
  emptyDeltaIndex(&openChapterIndex->deltaIndex);
Packit Service 310c69
  openChapterIndex->virtualChapterNumber = virtualChapterNumber;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Check whether a delta list entry reflects a successful search for a given
Packit Service 310c69
 * address.
Packit Service 310c69
 *
Packit Service 310c69
 * @param entry    the delta list entry from the search
Packit Service 310c69
 * @param address  the address of the desired entry
Packit Service 310c69
 *
Packit Service 310c69
 * @return true iff the address was found
Packit Service 310c69
 **/
Packit Service 310c69
static INLINE bool wasEntryFound(const DeltaIndexEntry *entry,
Packit Service 310c69
                                 unsigned int           address)
Packit Service 310c69
{
Packit Service 310c69
  return (!entry->atEnd && (entry->key == address));
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int putOpenChapterIndexRecord(OpenChapterIndex   *openChapterIndex,
Packit Service 310c69
                              const UdsChunkName *name,
Packit Service 310c69
                              unsigned int        pageNumber)
Packit Service 310c69
{
Packit Service 310c69
  const Geometry *geometry = openChapterIndex->geometry;
Packit Service 310c69
  int result
Packit Service 310c69
    = ASSERT_WITH_ERROR_CODE(pageNumber < geometry->recordPagesPerChapter,
Packit Service 310c69
                             UDS_INVALID_ARGUMENT,
Packit Service 310c69
                             "Page number within chapter (%u) exceeds"
Packit Service 310c69
                             " the maximum value %u",
Packit Service 310c69
                             pageNumber, geometry->recordPagesPerChapter);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  DeltaIndexEntry entry;
Packit Service 310c69
  unsigned int address = hashToChapterDeltaAddress(name, geometry);
Packit Service 310c69
  result = getDeltaIndexEntry(&openChapterIndex->deltaIndex,
Packit Service 310c69
                              hashToChapterDeltaList(name, geometry),
Packit Service 310c69
                              address, name->name, false, &entry);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  bool found = wasEntryFound(&entry, address);
Packit Service 310c69
  result = ASSERT_WITH_ERROR_CODE(!(found && entry.isCollision),
Packit Service 310c69
                                  UDS_BAD_STATE,
Packit Service 310c69
                                  "Chunk appears more than once in chapter %"
Packit Service 310c69
                                  PRIu64,
Packit Service 310c69
                                  openChapterIndex->virtualChapterNumber);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  return putDeltaIndexEntry(&entry, address, pageNumber,
Packit Service 310c69
                            (found ? name->name : NULL));
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int packOpenChapterIndexPage(OpenChapterIndex *openChapterIndex,
Packit Service 310c69
                             byte             *memory,
Packit Service 310c69
                             unsigned int      firstList,
Packit Service 310c69
                             bool              lastPage,
Packit Service 310c69
                             unsigned int     *numLists)
Packit Service 310c69
{
Packit Service 310c69
  DeltaIndex *deltaIndex = &openChapterIndex->deltaIndex;
Packit Service 310c69
  const Geometry *geometry = openChapterIndex->geometry;
Packit Service 310c69
  unsigned int removals = 0;
Packit Service 310c69
  for (;;) {
Packit Service 310c69
    int result = packDeltaIndexPage(deltaIndex, openChapterIndex->volumeNonce,
Packit Service 310c69
                                    openChapterIndex->headerNativeEndian,
Packit Service 310c69
                                    memory, geometry->bytesPerPage,
Packit Service 310c69
                                    openChapterIndex->virtualChapterNumber,
Packit Service 310c69
                                    firstList, numLists);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
    if ((firstList + *numLists) == geometry->deltaListsPerChapter) {
Packit Service 310c69
      // All lists are packed
Packit Service 310c69
      break;
Packit Service 310c69
    } else if (*numLists == 0) {
Packit Service 310c69
      // The next delta list does not fit on a page.  This delta list will
Packit Service 310c69
      // be removed.
Packit Service 310c69
    } else if (lastPage) {
Packit Service 310c69
      /*
Packit Service 310c69
       * This is the last page and there are lists left unpacked, but all of
Packit Service 310c69
       * the remaining lists must fit on the page. Find a list that contains
Packit Service 310c69
       * entries and remove the entire list. Try the first list that does not
Packit Service 310c69
       * fit. If it is empty, we will select the last list that already fits
Packit Service 310c69
       * and has any entries.
Packit Service 310c69
       */
Packit Service 310c69
    } else {
Packit Service 310c69
      // This page is done
Packit Service 310c69
      break;
Packit Service 310c69
    }
Packit Service 310c69
    if (removals == 0) {
Packit Service 310c69
      DeltaIndexStats stats;
Packit Service 310c69
      getDeltaIndexStats(deltaIndex, &stats);
Packit Service 310c69
      logWarning("The chapter index for chapter %" PRIu64
Packit Service 310c69
                 " contains %ld entries with %ld collisions",
Packit Service 310c69
                 openChapterIndex->virtualChapterNumber,
Packit Service 310c69
                 stats.recordCount, stats.collisionCount);
Packit Service 310c69
    }
Packit Service 310c69
    DeltaIndexEntry entry;
Packit Service 310c69
    int listNumber = *numLists;
Packit Service 310c69
    do {
Packit Service 310c69
      if (listNumber < 0) {
Packit Service 310c69
        return UDS_OVERFLOW;
Packit Service 310c69
      }
Packit Service 310c69
      result = startDeltaIndexSearch(deltaIndex, firstList + listNumber--,
Packit Service 310c69
                                     0, false, &entry);
Packit Service 310c69
      if (result != UDS_SUCCESS) {
Packit Service 310c69
        return result;
Packit Service 310c69
      }
Packit Service 310c69
      result = nextDeltaIndexEntry(&entry);
Packit Service 310c69
      if (result != UDS_SUCCESS) {
Packit Service 310c69
        return result;
Packit Service 310c69
      }
Packit Service 310c69
    } while (entry.atEnd);
Packit Service 310c69
    do {
Packit Service 310c69
      result = removeDeltaIndexEntry(&entry);
Packit Service 310c69
      if (result != UDS_SUCCESS) {
Packit Service 310c69
        return result;
Packit Service 310c69
      }
Packit Service 310c69
      removals++;
Packit Service 310c69
    } while (!entry.atEnd);
Packit Service 310c69
  }
Packit Service 310c69
  if (removals > 0) {
Packit Service 310c69
    logWarning("To avoid chapter index page overflow in chapter %" PRIu64
Packit Service 310c69
               ", %u entries were removed from the chapter index",
Packit Service 310c69
               openChapterIndex->virtualChapterNumber, removals);
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int getOpenChapterIndexSize(OpenChapterIndex *openChapterIndex)
Packit Service 310c69
{
Packit Service 310c69
  DeltaIndexStats stats;
Packit Service 310c69
  getDeltaIndexStats(&openChapterIndex->deltaIndex, &stats);
Packit Service 310c69
  return stats.recordCount;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
size_t getOpenChapterIndexMemoryAllocated(OpenChapterIndex *openChapterIndex)
Packit Service 310c69
{
Packit Service 310c69
  DeltaIndexStats stats;
Packit Service 310c69
  getDeltaIndexStats(&openChapterIndex->deltaIndex, &stats);
Packit Service 310c69
  return stats.memoryAllocated + sizeof(OpenChapterIndex);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int initializeChapterIndexPage(DeltaIndexPage *chapterIndexPage,
Packit Service 310c69
                               const Geometry *geometry,
Packit Service 310c69
                               byte           *indexPage,
Packit Service 310c69
                               uint64_t        volumeNonce)
Packit Service 310c69
{
Packit Service 310c69
  return initializeDeltaIndexPage(chapterIndexPage, volumeNonce,
Packit Service 310c69
                                  geometry->chapterMeanDelta,
Packit Service 310c69
                                  geometry->chapterPayloadBits,
Packit Service 310c69
                                  indexPage, geometry->bytesPerPage);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int validateChapterIndexPage(const DeltaIndexPage *chapterIndexPage,
Packit Service 310c69
                             const Geometry       *geometry)
Packit Service 310c69
{
Packit Service 310c69
  const DeltaIndex *deltaIndex = &chapterIndexPage->deltaIndex;
Packit Service 310c69
  unsigned int first = chapterIndexPage->lowestListNumber;
Packit Service 310c69
  unsigned int last  = chapterIndexPage->highestListNumber;
Packit Service 310c69
  // We walk every delta list from start to finish.
Packit Service 310c69
  unsigned int listNumber;
Packit Service 310c69
  for (listNumber = first; listNumber <= last; listNumber++) {
Packit Service 310c69
    DeltaIndexEntry entry;
Packit Service 310c69
    int result = startDeltaIndexSearch(deltaIndex, listNumber - first, 0, true,
Packit Service 310c69
                                       &entry);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
    for (;;) {
Packit Service 310c69
      result = nextDeltaIndexEntry(&entry);
Packit Service 310c69
      if (result != UDS_SUCCESS) {
Packit Service 310c69
        if (result == UDS_CORRUPT_DATA) {
Packit Service 310c69
          // A random bit stream is highly likely to arrive here when we go
Packit Service 310c69
          // past the end of the delta list
Packit Service 310c69
          return UDS_CORRUPT_COMPONENT;
Packit Service 310c69
        }
Packit Service 310c69
        return result;
Packit Service 310c69
      }
Packit Service 310c69
      if (entry.atEnd) {
Packit Service 310c69
        break;
Packit Service 310c69
      }
Packit Service 310c69
      // Also make sure that the record page field contains a plausible value
Packit Service 310c69
      if (getDeltaEntryValue(&entry) >= geometry->recordPagesPerChapter) {
Packit Service 310c69
        // Do not log this as an error.  It happens in normal operation when
Packit Service 310c69
        // we are doing a rebuild but haven't written the entire volume once.
Packit Service 310c69
        return UDS_CORRUPT_COMPONENT;
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 searchChapterIndexPage(DeltaIndexPage     *chapterIndexPage,
Packit Service 310c69
                           const Geometry     *geometry,
Packit Service 310c69
                           const UdsChunkName *name,
Packit Service 310c69
                           int                *recordPagePtr)
Packit Service 310c69
{
Packit Service 310c69
  DeltaIndex *deltaIndex = &chapterIndexPage->deltaIndex;
Packit Service 310c69
  unsigned int address = hashToChapterDeltaAddress(name, geometry);
Packit Service 310c69
  unsigned int deltaListNumber = hashToChapterDeltaList(name, geometry);
Packit Service 310c69
  unsigned int subListNumber
Packit Service 310c69
    = deltaListNumber - chapterIndexPage->lowestListNumber;;
Packit Service 310c69
  DeltaIndexEntry entry;
Packit Service 310c69
  int result = getDeltaIndexEntry(deltaIndex, subListNumber, address,
Packit Service 310c69
                                  name->name, true, &entry);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (wasEntryFound(&entry, address)) {
Packit Service 310c69
    *recordPagePtr = getDeltaEntryValue(&entry);
Packit Service 310c69
  } else {
Packit Service 310c69
    *recordPagePtr = NO_CHAPTER_INDEX_ENTRY;
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}