Added option in FLAIM to disable direct I/O on Linux and Unix platforms. Re-architected the FTK I/O layer and cleaned up the async interfaces.
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@643 0109f412-320b-0410-ab79-c3e0c5ffbbe6
This commit is contained in:
@@ -42,13 +42,12 @@
|
||||
#define FLM_MAX_CACHE_SIZE (~((FLMUINT)0))
|
||||
#endif
|
||||
|
||||
#define DEFAULT_OPEN_THRESHOLD 100 // 100 file handles to cache
|
||||
#define DEFAULT_MAX_AVAIL_TIME 900 // 15 minutes
|
||||
|
||||
FLMATOMIC gv_flmSysSpinLock = 0;
|
||||
FLMUINT gv_uiFlmSysStartupCount = 0;
|
||||
|
||||
FSTATIC void flmInitHashTbl(
|
||||
FBUCKET * pHashTable,
|
||||
FLMUINT uiHashEntries);
|
||||
|
||||
FSTATIC RCODE flmGetCacheBytes(
|
||||
FLMUINT uiPercent,
|
||||
FLMUINT uiMin,
|
||||
@@ -84,7 +83,7 @@ FSTATIC void flmCleanup( void);
|
||||
FSTATIC void flmUnlinkFileFromBucket(
|
||||
FFILE * pFile);
|
||||
|
||||
RCODE flmSystemMonitor(
|
||||
RCODE FLMAPI flmSystemMonitor(
|
||||
IF_Thread * pThread);
|
||||
|
||||
FSTATIC RCODE flmRegisterHttpCallback(
|
||||
@@ -156,67 +155,6 @@ FINLINE void flmFreeDictList(
|
||||
*ppDictRV = NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: This routine initializes a hash table.
|
||||
****************************************************************************/
|
||||
FSTATIC void flmInitHashTbl(
|
||||
FBUCKET * pHashTable,
|
||||
FLMUINT uiHashEntries)
|
||||
{
|
||||
FLMUINT uiCnt;
|
||||
FLMUINT uiRandVal;
|
||||
FLMUINT uiTempVal;
|
||||
|
||||
for( uiCnt = 0; uiCnt < uiHashEntries; uiCnt++)
|
||||
{
|
||||
pHashTable [uiCnt].uiHashValue = (FLMBYTE)uiCnt;
|
||||
pHashTable [uiCnt].pFirstInBucket = NULL;
|
||||
}
|
||||
|
||||
if (uiHashEntries <= 256)
|
||||
{
|
||||
for (uiCnt = 0; uiCnt < uiHashEntries - 1; uiCnt++)
|
||||
{
|
||||
uiRandVal = f_getRandomUINT32( (FLMUINT32)uiCnt, (FLMUINT32)(uiHashEntries - 1));
|
||||
|
||||
if (uiRandVal != uiCnt)
|
||||
{
|
||||
uiTempVal = (FLMBYTE)pHashTable [uiCnt].uiHashValue;
|
||||
pHashTable [uiCnt].uiHashValue = pHashTable [uiRandVal].uiHashValue;
|
||||
pHashTable [uiRandVal].uiHashValue = uiTempVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: This routine allocates and initializes a hash table.
|
||||
****************************************************************************/
|
||||
RCODE flmAllocHashTbl(
|
||||
FLMUINT uiHashTblSize,
|
||||
FBUCKET ** ppHashTblRV)
|
||||
{
|
||||
RCODE rc = FERR_OK;
|
||||
FBUCKET * pHashTbl = NULL;
|
||||
|
||||
// Allocate memory for the hash table
|
||||
|
||||
if( RC_BAD( rc = f_calloc(
|
||||
(FLMUINT)(sizeof( FBUCKET)) * uiHashTblSize, &pHashTbl)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Initialize the hash table
|
||||
|
||||
flmInitHashTbl( pHashTbl, uiHashTblSize);
|
||||
|
||||
Exit:
|
||||
|
||||
*ppHashTblRV = pHashTbl;
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: This routine determines the number of cache bytes to use for caching
|
||||
based on a percentage of available physical memory or a percentage
|
||||
@@ -382,7 +320,6 @@ FLMEXP RCODE FLMAPI FlmStartup( void)
|
||||
// call to f_memoryInit().
|
||||
|
||||
gv_FlmSysData.hShareMutex = F_MUTEX_NULL;
|
||||
gv_FlmSysData.hFileHdlMutex = F_MUTEX_NULL;
|
||||
gv_FlmSysData.uiMaxStratifyIterations = DEFAULT_MAX_STRATIFY_ITERATIONS;
|
||||
gv_FlmSysData.uiMaxStratifyTime = DEFAULT_MAX_STRATIFY_TIME;
|
||||
|
||||
@@ -391,7 +328,15 @@ FLMEXP RCODE FLMAPI FlmStartup( void)
|
||||
gv_FlmSysData.UpdateEvents.hMutex = F_MUTEX_NULL;
|
||||
gv_FlmSysData.LockEvents.hMutex = F_MUTEX_NULL;
|
||||
gv_FlmSysData.SizeEvents.hMutex = F_MUTEX_NULL;
|
||||
|
||||
// Set the default file open flags
|
||||
|
||||
gv_FlmSysData.uiFileOpenFlags =
|
||||
FLM_IO_RDWR | FLM_IO_SH_DENYNONE | FLM_IO_DIRECT;
|
||||
|
||||
gv_FlmSysData.uiFileCreateFlags =
|
||||
gv_FlmSysData.uiFileOpenFlags | FLM_IO_EXCL | FLM_IO_CREATE_DIR;
|
||||
|
||||
#ifdef FLM_DBG_LOG
|
||||
flmDbgLogInit();
|
||||
#endif
|
||||
@@ -484,6 +429,7 @@ FLMEXP RCODE FLMAPI FlmStartup( void)
|
||||
|
||||
gv_FlmSysData.uiMaxCache = uiCacheBytes;
|
||||
uiCacheBytes >>= 1;
|
||||
|
||||
if (RC_BAD( rc = ScaInit( uiCacheBytes)))
|
||||
{
|
||||
goto Exit;
|
||||
@@ -506,16 +452,6 @@ FLMEXP RCODE FLMAPI FlmStartup( void)
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (RC_BAD(rc = f_mutexCreate( &gv_FlmSysData.hFileHdlMutex)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (RC_BAD(rc = f_mutexCreate( &gv_FlmSysData.hServerLockMgrMutex)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (RC_BAD( rc = f_mutexCreate( &gv_FlmSysData.HttpConfigParms.hMutex)))
|
||||
{
|
||||
goto Exit;
|
||||
@@ -536,7 +472,7 @@ FLMEXP RCODE FLMAPI FlmStartup( void)
|
||||
|
||||
// Allocate memory for the file name hash table
|
||||
|
||||
if (RC_BAD(rc = flmAllocHashTbl( FILE_HASH_ENTRIES,
|
||||
if (RC_BAD(rc = f_allocHashTable( FILE_HASH_ENTRIES,
|
||||
&gv_FlmSysData.pFileHashTbl)))
|
||||
{
|
||||
goto Exit;
|
||||
@@ -551,8 +487,15 @@ FLMEXP RCODE FLMAPI FlmStartup( void)
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
gv_FlmSysData.bOkToDoAsyncWrites = gv_FlmSysData.pFileSystem->canDoAsync();
|
||||
|
||||
// Allocate a file handle cache
|
||||
|
||||
if( RC_BAD( rc = gv_FlmSysData.pFileSystem->allocFileHandleCache(
|
||||
DEFAULT_OPEN_THRESHOLD, DEFAULT_MAX_UNUSED_TIME,
|
||||
&gv_FlmSysData.pFileHdlCache)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Set up the session manager
|
||||
|
||||
if( (gv_FlmSysData.pSessionMgr = f_new F_SessionMgr) == NULL)
|
||||
@@ -599,6 +542,7 @@ FLMEXP RCODE FLMAPI FlmStartup( void)
|
||||
iHandle = (int)f_getpid();
|
||||
|
||||
// Initialize NICI
|
||||
|
||||
if (CCS_Init(&iHandle))
|
||||
{
|
||||
// Failure.
|
||||
@@ -1139,8 +1083,39 @@ FLMEXP RCODE FLMAPI FlmConfig(
|
||||
{
|
||||
case FLM_OPEN_THRESHOLD:
|
||||
{
|
||||
rc = gv_FlmSysData.pFileHdlCache->setOpenThreshold( (FLMUINT)Value1);
|
||||
break;
|
||||
}
|
||||
|
||||
case FLM_DIRECT_IO_STATE:
|
||||
{
|
||||
// Direct I/O state can only be changed when there are no open
|
||||
// databases. We also only allow DIO to be disabled on Unix
|
||||
// platforms.
|
||||
|
||||
#ifdef FLM_UNIX
|
||||
f_mutexLock( gv_FlmSysData.hShareMutex);
|
||||
|
||||
if( !gv_FlmSysData.uiOpenFFiles)
|
||||
{
|
||||
if( (FLMBOOL)Value1)
|
||||
{
|
||||
gv_FlmSysData.uiFileOpenFlags =
|
||||
FLM_IO_RDWR | FLM_IO_SH_DENYNONE | FLM_IO_DIRECT;
|
||||
}
|
||||
else
|
||||
{
|
||||
gv_FlmSysData.uiFileOpenFlags =
|
||||
FLM_IO_RDWR | FLM_IO_SH_DENYNONE;
|
||||
}
|
||||
|
||||
gv_FlmSysData.uiFileCreateFlags =
|
||||
gv_FlmSysData.uiFileOpenFlags | FLM_IO_EXCL | FLM_IO_CREATE_DIR;
|
||||
}
|
||||
|
||||
f_mutexUnlock( gv_FlmSysData.hShareMutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
case FLM_CACHE_LIMIT:
|
||||
{
|
||||
@@ -1621,8 +1596,7 @@ Desc : Gets configured shared attributes.
|
||||
****************************************************************************/
|
||||
FLMEXP RCODE FLMAPI FlmGetConfig(
|
||||
eFlmConfigTypes eConfigType,
|
||||
void * Value1
|
||||
)
|
||||
void * Value1)
|
||||
{
|
||||
RCODE rc = FERR_OK;
|
||||
|
||||
@@ -1652,11 +1626,31 @@ FLMEXP RCODE FLMAPI FlmGetConfig(
|
||||
break;
|
||||
|
||||
case FLM_OPEN_FILES:
|
||||
{
|
||||
*((FLMUINT *)Value1) = f_getOpenFileCount();
|
||||
break;
|
||||
}
|
||||
|
||||
case FLM_OPEN_THRESHOLD:
|
||||
*((FLMUINT *)Value1) = gv_FlmSysData.pFileHdlCache->getOpenThreshold();
|
||||
break;
|
||||
|
||||
case FLM_DIRECT_IO_STATE:
|
||||
{
|
||||
f_mutexLock( gv_FlmSysData.hShareMutex);
|
||||
|
||||
if( gv_FlmSysData.uiFileOpenFlags & FLM_IO_DIRECT)
|
||||
{
|
||||
*((FLMBOOL *)Value1) = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*((FLMBOOL *)Value1) = FALSE;
|
||||
}
|
||||
|
||||
f_mutexUnlock( gv_FlmSysData.hShareMutex);
|
||||
}
|
||||
|
||||
case FLM_TMPDIR:
|
||||
f_mutexLock( gv_FlmSysData.hShareMutex);
|
||||
|
||||
@@ -2229,8 +2223,7 @@ Desc: This routine frees a registered event.
|
||||
FSTATIC void flmFreeEvent(
|
||||
FEVENT * pEvent,
|
||||
F_MUTEX hMutex,
|
||||
FEVENT ** ppEventListRV
|
||||
)
|
||||
FEVENT ** ppEventListRV)
|
||||
{
|
||||
f_mutexLock( hMutex);
|
||||
if (pEvent->pPrev)
|
||||
@@ -2335,7 +2328,7 @@ FSTATIC void flmCleanup( void)
|
||||
|
||||
if (gv_FlmSysData.pFileHashTbl)
|
||||
{
|
||||
FBUCKET * pFileHashTbl;
|
||||
F_BUCKET * pFileHashTbl;
|
||||
|
||||
// flmFreeFile expects the global mutex to be locked
|
||||
// IMPORTANT NOTE: pFileHashTbl is ALWAYS allocated
|
||||
@@ -2391,16 +2384,6 @@ FSTATIC void flmCleanup( void)
|
||||
f_mutexDestroy( &gv_FlmSysData.hShareMutex);
|
||||
}
|
||||
|
||||
if (gv_FlmSysData.hFileHdlMutex != F_MUTEX_NULL)
|
||||
{
|
||||
f_mutexDestroy( &gv_FlmSysData.hFileHdlMutex);
|
||||
}
|
||||
|
||||
if (gv_FlmSysData.hServerLockMgrMutex != F_MUTEX_NULL)
|
||||
{
|
||||
f_mutexDestroy( &gv_FlmSysData.hServerLockMgrMutex);
|
||||
}
|
||||
|
||||
if (gv_FlmSysData.HttpConfigParms.hMutex != F_MUTEX_NULL)
|
||||
{
|
||||
f_mutexDestroy( &gv_FlmSysData.HttpConfigParms.hMutex);
|
||||
@@ -2446,12 +2429,12 @@ FSTATIC void flmCleanup( void)
|
||||
|
||||
// Free (release) FLAIM's File Shared File System Object.
|
||||
|
||||
if (gv_FlmSysData.pFileSystem)
|
||||
if( gv_FlmSysData.pFileSystem)
|
||||
{
|
||||
gv_FlmSysData.pFileSystem->Release();
|
||||
gv_FlmSysData.pFileSystem = NULL;
|
||||
}
|
||||
|
||||
|
||||
#ifdef FLM_DBG_LOG
|
||||
flmDbgLogExit();
|
||||
#endif
|
||||
@@ -2472,6 +2455,14 @@ FSTATIC void flmCleanup( void)
|
||||
gv_FlmSysData.pThreadMgr = NULL;
|
||||
}
|
||||
|
||||
// Release the file handle cache
|
||||
|
||||
if( gv_FlmSysData.pFileHdlCache)
|
||||
{
|
||||
gv_FlmSysData.pFileHdlCache->Release();
|
||||
gv_FlmSysData.pFileHdlCache = NULL;
|
||||
}
|
||||
|
||||
// Release the slab manager
|
||||
|
||||
if( gv_FlmSysData.pSlabManager)
|
||||
@@ -2584,7 +2575,7 @@ RCODE flmLinkFileToBucket(
|
||||
{
|
||||
RCODE rc = FERR_OK;
|
||||
FFILE * pTmpFile;
|
||||
FBUCKET * pBucket;
|
||||
F_BUCKET * pBucket;
|
||||
FLMUINT uiBucket;
|
||||
char szDbPathStr[ F_PATH_MAX_SIZE];
|
||||
|
||||
@@ -2600,16 +2591,19 @@ RCODE flmLinkFileToBucket(
|
||||
|
||||
uiBucket = f_strHashBucket( szDbPathStr, pBucket, FILE_HASH_ENTRIES);
|
||||
pBucket = &pBucket [uiBucket];
|
||||
|
||||
if (pBucket->pFirstInBucket)
|
||||
{
|
||||
pTmpFile = (FFILE *)pBucket->pFirstInBucket;
|
||||
pTmpFile->pPrev = pFile;
|
||||
}
|
||||
|
||||
pFile->uiBucket = uiBucket;
|
||||
pFile->pPrev = (FFILE *)NULL;
|
||||
pFile->pNext = (FFILE *)pBucket->pFirstInBucket;
|
||||
pBucket->pFirstInBucket = pFile;
|
||||
|
||||
gv_FlmSysData.uiOpenFFiles++;
|
||||
|
||||
Exit:
|
||||
|
||||
return( rc);
|
||||
@@ -2622,9 +2616,7 @@ Desc: This routine unlinks an FFILE structure from its name hash bucket.
|
||||
locked.
|
||||
****************************************************************************/
|
||||
FSTATIC void flmUnlinkFileFromBucket(
|
||||
FFILE * pFile /* Pointer to file that is to be unlinked from
|
||||
its name hash bucket. */
|
||||
)
|
||||
FFILE * pFile)
|
||||
{
|
||||
if (pFile->uiBucket != 0xFFFF)
|
||||
{
|
||||
@@ -2642,6 +2634,9 @@ FSTATIC void flmUnlinkFileFromBucket(
|
||||
}
|
||||
pFile->uiBucket = 0xFFFF;
|
||||
}
|
||||
|
||||
flmAssert( gv_FlmSysData.uiOpenFFiles);
|
||||
gv_FlmSysData.uiOpenFFiles--;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -2777,6 +2772,9 @@ void flmCheckNUStructs(
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gv_FlmSysData.pFileHdlCache->closeUnusedFiles(
|
||||
FLM_TIMER_UNITS_TO_SECS( gv_FlmSysData.uiMaxUnusedTime));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -2785,14 +2783,10 @@ Desc: This routine unlinks an FDICT structure from its FFILE structure and
|
||||
NOTE: This routine assumes that the global mutex is locked.
|
||||
****************************************************************************/
|
||||
void flmUnlinkDict(
|
||||
FDICT * pDict /* FDICT that is to be unlinked from its FFFILE
|
||||
structure. */
|
||||
)
|
||||
FDICT * pDict)
|
||||
{
|
||||
/*
|
||||
Now unlink the local dictionary from its file - if it is connected
|
||||
to one.
|
||||
*/
|
||||
// Now unlink the local dictionary from its file - if it is connected
|
||||
// to one.
|
||||
|
||||
if (pDict->pFile)
|
||||
{
|
||||
@@ -2912,7 +2906,7 @@ Desc: This routine functions as a thread. It monitors open files and
|
||||
frees up files which have been closed longer than the maximum
|
||||
close time.
|
||||
****************************************************************************/
|
||||
RCODE flmSystemMonitor(
|
||||
RCODE FLMAPI flmSystemMonitor(
|
||||
IF_Thread * pThread)
|
||||
{
|
||||
FLMUINT uiLastUnusedCleanupTime = 0;
|
||||
@@ -3381,7 +3375,7 @@ RCODE F_Session::setupSession(
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if( RC_BAD( rc = m_pDbTable->setupHashTable( FALSE, 16)))
|
||||
if( RC_BAD( rc = m_pDbTable->setupHashTable( FALSE, 16, 0)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
@@ -3403,7 +3397,7 @@ RCODE F_Session::addDbHandle(
|
||||
{
|
||||
RCODE rc = FERR_OK;
|
||||
F_SessionDb * pSessionDb = NULL;
|
||||
void * pvKey;
|
||||
const void * pvKey;
|
||||
FLMUINT uiKeyLen;
|
||||
|
||||
if( (pSessionDb = f_new F_SessionDb) == NULL)
|
||||
@@ -3424,7 +3418,9 @@ RCODE F_Session::addDbHandle(
|
||||
|
||||
if( pucKey)
|
||||
{
|
||||
pvKey = pSessionDb->getKey( &uiKeyLen);
|
||||
pvKey = pSessionDb->getKey();
|
||||
uiKeyLen = pSessionDb->getKeyLength();
|
||||
|
||||
flmAssert( uiKeyLen == F_SESSION_DB_KEY_LEN);
|
||||
f_memcpy( pucKey, (FLMBYTE *)pvKey, uiKeyLen);
|
||||
}
|
||||
@@ -3538,7 +3534,7 @@ void F_Session::releaseFileResources(
|
||||
pNextObject->AddRef();
|
||||
}
|
||||
|
||||
if( pObject->objectType() == HASH_DB_OBJ)
|
||||
if( pObject->getObjectType() == HASH_DB_OBJ)
|
||||
{
|
||||
pSessionDb = (F_SessionDb *)pObject;
|
||||
|
||||
@@ -3733,16 +3729,19 @@ void F_Session::unlockSession( void)
|
||||
/****************************************************************************
|
||||
Desc: Gets the session object's hash key
|
||||
****************************************************************************/
|
||||
void * F_Session::getKey(
|
||||
FLMUINT * puiKeyLen)
|
||||
const void * FLMAPI F_Session::getKey( void)
|
||||
{
|
||||
if( puiKeyLen)
|
||||
{
|
||||
*puiKeyLen = (FLMUINT)sizeof( m_ucKey);
|
||||
}
|
||||
return( (void *)(&m_ucKey[ 0]));
|
||||
return( m_ucKey);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc:
|
||||
****************************************************************************/
|
||||
FLMUINT FLMAPI F_Session::getKeyLength( void)
|
||||
{
|
||||
return( sizeof( m_ucKey));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Adds a reference to the session object. The mutex is locked prior
|
||||
to incrementing the count since multiple threads are allowed to
|
||||
@@ -3826,7 +3825,7 @@ void F_SessionMgr::releaseFileResources(
|
||||
|
||||
while( pObject)
|
||||
{
|
||||
flmAssert( pObject->objectType() == HASH_SESSION_OBJ);
|
||||
flmAssert( pObject->getObjectType() == HASH_SESSION_OBJ);
|
||||
|
||||
pSession = (F_Session *)pObject;
|
||||
if( (pObject = pObject->getNextInGlobal()) != NULL)
|
||||
@@ -3876,7 +3875,7 @@ void F_SessionMgr::shutdownSessions()
|
||||
|
||||
while( pObject)
|
||||
{
|
||||
flmAssert( pObject->objectType() == HASH_SESSION_OBJ);
|
||||
flmAssert( pObject->getObjectType() == HASH_SESSION_OBJ);
|
||||
|
||||
pSession = (F_Session *)pObject;
|
||||
if( (pObject = pObject->getNextInGlobal()) != NULL)
|
||||
@@ -3926,7 +3925,7 @@ RCODE F_SessionMgr::setupSessionMgr( void)
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if( RC_BAD( rc = m_pSessionTable->setupHashTable( FALSE, 128)))
|
||||
if( RC_BAD( rc = m_pSessionTable->setupHashTable( FALSE, 128, 0)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
@@ -4094,7 +4093,7 @@ void F_SessionMgr::timeoutInactiveSessions(
|
||||
|
||||
while( pObject)
|
||||
{
|
||||
flmAssert( pObject->objectType() == HASH_SESSION_OBJ);
|
||||
flmAssert( pObject->getObjectType() == HASH_SESSION_OBJ);
|
||||
|
||||
pSession = (F_Session *)pObject;
|
||||
if( (pObject = pObject->getNextInGlobal()) != NULL)
|
||||
@@ -4125,444 +4124,6 @@ Exit:
|
||||
f_mutexUnlock( m_hMutex);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Constructor
|
||||
****************************************************************************/
|
||||
F_HashTable::F_HashTable()
|
||||
{
|
||||
m_hMutex = F_MUTEX_NULL;
|
||||
m_pGlobalList = NULL;
|
||||
m_ppHashTable = NULL;
|
||||
m_uiBuckets = 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Destructor
|
||||
****************************************************************************/
|
||||
F_HashTable::~F_HashTable()
|
||||
{
|
||||
F_HashObject * pCur;
|
||||
F_HashObject * pNext;
|
||||
|
||||
pCur = m_pGlobalList;
|
||||
while( pCur)
|
||||
{
|
||||
pNext = pCur->m_pNextInGlobal;
|
||||
unlinkObject( pCur);
|
||||
pCur->Release();
|
||||
pCur = pNext;
|
||||
}
|
||||
|
||||
if( m_ppHashTable)
|
||||
{
|
||||
f_free( &m_ppHashTable);
|
||||
}
|
||||
|
||||
if( m_hMutex != F_MUTEX_NULL)
|
||||
{
|
||||
f_mutexDestroy( &m_hMutex);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Configures the hash table prior to first use
|
||||
****************************************************************************/
|
||||
RCODE F_HashTable::setupHashTable(
|
||||
FLMBOOL bMultithreaded,
|
||||
FLMUINT uiNumBuckets)
|
||||
{
|
||||
RCODE rc = FERR_OK;
|
||||
|
||||
flmAssert( uiNumBuckets);
|
||||
|
||||
// Create the hash table
|
||||
|
||||
if( RC_BAD( rc = f_alloc(
|
||||
sizeof( F_HashObject *) * uiNumBuckets, &m_ppHashTable)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
m_uiBuckets = uiNumBuckets;
|
||||
f_memset( m_ppHashTable, 0, sizeof( F_HashObject *) * uiNumBuckets);
|
||||
|
||||
if( bMultithreaded)
|
||||
{
|
||||
// Initialize the mutex
|
||||
|
||||
if( RC_BAD( rc = f_mutexCreate( &m_hMutex)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Retrieves an object from the hash table with the specified key.
|
||||
This routine assumes the table's mutex has already been locked.
|
||||
A reference IS NOT added to the object for the caller.
|
||||
****************************************************************************/
|
||||
RCODE F_HashTable::findObject(
|
||||
void * pvKey,
|
||||
FLMUINT uiKeyLen,
|
||||
F_HashObject ** ppObject)
|
||||
{
|
||||
F_HashObject * pObject = NULL;
|
||||
FLMUINT uiBucket;
|
||||
FLMUINT32 ui32CRC = 0;
|
||||
RCODE rc = FERR_OK;
|
||||
|
||||
*ppObject = NULL;
|
||||
|
||||
// Calculate the hash bucket and mutex offset
|
||||
|
||||
uiBucket = getHashBucket( pvKey, uiKeyLen, &ui32CRC);
|
||||
|
||||
// Search the bucket for an object with a matching
|
||||
// key.
|
||||
|
||||
pObject = m_ppHashTable[ uiBucket];
|
||||
while( pObject)
|
||||
{
|
||||
if( pObject->getKeyCRC() == ui32CRC)
|
||||
{
|
||||
void * pvTmpKey;
|
||||
FLMUINT uiTmpKeyLen;
|
||||
|
||||
pvTmpKey = pObject->getKey( &uiTmpKeyLen);
|
||||
if( uiTmpKeyLen == uiKeyLen &&
|
||||
f_memcmp( pvTmpKey, pvKey, uiKeyLen) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
pObject = pObject->m_pNextInBucket;
|
||||
}
|
||||
|
||||
if( !pObject)
|
||||
{
|
||||
rc = RC_SET( FERR_NOT_FOUND);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
*ppObject = pObject;
|
||||
|
||||
Exit:
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Adds an object to the hash table
|
||||
****************************************************************************/
|
||||
RCODE F_HashTable::addObject(
|
||||
F_HashObject * pObject)
|
||||
{
|
||||
FLMUINT uiBucket;
|
||||
F_HashObject * pTmp;
|
||||
void * pvKey;
|
||||
FLMUINT uiKeyLen;
|
||||
FLMUINT32 ui32CRC;
|
||||
FLMBOOL bMutexLocked = FALSE;
|
||||
RCODE rc = FERR_OK;
|
||||
|
||||
// Calculate and set the objects hash bucket
|
||||
|
||||
flmAssert( pObject->getHashBucket() == F_INVALID_HASH_BUCKET);
|
||||
|
||||
pvKey = pObject->getKey( &uiKeyLen);
|
||||
flmAssert( uiKeyLen);
|
||||
|
||||
uiBucket = getHashBucket( pvKey, uiKeyLen, &ui32CRC);
|
||||
pObject->setKeyCRC( ui32CRC);
|
||||
|
||||
// Lock the mutex
|
||||
|
||||
if( m_hMutex != F_MUTEX_NULL)
|
||||
{
|
||||
f_mutexLock( m_hMutex);
|
||||
bMutexLocked = TRUE;
|
||||
}
|
||||
|
||||
// Make sure the object doesn't already exist
|
||||
|
||||
if( RC_BAD( rc = findObject( pvKey, uiKeyLen, &pTmp)))
|
||||
{
|
||||
if( rc != FERR_NOT_FOUND)
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
rc = FERR_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
flmAssert( 0);
|
||||
rc = RC_SET( FERR_EXISTS);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Add a reference to the object
|
||||
|
||||
pObject->AddRef();
|
||||
|
||||
// Link the object into the appropriate lists
|
||||
|
||||
linkObject( pObject, uiBucket);
|
||||
|
||||
Exit:
|
||||
|
||||
// Unlock the mutex
|
||||
|
||||
if( bMutexLocked)
|
||||
{
|
||||
f_mutexUnlock( m_hMutex);
|
||||
}
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Returns the next object in the linked list of objects in the hash
|
||||
table. If *ppObject == NULL, the first object will be returned.
|
||||
****************************************************************************/
|
||||
RCODE F_HashTable::getNextObjectInGlobal(
|
||||
F_HashObject ** ppObject)
|
||||
{
|
||||
FLMBOOL bMutexLocked = FALSE;
|
||||
F_HashObject * pOldObj;
|
||||
RCODE rc = FERR_OK;
|
||||
|
||||
// Lock the mutex
|
||||
|
||||
if( m_hMutex != F_MUTEX_NULL)
|
||||
{
|
||||
f_mutexLock( m_hMutex);
|
||||
bMutexLocked = TRUE;
|
||||
}
|
||||
|
||||
if( !(*ppObject))
|
||||
{
|
||||
*ppObject = m_pGlobalList;
|
||||
}
|
||||
else
|
||||
{
|
||||
pOldObj = *ppObject;
|
||||
*ppObject = (*ppObject)->m_pNextInGlobal;
|
||||
pOldObj->Release();
|
||||
}
|
||||
|
||||
if( *ppObject == NULL)
|
||||
{
|
||||
rc = RC_SET( FERR_EOF_HIT);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
(*ppObject)->AddRef();
|
||||
|
||||
Exit:
|
||||
|
||||
if( bMutexLocked)
|
||||
{
|
||||
f_mutexUnlock( m_hMutex);
|
||||
}
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Retrieves an object from the hash table with the specified key
|
||||
****************************************************************************/
|
||||
RCODE F_HashTable::getObject(
|
||||
void * pvKey,
|
||||
FLMUINT uiKeyLen,
|
||||
F_HashObject ** ppObject,
|
||||
FLMBOOL bRemove)
|
||||
{
|
||||
F_HashObject * pObject;
|
||||
FLMBOOL bMutexLocked = FALSE;
|
||||
RCODE rc = FERR_OK;
|
||||
|
||||
// Lock the mutex
|
||||
|
||||
if( m_hMutex != F_MUTEX_NULL)
|
||||
{
|
||||
f_mutexLock( m_hMutex);
|
||||
bMutexLocked = TRUE;
|
||||
}
|
||||
|
||||
// Search for an object with a matching key.
|
||||
|
||||
if( RC_BAD( rc = findObject( pvKey, uiKeyLen, &pObject)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if( pObject && bRemove)
|
||||
{
|
||||
unlinkObject( pObject);
|
||||
if( !ppObject)
|
||||
{
|
||||
pObject->Release();
|
||||
pObject = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if( ppObject)
|
||||
{
|
||||
if( !bRemove)
|
||||
{
|
||||
pObject->AddRef();
|
||||
}
|
||||
*ppObject = pObject;
|
||||
pObject = NULL;
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
if( bMutexLocked)
|
||||
{
|
||||
f_mutexUnlock( m_hMutex);
|
||||
}
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Removes an object from the hash table by key
|
||||
****************************************************************************/
|
||||
RCODE F_HashTable::removeObject(
|
||||
void * pvKey,
|
||||
FLMUINT uiKeyLen)
|
||||
{
|
||||
return( getObject( pvKey, uiKeyLen, NULL, TRUE));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Removes an object from the hash table by object pointer
|
||||
****************************************************************************/
|
||||
RCODE F_HashTable::removeObject(
|
||||
F_HashObject * pObject)
|
||||
{
|
||||
FLMUINT uiKeyLen;
|
||||
void * pvKey;
|
||||
|
||||
pvKey = pObject->getKey( &uiKeyLen);
|
||||
return( getObject( pvKey, uiKeyLen, NULL, TRUE));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Calculates the hash bucket of a key and optionally returns the key's
|
||||
CRC.
|
||||
****************************************************************************/
|
||||
FLMUINT F_HashTable::getHashBucket(
|
||||
void * pvKey,
|
||||
FLMUINT uiLen,
|
||||
FLMUINT32 * pui32KeyCRC)
|
||||
{
|
||||
FLMUINT32 ui32CRC = 0;
|
||||
|
||||
f_updateCRC( (FLMBYTE *)pvKey, uiLen, &ui32CRC);
|
||||
if( pui32KeyCRC)
|
||||
{
|
||||
*pui32KeyCRC = ui32CRC;
|
||||
}
|
||||
return( ui32CRC % m_uiBuckets);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Links an object to the global list and also to its bucket
|
||||
Notes: This routine assumes that the bucket's mutex is already locked
|
||||
if the hash table is multi-threaded.
|
||||
****************************************************************************/
|
||||
void F_HashTable::linkObject(
|
||||
F_HashObject * pObject,
|
||||
FLMUINT uiBucket)
|
||||
{
|
||||
flmAssert( uiBucket < m_uiBuckets);
|
||||
flmAssert( pObject->getHashBucket() == F_INVALID_HASH_BUCKET);
|
||||
|
||||
// Set the object's bucket
|
||||
|
||||
pObject->setHashBucket( uiBucket);
|
||||
|
||||
// Link the object to its hash bucket
|
||||
|
||||
pObject->m_pNextInBucket = m_ppHashTable[ uiBucket];
|
||||
if( m_ppHashTable[ uiBucket])
|
||||
{
|
||||
m_ppHashTable[ uiBucket]->m_pPrevInBucket = pObject;
|
||||
}
|
||||
m_ppHashTable[ uiBucket] = pObject;
|
||||
|
||||
// Link to the global list
|
||||
|
||||
pObject->m_pNextInGlobal = m_pGlobalList;
|
||||
if( m_pGlobalList)
|
||||
{
|
||||
m_pGlobalList->m_pPrevInGlobal = pObject;
|
||||
}
|
||||
m_pGlobalList = pObject;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Unlinks an object from its bucket and the global list.
|
||||
Notes: This routine assumes that the bucket's mutex is already locked
|
||||
if the hash table is multi-threaded.
|
||||
****************************************************************************/
|
||||
void F_HashTable::unlinkObject(
|
||||
F_HashObject * pObject)
|
||||
{
|
||||
FLMUINT uiBucket = pObject->getHashBucket();
|
||||
|
||||
// Is the bucket valid?
|
||||
|
||||
flmAssert( uiBucket < m_uiBuckets);
|
||||
|
||||
// Unlink from the hash bucket
|
||||
|
||||
if( pObject->m_pNextInBucket)
|
||||
{
|
||||
pObject->m_pNextInBucket->m_pPrevInBucket = pObject->m_pPrevInBucket;
|
||||
}
|
||||
|
||||
if( pObject->m_pPrevInBucket)
|
||||
{
|
||||
pObject->m_pPrevInBucket->m_pNextInBucket = pObject->m_pNextInBucket;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ppHashTable[ uiBucket] = pObject->m_pNextInBucket;
|
||||
}
|
||||
|
||||
pObject->m_pPrevInBucket = NULL;
|
||||
pObject->m_pNextInBucket = NULL;
|
||||
pObject->setHashBucket( F_INVALID_HASH_BUCKET);
|
||||
|
||||
// Unlink from the global list
|
||||
|
||||
if( pObject->m_pNextInGlobal)
|
||||
{
|
||||
pObject->m_pNextInGlobal->m_pPrevInGlobal = pObject->m_pPrevInGlobal;
|
||||
}
|
||||
|
||||
if( pObject->m_pPrevInGlobal)
|
||||
{
|
||||
pObject->m_pPrevInGlobal->m_pNextInGlobal = pObject->m_pNextInGlobal;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pGlobalList = pObject->m_pNextInGlobal;
|
||||
}
|
||||
|
||||
pObject->m_pPrevInGlobal = NULL;
|
||||
pObject->m_pNextInGlobal = NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Constructor
|
||||
****************************************************************************/
|
||||
@@ -4615,14 +4176,17 @@ RCODE F_SessionDb::setupSessionDb(
|
||||
/****************************************************************************
|
||||
Desc: Returns the key and key length of a database object
|
||||
****************************************************************************/
|
||||
void * F_SessionDb::getKey(
|
||||
FLMUINT * puiKeyLen)
|
||||
const void * FLMAPI F_SessionDb::getKey( void)
|
||||
{
|
||||
if( puiKeyLen)
|
||||
{
|
||||
*puiKeyLen = (FLMUINT)sizeof( m_ucKey);
|
||||
}
|
||||
return( (void *)(&m_ucKey[ 0]));
|
||||
return( m_ucKey);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Returns the key and key length of a database object
|
||||
****************************************************************************/
|
||||
FLMUINT FLMAPI F_SessionDb::getKeyLength( void)
|
||||
{
|
||||
return( sizeof( m_ucKey));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -4763,6 +4327,16 @@ FLMUINT FLMAPI F_SuperFileClient::getFileOffset(
|
||||
return( FSGetFileOffset( uiBlockAddr));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc:
|
||||
****************************************************************************/
|
||||
FLMUINT FLMAPI F_SuperFileClient::getBlockAddress(
|
||||
FLMUINT uiFileNumber,
|
||||
FLMUINT uiFileOffset)
|
||||
{
|
||||
return( FSBlkAddress( uiFileNumber, uiFileOffset));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc:
|
||||
****************************************************************************/
|
||||
|
||||
Reference in New Issue
Block a user