/*
* 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/udsMain.c#12 $
*/
#include "uds.h"
#include "config.h"
#include "geometry.h"
#include "indexLayout.h"
#include "indexRouter.h"
#include "indexSession.h"
#include "loadType.h"
#include "logger.h"
#include "memoryAlloc.h"
const UdsMemoryConfigSize UDS_MEMORY_CONFIG_MAX = 1024;
const UdsMemoryConfigSize UDS_MEMORY_CONFIG_256MB = (UdsMemoryConfigSize) -256;
const UdsMemoryConfigSize UDS_MEMORY_CONFIG_512MB = (UdsMemoryConfigSize) -512;
const UdsMemoryConfigSize UDS_MEMORY_CONFIG_768MB = (UdsMemoryConfigSize) -768;
/*
* ===========================================================================
* UDS system management
* ===========================================================================
*/
/**********************************************************************/
int udsInitializeConfiguration(UdsConfiguration *userConfig,
UdsMemoryConfigSize memGB)
{
if (userConfig == NULL) {
return logErrorWithStringError(UDS_CONF_PTR_REQUIRED,
"received a NULL config pointer");
}
/* Set the configuration parameters that change with memory size. If you
* change these values, you should also:
*
* Change Configuration_x1, which tests these values and expects to see them
*
* Bump the index configuration version number. This bump ensures that
* the test infrastructure will be forced to test the new configuration.
*/
unsigned int chaptersPerVolume, recordPagesPerChapter;
if (memGB == UDS_MEMORY_CONFIG_256MB) {
chaptersPerVolume = DEFAULT_CHAPTERS_PER_VOLUME;
recordPagesPerChapter = SMALL_RECORD_PAGES_PER_CHAPTER;
} else if (memGB == UDS_MEMORY_CONFIG_512MB) {
chaptersPerVolume = DEFAULT_CHAPTERS_PER_VOLUME;
recordPagesPerChapter = 2 * SMALL_RECORD_PAGES_PER_CHAPTER;
} else if (memGB == UDS_MEMORY_CONFIG_768MB) {
chaptersPerVolume = DEFAULT_CHAPTERS_PER_VOLUME;
recordPagesPerChapter = 3 * SMALL_RECORD_PAGES_PER_CHAPTER;
} else if (memGB == 1) {
chaptersPerVolume = DEFAULT_CHAPTERS_PER_VOLUME;
recordPagesPerChapter = DEFAULT_RECORD_PAGES_PER_CHAPTER;
} else if ((memGB > 1) && (memGB <= UDS_MEMORY_CONFIG_MAX)) {
chaptersPerVolume = memGB * DEFAULT_CHAPTERS_PER_VOLUME;
recordPagesPerChapter = DEFAULT_RECORD_PAGES_PER_CHAPTER;
} else {
return UDS_INVALID_MEMORY_SIZE;
}
int result = ALLOCATE(1, struct udsConfiguration, "udsConfiguration",
userConfig);
if (result != UDS_SUCCESS) {
return result;
}
(*userConfig)->recordPagesPerChapter = recordPagesPerChapter;
(*userConfig)->chaptersPerVolume = chaptersPerVolume;
(*userConfig)->sparseChaptersPerVolume = DEFAULT_SPARSE_CHAPTERS_PER_VOLUME;
(*userConfig)->cacheChapters = DEFAULT_CACHE_CHAPTERS;
(*userConfig)->checkpointFrequency = DEFAULT_CHECKPOINT_FREQUENCY;
(*userConfig)->masterIndexMeanDelta = DEFAULT_MASTER_INDEX_MEAN_DELTA;
(*userConfig)->bytesPerPage = DEFAULT_BYTES_PER_PAGE;
(*userConfig)->sparseSampleRate = DEFAULT_SPARSE_SAMPLE_RATE;
(*userConfig)->nonce = 0;
return UDS_SUCCESS;
}
/**********************************************************************/
void udsConfigurationSetSparse(UdsConfiguration userConfig, bool sparse)
{
bool prevSparse = (userConfig->sparseChaptersPerVolume != 0);
if (sparse == prevSparse) {
// nothing to do
return;
}
unsigned int prevChaptersPerVolume = userConfig->chaptersPerVolume;
if (sparse) {
// Index 10TB with 4K blocks, 95% sparse, fit in dense (1TB) footprint
userConfig->chaptersPerVolume = 10 * prevChaptersPerVolume;
userConfig->sparseChaptersPerVolume = 9 * prevChaptersPerVolume
+ prevChaptersPerVolume / 2;
userConfig->sparseSampleRate = 32;
} else {
userConfig->chaptersPerVolume = prevChaptersPerVolume / 10;
userConfig->sparseChaptersPerVolume = 0;
userConfig->sparseSampleRate = 0;
}
}
/**********************************************************************/
bool udsConfigurationGetSparse(UdsConfiguration userConfig)
{
return userConfig->sparseChaptersPerVolume > 0;
}
/**********************************************************************/
void udsConfigurationSetNonce(UdsConfiguration userConfig, UdsNonce nonce)
{
userConfig->nonce = nonce;
}
/**********************************************************************/
UdsNonce udsConfigurationGetNonce(UdsConfiguration userConfig)
{
return userConfig->nonce;
}
/**********************************************************************/
unsigned int udsConfigurationGetMemory(UdsConfiguration userConfig)
{
enum {
CHAPTERS = DEFAULT_CHAPTERS_PER_VOLUME,
SMALL_PAGES = CHAPTERS * SMALL_RECORD_PAGES_PER_CHAPTER,
LARGE_PAGES = CHAPTERS * DEFAULT_RECORD_PAGES_PER_CHAPTER
};
unsigned int pages = (userConfig->chaptersPerVolume
* userConfig->recordPagesPerChapter);
if (userConfig->sparseChaptersPerVolume != 0) {
pages /= 10;
}
switch (pages) {
case SMALL_PAGES: return UDS_MEMORY_CONFIG_256MB;
case 2 * SMALL_PAGES: return UDS_MEMORY_CONFIG_512MB;
case 3 * SMALL_PAGES: return UDS_MEMORY_CONFIG_768MB;
default: return pages / LARGE_PAGES;
}
}
/**********************************************************************/
unsigned int
udsConfigurationGetChaptersPerVolume(UdsConfiguration userConfig)
{
return userConfig->chaptersPerVolume;
}
/**********************************************************************/
void udsFreeConfiguration(UdsConfiguration userConfig)
{
FREE(userConfig);
}
/**********************************************************************/
int udsCreateIndexSession(struct uds_index_session **session)
{
if (session == NULL) {
return UDS_NO_INDEXSESSION;
}
struct uds_index_session *indexSession = NULL;
int result = makeEmptyIndexSession(&indexSession);
if (result != UDS_SUCCESS) {
return result;
}
*session = indexSession;
return UDS_SUCCESS;
}
/**********************************************************************/
static
int initializeIndexSessionWithLayout(struct uds_index_session *indexSession,
IndexLayout *layout,
const struct uds_parameters *userParams,
LoadType loadType)
{
int result = ((loadType == LOAD_CREATE)
? writeIndexConfig(layout, &indexSession->userConfig)
: verifyIndexConfig(layout, &indexSession->userConfig));
if (result != UDS_SUCCESS) {
return result;
}
Configuration *indexConfig;
result = makeConfiguration(&indexSession->userConfig, &indexConfig);
if (result != UDS_SUCCESS) {
logErrorWithStringError(result, "Failed to allocate config");
return result;
}
// Zero the stats for the new index.
memset(&indexSession->stats, 0, sizeof(indexSession->stats));
result = makeIndexRouter(layout, indexConfig, userParams, loadType,
&indexSession->loadContext, enterCallbackStage,
&indexSession->router);
freeConfiguration(indexConfig);
if (result != UDS_SUCCESS) {
logErrorWithStringError(result, "Failed to make router");
return result;
}
logUdsConfiguration(&indexSession->userConfig);
return UDS_SUCCESS;
}
/**********************************************************************/
static int initializeIndexSession(struct uds_index_session *indexSession,
const char *name,
const struct uds_parameters *userParams,
LoadType loadType)
{
IndexLayout *layout;
int result = makeIndexLayout(name, loadType == LOAD_CREATE,
&indexSession->userConfig, &layout);
if (result != UDS_SUCCESS) {
return result;
}
result = initializeIndexSessionWithLayout(indexSession, layout, userParams,
loadType);
putIndexLayout(&layout);
return result;
}
/**********************************************************************/
int udsOpenIndex(UdsOpenIndexType openType,
const char *name,
const struct uds_parameters *userParams,
UdsConfiguration userConfig,
struct uds_index_session *session)
{
if (name == NULL) {
return UDS_INDEX_NAME_REQUIRED;
}
if (userConfig == NULL) {
return UDS_CONF_REQUIRED;
}
if (session == NULL) {
return UDS_NO_INDEXSESSION;
}
int result = startLoadingIndexSession(session);
if (result != UDS_SUCCESS) {
return result;
}
session->userConfig = *userConfig;
// Map the external openType to the internal loadType
LoadType loadType = openType == UDS_CREATE ? LOAD_CREATE
: openType == UDS_NO_REBUILD ? LOAD_LOAD
: LOAD_REBUILD;
logNotice("%s: %s", getLoadType(loadType), name);
result = initializeIndexSession(session, name, userParams, loadType);
if (result != UDS_SUCCESS) {
logErrorWithStringError(result, "Failed %s", getLoadType(loadType));
saveAndFreeIndex(session);
}
finishLoadingIndexSession(session, result);
return sansUnrecoverable(result);
}
/**********************************************************************/
const char *udsGetVersion(void)
{
#ifdef UDS_VERSION
return UDS_VERSION;
#else
return "internal version";
#endif
}
/**********************************************************************/
const char *udsStringError(int errnum, char *buf, size_t buflen)
{
if (buf == NULL) {
return NULL;
}
return stringError(errnum, buf, buflen);
}