/*
* 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/masterIndex006.c#2 $
*/
#include "masterIndex006.h"
#include "buffer.h"
#include "compiler.h"
#include "errors.h"
#include "hashUtils.h"
#include "logger.h"
#include "masterIndex005.h"
#include "memoryAlloc.h"
#include "permassert.h"
#include "threads.h"
#include "uds.h"
/*
* The master index is a kept as a wrapper around 2 master index
* implementations, one for dense chapters and one for sparse chapters.
* Methods will be routed to one or the other, or both, depending on the
* method and data passed in.
*
* The master index is divided into zones, and in normal operation there is
* one thread operating on each zone. Any operation that operates on all
* the zones needs to do its operation at a safe point that ensures that
* only one thread is operating on the master index.
*
* The only multithreaded operation supported by the sparse master index is
* the lookupMasterIndexName() method. It is called by the thread that
* assigns an index request to the proper zone, and needs to do a master
* index query for sampled chunk names. The zone mutexes are used to make
* this lookup operation safe.
*/
typedef struct __attribute__((aligned(CACHE_LINE_BYTES))) masterIndexZone {
Mutex hookMutex; // Protects the sampled index in this zone
} MasterIndexZone;
typedef struct {
MasterIndex common; // Common master index methods
unsigned int sparseSampleRate; // The sparse sample rate
unsigned int numZones; // The number of zones
MasterIndex *miNonHook; // The non-hook index
MasterIndex *miHook; // The hook index == sample index
MasterIndexZone *masterZones; // The zones
} MasterIndex6;
/**
* Determine whether a given chunk name is a hook.
*
* @param masterIndex The master index
* @param name The block name
*
* @return whether to use as sample
**/
static INLINE bool isMasterIndexSample_006(const MasterIndex *masterIndex,
const UdsChunkName *name)
{
const MasterIndex6 *mi6 = const_container_of(masterIndex, MasterIndex6,
common);
return (extractSamplingBytes(name) % mi6->sparseSampleRate) == 0;
}
/***********************************************************************/
/**
* Get the subindex for the given chunk name
*
* @param masterIndex The master index
* @param name The block name
*
* @return the subindex
**/
static INLINE MasterIndex *getSubIndex(const MasterIndex *masterIndex,
const UdsChunkName *name)
{
const MasterIndex6 *mi6 = const_container_of(masterIndex, MasterIndex6,
common);
return (isMasterIndexSample_006(masterIndex, name)
? mi6->miHook
: mi6->miNonHook);
}
/***********************************************************************/
/**
* Terminate and clean up the master index
*
* @param masterIndex The master index to terminate
**/
static void freeMasterIndex_006(MasterIndex *masterIndex)
{
if (masterIndex != NULL) {
MasterIndex6 *mi6 = container_of(masterIndex, MasterIndex6, common);
if (mi6->masterZones != NULL) {
unsigned int zone;
for (zone = 0; zone < mi6->numZones; zone++) {
destroyMutex(&mi6->masterZones[zone].hookMutex);
}
FREE(mi6->masterZones);
mi6->masterZones = NULL;
}
if (mi6->miNonHook != NULL) {
freeMasterIndex(mi6->miNonHook);
mi6->miNonHook = NULL;
}
if (mi6->miHook != NULL) {
freeMasterIndex(mi6->miHook);
mi6->miHook = NULL;
}
FREE(masterIndex);
}
}
/***********************************************************************/
/**
* Constants and structures for the saved master index file. "MI6" is for
* masterIndex006, and "-XXXX" is a number to increment when the format of
* the data changes.
**/
enum { MAGIC_SIZE = 8 };
static const char MAGIC_MI_START[] = "MI6-0001";
struct mi006_data {
char magic[MAGIC_SIZE]; // MAGIC_MI_START
unsigned int sparseSampleRate;
};
/***********************************************************************/
/**
* Set the tag value used when saving and/or restoring a master index.
*
* @param masterIndex The master index
* @param tag The tag value
**/
static void setMasterIndexTag_006(MasterIndex *masterIndex
__attribute__((unused)),
byte tag __attribute__((unused)))
{
}
/***********************************************************************/
__attribute__((warn_unused_result))
static int encodeMasterIndexHeader(Buffer *buffer, struct mi006_data *header)
{
int result = putBytes(buffer, MAGIC_SIZE, MAGIC_MI_START);
if (result != UDS_SUCCESS) {
return result;
}
result = putUInt32LEIntoBuffer(buffer, header->sparseSampleRate);
if (result != UDS_SUCCESS) {
return result;
}
result = ASSERT_LOG_ONLY(contentLength(buffer) == sizeof(struct mi006_data),
"%zu bytes of config written, of %zu expected",
contentLength(buffer), sizeof(struct mi006_data));
return result;
}
/**
* Start saving a master index to a buffered output stream.
*
* @param masterIndex The master index
* @param zoneNumber The number of the zone to save
* @param bufferedWriter The index state component being written
*
* @return UDS_SUCCESS on success, or an error code on failure
**/
static int startSavingMasterIndex_006(const MasterIndex *masterIndex,
unsigned int zoneNumber,
BufferedWriter *bufferedWriter)
{
const MasterIndex6 *mi6 = const_container_of(masterIndex, MasterIndex6,
common);
Buffer *buffer;
int result = makeBuffer(sizeof(struct mi006_data), &buffer);
if (result != UDS_SUCCESS) {
return result;
}
struct mi006_data header;
memset(&header, 0, sizeof(header));
memcpy(header.magic, MAGIC_MI_START, MAGIC_SIZE);
header.sparseSampleRate = mi6->sparseSampleRate;
result = encodeMasterIndexHeader(buffer, &header);
if (result != UDS_SUCCESS) {
freeBuffer(&buffer);
return result;
}
result = writeToBufferedWriter(bufferedWriter, getBufferContents(buffer),
contentLength(buffer));
freeBuffer(&buffer);
if (result != UDS_SUCCESS) {
logWarningWithStringError(result, "failed to write master index header");
return result;
}
result = startSavingMasterIndex(mi6->miNonHook, zoneNumber, bufferedWriter);
if (result != UDS_SUCCESS) {
return result;
}
result = startSavingMasterIndex(mi6->miHook, zoneNumber, bufferedWriter);
if (result != UDS_SUCCESS) {
return result;
}
return UDS_SUCCESS;
}
/***********************************************************************/
/**
* Have all the data been written while saving a master index to an output
* stream? If the answer is yes, it is still necessary to call
* finishSavingMasterIndex(), which will return quickly.
*
* @param masterIndex The master index
* @param zoneNumber The number of the zone to save
*
* @return true if all the data are written
**/
static bool isSavingMasterIndexDone_006(const MasterIndex *masterIndex,
unsigned int zoneNumber)
{
const MasterIndex6 *mi6 = const_container_of(masterIndex, MasterIndex6,
common);
return (isSavingMasterIndexDone(mi6->miNonHook, zoneNumber)
&& isSavingMasterIndexDone(mi6->miHook, zoneNumber));
}
/***********************************************************************/
/**
* Finish saving a master index to an output stream. Force the writing of
* all of the remaining data. If an error occurred asynchronously during
* the save operation, it will be returned here.
*
* @param masterIndex The master index
* @param zoneNumber The number of the zone to save
*
* @return UDS_SUCCESS on success, or an error code on failure
**/
static int finishSavingMasterIndex_006(const MasterIndex *masterIndex,
unsigned int zoneNumber)
{
const MasterIndex6 *mi6 = const_container_of(masterIndex, MasterIndex6,
common);
int result = finishSavingMasterIndex(mi6->miNonHook, zoneNumber);
if (result == UDS_SUCCESS) {
result = finishSavingMasterIndex(mi6->miHook, zoneNumber);
}
return result;
}
/***********************************************************************/
/**
* Abort saving a master index to an output stream. If an error occurred
* asynchronously during the save operation, it will be dropped.
*
* @param masterIndex The master index
* @param zoneNumber The number of the zone to save
*
* @return UDS_SUCCESS on success, or an error code on failure
**/
static int abortSavingMasterIndex_006(const MasterIndex *masterIndex,
unsigned int zoneNumber)
{
const MasterIndex6 *mi6 = const_container_of(masterIndex, MasterIndex6,
common);
int result = abortSavingMasterIndex(mi6->miNonHook, zoneNumber);
int result2 = abortSavingMasterIndex(mi6->miHook, zoneNumber);
if (result == UDS_SUCCESS) {
result = result2;
}
return result;
}
/***********************************************************************/
__attribute__((warn_unused_result))
static int decodeMasterIndexHeader(Buffer *buffer, struct mi006_data *header)
{
int result = getBytesFromBuffer(buffer, sizeof(header->magic),
&header->magic);
if (result != UDS_SUCCESS) {
return result;
}
result = getUInt32LEFromBuffer(buffer, &header->sparseSampleRate);
if (result != UDS_SUCCESS) {
return result;
}
result = ASSERT_LOG_ONLY(contentLength(buffer) == 0,
"%zu bytes decoded of %zu expected",
bufferLength(buffer) - contentLength(buffer),
bufferLength(buffer));
if (result != UDS_SUCCESS) {
result = UDS_CORRUPT_COMPONENT;
}
return result;
}
/**
* Start restoring the master index from multiple buffered readers
*
* @param masterIndex The master index to restore into
* @param bufferedReaders The buffered reader to read the master index from
* @param numReaders The number of buffered readers
*
* @return UDS_SUCCESS on success, or an error code on failure
**/
static int startRestoringMasterIndex_006(MasterIndex *masterIndex,
BufferedReader **bufferedReaders,
int numReaders)
{
MasterIndex6 *mi6 = container_of(masterIndex, MasterIndex6, common);
int result = ASSERT_WITH_ERROR_CODE(masterIndex != NULL, UDS_BAD_STATE,
"cannot restore to null master index");
if (result != UDS_SUCCESS) {
return result;
}
int i;
for (i = 0; i < numReaders; i++) {
Buffer *buffer;
result = makeBuffer(sizeof(struct mi006_data), &buffer);
if (result != UDS_SUCCESS) {
return result;
}
result = readFromBufferedReader(bufferedReaders[i],
getBufferContents(buffer),
bufferLength(buffer));
if (result != UDS_SUCCESS) {
freeBuffer(&buffer);
return logWarningWithStringError(result,
"failed to read master index header");
}
result = resetBufferEnd(buffer, bufferLength(buffer));
if (result != UDS_SUCCESS) {
freeBuffer(&buffer);
return result;
}
struct mi006_data header;
result = decodeMasterIndexHeader(buffer, &header);
freeBuffer(&buffer);
if (result != UDS_SUCCESS) {
return result;
}
if (memcmp(header.magic, MAGIC_MI_START, MAGIC_SIZE) != 0) {
return logWarningWithStringError(UDS_CORRUPT_COMPONENT,
"master index file had bad magic"
" number");
}
if (i == 0) {
mi6->sparseSampleRate = header.sparseSampleRate;
} else if (mi6->sparseSampleRate != header.sparseSampleRate) {
logWarningWithStringError(UDS_CORRUPT_COMPONENT,
"Inconsistent sparse sample rate in delta"
" index zone files: %u vs. %u",
mi6->sparseSampleRate,
header.sparseSampleRate);
return UDS_CORRUPT_COMPONENT;
}
}
result = startRestoringMasterIndex(mi6->miNonHook, bufferedReaders,
numReaders);
if (result != UDS_SUCCESS) {
return result;
}
return startRestoringMasterIndex(mi6->miHook, bufferedReaders, numReaders);
}
/***********************************************************************/
/**
* Have all the data been read while restoring a master index from an
* input stream?
*
* @param masterIndex The master index to restore into
*
* @return true if all the data are read
**/
static bool isRestoringMasterIndexDone_006(const MasterIndex *masterIndex)
{
const MasterIndex6 *mi6 = const_container_of(masterIndex, MasterIndex6,
common);
return (isRestoringMasterIndexDone(mi6->miNonHook)
&& isRestoringMasterIndexDone(mi6->miHook));
}
/***********************************************************************/
/**
* Restore a saved delta list
*
* @param masterIndex The master index to restore into
* @param dlsi The DeltaListSaveInfo describing the delta list
* @param data The saved delta list bit stream
*
* @return error code or UDS_SUCCESS
**/
static int restoreDeltaListToMasterIndex_006(MasterIndex *masterIndex,
const DeltaListSaveInfo *dlsi,
const byte data[DELTA_LIST_MAX_BYTE_COUNT])
{
MasterIndex6 *mi6 = container_of(masterIndex, MasterIndex6, common);
int result = restoreDeltaListToMasterIndex(mi6->miNonHook, dlsi, data);
if (result != UDS_SUCCESS) {
result = restoreDeltaListToMasterIndex(mi6->miHook, dlsi, data);
}
return result;
}
/***********************************************************************/
/**
* Abort restoring a master index from an input stream.
*
* @param masterIndex The master index
**/
static void abortRestoringMasterIndex_006(MasterIndex *masterIndex)
{
MasterIndex6 *mi6 = container_of(masterIndex, MasterIndex6, common);
abortRestoringMasterIndex(mi6->miNonHook);
abortRestoringMasterIndex(mi6->miHook);
}
/***********************************************************************/
/**
* Set the open chapter number on a zone. The master index zone will be
* modified to index the proper number of chapters ending with the new open
* chapter.
*
* @param masterIndex The master index
* @param zoneNumber The zone number
* @param virtualChapter The new open chapter number
**/
static void setMasterIndexZoneOpenChapter_006(MasterIndex *masterIndex,
unsigned int zoneNumber,
uint64_t virtualChapter)
{
MasterIndex6 *mi6 = container_of(masterIndex, MasterIndex6, common);
setMasterIndexZoneOpenChapter(mi6->miNonHook, zoneNumber, virtualChapter);
// We need to prevent a lookupMasterIndexName() happening while we are
// changing the open chapter number
Mutex *mutex = &mi6->masterZones[zoneNumber].hookMutex;
lockMutex(mutex);
setMasterIndexZoneOpenChapter(mi6->miHook, zoneNumber, virtualChapter);
unlockMutex(mutex);
}
/***********************************************************************/
/**
* Set the open chapter number. The master index will be modified to index
* the proper number of chapters ending with the new open chapter.
*
* @param masterIndex The master index
* @param virtualChapter The new open chapter number
**/
static void setMasterIndexOpenChapter_006(MasterIndex *masterIndex,
uint64_t virtualChapter)
{
MasterIndex6 *mi6 = container_of(masterIndex, MasterIndex6, common);
unsigned int zone;
for (zone = 0; zone < mi6->numZones; zone++) {
setMasterIndexZoneOpenChapter_006(masterIndex, zone, virtualChapter);
}
}
/***********************************************************************/
/**
* Find the master index zone associated with a chunk name
*
* @param masterIndex The master index
* @param name The chunk name
*
* @return the zone that the chunk name belongs to
**/
static unsigned int getMasterIndexZone_006(const MasterIndex *masterIndex,
const UdsChunkName *name)
{
return getMasterIndexZone(getSubIndex(masterIndex, name), name);
}
/***********************************************************************/
/**
* Do a quick read-only lookup of the chunk name and return information
* needed by the index code to process the chunk name.
*
* @param masterIndex The master index
* @param name The chunk name
* @param triage Information about the chunk name
*
* @return UDS_SUCCESS or an error code
**/
static int lookupMasterIndexName_006(const MasterIndex *masterIndex,
const UdsChunkName *name,
MasterIndexTriage *triage)
{
const MasterIndex6 *mi6 = const_container_of(masterIndex, MasterIndex6,
common);
triage->isSample = isMasterIndexSample_006(masterIndex, name);
triage->inSampledChapter = false;
triage->zone = getMasterIndexZone_006(masterIndex, name);
int result = UDS_SUCCESS;
if (triage->isSample) {
Mutex *mutex = &mi6->masterZones[triage->zone].hookMutex;
lockMutex(mutex);
result = lookupMasterIndexSampledName(mi6->miHook, name, triage);
unlockMutex(mutex);
}
return result;
}
/***********************************************************************/
/**
* Do a quick read-only lookup of the sampled chunk name and return
* information needed by the index code to process the chunk name.
*
* @param masterIndex The master index
* @param name The chunk name
* @param triage Information about the chunk name. The zone and
* isSample fields are already filled in. Set
* inSampledChapter and virtualChapter if the chunk
* name is found in the index.
*
* @return UDS_SUCCESS or an error code
**/
static int lookupMasterIndexSampledName_006(const MasterIndex *masterIndex
__attribute__((unused)),
const UdsChunkName *name
__attribute__((unused)),
MasterIndexTriage *triage
__attribute__((unused)))
{
return ASSERT_WITH_ERROR_CODE(false, UDS_BAD_STATE,
"%s should not be called", __func__);
}
/***********************************************************************/
/**
* Find the master index record associated with a block name
*
* This is always the first routine to be called when dealing with a delta
* master index entry. The fields of the record parameter should be
* examined to determine the state of the record:
*
* If isFound is false, then we did not find an entry for the block
* name. Information is saved in the MasterIndexRecord so that
* putMasterIndexRecord() will insert an entry for that block name at
* the proper place.
*
* If isFound is true, then we did find an entry for the block name.
* Information is saved in the MasterIndexRecord so that the "chapter"
* and "isCollision" fields reflect the entry found.
* Calls to removeMasterIndexRecord() will remove the entry, calls to
* setMasterIndexRecordChapter() can modify the entry, and calls to
* putMasterIndexRecord() can insert a collision record with this
* entry.
*
* @param masterIndex The master index to search
* @param name The chunk name
* @param record Set to the info about the record searched for
*
* @return UDS_SUCCESS or an error code
**/
static int getMasterIndexRecord_006(MasterIndex *masterIndex,
const UdsChunkName *name,
MasterIndexRecord *record)
{
const MasterIndex6 *mi6 = const_container_of(masterIndex, MasterIndex6,
common);
int result;
if (isMasterIndexSample_006(masterIndex, name)) {
/*
* We need to prevent a lookupMasterIndexName() happening while we are
* finding the master index record. Remember that because of lazy LRU
* flushing of the master index, getMasterIndexRecord() is not a
* read-only operation.
*/
unsigned int zone = getMasterIndexZone(mi6->miHook, name);
Mutex *mutex = &mi6->masterZones[zone].hookMutex;
lockMutex(mutex);
result = getMasterIndexRecord(mi6->miHook, name, record);
unlockMutex(mutex);
// Remember the mutex so that other operations on the MasterIndexRecord
// can use it
record->mutex = mutex;
} else {
result = getMasterIndexRecord(mi6->miNonHook, name, record);
}
return result;
}
/***********************************************************************/
/**
* Get the number of bytes used for master index entries.
*
* @param masterIndex The master index
*
* @return The number of bytes in use
**/
static size_t getMasterIndexMemoryUsed_006(const MasterIndex *masterIndex)
{
const MasterIndex6 *mi6 = const_container_of(masterIndex, MasterIndex6,
common);
return (getMasterIndexMemoryUsed(mi6->miNonHook)
+ getMasterIndexMemoryUsed(mi6->miHook));
}
/***********************************************************************/
/**
* Return the master index stats. There is only one portion of the master
* index in this implementation, and we call it the dense portion of the
* index.
*
* @param masterIndex The master index
* @param dense Stats for the dense portion of the index
* @param sparse Stats for the sparse portion of the index
**/
static void getMasterIndexStats_006(const MasterIndex *masterIndex,
MasterIndexStats *dense,
MasterIndexStats *sparse)
{
const MasterIndex6 *mi6 = const_container_of(masterIndex, MasterIndex6,
common);
MasterIndexStats dummyStats;
getMasterIndexStats(mi6->miNonHook, dense, &dummyStats);
getMasterIndexStats(mi6->miHook, sparse, &dummyStats);
}
/***********************************************************************/
typedef struct {
Configuration hookConfig; // Describe the hook part of the index
Geometry hookGeometry;
Configuration nonHookConfig; // Describe the non-hook part of the index
Geometry nonHookGeometry;
} SplitConfig;
/***********************************************************************/
static int splitConfiguration006(const Configuration *config,
SplitConfig *split)
{
int result
= ASSERT_WITH_ERROR_CODE(config->geometry->sparseChaptersPerVolume != 0,
UDS_INVALID_ARGUMENT,
"cannot initialize sparse+dense master index"
" with no sparse chapters");
if (result != UDS_SUCCESS) {
return result;
}
result = ASSERT_WITH_ERROR_CODE(config->sparseSampleRate != 0,
UDS_INVALID_ARGUMENT,
"cannot initialize sparse+dense master"
" index with a sparse sample rate of %u",
config->sparseSampleRate);
if (result != UDS_SUCCESS) {
return result;
}
// Start with copies of the base configuration
split->hookConfig = *config;
split->hookGeometry = *config->geometry;
split->hookConfig.geometry = &split->hookGeometry;
split->nonHookConfig = *config;
split->nonHookGeometry = *config->geometry;
split->nonHookConfig.geometry = &split->nonHookGeometry;
uint64_t sampleRate = config->sparseSampleRate;
uint64_t numChapters = config->geometry->chaptersPerVolume;
uint64_t numSparseChapters = config->geometry->sparseChaptersPerVolume;
uint64_t numDenseChapters = numChapters - numSparseChapters;
uint64_t sampleRecords = config->geometry->recordsPerChapter / sampleRate;
// Adjust the number of records indexed for each chapter
split->hookGeometry.recordsPerChapter = sampleRecords;
split->nonHookGeometry.recordsPerChapter -= sampleRecords;
// Adjust the number of chapters indexed
split->hookGeometry.sparseChaptersPerVolume = 0;
split->nonHookGeometry.sparseChaptersPerVolume = 0;
split->nonHookGeometry.chaptersPerVolume = numDenseChapters;
return UDS_SUCCESS;
}
/***********************************************************************/
int computeMasterIndexSaveBytes006(const Configuration *config,
size_t *numBytes)
{
SplitConfig split;
int result = splitConfiguration006(config, &split);
if (result != UDS_SUCCESS) {
return result;
}
size_t hookBytes, nonHookBytes;
result = computeMasterIndexSaveBytes005(&split.hookConfig, &hookBytes);
if (result != UDS_SUCCESS) {
return result;
}
result = computeMasterIndexSaveBytes005(&split.nonHookConfig, &nonHookBytes);
if (result != UDS_SUCCESS) {
return result;
}
// Saving a MasterIndex006 needs a header plus the hook index plus the
// non-hook index
*numBytes = sizeof(struct mi006_data) + hookBytes + nonHookBytes;
return UDS_SUCCESS;
}
/***********************************************************************/
int makeMasterIndex006(const Configuration *config, unsigned int numZones,
uint64_t volumeNonce, MasterIndex **masterIndex)
{
SplitConfig split;
int result = splitConfiguration006(config, &split);
if (result != UDS_SUCCESS) {
return result;
}
MasterIndex6 *mi6;
result = ALLOCATE(1, MasterIndex6, "master index", &mi6);
if (result != UDS_SUCCESS) {
return result;
}
mi6->common.abortRestoringMasterIndex = abortRestoringMasterIndex_006;
mi6->common.abortSavingMasterIndex = abortSavingMasterIndex_006;
mi6->common.finishSavingMasterIndex = finishSavingMasterIndex_006;
mi6->common.freeMasterIndex = freeMasterIndex_006;
mi6->common.getMasterIndexMemoryUsed = getMasterIndexMemoryUsed_006;
mi6->common.getMasterIndexRecord = getMasterIndexRecord_006;
mi6->common.getMasterIndexStats = getMasterIndexStats_006;
mi6->common.getMasterIndexZone = getMasterIndexZone_006;
mi6->common.isMasterIndexSample = isMasterIndexSample_006;
mi6->common.isRestoringMasterIndexDone = isRestoringMasterIndexDone_006;
mi6->common.isSavingMasterIndexDone = isSavingMasterIndexDone_006;
mi6->common.lookupMasterIndexName = lookupMasterIndexName_006;
mi6->common.lookupMasterIndexSampledName = lookupMasterIndexSampledName_006;
mi6->common.restoreDeltaListToMasterIndex = restoreDeltaListToMasterIndex_006;
mi6->common.setMasterIndexOpenChapter = setMasterIndexOpenChapter_006;
mi6->common.setMasterIndexTag = setMasterIndexTag_006;
mi6->common.setMasterIndexZoneOpenChapter = setMasterIndexZoneOpenChapter_006;
mi6->common.startRestoringMasterIndex = startRestoringMasterIndex_006;
mi6->common.startSavingMasterIndex = startSavingMasterIndex_006;
mi6->numZones = numZones;
mi6->sparseSampleRate = config->sparseSampleRate;
result = ALLOCATE(numZones, MasterIndexZone, "master index zones",
&mi6->masterZones);
unsigned int zone;
for (zone = 0; zone < numZones; zone++) {
if (result == UDS_SUCCESS) {
result = initMutex(&mi6->masterZones[zone].hookMutex);
}
}
if (result != UDS_SUCCESS) {
freeMasterIndex_006(&mi6->common);
return result;
}
result = makeMasterIndex005(&split.nonHookConfig, numZones, volumeNonce,
&mi6->miNonHook);
if (result != UDS_SUCCESS) {
freeMasterIndex_006(&mi6->common);
return logErrorWithStringError(result,
"Error creating non hook master index");
}
setMasterIndexTag(mi6->miNonHook, 'd');
result = makeMasterIndex005(&split.hookConfig, numZones, volumeNonce,
&mi6->miHook);
if (result != UDS_SUCCESS) {
freeMasterIndex_006(&mi6->common);
return logErrorWithStringError(result,
"Error creating hook master index");
}
setMasterIndexTag(mi6->miHook, 's');
*masterIndex = &mi6->common;
return UDS_SUCCESS;
}