Blame source/uds/indexCheckpoint.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/indexCheckpoint.c#2 $
Packit Service 310c69
 */
Packit Service 310c69
Packit Service 310c69
#include "indexCheckpoint.h"
Packit Service 310c69
Packit Service 310c69
#include "errors.h"
Packit Service 310c69
#include "logger.h"
Packit Service 310c69
#include "memoryAlloc.h"
Packit Service 310c69
#include "permassert.h"
Packit Service 310c69
#include "threads.h"
Packit Service 310c69
#include "typeDefs.h"
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * index checkpointState values
Packit Service 310c69
 *
Packit Service 310c69
 * @note The order of these values is significant,
Packit Service 310c69
 *       see indexState.c doIndexStateCheckpointInZone().
Packit Service 310c69
 **/
Packit Service 310c69
typedef enum checkpointState {
Packit Service 310c69
  NOT_CHECKPOINTING,
Packit Service 310c69
  CHECKPOINT_IN_PROGRESS,
Packit Service 310c69
  CHECKPOINT_ABORTING
Packit Service 310c69
} CheckpointState;
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Private structure which tracks checkpointing.
Packit Service 310c69
 **/
Packit Service 310c69
struct indexCheckpoint {
Packit Service 310c69
  Mutex            mutex;       // covers this group of fields
Packit Service 310c69
  uint64_t         chapter;     // vcn of the starting chapter
Packit Service 310c69
  CheckpointState  state;       // is checkpoint in progress or aborting
Packit Service 310c69
  unsigned int     zonesBusy;   // count of zones not yet done
Packit Service 310c69
  unsigned int     frequency;   // number of chapters between checkpoints
Packit Service 310c69
  uint64_t         checkpoints; // number of checkpoints this session
Packit Service 310c69
};
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Enum return value of indexCheckpointTrigger function.
Packit Service 310c69
 **/
