/*
* Copyright (c) 2020 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* $Id: //eng/uds-releases/jasper/src/uds/indexState.c#6 $
*/
#include "indexState.h"
#include "errors.h"
#include "indexComponent.h"
#include "indexLayout.h"
#include "logger.h"
#include "memoryAlloc.h"
/*****************************************************************************/
int makeIndexState(IndexLayout *layout,
unsigned int numZones,
unsigned int maxComponents,
IndexState **statePtr)
{
if (maxComponents == 0) {
return logErrorWithStringError(
UDS_INVALID_ARGUMENT, "cannot make index state with maxComponents 0");
}
IndexState *state = NULL;
int result = ALLOCATE_EXTENDED(IndexState, maxComponents, IndexComponent *,
"index state", &state);
if (result != UDS_SUCCESS) {
return result;
}
state->count = 0;
state->layout = layout;
state->length = maxComponents;
state->loadZones = 0;
state->loadSlot = UINT_MAX;
state->saveSlot = UINT_MAX;
state->saving = false;
state->zoneCount = numZones;
*statePtr = state;
return UDS_SUCCESS;
}
/*****************************************************************************/
void freeIndexState(IndexState **statePtr)
{
IndexState *state = *statePtr;
*statePtr = NULL;
if (state != NULL) {
unsigned int i;
for (i = 0; i < state->count; ++i) {
freeIndexComponent(&state->entries[i]);
}
FREE(state);
}
}
/*****************************************************************************/
/**
* Add a component to the index state.
*
* @param state The index state.
* @param component The index component.
*
* @return UDS_SUCCESS or an error code.
**/
static int addComponentToIndexState(IndexState *state,
IndexComponent *component)
{
if (findIndexComponent(state, component->info) != NULL) {
return logErrorWithStringError(
UDS_INVALID_ARGUMENT, "cannot add state component %s: already present",
component->info->name);
}
if (state->count >= state->length) {
return logErrorWithStringError(
UDS_RESOURCE_LIMIT_EXCEEDED,
"cannot add state component %s, %u components already added",
component->info->name, state->count);
}
state->entries[state->count] = component;
++state->count;
return UDS_SUCCESS;
}
/*****************************************************************************/
int addIndexStateComponent(IndexState *state,
const IndexComponentInfo *info,
void *data,
void *context)
{
IndexComponent *component = NULL;
int result = makeIndexComponent(state, info, state->zoneCount, data, context,
&component);
if (result != UDS_SUCCESS) {
return logErrorWithStringError(result,
"cannot make region index component");
}
result = addComponentToIndexState(state, component);
if (result != UDS_SUCCESS) {
freeIndexComponent(&component);
return result;
}
return UDS_SUCCESS;
}
/*****************************************************************************/
IndexComponent *findIndexComponent(const IndexState *state,
const IndexComponentInfo *info)
{
unsigned int i;
for (i = 0; i < state->count; ++i) {
IndexComponent *component = state->entries[i];
if (info == component->info) {
return component;
}
}
return NULL;
}
/*****************************************************************************/
static const char *indexSaveTypeName(IndexSaveType saveType)
{
return saveType == IS_SAVE ? "save" : "checkpoint";
}
/*****************************************************************************/
int loadIndexState(IndexState *state, bool *replayPtr)
{
int result = findLatestIndexSaveSlot(state->layout, &state->loadZones,
&state->loadSlot);
if (result != UDS_SUCCESS) {
return result;
}
bool replayRequired = false;
unsigned int i;
for (i = 0; i < state->count; ++i) {
IndexComponent *component = state->entries[i];
result = readIndexComponent(component);
if (result != UDS_SUCCESS) {
if (!missingIndexComponentRequiresReplay(component)) {
state->loadZones = 0;
state->loadSlot = UINT_MAX;
return logErrorWithStringError(result, "index component %s",
indexComponentName(component));
}
replayRequired = true;
}
}
state->loadZones = 0;
state->loadSlot = UINT_MAX;
if (replayPtr != NULL) {
*replayPtr = replayRequired;
}
return UDS_SUCCESS;
}
/*****************************************************************************/
int prepareToSaveIndexState(IndexState *state, IndexSaveType saveType)
{
if (state->saving) {
return logErrorWithStringError(UDS_BAD_STATE,
"already saving the index state");
}
int result = setupIndexSaveSlot(state->layout, state->zoneCount, saveType,
&state->saveSlot);
if (result != UDS_SUCCESS) {
return logErrorWithStringError(result, "cannot prepare index %s",
indexSaveTypeName(saveType));
}
return UDS_SUCCESS;
}
/*****************************************************************************/
/**
* Complete the saving of an index state.
*
* @param state the index state
*
* @return UDS_SUCCESS or an error code
**/
static int completeIndexSaving(IndexState *state)
{
state->saving = false;
int result = commitIndexSave(state->layout, state->saveSlot);
state->saveSlot = UINT_MAX;
if (result != UDS_SUCCESS) {
return logErrorWithStringError(result, "cannot commit index state");
}
return UDS_SUCCESS;
}
/*****************************************************************************/
static int cleanupSave(IndexState *state)
{
int result = cancelIndexSave(state->layout, state->saveSlot);
state->saveSlot = UINT_MAX;
if (result != UDS_SUCCESS) {
return logErrorWithStringError(result, "cannot cancel index save");
}
return UDS_SUCCESS;
}
/*****************************************************************************/
int saveIndexState(IndexState *state)
{
int result = prepareToSaveIndexState(state, IS_SAVE);
if (result != UDS_SUCCESS) {
return result;
}
unsigned int i;
for (i = 0; i < state->count; ++i) {
IndexComponent *component = state->entries[i];
result = writeIndexComponent(component);
if (result != UDS_SUCCESS) {
cleanupSave(state);
return result;
}
}
return completeIndexSaving(state);
}
/*****************************************************************************/
int writeIndexStateCheckpoint(IndexState *state)
{
int result = prepareToSaveIndexState(state, IS_CHECKPOINT);
if (result != UDS_SUCCESS) {
return result;
}
unsigned int i;
for (i = 0; i < state->count; ++i) {
IndexComponent *component = state->entries[i];
if (skipIndexComponentOnCheckpoint(component)) {
continue;
}
result = writeIndexComponent(component);
if (result != UDS_SUCCESS) {
cleanupSave(state);
return result;
}
}
return completeIndexSaving(state);
}
/*****************************************************************************/
int startIndexStateCheckpoint(IndexState *state)
{
int result = prepareToSaveIndexState(state, IS_CHECKPOINT);
if (result != UDS_SUCCESS) {
return result;
}
state->saving = true;
unsigned int i;
for (i = 0; i < state->count; ++i) {
IndexComponent *component = state->entries[i];
if (skipIndexComponentOnCheckpoint(component)) {
continue;
}
result = startIndexComponentIncrementalSave(component);
if (result != UDS_SUCCESS) {
abortIndexStateCheckpoint(state);
return result;
}
}
return result;
}
/*****************************************************************************/
int performIndexStateCheckpointChapterSynchronizedSaves(IndexState *state)
{
if (!state->saving) {
return UDS_SUCCESS;
}
unsigned int i;
for (i = 0; i < state->count; ++i) {
IndexComponent *component = state->entries[i];
if (skipIndexComponentOnCheckpoint(component) ||
!deferIndexComponentCheckpointToChapterWriter(component)) {
continue;
}
int result = performIndexComponentChapterWriterSave(component);
if (result != UDS_SUCCESS) {
return result;
}
}
return UDS_SUCCESS;
}
/**
* Wrapper function to do a zone-based checkpoint operation.
*
* @param [in] state the index state
* @param [in] zone the zone number
* @param [in] compFunc the index component function to use
* @param [out] completed if non-NULL, where to save the completion status
*
* @return UDS_SUCCESS or an error code
*
**/
static int doIndexStateCheckpointInZone(IndexState *state,
unsigned int zone,
int (*compFunc)(IndexComponent *,
unsigned int,
CompletionStatus *),
CompletionStatus *completed)
{
if (!state->saving) {
if (completed != NULL) {
*completed = CS_COMPLETED_PREVIOUSLY;
}
return UDS_SUCCESS;
}
CompletionStatus status = CS_COMPLETED_PREVIOUSLY;
unsigned int i;
for (i = 0; i < state->count; ++i) {
IndexComponent *component = state->entries[i];
if (skipIndexComponentOnCheckpoint(component)) {
continue;
}
if (zone > 0 && !component->info->multiZone) {
continue;
}
CompletionStatus componentStatus = CS_NOT_COMPLETED;
int result = (*compFunc)(component, zone, &componentStatus);
if (result != UDS_SUCCESS) {
return result;
}
// compute rolling least status
if (componentStatus < status) {
status = componentStatus;
}
}
if (completed != NULL) {
*completed = status;
}
return UDS_SUCCESS;
}
/*****************************************************************************/
int performIndexStateCheckpointInZone(IndexState *state,
unsigned int zone,
CompletionStatus *completed)
{
return doIndexStateCheckpointInZone(state, zone,
&performIndexComponentZoneSave,
completed);
}
/*****************************************************************************/
int finishIndexStateCheckpointInZone(IndexState *state,
unsigned int zone,
CompletionStatus *completed)
{
return doIndexStateCheckpointInZone(state, zone,
&finishIndexComponentZoneSave,
completed);
}
/*****************************************************************************/
int abortIndexStateCheckpointInZone(IndexState *state,
unsigned int zone,
CompletionStatus *completed)
{
return doIndexStateCheckpointInZone(state, zone,
&abortIndexComponentZoneSave, completed);
}
/*****************************************************************************/
int finishIndexStateCheckpoint(IndexState *state)
{
if (!state->saving) {
return UDS_SUCCESS;
}
unsigned int i;
for (i = 0; i < state->count; ++i) {
IndexComponent *component = state->entries[i];
if (skipIndexComponentOnCheckpoint(component)) {
continue;
}
int result = finishIndexComponentIncrementalSave(component);
if (result != UDS_SUCCESS) {
abortIndexStateCheckpoint(state);
return result;
}
}
int result = completeIndexSaving(state);
if (result != UDS_SUCCESS) {
return result;
}
return UDS_SUCCESS;
}
/*****************************************************************************/
int abortIndexStateCheckpoint(IndexState *state)
{
if (!state->saving) {
return logErrorWithStringError(UDS_BAD_STATE,
"not saving the index state");
}
logError("aborting index state checkpoint");
int result = UDS_SUCCESS;
unsigned int i;
for (i = 0; i < state->count; ++i) {
IndexComponent *component = state->entries[i];
if (skipIndexComponentOnCheckpoint(component)) {
continue;
}
int tmp = abortIndexComponentIncrementalSave(component);
if (result == UDS_SUCCESS) {
result = tmp;
}
}
cleanupSave(state);
state->saving = false;
return result;
}
/*****************************************************************************/
int discardIndexStateData(IndexState *state)
{
int result = discardIndexSaves(state->layout, true);
state->saveSlot = UINT_MAX;
if (result != UDS_SUCCESS) {
return logErrorWithStringError(result,
"%s: cannot destroy all index saves",
__func__);
}
return UDS_SUCCESS;
}
/*****************************************************************************/
int discardLastIndexStateSave(IndexState *state)
{
int result = discardIndexSaves(state->layout, false);
state->saveSlot = UINT_MAX;
if (result != UDS_SUCCESS) {
return logErrorWithStringError(result,
"%s: cannot destroy latest index save",
__func__);
}
return UDS_SUCCESS;
}
/*****************************************************************************/
Buffer *getStateIndexStateBuffer(IndexState *state, IOAccessMode mode)
{
unsigned int slot = mode == IO_READ ? state->loadSlot : state->saveSlot;
return getIndexStateBuffer(state->layout, slot);
}
/*****************************************************************************/
int openStateBufferedReader(IndexState *state,
RegionKind kind,
unsigned int zone,
BufferedReader **readerPtr)
{
return openIndexBufferedReader(state->layout, state->loadSlot, kind, zone,
readerPtr);
}
/*****************************************************************************/
int openStateBufferedWriter(IndexState *state,
RegionKind kind,
unsigned int zone,
BufferedWriter **writerPtr)
{
return openIndexBufferedWriter(state->layout, state->saveSlot, kind, zone,
writerPtr);
}