Blame source/uds/indexZone.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/indexZone.c#4 $
Packit Service 310c69
 */
Packit Service 310c69
Packit Service 310c69
#include "indexZone.h"
Packit Service 310c69
Packit Service 310c69
#include "errors.h"
Packit Service 310c69
#include "index.h"
Packit Service 310c69
#include "indexCheckpoint.h"
Packit Service 310c69
#include "indexRouter.h"
Packit Service 310c69
#include "logger.h"
Packit Service 310c69
#include "memoryAlloc.h"
Packit Service 310c69
#include "permassert.h"
Packit Service 310c69
#include "request.h"
Packit Service 310c69
#include "sparseCache.h"
Packit Service 310c69
#include "uds.h"
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int makeIndexZone(struct index *index, unsigned int zoneNumber)
Packit Service 310c69
{
Packit Service 310c69
  IndexZone *zone;
Packit Service 310c69
  int result = ALLOCATE(1, IndexZone, "index zone", &zone);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = makeOpenChapter(index->volume->geometry, index->zoneCount,
Packit Service 310c69
                           &zone->openChapter);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeIndexZone(zone);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = makeOpenChapter(index->volume->geometry, index->zoneCount,
Packit Service 310c69
                           &zone->writingChapter);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeIndexZone(zone);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  zone->index              = index;
Packit Service 310c69
  zone->id                 = zoneNumber;
Packit Service 310c69
  index->zones[zoneNumber] = zone;
Packit Service 310c69
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void freeIndexZone(IndexZone *zone)
Packit Service 310c69
{
Packit Service 310c69
  if (zone == NULL) {
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  freeOpenChapter(zone->openChapter);
Packit Service 310c69
  freeOpenChapter(zone->writingChapter);
Packit Service 310c69
  FREE(zone);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
bool isZoneChapterSparse(const IndexZone *zone,
Packit Service 310c69
                         uint64_t         virtualChapter)
Packit Service 310c69
{
Packit Service 310c69
  return isChapterSparse(zone->index->volume->geometry,
Packit Service 310c69
                         zone->oldestVirtualChapter,
Packit Service 310c69
                         zone->newestVirtualChapter,
Packit Service 310c69
                         virtualChapter);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void setActiveChapters(IndexZone *zone)
Packit Service 310c69
{
Packit Service 310c69
  zone->oldestVirtualChapter = zone->index->oldestVirtualChapter;
Packit Service 310c69
  zone->newestVirtualChapter = zone->index->newestVirtualChapter;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Swap the open and writing chapters after blocking until there are no active
Packit Service 310c69
 * chapter writers on the index.
Packit Service 310c69
 *
Packit Service 310c69
 * @param zone  The zone swapping chapters
Packit Service 310c69
 *
Packit Service 310c69
 * @return UDS_SUCCESS or a return code
Packit Service 310c69
 **/
Packit Service 310c69
static int swapOpenChapter(IndexZone *zone)
Packit Service 310c69
{
Packit Service 310c69
  // Wait for any currently writing chapter to complete
Packit Service 310c69
  int result = finishPreviousChapter(zone->index->chapterWriter,
Packit Service 310c69
                                     zone->newestVirtualChapter);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Swap the writing and open chapters
Packit Service 310c69
  OpenChapterZone *tempChapter = zone->openChapter;
Packit Service 310c69
  zone->openChapter            = zone->writingChapter;
Packit Service 310c69
  zone->writingChapter         = tempChapter;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Advance to a new open chapter, and forget the oldest chapter in the
Packit Service 310c69
 * index if necessary.
Packit Service 310c69
 *
Packit Service 310c69
 * @param zone                 The zone containing the chapter to reap
Packit Service 310c69
 *
Packit Service 310c69
 * @return UDS_SUCCESS or an error code
Packit Service 310c69
 **/
Packit Service 310c69
static int reapOldestChapter(IndexZone *zone)
Packit Service 310c69
{
Packit Service 310c69
  Index *index = zone->index;
Packit Service 310c69
  unsigned int chaptersPerVolume = index->volume->geometry->chaptersPerVolume;
Packit Service 310c69
  int result
Packit Service 310c69
    = ASSERT(((zone->newestVirtualChapter - zone->oldestVirtualChapter)
Packit Service 310c69
              <= chaptersPerVolume),
Packit Service 310c69
             "newest (%llu) and oldest (%llu) virtual chapters "
Packit Service 310c69
             "less than or equal to chapters per volume (%u)",
Packit Service 310c69
             zone->newestVirtualChapter, zone->oldestVirtualChapter,
Packit Service 310c69
             chaptersPerVolume);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  setMasterIndexZoneOpenChapter(index->masterIndex, zone->id,
Packit Service 310c69
                                zone->newestVirtualChapter);
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int executeSparseCacheBarrierMessage(IndexZone          *zone,
Packit Service 310c69
                                     BarrierMessageData *barrier)
Packit Service 310c69
{
Packit Service 310c69
  /*
Packit Service 310c69
   * Check if the chapter index for the virtual chapter is already in the
Packit Service 310c69
   * cache, and if it's not, rendezvous with the other zone threads to add the
Packit Service 310c69
   * chapter index to the sparse index cache.
Packit Service 310c69
   */
Packit Service 310c69
  return updateSparseCache(zone, barrier->virtualChapter);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Handle notification that some other zone has closed its open chapter. If
Packit Service 310c69
 * the chapter that was closed is still the open chapter for this zone,
Packit Service 310c69
 * close it now in order to minimize skew.
Packit Service 310c69
 *
Packit Service 310c69
 * @param zone          The zone receiving the notification
Packit Service 310c69
 * @param chapterClosed The notification
Packit Service 310c69
 *
Packit Service 310c69
 * @return UDS_SUCCESS or an error code
Packit Service 310c69
 **/
Packit Service 310c69
static int handleChapterClosed(IndexZone                *zone,
Packit Service 310c69
                               ChapterClosedMessageData *chapterClosed)
Packit Service 310c69
{
Packit Service 310c69
  if (zone->newestVirtualChapter == chapterClosed->virtualChapter) {
Packit Service 310c69
    return openNextChapter(zone, NULL);
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 dispatchIndexZoneControlRequest(Request *request)
Packit Service 310c69
{
Packit Service 310c69
  ZoneMessage *message = &request->zoneMessage;
Packit Service 310c69
  IndexZone *zone = message->index->zones[request->zoneNumber];
Packit Service 310c69
Packit Service 310c69
  switch (request->action) {
Packit Service 310c69
  case REQUEST_SPARSE_CACHE_BARRIER:
Packit Service 310c69
    return executeSparseCacheBarrierMessage(zone, &message->data.barrier);
Packit Service 310c69
Packit Service 310c69
  case REQUEST_ANNOUNCE_CHAPTER_CLOSED:
Packit Service 310c69
    return handleChapterClosed(zone, &message->data.chapterClosed);
Packit Service 310c69
Packit Service 310c69
  default:
Packit Service 310c69
    return ASSERT_FALSE("valid control message type: %d", request->action);
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Announce the closure of the current open chapter to the other zones.
Packit Service 310c69
 *
Packit Service 310c69
 * @param request       The request which caused the chapter to close
Packit Service 310c69
 *                      (may be NULL)
Packit Service 310c69
 * @param zone          The zone which first closed the chapter
Packit Service 310c69
 * @param closedChapter The chapter which was closed
Packit Service 310c69
 *
Packit Service 310c69
 * @return UDS_SUCCESS or an error code
Packit Service 310c69
 **/
Packit Service 310c69
static int announceChapterClosed(Request   *request,
Packit Service 310c69
                                 IndexZone *zone,
Packit Service 310c69
                                 uint64_t   closedChapter)
Packit Service 310c69
{
Packit Service 310c69
  IndexRouter *router = ((request != NULL) ? request->router : NULL);
Packit Service 310c69
Packit Service 310c69
  ZoneMessage zoneMessage = {
Packit Service 310c69
    .index = zone->index,
Packit Service 310c69
    .data  = {
Packit Service 310c69
      .chapterClosed = { .virtualChapter = closedChapter }
Packit Service 310c69
    }
Packit Service 310c69
  };
Packit Service 310c69
Packit Service 310c69
  unsigned int i;
Packit Service 310c69
  for (i = 0; i < zone->index->zoneCount; i++) {
Packit Service 310c69
    if (zone->id == i) {
Packit Service 310c69
      continue;
Packit Service 310c69
    }
Packit Service 310c69
    int result;
Packit Service 310c69
    if (router != NULL) {
Packit Service 310c69
      result = launchZoneControlMessage(REQUEST_ANNOUNCE_CHAPTER_CLOSED,
Packit Service 310c69
                                        zoneMessage, i, router);
Packit Service 310c69
    } else {
Packit Service 310c69
      // We're in a test which doesn't have zone queues, so we can just
Packit Service 310c69
      // call the message function directly.
Packit Service 310c69
      result = handleChapterClosed(zone->index->zones[i],
Packit Service 310c69
                                   &zoneMessage.data.chapterClosed);
Packit Service 310c69
    }
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
int openNextChapter(IndexZone *zone, Request *request)
Packit Service 310c69
{
Packit Service 310c69
  logDebug("closing chapter %llu of zone %d after %u entries (%u short)",
Packit Service 310c69
           zone->newestVirtualChapter, zone->id, zone->openChapter->size,
Packit Service 310c69
           zone->openChapter->capacity - zone->openChapter->size);
Packit Service 310c69
Packit Service 310c69
  int result = swapOpenChapter(zone);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  uint64_t closedChapter = zone->newestVirtualChapter++;
Packit Service 310c69
  result = reapOldestChapter(zone);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return logUnrecoverable(result, "reapOldestChapter failed");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  resetOpenChapter(zone->openChapter);
Packit Service 310c69
Packit Service 310c69
  // begin, continue, or finish the checkpoint processing
Packit Service 310c69
  // moved above startClosingChapter because some of the
Packit Service 310c69
  // checkpoint processing now done by the chapter writer thread
Packit Service 310c69
  result = processCheckpointing(zone->index,
Packit Service 310c69
                                zone->id,
Packit Service 310c69
                                zone->newestVirtualChapter);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  unsigned int finishedZones = startClosingChapter(zone->index->chapterWriter,
Packit Service 310c69
                                                   zone->id,
Packit Service 310c69
                                                   zone->writingChapter);
Packit Service 310c69
  if ((finishedZones == 1) && (zone->index->zoneCount > 1)) {
Packit Service 310c69
    // This is the first zone of a multi-zone index to close this chapter,
Packit Service 310c69
    // so inform the other zones in order to control zone skew.
Packit Service 310c69
    result = announceChapterClosed(request, zone, closedChapter);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // If the chapter being opened won't overwrite the oldest chapter, we're
Packit Service 310c69
  // done.
Packit Service 310c69
  if (!areSamePhysicalChapter(zone->index->volume->geometry,
Packit Service 310c69
                              zone->newestVirtualChapter,
Packit Service 310c69
                              zone->oldestVirtualChapter)) {
Packit Service 310c69
    return UDS_SUCCESS;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  uint64_t victim = zone->oldestVirtualChapter++;
Packit Service 310c69
  if (finishedZones < zone->index->zoneCount) {
Packit Service 310c69
    // We are not the last zone to close the chapter, so we're done
Packit Service 310c69
    return UDS_SUCCESS;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  /*
Packit Service 310c69
   * We are the last zone to close the chapter, so clean up the cache. That
Packit Service 310c69
   * it is safe to let the last thread out of the previous chapter to do this
Packit Service 310c69
   * relies on the fact that although the new open chapter shadows the oldest
Packit Service 310c69
   * chapter in the cache, until we write the new open chapter to disk, we'll
Packit Service 310c69
   * never look for it in the cache.
Packit Service 310c69
   */
Packit Service 310c69
  return forgetChapter(zone->index->volume, victim, INVALIDATION_EXPIRE);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
IndexRegion computeIndexRegion(const IndexZone *zone,
Packit Service 310c69
                               uint64_t         virtualChapter)
Packit Service 310c69
{
Packit Service 310c69
  if (virtualChapter == zone->newestVirtualChapter) {
Packit Service 310c69
    return LOC_IN_OPEN_CHAPTER;
Packit Service 310c69
  }
Packit Service 310c69
  return (isZoneChapterSparse(zone, virtualChapter)
Packit Service 310c69
          ? LOC_IN_SPARSE : LOC_IN_DENSE);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int getRecordFromZone(IndexZone *zone,
Packit Service 310c69
                      Request   *request,
Packit Service 310c69
                      bool      *found,
Packit Service 310c69
                      uint64_t   virtualChapter)
Packit Service 310c69
{
Packit Service 310c69
  if (virtualChapter == zone->newestVirtualChapter) {
Packit Service 310c69
    searchOpenChapter(zone->openChapter, &request->chunkName,
Packit Service 310c69
                      &request->oldMetadata, found);
Packit Service 310c69
    return UDS_SUCCESS;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if ((zone->newestVirtualChapter > 0)
Packit Service 310c69
      && (virtualChapter == (zone->newestVirtualChapter - 1))
Packit Service 310c69
      && (zone->writingChapter->size > 0)) {
Packit Service 310c69
    // Only search the writing chapter if it is full, else look on disk.
Packit Service 310c69
    searchOpenChapter(zone->writingChapter, &request->chunkName,
Packit Service 310c69
                      &request->oldMetadata, found);
Packit Service 310c69
    return UDS_SUCCESS;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // The slow lane thread has determined the location previously. We don't need
Packit Service 310c69
  // to search again. Just return the location.
Packit Service 310c69
  if (request->slLocationKnown) {
Packit Service 310c69
    *found = request->slLocation != LOC_UNAVAILABLE;
Packit Service 310c69
    return UDS_SUCCESS;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  Volume *volume = zone->index->volume;
Packit Service 310c69
  if (isZoneChapterSparse(zone, virtualChapter)
Packit Service 310c69
      && sparseCacheContains(volume->sparseCache, virtualChapter,
Packit Service 310c69
                             request->zoneNumber)) {
Packit Service 310c69
    // The named chunk, if it exists, is in a sparse chapter that is cached,
Packit Service 310c69
    // so just run the chunk through the sparse chapter cache search.
Packit Service 310c69
    return searchSparseCacheInZone(zone, request, virtualChapter, found);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return searchVolumePageCache(volume, request, &request->chunkName,
Packit Service 310c69
                               virtualChapter, &request->oldMetadata, found);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int putRecordInZone(IndexZone          *zone,
Packit Service 310c69
                    Request            *request,
Packit Service 310c69
                    const UdsChunkData *metadata)
Packit Service 310c69
{
Packit Service 310c69
  unsigned int remaining;
Packit Service 310c69
  int result = putOpenChapter(zone->openChapter, &request->chunkName, metadata,
Packit Service 310c69
                              &remaining);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (remaining == 0) {
Packit Service 310c69
    return openNextChapter(zone, request);
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 searchSparseCacheInZone(IndexZone *zone,
Packit Service 310c69
                            Request   *request,
Packit Service 310c69
                            uint64_t   virtualChapter,
Packit Service 310c69
                            bool      *found)
Packit Service 310c69
{
Packit Service 310c69
  int recordPageNumber;
Packit Service 310c69
  int result = searchSparseCache(zone, &request->chunkName, &virtualChapter,
Packit Service 310c69
                                 &recordPageNumber);
Packit Service 310c69
  if ((result != UDS_SUCCESS) || (virtualChapter == UINT64_MAX)) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  Volume *volume = zone->index->volume;
Packit Service 310c69
  // XXX map to physical chapter and validate. It would be nice to just pass
Packit Service 310c69
  // the virtual in to the slow lane, since it's tracking invalidations.
Packit Service 310c69
  unsigned int chapter
Packit Service 310c69
    = mapToPhysicalChapter(volume->geometry, virtualChapter);
Packit Service 310c69
Packit Service 310c69
  return searchCachedRecordPage(volume, request, &request->chunkName, chapter,
Packit Service 310c69
                                recordPageNumber, &request->oldMetadata,
Packit Service 310c69
                                found);
Packit Service 310c69
}