Files
mars-flaim/flaim/util/gigatest.cpp
ahodgkinson f54e6ce080 Changed license to LGPL.
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@1009 0109f412-320b-0410-ab79-c3e0c5ffbbe6
2007-01-23 09:38:48 +00:00

1426 lines
32 KiB
C++

//-------------------------------------------------------------------------
// Desc: Gigatest
// Tabs: 3
//
// Copyright (c) 2000-2007 Novell, Inc. All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version 2.1
// of the License.
//
// This library 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
// Library Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, contact Novell, Inc.
//
// To contact Novell about this file by physical or electronic mail,
// you may find current contact information at www.novell.com.
//
// $Id$
//------------------------------------------------------------------------------
#include "flaim.h"
#include "flm_lutl.h"
#include "gigatest.h"
// Columns/Rows where things go on the screen.
#define LABEL_COLUMN 5
#define DATA_COLUMN 35
#define MAX_CACHE_ROW 1
#define USED_CACHE_ROW 2
#define ITEMS_CACHED_ROW 3
#define DIRTY_CACHE_ROW 4
#define LOG_CACHE_ROW 5
#define FREE_CACHE_ROW 6
#define CP_STATE_ROW 7
#define DB_NAME_ROW 8
#define TOTAL_TO_LOAD_ROW 9
#define TRANS_SIZE_ROW 10
#define TOTAL_LOADED_ROW 11
#define ADDS_PER_SEC_CURRENT 12
#define ADDS_PER_SEC_OVERALL 13
#define ELAPSED_TIME_ROW 14
char gv_szDibName[ 200];
char gv_szDataDir[ 200];
char gv_szRflDir[ 200];
char gv_szDirectoryPath[ F_PATH_MAX_SIZE];
char gv_pszFileName[ F_FILENAME_SIZE];
FLMUINT gv_ui10Secs;
FLMUINT gv_ui1Sec;
IF_Thread * gv_pScreenThrd = NULL;
FLMUINT gv_uiCacheSize;
FLMUINT gv_uiBlockCachePercentage;
FLMUINT gv_uiMaxDirtyCache;
FLMUINT gv_uiLowDirtyCache;
FLMUINT gv_uiTotalToLoad;
FLMUINT gv_uiTransSize;
FLMUINT gv_uiTotalLoaded;
FLMUINT gv_ui10SecTotal;
FLMUINT gv_ui10SecStartTime;
FLMUINT gv_uiStartTime;
HFDB gv_hDb;
FLMBOOL gv_bShutdown;
FLMBOOL gv_bRunning;
FTX_SCREEN * gv_pScreen;
FTX_WINDOW * gv_pWindow;
F_MUTEX gv_hWindowMutex;
char * gv_pszTitle;
FLMUINT gv_uiNumCols;
FLMUINT gv_uiNumRows;
FLMUINT gv_uiMaxMemory;
FLMUINT gv_uiCPInterval;
FLMUINT gv_uiNumFields;
FLMUINT gv_uiPreallocSpace;
const char ** gv_ppszCurrGiven;
const char ** gv_ppszCurrFamily;
IF_Thread * gv_pIxManagerThrd;
FLMBOOL gv_bBatchMode;
FLMBOOL gv_bDisableDirectIO;
#ifdef FLM_NLM
FLMBOOL gv_bSynchronized;
#endif
const char * gv_pszGigaDictionary =
"0 @1@ field Person\n"
" 1 type text\n"
"0 @2@ field LastName\n"
" 1 type text\n"
"0 @3@ field FirstName\n"
" 1 type text\n"
"0 @4@ field Age\n"
" 1 type number\n"
"0 @100@ index LastFirst_IX\n"
" 1 language US\n"
" 1 key\n"
" 2 field 2\n"
" 3 required\n"
" 2 field 3\n"
" 3 required\n";
#define PERSON_TAG 1
#define LAST_NAME_TAG 2
#define FIRST_NAME_TAG 3
#define AGE_TAG 4
#define LAST_NAME_FIRST_NAME_IX 100
FLMUINT gigaGetInput(
const char * pszMsg1,
const char * pszMsg2,
FLMBOOL bMutexLocked = FALSE);
void gigaOutputErrMsg(
const char * pszErrMsg,
FLMBOOL bMutexLocked = FALSE);
void gigaOutputRcErr(
const char * pszWhat,
RCODE rc,
FLMBOOL bMutexLocked = FALSE);
void gigaOutputLabel(
FLMUINT uiRow,
const char * pszLabel,
FLMBOOL bMutexLocked = FALSE);
void gigaOutputStr(
FLMUINT uiRow,
const char * pszStr,
FLMBOOL bMutexLocked = FALSE);
void gigaOutputUINT(
FLMUINT uiRow,
FLMUINT uiNum,
FLMBOOL bMutexLocked = FALSE);
#ifdef FLM_NLM
extern "C"
{
void SynchronizeStart();
int nlm_main(
int ArgC,
char ** ArgV);
int atexit( void (*)( void ) );
}
void gigaCleanup( void);
#endif
void gigaInitGlobalVars( void);
void gigaShowHelp( void);
FLMBOOL gigaGetParams(
FLMINT iArgC,
const char ** ppszArgV);
FLMUINT gigaSeeIfQuit( void);
RCODE gigaStartTrans( void);
RCODE gigaMakeNewRecord(
FlmRecord ** ppRecord);
RCODE gigaCommitTrans( void);
void gigaUpdateMemInfo( void);
RCODE gigaLoadDatabase( void);
void gigaCheckpointDisplay( void);
RCODE FLMAPI gigaScreenThread(
IF_Thread * pThread);
RCODE gigaStartScreenThread( void);
/********************************************************************
Desc:
*********************************************************************/
#if defined( FLM_UNIX)
int main(
int iArgC,
char ** ppszArgV)
#elif defined( FLM_NLM)
int nlm_main(
int iArgC,
char ** ppszArgV)
#else
int __cdecl main(
int iArgC,
char ** ppszArgV)
#endif
{
int iRetCode = 0;
gigaInitGlobalVars();
#ifdef FLM_NLM
// Setup the routines to be called when the NLM exits itself
atexit( gigaCleanup);
#endif
if( RC_BAD( FlmStartup()))
{
iRetCode = 1;
goto Exit;
}
if( RC_BAD( FTXInit( gv_pszTitle, (FLMBYTE)80, (FLMBYTE)50,
FLM_BLUE, FLM_LIGHTGRAY, NULL, NULL)))
{
iRetCode = 1;
goto Exit;
}
FTXSetShutdownFlag( &gv_bShutdown);
if( RC_BAD( FTXScreenInit( gv_pszTitle, &gv_pScreen)))
{
iRetCode = 1;
goto Exit;
}
if( RC_BAD( FTXScreenInitStandardWindows( gv_pScreen, FLM_RED, FLM_WHITE,
FLM_BLUE, FLM_WHITE, FALSE, TRUE, gv_pszTitle, NULL, &gv_pWindow)))
{
iRetCode = 1;
goto Exit;
}
FTXWinGetCanvasSize( gv_pWindow, &gv_uiNumCols, &gv_uiNumRows);
if( RC_BAD( f_mutexCreate( &gv_hWindowMutex)))
{
iRetCode = 99;
goto Exit;
}
if( !gigaGetParams( iArgC, (const char **)ppszArgV))
{
iRetCode = 2;
goto Exit;
}
f_pathReduce( gv_szDibName, gv_szDirectoryPath, gv_pszFileName);
if( !gv_szDirectoryPath [0])
{
f_strcpy( gv_szDirectoryPath, ".");
}
if( RC_BAD( gigaLoadDatabase()))
{
iRetCode = 7;
goto Exit;
}
if( !gv_bBatchMode)
{
gigaOutputErrMsg( "Load complete");
}
Exit:
if( gv_hWindowMutex != F_MUTEX_NULL)
{
f_mutexDestroy( &gv_hWindowMutex);
}
FTXExit();
FlmShutdown();
#ifdef FLM_NLM
if (!gv_bSynchronized)
{
SynchronizeStart();
gv_bSynchronized = TRUE;
}
#endif
gv_bRunning = FALSE;
return( iRetCode);
}
/********************************************************************
Desc: Initialize global variables.
*********************************************************************/
void gigaInitGlobalVars( void)
{
gv_hDb = HFDB_NULL;
gv_bShutdown = FALSE;
gv_bRunning = TRUE;
gv_pScreen = NULL;
gv_pWindow = NULL;
gv_hWindowMutex = F_MUTEX_NULL;
gv_pszTitle = (char *)"GigaTest 1.0 for FLAIM";
gv_uiNumCols = 0;
gv_uiNumRows = 0;
gv_uiMaxMemory = 0;
gv_uiCPInterval = 0xFFFFFFFF;
gv_uiNumFields = 0;
gv_uiPreallocSpace = 0;
gv_ppszCurrGiven = &gv_pszGivenNames [0];
gv_ppszCurrFamily = &gv_pszFamilyNames [0];
gv_pIxManagerThrd = NULL;
gv_bBatchMode = FALSE;
gv_bDisableDirectIO = FALSE;
#ifdef FLM_NLM
gv_bSynchronized = FALSE;
#endif
}
/********************************************************************
Desc: Show help for the gigaloader.
*********************************************************************/
void gigaShowHelp( void)
{
#ifdef FLM_NLM
if (!gv_bSynchronized)
{
SynchronizeStart();
gv_bSynchronized = TRUE;
}
#endif
f_mutexLock( gv_hWindowMutex);
FTXWinClear( gv_pWindow);
FTXWinPrintStr( gv_pWindow, "\n");
FTXWinPrintStr( gv_pWindow,
"Parameters: [Number To Create] [Options]\n\n");
FTXWinPrintStr( gv_pWindow,
"\nNumber To Create\n");
FTXWinPrintStr( gv_pWindow,
" Number of object to create (default = 100,000)\n");
FTXWinPrintStr( gv_pWindow,
"\nOptions (may be specified anywhere on command line):\n");
FTXWinPrintStr( gv_pWindow,
" -b = Run in batch mode.\n");
FTXWinPrintStr( gv_pWindow,
" -c<n> = Cache (bytes) to use, 0=Use default mode\n");
FTXWinPrintStr( gv_pWindow,
" -p<n> = Block cache percentage (0-100) to use (default 50)\n");
FTXWinPrintStr( gv_pWindow,
" -i<n> = Checkpoint interval (seconds) to use.\n");
#ifdef FLM_NLM
FTXWinPrintStr( gv_pWindow,
" -n<DbName> = Database name (default = sys:\\_netware\\gigatest.db).\n");
#else
FTXWinPrintStr( gv_pWindow,
" -n<DbName> = Database name (default = gigatest.db).\n");
#endif
FTXWinPrintStr( gv_pWindow,
" -dr<Dir> = Directory where rfl files are located (default=same as db)\n");
FTXWinPrintStr( gv_pWindow,
" -dd<Dir> = Directory where data files are located (default=same as db)\n");
FTXWinPrintStr( gv_pWindow,
" -t<n> = Transaction Size (objects per transaction, default=100).\n");
#ifdef FLM_NLM
FTXWinPrintStr( gv_pWindow,
" -w = Wait to end to synchronize\n");
#endif
FTXWinPrintStr( gv_pWindow,
" -md<n> = Set maximum dirty cache (bytes), 0=Use default mode\n");
FTXWinPrintStr( gv_pWindow,
" -ld<n> = Set low dirty cache (bytes), default=0\n");
FTXWinPrintStr( gv_pWindow,
" -? = A '?' anywhere in the command line will cause this help\n");
FTXWinPrintStr( gv_pWindow,
" screen to be displayed, with or without the leading '-'.\n");
f_mutexUnlock( gv_hWindowMutex);
gigaOutputErrMsg( "");
}
/********************************************************************
Desc: Get command line parameters.
*********************************************************************/
FLMBOOL gigaGetParams(
FLMINT iArgC,
const char ** ppszArgV)
{
FLMBOOL bOk = FALSE;
FLMUINT uiLoop;
const char * pszPtr;
FLMBOOL bHaveNumToLoad = FALSE;
#ifdef FLM_NLM
FLMBOOL bWaitToSync = FALSE;
#endif
char szMsg [100];
gv_uiCacheSize = 0;
gv_uiBlockCachePercentage = 50;
gv_uiMaxDirtyCache = 0;
gv_uiLowDirtyCache = 0;
gv_uiTotalToLoad = 100000;
gv_uiTransSize = 100;
gv_uiTotalLoaded = 0;
#ifdef FLM_NLM
f_strcpy( gv_szDibName, "sys:\\_netware\\gigatest.db");
#else
f_strcpy( gv_szDibName, "gigatest.db");
#endif
gv_szDataDir[ 0] = 0;
gv_szRflDir[ 0] = 0;
// If no parameters were entered, show a help screen.
if( iArgC < 2)
{
gigaShowHelp();
goto Exit;
}
uiLoop = 1;
while( uiLoop < (FLMUINT)iArgC)
{
pszPtr = ppszArgV [uiLoop];
// See if they specified an option
#ifdef FLM_UNIX
if( *pszPtr == '-')
#else
if( (*pszPtr == '-') || (*pszPtr == '/'))
#endif
{
pszPtr++;
if ((*pszPtr == 'c') || (*pszPtr == 'C'))
{
gv_uiCacheSize = f_atol( (pszPtr + 1));
}
else if ((*pszPtr == 'i') || (*pszPtr == 'I'))
{
gv_uiCPInterval = f_atol( (pszPtr + 1));
}
else if ((*pszPtr == 'p') || (*pszPtr == 'P'))
{
gv_uiBlockCachePercentage = f_atol( (pszPtr + 1));
}
else if ((*pszPtr == 'm') || (*pszPtr == 'M'))
{
pszPtr++;
if ((*pszPtr == 'd') || (*pszPtr == 'D'))
{
gv_uiMaxDirtyCache = f_atol( (pszPtr + 1));
}
}
else if ((*pszPtr == 'l') || (*pszPtr == 'L'))
{
pszPtr++;
if ((*pszPtr == 'd') || (*pszPtr == 'D'))
{
gv_uiLowDirtyCache = f_atol( (pszPtr + 1));
}
}
else if ((*pszPtr == 't') || (*pszPtr == 'T'))
{
gv_uiTransSize = f_atol( (pszPtr + 1));
}
else if ((*pszPtr == 'n') || (*pszPtr == 'N'))
{
f_strcpy( gv_szDibName, pszPtr + 1);
}
else if (*pszPtr == 'd' || *pszPtr == 'D')
{
if( f_stricmp( pszPtr, "dio") == 0)
{
gv_bDisableDirectIO = TRUE;
}
else
{
pszPtr++;
if (*pszPtr == 'r' || *pszPtr == 'R')
{
f_strcpy( gv_szRflDir, pszPtr + 1);
}
else if (*pszPtr == 'd' || *pszPtr == 'D')
{
f_strcpy( gv_szDataDir, pszPtr + 1);
}
else
{
f_sprintf( szMsg, "Invalid option %s", (pszPtr - 1));
gigaOutputErrMsg( szMsg);
goto Exit;
}
}
}
else if (f_stricmp( pszPtr, "B") == 0)
{
gv_bBatchMode = TRUE;
}
#ifdef FLM_NLM
else if (f_stricmp( pszPtr, "W") == 0)
{
bWaitToSync = TRUE;
}
#endif
else if (f_stricmp( pszPtr, "?") == 0 ||
f_stricmp( pszPtr, "HELP") == 0)
{
gigaShowHelp();
goto Exit;
}
else
{
f_sprintf( szMsg, "Invalid option %s", pszPtr);
gigaOutputErrMsg( szMsg);
goto Exit;
}
}
else if (f_stricmp( pszPtr, "?") == 0)
{
gigaShowHelp();
return( FALSE);
}
else if (!bHaveNumToLoad)
{
gv_uiTotalToLoad = f_atol( pszPtr);
bHaveNumToLoad = TRUE;
}
uiLoop++;
}
#ifdef FLM_NLM
if (!bWaitToSync && !gv_bSynchronized)
{
SynchronizeStart();
gv_bSynchronized = TRUE;
}
#endif
bOk = TRUE;
Exit:
return( bOk);
}
/********************************************************************
Desc: Checks to see if the user pressed ESCAPE to exit the loader.
Also updates the total loaded counter on the screen.
*********************************************************************/
FLMUINT gigaSeeIfQuit( void)
{
FLMUINT uiChar = 0;;
f_mutexLock( gv_hWindowMutex);
gigaOutputUINT( TOTAL_LOADED_ROW, gv_uiTotalLoaded, TRUE);
if (RC_OK( FTXWinTestKB( gv_pWindow)))
{
FTXWinInputChar( gv_pWindow, &uiChar);
if (uiChar == FKB_ESCAPE)
{
uiChar = gigaGetInput(
"ESCAPE pressed, quit? (ESC,Q,Y=Quit, other=continue): ",
NULL, TRUE);
switch (uiChar)
{
case 'Q':
case 'q':
case 'y':
case 'Y':
uiChar = FKB_ESCAPE;
break;
case FKB_ESCAPE:
break;
default:
uiChar = 0;
break;
}
}
else if( uiChar == 'i' || uiChar == 'I')
{
HFDB hDb;
f_threadDestroy( &gv_pIxManagerThrd);
if (RC_OK( FlmDbOpen( gv_szDibName, gv_szDataDir,
gv_szRflDir, 0, NULL, &hDb)))
{
f_threadCreate( &gv_pIxManagerThrd,
flstIndexManagerThread, "index_manager",
F_DEFAULT_THREAD_GROUP, 0, (void *)hDb);
}
}
}
if (gv_bShutdown)
{
uiChar = FKB_ESCAPE;
}
f_mutexUnlock( gv_hWindowMutex);
return( uiChar);
}
/********************************************************************
Desc: Starts a transaction and does a few modifications that are
necessary at the beginning of a transaction.
*********************************************************************/
RCODE gigaStartTrans( void)
{
RCODE rc = NE_FLM_OK;
FLMUINT uiChar;
while( !gv_bShutdown)
{
if( RC_BAD( rc = FlmDbTransBegin( gv_hDb,
FLM_UPDATE_TRANS, FLM_NO_TIMEOUT)))
{
if( rc != FERR_MUST_WAIT_CHECKPOINT)
{
gigaOutputRcErr( "starting transaction", rc);
goto Exit;
}
f_yieldCPU();
if( (uiChar = gigaSeeIfQuit()) != 0)
{
if (uiChar == FKB_ESCAPE)
{
gigaOutputRcErr( "starting transaction", rc);
goto Exit;
}
}
}
else
{
break;
}
}
Exit:
return( rc);
}
/********************************************************************
Desc:
*********************************************************************/
RCODE gigaMakeNewRecord(
FlmRecord ** ppRecord)
{
RCODE rc = NE_FLM_OK;
FlmRecord * pRecord = NULL;
void * pvField;
if( *ppRecord && !(*ppRecord)->isReadOnly())
{
f_assert( (*ppRecord)->getRefCount() == 1);
pRecord = *ppRecord;
*ppRecord = NULL;
pRecord->clear();
}
else
{
if( (pRecord = f_new FlmRecord) == NULL)
{
rc = RC_SET( NE_FLM_MEM);
goto Exit;
}
}
if( RC_BAD( rc = pRecord->insertLast( 0, PERSON_TAG,
FLM_TEXT_TYPE, NULL)))
{
goto Exit;
}
if( RC_BAD( rc = pRecord->insertLast( 1, FIRST_NAME_TAG,
FLM_TEXT_TYPE, &pvField)))
{
goto Exit;
}
if( RC_BAD( rc = pRecord->setNative( pvField, *gv_ppszCurrGiven)))
{
goto Exit;
}
if( RC_BAD( rc = pRecord->insertLast( 1, LAST_NAME_TAG,
FLM_TEXT_TYPE, &pvField)))
{
goto Exit;
}
if( RC_BAD( rc = pRecord->setNative( pvField, *gv_ppszCurrFamily)))
{
goto Exit;
}
if( RC_BAD( rc = pRecord->insertLast( 1, AGE_TAG,
FLM_NUMBER_TYPE, &pvField)))
{
goto Exit;
}
if( RC_BAD( rc = pRecord->setUINT( pvField, f_getRandomUINT32( 1, 100))))
{
goto Exit;
}
if( *ppRecord)
{
(*ppRecord)->Release();
}
*ppRecord = pRecord;
pRecord = NULL;
gv_ppszCurrGiven++;
if( *gv_ppszCurrGiven == NULL)
{
gv_ppszCurrGiven = &gv_pszGivenNames [0];
gv_ppszCurrFamily++;
if (*gv_ppszCurrFamily == NULL)
{
gv_ppszCurrFamily = &gv_pszFamilyNames[0];
}
}
Exit:
if( pRecord)
{
pRecord->Release();
}
return( rc);
}
/********************************************************************
Desc: Commits the current transaction - fixes up the parent object to
point to the last child added before committing.
*********************************************************************/
RCODE gigaCommitTrans( void)
{
RCODE rc = NE_FLM_OK;
gigaOutputUINT( TOTAL_LOADED_ROW, gv_uiTotalLoaded);
// Commit the transaction.
if( RC_BAD( rc = FlmDbTransCommit( gv_hDb)))
{
gigaOutputRcErr( "committing transaction", rc);
goto Exit;
}
Exit:
return( rc);
}
/********************************************************************
Desc: Update the memory information on the screen.
*********************************************************************/
void gigaCheckpointDisplay( void)
{
char szBuf[ 80];
CHECKPOINT_INFO cpInfo;
FlmDbGetConfig( gv_hDb, FDB_GET_CHECKPOINT_INFO, &cpInfo, NULL, NULL);
if (!cpInfo.bRunning)
{
f_strcpy( szBuf, "Idle ");
}
else
{
if (cpInfo.bForcingCheckpoint)
{
f_sprintf( szBuf, "Forcing (%ums) ",
(unsigned)cpInfo.uiRunningTime);
}
else
{
f_sprintf( szBuf, "Running (%ums) ",
(unsigned)cpInfo.uiRunningTime);
}
}
gigaOutputStr( CP_STATE_ROW, szBuf);
}
/********************************************************************
Desc: Update the memory information on the screen.
*********************************************************************/
void gigaUpdateMemInfo( void)
{
FLM_MEM_INFO MemInfo;
char szBuf [50];
FlmGetMemoryInfo( &MemInfo);
f_sprintf( (char *)szBuf, "Blk: %-10u Record: %-10u",
(unsigned)MemInfo.BlockCache.uiMaxBytes,
(unsigned)MemInfo.RecordCache.uiMaxBytes);
gigaOutputStr( MAX_CACHE_ROW, szBuf);
f_sprintf( (char *)szBuf, "Blk: %-10u Record: %-10u",
(unsigned)MemInfo.BlockCache.uiTotalBytesAllocated,
(unsigned)MemInfo.RecordCache.uiTotalBytesAllocated);
gigaOutputStr( USED_CACHE_ROW, szBuf);
f_sprintf( (char *)szBuf, "Blk: %-10u Record: %-10u",
(unsigned)MemInfo.BlockCache.uiCount,
(unsigned)MemInfo.RecordCache.uiCount);
gigaOutputStr( ITEMS_CACHED_ROW, szBuf);
f_sprintf( (char *)szBuf, "Cnt: %-10u Bytes : %-10u",
(unsigned)MemInfo.uiDirtyCount, (unsigned)MemInfo.uiDirtyBytes);
gigaOutputStr( DIRTY_CACHE_ROW, szBuf);
f_sprintf( (char *)szBuf, "Cnt: %-10u Bytes : %-10u",
(unsigned)MemInfo.uiLogCount, (unsigned)MemInfo.uiLogBytes);
gigaOutputStr( LOG_CACHE_ROW, szBuf);
f_sprintf( (char *)szBuf, "Cnt: %-10u Bytes : %-10u",
(unsigned)MemInfo.uiFreeCount,
(unsigned)MemInfo.uiFreeBytes);
gigaOutputStr( FREE_CACHE_ROW, szBuf);
gigaCheckpointDisplay();
}
/****************************************************************************
Desc: This routine functions as a thread. It keeps the gigaload screen
up to date.
****************************************************************************/
RCODE FLMAPI gigaScreenThread(
IF_Thread * pThread)
{
FLMUINT uiCurrTime;
for (;;)
{
// See if we should shut down.
if( pThread->getShutdownFlag())
{
break;
}
uiCurrTime = FLM_GET_TIMER();
// Update the display
gigaUpdateMemInfo();
pThread->sleep( 1000);
}
return( FERR_OK);
}
/********************************************************************
Desc: Start the screen thread.
*********************************************************************/
RCODE gigaStartScreenThread( void)
{
RCODE rc = FERR_OK;
// Start the screen thread
if( RC_BAD( rc = f_threadCreate( &gv_pScreenThrd,
gigaScreenThread, "Gigaload Monitor")))
{
goto Exit;
}
Exit:
return( rc);
}
/********************************************************************
Desc: Shutdown the screen thread.
*********************************************************************/
void gigaStopScreenThread( void)
{
f_threadDestroy( &gv_pScreenThrd);
}
/********************************************************************
Desc:
*********************************************************************/
void gigaUpdateLoadTimes( void)
{
FLMUINT uiElapsedTime;
FLMUINT uiCurrTime;
FLMUINT uiSecs;
FLMUINT uiAddsPerSec;
char szElapsedTime [20];
uiCurrTime = FLM_GET_TIMER();
uiElapsedTime = FLM_ELAPSED_TIME( uiCurrTime, gv_ui10SecStartTime);
// Calculate and display the average for the last 10 seconds.
uiSecs = FLM_TIMER_UNITS_TO_SECS( uiElapsedTime);
uiAddsPerSec = (gv_uiTotalLoaded - gv_ui10SecTotal) / uiSecs;
f_mutexLock( gv_hWindowMutex);
gigaOutputUINT( ADDS_PER_SEC_CURRENT, uiAddsPerSec, TRUE);
gv_ui10SecTotal = gv_uiTotalLoaded;
gv_ui10SecStartTime = uiCurrTime;
// Calculate and display the overall average
uiElapsedTime = FLM_ELAPSED_TIME( uiCurrTime, gv_uiStartTime);
uiSecs = FLM_TIMER_UNITS_TO_SECS( uiElapsedTime);
uiAddsPerSec = gv_uiTotalLoaded / uiSecs;
gigaOutputUINT( ADDS_PER_SEC_OVERALL, uiAddsPerSec, TRUE);
f_sprintf( szElapsedTime, "%u:%02u:%02u",
(unsigned)uiSecs / 3600,
(unsigned)(uiSecs % 3600) / 60,
(unsigned)uiSecs % 60);
gigaOutputStr( ELAPSED_TIME_ROW, szElapsedTime, TRUE);
f_mutexUnlock( gv_hWindowMutex);
}
/********************************************************************
Desc: Loads the database with objects.
*********************************************************************/
RCODE gigaLoadDatabase( void)
{
RCODE rc = NE_FLM_OK;
FLMBOOL bTransActive = FALSE;
FLMBOOL bCommitTrans = FALSE;
FLMUINT uiObjsInTrans = 0;
FLMUINT uiChar = 0;
FLMUINT bSuspend = FALSE;
FlmRecord * pNewRec = NULL;
// Set cache size, if specified on command line.
if( gv_uiCacheSize)
{
if( RC_BAD( rc = FlmSetHardMemoryLimit( 0, FALSE, 0,
gv_uiCacheSize, 0)))
{
gigaOutputRcErr( "setting cache size", rc);
goto Exit;
}
}
// Set block cache percentage, if it is not default.
if( gv_uiBlockCachePercentage != 50)
{
if( RC_BAD( rc = FlmConfig( FLM_BLOCK_CACHE_PERCENTAGE,
(void *)gv_uiBlockCachePercentage, (void *)0)))
{
gigaOutputRcErr( "setting block cache percentage", rc);
goto Exit;
}
}
// Set the maximum and low dirty cache, if one was specified
if( gv_uiMaxDirtyCache)
{
if( RC_BAD( rc = FlmConfig( FLM_MAX_DIRTY_CACHE,
(void *)gv_uiMaxDirtyCache, (void *)gv_uiLowDirtyCache)))
{
gigaOutputRcErr( "setting maximum dirty cache", rc);
goto Exit;
}
}
// Set checkpoint interval, if one is specified.
if( gv_uiCPInterval != 0xFFFFFFFF)
{
if( RC_BAD( rc = FlmConfig( FLM_MAX_CP_INTERVAL,
(void *)gv_uiCPInterval, (void *)0)))
{
gigaOutputRcErr( "setting checkpoint interval", rc);
goto Exit;
}
}
// Enable/Disable direct I/O
if( RC_BAD( rc = FlmConfig( FLM_DIRECT_IO_STATE,
(void *)!gv_bDisableDirectIO, NULL)))
{
goto Exit;
}
// Create the database.
(void)FlmDbRemove( gv_szDibName, gv_szDataDir, gv_szRflDir, TRUE);
if( RC_BAD( rc = FlmDbCreate( gv_szDibName, gv_szDataDir, gv_szRflDir,
NULL, gv_pszGigaDictionary, NULL, &gv_hDb)))
{
gigaOutputRcErr( "creating database", rc);
goto Exit;
}
if( RC_BAD( rc = FlmDbConfig( gv_hDb,
FDB_RFL_FOOTPRINT_SIZE, (void *)(512 * 1024 * 1024), NULL)))
{
goto Exit;
}
if( RC_BAD( rc = FlmDbConfig( gv_hDb,
FDB_RBL_FOOTPRINT_SIZE, (void *)(512 * 1024 * 1024), NULL)))
{
goto Exit;
}
// Create the display
gv_uiTotalLoaded = 0;
gv_ui10SecTotal = 0;
f_mutexLock( gv_hWindowMutex);
FTXWinClear( gv_pWindow);
f_mutexUnlock( gv_hWindowMutex);
gigaOutputLabel( MAX_CACHE_ROW, "Maximum Cache Size (bytes)");
gigaOutputLabel( USED_CACHE_ROW, "Cache Used (bytes)");
gigaOutputLabel( ITEMS_CACHED_ROW, "Cache Used (items)");
gigaOutputLabel( DIRTY_CACHE_ROW, "Dirty Cache (bytes)");
gigaOutputLabel( LOG_CACHE_ROW, "Log Cache (bytes)");
gigaOutputLabel( FREE_CACHE_ROW, "Free Cache (bytes)");
gigaOutputLabel( CP_STATE_ROW, "Checkpoint State");
gigaUpdateMemInfo();
gigaOutputLabel( DB_NAME_ROW, "Database Name");
gigaOutputStr( DB_NAME_ROW, gv_szDibName);
gigaOutputLabel( TOTAL_TO_LOAD_ROW, "Total To Load");
gigaOutputUINT( TOTAL_TO_LOAD_ROW, gv_uiTotalToLoad);
gigaOutputLabel( TRANS_SIZE_ROW, "Transaction Size");
gigaOutputUINT( TRANS_SIZE_ROW, gv_uiTransSize);
gigaOutputLabel( TOTAL_LOADED_ROW, "Total Loaded");
gigaOutputUINT( TOTAL_LOADED_ROW, gv_uiTotalLoaded);
gigaOutputLabel( ADDS_PER_SEC_CURRENT, "Adds/Sec. (10 secs)");
gigaOutputUINT( ADDS_PER_SEC_CURRENT, 0);
gigaOutputLabel( ADDS_PER_SEC_OVERALL, "Adds/Sec. (overall)");
gigaOutputUINT( ADDS_PER_SEC_OVERALL, 0);
gigaOutputLabel( ELAPSED_TIME_ROW, "Elapsed Time");
gigaOutputStr( ELAPSED_TIME_ROW, "<none>");
if( RC_BAD( rc = gigaStartScreenThread()))
{
goto Exit;
}
gv_ui10SecStartTime = gv_uiStartTime = FLM_GET_TIMER();
gv_ui10Secs = FLM_SECS_TO_TIMER_UNITS( 10);
gv_ui1Sec = FLM_SECS_TO_TIMER_UNITS( 1);
for( ;;)
{
// See if we have been told to shut down, or if the user
// has pressed escape.
if( gv_bShutdown)
{
break;
}
// Every 127 objects, see if character was pressed and update
// count on screen.
if( (gv_uiTotalLoaded & 0x7F) == 0)
{
f_yieldCPU();
if( (uiChar = gigaSeeIfQuit()) != 0)
{
if( uiChar == FKB_ESCAPE)
{
break;
}
else if( uiChar == 's' || uiChar == 'S')
{
bSuspend = TRUE;
}
}
// Check for other keyboard options
}
else if( (gv_uiTotalLoaded & 0x7) == 0)
{
FLMUINT uiElapsedTime;
FLMUINT uiCurrTime;
uiCurrTime = FLM_GET_TIMER();
// If at least 10 seconds have elapsed, redisplay the average
// rate values.
if( (uiElapsedTime = FLM_ELAPSED_TIME( uiCurrTime,
gv_ui10SecStartTime)) >= gv_ui10Secs)
{
gigaUpdateLoadTimes();
}
}
// Start a transaction, if one is not going.
if( !bTransActive)
{
if( bSuspend)
{
uiChar = gigaGetInput(
"Load suspended, press any character to continue loading: ",
NULL);
bSuspend = FALSE;
}
if( RC_BAD( rc = gigaStartTrans()))
{
goto Exit;
}
bTransActive = TRUE;
bCommitTrans = FALSE;
uiObjsInTrans = 0;
}
// Increment the load counters and determine if this will be the
// last object of the transaction.
gv_uiTotalLoaded++;
uiObjsInTrans++;
if( uiObjsInTrans == gv_uiTransSize ||
gv_uiTotalLoaded == gv_uiTotalToLoad)
{
bCommitTrans = TRUE;
}
// Create a new object.
if( RC_BAD( rc = gigaMakeNewRecord( &pNewRec)))
{
goto Exit;
}
if( RC_BAD( rc = FlmRecordAdd( gv_hDb, FLM_DATA_CONTAINER,
NULL, pNewRec, FLM_DONT_INSERT_IN_CACHE)))
{
goto Exit;
}
// Commit when we reach the transaction size or the total to load.
// NOTE: The bCommitTrans flag is set above.
if( bCommitTrans)
{
if( RC_BAD( rc = gigaCommitTrans()))
{
goto Exit;
}
bTransActive = FALSE;
}
// See if we are done.
if( gv_uiTotalLoaded == gv_uiTotalToLoad)
{
flmAssert( !bTransActive);
break;
}
}
Exit:
if( pNewRec)
{
pNewRec->Release();
}
if( bTransActive)
{
(void)FlmDbTransAbort( gv_hDb);
}
if( gv_hDb != HFDB_NULL)
{
FlmDbCheckpoint( gv_hDb, FLM_NO_TIMEOUT);
gigaStopScreenThread();
FlmDbClose( &gv_hDb);
// This will cause us to wait for the last checkpoint
// to finish.
(void)FlmConfig( FLM_CLOSE_FILE, (void *)gv_szDibName,
(void *)gv_szDataDir);
}
gigaUpdateLoadTimes();
gigaStopScreenThread();
f_threadDestroy( &gv_pIxManagerThrd);
return( rc);
}
#ifdef FLM_NLM
/****************************************************************************
Desc: This routine shuts down all threads in the NLM.
****************************************************************************/
void gigaCleanup( void)
{
gv_bShutdown = TRUE;
while( gv_bRunning)
{
f_yieldCPU();
}
}
#endif
/****************************************************************************
Desc: Displays two lines of message and gets the user's input.
*****************************************************************************/
FLMUINT gigaGetInput(
const char * pszMsg1,
const char * pszMsg2,
FLMBOOL bMutexLocked)
{
eColorType eSaveBack;
eColorType eSaveFore;
FLMUINT uiChar;
if (!bMutexLocked && gv_hWindowMutex != F_MUTEX_NULL)
{
f_mutexLock( gv_hWindowMutex);
}
// Get the background and foreground color so we can restore them.
FTXWinGetBackFore( gv_pWindow, &eSaveBack, &eSaveFore);
// Clear the last one or two lines on the screen
if (pszMsg2 && *pszMsg2)
{
FTXWinClearXY( gv_pWindow, 0, gv_uiNumRows - 2);
}
else
{
FTXWinClearXY( gv_pWindow, 0, gv_uiNumRows - 1);
}
// Change to WHITE on RED.
FTXWinSetBackFore( gv_pWindow, FLM_RED, FLM_WHITE);
// Display messages on last two lines of screen.
if (pszMsg2 && *pszMsg2)
{
FTXWinPrintStrXY( gv_pWindow, pszMsg1,
0, gv_uiNumRows - 2);
FTXWinPrintStrXY( gv_pWindow, pszMsg2,
0, gv_uiNumRows - 1);
}
else
{
FTXWinPrintStrXY( gv_pWindow, pszMsg1,
0, gv_uiNumRows - 1);
}
// Wait for user to press key.
for (;;)
{
if (gv_bShutdown)
{
uiChar = 0;
break;
}
if (RC_OK( FTXWinTestKB( gv_pWindow)))
{
FTXWinInputChar( gv_pWindow, &uiChar);
break;
}
f_sleep(50);
}
// Clear out last one or two lines of screen.
FTXWinSetBackFore( gv_pWindow, eSaveBack, eSaveFore);
if (pszMsg2 && *pszMsg2)
{
FTXWinClearXY( gv_pWindow, 0, gv_uiNumRows - 2);
}
else
{
FTXWinClearXY( gv_pWindow, 0, gv_uiNumRows - 1);
}
if (!bMutexLocked && gv_hWindowMutex != F_MUTEX_NULL)
{
f_mutexUnlock( gv_hWindowMutex);
}
return( uiChar);
}
/****************************************************************************
Desc: Displays an error message.
*****************************************************************************/
void gigaOutputErrMsg(
const char * pszErrMsg,
FLMBOOL bMutexLocked)
{
(void)gigaGetInput( pszErrMsg, "Press any character to continue: ",
bMutexLocked);
}
/****************************************************************************
Desc: Displays an error message with an RCODE.
*****************************************************************************/
void gigaOutputRcErr(
const char * pszWhat,
RCODE rc,
FLMBOOL bMutexLocked)
{
char szMsg [100];
f_sprintf( szMsg, "Error %s: %s (%04X)", pszWhat,
FlmErrorString( rc), (unsigned)rc);
gigaOutputErrMsg( szMsg, bMutexLocked);
}
/********************************************************************
Desc: Output a label in the LABEL_COLUMN
*********************************************************************/
void gigaOutputLabel(
FLMUINT uiRow,
const char * pszLabel,
FLMBOOL bMutexLocked)
{
char szLabel [DATA_COLUMN - LABEL_COLUMN];
char * pszTmp;
FLMUINT uiNumDots = sizeof( szLabel) - 1;
f_memset( szLabel, '.', uiNumDots);
szLabel [uiNumDots] = 0;
pszTmp = &szLabel [0];
uiNumDots -= 2;
while( *pszLabel && uiNumDots)
{
*pszTmp++ = (FLMBYTE)(*pszLabel++);
uiNumDots--;
}
if( !bMutexLocked && gv_hWindowMutex != F_MUTEX_NULL)
{
f_mutexLock( gv_hWindowMutex);
}
FTXWinPrintStrXY( gv_pWindow, szLabel, LABEL_COLUMN, uiRow);
if( !bMutexLocked && gv_hWindowMutex != F_MUTEX_NULL)
{
f_mutexUnlock( gv_hWindowMutex);
}
}
/********************************************************************
Desc: Output a string in the DATA_COLUMN
*********************************************************************/
void gigaOutputStr(
FLMUINT uiRow,
const char * pszStr,
FLMBOOL bMutexLocked)
{
if( !bMutexLocked && gv_hWindowMutex != F_MUTEX_NULL)
{
f_mutexLock( gv_hWindowMutex);
}
FTXWinPrintStrXY( gv_pWindow, pszStr, DATA_COLUMN, uiRow);
if( !bMutexLocked && gv_hWindowMutex != F_MUTEX_NULL)
{
f_mutexUnlock( gv_hWindowMutex);
}
}
/********************************************************************
Desc: Output a FLMUINT in the DATA_COLUMN
*********************************************************************/
void gigaOutputUINT(
FLMUINT uiRow,
FLMUINT uiNum,
FLMBOOL bMutexLocked)
{
char szBuf [20];
f_sprintf( szBuf, "%-10u", (unsigned)uiNum);
gigaOutputStr( uiRow, szBuf, bMutexLocked);
}