Blame source/uds/index.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/index.c#15 $
Packit Service 310c69
 */
Packit Service 310c69
Packit Service 310c69
#include "index.h"
Packit Service 310c69
Packit Service 310c69
#include "hashUtils.h"
Packit Service 310c69
#include "indexCheckpoint.h"
Packit Service 310c69
#include "indexInternals.h"
Packit Service 310c69
#include "logger.h"
Packit Service 310c69
Packit Service 310c69
static const uint64_t NO_LAST_CHECKPOINT = UINT_MAX;
Packit Service 310c69
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Replay an index which was loaded from a checkpoint.
Packit Service 310c69
 *
Packit Service 310c69
 * @param index                 The index to replay
Packit Service 310c69
 * @param lastCheckpointChapter The number of the chapter where the
Packit Service 310c69
 *                              last checkpoint was made
Packit Service 310c69
 *
Packit Service 310c69
 * @return UDS_SUCCESS or an error code.
Packit Service 310c69
 **/
Packit Service 310c69
static int replayIndexFromCheckpoint(Index *index,
Packit Service 310c69
                                     uint64_t lastCheckpointChapter)
Packit Service 310c69
{
Packit Service 310c69
  // Find the volume chapter boundaries
Packit Service 310c69
  uint64_t lowestVCN, highestVCN;
Packit Service 310c69
  bool isEmpty = false;
Packit Service 310c69
  IndexLookupMode oldLookupMode = index->volume->lookupMode;
Packit Service 310c69
  index->volume->lookupMode = LOOKUP_FOR_REBUILD;
Packit Service 310c69
  int result = findVolumeChapterBoundaries(index->volume, &lowestVCN,
Packit Service 310c69
                                           &highestVCN, &isEmpty);
Packit Service 310c69
  index->volume->lookupMode = oldLookupMode;
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return logFatalWithStringError(result,
Packit Service 310c69
                                   "cannot replay index: "
Packit Service 310c69
                                   "unknown volume chapter boundaries");
Packit Service 310c69
  }