Packit Service 310c69
typedef enum indexCheckpointTriggerValue {
Packit Service 310c69
  ICTV_IDLE,       //< no checkpointing right now
Packit Service 310c69
  ICTV_START,      //< start a new checkpoint now
Packit Service 310c69
  ICTV_CONTINUE,   //< continue checkpointing if needed
Packit Service 310c69
  ICTV_FINISH,     //< finish checkpointing, next time will start new cycle
Packit Service 310c69
  ICTV_ABORT       //< immediately abort checkpointing
Packit Service 310c69
} IndexCheckpointTriggerValue;
Packit Service 310c69
Packit Service 310c69
typedef int CheckpointFunction(Index *index, unsigned int zone);
Packit Service 310c69
Packit Service 310c69
//  These functions are called while holding the checkpoint->mutex but are
Packit Service 310c69
//  expected to release it.
Packit Service 310c69
//
Packit Service 310c69
static CheckpointFunction doCheckpointStart;
Packit Service 310c69
static CheckpointFunction doCheckpointProcess;
Packit Service 310c69
static CheckpointFunction doCheckpointFinish;
Packit Service 310c69
static CheckpointFunction doCheckpointAbort;
Packit Service 310c69
Packit Service 310c69
CheckpointFunction *const checkpointFuncs[] = {
Packit Service 310c69
  NULL,
Packit Service 310c69
  doCheckpointStart,
Packit Service 310c69
  doCheckpointProcess,
Packit Service 310c69
  doCheckpointFinish,
Packit Service 310c69
  doCheckpointAbort
Packit Service 310c69
};
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int makeIndexCheckpoint(Index *index)
Packit Service 310c69
{
Packit Service 310c69
  IndexCheckpoint *checkpoint;
Packit Service 310c69
  int result
Packit Service 310c69
    = ALLOCATE(1, IndexCheckpoint, "IndexCheckpoint", &checkpoint);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = initMutex(&checkpoint->mutex);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    FREE(checkpoint);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  checkpoint->checkpoints = 0;
Packit Service 310c69
Packit Service 310c69
  index->checkpoint = checkpoint;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void freeIndexCheckpoint(IndexCheckpoint *checkpoint)
Packit Service 310c69
{
Packit Service 310c69
  if (checkpoint != NULL) {
Packit Service 310c69
    destroyMutex(&checkpoint->mutex);
Packit Service 310c69
    FREE(checkpoint);
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
unsigned int getIndexCheckpointFrequency(IndexCheckpoint *checkpoint)
Packit Service 310c69
{
Packit Service 310c69
  lockMutex(&checkpoint->mutex);
Packit Service 310c69
  unsigned int frequency = checkpoint->frequency;
Packit Service 310c69
  unlockMutex(&checkpoint->mutex);
Packit Service 310c69
  return frequency;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
unsigned int setIndexCheckpointFrequency(IndexCheckpoint *checkpoint,
Packit Service 310c69
                                         unsigned int     frequency)
Packit Service 310c69
{
Packit Service 310c69
  lockMutex(&checkpoint->mutex);
Packit Service 310c69
  unsigned int oldFrequency = checkpoint->frequency;
Packit Service 310c69
  checkpoint->frequency = frequency;
Packit Service 310c69
  unlockMutex(&checkpoint->mutex);
Packit Service 310c69
  return oldFrequency;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
uint64_t getCheckpointCount(IndexCheckpoint *checkpoint)
Packit Service 310c69
{
Packit Service 310c69
  return checkpoint->checkpoints;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static IndexCheckpointTriggerValue
Packit Service 310c69
getCheckpointAction(IndexCheckpoint *checkpoint,
Packit Service 310c69
                    uint64_t virtualChapter)
Packit Service 310c69
{
Packit Service 310c69
  if (checkpoint->frequency == 0) {
Packit Service 310c69
    return ICTV_IDLE;
Packit Service 310c69
  }
Packit Service 310c69
  unsigned int value = virtualChapter % checkpoint->frequency;
Packit Service 310c69
  if (checkpoint->state == CHECKPOINT_ABORTING) {
Packit Service 310c69
    return ICTV_ABORT;
Packit Service 310c69
  } else if (checkpoint->state == CHECKPOINT_IN_PROGRESS) {
Packit Service 310c69
    if (value == checkpoint->frequency - 1) {
Packit Service 310c69
      return ICTV_FINISH;
Packit Service 310c69
    } else {
Packit Service 310c69
      return ICTV_CONTINUE;
Packit Service 310c69
    }
Packit Service 310c69
  } else {
Packit Service 310c69
    if (value == 0) {
Packit Service 310c69
      return ICTV_START;
Packit Service 310c69
    } else {
Packit Service 310c69
      return ICTV_IDLE;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int processCheckpointing(Index        *index,
Packit Service 310c69
                         unsigned int  zone,
Packit Service 310c69
                         uint64_t      newVirtualChapter)
Packit Service 310c69
{
Packit Service 310c69
  IndexCheckpoint *checkpoint = index->checkpoint;
Packit Service 310c69
  lockMutex(&checkpoint->mutex);
Packit Service 310c69
Packit Service 310c69
  IndexCheckpointTriggerValue ictv
Packit Service 310c69
    = getCheckpointAction(checkpoint, newVirtualChapter);
Packit Service 310c69
Packit Service 310c69
  if (ictv == ICTV_START) {
Packit Service 310c69
    checkpoint->chapter = newVirtualChapter;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  CheckpointFunction *func = checkpointFuncs[ictv];
Packit Service 310c69
  if (func == NULL) {
Packit Service 310c69
    // nothing to do in idle state
Packit Service 310c69
    unlockMutex(&checkpoint->mutex);
Packit Service 310c69
    return UDS_SUCCESS;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return (*func)(index, zone);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int processChapterWriterCheckpointSaves(Index *index)
Packit Service 310c69
{
Packit Service 310c69
  IndexCheckpoint *checkpoint = index->checkpoint;
Packit Service 310c69
Packit Service 310c69
  int result = UDS_SUCCESS;
Packit Service 310c69
Packit Service 310c69
  lockMutex(&checkpoint->mutex);
Packit Service 310c69
  if (checkpoint->state == CHECKPOINT_IN_PROGRESS) {
Packit Service 310c69
    result =
Packit Service 310c69
      performIndexStateCheckpointChapterSynchronizedSaves(index->state);
Packit Service 310c69
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      checkpoint->state = CHECKPOINT_ABORTING;
Packit Service 310c69
      logInfo("checkpoint failed");
Packit Service 310c69
      index->lastCheckpoint = index->prevCheckpoint;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  unlockMutex(&checkpoint->mutex);
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 *  Helper function used to abort checkpoint if an error has occurred.
Packit Service 310c69
 *
Packit Service 310c69
 *  @param index        the index
Packit Service 310c69
 *  @param result       the error result
Packit Service 310c69
 *
Packit Service 310c69
 *  @return result
Packit Service 310c69
 **/
Packit Service 310c69
static int abortCheckpointing(Index *index, int result)
Packit Service 310c69
{
Packit Service 310c69
  if (index->checkpoint->state != NOT_CHECKPOINTING) {
Packit Service 310c69
    index->checkpoint->state = CHECKPOINT_ABORTING;
Packit Service 310c69
    logInfo("checkpoint failed");
Packit Service 310c69
    index->lastCheckpoint = index->prevCheckpoint;
Packit Service 310c69
  }
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int finishCheckpointing(Index *index)
Packit Service 310c69
{
Packit Service 310c69
  IndexCheckpoint *checkpoint = index->checkpoint;
Packit Service 310c69
Packit Service 310c69
  int result = processChapterWriterCheckpointSaves(index);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  lockMutex(&checkpoint->mutex);
Packit Service 310c69
Packit Service 310c69
  unsigned int z;
Packit Service 310c69
  for (z = 0; z < index->zoneCount; ++z) {
Packit Service 310c69
    if (checkpoint->state != CHECKPOINT_IN_PROGRESS) {
Packit Service 310c69
      break;
Packit Service 310c69
    }
Packit Service 310c69
    result = doCheckpointFinish(index, z);
Packit Service 310c69
    // reacquire mutex released by doCheckpointFinish
Packit Service 310c69
    lockMutex(&checkpoint->mutex);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      break;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if ((result == UDS_SUCCESS) &&
Packit Service 310c69
      (checkpoint->state == CHECKPOINT_IN_PROGRESS)) {
Packit Service 310c69
    result = finishIndexStateCheckpoint(index->state);
Packit Service 310c69
    if (result == UDS_SUCCESS) {
Packit Service 310c69
      checkpoint->state = NOT_CHECKPOINTING;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  unlockMutex(&checkpoint->mutex);
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Starts an incremental checkpoint.
Packit Service 310c69
 *
Packit Service 310c69
 * Called by the first zone to finish a chapter which starts a checkpoint.
Packit Service 310c69
 *
Packit Service 310c69
 * @param index the index
Packit Service 310c69
 * @param zone  the zone number
Packit Service 310c69
 *
Packit Service 310c69
 * @return UDS_SUCCESS or an error code
Packit Service 310c69
 **/
Packit Service 310c69
static int doCheckpointStart(Index *index, unsigned int zone)
Packit Service 310c69
{
Packit Service 310c69
  IndexCheckpoint *checkpoint = index->checkpoint;
Packit Service 310c69
  beginSave(index, true, checkpoint->chapter);
Packit Service 310c69
  int result = startIndexStateCheckpoint(index->state);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    logErrorWithStringError(result, "cannot start index checkpoint");
Packit Service 310c69
    index->lastCheckpoint = index->prevCheckpoint;
Packit Service 310c69
    unlockMutex(&checkpoint->mutex);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  checkpoint->state = CHECKPOINT_IN_PROGRESS;
Packit Service 310c69
  checkpoint->zonesBusy = index->zoneCount;
Packit Service 310c69
Packit Service 310c69
  return doCheckpointProcess(index, zone);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static int doCheckpointProcess(Index *index, unsigned int zone)
Packit Service 310c69
{
Packit Service 310c69
  IndexCheckpoint *checkpoint = index->checkpoint;
Packit Service 310c69
  unlockMutex(&checkpoint->mutex);
Packit Service 310c69
  CompletionStatus status = CS_NOT_COMPLETED;
Packit Service 310c69
  int result = performIndexStateCheckpointInZone(index->state, zone, &status);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    lockMutex(&checkpoint->mutex);
Packit Service 310c69
    logErrorWithStringError(result, "cannot continue index checkpoint");
Packit Service 310c69
    result = abortCheckpointing(index, result);
Packit Service 310c69
    unlockMutex(&checkpoint->mutex);
Packit Service 310c69
  } else if (status == CS_JUST_COMPLETED) {
Packit Service 310c69
    lockMutex(&checkpoint->mutex);
Packit Service 310c69
    if (--checkpoint->zonesBusy == 0) {
Packit Service 310c69
      checkpoint->checkpoints += 1;
Packit Service 310c69
      logInfo("finished checkpoint");
Packit Service 310c69
      result = finishIndexStateCheckpoint(index->state);
Packit Service 310c69
      if (result != UDS_SUCCESS) {
Packit Service 310c69
        logErrorWithStringError(result, "%s checkpoint finish failed",
Packit Service 310c69
                                __func__);
Packit Service 310c69
      }
Packit Service 310c69
      checkpoint->state = NOT_CHECKPOINTING;
Packit Service 310c69
    }
Packit Service 310c69
    unlockMutex(&checkpoint->mutex);
Packit Service 310c69
  }
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static int doCheckpointAbort(Index *index, unsigned int zone)
Packit Service 310c69
{
Packit Service 310c69
  IndexCheckpoint *checkpoint = index->checkpoint;
Packit Service 310c69
  CompletionStatus status = CS_NOT_COMPLETED;
Packit Service 310c69
  int result = abortIndexStateCheckpointInZone(index->state, zone, &status);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    logErrorWithStringError(result, "cannot abort index checkpoint");
Packit Service 310c69
  } else if (status == CS_JUST_COMPLETED) {
Packit Service 310c69
    if (--checkpoint->zonesBusy == 0) {
Packit Service 310c69
      logInfo("aborted checkpoint");
Packit Service 310c69
      result = abortIndexStateCheckpoint(index->state);
Packit Service 310c69
      if (result != UDS_SUCCESS) {
Packit Service 310c69
        logErrorWithStringError(result, "checkpoint abort failed");
Packit Service 310c69
      }
Packit Service 310c69
      checkpoint->state = NOT_CHECKPOINTING;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
  unlockMutex(&checkpoint->mutex);
Packit Service 310c69
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static int doCheckpointFinish(Index *index, unsigned int zone)
Packit Service 310c69
{
Packit Service 310c69
  IndexCheckpoint *checkpoint = index->checkpoint;
Packit Service 310c69
  CompletionStatus status = CS_NOT_COMPLETED;
Packit Service 310c69
  unlockMutex(&checkpoint->mutex);
Packit Service 310c69
  int result = finishIndexStateCheckpointInZone(index->state, zone, &status);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    logErrorWithStringError(result, "cannot finish index checkpoint");
Packit Service 310c69
    lockMutex(&checkpoint->mutex);
Packit Service 310c69
    result = abortCheckpointing(index, result);
Packit Service 310c69
    unlockMutex(&checkpoint->mutex);
Packit Service 310c69
  } else if (status == CS_JUST_COMPLETED) {
Packit Service 310c69
    lockMutex(&checkpoint->mutex);
Packit Service 310c69
    if (--checkpoint->zonesBusy == 0) {
Packit Service 310c69
      checkpoint->checkpoints += 1;
Packit Service 310c69
      logInfo("finished checkpoint");
Packit Service 310c69
      result = finishIndexStateCheckpoint(index->state);
Packit Service 310c69
      if (result != UDS_SUCCESS) {
Packit Service 310c69
        logErrorWithStringError(result, "%s checkpoint finish failed",
Packit Service 310c69
                                __func__);
Packit Service 310c69
      }
Packit Service 310c69
      checkpoint->state = NOT_CHECKPOINTING;
Packit Service 310c69
    }
Packit Service 310c69
    unlockMutex(&checkpoint->mutex);
Packit Service 310c69
  }
Packit Service 310c69
  return result;
Packit Service 310c69
}