//-------------------------------------------------------------------------
// Desc: Class for displaying various statistics in HTML on a web page.
// Tabs: 3
//
// Copyright (c) 2002-2006 Novell, Inc. All Rights Reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the GNU General Public
// License as published by the Free Software Foundation.
//
// 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, 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: imonstat.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $
//-------------------------------------------------------------------------
#include "flaimsys.h"
#define STAT_DISPLAY_ORDER "StatDisplayOrder"
#define CACHE_STAT_STR "Cache"
#define OPERATIONS_STAT_STR "Operations"
#define LOCKS_STAT_STR "Locks"
#define DISK_STAT_STR "Disk"
#define CHECK_POINT_STR "CPThread"
#define DEFAULT_STAT_ORDER CACHE_STAT_STR ";" \
OPERATIONS_STAT_STR ";" \
LOCKS_STAT_STR ";" \
DISK_STAT_STR ";" \
CHECK_POINT_STR ";"
#define SAVED_STATS "SavedStats"
#define STAT_FOCUS "StatFocus"
// Stat types
#define CACHE_STATS 1
#define OPERATION_STATS 2
#define LOCK_STATS 3
#define DISK_STATS 4
#define CHECK_POINT_STATS 5
#define MAX_STAT_TYPES 5
/****************************************************************************
Desc: Gather statistics from a BLOCKIO_STATS structure.
****************************************************************************/
void F_StatsPage::gatherBlockIOStats(
STAT_GATHER * pStatGather,
DISKIO_STAT * pReadStat,
DISKIO_STAT * pWriteStat,
BLOCKIO_STATS * pBlockIOStats
)
{
// Gather the read statistics.
flmUpdateDiskIOStats( &pStatGather->IOReads,
&pBlockIOStats->BlockReads);
flmUpdateDiskIOStats( &pStatGather->IOReads,
&pBlockIOStats->OldViewBlockReads);
flmUpdateDiskIOStats( &pStatGather->IORollbackBlockReads,
&pBlockIOStats->OldViewBlockReads);
flmUpdateDiskIOStats( pReadStat, &pBlockIOStats->BlockReads);
// Gather the check errors
pStatGather->uiCheckErrors +=
(pBlockIOStats->uiBlockChkErrs +
pBlockIOStats->uiOldViewBlockChkErrs);
// Gather the write statistics
flmUpdateDiskIOStats( &pStatGather->IOWrites,
&pBlockIOStats->BlockWrites);
flmUpdateDiskIOStats( pWriteStat, &pBlockIOStats->BlockWrites);
}
/****************************************************************************
Desc: Gather statistics for an LFILE.
****************************************************************************/
void F_StatsPage::gatherLFileStats(
STAT_GATHER * pStatGather,
LFILE_STATS * pLFileStats
)
{
pStatGather->uiNumLFileStats++;
pStatGather->ui64BlockSplits += pLFileStats->ui64BlockSplits;
pStatGather->ui64BlockCombines += pLFileStats->ui64BlockCombines;
// Gather root block statistics
gatherBlockIOStats( pStatGather, &pStatGather->IORootBlockReads,
&pStatGather->IORootBlockWrites, &pLFileStats->RootBlockStats);
// Gather non-leaf block statistics
gatherBlockIOStats( pStatGather, &pStatGather->IONonLeafBlockReads,
&pStatGather->IONonLeafBlockWrites, &pLFileStats->MiddleBlockStats);
// Gather leaf block statistics
gatherBlockIOStats( pStatGather, &pStatGather->IOLeafBlockReads,
&pStatGather->IOLeafBlockWrites, &pLFileStats->LeafBlockStats);
}
/****************************************************************************
Desc: Gather statistics for a particular database.
****************************************************************************/
void F_StatsPage::gatherDbStats(
STAT_GATHER * pStatGather,
DB_STATS * pDbStats
)
{
FLMUINT uiLoop;
pStatGather->uiNumDbStats++;
flmUpdateCountTimeStats( &pStatGather->CommittedUpdTrans,
&pDbStats->UpdateTransStats.CommittedTrans);
flmUpdateCountTimeStats( &pStatGather->GroupCompletes,
&pDbStats->UpdateTransStats.GroupCompletes);
pStatGather->ui64GroupFinished +=
pDbStats->UpdateTransStats.ui64GroupFinished;
flmUpdateCountTimeStats( &pStatGather->AbortedUpdTrans,
&pDbStats->UpdateTransStats.AbortedTrans);
flmUpdateCountTimeStats( &pStatGather->CommittedReadTrans,
&pDbStats->ReadTransStats.CommittedTrans);
flmUpdateCountTimeStats( &pStatGather->AbortedReadTrans,
&pDbStats->ReadTransStats.AbortedTrans);
pStatGather->Reads.ui64Count += pDbStats->ui64NumRecordReads;
flmUpdateCountTimeStats( &pStatGather->Adds,
&pDbStats->RecordAdds);
flmUpdateCountTimeStats( &pStatGather->Modifies,
&pDbStats->RecordModifies);
flmUpdateCountTimeStats( &pStatGather->Deletes,
&pDbStats->RecordDeletes);
pStatGather->Queries.ui64Count += pDbStats->ui64NumCursors;
pStatGather->QueryReads.ui64Count += pDbStats->ui64NumCursorReads;
if ((m_pFocusBlock == NULL) ||
(m_pFocusBlock->uiLFileNum == 0))
{
// Gather the avail block statistics
gatherBlockIOStats( pStatGather, &pStatGather->IOAvailBlockReads,
&pStatGather->IOAvailBlockWrites, &pDbStats->AvailBlockStats);
// Gather the LFH block statistics
gatherBlockIOStats( pStatGather, &pStatGather->IOLFHBlockReads,
&pStatGather->IOLFHBlockWrites, &pDbStats->LFHBlockStats);
// Gather log block reads
flmUpdateDiskIOStats( &pStatGather->IOReads,
&pDbStats->LogBlockReads);
flmUpdateDiskIOStats( &pStatGather->IORollbackBlockReads,
&pDbStats->LogBlockReads);
// Gather log header writes
flmUpdateDiskIOStats( &pStatGather->IOWrites,
&pDbStats->LogHdrWrites);
flmUpdateDiskIOStats( &pStatGather->IOLogHdrWrites,
&pDbStats->LogHdrWrites);
// Gather roll-back log writes
flmUpdateDiskIOStats( &pStatGather->IOWrites,
&pDbStats->LogBlockWrites);
flmUpdateDiskIOStats( &pStatGather->IORollBackLogWrites,
&pDbStats->LogBlockWrites);
// Gather rolled-back block writes
flmUpdateDiskIOStats( &pStatGather->IOWrites,
&pDbStats->LogBlockRestores);
flmUpdateDiskIOStats( &pStatGather->IORolledbackBlockWrites,
&pDbStats->LogBlockRestores);
// Gather I/O error statistics
pStatGather->uiReadErrors += pDbStats->uiReadErrors;
pStatGather->uiWriteErrors += pDbStats->uiWriteErrors;
pStatGather->uiCheckErrors +=
(pDbStats->AvailBlockStats.uiBlockChkErrs +
pDbStats->AvailBlockStats.uiOldViewBlockChkErrs +
pDbStats->LFHBlockStats.uiBlockChkErrs +
pDbStats->LFHBlockStats.uiOldViewBlockChkErrs +
pDbStats->uiLogBlockChkErrs);
}
// Gather lock statistics
flmUpdateCountTimeStats( &pStatGather->NoLocks,
&pDbStats->NoLocks);
flmUpdateCountTimeStats( &pStatGather->WaitingForLock,
&pDbStats->WaitingForLock);
flmUpdateCountTimeStats( &pStatGather->HeldLock,
&pDbStats->HeldLock);
for (uiLoop = 0; uiLoop < pDbStats->uiNumLFileStats; uiLoop++)
{
if ((m_pFocusBlock == NULL) ||
(m_pFocusBlock->uiLFileNum == 0) ||
(m_pFocusBlock->uiLFileNum == pDbStats->pLFileStats [uiLoop].uiLFileNum))
{
gatherLFileStats( pStatGather, &pDbStats->pLFileStats [uiLoop]);
}
}
}
/****************************************************************************
Desc: Gather statistics for all databases in the FLM_STATS structure.
****************************************************************************/
void F_StatsPage::gatherStats(
STAT_GATHER * pStatGather
)
{
FLMUINT uiLoop;
f_memset( pStatGather, 0, sizeof( STAT_GATHER));
f_mutexLock( gv_FlmSysData.Stats.hMutex);
pStatGather->bCollectingStats = gv_FlmSysData.Stats.bCollectingStats;
if (gv_FlmSysData.Stats.uiStartTime)
{
pStatGather->uiStartTime = gv_FlmSysData.Stats.uiStartTime;
pStatGather->uiStopTime = gv_FlmSysData.Stats.uiStopTime;
for (uiLoop = 0; uiLoop < gv_FlmSysData.Stats.uiNumDbStats; uiLoop++)
{
if ((m_pFocusBlock == NULL) ||
(f_strcmp(m_pFocusBlock->szFileName,
gv_FlmSysData.Stats.pDbStats [uiLoop].pszDbName) == 0))
{
gatherDbStats( pStatGather,
&gv_FlmSysData.Stats.pDbStats [uiLoop]);
}
}
}
f_mutexUnlock( gv_FlmSysData.Stats.hMutex);
// Get the cache statistics.
f_mutexLock( gv_FlmSysData.hShareMutex);
f_mutexLock( gv_FlmSysData.RCacheMgr.hMutex);
f_memcpy( &pStatGather->RecordCache,
&gv_FlmSysData.RCacheMgr.Usage,
sizeof( pStatGather->RecordCache));
f_memcpy( &pStatGather->BlockCache,
&gv_FlmSysData.SCacheMgr.Usage,
sizeof( pStatGather->BlockCache));
pStatGather->uiFreeCount = gv_FlmSysData.SCacheMgr.uiFreeCount;
pStatGather->uiFreeBytes = gv_FlmSysData.SCacheMgr.uiFreeBytes;
pStatGather->uiReplaceableCount = gv_FlmSysData.SCacheMgr.uiReplaceableCount;
pStatGather->uiReplaceableBytes = gv_FlmSysData.SCacheMgr.uiReplaceableBytes;
f_mutexUnlock( gv_FlmSysData.RCacheMgr.hMutex);
for (uiLoop = 0; uiLoop < FILE_HASH_ENTRIES; uiLoop++)
{
FFILE * pFile = (FFILE *)gv_FlmSysData.pFileHashTbl [uiLoop].pFirstInBucket;
while (pFile)
{
if (pFile->uiDirtyCacheCount)
{
pStatGather->uiDirtyBytes +=
pFile->uiDirtyCacheCount * pFile->FileHdr.uiBlockSize;
pStatGather->uiDirtyBlocks +=
pFile->uiDirtyCacheCount;
}
if (pFile->uiLogCacheCount)
{
pStatGather->uiLogBytes +=
pFile->uiLogCacheCount * pFile->FileHdr.uiBlockSize;
pStatGather->uiLogBlocks +=
pFile->uiLogCacheCount;
}
gatherCPStats( pStatGather, pFile);
gatherLockStats( pStatGather, pFile);
pFile = pFile->pNext;
}
}
f_mutexUnlock( gv_FlmSysData.hShareMutex);
}
/****************************************************************************
Desc: Prints the web page for system configuration parameters.
****************************************************************************/
RCODE F_StatsPage::display(
FLMUINT uiNumParams,
const char ** ppszParams)
{
RCODE rc = FERR_OK;
void * pvSession = NULL;
STAT_GATHER * pStatGather = NULL;
STAT_GATHER * pOldStatGather = NULL;
char szStatOrder [50];
char szAction [5];
char szStatNewOrder [50];
char * pszStat;
char * ppszStatOrders [MAX_STAT_TYPES];
FLMUINT uiLoop;
FLMUINT uiAction;
FLMBOOL bRefresh;
FLMBOOL bFocus;
char * pszTemp = NULL;
char * pszHeading = NULL;
char szCfgAction [50];
eFlmConfigTypes eConfigType;
FLMUINT uiStatOrders [MAX_STAT_TYPES];
// Are we attempting to change the focus?
bFocus = DetectParameter( uiNumParams, ppszParams, "Focus");
if (bFocus)
{
// Prepare the page to request the user input on what to focus on.
displayFocus( uiNumParams, ppszParams);
goto Exit;
}
if( RC_BAD( rc = f_alloc( 100, &pszTemp)))
{
printErrorPage( rc, TRUE, (char *)"Failed to allocate temporary buffer");
goto Exit;
}
if( RC_BAD( rc = f_alloc( 250, &pszHeading)))
{
printErrorPage( rc, TRUE, (char *)"Failed to allocate temporary buffer");
goto Exit;
}
if (RC_OK( ExtractParameter( uiNumParams, ppszParams,
"CfgAction", sizeof( szCfgAction), szCfgAction)))
{
FLMUINT uiValue1 = 0;
FLMUINT uiValue2 = 0;
eConfigType = (eFlmConfigTypes)f_atoi( szCfgAction);
// Call FlmConfig to perform this action.
if (RC_BAD( rc = FlmConfig( eConfigType, (void *)uiValue1,
(void *)uiValue2)))
{
printErrorPage( FERR_FAILURE, TRUE, (char *)"Failed to perform configuration update");
goto Exit;
}
}
// Get the session, then try to retrieve the StatOrder. If it isn't there, then
// we can set it to the default.
szStatOrder[0] = 0;
if (gv_FlmSysData.HttpConfigParms.fnAcquireSession)
{
char szFocus[100];
if ((pvSession = fnAcquireSession()) != NULL)
{
FLMUINT uiSize = sizeof( szStatOrder);
if (fnGetSessionValue( pvSession,
STAT_DISPLAY_ORDER,
(void *)szStatOrder,
(size_t *)&uiSize) != 0)
{
// If we could not get display order, then set the default.
f_strcpy( szStatOrder, DEFAULT_STAT_ORDER);
}
// Find out if we are focusing our stats collection.
uiSize = sizeof( szFocus) - 1;
if (fnGetSessionValue( pvSession,
STAT_FOCUS,
(void *)szFocus,
(size_t *)&uiSize) == 0)
{
szFocus[ uiSize] = '\0';
if (RC_BAD( setFocus( szFocus)))
{
printErrorPage( FERR_MEM, TRUE, "Failed to establish focus criteria");
goto Exit;
}
}
}
}
// See if they changed the display order.
uiAction = (FLMUINT)(-1);
if (RC_OK( ExtractParameter( uiNumParams, ppszParams,
"Action", sizeof( szAction), szAction)))
{
uiAction = (FLMUINT)f_atoi( szAction);
}
uiLoop = 0;
pszStat = &szStatOrder [0];
while (*pszStat && uiLoop < MAX_STAT_TYPES)
{
ppszStatOrders [uiLoop] = pszStat;
uiLoop++;
while (*pszStat && *pszStat != ';')
{
pszStat++;
}
if (*pszStat)
{
*pszStat = 0;
pszStat++;
}
}
// See if they changed the order.
if (uiAction != (FLMUINT)(-1) && uiAction < MAX_STAT_TYPES * 2)
{
// Odd numbers mean shift to top (move slot 0 to 0, 1 to 0, 2 to 0, 3 to 0)
// Even number mean shift up (move slot 0 to 3, 1 to 0, 2 to 1, 3 to 2)
if (uiAction & 1)
{
uiAction /= 2;
// Trade places with the guy that is in the top position
// No need to move the top one.
if (uiAction)
{
pszStat = ppszStatOrders [0];
ppszStatOrders [0] = ppszStatOrders [uiAction];
ppszStatOrders [uiAction] = pszStat;
}
}
else
{
uiAction /= 2;
pszStat = ppszStatOrders [uiAction];
// Trade places with the guy that is lower.
if (!uiAction)
{
ppszStatOrders [uiAction] = ppszStatOrders [MAX_STAT_TYPES - 1];
ppszStatOrders [MAX_STAT_TYPES - 1] = pszStat;
}
else
{
ppszStatOrders [uiAction] = ppszStatOrders [uiAction - 1];
ppszStatOrders [uiAction - 1] = pszStat;
}
}
// Output the new order.
pszStat = &szStatNewOrder [0];
for (uiLoop = 0; uiLoop < MAX_STAT_TYPES; uiLoop++)
{
f_strcpy( pszStat, ppszStatOrders [uiLoop]);
while (*pszStat)
{
pszStat++;
}
*pszStat++ = ';';
}
*pszStat = 0;
(void)fnSetSessionValue( pvSession,
STAT_DISPLAY_ORDER,
szStatNewOrder,
(size_t)(f_strlen( szStatNewOrder) + 1));
}
if (RC_BAD( rc = f_calloc( sizeof( STAT_GATHER), &pStatGather)))
{
printErrorPage( rc, TRUE, "ERROR ALLOCATING MEMORY: ");
goto Exit;
}
if (RC_BAD( rc = f_calloc( sizeof( STAT_GATHER), &pOldStatGather)))
{
printErrorPage( rc, TRUE, "ERROR ALLOCATING MEMORY: ");
goto Exit;
}
// Collect the current statistics...
gatherStats( pStatGather);
// See if we have any stats from a previous run stored in the session.
if (pvSession)
{
FLMUINT uiSize = sizeof( STAT_GATHER);
if (fnGetSessionValue( pvSession,
SAVED_STATS,
(void *)pOldStatGather,
(size_t *)&uiSize) != 0)
{
// If we could not get any former stats, then just copy the current one.
f_memcpy( pOldStatGather, pStatGather, sizeof( STAT_GATHER));
}
// Now save the new stats for the next go round...
if (fnSetSessionValue( pvSession,
SAVED_STATS,
(void *)pStatGather,
sizeof( STAT_GATHER)) != 0)
{
printErrorPage( rc, TRUE, "ERROR Saving Gathered Statistics in current Session: ");
goto Exit;
}
}
// Output the web page.
stdHdr();
fnPrintf( m_pHRequest, HTML_DOCTYPE);
fnPrintf( m_pHRequest, "\n");
bRefresh = DetectParameter( uiNumParams, ppszParams, "Refresh");
if (bRefresh)
{
// Send back the page with a refresh command in the header
fnPrintf( m_pHRequest,
"
"
""
"System Statistics\n",
m_pszURLString);
printStyle();
popupFrame();
fnPrintf( m_pHRequest, "\n");
fnPrintf( m_pHRequest, "\n");
f_sprintf( (char *)pszTemp,
"Stop Auto-refresh",
m_pszURLString);
}
else
{
fnPrintf( m_pHRequest, "System Statistics\n");
printStyle();
popupFrame();
fnPrintf( m_pHRequest, "\n");
fnPrintf( m_pHRequest, "\n");
f_sprintf( (char *)pszTemp,
"Start Auto-refresh (5 sec.)",
m_pszURLString);
}
// Format the main heading title
formatStatsHeading( pStatGather, pszHeading);
// Begin the table
fnPrintf( m_pHRequest, "\n");
fnPrintf( m_pHRequest, "\n");
fnPrintf( m_pHRequest, "| \n");
fnPrintf( m_pHRequest, (char *)pszHeading);
fnPrintf( m_pHRequest, " |
\n");
printTableRowStart();
printColumnHeading( "", JUSTIFY_LEFT, FLM_IMON_COLOR_PUTTY_1, 4, 1, FALSE);
fnPrintf( m_pHRequest, "Refresh, ",
m_pszURLString,
(bRefresh ? "?Refresh" : ""));
fnPrintf( m_pHRequest, "%s, ", pszTemp);
if (!pStatGather->uiStartTime || gv_FlmSysData.Stats.uiStopTime)
{
fnPrintf( m_pHRequest, "Begin Statistics, ",
m_pszURLString,
FLM_START_STATS,
(bRefresh ? "&Refresh" : ""));
}
if (pStatGather->uiStartTime && !gv_FlmSysData.Stats.uiStopTime)
{
fnPrintf( m_pHRequest, "End Statistics, ",
m_pszURLString,
FLM_STOP_STATS,
(bRefresh ? "&Refresh" : ""));
}
fnPrintf( m_pHRequest, "Reset Statistics, ",
m_pszURLString,
FLM_RESET_STATS,
(bRefresh ? "&Refresh" : ""));
fnPrintf( m_pHRequest, "Set Focus",
m_pszURLString,
(bRefresh ? "&Refresh" : ""));
printColumnHeadingClose();
printTableRowEnd();
printTableRowStart( TRUE);
printColumnHeading( "", JUSTIFY_LEFT, FLM_IMON_COLOR_PUTTY_1, 4, 1, FALSE);
fnPrintf( m_pHRequest, "Stats Order: ");
for (uiLoop = 0; uiLoop < MAX_STAT_TYPES; uiLoop++)
{
FLMUINT uiStat;
char * pszStatOrder = ppszStatOrders [uiLoop];
if (f_stricmp( pszStatOrder, CACHE_STAT_STR) == 0)
{
uiStat = CACHE_STATS;
}
else if (f_stricmp( pszStatOrder, OPERATIONS_STAT_STR) == 0)
{
uiStat = OPERATION_STATS;
}
else if (f_stricmp( pszStatOrder, LOCKS_STAT_STR) == 0)
{
uiStat = LOCK_STATS;
}
else if (f_stricmp( pszStatOrder, CHECK_POINT_STR) == 0)
{
uiStat = CHECK_POINT_STATS;
}
else
{
uiStat = DISK_STATS;
}
uiStatOrders [uiLoop] = uiStat;
fnPrintf( m_pHRequest, "%s: ", pszStatOrder);
fnPrintf( m_pHRequest,
"Top, ",
m_pszURLString,
(uiLoop * 2) + 1, (bRefresh ? "&Refresh" : ""));
fnPrintf( m_pHRequest,
"Up \n",
m_pszURLString,
uiLoop * 2, (bRefresh ? "&Refresh" : ""));
}
printColumnHeadingClose();
printTableRowEnd();
printTableEnd();
displayStats( pStatGather, pOldStatGather, (FLMUINT *)uiStatOrders);
printDocEnd();
Exit:
fnEmit();
if (pStatGather)
{
freeCPInfoHeaders( pStatGather);
freeLockUsers( pStatGather);
f_free( &pStatGather);
}
if (pOldStatGather)
{
f_free( &pOldStatGather);
}
if (pvSession)
{
fnReleaseSession( pvSession);
}
if (pszTemp)
{
f_free( &pszTemp);
}
if (pszHeading)
{
f_free( &pszHeading);
}
return( rc);
}
/****************************************************************************
Desc: Formats the main title heading string so that it displays the start/stop
/elapsed times for the statistics.
****************************************************************************/
void F_StatsPage::formatStatsHeading(
STAT_GATHER * pStatGather,
const char * pszHeading)
{
char szBuffer[ 30];
FLMUINT64 ui64ElapTime;
FLMUINT uiCurrTime;
flmAssert( pStatGather);
flmAssert( pszHeading);
f_sprintf( (char *)pszHeading, "Statistics: ");
// Are we collecting stats?
if (pStatGather->uiStartTime)
{
printDate( gv_FlmSysData.Stats.uiStartTime, szBuffer);
f_strcat( (char *)pszHeading, (char *)szBuffer);
f_strcat( (char *)pszHeading, " to ");
// Check for a stop time.
if (gv_FlmSysData.Stats.uiStopTime)
{
printDate( gv_FlmSysData.Stats.uiStopTime, szBuffer);
f_strcat( (char *)pszHeading, (char *)szBuffer);
ui64ElapTime = (FLMUINT64)(gv_FlmSysData.Stats.uiStopTime -
gv_FlmSysData.Stats.uiStartTime);
}
else
{
f_strcat( (char *)pszHeading, "Present");
f_timeGetSeconds( &uiCurrTime);
ui64ElapTime = (FLMUINT64)(uiCurrTime - gv_FlmSysData.Stats.uiStartTime);
}
f_strcat( (char *)pszHeading, " Elapsed: ");
printElapTime( ui64ElapTime, szBuffer, JUSTIFY_LEFT, FALSE);
f_strcat( (char *)pszHeading, (char *)szBuffer);
}
else
{
f_strcat( (char *)pszHeading, " Not collecting");
}
}
/****************************************************************************
Desc: Outputs statistics for a particular IO category.
****************************************************************************/
void F_StatsPage::printIORow(
FLMBOOL bHighlight,
const char * pszIOCategory,
DISKIO_STAT * pIOStat,
DISKIO_STAT * pOldIOStat)
{
char szTemp[30];
printTableRowStart( bHighlight);
printTableDataStart( TRUE, JUSTIFY_LEFT);
fnPrintf( m_pHRequest, "%s", pszIOCategory);
printTableDataEnd();
printCommaNum( pIOStat->ui64Count,
JUSTIFY_RIGHT,
(pIOStat->ui64Count != pOldIOStat->ui64Count ? TRUE : FALSE));
printCommaNum( pIOStat->ui64TotalBytes,
JUSTIFY_RIGHT,
(pIOStat->ui64TotalBytes != pOldIOStat->ui64TotalBytes ? TRUE : FALSE));
printElapTime( pIOStat->ui64ElapMilli, szTemp);
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "%s%s%s",
(pIOStat->ui64ElapMilli != pOldIOStat->ui64ElapMilli ? "" : ""),
szTemp,
(pIOStat->ui64ElapMilli != pOldIOStat->ui64ElapMilli ? "" : ""));
printTableDataEnd();
if (pIOStat->ui64Count)
{
printElapTime( pIOStat->ui64ElapMilli / pIOStat->ui64Count, szTemp);
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "%s%s%s",
(pOldIOStat->ui64Count ? (pIOStat->ui64ElapMilli / pIOStat->ui64Count !=
pOldIOStat->ui64ElapMilli / pOldIOStat->ui64Count ? "" : "") : "") ,
szTemp,
(pOldIOStat->ui64Count ? (pIOStat->ui64ElapMilli / pIOStat->ui64Count !=
pOldIOStat->ui64ElapMilli / pOldIOStat->ui64Count ? "" : "") : ""));
printTableDataEnd();
}
else
{
printElapTime( 0);
}
printTableRowEnd();
}
/****************************************************************************
Desc: Outputs count/time statistics for a particular category.
****************************************************************************/
void F_StatsPage::printCountTimeRow(
FLMBOOL bHighlight,
const char * pszCategory,
COUNT_TIME_STAT * pStat,
COUNT_TIME_STAT * pOldStat,
FLMBOOL bPrintCountOnly)
{
char szTemp[ 30];
printTableRowStart( bHighlight);
printTableDataStart( TRUE, JUSTIFY_LEFT);
fnPrintf( m_pHRequest, "%s", pszCategory);
printTableDataEnd();
printCommaNum( pStat->ui64Count, JUSTIFY_RIGHT,
(pStat->ui64Count != pOldStat->ui64Count ? TRUE : FALSE));
if (bPrintCountOnly)
{
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "N/A");
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "N/A");
printTableDataEnd();
}
else
{
printElapTime( pStat->ui64ElapMilli, szTemp);
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "%s%s%s",
(pStat->ui64ElapMilli != pOldStat->ui64ElapMilli ? "" : ""),
szTemp,
(pStat->ui64ElapMilli != pOldStat->ui64ElapMilli ? "" : ""));
printTableDataEnd();
if (pStat->ui64Count)
{
printElapTime( pStat->ui64ElapMilli / pStat->ui64Count, szTemp);
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "%s%s%s",
(pOldStat->ui64Count ?
(pStat->ui64ElapMilli / pStat->ui64Count !=
pOldStat->ui64ElapMilli / pOldStat->ui64Count ?
"" : "") :
""),
szTemp,
(pOldStat->ui64Count ?
(pStat->ui64ElapMilli / pStat->ui64Count !=
pOldStat->ui64ElapMilli / pOldStat->ui64Count ?
"" : "") :
""));
printTableDataEnd();
}
else
{
printElapTime( 0);
}
}
printTableRowEnd();
}
/****************************************************************************
Desc: Outputs statistics for a particular Lock category.
****************************************************************************/
void F_StatsPage::printCacheStatRow(
FLMBOOL bHighlight,
const char * pszCategory,
FLMUINT uiBlockCacheValue,
FLMUINT uiRecordCacheValue,
FLMBOOL bRecordCacheValueApplicable,
FLMBOOL bBChangedValue,
FLMBOOL bRChangedValue)
{
printTableRowStart( bHighlight);
printTableDataStart( TRUE, JUSTIFY_LEFT);
fnPrintf( m_pHRequest, "%s", pszCategory);
printTableDataEnd();
printCommaNum( uiBlockCacheValue, JUSTIFY_RIGHT, bBChangedValue);
if (bRecordCacheValueApplicable)
{
printCommaNum( uiRecordCacheValue, JUSTIFY_RIGHT, bRChangedValue);
}
else
{
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "N/A");
printTableDataEnd();
}
printTableRowEnd();
}
/****************************************************************************
Desc: Outputs statistics page
****************************************************************************/
void F_StatsPage::displayStats(
STAT_GATHER * pStatGather,
STAT_GATHER * pOldStatGather,
FLMUINT * puiStatOrders
)
{
FLMUINT uiLoop;
for (uiLoop = 0; uiLoop < MAX_STAT_TYPES; uiLoop++)
{
switch (puiStatOrders [uiLoop])
{
case CACHE_STATS:
printCacheStats( pStatGather, pOldStatGather);
break;
case OPERATION_STATS:
printOperationStats( pStatGather, pOldStatGather);
break;
case LOCK_STATS:
printLockStats( pStatGather, pOldStatGather);
break;
case DISK_STATS:
printDiskStats( pStatGather, pOldStatGather);
break;
case CHECK_POINT_STATS:
printCPStats( pStatGather);
break;
default:
break;
}
}
fnPrintf( m_pHRequest, "
\n");
}
/****************************************************************************
Desc: Deletes all LOCK_USER_HEADER structures linked from the pStatGather structure.
****************************************************************************/
void F_StatsPage::freeLockUsers(
STAT_GATHER * pStatGather
)
{
LOCK_USER_HEADER_p pTmp;
while (pStatGather->pLockUsers)
{
pTmp = pStatGather->pLockUsers;
pStatGather->pLockUsers = pStatGather->pLockUsers->pNext;
if (pTmp->pDbLockUser)
{
f_free( &pTmp->pDbLockUser);
}
if (pTmp->pTxLockUser)
{
f_free( &pTmp->pTxLockUser);
}
f_free( &pTmp);
}
}
/****************************************************************************
Desc: Gets the LOCK_USER information for the specified pFile.
****************************************************************************/
void F_StatsPage::gatherLockStats(
STAT_GATHER * pStatGather,
FFILE_p pFile
)
{
LOCK_USER_HEADER_p pTmp;
RCODE rc;
flmAssert( pStatGather);
flmAssert( pFile);
// Allocate a new LOCK_USER_HEADER and link it into the list.
if( RC_BAD( rc = f_alloc( sizeof( LOCK_USER_HEADER), &pTmp)))
{
goto Exit;
}
pTmp->pNext = pStatGather->pLockUsers;
pStatGather->pLockUsers = pTmp;
// Save the file name.
if (pFile->pszDbPath)
{
f_strcpy( (char *)pTmp->szFileName, pFile->pszDbPath);
}
else
{
f_sprintf( (char *)pTmp->szFileName, "Unknown Db Name");
}
// Now let's see if we can get the Lock User Info for the
// two locks - Write locks (tx) and Wait locks (db).
if (pFile->pFileLockObj)
{
if (RC_BAD( rc = pFile->pFileLockObj->GetLockInfo( TRUE, (void *)&pTmp->pDbLockUser)))
{
pTmp->pDbLockUser = NULL;
}
}
else
{
pTmp->pDbLockUser = NULL;
}
if (pFile->pWriteLockObj)
{
if (RC_BAD( rc = pFile->pWriteLockObj->GetLockInfo( TRUE, (void *)&pTmp->pTxLockUser)))
{
pTmp->pTxLockUser = NULL;
}
}
else
{
pTmp->pTxLockUser = NULL;
}
Exit:
return;
}
/****************************************************************************
Desc: Gets the CHECKPOINT_INFO information for the specified pFile.
****************************************************************************/
void F_StatsPage::gatherCPStats(
STAT_GATHER * pStatGather,
FFILE_p pFile
)
{
CP_INFO_HEADER_p pTmp;
RCODE rc = FERR_OK;
flmAssert( pStatGather);
flmAssert( pFile);
// Allocate a new CP_INFO_HEADER and link it into the list.
if( RC_BAD( rc = f_alloc( sizeof( CP_INFO_HEADER), &pTmp)))
{
goto Exit;
}
if( RC_BAD( rc = f_alloc(
sizeof( CHECKPOINT_INFO), &pTmp->pCheckpointInfo)))
{
goto Exit;
}
// Save the file name.
if (pFile->pszDbPath)
{
f_strcpy( (char *)pTmp->szFileName, pFile->pszDbPath);
}
else
{
f_sprintf( (char *)pTmp->szFileName, "Unknown Db Name");
}
pTmp->pNext = pStatGather->pCPHeader;
pStatGather->pCPHeader = pTmp;
flmGetCPInfo( pFile, pTmp->pCheckpointInfo);
Exit:
if (RC_BAD(rc) && pTmp)
{
f_free( &pTmp);
}
return;
}
/****************************************************************************
Desc: Deletes all CP_INFO_HEADER structures linked from the pStatGather structure.
****************************************************************************/
void F_StatsPage::freeCPInfoHeaders(
STAT_GATHER * pStatGather
)
{
CP_INFO_HEADER_p pTmp;
while (pStatGather->pCPHeader)
{
pTmp = pStatGather->pCPHeader;
pStatGather->pCPHeader = pStatGather->pCPHeader->pNext;
if (pTmp->pCheckpointInfo)
{
f_free( &pTmp->pCheckpointInfo);
}
f_free( &pTmp);
}
}
/****************************************************************************
Desc: Prints out the Cache Stats stored in pStatGather.
****************************************************************************/
void F_StatsPage::printCacheStats(
STAT_GATHER * pStatGather,
STAT_GATHER * pOldStatGather)
{
fnPrintf( m_pHRequest, "
\n");
// Cache table.
printTableStart( "Cache", 3, 50);
// Cache table column headers
printTableRowStart();
printColumnHeading( "Stat Type", JUSTIFY_LEFT);
printColumnHeading( "Block Cache", JUSTIFY_RIGHT);
printColumnHeading( "Record Cache", JUSTIFY_RIGHT);
printTableRowEnd();
printCacheStatRow( TRUE, "Current Limit (Bytes)",
pStatGather->BlockCache.uiMaxBytes,
pStatGather->RecordCache.uiMaxBytes, TRUE,
(pStatGather->BlockCache.uiMaxBytes !=
pOldStatGather->BlockCache.uiMaxBytes ? TRUE : FALSE),
(pStatGather->RecordCache.uiMaxBytes !=
pOldStatGather->RecordCache.uiMaxBytes ? TRUE : FALSE));
printCacheStatRow( FALSE, "Total Items Cached",
pStatGather->BlockCache.uiCount,
pStatGather->RecordCache.uiCount, TRUE,
(pStatGather->BlockCache.uiCount !=
pOldStatGather->BlockCache.uiCount ? TRUE : FALSE),
(pStatGather->RecordCache.uiCount !=
pOldStatGather->RecordCache.uiCount ? TRUE : FALSE));
printCacheStatRow( TRUE, "Total Bytes Cached",
pStatGather->BlockCache.uiTotalBytesAllocated,
pStatGather->RecordCache.uiTotalBytesAllocated, TRUE,
(pStatGather->BlockCache.uiTotalBytesAllocated !=
pOldStatGather->BlockCache.uiTotalBytesAllocated ? TRUE : FALSE),
(pStatGather->RecordCache.uiTotalBytesAllocated !=
pOldStatGather->RecordCache.uiTotalBytesAllocated ? TRUE : FALSE));
printCacheStatRow( FALSE, "Old Items Cached",
pStatGather->BlockCache.uiOldVerCount,
pStatGather->RecordCache.uiOldVerCount, TRUE,
(pStatGather->BlockCache.uiOldVerCount !=
pOldStatGather->BlockCache.uiOldVerCount ? TRUE : FALSE),
(pStatGather->RecordCache.uiOldVerCount !=
pOldStatGather->RecordCache.uiOldVerCount ? TRUE : FALSE));
printCacheStatRow( TRUE, "Old Bytes Cached",
pStatGather->BlockCache.uiOldVerBytes,
pStatGather->RecordCache.uiOldVerBytes, TRUE,
(pStatGather->BlockCache.uiOldVerBytes !=
pOldStatGather->BlockCache.uiOldVerBytes ? TRUE : FALSE),
(pStatGather->RecordCache.uiOldVerBytes !=
pOldStatGather->RecordCache.uiOldVerBytes ? TRUE : FALSE));
printCacheStatRow( FALSE, "Hits",
pStatGather->BlockCache.uiCacheHits,
pStatGather->RecordCache.uiCacheHits, TRUE,
(pStatGather->BlockCache.uiCacheHits !=
pOldStatGather->BlockCache.uiCacheHits ? TRUE : FALSE),
(pStatGather->RecordCache.uiCacheHits !=
pOldStatGather->RecordCache.uiCacheHits ? TRUE : FALSE));
printCacheStatRow( TRUE, "Hit Looks",
pStatGather->BlockCache.uiCacheHitLooks,
pStatGather->RecordCache.uiCacheHitLooks, TRUE,
(pStatGather->BlockCache.uiCacheHitLooks !=
pOldStatGather->BlockCache.uiCacheHitLooks ? TRUE : FALSE),
(pStatGather->RecordCache.uiCacheHitLooks !=
pOldStatGather->RecordCache.uiCacheHitLooks ? TRUE : FALSE));
printCacheStatRow( FALSE, "Looks per Hit",
(pStatGather->BlockCache.uiCacheHits
? pStatGather->BlockCache.uiCacheHitLooks /
pStatGather->BlockCache.uiCacheHits
: (FLMUINT)0),
(pStatGather->RecordCache.uiCacheHits
? pStatGather->RecordCache.uiCacheHitLooks /
pStatGather->RecordCache.uiCacheHits
: (FLMUINT)0), TRUE,
(pStatGather->BlockCache.uiCacheHits !=
pOldStatGather->BlockCache.uiCacheHits ? TRUE : FALSE),
(pStatGather->RecordCache.uiCacheHits !=
pOldStatGather->RecordCache.uiCacheHits ? TRUE : FALSE));
printCacheStatRow( TRUE, "Faults",
pStatGather->BlockCache.uiCacheFaults,
pStatGather->RecordCache.uiCacheFaults, TRUE,
(pStatGather->BlockCache.uiCacheFaults !=
pOldStatGather->BlockCache.uiCacheFaults ? TRUE : FALSE),
(pStatGather->RecordCache.uiCacheFaults !=
pOldStatGather->RecordCache.uiCacheFaults ? TRUE : FALSE));
printCacheStatRow( FALSE, "Fault Looks",
pStatGather->BlockCache.uiCacheFaultLooks,
pStatGather->RecordCache.uiCacheFaultLooks, TRUE,
(pStatGather->BlockCache.uiCacheFaultLooks !=
pOldStatGather->BlockCache.uiCacheFaultLooks ? TRUE : FALSE),
(pStatGather->RecordCache.uiCacheFaultLooks !=
pOldStatGather->RecordCache.uiCacheFaultLooks ? TRUE : FALSE));
printCacheStatRow( TRUE, "Looks Per Fault",
(pStatGather->BlockCache.uiCacheFaults
? pStatGather->BlockCache.uiCacheFaultLooks /
pStatGather->BlockCache.uiCacheFaults
: (FLMUINT)0),
(pStatGather->RecordCache.uiCacheFaults
? pStatGather->RecordCache.uiCacheFaultLooks /
pStatGather->RecordCache.uiCacheFaults
: (FLMUINT)0), TRUE,
(pStatGather->BlockCache.uiCacheFaults !=
pOldStatGather->BlockCache.uiCacheFaults ? TRUE : FALSE),
(pStatGather->RecordCache.uiCacheFaults !=
pOldStatGather->RecordCache.uiCacheFaults ? TRUE : FALSE));
printCacheStatRow( FALSE, "Dirty Blocks",
pStatGather->uiDirtyBlocks, 0, FALSE,
(pStatGather->uiDirtyBlocks !=
pOldStatGather->uiDirtyBlocks ? TRUE : FALSE));
printCacheStatRow( TRUE, "Dirty Bytes",
pStatGather->uiDirtyBytes, 0, FALSE,
(pStatGather->uiDirtyBytes !=
pOldStatGather->uiDirtyBytes ? TRUE : FALSE));
printCacheStatRow( FALSE, "Log Blocks",
pStatGather->uiLogBlocks, 0, FALSE,
(pStatGather->uiLogBlocks !=
pOldStatGather->uiLogBlocks ? TRUE : FALSE));
printCacheStatRow( TRUE, "Log Bytes",
pStatGather->uiLogBytes, 0, FALSE,
(pStatGather->uiLogBytes !=
pOldStatGather->uiLogBytes ? TRUE : FALSE));
printCacheStatRow( FALSE, "Free Blocks",
pStatGather->uiFreeCount, 0, FALSE,
(pStatGather->uiFreeCount !=
pOldStatGather->uiFreeCount ? TRUE : FALSE));
printCacheStatRow( TRUE, "Free Bytes",
pStatGather->uiFreeBytes, 0, FALSE,
(pStatGather->uiFreeBytes !=
pOldStatGather->uiFreeBytes ? TRUE : FALSE));
printCacheStatRow( FALSE, "Replaceable Blocks",
pStatGather->uiReplaceableCount, 0, FALSE,
(pStatGather->uiReplaceableCount !=
pOldStatGather->uiReplaceableCount ? TRUE : FALSE));
printCacheStatRow( TRUE, "Replaceable Bytes",
pStatGather->uiReplaceableBytes, 0, FALSE,
(pStatGather->uiReplaceableBytes !=
pOldStatGather->uiReplaceableBytes ? TRUE : FALSE));
printTableEnd();
}
/****************************************************************************
Desc: Prints out the Operation Stats stored in pStatGather.
****************************************************************************/
void F_StatsPage::printOperationStats(
STAT_GATHER * pStatGather,
STAT_GATHER * pOldStatGather)
{
COUNT_TIME_STAT Stat;
COUNT_TIME_STAT OldStat;
FLMBOOL bHighlight;
if (pStatGather->uiStartTime)
{
fnPrintf( m_pHRequest, "
\n");
// Database operations table
printTableStart( "Database Operations", 4, 75);
// Operations table column headers
printTableRowStart();
printColumnHeading( "Operation", JUSTIFY_LEFT);
printColumnHeading( "Count", JUSTIFY_RIGHT);
printColumnHeading( "Total Seconds", JUSTIFY_RIGHT);
printColumnHeading( "Avg Seconds", JUSTIFY_RIGHT);
printTableRowEnd();
// Transaction rows
bHighlight = FALSE;
printCountTimeRow( bHighlight = ~bHighlight, "Committed Update Trans",
&pStatGather->CommittedUpdTrans,
&pOldStatGather->CommittedUpdTrans);
printCountTimeRow( bHighlight = ~bHighlight, "Aborted Update Trans",
&pStatGather->AbortedUpdTrans,
&pOldStatGather->AbortedUpdTrans);
printCountTimeRow( bHighlight = ~bHighlight, "Group Finishes",
&pStatGather->GroupCompletes,
&pOldStatGather->GroupCompletes);
Stat.ui64Count = pStatGather->ui64GroupFinished;
OldStat.ui64Count = pOldStatGather->ui64GroupFinished;
printCountTimeRow( bHighlight = ~bHighlight, "Total Finished",
&Stat, &OldStat, TRUE);
if (pStatGather->GroupCompletes.ui64Count)
{
Stat.ui64Count = pStatGather->ui64GroupFinished /
pStatGather->GroupCompletes.ui64Count;
}
else
{
Stat.ui64Count = 0;
}
if (pOldStatGather->GroupCompletes.ui64Count)
{
OldStat.ui64Count = pOldStatGather->ui64GroupFinished /
pOldStatGather->GroupCompletes.ui64Count;
}
else
{
OldStat.ui64Count = 0;
}
printCountTimeRow( bHighlight = ~bHighlight, "Average Per Group",
&Stat, &OldStat, TRUE);
printCountTimeRow( bHighlight = ~bHighlight, "Committed Read Trans",
&pStatGather->CommittedReadTrans,
&pOldStatGather->CommittedReadTrans);
printCountTimeRow( bHighlight = ~bHighlight, "Aborted Read Trans",
&pStatGather->AbortedReadTrans,
&pOldStatGather->AbortedReadTrans);
printCountTimeRow( bHighlight = ~bHighlight, "Reads",
&pStatGather->Reads,
&pOldStatGather->Reads);
printCountTimeRow( bHighlight = ~bHighlight, "Adds",
&pStatGather->Adds,
&pOldStatGather->Adds);
printCountTimeRow( bHighlight = ~bHighlight, "Modifies",
&pStatGather->Modifies,
&pOldStatGather->Modifies);
printCountTimeRow( bHighlight = ~bHighlight, "Deletes",
&pStatGather->Deletes,
&pOldStatGather->Deletes);
printCountTimeRow( bHighlight = ~bHighlight, "Queries",
&pStatGather->Queries,
&pOldStatGather->Queries, TRUE);
printCountTimeRow( bHighlight = ~bHighlight, "Query Reads",
&pStatGather->QueryReads,
&pOldStatGather->QueryReads, TRUE);
Stat.ui64Count = pStatGather->ui64BlockSplits;
OldStat.ui64Count = pOldStatGather->ui64BlockSplits;
printCountTimeRow( bHighlight = ~bHighlight, "Block Splits",
&Stat, &OldStat, TRUE);
Stat.ui64Count = pStatGather->ui64BlockCombines;
OldStat.ui64Count = pOldStatGather->ui64BlockCombines;
printCountTimeRow( bHighlight = ~bHighlight, "Block Combines",
&Stat, &OldStat, TRUE);
printTableEnd();
}
}
/****************************************************************************
Desc: Prints out the Lock Stats stored in pStatGather.
****************************************************************************/
void F_StatsPage::printLockStats(
STAT_GATHER * pStatGather,
STAT_GATHER * pOldStatGather)
{
if (pStatGather->uiStartTime)
{
LOCK_USER_HEADER_p pLckHdr;
fnPrintf( m_pHRequest, "
\n");
// Lock table.
printTableStart( "Locks", 4, 75);
// Locks table column headers
printTableRowStart();
printColumnHeading( "Stat Type", JUSTIFY_LEFT);
printColumnHeading( "Count", JUSTIFY_RIGHT);
printColumnHeading( "Total Seconds", JUSTIFY_RIGHT);
printColumnHeading( "Avg Seconds", JUSTIFY_RIGHT);
printTableRowEnd();
printCountTimeRow( TRUE, "Time No Locks Held",
&pStatGather->NoLocks,
&pOldStatGather->NoLocks);
printCountTimeRow( FALSE, "Time Waiting for Locks",
&pStatGather->WaitingForLock,
&pOldStatGather->WaitingForLock);
printCountTimeRow( TRUE, "Time Locks Held",
&pStatGather->HeldLock,
&pOldStatGather->HeldLock);
printTableEnd();
// Display the Lock Queue for each of the files open...
pLckHdr = pStatGather->pLockUsers;
while (pLckHdr)
{
char szTitle[ 128];
FLMBOOL bHighlight = FALSE;
FLMBOOL bLocked = TRUE;
LOCK_USER * pLckUsr;
FLMUINT uiTxWaiters;
FLMUINT uiDbWaiters;
uiTxWaiters = 0;
pLckUsr = pLckHdr->pTxLockUser;
while (pLckUsr && pLckUsr->uiThreadId)
{
uiTxWaiters++;
pLckUsr++;
}
if( uiTxWaiters)
{
uiTxWaiters--;
}
uiDbWaiters = 0;
pLckUsr = pLckHdr->pDbLockUser;
while (pLckUsr && pLckUsr->uiThreadId)
{
uiDbWaiters++;
pLckUsr++;
}
if( uiDbWaiters)
{
uiDbWaiters--;
}
fnPrintf( m_pHRequest, "
\n");
// Start the new table
f_sprintf( (char *)szTitle,
"Lock Queue - %s, TX Waiters: %u, DB Waiters: %u", pLckHdr->szFileName,
(unsigned)uiTxWaiters, (unsigned)uiDbWaiters);
printTableStart( (char *)szTitle, 4, 75);
printTableRowStart( bHighlight = ~bHighlight);
printColumnHeading( "Thread Id", JUSTIFY_LEFT);
printColumnHeading( "Name", JUSTIFY_RIGHT);
printColumnHeading( "Status", JUSTIFY_RIGHT);
printColumnHeading( "Time", JUSTIFY_RIGHT);
printTableRowEnd();
// Display the body...
pLckUsr = pLckHdr->pTxLockUser;
while (pLckUsr && pLckUsr->uiThreadId)
{
char szThreadName[ 50];
printTableRowStart( bHighlight = ~bHighlight);
printTableDataStart( TRUE, JUSTIFY_LEFT);
fnPrintf( m_pHRequest, "%u", (unsigned)pLckUsr->uiThreadId);
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
#ifdef FLM_NLM
if( kGetThreadName( pLckUsr->uiThreadId, (char *)szThreadName,
sizeof( szThreadName)) !=0)
{
f_sprintf( (char *)szThreadName, "N/A");
}
#else
// Get the thread name from the thread manager
// gv_FlmSysData.pThreadMgr->getThreadName( pLckUsr->uiThreadId, szThreadName);
f_sprintf( (char *)szThreadName, "N/A"); // VISIT: Remove this when you get the function above working
#endif
fnPrintf( m_pHRequest, "%s", szThreadName);
printTableDataEnd();
// Status
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "%s (Tx)", bLocked ? "Locked" : "Waiting");
bLocked = FALSE;
printTableDataEnd();
// Time in status
printElapTime( (FLMUINT64)pLckUsr->uiTime, NULL, JUSTIFY_RIGHT, TRUE);
printTableRowEnd();
// Next entry...
pLckUsr++;
}
// Display the Db info.
pLckUsr = pLckHdr->pDbLockUser;
bLocked = TRUE;
while (pLckUsr && pLckUsr->uiThreadId)
{
char szThreadName[ 50];
printTableRowStart( bHighlight = ~bHighlight);
printTableDataStart( TRUE, JUSTIFY_LEFT);
fnPrintf( m_pHRequest, "%u", (unsigned)pLckUsr->uiThreadId);
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
#ifdef FLM_NLM
if( kGetThreadName( pLckUsr->uiThreadId, (char *)szThreadName,
sizeof( szThreadName)) !=0)
{
f_sprintf( (char *)szThreadName, "N/A");
}
#else
// Get the thread name from the thread manager
// gv_FlmSysData.pThreadMgr->getThreadName( pLckUsr->uiThreadId, szThreadName);
f_sprintf( (char *)szThreadName, "N/A"); // VISIT: Remove this when you get the function above working
#endif
fnPrintf( m_pHRequest, "%s", szThreadName);
printTableDataEnd();
// Status
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "%s (Db)", bLocked ? "Locked" : "Waiting");
bLocked = FALSE;
printTableDataEnd();
// Time in status
printElapTime( (FLMUINT64)pLckUsr->uiTime, NULL, JUSTIFY_RIGHT, TRUE);
printTableRowEnd();
// Next entry...
pLckUsr++;
}
printTableEnd();
pLckHdr = pLckHdr->pNext;
}
}
}
/****************************************************************************
Desc: Prints out the Disk Stats stored in pStatGather.
****************************************************************************/
void F_StatsPage::printDiskStats(
STAT_GATHER * pStatGather,
STAT_GATHER * pOldStatGather)
{
char szTemp[ 100];
FLMBOOL bHighlight = FALSE;
if (pStatGather->uiStartTime)
{
fnPrintf( m_pHRequest, "
\n");
// Disk IO table.
f_sprintf( (char *)szTemp, "Disk IO");
if (m_pFocusBlock)
{
f_strcat( (char *)szTemp, " - focus enabled on ");
f_strcat( (char *)szTemp, (char *)m_pFocusBlock->szFileName);
if (m_pFocusBlock->uiLFileNum > 0)
{
char szLFNum[ 20];
f_strcat( (char *)szTemp, " on logical file ");
f_sprintf( (char *)szLFNum, "%lu", m_pFocusBlock->uiLFileNum);
f_strcat( (char *)szTemp, (char *)szLFNum);
}
}
printTableStart( (char *)szTemp, 5, 100);
// Database operations table column headers
printTableRowStart();
printColumnHeading( "IO CATEGORY", JUSTIFY_LEFT);
printColumnHeading( "Count", JUSTIFY_RIGHT);
printColumnHeading( "Total Bytes", JUSTIFY_RIGHT);
printColumnHeading( "Total Seconds", JUSTIFY_RIGHT);
printColumnHeading( "Avg Seconds", JUSTIFY_RIGHT);
printTableRowEnd();
printIORow( bHighlight = !bHighlight, "READS",
&pStatGather->IOReads,
&pOldStatGather->IOReads);
printIORow( bHighlight = !bHighlight, "Root Blocks",
&pStatGather->IORootBlockReads,
&pOldStatGather->IORootBlockReads);
printIORow( bHighlight = !bHighlight, "Non-Leaf Blocks",
&pStatGather->IONonLeafBlockReads,
&pOldStatGather->IONonLeafBlockReads);
printIORow( bHighlight = !bHighlight, "Leaf Blocks",
&pStatGather->IOLeafBlockReads,
&pOldStatGather->IOLeafBlockReads);
if ((m_pFocusBlock == NULL) ||
(m_pFocusBlock->uiLFileNum == 0))
{
printIORow( bHighlight = !bHighlight, "Avail Blocks",
&pStatGather->IOAvailBlockReads,
&pOldStatGather->IOAvailBlockReads);
printIORow( bHighlight = !bHighlight, "LFH Blocks",
&pStatGather->IOLFHBlockReads,
&pOldStatGather->IOLFHBlockReads);
printIORow( bHighlight = !bHighlight, "Prior Image Blocks",
&pStatGather->IORollbackBlockReads,
&pOldStatGather->IORollbackBlockReads);
printTableRowStart( bHighlight = !bHighlight);
printTableDataStart( TRUE, JUSTIFY_LEFT);
fnPrintf( m_pHRequest, "Read Errors");
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "%s%u%s",
(pStatGather->uiReadErrors != pOldStatGather->uiReadErrors ? "" : ""),
(unsigned)pStatGather->uiReadErrors,
(pStatGather->uiReadErrors != pOldStatGather->uiReadErrors ? "" : ""));
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "N/A");
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "N/A");
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "N/A");
printTableDataEnd();
printTableRowEnd();
printTableRowStart( bHighlight = !bHighlight);
printTableDataStart( TRUE, JUSTIFY_LEFT);
fnPrintf( m_pHRequest, "Check Errors");
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "%s%u%s",
(pStatGather->uiCheckErrors != pOldStatGather->uiCheckErrors ? "" : ""),
(unsigned)pStatGather->uiCheckErrors,
(pStatGather->uiCheckErrors != pOldStatGather->uiCheckErrors ? "" : ""));
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "N/A");
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "N/A");
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "N/A");
printTableDataEnd();
printTableRowEnd();
}
printIORow( bHighlight = !bHighlight, "WRITES",
&pStatGather->IOWrites,
&pOldStatGather->IOWrites);
printIORow( bHighlight = !bHighlight, "Root Blocks",
&pStatGather->IORootBlockWrites,
&pOldStatGather->IORootBlockWrites);
printIORow( bHighlight = !bHighlight, "Non-Leaf Blocks",
&pStatGather->IONonLeafBlockWrites,
&pOldStatGather->IONonLeafBlockWrites);
printIORow( bHighlight = !bHighlight, "Leaf Blocks",
&pStatGather->IOLeafBlockWrites,
&pOldStatGather->IOLeafBlockWrites);
if ((m_pFocusBlock == NULL) ||
(m_pFocusBlock->uiLFileNum == 0))
{
printIORow( bHighlight = !bHighlight, "Avail Blocks",
&pStatGather->IOAvailBlockWrites,
&pOldStatGather->IOAvailBlockWrites);
printIORow( bHighlight = !bHighlight, "LFH Blocks",
&pStatGather->IOLFHBlockWrites,
&pOldStatGather->IOLFHBlockWrites);
printIORow( bHighlight = !bHighlight, "Rollback Log Blocks",
&pStatGather->IORollBackLogWrites,
&pOldStatGather->IORollBackLogWrites);
printIORow( bHighlight = !bHighlight, "Log Header",
&pStatGather->IOLogHdrWrites,
&pOldStatGather->IOLogHdrWrites);
printIORow( bHighlight = !bHighlight, "Undo Blocks",
&pStatGather->IORolledbackBlockWrites,
&pOldStatGather->IORolledbackBlockWrites);
printTableRowStart( bHighlight = !bHighlight);
printTableDataStart( TRUE, JUSTIFY_LEFT);
fnPrintf( m_pHRequest, "Write Errors");
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "%s%u%s",
(pStatGather->uiWriteErrors != pOldStatGather->uiWriteErrors ? "" : ""),
(unsigned)pStatGather->uiWriteErrors,
(pStatGather->uiWriteErrors != pOldStatGather->uiWriteErrors ? "" : ""));
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "N/A");
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "N/A");
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "N/A");
printTableDataEnd();
printTableRowEnd();
}
printTableEnd();
}
}
/****************************************************************************
Desc: Prints out the Checkpoint Stats stored in pStatGather.
****************************************************************************/
void F_StatsPage::printCPStats(
STAT_GATHER * pStatGather)
{
CP_INFO_HEADER_p pCPHdr;
fnPrintf( m_pHRequest, "
\n");
// Checkpoint Thread table.
pCPHdr = pStatGather->pCPHeader;
while (pCPHdr)
{
char szTitle[ 50];
CHECKPOINT_INFO * pCPInfo;
FLMBOOL bHighlight = FALSE;
f_sprintf( (char *)szTitle, "Checkpoint Thread - %s", pCPHdr->szFileName);
printTableStart( (char *)szTitle, 2, 50);
printTableRowStart();
printColumnHeading( "Stat Type", JUSTIFY_LEFT);
printColumnHeading( "Value", JUSTIFY_RIGHT);
printTableRowEnd();
pCPInfo = pCPHdr->pCheckpointInfo;
printTableRowStart( bHighlight = !bHighlight);
printTableDataStart( TRUE, JUSTIFY_LEFT);
fnPrintf( m_pHRequest, "State");
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "%s", pCPInfo->bRunning ? "Yes" : "No");
printTableDataEnd();
printTableRowEnd();
printTableRowStart( bHighlight = !bHighlight);
printTableDataStart( TRUE, JUSTIFY_LEFT);
fnPrintf( m_pHRequest, "Running Time");
printTableDataEnd();
printElapTime( (FLMUINT64)pCPInfo->uiRunningTime, NULL, JUSTIFY_RIGHT, TRUE);
printTableRowEnd();
printTableRowStart( bHighlight = !bHighlight);
printTableDataStart( TRUE, JUSTIFY_LEFT);
fnPrintf( m_pHRequest, "Forcing Checkpoint");
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "%s", pCPInfo->bForcingCheckpoint ? "Yes" : "No");
printTableDataEnd();
printTableRowEnd();
printTableRowStart( bHighlight = !bHighlight);
printTableDataStart( TRUE, JUSTIFY_LEFT);
fnPrintf( m_pHRequest, "Forced Checkpoint Running Time");
printTableDataEnd();
printElapTime( (FLMUINT64)pCPInfo->uiForceCheckpointRunningTime, NULL, JUSTIFY_RIGHT, TRUE);
printTableRowEnd();
printTableRowStart( bHighlight = !bHighlight);
printTableDataStart( TRUE, JUSTIFY_LEFT);
fnPrintf( m_pHRequest, "Forced Checkpoint Reason");
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
switch( pCPInfo->iForceCheckpointReason)
{
case CP_TIME_INTERVAL_REASON:
fnPrintf( m_pHRequest, "Time interval");
break;
case CP_SHUTTING_DOWN_REASON:
fnPrintf( m_pHRequest, "Shutting down");
break;
case CP_RFL_VOLUME_PROBLEM:
fnPrintf( m_pHRequest, "RFL volume problem");
break;
default:
fnPrintf( m_pHRequest, "Unknown");
break;
}
printTableDataEnd();
printTableRowEnd();
printTableRowStart( bHighlight = !bHighlight);
printTableDataStart( TRUE, JUSTIFY_LEFT);
fnPrintf( m_pHRequest, "Waiting for Read Trans Time");
printTableDataEnd();
printElapTime( (FLMUINT64)pCPInfo->uiWaitTruncateTime, NULL, JUSTIFY_RIGHT, TRUE);
printTableRowEnd();
printTableRowStart( bHighlight = !bHighlight);
printTableDataStart( TRUE, JUSTIFY_LEFT);
fnPrintf( m_pHRequest, "Writing Data Blocks");
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "%s", pCPInfo->bWritingDataBlocks ? "Yes" : "No");
printTableDataEnd();
printTableRowEnd();
printTableRowStart( bHighlight = !bHighlight);
printTableDataStart( TRUE, JUSTIFY_LEFT);
fnPrintf( m_pHRequest, "Log Blocks Written");
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "%u", pCPInfo->uiLogBlocksWritten);
printTableDataEnd();
printTableRowEnd();
printTableRowStart( bHighlight = !bHighlight);
printTableDataStart( TRUE, JUSTIFY_LEFT);
fnPrintf( m_pHRequest, "Data Blocks Written");
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "%u", pCPInfo->uiDataBlocksWritten);
printTableDataEnd();
printTableRowEnd();
if (pCPInfo->uiDirtyCacheBytes && pCPInfo->uiBlockSize)
{
printTableRowStart( bHighlight = !bHighlight);
printTableDataStart( TRUE, JUSTIFY_LEFT);
fnPrintf( m_pHRequest, "Dirty Cache Blocks");
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "%u", pCPInfo->uiDirtyCacheBytes / pCPInfo->uiBlockSize);
printTableDataEnd();
printTableRowEnd();
}
printTableRowStart( bHighlight = !bHighlight);
printTableDataStart( TRUE, JUSTIFY_LEFT);
fnPrintf( m_pHRequest, "Block Size");
printTableDataEnd();
printTableDataStart( TRUE, JUSTIFY_RIGHT);
fnPrintf( m_pHRequest, "%u", pCPInfo->uiBlockSize);
printTableDataEnd();
printTableRowEnd();
printTableEnd();
pCPHdr = pCPHdr->pNext;
}
}
/****************************************************************************
Desc: Prints out the Checkpoint Stats stored in pStatGather.
****************************************************************************/
void F_StatsPage::displayFocus(
FLMUINT uiNumParams,
const char ** ppszParams)
{
FLMBOOL bFocusAll;
FLMBOOL bFocusLFile;
FLMBOOL bFocusDb;
void * pvSession = NULL;
char szTmpFocus[ 1] = { 0 };
FLMUINT uiLoop;
bFocusAll = DetectParameter( uiNumParams, ppszParams, "All");
bFocusLFile = DetectParameter( uiNumParams, ppszParams, "LFile");
bFocusDb = DetectParameter( uiNumParams, ppszParams, "Db");
if (gv_FlmSysData.HttpConfigParms.fnAcquireSession)
{
if ((pvSession = fnAcquireSession()) == NULL)
{
printErrorPage( FERR_FAILURE, TRUE, "Could not obtain session handle");
goto Exit;
}
}
if (!bFocusLFile & !bFocusDb & !bFocusAll)
{
printDocStart( "Focus");
fnPrintf( m_pHRequest, "\n");
// We need to collect a list of databases to present.
f_mutexLock( gv_FlmSysData.Stats.hMutex);
for (uiLoop = 0; uiLoop < gv_FlmSysData.Stats.uiNumDbStats; uiLoop++)
{
FLMBOOL bHighlight = FALSE;
fnPrintf( m_pHRequest, "\n");
}
f_mutexUnlock( gv_FlmSysData.Stats.hMutex);
printDocEnd();
goto Exit;
}
if (bFocusAll)
{
// A request to set the focus to all indicates that we are currently
// focusing on something other than All, so we will need to delete
// the current focus setting. Setting the value to NULL will delete
// the existing entry. If we find an entry in m_pFocusBlock
// (which we shouldn't) we will delete it.
if (m_pFocusBlock)
{
flmAssert( 0);
f_free( &m_pFocusBlock);
}
if (fnSetSessionValue( pvSession,
STAT_FOCUS, (void *)szTmpFocus, 0) != 0)
{
flmAssert( 0);
printErrorPage( FERR_MEM, TRUE, "Could not process request due to a memory allocation failure");
goto Exit;
}
}
else
{
// We assume we have bDb set since bLFile cannot be set without it.
// Retrieve the Db value.
char szDb[ 101];
char szLFile[ 21];
char szTemp[ 123];
if (RC_BAD( ExtractParameter( uiNumParams, ppszParams,
"Db", sizeof( szDb), szDb)))
{
printErrorPage( FERR_INVALID_PARM, TRUE, "Parameter Db not present. Could not process this request.");
goto Exit;
}
if (bFocusLFile)
{
if (RC_BAD( ExtractParameter( uiNumParams, ppszParams,
"LFile", sizeof( szLFile), szLFile)))
{
printErrorPage( FERR_INVALID_PARM, TRUE, "Parameter Db not present. Could not process this request.");
goto Exit;
}
}
fcsDecodeHttpString( szDb);
f_sprintf( (char *)szTemp, "%.100s;%.20s", szDb, (char *)szLFile);
// Now save this in the current session...
if (fnSetSessionValue( pvSession,
STAT_FOCUS,
(void *)szTemp,
(size_t)f_strlen(szTemp)) != 0)
{
flmAssert( 0);
goto Exit;
}
}
// Getting to this point indicates success. We will return a confirmation page.
printDocStart( "Focus - Confirmation");
fnPrintf( m_pHRequest, "\n",
m_pszURLString);
printDocEnd();
Exit:
if (pvSession)
{
fnReleaseSession( pvSession);
}
}
/****************************************************************************
Desc: Prints out the Checkpoint Stats stored in pStatGather.
****************************************************************************/
RCODE F_StatsPage::setFocus(
char * pszFocus)
{
RCODE rc = FERR_OK;
char * pTmp;
if (m_pFocusBlock)
{
flmAssert( 0);
f_free( &m_pFocusBlock);
}
if (f_strlen( pszFocus) == 0)
{
goto Exit;
}
if( RC_BAD( rc = f_alloc(
sizeof( FOCUS_BLOCK), &m_pFocusBlock)))
{
goto Exit;
}
pTmp = pszFocus;
m_pFocusBlock->uiLFileNum = 0;
while (*pTmp != ';' && *pTmp != '\0')
{
pTmp++;
}
*pTmp = 0;
f_strcpy( m_pFocusBlock->szFileName, pszFocus);
pTmp++;
if( *pTmp != '\0')
{
m_pFocusBlock->uiLFileNum = f_atoud( pTmp);
}
Exit:
return( rc);
}