Packit Service 310c69
  if (lowestVCN > highestVCN) {
Packit Service 310c69
    logFatal("cannot replay index: no valid chapters exist");
Packit Service 310c69
    return UDS_CORRUPT_COMPONENT;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (isEmpty) {
Packit Service 310c69
    // The volume is empty, so the index should also be empty
Packit Service 310c69
    if (index->newestVirtualChapter != 0) {
Packit Service 310c69
      logFatal("cannot replay index from empty volume");
Packit Service 310c69
      return UDS_CORRUPT_COMPONENT;
Packit Service 310c69
    }
Packit Service 310c69
    return UDS_SUCCESS;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  unsigned int chaptersPerVolume = index->volume->geometry->chaptersPerVolume;
Packit Service 310c69
  index->oldestVirtualChapter = lowestVCN;
Packit Service 310c69
  index->newestVirtualChapter = highestVCN + 1;
Packit Service 310c69
  if (index->newestVirtualChapter == lowestVCN + chaptersPerVolume) {
Packit Service 310c69
    // skip the chapter shadowed by the open chapter
Packit Service 310c69
    index->oldestVirtualChapter++;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  uint64_t firstReplayChapter = lastCheckpointChapter;
Packit Service 310c69
  if (firstReplayChapter < index->oldestVirtualChapter) {
Packit Service 310c69
    firstReplayChapter = index->oldestVirtualChapter;
Packit Service 310c69
  }
Packit Service 310c69
  return replayVolume(index, firstReplayChapter);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static int loadIndex(Index *index, bool allowReplay)
Packit Service 310c69
{
Packit Service 310c69
  bool replayRequired = false;
Packit Service 310c69
Packit Service 310c69
  int result = loadIndexState(index->state, &replayRequired);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (replayRequired && !allowReplay) {
Packit Service 310c69
    return logErrorWithStringError(
Packit Service 310c69
      UDS_INDEX_NOT_SAVED_CLEANLY,
Packit Service 310c69
      "index not saved cleanly: open chapter missing");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  uint64_t lastCheckpointChapter
Packit Service 310c69
    = ((index->lastCheckpoint != NO_LAST_CHECKPOINT)
Packit Service 310c69
       ? index->lastCheckpoint : 0);
Packit Service 310c69
Packit Service 310c69
  logInfo("loaded index from chapter %llu through chapter %llu",
Packit Service 310c69
          index->oldestVirtualChapter, lastCheckpointChapter);
Packit Service 310c69
Packit Service 310c69
  if (replayRequired) {
Packit Service 310c69
    result = replayIndexFromCheckpoint(index, lastCheckpointChapter);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  unsigned int i;
Packit Service 310c69
  for (i = 0; i < index->zoneCount; i++) {
Packit Service 310c69
    setActiveChapters(index->zones[i]);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  index->loadedType = replayRequired ? LOAD_REPLAY : LOAD_LOAD;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static int rebuildIndex(Index *index)
Packit Service 310c69
{
Packit Service 310c69
  // Find the volume chapter boundaries
Packit Service 310c69
  uint64_t lowestVCN, highestVCN;
Packit Service 310c69
  bool isEmpty = false;
Packit Service 310c69
  IndexLookupMode oldLookupMode = index->volume->lookupMode;
Packit Service 310c69
  index->volume->lookupMode = LOOKUP_FOR_REBUILD;
Packit Service 310c69
  int result = findVolumeChapterBoundaries(index->volume, &lowestVCN,
Packit Service 310c69
                                           &highestVCN, &isEmpty);
Packit Service 310c69
  index->volume->lookupMode = oldLookupMode;
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return logFatalWithStringError(result,
Packit Service 310c69
                                   "cannot rebuild index: "
Packit Service 310c69
                                   "unknown volume chapter boundaries");
Packit Service 310c69
  }
Packit Service 310c69
  if (lowestVCN > highestVCN) {
Packit Service 310c69
    logFatal("cannot rebuild index: no valid chapters exist");
Packit Service 310c69
    return UDS_CORRUPT_COMPONENT;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (isEmpty) {
Packit Service 310c69
    index->newestVirtualChapter = index->oldestVirtualChapter = 0;
Packit Service 310c69
  } else {
Packit Service 310c69
    unsigned int numChapters = index->volume->geometry->chaptersPerVolume;
Packit Service 310c69
    index->newestVirtualChapter = highestVCN + 1;
Packit Service 310c69
    index->oldestVirtualChapter = lowestVCN;
Packit Service 310c69
    if (index->newestVirtualChapter
Packit Service 310c69
        == (index->oldestVirtualChapter + numChapters)) {
Packit Service 310c69
      // skip the chapter shadowed by the open chapter
Packit Service 310c69
      index->oldestVirtualChapter++;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if ((index->newestVirtualChapter - index->oldestVirtualChapter) >
Packit Service 310c69
      index->volume->geometry->chaptersPerVolume) {
Packit Service 310c69
    return logFatalWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                   "cannot rebuild index: "
Packit Service 310c69
                                   "volume chapter boundaries too large");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  setMasterIndexOpenChapter(index->masterIndex, 0);
Packit Service 310c69
  if (isEmpty) {
Packit Service 310c69
    index->loadedType = LOAD_EMPTY;
Packit Service 310c69
    return UDS_SUCCESS;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = replayVolume(index, index->oldestVirtualChapter);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  unsigned int i;
Packit Service 310c69
  for (i = 0; i < index->zoneCount; i++) {
Packit Service 310c69
    setActiveChapters(index->zones[i]);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  index->loadedType = LOAD_REBUILD;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int makeIndex(IndexLayout                  *layout,
Packit Service 310c69
              const Configuration          *config,
Packit Service 310c69
              const struct uds_parameters  *userParams,
Packit Service 310c69
              unsigned int                  zoneCount,
Packit Service 310c69
              LoadType                      loadType,
Packit Service 310c69
              IndexLoadContext             *loadContext,
Packit Service 310c69
              Index                       **newIndex)
Packit Service 310c69
{
Packit Service 310c69
  Index *index;
Packit Service 310c69
  int result = allocateIndex(layout, config, userParams, zoneCount, loadType,
Packit Service 310c69
                             &index);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return logErrorWithStringError(result, "could not allocate index");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  index->loadContext = loadContext;
Packit Service 310c69
Packit Service 310c69
  uint64_t nonce = getVolumeNonce(layout);
Packit Service 310c69
  result = makeMasterIndex(config, zoneCount, nonce, &index->masterIndex);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeIndex(index);
Packit Service 310c69
    return logErrorWithStringError(result, "could not make master index");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = addIndexStateComponent(index->state, MASTER_INDEX_INFO, NULL,
Packit Service 310c69
                                  index->masterIndex);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeIndex(index);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = addIndexStateComponent(index->state, &INDEX_PAGE_MAP_INFO,
Packit Service 310c69
                                  index->volume->indexPageMap, NULL);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeIndex(index);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = makeChapterWriter(index, getIndexVersion(layout),
Packit Service 310c69
                             &index->chapterWriter);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeIndex(index);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if ((loadType == LOAD_LOAD) || (loadType == LOAD_REBUILD)) {
Packit Service 310c69
    if (!index->existed) {
Packit Service 310c69
      freeIndex(index);
Packit Service 310c69
      return UDS_NO_INDEX;
Packit Service 310c69
    }
Packit Service 310c69
    result = loadIndex(index, loadType == LOAD_REBUILD);
Packit Service 310c69
    switch (result) {
Packit Service 310c69
    case UDS_SUCCESS:
Packit Service 310c69
      break;
Packit Service 310c69
    case ENOMEM:
Packit Service 310c69
      // We should not try a rebuild for this error.
Packit Service 310c69
      logErrorWithStringError(result, "index could not be loaded");
Packit Service 310c69
      break;
Packit Service 310c69
    default:
Packit Service 310c69
      logErrorWithStringError(result, "index could not be loaded");
Packit Service 310c69
      if (loadType == LOAD_REBUILD) {
Packit Service 310c69
        result = rebuildIndex(index);
Packit Service 310c69
        if (result != UDS_SUCCESS) {
Packit Service 310c69
          logErrorWithStringError(result, "index could not be rebuilt");
Packit Service 310c69
        }
Packit Service 310c69
      }
Packit Service 310c69
      break;
Packit Service 310c69
    }
Packit Service 310c69
  } else {
Packit Service 310c69
    index->loadedType = LOAD_CREATE;
Packit Service 310c69
    discardIndexStateData(index->state);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeIndex(index);
Packit Service 310c69
    return logUnrecoverable(result, "fatal error in makeIndex");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (index->loadContext != NULL) {
Packit Service 310c69
    lockMutex(&index->loadContext->mutex);
Packit Service 310c69
    index->loadContext->status = INDEX_READY;
Packit Service 310c69
    // If we get here, suspend is meaningless, but notify any thread trying
Packit Service 310c69
    // to suspend us so it doesn't hang.
Packit Service 310c69
    broadcastCond(&index->loadContext->cond);
Packit Service 310c69
    unlockMutex(&index->loadContext->mutex);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  index->hasSavedOpenChapter = index->loadedType == LOAD_LOAD;
Packit Service 310c69
  *newIndex = index;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void freeIndex(Index *index)
Packit Service 310c69
{
Packit Service 310c69
  if (index == NULL) {
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
  freeChapterWriter(index->chapterWriter);
Packit Service 310c69
Packit Service 310c69
  if (index->masterIndex != NULL) {
Packit Service 310c69
    freeMasterIndex(index->masterIndex);
Packit Service 310c69
  }
Packit Service 310c69
  releaseIndex(index);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int saveIndex(Index *index)
Packit Service 310c69
{
Packit Service 310c69
  waitForIdleChapterWriter(index->chapterWriter);
Packit Service 310c69
  int result = finishCheckpointing(index);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    logInfo("save index failed");
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  beginSave(index, false, index->newestVirtualChapter);
Packit Service 310c69
Packit Service 310c69
  result = saveIndexState(index->state);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    logInfo("save index failed");
Packit Service 310c69
    index->lastCheckpoint = index->prevCheckpoint;
Packit Service 310c69
  } else {
Packit Service 310c69
    index->hasSavedOpenChapter = true;
Packit Service 310c69
    logInfo("finished save (vcn %llu)", index->lastCheckpoint);
Packit Service 310c69
  }
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Get the zone for a request.
Packit Service 310c69
 *
Packit Service 310c69
 * @param index The index
Packit Service 310c69
 * @param request The request
Packit Service 310c69
 *
Packit Service 310c69
 * @return The zone for the request
Packit Service 310c69
 **/
Packit Service 310c69
static IndexZone *getRequestZone(Index *index, Request *request)
Packit Service 310c69
{
Packit Service 310c69
  return index->zones[request->zoneNumber];
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Search an index zone. This function is only correct for LRU.
Packit Service 310c69
 *
Packit Service 310c69
 * @param zone              The index zone to query.
Packit Service 310c69
 * @param request           The request originating the query.
Packit Service 310c69
 *
Packit Service 310c69
 * @return UDS_SUCCESS or an error code
Packit Service 310c69
 **/
Packit Service 310c69
static int searchIndexZone(IndexZone *zone, Request *request)
Packit Service 310c69
{
Packit Service 310c69
  MasterIndexRecord record;
Packit Service 310c69
  int result = getMasterIndexRecord(zone->index->masterIndex,
Packit Service 310c69
                                    &request->chunkName, &record);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  bool found = false;
Packit Service 310c69
  if (record.isFound) {
Packit Service 310c69
    result = getRecordFromZone(zone, request, &found, record.virtualChapter);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
    if (found) {
Packit Service 310c69
      request->location = computeIndexRegion(zone, record.virtualChapter);
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  /*
Packit Service 310c69
   * If a record has overflowed a chapter index in more than one chapter
Packit Service 310c69
   * (or overflowed in one chapter and collided with an existing record),
Packit Service 310c69
   * it will exist as a collision record in the master index, but we won't
Packit Service 310c69
   * find it in the volume. This case needs special handling.
Packit Service 310c69
   */
Packit Service 310c69
  bool     overflowRecord = (record.isFound && record.isCollision && !found);
Packit Service 310c69
  uint64_t chapter        = zone->newestVirtualChapter;
Packit Service 310c69
  if (found || overflowRecord) {
Packit Service 310c69
    if ((request->action == REQUEST_QUERY)
Packit Service 310c69
        && (!request->update || overflowRecord)) {
Packit Service 310c69
      /* This is a query without update, or with nothing to update */
Packit Service 310c69
      return UDS_SUCCESS;
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    if (record.virtualChapter != chapter) {
Packit Service 310c69
      /*
Packit Service 310c69
       * Update the master index to reference the new chapter for the block.
Packit Service 310c69
       * If the record had been deleted or dropped from the chapter index, it
Packit Service 310c69
       * will be back.
Packit Service 310c69
       */
Packit Service 310c69
      result = setMasterIndexRecordChapter(&record, chapter);
Packit Service 310c69
    } else if (request->action != REQUEST_UPDATE) {
Packit Service 310c69
      /* The record is already in the open chapter, so we're done */
Packit Service 310c69
      return UDS_SUCCESS;
Packit Service 310c69
    }
Packit Service 310c69
  } else {
Packit Service 310c69
    // The record wasn't in the master index, so check whether the name
Packit Service 310c69
    // is in a cached sparse chapter.
Packit Service 310c69
    if (!isMasterIndexSample(zone->index->masterIndex, &request->chunkName)
Packit Service 310c69
        && isSparse(zone->index->volume->geometry)) {
Packit Service 310c69
      // Passing UINT64_MAX triggers a search of the entire sparse cache.
Packit Service 310c69
      result = searchSparseCacheInZone(zone, request, UINT64_MAX, &found);
Packit Service 310c69
      if (result != UDS_SUCCESS) {
Packit Service 310c69
        return result;
Packit Service 310c69
      }
Packit Service 310c69
Packit Service 310c69
      if (found) {
Packit Service 310c69
        request->location = LOC_IN_SPARSE;
Packit Service 310c69
      }
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    if (request->action == REQUEST_QUERY) {
Packit Service 310c69
      if (!found || !request->update) {
Packit Service 310c69
        // This is a query without update or for a new record, so we're done.
Packit Service 310c69
        return UDS_SUCCESS;
Packit Service 310c69
      }
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    /*
Packit Service 310c69
     * Add a new entry to the master index referencing the open chapter.
Packit Service 310c69
     * This needs to be done both for new records, and for records from
Packit Service 310c69
     * cached sparse chapters.
Packit Service 310c69
     */
Packit Service 310c69
    result = putMasterIndexRecord(&record, chapter);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (result == UDS_OVERFLOW) {
Packit Service 310c69
    /*
Packit Service 310c69
     * The master index encountered a delta list overflow.  The condition
Packit Service 310c69
     * was already logged. We will go on without adding the chunk to the
Packit Service 310c69
     * open chapter.
Packit Service 310c69
     */
Packit Service 310c69
    return UDS_SUCCESS;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  UdsChunkData *metadata;
Packit Service 310c69
  if (!found || (request->action == REQUEST_UPDATE)) {
Packit Service 310c69
    // This is a new record or we're updating an existing record.
Packit Service 310c69
    metadata = &request->newMetadata;
Packit Service 310c69
  } else {
Packit Service 310c69
    // This is a duplicate, so move the record to the open chapter (for LRU).
Packit Service 310c69
    metadata = &request->oldMetadata;
Packit Service 310c69
  }
Packit Service 310c69
  return putRecordInZone(zone, request, metadata);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static int removeFromIndexZone(IndexZone *zone, Request *request)
Packit Service 310c69
{
Packit Service 310c69
  MasterIndexRecord record;
Packit Service 310c69
  int result = getMasterIndexRecord(zone->index->masterIndex,
Packit Service 310c69
                                    &request->chunkName, &record);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (!record.isFound) {
Packit Service 310c69
    // The name does not exist in master index, so there is nothing to remove.
Packit Service 310c69
    return UDS_SUCCESS;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (!record.isCollision) {
Packit Service 310c69
    // Non-collision records are hints, so resolve the name in the chapter.
Packit Service 310c69
    bool found;
Packit Service 310c69
    int result = getRecordFromZone(zone, request, &found,
Packit Service 310c69
                                   record.virtualChapter);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    if (!found) {
Packit Service 310c69
      // The name does not exist in the chapter, so there is nothing to remove.
Packit Service 310c69
      return UDS_SUCCESS;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  request->location = computeIndexRegion(zone, record.virtualChapter);
Packit Service 310c69
Packit Service 310c69
  /*
Packit Service 310c69
   * Delete the master index entry for the named record only. Note that a
Packit Service 310c69
   * later search might later return stale advice if there is a colliding name
Packit Service 310c69
   * in the same chapter, but it's a very rare case (1 in 2^21).
Packit Service 310c69
   */
Packit Service 310c69
  result = removeMasterIndexRecord(&record);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // If the record is in the open chapter, we must remove it or mark it
Packit Service 310c69
  // deleted to avoid trouble if the record is added again later.
Packit Service 310c69
  if (request->location == LOC_IN_OPEN_CHAPTER) {
Packit Service 310c69
    bool hashExists = false;
Packit Service 310c69
    removeFromOpenChapter(zone->openChapter, &request->chunkName, &hashExists);
Packit Service 310c69
    result = ASSERT(hashExists, "removing record not found in open chapter");
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
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
 * Simulate the creation of a sparse cache barrier message by the triage
Packit Service 310c69
 * queue, and the later execution of that message in an index zone.
Packit Service 310c69
 *
Packit Service 310c69
 * If the index receiving the request is multi-zone or dense, this function
Packit Service 310c69
 * does nothing. This simulation is an optimization for single-zone sparse
Packit Service 310c69
 * indexes. It also supports unit testing of indexes without routers and
Packit Service 310c69
 * queues.
Packit Service 310c69
 *
Packit Service 310c69
 * @param zone     the index zone responsible for the index request
Packit Service 310c69
 * @param request  the index request about to be executed
Packit Service 310c69
 *
Packit Service 310c69
 * @return UDS_SUCCESS always
Packit Service 310c69
 **/
Packit Service 310c69
static int simulateIndexZoneBarrierMessage(IndexZone *zone, Request *request)
Packit Service 310c69
{
Packit Service 310c69
  // Do nothing unless this is a single-zone sparse index.
Packit Service 310c69
  if ((zone->index->zoneCount > 1)
Packit Service 310c69
      || !isSparse(zone->index->volume->geometry)) {
Packit Service 310c69
    return UDS_SUCCESS;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Check if the index request is for a sampled name in a sparse chapter.
Packit Service 310c69
  uint64_t sparseVirtualChapter = triageIndexRequest(zone->index, request);
Packit Service 310c69
  if (sparseVirtualChapter == UINT64_MAX) {
Packit Service 310c69
    // Not indexed, not a hook, or in a chapter that is still dense, which
Packit Service 310c69
    // means there should be no change to the sparse chapter index cache.
Packit Service 310c69
    return UDS_SUCCESS;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  /*
Packit Service 310c69
   * The triage queue would have generated and enqueued a barrier message
Packit Service 310c69
   * preceding this request, which we simulate by directly invoking the
Packit Service 310c69
   * execution hook for an equivalent message.
Packit Service 310c69
   */
Packit Service 310c69
  BarrierMessageData barrier = { .virtualChapter = sparseVirtualChapter };
Packit Service 310c69
  return executeSparseCacheBarrierMessage(zone, &barrier);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static int dispatchIndexZoneRequest(IndexZone *zone, Request *request)
Packit Service 310c69
{
Packit Service 310c69
  if (!request->requeued) {
Packit Service 310c69
    // Single-zone sparse indexes don't have a triage queue to generate cache
Packit Service 310c69
    // barrier requests, so see if we need to synthesize a barrier.
Packit Service 310c69
    int result = simulateIndexZoneBarrierMessage(zone, request);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Set the default location. It will be overwritten if we find the chunk.
Packit Service 310c69
  request->location = LOC_UNAVAILABLE;
Packit Service 310c69
Packit Service 310c69
  int result;
Packit Service 310c69
  switch (request->action) {
Packit Service 310c69
  case REQUEST_INDEX:
Packit Service 310c69
  case REQUEST_UPDATE:
Packit Service 310c69
  case REQUEST_QUERY:
Packit Service 310c69
    result = makeUnrecoverable(searchIndexZone(zone, request));
Packit Service 310c69
    break;
Packit Service 310c69
Packit Service 310c69
  case REQUEST_DELETE:
Packit Service 310c69
    result = makeUnrecoverable(removeFromIndexZone(zone, request));
Packit Service 310c69
    break;
Packit Service 310c69
Packit Service 310c69
  default:
Packit Service 310c69
    result = logWarningWithStringError(UDS_INVALID_ARGUMENT,
Packit Service 310c69
                                       "attempted to execute invalid action:"
Packit Service 310c69
                                       " %d",
Packit Service 310c69
                                       request->action);
Packit Service 310c69
    break;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int dispatchIndexRequest(Index *index, Request *request)
Packit Service 310c69
{
Packit Service 310c69
  return dispatchIndexZoneRequest(getRequestZone(index, request), request);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static int rebuildIndexPageMap(Index *index, uint64_t vcn)
Packit Service 310c69
{
Packit Service 310c69
  Geometry *geometry = index->volume->geometry;
Packit Service 310c69
  unsigned int chapter = mapToPhysicalChapter(geometry, vcn);
Packit Service 310c69
  unsigned int expectedListNumber = 0;
Packit Service 310c69
  unsigned int indexPageNumber;
Packit Service 310c69
  for (indexPageNumber = 0;
Packit Service 310c69
       indexPageNumber < geometry->indexPagesPerChapter;
Packit Service 310c69
       indexPageNumber++) {
Packit Service 310c69
    DeltaIndexPage *chapterIndexPage;
Packit Service 310c69
    int result = getPage(index->volume, chapter, indexPageNumber,
Packit Service 310c69
                         CACHE_PROBE_INDEX_FIRST, NULL, &chapterIndexPage);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return logErrorWithStringError(result,
Packit Service 310c69
                                     "failed to read index page %u"
Packit Service 310c69
                                     " in chapter %u",
Packit Service 310c69
                                     indexPageNumber, chapter);
Packit Service 310c69
    }
Packit Service 310c69
    unsigned int lowestDeltaList = chapterIndexPage->lowestListNumber;
Packit Service 310c69
    unsigned int highestDeltaList = chapterIndexPage->highestListNumber;
Packit Service 310c69
    if (lowestDeltaList != expectedListNumber) {
Packit Service 310c69
      return logErrorWithStringError(UDS_CORRUPT_DATA,
Packit Service 310c69
                                     "chapter %u index page %u is corrupt",
Packit Service 310c69
                                     chapter, indexPageNumber);
Packit Service 310c69
    }
Packit Service 310c69
    result = updateIndexPageMap(index->volume->indexPageMap, vcn, chapter,
Packit Service 310c69
                                indexPageNumber, highestDeltaList);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return logErrorWithStringError(result,
Packit Service 310c69
                                     "failed to update chapter %u index page"
Packit Service 310c69
                                     " %u",
Packit Service 310c69
                                     chapter, indexPageNumber);
Packit Service 310c69
    }
Packit Service 310c69
    expectedListNumber = highestDeltaList + 1;
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Add an entry to the master index when rebuilding.
Packit Service 310c69
 *
Packit Service 310c69
 * @param index                The index to query.
Packit Service 310c69
 * @param name                 The block name of interest.
Packit Service 310c69
 * @param virtualChapter       The virtual chapter number to write to the
Packit Service 310c69
 *                             master index
Packit Service 310c69
 * @param willBeSparseChapter  True if this entry will be in the sparse portion
Packit Service 310c69
 *                             of the index at the end of rebuilding
Packit Service 310c69
 *
Packit Service 310c69
 * @return UDS_SUCCESS or an error code
Packit Service 310c69
 **/
Packit Service 310c69
static int replayRecord(Index              *index,
Packit Service 310c69
                        const UdsChunkName *name,
Packit Service 310c69
                        uint64_t            virtualChapter,
Packit Service 310c69
                        bool                willBeSparseChapter)
Packit Service 310c69
{
Packit Service 310c69
  if (willBeSparseChapter && !isMasterIndexSample(index->masterIndex, name)) {
Packit Service 310c69
    // This entry will be in a sparse chapter after the rebuild completes,
Packit Service 310c69
    // and it is not a sample, so just skip over it.
Packit Service 310c69
    return UDS_SUCCESS;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  MasterIndexRecord record;
Packit Service 310c69
  int result = getMasterIndexRecord(index->masterIndex, name, &record);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  bool updateRecord;
Packit Service 310c69
  if (record.isFound) {
Packit Service 310c69
    if (record.isCollision) {
Packit Service 310c69
      if (record.virtualChapter == virtualChapter) {
Packit Service 310c69
        /* The record is already correct, so we don't need to do anything */
Packit Service 310c69
        return UDS_SUCCESS;
Packit Service 310c69
      }
Packit Service 310c69
      updateRecord = true;
Packit Service 310c69
    } else if (record.virtualChapter == virtualChapter) {
Packit Service 310c69
      /*
Packit Service 310c69
       * There is a master index entry pointing to the current
Packit Service 310c69
       * chapter, but we don't know if it is for the same name as the
Packit Service 310c69
       * one we are currently working on or not. For now, we're just
Packit Service 310c69
       * going to assume that it isn't. This will create one extra
Packit Service 310c69
       * collision record if there was a deleted record in the current
Packit Service 310c69
       * chapter.
Packit Service 310c69
       */
Packit Service 310c69
      updateRecord = false;
Packit Service 310c69
    } else {
Packit Service 310c69
      /*
Packit Service 310c69
       * If we're rebuilding, we don't normally want to go to disk to see if
Packit Service 310c69
       * the record exists, since we will likely have just read the record from
Packit Service 310c69
       * disk (i.e. we know it's there). The exception to this is when we
Packit Service 310c69
       * already find an entry in the master index that has a different chapter.
Packit Service 310c69
       * In this case, we need to search that chapter to determine if the
Packit Service 310c69
       * master index entry was for the same record or a different one.
Packit Service 310c69
       */
Packit Service 310c69
      result = searchVolumePageCache(index->volume, NULL, name,
Packit Service 310c69
                                     record.virtualChapter, NULL,
Packit Service 310c69
                                     &updateRecord);
Packit Service 310c69
      if (result != UDS_SUCCESS) {
Packit Service 310c69
        return result;
Packit Service 310c69
      }
Packit Service 310c69
    }
Packit Service 310c69
  } else {
Packit Service 310c69
    updateRecord = false;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (updateRecord) {
Packit Service 310c69
    /*
Packit Service 310c69
     * Update the master index to reference the new chapter for the block.
Packit Service 310c69
     * If the record had been deleted or dropped from the chapter index, it
Packit Service 310c69
     * will be back.
Packit Service 310c69
     */
Packit Service 310c69
    result = setMasterIndexRecordChapter(&record, virtualChapter);
Packit Service 310c69
  } else {
Packit Service 310c69
    /*
Packit Service 310c69
     * Add a new entry to the master index referencing the open
Packit Service 310c69
     * chapter. This should be done regardless of whether we are a brand
Packit Service 310c69
     * new record or a sparse record, i.e. one that doesn't exist in the
Packit Service 310c69
     * index but does on disk, since for a sparse record, we would want to
Packit Service 310c69
     * un-sparsify if it did exist.
Packit Service 310c69
     */
Packit Service 310c69
    result = putMasterIndexRecord(&record, virtualChapter);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if ((result == UDS_DUPLICATE_NAME) || (result == UDS_OVERFLOW)) {
Packit Service 310c69
    /* Ignore duplicate record and delta list overflow errors */
Packit Service 310c69
    return UDS_SUCCESS;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void beginSave(Index *index, bool checkpoint, uint64_t openChapterNumber)
Packit Service 310c69
{
Packit Service 310c69
  index->prevCheckpoint = index->lastCheckpoint;
Packit Service 310c69
  index->lastCheckpoint = ((openChapterNumber == 0)
Packit Service 310c69
                           ? NO_LAST_CHECKPOINT
Packit Service 310c69
                           : openChapterNumber - 1);
Packit Service 310c69
Packit Service 310c69
  const char *what = (checkpoint ? "checkpoint" : "save");
Packit Service 310c69
  logInfo("beginning %s (vcn %llu)", what, index->lastCheckpoint);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Suspend the index if necessary and wait for a signal to resume.
Packit Service 310c69
 *
Packit Service 310c69
 * @param index  The index to replay
Packit Service 310c69
 *
Packit Service 310c69
 * @return true if the replay should terminate
Packit Service 310c69
 **/
Packit Service 310c69
static bool checkForSuspend(Index *index)
Packit Service 310c69
{
Packit Service 310c69
  if (index->loadContext == NULL) {
Packit Service 310c69
    return false;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  lockMutex(&index->loadContext->mutex);
Packit Service 310c69
  if (index->loadContext->status != INDEX_SUSPENDING) {
Packit Service 310c69
    unlockMutex(&index->loadContext->mutex);
Packit Service 310c69
    return false;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Notify that we are suspended and wait for the resume.
Packit Service 310c69
  index->loadContext->status = INDEX_SUSPENDED;
Packit Service 310c69
  broadcastCond(&index->loadContext->cond);
Packit Service 310c69
Packit Service 310c69
  while ((index->loadContext->status != INDEX_OPENING)
Packit Service 310c69
         && (index->loadContext->status != INDEX_FREEING)) {
Packit Service 310c69
    waitCond(&index->loadContext->cond, &index->loadContext->mutex);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  bool retVal = (index->loadContext->status == INDEX_FREEING);
Packit Service 310c69
  unlockMutex(&index->loadContext->mutex);
Packit Service 310c69
  return retVal;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int replayVolume(Index *index, uint64_t fromVCN)
Packit Service 310c69
{
Packit Service 310c69
  int result;
Packit Service 310c69
  uint64_t uptoVCN = index->newestVirtualChapter;
Packit Service 310c69
  logInfo("Replaying volume from chapter %llu through chapter %"
Packit Service 310c69
          PRIu64,
Packit Service 310c69
          fromVCN, uptoVCN);
Packit Service 310c69
  setMasterIndexOpenChapter(index->masterIndex, uptoVCN);
Packit Service 310c69
  setMasterIndexOpenChapter(index->masterIndex, fromVCN);
Packit Service 310c69
Packit Service 310c69
  /*
Packit Service 310c69
   * At least two cases to deal with here!
Packit Service 310c69
   * - index loaded but replaying from lastCheckpoint; maybe full, maybe not
Packit Service 310c69
   * - index failed to load, full rebuild
Packit Service 310c69
   *   Starts empty, then dense-only, then dense-plus-sparse.
Packit Service 310c69
   *   Need to sparsify while processing individual chapters.
Packit Service 310c69
   */
Packit Service 310c69
  IndexLookupMode oldLookupMode = index->volume->lookupMode;
Packit Service 310c69
  index->volume->lookupMode = LOOKUP_FOR_REBUILD;
Packit Service 310c69
  /*
Packit Service 310c69
   * Go through each record page of each chapter and add the records back to
Packit Service 310c69
   * the master index.  This should not cause anything to be written to either
Packit Service 310c69
   * the open chapter or on disk volume.  Also skip the on disk chapter
Packit Service 310c69
   * corresponding to upto, as this would have already been
Packit Service 310c69
   * purged from the master index when the chapter was opened.
Packit Service 310c69
   *
Packit Service 310c69
   * Also, go through each index page for each chapter and rebuild the
Packit Service 310c69
   * index page map.
Packit Service 310c69
   */
Packit Service 310c69
  const Geometry *geometry = index->volume->geometry;
Packit Service 310c69
  uint64_t oldIPMupdate = getLastUpdate(index->volume->indexPageMap);
Packit Service 310c69
  uint64_t vcn;
Packit Service 310c69
  for (vcn = fromVCN; vcn < uptoVCN; ++vcn) {
Packit Service 310c69
    if (checkForSuspend(index)) {
Packit Service 310c69
      logInfo("Replay interrupted by index shutdown at chapter %llu", vcn);
Packit Service 310c69
      return UDS_SHUTTINGDOWN;
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    bool willBeSparseChapter = isChapterSparse(geometry, fromVCN, uptoVCN,
Packit Service 310c69
                                               vcn);
Packit Service 310c69
    unsigned int chapter = mapToPhysicalChapter(geometry, vcn);
Packit Service 310c69
    prefetchVolumePages(&index->volume->volumeStore,
Packit Service 310c69
                        mapToPhysicalPage(geometry, chapter, 0),
Packit Service 310c69
                        geometry->pagesPerChapter);
Packit Service 310c69
    setMasterIndexOpenChapter(index->masterIndex, vcn);
Packit Service 310c69
    result = rebuildIndexPageMap(index, vcn);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      index->volume->lookupMode = oldLookupMode;
Packit Service 310c69
      return logErrorWithStringError(result,
Packit Service 310c69
                                     "could not rebuild index page map for"
Packit Service 310c69
                                     " chapter %u",
Packit Service 310c69
                                     chapter);
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    unsigned int j;
Packit Service 310c69
    for (j = 0; j < geometry->recordPagesPerChapter; j++) {
Packit Service 310c69
      unsigned int recordPageNumber = geometry->indexPagesPerChapter + j;
Packit Service 310c69
      byte *recordPage;
Packit Service 310c69
      result = getPage(index->volume, chapter, recordPageNumber,
Packit Service 310c69
                       CACHE_PROBE_RECORD_FIRST, &recordPage, NULL);
Packit Service 310c69
      if (result != UDS_SUCCESS) {
Packit Service 310c69
        index->volume->lookupMode = oldLookupMode;
Packit Service 310c69
        return logUnrecoverable(result, "could not get page %d",
Packit Service 310c69
                                recordPageNumber);
Packit Service 310c69
      }
Packit Service 310c69
      unsigned int k;
Packit Service 310c69
      for (k = 0; k < geometry->recordsPerPage; k++) {
Packit Service 310c69
        const byte *nameBytes = recordPage + (k * BYTES_PER_RECORD);
Packit Service 310c69
Packit Service 310c69
        UdsChunkName name;
Packit Service 310c69
        memcpy(&name.name, nameBytes, UDS_CHUNK_NAME_SIZE);
Packit Service 310c69
Packit Service 310c69
        result = replayRecord(index, &name, vcn, willBeSparseChapter);
Packit Service 310c69
        if (result != UDS_SUCCESS) {
Packit Service 310c69
          char hexName[(2 * UDS_CHUNK_NAME_SIZE) + 1];
Packit Service 310c69
          if (chunkNameToHex(&name, hexName, sizeof(hexName)) != UDS_SUCCESS) {
Packit Service 310c69
            strncpy(hexName, "<unknown>", sizeof(hexName));
Packit Service 310c69
          }
Packit Service 310c69
          index->volume->lookupMode = oldLookupMode;
Packit Service 310c69
          return logUnrecoverable(result,
Packit Service 310c69
                                  "could not find block %s during rebuild",
Packit Service 310c69
                                  hexName);
Packit Service 310c69
        }
Packit Service 310c69
      }
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
  index->volume->lookupMode = oldLookupMode;
Packit Service 310c69
Packit Service 310c69
  // We also need to reap the chapter being replaced by the open chapter
Packit Service 310c69
  setMasterIndexOpenChapter(index->masterIndex, uptoVCN);
Packit Service 310c69
Packit Service 310c69
  uint64_t newIPMupdate = getLastUpdate(index->volume->indexPageMap);
Packit Service 310c69
Packit Service 310c69
  if (newIPMupdate != oldIPMupdate) {
Packit Service 310c69
    logInfo("replay changed index page map update from %llu to %llu",
Packit Service 310c69
            oldIPMupdate, newIPMupdate);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void getIndexStats(Index *index, UdsIndexStats *counters)
Packit Service 310c69
{
Packit Service 310c69
  uint64_t cwAllocated = getChapterWriterMemoryAllocated(index->chapterWriter);
Packit Service 310c69
  // We're accessing the master index while not on a zone thread, but that's
Packit Service 310c69
  // safe to do when acquiring statistics.
Packit Service 310c69
  MasterIndexStats denseStats, sparseStats;
Packit Service 310c69
  getMasterIndexStats(index->masterIndex, &denseStats, &sparseStats);
Packit Service 310c69
Packit Service 310c69
  counters->entriesIndexed   = (denseStats.recordCount
Packit Service 310c69
                                + sparseStats.recordCount);
Packit Service 310c69
  counters->memoryUsed       = ((uint64_t) denseStats.memoryAllocated
Packit Service 310c69
                                + (uint64_t) sparseStats.memoryAllocated
Packit Service 310c69
                                + (uint64_t) getCacheSize(index->volume)
Packit Service 310c69
                                + cwAllocated);
Packit Service 310c69
  counters->collisions       = (denseStats.collisionCount
Packit Service 310c69
                                + sparseStats.collisionCount);
Packit Service 310c69
  counters->entriesDiscarded = (denseStats.discardCount
Packit Service 310c69
                                + sparseStats.discardCount);
Packit Service 310c69
  counters->checkpoints      = getCheckpointCount(index->checkpoint);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void advanceActiveChapters(Index *index)
Packit Service 310c69
{
Packit Service 310c69
  index->newestVirtualChapter++;
Packit Service 310c69
  if (areSamePhysicalChapter(index->volume->geometry,
Packit Service 310c69
                             index->newestVirtualChapter,
Packit Service 310c69
                             index->oldestVirtualChapter)) {
Packit Service 310c69
    index->oldestVirtualChapter++;
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
uint64_t triageIndexRequest(Index *index, Request *request)
Packit Service 310c69
{
Packit Service 310c69
  MasterIndexTriage triage;
Packit Service 310c69
  lookupMasterIndexName(index->masterIndex, &request->chunkName, &triage);
Packit Service 310c69
  if (!triage.inSampledChapter) {
Packit Service 310c69
    // Not indexed or not a hook.
Packit Service 310c69
    return UINT64_MAX;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  IndexZone *zone = getRequestZone(index, request);
Packit Service 310c69
  if (!isZoneChapterSparse(zone, triage.virtualChapter)) {
Packit Service 310c69
    return UINT64_MAX;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // XXX Optimize for a common case by remembering the chapter from the most
Packit Service 310c69
  // recent barrier message and skipping this chapter if is it the same.
Packit Service 310c69
Packit Service 310c69
  // Return the sparse chapter number to trigger the barrier messages.
Packit Service 310c69
  return triage.virtualChapter;
Packit Service 310c69
}