RCODE CSPDB::registerFieldArray(HFDB hFlaim, CS_FIELD_DEF *fieldTable, FLMINT count) { RCODE rc = FERR_OK; int i; // Begin a flaim transaction. rc = FlmDbTransBegin(hFlaim, FLM_UPDATE_TRANS, 255); if (RC_OK(rc)) { for (i = 0; i < count; ++i) { FLMUINT fieldId = fieldTable[i].id; rc = RegisterField(hFlaim, fieldTable[i].name, CSPTypeToFlaimType(fieldTable[i].type), &fieldId); if (RC_BAD(rc)) { break; } } if (RC_OK(rc)) { FlmDbTransCommit(hFlaim); } else { FlmDbTransAbort(hFlaim); } } return (rc); } // CSPDB::registerFieldArray()
RCODE CSPDB::registerIndexArray(HFDB hFlaim, CS_FIELD_DEF *indexTable, FLMINT count) { RCODE rc = FERR_OK; int i; rc = FlmDbTransBegin(hFlaim, FLM_UPDATE_TRANS, 255); if (RC_OK(rc)) { for (i = 0; i < count; ++i) { rc = AddIndex(hFlaim, indexTable[i].name, indexTable[i].id); if (RC_BAD(rc)) { break; } } if (RC_OK(rc)) { rc = FlmDbTransCommit(hFlaim); } else { rc = FlmDbTransAbort(hFlaim); } } return (rc); } // CSPDB::registerIndexArray()
/** * Method to connect to the store. * * @param storePath The full path to the store to connect to. * @return HRESULT */ RCODE CSPStore::OpenStore( char *pStorePath) { RCODE rc = FERR_OK; char* pDbPath; // Convert the path to current code page and then create the data base. pDbPath = setupDbPath(pStorePath); if (pDbPath) { rc = FlmDbOpen( pDbPath, NULL, NULL, //default pRflDir 0, NULL, &m_hFlaim); if (RC_OK(rc)) { // Now setup the store. rc = m_pDB->initializeDB(m_hFlaim, false); if (RC_OK(rc)) { m_connected = true; } } } return (rc); } // CSPStore::OpenStore()
RCODE CSPDB::initializeDB(HFDB hFlaim, FLMBOOL created) { RCODE rc = FERR_OK; if (!m_flaimInitialized) { SetupNameTable(hFlaim); if (RC_OK(rc)) { if (created) { // Register the well know properties rc = registerFieldArray(hFlaim, propertyArray, sizeof(propertyArray) / sizeof(CS_FIELD_DEF)); if (RC_OK(rc)) { // Add the indexes rc = registerIndexArray(hFlaim, propertyArray, sizeof(propertyArray) / sizeof(CS_FIELD_DEF)); } } m_flaimInitialized = true; } } return (rc); } // CSPDB::initializeDB()
/******************************************************************** 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: ****************************************************************************/ RCODE FLMAPI f_rwlockAcquire( F_RWLOCK hReadWriteLock, F_SEM hSem, FLMBOOL bWriter) { RCODE rc = NE_FLM_OK; F_RWLOCK_IMP * pReadWriteLock = (F_RWLOCK_IMP *)hReadWriteLock; FLMBOOL bMutexLocked = FALSE; f_mutexLock( pReadWriteLock->hMutex); bMutexLocked = TRUE; if( bWriter) { if( pReadWriteLock->iRefCnt != 0) { rc = f_notifyWait( pReadWriteLock->hMutex, hSem, (void *)((FLMINT)bWriter), &pReadWriteLock->pNotifyList); } if( RC_OK( rc)) { f_assert( !pReadWriteLock->iRefCnt); pReadWriteLock->iRefCnt = -1; pReadWriteLock->uiWriteThread = f_threadId(); } } else { if( pReadWriteLock->iRefCnt < 0 || pReadWriteLock->pNotifyList) { rc = f_notifyWait( pReadWriteLock->hMutex, hSem, (void *)((FLMINT)bWriter), &pReadWriteLock->pNotifyList); } if( RC_OK( rc)) { pReadWriteLock->iRefCnt++; } } f_assert( RC_BAD( rc) || pReadWriteLock->iRefCnt); if( bMutexLocked) { f_mutexUnlock( pReadWriteLock->hMutex); } return( rc); }
/**************************************************************************** Desc: ****************************************************************************/ void F_IOBuffer::notifyComplete( RCODE completionRc) { f_assert( m_bPending); m_bPending = FALSE; m_bCompleted = TRUE; m_completionRc = completionRc; m_uiEndTime = FLM_GET_TIMER(); m_uiElapsedTime = FLM_TIMER_UNITS_TO_MILLI( FLM_ELAPSED_TIME( m_uiEndTime, m_uiStartTime)); if( m_fnCompletion) { m_fnCompletion( this, m_pvData); m_fnCompletion = NULL; m_pvData = NULL; } if( m_pBufferMgr) { f_assert( m_eList == MGR_LIST_PENDING); f_mutexLock( m_pBufferMgr->m_hMutex); m_pBufferMgr->unlinkFromList( this); m_pBufferMgr->linkToList( &m_pBufferMgr->m_pFirstUsed, this); if( RC_OK( m_pBufferMgr->m_completionRc) && RC_BAD( completionRc)) { m_pBufferMgr->m_completionRc = completionRc; } f_mutexUnlock( m_pBufferMgr->m_hMutex); } }
/**************************************************************************** Desc: Event callback *****************************************************************************/ void IX_Event::catchEvent( eEventType eEvent, IF_Db * pDb, FLMUINT, // uiThreadId, FLMUINT64, // ui64TransID, FLMUINT uiIndexOrCollection, FLMUINT64 ui64NodeId, RCODE // rc ) { XFLM_INDEX_STATUS ixStatus; FLMUINT uiGMT; if (eEvent == XFLM_EVENT_INDEXING_PROGRESS && !ui64NodeId && pDb) { if (RC_OK( ((F_Db *)pDb)->indexStatus( uiIndexOrCollection, &ixStatus))) { f_timeGetSeconds( &uiGMT ); f_mutexLock( m_pDispInfo->hScreenMutex); FTXWinPrintf( m_pDispInfo->pLogWin, "Index %u came on-line. Elapsed time = %u second(s)\n", uiIndexOrCollection, uiGMT - (FLMUINT)ixStatus.ui32StartTime); f_mutexUnlock( m_pDispInfo->hScreenMutex); } } }
RCODE CSPDB::RegisterField(HFDB hFlaim, FLMUNICODE *pFieldName, FLMUINT flmType, FLMUINT* pFieldId) { RCODE rc = FERR_OK; FlmRecord *pRec = NULL; void *pvField = 0; pRec = new FlmRecord(); if (pRec != NULL) { rc = pRec->insertLast(0, FLM_FIELD_TAG, FLM_TEXT_TYPE, &pvField); if (RC_OK(rc)) { rc = pRec->setUnicode(pvField, (FLMUNICODE*)pFieldName); if (RC_OK(rc)) { rc = pRec->insert(pvField, INSERT_LAST_CHILD, FLM_TYPE_TAG, FLM_TEXT_TYPE, &pvField); if (RC_OK(rc)) { if (flmType != FLM_UNDEFINED_TYPE) { rc = pRec->setUnicode(pvField, (FLMUNICODE*)cs_flaim_type_name[flmType]); if (RC_OK(rc)) { rc = FlmRecordAdd(hFlaim, FLM_DICT_CONTAINER, pFieldId, pRec, 0); if (RC_OK(rc)) { rc = m_NameTable.addTag((FLMUNICODE*)pFieldName, 0, *pFieldId, 0, 0, TRUE); } } } else { rc = FERR_BAD_FIELD_TYPE; } } } } pRec->Release(); } else { rc = FERR_MEM; } return (rc); } // CSPDB::registerField()
/**************************************************************************** Desc: Adds a field path to the selection criteria of a given cursor. A field path is the fully qualified context of a field within a record. ****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorAddFieldPath( HFCURSOR hCursor, FLMUINT * puiFldPath, FLMUINT uiFlags) { RCODE rc = FERR_OK; FQNODE * pTmpQNode; CURSOR * pCursor = (CURSOR *)hCursor; if (!pCursor) { flmAssert( 0); rc = RC_SET( FERR_INVALID_PARM); goto Exit; } if (RC_BAD( rc = pCursor->rc)) { goto Exit; } // If a read operation has already been performed on this query, no // selection criteria may be added. if (pCursor->bOptimized) { rc = RC_SET( FERR_ILLEGAL_OP); goto Exit; } if (!( pCursor->QTInfo.uiExpecting & FLM_Q_OPERAND)) { rc = RC_SET( FERR_CURSOR_SYNTAX); goto Exit; } if (RC_OK( rc = flmCurMakeQNode( &pCursor->QueryPool, FLM_FLD_PATH, puiFldPath, 0, pCursor->QTInfo.uiFlags, &pTmpQNode))) { pTmpQNode->pQAtom->uiFlags |= uiFlags; pCursor->QTInfo.pCurAtomNode = pTmpQNode; if (pCursor->QTInfo.pCurOpNode) { flmCurLinkLastChild( pCursor->QTInfo.pCurOpNode, pCursor->QTInfo.pCurAtomNode); } pCursor->QTInfo.uiExpecting &= ~FLM_Q_OPERAND; pCursor->QTInfo.uiExpecting |= FLM_Q_OPERATOR; } Exit: if (pCursor) { pCursor->rc = rc; } return( rc); }
RCODE CSPStore::CreateStore(char *pStorePath) { RCODE rc = FERR_OK; char* pDbPath; // Create the path to the database. pDbPath = setupDbPath(pStorePath); if (pDbPath) { // Create the New Store. rc = FlmDbCreate( pDbPath, NULL, NULL, //default pRflDir NULL, NULL, NULL, &m_hFlaim); if (RC_OK(rc)) { // Now setup the store. rc = m_pDB->initializeDB(m_hFlaim, true); if (RC_OK(rc)) { m_connected = true; } else { FlmDbRemove( pDbPath, NULL, NULL, true); } } } return (rc); } // CSPStore::CreateStore()
CSPDB::CSPDB() : m_flaimInitialized(false) { RCODE rc; // Make sure the Flaim library has been initialized. rc = FlmStartup(); if (RC_OK(rc)) { m_RefCount = 1; } }
/**************************************************************************** Desc: ****************************************************************************/ FSTATIC void _flmDbgLogFlush( void) { FLMUINT uiBytesToWrite; FLMUINT uiBytesWritten; char * pszBufPtr = g_pszLogBuf; FLMUINT uiTotalToWrite = g_uiLogBufOffset; RCODE rc = NE_SFLM_OK; FLMUINT uiBufferSize = DBG_LOG_BUFFER_SIZE + 1024; while( uiTotalToWrite) { if( uiTotalToWrite > 0xFE00) { uiBytesToWrite = 0xFE00; } else { uiBytesToWrite = uiTotalToWrite; } if( RC_BAD( rc = g_pLogFile->SectorWrite( g_uiLogFileOffset, uiBytesToWrite, pszBufPtr, uiBufferSize, NULL, &uiBytesWritten, FALSE))) { goto Exit; } flmAssert( uiBytesToWrite == uiBytesWritten); g_uiLogFileOffset += uiBytesWritten; pszBufPtr += uiBytesWritten; uiBufferSize -= uiBytesWritten; uiTotalToWrite -= uiBytesWritten; } if (g_uiLogBufOffset & 0x1FF) { if (g_uiLogBufOffset > 512) { f_memcpy( g_pszLogBuf, &g_pszLogBuf [g_uiLogBufOffset & 0xFFFFFE00], 512); g_uiLogBufOffset &= 0x1FF; } g_uiLogFileOffset -= g_uiLogBufOffset; } else { g_uiLogBufOffset = 0; } Exit: flmAssert( RC_OK( rc)); }
/**************************************************************************** Desc: ****************************************************************************/ FINLINE void FTKAPI F_DirHdl::currentItemPath( char * pszPath) { if( RC_OK( m_rc)) { f_strcpy( pszPath, m_szDirectoryPath); #ifdef FLM_RING_ZERO_NLM f_pathAppend( pszPath, currentItemName()); #else f_pathAppend( pszPath, m_szFileName); #endif } }
/**************************************************************************** Desc: ****************************************************************************/ const char * FTKAPI F_DirHdl::currentItemName( void) { const char * pszName = NULL; #ifndef FLM_RING_ZERO_NLM if( RC_OK( m_rc)) { pszName = m_szFileName; } #else FLMUINT uiLength; if( RC_OK( m_rc)) { if( !m_FindData.pCurrentItem) { return( NULL); } uiLength = sizeof( m_FindData.ucTempBuffer) - 1; if( m_FindData.pCurrentItem->DFileNameLength < uiLength) { uiLength = m_FindData.pCurrentItem->DFileNameLength; } f_strncpy( m_FindData.ucTempBuffer, (const char *)m_FindData.pCurrentItem->DFileName, uiLength); m_FindData.ucTempBuffer[ uiLength] = 0; pszName = m_FindData.ucTempBuffer; } #endif return( pszName); }
/**************************************************************************** Desc: Aborts an active transaction. ****************************************************************************/ FLMEXP RCODE FLMAPI FlmDbTransAbort( HFDB hDb) { RCODE rc; FDB * pDb = (FDB *)hDb; FLMBOOL bIgnore; if (IsInCSMode( hDb)) { fdbInitCS( pDb); FCL_WIRE Wire( pDb->pCSContext, pDb); if (!pDb->pCSContext->bConnectionGood) { rc = RC_SET( FERR_BAD_SERVER_CONNECTION); } else { rc = Wire.doTransOp( FCS_OP_TRANSACTION_ABORT, 0, 0, 0); } goto Exit; } if (RC_BAD( rc = fdbInit( pDb, FLM_NO_TRANS, FDB_TRANS_GOING_OK | FDB_CLOSING_OK, 0, &bIgnore))) { goto Exit; } // If there is an invisible transaction going, it should not be // abortable by an application. if ((pDb->uiTransType == FLM_NO_TRANS) || (pDb->uiFlags & FDB_INVISIBLE_TRANS)) { rc = RC_SET( FERR_NO_TRANS_ACTIVE); goto Exit; } rc = flmAbortDbTrans( pDb); Exit: if( RC_OK( rc)) { rc = flmCheckDatabaseState( pDb); } flmExit( FLM_DB_TRANS_ABORT, pDb, rc); return( rc); }
/**************************************************************************** Desc: ****************************************************************************/ RCODE F_DbCheck::createAndOpenResultSetDb( void) { RCODE rc = NE_XFLM_OK; XFLM_CREATE_OPTS createOpts; if (m_pResultSetDb) { if (RC_BAD( rc = closeAndDeleteResultSetDb())) { goto Exit; } } f_memset( &createOpts, 0, sizeof( XFLM_CREATE_OPTS)); for (;;) { // Generate a random file name f_sprintf( m_szResultSetDibName, "%d.db", (int)m_pRandGen->getUINT32( 100, 20000)); if (RC_OK( rc = gv_pXFlmDbSystem->dbCreate( m_szResultSetDibName, NULL, NULL, NULL, NULL, &createOpts, TRUE, (IF_Db **)&m_pResultSetDb))) { break; } if (rc == NE_XFLM_FILE_EXISTS || rc == NE_FLM_IO_ACCESS_DENIED) { rc = NE_XFLM_OK; } else { goto Exit; } } // Shouldn't have an RFL object - don't want anything // logged by this database. flmAssert( !m_pResultSetDb->getDatabase()->m_pRfl); Exit: return rc; }
/**************************************************************************** Desc: ****************************************************************************/ RCODE FTKAPI F_IOBufferMgr::waitForAllPendingIO( void) { RCODE rc = NE_FLM_OK; RCODE tmpRc; F_IOBuffer * pBuf; FLMBOOL bMutexLocked = FALSE; f_mutexLock( m_hMutex); bMutexLocked = TRUE; while( (pBuf = m_pFirstPending) != NULL) { pBuf->AddRef(); f_mutexUnlock( m_hMutex); bMutexLocked = FALSE; if( RC_BAD( tmpRc = pBuf->waitToComplete())) { if( RC_OK( m_completionRc)) { f_mutexLock( m_hMutex); bMutexLocked = TRUE; m_completionRc = tmpRc; } } if( !bMutexLocked) { f_mutexLock( m_hMutex); bMutexLocked = TRUE; } pBuf->Release( TRUE); pBuf = NULL; } rc = m_completionRc; m_completionRc = NE_FLM_OK; if( bMutexLocked) { f_mutexUnlock( m_hMutex); } return( rc); }
/**************************************************************************** Desc: ****************************************************************************/ RCODE ArgList::expandFileArgs( const char * pszFilename) { RCODE rc = FERR_OK; char token[64]; IF_FileHdl * pFileHdl = NULL; if( RC_BAD( rc = gv_FlmSysData.pFileSystem->openFile( pszFilename, FLM_IO_RDWR, &pFileHdl))) { goto Exit; } while( RC_OK( rc = getTokenFromFile(token, pFileHdl))) { if( token[0] == '@') { if( RC_BAD( rc = expandFileArgs( &token[1]))) { goto Exit; } } else { flmAssert(*token); if( RC_BAD( rc = addArg( token))) { goto Exit; } } } if( rc == FERR_IO_END_OF_FILE) { rc = FERR_OK; } Exit: if( pFileHdl) { pFileHdl->Release(); } return( rc); }
/**************************************************************************** Desc: This code is common to all of the SetParam() functions ****************************************************************************/ RCODE F_IniFile::setParamCommon( INI_LINE ** ppLine, const char * pszParamName) { RCODE rc = NE_FLM_OK; INI_LINE * pLine; if( RC_BAD( rc = m_pool.poolCalloc( sizeof( INI_LINE), (void **)&pLine))) { goto Exit; } if( m_pLastLine) { m_pLastLine->pNext = pLine; } pLine->pPrev = m_pLastLine; m_pLastLine = pLine; if( !m_pFirstLine) { m_pFirstLine = pLine; } if( RC_BAD( rc = m_pool.poolAlloc( f_strlen(pszParamName)+1, (void **)&pLine->pszParamName))) { goto Exit; } f_strcpy( pLine->pszParamName, pszParamName); Exit: if( RC_OK( rc)) { *ppLine = pLine; } return( rc); }
/**************************************************************************** Desc: ****************************************************************************/ RCODE FLMAPI f_rwlockPromote( F_RWLOCK hReadWriteLock, F_SEM hSem) { RCODE rc = NE_FLM_OK; F_RWLOCK_IMP * pReadWriteLock = (F_RWLOCK_IMP *)hReadWriteLock; FLMBOOL bMutexLocked = FALSE; f_mutexLock( pReadWriteLock->hMutex); bMutexLocked = TRUE; if( pReadWriteLock->iRefCnt <= 0) { rc = RC_SET_AND_ASSERT( NE_FLM_ILLEGAL_OP); goto Exit; } pReadWriteLock->iRefCnt--; if( pReadWriteLock->iRefCnt != 0) { rc = f_notifyWait( pReadWriteLock->hMutex, hSem, (void *)TRUE, &pReadWriteLock->pNotifyList); } if( RC_OK( rc)) { f_assert( !pReadWriteLock->iRefCnt); pReadWriteLock->iRefCnt = -1; pReadWriteLock->uiWriteThread = f_threadId(); } Exit: f_assert( RC_BAD( rc) || pReadWriteLock->iRefCnt); if( bMutexLocked) { f_mutexUnlock( pReadWriteLock->hMutex); } return( rc); }
/**************************************************************************** Desc: ****************************************************************************/ FLMUINT64 FTKAPI F_DirHdl::currentItemSize( void) { FLMUINT64 ui64Size = 0; if( RC_OK( m_rc)) { #if defined( FLM_WIN) ui64Size = (((FLMUINT64)m_FindData.findBuffer.nFileSizeHigh) << 32) + m_FindData.findBuffer.nFileSizeLow; #elif defined( FLM_UNIX) || defined ( FLM_LIBC_NLM) ui64Size = m_FindData.FileStat.st_size; #elif defined( FLM_RING_ZERO_NLM) char szTmpPath[ F_PATH_MAX_SIZE]; currentItemPath( szTmpPath); (void)f_getFileSysPtr()->getFileSize( szTmpPath, &ui64Size); #endif } return( ui64Size); }
/**************************************************************************** Desc: ****************************************************************************/ void flmDbgLogInit( void) { char szLogPath[ 256]; RCODE rc = NE_SFLM_OK; flmAssert( g_hDbgLogMutex == F_MUTEX_NULL); // Allocate a buffer for the log if (RC_BAD( rc = f_alloc( DBG_LOG_BUFFER_SIZE + 1024, &g_pszLogBuf))) { goto Exit; } // Create the mutex if (RC_BAD( rc = f_mutexCreate( &g_hDbgLogMutex))) { goto Exit; } // Build the file path #ifdef FLM_NLM f_strcpy( szLogPath, "SYS:\\FLMDBG.LOG"); #else f_sprintf( szLogPath, "FLMDBG.LOG"); #endif // Create the file - truncate if it exists already. if( RC_BAD( rc = gv_SFlmSysData.pFileSystem->Create( szLogPath, XFLM_IO_RDWR | XFLM_IO_SH_DENYNONE | XFLM_IO_DIRECT, &g_pLogFile))) { goto Exit; } Exit: flmAssert( RC_OK( rc)); }
/**************************************************************************** Desc: ****************************************************************************/ XFLXPC RCODE XFLAPI xflaim_DOMNode_hasAttribute( IF_DOMNode * pThisNode, IF_Db * pDb, FLMUINT32 ui32AttrNameId, FLMBOOL * pbHasAttr) { RCODE rc; rc = pThisNode->hasAttribute( pDb, (FLMUINT)ui32AttrNameId, NULL); if (RC_OK( rc)) { *pbHasAttr = TRUE; } else if (rc == NE_XFLM_DOM_NODE_NOT_FOUND) { *pbHasAttr = FALSE; rc = NE_XFLM_OK; } return( rc); }
FlmRecord * CSPStore::FindObject(FLMUNICODE *pId) { RCODE rc = FERR_OK; HFCURSOR cursor = 0; FlmRecord *pRec = NULL; FlmRecord *pRWRec = NULL; FLMUINT fieldId; FLMUINT count; rc = NameToId(CS_Name_GUID, &fieldId); if (RC_OK(rc)) { rc = FlmCursorInit(m_hFlaim, FLM_DATA_CONTAINER, &cursor); if (RC_OK(rc)) { rc = FlmCursorAddField(cursor, fieldId, 0); if (RC_OK(rc)) { rc = FlmCursorAddOp(cursor, FLM_EQ_OP, 0); if (RC_OK(rc)) { rc = FlmCursorAddValue(cursor, FLM_UNICODE_VAL, pId, 0); if (RC_OK(rc)) { rc = FlmCursorRecCount(cursor, &count); if (RC_OK(rc) && count != 0) { rc = FlmCursorNext(cursor, &pRec); if (RC_OK(rc)) { pRWRec = pRec->copy(); pRec->Release(); pRec = NULL; } } } } } FlmCursorFree(&cursor); } } return (pRWRec); } // CSPStore::FindObject()
/*API~*********************************************************************** Area : TRANSACTION Desc : Aborts an active transaction. *END************************************************************************/ RCODE F_Db::transAbort( void) { RCODE rc = NE_XFLM_OK; if (m_eTransType == XFLM_NO_TRANS) { rc = RC_SET( NE_XFLM_NO_TRANS_ACTIVE); goto Exit; } rc = abortTrans(); Exit: if (RC_OK( rc)) { rc = checkState( __FILE__, __LINE__); } return( rc); }
/**************************************************************************** Desc: Thread that will build an index in the background. Caller will create a pDb to use. This pDb must be freed at the conclusion of the routine. ****************************************************************************/ FSTATIC RCODE FLMAPI flmBackgroundIndexBuildThrd( IF_Thread * pThread) { RCODE rc = FERR_OK; IXD * pIxd; F_BKGND_IX * pBackgroundIx = (F_BKGND_IX *)pThread->getParm1(); FLMBOOL bStartedTrans; FLMBOOL bDbInitialized; FLMUINT uiContainerNum; FLMUINT uiFirstDrn; FLMUINT uiIndexNum; FDB * pDb = NULL; FLMBOOL bForcedShutdown = FALSE; FLMBOOL bHitEnd; FINDEX_STATUS savedIxStatus; FlmRecord * pReusableRec = NULL; char szMsg[ 128]; FLMINT iErrorLine = 0; FLMBOOL bLimitedMode = FALSE; pThread->setThreadStatus( FLM_THREAD_STATUS_INITIALIZING); if( (pReusableRec = f_new FlmRecord) != NULL) { if( RC_BAD( pReusableRec->preallocSpace( 512, 1024 * 64))) { pReusableRec->Release(); pReusableRec = NULL; } } Loop_Again: rc = FERR_OK; uiIndexNum = pBackgroundIx->indexStatus.uiIndexNum; flmAssert( pThread->getThreadAppId() == uiIndexNum); bDbInitialized = FALSE; bStartedTrans = FALSE; pDb = NULL; // We could loop forever on flmOpenFile errors, check if we should exit. if( pThread->getShutdownFlag()) { bForcedShutdown = TRUE; goto Exit; } if( RC_BAD( rc = flmOpenFile( pBackgroundIx->pFile, NULL, NULL, NULL, 0, TRUE, NULL, NULL, pBackgroundIx->pFile->pszDbPassword, &pDb))) { // If the file is being closed, this is not an error. if( pBackgroundIx->pFile->uiFlags & DBF_BEING_CLOSED) { bForcedShutdown = TRUE; rc = FERR_OK; } else { iErrorLine = (FLMINT)__LINE__; } goto Exit; } flmAssert( pDb->pSFileHdl); bDbInitialized = TRUE; if (RC_BAD( rc = fdbInit( pDb, FLM_NO_TRANS, 0, 0, &bStartedTrans))) { iErrorLine = (FLMINT)__LINE__; goto Exit; } flmAssert( !bStartedTrans); pDb->uiFlags |= FDB_BACKGROUND_INDEXING; for(;;) { // Set the thread's status pThread->setThreadStatus( FLM_THREAD_STATUS_RUNNING); // See if we should shut down. if( pThread->getShutdownFlag()) { bForcedShutdown = TRUE; break; } // Obtain the file lock flmAssert( !(pDb->uiFlags & FDB_HAS_FILE_LOCK)); if( RC_BAD( rc = pDb->pFile->pFileLockObj->lock( pDb->hWaitSem, TRUE, FLM_NO_TIMEOUT, FLM_BACKGROUND_LOCK_PRIORITY, pDb->pDbStats ? &pDb->pDbStats->LockStats : NULL))) { if( rc == FERR_IO_FILE_LOCK_ERR) { // This would only happen if we were signaled to shut down. // So, it's ok to exit flmAssert( pThread->getShutdownFlag()); bForcedShutdown = TRUE; rc = FERR_OK; } else { iErrorLine = (FLMINT)__LINE__; } goto Exit; } // The lock needs to be marked as implicit so that flmCommitDbTrans // will unlock the file and allow the next update transaction to // begin before all writes are complete. pDb->uiFlags |= (FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_IMPLICIT); // If there are higher priority waiters in the lock queue, // or we are being told to shut down, we want to relinquish. if( pThread->getShutdownFlag() || pDb->pFile->pFileLockObj->haveHigherPriorityWaiter( FLM_BACKGROUND_LOCK_PRIORITY)) { if (RC_BAD( rc = pDb->pFile->pFileLockObj->unlock())) { iErrorLine = (FLMINT)__LINE__; goto Exit; } pDb->uiFlags &= ~(FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_IMPLICIT); continue; } // Start an update transaction if( RC_BAD( rc = flmBeginDbTrans( pDb, FLM_UPDATE_TRANS, FLM_NO_TIMEOUT, FLM_DONT_POISON_CACHE))) { if( rc == FERR_IO_FILE_LOCK_ERR) { // This would only happen if we were signaled to shut down. // So, it's ok to exit flmAssert( pThread->getShutdownFlag()); bForcedShutdown = TRUE; rc = FERR_OK; } else { iErrorLine = (FLMINT)__LINE__; } goto Exit; } bStartedTrans = TRUE; if( RC_BAD( rc = fdictGetIndex( pDb->pDict, pDb->pFile->bInLimitedMode, uiIndexNum, NULL, &pIxd, TRUE))) { // Index may have been deleted by another transaction, or // there may have been some other error. iErrorLine = (FLMINT)__LINE__; goto Exit; } // If we're running in limited mode, then we can't mess with encrypted // indexes. On the other hand, since the index is marked as offline, // but not suspended, this thread has to exist, or else it will cause // all kinds of problems elsewhere. So, in such a case, we will simply // sleep in an inifinite loop until the shutdown flag is set. // (We consider this acceptable becase running in limited mode is not // the norm, and Flaim probably won't be up for very long in this mode.) if( pDb->pFile->bInLimitedMode && pIxd->uiEncId) { bLimitedMode = TRUE; goto Exit; } // Look up the tracker info to determine where we need to being indexing if (RC_BAD( rc = flmGetIxTrackerInfo( pDb, pBackgroundIx->indexStatus.uiIndexNum, &uiContainerNum, &uiFirstDrn, NULL, &pBackgroundIx->indexStatus.bSuspended))) { iErrorLine = (FLMINT)__LINE__; goto Exit; } // If the index is suspended, this thread should have been // shut down. The suspending thread will keep the database // locked until we exit. So, if we have the database locked, // the index better not be suspended. flmAssert( !pBackgroundIx->indexStatus.bSuspended && !(pIxd->uiFlags & IXD_SUSPENDED)); if (pIxd->uiContainerNum) { uiContainerNum = pIxd->uiContainerNum; if( uiFirstDrn == DRN_LAST_MARKER) { goto Exit; } } else { if( uiFirstDrn == DRN_LAST_MARKER && uiContainerNum == 0xFFFFFFFF) { goto Exit; } else { // The container number from the tracker record // may not be a real container. // Determine what the next actual container number is. if (uiContainerNum != FLM_DATA_CONTAINER) { while( uiContainerNum < pDb->pDict->uiIttCnt) { ITT * pItt = &pDb->pDict->pIttTbl [uiContainerNum]; if (ITT_IS_CONTAINER( pItt)) { break; } else { uiContainerNum++; } } if (uiContainerNum >= pDb->pDict->uiIttCnt) { uiContainerNum = FLM_DATA_CONTAINER; } } } } // Setup the DRN range we want to index. uiFirstDrn++; flmAssert( pIxd->uiLastDrnIndexed == uiFirstDrn - 1); // Set the thread's status pThread->setThreadStatus( "Indexing %u:%u", (unsigned)uiContainerNum, (unsigned)uiFirstDrn); // Read and index up to the highest drn (or record higher than uiEndDrn) // or until time runs out. The 500 is millisecs to take for the transaction. f_memcpy( &savedIxStatus, &pBackgroundIx->indexStatus, sizeof( FINDEX_STATUS)); if( RC_BAD( rc = flmIndexSetOfRecords( pDb, uiIndexNum, uiContainerNum, uiFirstDrn, DRN_LAST_MARKER, NULL, NULL, NULL, NULL, &pBackgroundIx->indexStatus, &bHitEnd, pThread, pReusableRec))) { // Lock the mutex while copying the saved index status back to // the main index status so that someone requesting the index status // won't see the status while the memcpy is in progress. f_mutexLock( gv_FlmSysData.hShareMutex); f_memcpy( &pBackgroundIx->indexStatus, &savedIxStatus, sizeof( FINDEX_STATUS)); f_mutexUnlock( gv_FlmSysData.hShareMutex); iErrorLine = (FLMINT)__LINE__; goto Exit; } if( pBackgroundIx->indexStatus.uiRecordsProcessed - savedIxStatus.uiRecordsProcessed) { if( RC_BAD( rc = pDb->pFile->pRfl->logIndexSet( uiIndexNum, uiContainerNum, uiFirstDrn, pBackgroundIx->indexStatus.uiLastRecordIdIndexed))) { iErrorLine = (FLMINT)__LINE__; goto Exit; } } // Commit the transaction (even if we didn't do any indexing work). if( RC_BAD( rc = flmCommitDbTrans( pDb, 0, FALSE))) { iErrorLine = (FLMINT)__LINE__; goto Exit; } bStartedTrans = FALSE; pBackgroundIx->indexStatus.uiTransactions++; if( bHitEnd) { // flmIndexSetOfRecords brought the index on-line if( gv_FlmSysData.UpdateEvents.pEventCBList) { flmDoEventCallback( F_EVENT_UPDATES, F_EVENT_INDEXING_COMPLETE, (void *)uiIndexNum, (void *)0); } // Log a message flmLogIndexingProgress( uiIndexNum, 0); break; } } Exit: pThread->setThreadStatus( FLM_THREAD_STATUS_TERMINATING); if( bStartedTrans) { (void)flmAbortDbTrans( pDb); bStartedTrans = FALSE; } if( pDb && pDb->uiFlags & FDB_HAS_FILE_LOCK) { (void)pDb->pFile->pFileLockObj->unlock(); pDb->uiFlags &= ~(FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_IMPLICIT); } if( bDbInitialized) { fdbExit( pDb); bDbInitialized = FALSE; } if( pDb) { (void)FlmDbClose( (HFDB *) &pDb); } if( RC_BAD(rc) && !bForcedShutdown) { if (rc == FERR_MEM || rc == FERR_IO_DISK_FULL || rc == FERR_MUST_WAIT_CHECKPOINT) { // Log the error f_sprintf( (char *)szMsg, "Background indexing thread %u (index %u)", (unsigned)pThread->getThreadId(), (unsigned)uiIndexNum); flmLogError( rc, (char *)szMsg, __FILE__, iErrorLine); // Sleep a half second and try again. pThread->sleep( 500); goto Loop_Again; } else { f_sprintf( (char *)szMsg, "Background indexing thread %u (index %u) -- unrecoverable error.", (unsigned)pThread->getThreadId(), (unsigned)uiIndexNum); flmLogError( rc, (char *)szMsg, __FILE__, iErrorLine); } } if( pReusableRec) { flmAssert( pReusableRec->getRefCount() == 1); pReusableRec->Release(); } if( bLimitedMode) { flmAssert( RC_OK( rc)); for (;;) { if( pThread->getShutdownFlag()) { break; } pThread->sleep( 1000); } } // Set the thread's app ID to 0, so that it will not // be found now that the thread is terminating (we don't // want flmBackgroundIndexGet to find the thread). pThread->setThreadAppId( 0); // Free the background index structure f_mutexLock( gv_FlmSysData.hShareMutex); f_free( &pBackgroundIx); pThread->setParm1( NULL); f_mutexUnlock( gv_FlmSysData.hShareMutex); return( rc); }
/**************************************************************************** Desc: Set a UTF8 value for a vector element. ****************************************************************************/ RCODE XFLAPI F_DataVector::setUTF8( FLMUINT uiElementNumber, const FLMBYTE * pszUTF8, FLMUINT uiBytesInBuffer) { RCODE rc = NE_XFLM_OK; FLMBYTE * pucDataPtr; FLMUINT uiLen; FLMBYTE ucTmpBuf [64]; // A NULL or empty pszNative string is allowed - on those cases // just set the data type. if (pszUTF8 == NULL || *pszUTF8 == 0) { rc = storeValue( uiElementNumber, XFLM_TEXT_TYPE, NULL, 0); goto Exit; } // See if it will fit in our temporary buffer on the stack. uiLen = sizeof( ucTmpBuf); if (RC_OK( rc = flmUTF8ToStorage( pszUTF8, uiBytesInBuffer, ucTmpBuf, &uiLen))) { if (RC_BAD( rc = storeValue( uiElementNumber, XFLM_TEXT_TYPE, ucTmpBuf, uiLen))) { goto Exit; } } else if (rc != NE_XFLM_CONV_DEST_OVERFLOW) { goto Exit; } else { // Determine the length needed. if (RC_BAD( rc = flmUTF8ToStorage( pszUTF8, uiBytesInBuffer, NULL, &uiLen))) { goto Exit; } // Allocate space for it in the vector and get a pointer // back so we can then store it. if (RC_BAD( rc = storeValue( uiElementNumber, XFLM_TEXT_TYPE, NULL, uiLen, &pucDataPtr))) { goto Exit; } // Store it out to the space we just allocated. if (RC_BAD( rc = flmUTF8ToStorage( pszUTF8, uiBytesInBuffer, pucDataPtr, &uiLen))) { goto Exit; } } Exit: return( rc); }
/**************************************************************************** Desc: Read in the block or get it from the cache. ****************************************************************************/ RCODE F_BtreeRoot::readBlk( FLMUINT uiBlkAddr, // Blk address to read eDynRSetBlkTypes eBlkType, // Expected access type to read F_BtreeBlk ** ppBlk) // (out) Return block { RCODE rc = NE_FLM_OK; FLMUINT uiPos; FLMUINT uiLRUValue = (FLMUINT)~0; FLMUINT uiLRUPos = 0; F_BtreeBlk * pNewBlk; for (uiPos = 0; uiPos < FBTREE_CACHE_BLKS; uiPos++) { if (m_CacheBlks[uiPos].uiBlkAddr == uiBlkAddr) { goto Exit; } // The ref count is used for pinning the block. if (m_CacheBlks[uiPos].pBlk && m_CacheBlks[uiPos].pBlk->getRefCount() == 1 && uiLRUValue > m_CacheBlks[uiPos].uiLRUValue) { uiLRUValue = m_CacheBlks[uiPos].uiLRUValue; uiLRUPos = uiPos; } // There better not be a hole by this point. flmAssert( m_CacheBlks[uiPos].pBlk != NULL); } uiPos = uiLRUPos; // Read from disk? flmAssert( m_pFileHdl != NULL); if (RC_BAD( rc = newCacheBlk( uiPos, &pNewBlk, eBlkType))) { goto Exit; } // Pick the LRU block and make that object do the reading // so it can reset all internals and get used to being a different blk. pNewBlk->blkAddr( uiBlkAddr); m_CacheBlks[uiPos].uiBlkAddr = uiBlkAddr; m_CacheBlks[uiPos].uiLRUValue = m_uiLRUCount++; if (RC_BAD( rc = pNewBlk->readBlk( m_pFileHdl, uiBlkAddr))) { // Release the block because the reset() changed the object type. // May hit the assert above. m_CacheBlks[uiPos].pBlk->Release(); m_CacheBlks[uiPos].pBlk = NULL; goto Exit; } Exit: if (RC_OK(rc)) { *ppBlk = m_CacheBlks[uiPos].pBlk; m_CacheBlks[uiPos].uiLRUValue = m_uiLRUCount++; } return( rc); }
/**************************************************************************** Desc: Insert the entry into the btree - should be positioned ****************************************************************************/ RCODE F_BtreeRoot::insert( void * pvEntry) { RCODE rc = NE_FLM_OK; FLMUINT uiCurLevel; FLMBYTE ucEntryBuf[FBTREE_MAX_LEVELS][DYNSSET_MAX_FIXED_ENTRY_SIZE]; FLMUINT uiNewBlkAddr; if (RC_OK( rc = m_BTStack[0]->insert( pvEntry))) { goto Exit; } // Failed to input at the left level. Do block split(s). // This is an iterative and NOT a recursive split algorithm. // The debugging, and cases to test should be lots easier this way. f_memcpy( ucEntryBuf[0], pvEntry, m_uiEntrySize); uiCurLevel = 0; uiNewBlkAddr = FBTREE_END; for(;;) { // Split while adding the element. if (RC_BAD( rc = (m_BTStack[uiCurLevel])->split( this, ucEntryBuf[ uiCurLevel], uiNewBlkAddr, ucEntryBuf[ uiCurLevel+1], &uiNewBlkAddr))) { goto Exit; } uiCurLevel++; flmAssert( uiCurLevel < m_uiLevels); if (RC_OK( rc = m_BTStack[uiCurLevel]->insertEntry( ucEntryBuf[uiCurLevel], uiNewBlkAddr))) { goto Exit; } // Only returns NE_FLM_OK or FAILURE. // Root split? if (uiCurLevel + 1 == m_uiLevels) { flmAssert( m_uiLevels + 1 <= FBTREE_MAX_LEVELS); if (m_uiLevels + 1 > FBTREE_MAX_LEVELS) { rc = RC_SET( NE_FLM_BTREE_FULL); goto Exit; } // Need to split the root block. rc = ((F_BtreeRoot *)m_BTStack[uiCurLevel])->split( ucEntryBuf[uiCurLevel], uiNewBlkAddr ); break; } } Exit: if (RC_OK(rc)) { m_uiTotalEntries++; } return( rc); }