Blame source/uds/indexPageMap.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/indexPageMap.c#4 $
Packit Service 310c69
 */
Packit Service 310c69
Packit Service 310c69
#include "indexPageMap.h"
Packit Service 310c69
Packit Service 310c69
#include "buffer.h"
Packit Service 310c69
#include "bufferedWriter.h"
Packit Service 310c69
#include "compiler.h"
Packit Service 310c69
#include "errors.h"
Packit Service 310c69
#include "hashUtils.h"
Packit Service 310c69
#include "indexComponent.h"
Packit Service 310c69
#include "logger.h"
Packit Service 310c69
#include "memoryAlloc.h"
Packit Service 310c69
#include "permassert.h"
Packit Service 310c69
#include "stringUtils.h"
Packit Service 310c69
#include "threads.h"
Packit Service 310c69
#include "uds.h"
Packit Service 310c69
Packit Service 310c69
static int readIndexPageMap(ReadPortal *portal);
Packit Service 310c69
static int writeIndexPageMap(IndexComponent *component,
Packit Service 310c69
                             BufferedWriter *writer,
Packit Service 310c69
                             unsigned int    zone);
Packit Service 310c69
Packit Service 310c69
static const byte INDEX_PAGE_MAP_MAGIC[] = "ALBIPM02";
Packit Service 310c69
enum {
Packit Service 310c69
  INDEX_PAGE_MAP_MAGIC_LENGTH = sizeof(INDEX_PAGE_MAP_MAGIC) - 1,
Packit Service 310c69
};
Packit Service 310c69
Packit Service 310c69
const IndexComponentInfo INDEX_PAGE_MAP_INFO = {
Packit Service 310c69
  .kind        = RL_KIND_INDEX_PAGE_MAP,
Packit Service 310c69
  .name        = "index page map",
Packit Service 310c69
  .saveOnly    = false,
Packit Service 310c69
  .chapterSync = true,
Packit Service 310c69
  .multiZone   = false,
Packit Service 310c69
  .ioStorage   = true,
Packit Service 310c69
  .loader      = readIndexPageMap,
Packit Service 310c69
  .saver       = writeIndexPageMap,
Packit Service 310c69
  .incremental = NULL,
Packit Service 310c69
};
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
static INLINE size_t numEntries(const Geometry *geometry)
Packit Service 310c69
{
Packit Service 310c69
  return geometry->chaptersPerVolume * (geometry->indexPagesPerChapter - 1);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
int makeIndexPageMap(const Geometry *geometry, IndexPageMap **mapPtr)
Packit Service 310c69
{
Packit Service 310c69
  unsigned int deltaListsPerChapter = geometry->deltaListsPerChapter;
Packit Service 310c69
  int result
Packit Service 310c69
    = ASSERT_WITH_ERROR_CODE(((deltaListsPerChapter - 1) <= UINT16_MAX),
Packit Service 310c69
                             UDS_BAD_STATE,
Packit Service 310c69
                             "delta lists per chapter (%u) is too large",
Packit Service 310c69
                             deltaListsPerChapter);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  IndexPageMap *map;
Packit Service 310c69
  result = ALLOCATE(1, IndexPageMap, "Index Page Map", &map);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  map->geometry = geometry;
Packit Service 310c69
Packit Service 310c69
  result = ALLOCATE(numEntries(geometry),
Packit Service 310c69
                    IndexPageMapEntry,
Packit Service 310c69
                    "Index Page Map Entries",
Packit Service 310c69
                    &map->entries);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeIndexPageMap(map);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  *mapPtr = map;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
void freeIndexPageMap(IndexPageMap *map)
Packit Service 310c69
{
Packit Service 310c69
  if (map != NULL) {
Packit Service 310c69
    FREE(map->entries);
Packit Service 310c69
    FREE(map);
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
uint64_t getLastUpdate(const IndexPageMap *map)
Packit Service 310c69
{
Packit Service 310c69
  return map->lastUpdate;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
int updateIndexPageMap(IndexPageMap   *map,
Packit Service 310c69
                       uint64_t        virtualChapterNumber,
Packit Service 310c69
                       unsigned int    chapterNumber,
Packit Service 310c69
                       unsigned int    indexPageNumber,
Packit Service 310c69
                       unsigned int    deltaListNumber)
Packit Service 310c69
{
Packit Service 310c69
  const Geometry *geometry = map->geometry;
Packit Service 310c69
  if ((virtualChapterNumber < map->lastUpdate)
Packit Service 310c69
      || (virtualChapterNumber > map->lastUpdate + 1)) {
Packit Service 310c69
    // if the lastUpdate is 0, this is likely to be normal because we are
Packit Service 310c69
    // replaying the volume
Packit Service 310c69
    if (map->lastUpdate != 0) {
Packit Service 310c69
      logWarning("unexpected index page map update, jumping from %" PRIu64
Packit Service 310c69
                 " to %llu",
Packit Service 310c69
                 map->lastUpdate, virtualChapterNumber);
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
  map->lastUpdate = virtualChapterNumber;
Packit Service 310c69
Packit Service 310c69
  if (chapterNumber >= geometry->chaptersPerVolume) {
Packit Service 310c69
    return logErrorWithStringError(
Packit Service 310c69
      UDS_INVALID_ARGUMENT, "chapter number %u exceeds maximum %u",
Packit Service 310c69
      chapterNumber, geometry->chaptersPerVolume - 1);
Packit Service 310c69
  }
Packit Service 310c69
  if (indexPageNumber >= geometry->indexPagesPerChapter) {
Packit Service 310c69
    return logErrorWithStringError(
Packit Service 310c69
      UDS_INVALID_ARGUMENT, "index page number %u exceeds maximum %u",
Packit Service 310c69
      indexPageNumber, geometry->indexPagesPerChapter - 1);
Packit Service 310c69
  }
Packit Service 310c69
  if (deltaListNumber >= geometry->deltaListsPerChapter) {
Packit Service 310c69
    return logErrorWithStringError(
Packit Service 310c69
      UDS_INVALID_ARGUMENT, "delta list number %u exceeds maximum %u",
Packit Service 310c69
      deltaListNumber, geometry->deltaListsPerChapter - 1);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (indexPageNumber == (geometry->indexPagesPerChapter - 1)) {
Packit Service 310c69
    /*
Packit Service 310c69
     * There is no entry for the last index page of a chapter since its entry
Packit Service 310c69
     * would always be geometry->deltaListsPerChapter - 1.
Packit Service 310c69
     */
Packit Service 310c69
    return UDS_SUCCESS;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  size_t slot
Packit Service 310c69
    = (chapterNumber * (geometry->indexPagesPerChapter - 1)) + indexPageNumber;
Packit Service 310c69
  map->entries[slot] = (IndexPageMapEntry) deltaListNumber;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
int findIndexPageNumber(const IndexPageMap *map,
Packit Service 310c69
                        const UdsChunkName *name,
Packit Service 310c69
                        unsigned int        chapterNumber,
Packit Service 310c69
                        unsigned int       *indexPageNumberPtr)
Packit Service 310c69
{
Packit Service 310c69
  const Geometry *geometry = map->geometry;
Packit Service 310c69
  if (chapterNumber >= geometry->chaptersPerVolume) {
Packit Service 310c69
    return logErrorWithStringError(
Packit Service 310c69
      UDS_INVALID_ARGUMENT, "chapter number %u exceeds maximum %u",
Packit Service 310c69
      chapterNumber, geometry->chaptersPerVolume - 1);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  unsigned int deltaListNumber = hashToChapterDeltaList(name, geometry);
Packit Service 310c69
  unsigned int slot = (chapterNumber * (geometry->indexPagesPerChapter - 1));
Packit Service 310c69
  unsigned int limit = slot + (geometry->indexPagesPerChapter - 1);
Packit Service 310c69
  unsigned int indexPageNumber = 0;
Packit Service 310c69
  for (; slot < limit; indexPageNumber++, slot++) {
Packit Service 310c69
    if (deltaListNumber <= map->entries[slot]) {
Packit Service 310c69
      break;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // This should be a clear post-condition of the loop above, but just in case
Packit Service 310c69
  // it's not obvious, the check is cheap.
Packit Service 310c69
  int result = ASSERT((indexPageNumber < geometry->indexPagesPerChapter),
Packit Service 310c69
                      "index page number too large");
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  *indexPageNumberPtr = indexPageNumber;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int getListNumberBounds(const IndexPageMap *map,
Packit Service 310c69
                        unsigned int        chapterNumber,
Packit Service 310c69
                        unsigned int        indexPageNumber,
Packit Service 310c69
                        IndexPageBounds    *bounds)
Packit Service 310c69
{
Packit Service 310c69
  const Geometry *geometry = map->geometry;
Packit Service 310c69
  int result = ASSERT((chapterNumber < geometry->chaptersPerVolume),
Packit Service 310c69
                      "chapter number is valid");
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = ASSERT((indexPageNumber < geometry->indexPagesPerChapter),
Packit Service 310c69
                  "index page number is valid");
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  unsigned int slot = chapterNumber * (geometry->indexPagesPerChapter - 1);
Packit Service 310c69
  bounds->lowestList = ((indexPageNumber == 0)
Packit Service 310c69
                        ? 0
Packit Service 310c69
                        : map->entries[slot + indexPageNumber - 1] + 1);
Packit Service 310c69
  bounds->highestList = ((indexPageNumber == geometry->indexPagesPerChapter - 1)
Packit Service 310c69
                         ? geometry->deltaListsPerChapter - 1
Packit Service 310c69
                         : map->entries[slot + indexPageNumber]);
Packit Service 310c69
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
size_t indexPageMapSize(const Geometry *geometry)
Packit Service 310c69
{
Packit Service 310c69
  return sizeof(IndexPageMapEntry) * numEntries(geometry);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
static int writeIndexPageMap(IndexComponent *component,
Packit Service 310c69
                             BufferedWriter *writer,
Packit Service 310c69
                             unsigned int    zone)
Packit Service 310c69
{
Packit Service 310c69
  int result = ASSERT((zone == 0), "unimplemented zone %d", zone);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  IndexPageMap *map = indexComponentData(component);
Packit Service 310c69
Packit Service 310c69
  Buffer *buffer;
Packit Service 310c69
  result = makeBuffer(INDEX_PAGE_MAP_MAGIC_LENGTH + sizeof(map->lastUpdate),
Packit Service 310c69
                      &buffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putBytes(buffer, INDEX_PAGE_MAP_MAGIC_LENGTH, INDEX_PAGE_MAP_MAGIC);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeBuffer(&buffer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt64LEIntoBuffer(buffer, map->lastUpdate);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeBuffer(&buffer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = writeToBufferedWriter(writer, getBufferContents(buffer),
Packit Service 310c69
                                 contentLength(buffer));
Packit Service 310c69
  freeBuffer(&buffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return logErrorWithStringError(result,
Packit Service 310c69
                                   "cannot write index page map header");
Packit Service 310c69
  }
Packit Service 310c69
  result = makeBuffer(indexPageMapSize(map->geometry), &buffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result
Packit Service 310c69
    = putUInt16LEsIntoBuffer(buffer, numEntries(map->geometry), map->entries);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeBuffer(&buffer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = writeToBufferedWriter(writer, getBufferContents(buffer),
Packit Service 310c69
                                 contentLength(buffer));
Packit Service 310c69
  freeBuffer(&buffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return logErrorWithStringError(result,
Packit Service 310c69
                                   "cannot write index page map data");
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
uint64_t computeIndexPageMapSaveSize(const Geometry *geometry)
Packit Service 310c69
{
Packit Service 310c69
  return indexPageMapSize(geometry) +
Packit Service 310c69
    INDEX_PAGE_MAP_MAGIC_LENGTH + sizeof(((IndexPageMap *) 0)->lastUpdate);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int decodeIndexPageMap(Buffer *buffer, IndexPageMap *map)
Packit Service 310c69
{
Packit Service 310c69
  int result = getUInt64LEFromBuffer(buffer, &map->lastUpdate);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt16LEsFromBuffer(buffer, numEntries(map->geometry),
Packit Service 310c69
                                  map->entries);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = ASSERT_LOG_ONLY(contentLength(buffer) == 0,
Packit Service 310c69
                           "%zu bytes decoded of %zu expected",
Packit Service 310c69
                           bufferLength(buffer) - contentLength(buffer),
Packit Service 310c69
                           bufferLength(buffer));
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
static int readIndexPageMap(ReadPortal *portal)
Packit Service 310c69
{
Packit Service 310c69
  IndexPageMap *map = indexComponentData(portal->component);
Packit Service 310c69
Packit Service 310c69
  BufferedReader *reader = NULL;
Packit Service 310c69
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
Packit Service 310c69
  result = verifyBufferedData(reader, INDEX_PAGE_MAP_MAGIC,
Packit Service 310c69
                              INDEX_PAGE_MAP_MAGIC_LENGTH);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return logErrorWithStringError(result, "bad index page map saved magic");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  Buffer *buffer;
Packit Service 310c69
  result
Packit Service 310c69
    = makeBuffer(sizeof(map->lastUpdate) + indexPageMapSize(map->geometry),
Packit Service 310c69
                 &buffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = readFromBufferedReader(reader, getBufferContents(buffer),
Packit Service 310c69
                                  bufferLength(buffer));
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeBuffer(&buffer);
Packit Service 310c69
    logErrorWithStringError(result, "cannot read index page map data");
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = resetBufferEnd(buffer, bufferLength(buffer));
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeBuffer(&buffer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = decodeIndexPageMap(buffer, map);
Packit Service 310c69
  freeBuffer(&buffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  logDebug("read index page map, last update %llu", map->lastUpdate);
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}