/******************************************************************************* Desc: Renames a database *******************************************************************************/ FLMEXP RCODE FLMAPI FlmDbRename( const char * pszDbName, const char * pszDataDir, const char * pszRflDir, const char * pszNewDbName, FLMBOOL bOverwriteDestOk, STATUS_HOOK fnStatusCallback, void * UserData) { RCODE rc = FERR_OK; IF_FileHdl * pFileHdl = NULL; FLMUINT uiFileNumber; FILE_HDR FileHdr; LOG_HDR LogHdr; DBRenameInfo * pRenameList = NULL; FLMBOOL bFileFound; FLMBYTE * pucBuffer = NULL; FLMBYTE * pucLogHdr; char * pszOldName; char * pszNewName; char * pszOldDataName; char * pszNewDataName; char * pszFullNewName; char szOldBase[ F_FILENAME_SIZE]; char szNewBase[ F_FILENAME_SIZE]; char * pszExtOld; char * pszExtNew; char * pszDataExtOld; char * pszDataExtNew; // Cannot handle empty database name. flmAssert( pszDbName && *pszDbName); flmAssert( pszNewDbName && *pszNewDbName); // Allocate memory for a read buffer, the log header, and various // file names. if( RC_BAD( rc = f_allocAlignedBuffer( 2048 + LOG_HEADER_SIZE + F_PATH_MAX_SIZE * 5, &pucBuffer))) { goto Exit; } pucLogHdr = pucBuffer + 2048; pszOldName = (char *)(pucLogHdr + LOG_HEADER_SIZE); pszNewName = pszOldName + F_PATH_MAX_SIZE; pszOldDataName = pszNewName + F_PATH_MAX_SIZE; pszNewDataName = pszOldDataName + F_PATH_MAX_SIZE; pszFullNewName = pszNewDataName + F_PATH_MAX_SIZE; // There must be either no directory specified for the new name, or // it must be identical to the old directory. if (RC_BAD( rc = gv_FlmSysData.pFileSystem->pathReduce( pszDbName, pszOldName, szOldBase))) { goto Exit; } if (RC_BAD( rc = gv_FlmSysData.pFileSystem->pathReduce( pszNewDbName, pszNewName, szNewBase))) { goto Exit; } // Directories must be the same. if (*pszNewName && f_stricmp( pszOldName, pszNewName) != 0) { rc = RC_SET( FERR_INVALID_PARM); goto Exit; } f_strcpy( pszNewName, pszOldName); if (RC_BAD( rc = gv_FlmSysData.pFileSystem->pathAppend( pszNewName, szNewBase))) { goto Exit; } f_strcpy( pszFullNewName, pszNewName); f_strcpy( pszOldName, pszDbName); if( pszDataDir && *pszDataDir) { f_strcpy( pszOldDataName, pszDataDir); f_strcpy( pszNewDataName, pszDataDir); if (RC_BAD( rc = gv_FlmSysData.pFileSystem->pathAppend( pszOldDataName, szOldBase))) { goto Exit; } if (RC_BAD( rc = gv_FlmSysData.pFileSystem->pathAppend( pszNewDataName, szNewBase))) { goto Exit; } } else { f_strcpy( pszNewDataName, pszNewName); f_strcpy( pszOldDataName, pszOldName); } // First make sure we have closed the databases and gotten rid of // them from our internal memory tables - in case they had been open. if( RC_BAD( rc = FlmConfig( FLM_CLOSE_FILE, (void *)pszDbName, (void *)pszDataDir))) { goto Exit; } if( RC_BAD( rc = FlmConfig( FLM_CLOSE_FILE, (void *)pszFullNewName, (void *)pszDataDir))) { goto Exit; } gv_FlmSysData.pFileHdlCache->closeUnusedFiles(); // Open the file so we can get the log header. if( RC_BAD( rc = gv_FlmSysData.pFileSystem->openFile( pszDbName, gv_FlmSysData.uiFileOpenFlags, &pFileHdl))) { goto Exit; } // Read the header to get the low and high RFL log // file numbers. if (RC_BAD( flmReadAndVerifyHdrInfo( NULL, pFileHdl, pucBuffer, &FileHdr, &LogHdr, pucLogHdr))) { goto Exit; } // Close the file. pFileHdl->Release(); pFileHdl = NULL; // Start renaming files, beginning with the main DB file. if( RC_BAD( rc = flmRenameFile( pszDbName, pszFullNewName, bOverwriteDestOk, FALSE, &pRenameList, &bFileFound, fnStatusCallback, UserData))) { goto Exit; } // Find where the extension of the old and new database names are pszExtOld = pszOldName + f_strlen( pszOldName) - 1; pszDataExtOld = pszOldDataName + f_strlen( pszOldDataName) - 1; while (pszExtOld != pszOldName && *pszExtOld != '.') { pszExtOld--; // Both the old db name and old data name have the same // base name, so we can decrement pszDataExtOld // at the same time we decrement pszExtOld. pszDataExtOld--; } if (*pszExtOld != '.') { pszExtOld = pszOldName + f_strlen( pszOldName); pszDataExtOld = pszOldDataName + f_strlen( pszOldDataName); } pszExtNew = pszNewName + f_strlen( pszNewName) - 1; pszDataExtNew = pszNewDataName + f_strlen( pszNewDataName) - 1; while (pszExtNew != pszOldName && *pszExtNew != '.') { pszExtNew--; // Both the new db name and new data name have the same // base name, so we can decrement pszDataExtNew // at the same time we decrement pszExtNew. pszDataExtNew--; } if (*pszExtNew != '.') { pszExtNew = pszNewName + f_strlen( pszNewName); pszDataExtNew = pszNewDataName + f_strlen( pszNewDataName); } // Rename the .lck file, if any. This is necessary for UNIX. f_strcpy( pszExtOld, ".lck"); f_strcpy( pszExtNew, ".lck"); if (RC_BAD( rc = flmRenameFile( pszOldName, pszNewName, bOverwriteDestOk, TRUE, &pRenameList, &bFileFound, fnStatusCallback, UserData))) { goto Exit; } // Rename block (data) files. uiFileNumber = 1; for (;;) { F_SuperFileClient::bldSuperFileExtension( FileHdr.uiVersionNum, uiFileNumber, pszDataExtOld); F_SuperFileClient::bldSuperFileExtension( FileHdr.uiVersionNum, uiFileNumber, pszDataExtNew); if (RC_BAD( rc = flmRenameFile( pszOldDataName, pszNewDataName, bOverwriteDestOk, TRUE, &pRenameList, &bFileFound, fnStatusCallback, UserData))) { goto Exit; } if (!bFileFound) { break; } if (uiFileNumber == MAX_DATA_BLOCK_FILE_NUMBER( FileHdr.uiVersionNum)) { break; } uiFileNumber++; } // Rename rollback log files. uiFileNumber = FIRST_LOG_BLOCK_FILE_NUMBER (FileHdr.uiVersionNum); for (;;) { F_SuperFileClient::bldSuperFileExtension( FileHdr.uiVersionNum, uiFileNumber, pszExtOld); F_SuperFileClient::bldSuperFileExtension( FileHdr.uiVersionNum, uiFileNumber, pszExtNew); if (RC_BAD( rc = flmRenameFile( pszOldName, pszNewName, bOverwriteDestOk, TRUE, &pRenameList, &bFileFound, fnStatusCallback, UserData))) { goto Exit; } if (!bFileFound) { break; } if (uiFileNumber == MAX_LOG_BLOCK_FILE_NUMBER( FileHdr.uiVersionNum)) { break; } uiFileNumber++; } // Rename roll-forward log files. if (FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) { // For pre-4.3 versions, only need to rename one RFL file. if (RC_BAD( rc = rflGetFileName( FileHdr.uiVersionNum, pszDbName, pszRflDir, 1, pszOldName))) { goto Exit; } if (RC_BAD( rc = rflGetFileName( FileHdr.uiVersionNum, pszFullNewName, pszRflDir, 1, pszNewName))) { goto Exit; } if (RC_BAD( rc = flmRenameFile( pszOldName, pszNewName, bOverwriteDestOk, TRUE, &pRenameList, &bFileFound, fnStatusCallback, UserData))) { goto Exit; } } else { // For 4.3 and greater, rename the RFL directory. if (RC_BAD( rc = rflGetDirAndPrefix( FileHdr.uiVersionNum, pszDbName, pszRflDir, pszOldName, szOldBase))) { goto Exit; } if (RC_BAD( rc = rflGetDirAndPrefix( FileHdr.uiVersionNum, pszFullNewName, pszRflDir, pszNewName, szNewBase))) { goto Exit; } if (RC_BAD( rc = flmRenameFile( pszOldName, pszNewName, bOverwriteDestOk, TRUE, &pRenameList, &bFileFound, fnStatusCallback, UserData))) { goto Exit; } } Exit: if( pFileHdl) { pFileHdl->Release(); } if( pucBuffer) { f_freeAlignedBuffer( &pucBuffer); } // Free the list of renamed files. while( pRenameList) { DBRenameInfo * pRenameFile; pRenameFile = pRenameList; pRenameList = pRenameList->pNext; // If we had an error of some sort, attempt to un-rename // the file that had been renamed. if (RC_BAD( rc)) { gv_FlmSysData.pFileSystem->renameFile( pRenameFile->Info.szDstFileName, pRenameFile->Info.szSrcFileName); } f_free( &pRenameFile); } return( rc); }
/******************************************************************** Desc: Loads the database with objects. *********************************************************************/ RCODE gigaLoadDatabase( void) { RCODE rc = NE_FLM_OK; FLMBOOL bTransActive = FALSE; FLMBOOL bCommitTrans = FALSE; FLMUINT uiObjsInTrans = 0; FLMUINT uiChar = 0; FLMUINT bSuspend = FALSE; FlmRecord * pNewRec = NULL; // Set cache size, if specified on command line. if( gv_uiCacheSize) { if( RC_BAD( rc = FlmSetHardMemoryLimit( 0, FALSE, 0, gv_uiCacheSize, 0))) { gigaOutputRcErr( "setting cache size", rc); goto Exit; } } // Set block cache percentage, if it is not default. if( gv_uiBlockCachePercentage != 50) { if( RC_BAD( rc = FlmConfig( FLM_BLOCK_CACHE_PERCENTAGE, (void *)gv_uiBlockCachePercentage, (void *)0))) { gigaOutputRcErr( "setting block cache percentage", rc); goto Exit; } } // Set the maximum and low dirty cache, if one was specified if( gv_uiMaxDirtyCache) { if( RC_BAD( rc = FlmConfig( FLM_MAX_DIRTY_CACHE, (void *)gv_uiMaxDirtyCache, (void *)gv_uiLowDirtyCache))) { gigaOutputRcErr( "setting maximum dirty cache", rc); goto Exit; } } // Set checkpoint interval, if one is specified. if( gv_uiCPInterval != 0xFFFFFFFF) { if( RC_BAD( rc = FlmConfig( FLM_MAX_CP_INTERVAL, (void *)gv_uiCPInterval, (void *)0))) { gigaOutputRcErr( "setting checkpoint interval", rc); goto Exit; } } // Enable/Disable direct I/O if( RC_BAD( rc = FlmConfig( FLM_DIRECT_IO_STATE, (void *)!gv_bDisableDirectIO, NULL))) { goto Exit; } // Create the database. (void)FlmDbRemove( gv_szDibName, gv_szDataDir, gv_szRflDir, TRUE); if( RC_BAD( rc = FlmDbCreate( gv_szDibName, gv_szDataDir, gv_szRflDir, NULL, gv_pszGigaDictionary, NULL, &gv_hDb))) { gigaOutputRcErr( "creating database", rc); goto Exit; } if( RC_BAD( rc = FlmDbConfig( gv_hDb, FDB_RFL_FOOTPRINT_SIZE, (void *)(512 * 1024 * 1024), NULL))) { goto Exit; } if( RC_BAD( rc = FlmDbConfig( gv_hDb, FDB_RBL_FOOTPRINT_SIZE, (void *)(512 * 1024 * 1024), NULL))) { goto Exit; } // Create the display gv_uiTotalLoaded = 0; gv_ui10SecTotal = 0; f_mutexLock( gv_hWindowMutex); FTXWinClear( gv_pWindow); f_mutexUnlock( gv_hWindowMutex); gigaOutputLabel( MAX_CACHE_ROW, "Maximum Cache Size (bytes)"); gigaOutputLabel( USED_CACHE_ROW, "Cache Used (bytes)"); gigaOutputLabel( ITEMS_CACHED_ROW, "Cache Used (items)"); gigaOutputLabel( DIRTY_CACHE_ROW, "Dirty Cache (bytes)"); gigaOutputLabel( LOG_CACHE_ROW, "Log Cache (bytes)"); gigaOutputLabel( FREE_CACHE_ROW, "Free Cache (bytes)"); gigaOutputLabel( CP_STATE_ROW, "Checkpoint State"); gigaUpdateMemInfo(); gigaOutputLabel( DB_NAME_ROW, "Database Name"); gigaOutputStr( DB_NAME_ROW, gv_szDibName); gigaOutputLabel( TOTAL_TO_LOAD_ROW, "Total To Load"); gigaOutputUINT( TOTAL_TO_LOAD_ROW, gv_uiTotalToLoad); gigaOutputLabel( TRANS_SIZE_ROW, "Transaction Size"); gigaOutputUINT( TRANS_SIZE_ROW, gv_uiTransSize); gigaOutputLabel( TOTAL_LOADED_ROW, "Total Loaded"); gigaOutputUINT( TOTAL_LOADED_ROW, gv_uiTotalLoaded); gigaOutputLabel( ADDS_PER_SEC_CURRENT, "Adds/Sec. (10 secs)"); gigaOutputUINT( ADDS_PER_SEC_CURRENT, 0); gigaOutputLabel( ADDS_PER_SEC_OVERALL, "Adds/Sec. (overall)"); gigaOutputUINT( ADDS_PER_SEC_OVERALL, 0); gigaOutputLabel( ELAPSED_TIME_ROW, "Elapsed Time"); gigaOutputStr( ELAPSED_TIME_ROW, "<none>"); if( RC_BAD( rc = gigaStartScreenThread())) { goto Exit; } gv_ui10SecStartTime = gv_uiStartTime = FLM_GET_TIMER(); gv_ui10Secs = FLM_SECS_TO_TIMER_UNITS( 10); gv_ui1Sec = FLM_SECS_TO_TIMER_UNITS( 1); for( ;;) { // See if we have been told to shut down, or if the user // has pressed escape. if( gv_bShutdown) { break; } // Every 127 objects, see if character was pressed and update // count on screen. if( (gv_uiTotalLoaded & 0x7F) == 0) { f_yieldCPU(); if( (uiChar = gigaSeeIfQuit()) != 0) { if( uiChar == FKB_ESCAPE) { break; } else if( uiChar == 's' || uiChar == 'S') { bSuspend = TRUE; } } // Check for other keyboard options } else if( (gv_uiTotalLoaded & 0x7) == 0) { FLMUINT uiElapsedTime; FLMUINT uiCurrTime; uiCurrTime = FLM_GET_TIMER(); // If at least 10 seconds have elapsed, redisplay the average // rate values. if( (uiElapsedTime = FLM_ELAPSED_TIME( uiCurrTime, gv_ui10SecStartTime)) >= gv_ui10Secs) { gigaUpdateLoadTimes(); } } // Start a transaction, if one is not going. if( !bTransActive) { if( bSuspend) { uiChar = gigaGetInput( "Load suspended, press any character to continue loading: ", NULL); bSuspend = FALSE; } if( RC_BAD( rc = gigaStartTrans())) { goto Exit; } bTransActive = TRUE; bCommitTrans = FALSE; uiObjsInTrans = 0; } // Increment the load counters and determine if this will be the // last object of the transaction. gv_uiTotalLoaded++; uiObjsInTrans++; if( uiObjsInTrans == gv_uiTransSize || gv_uiTotalLoaded == gv_uiTotalToLoad) { bCommitTrans = TRUE; } // Create a new object. if( RC_BAD( rc = gigaMakeNewRecord( &pNewRec))) { goto Exit; } if( RC_BAD( rc = FlmRecordAdd( gv_hDb, FLM_DATA_CONTAINER, NULL, pNewRec, FLM_DONT_INSERT_IN_CACHE))) { goto Exit; } // Commit when we reach the transaction size or the total to load. // NOTE: The bCommitTrans flag is set above. if( bCommitTrans) { if( RC_BAD( rc = gigaCommitTrans())) { goto Exit; } bTransActive = FALSE; } // See if we are done. if( gv_uiTotalLoaded == gv_uiTotalToLoad) { flmAssert( !bTransActive); break; } } Exit: if( pNewRec) { pNewRec->Release(); } if( bTransActive) { (void)FlmDbTransAbort( gv_hDb); } if( gv_hDb != HFDB_NULL) { FlmDbCheckpoint( gv_hDb, FLM_NO_TIMEOUT); gigaStopScreenThread(); FlmDbClose( &gv_hDb); // This will cause us to wait for the last checkpoint // to finish. (void)FlmConfig( FLM_CLOSE_FILE, (void *)gv_szDibName, (void *)gv_szDataDir); } gigaUpdateLoadTimes(); gigaStopScreenThread(); f_threadDestroy( &gv_pIxManagerThrd); return( rc); }
/******************************************************************************* Desc: Copies a database, including roll-forward log files. *******************************************************************************/ FLMEXP RCODE FLMAPI FlmDbCopy( const char * pszSrcDbName, const char * pszSrcDataDir, const char * pszSrcRflDir, const char * pszDestDbName, const char * pszDestDataDir, const char * pszDestRflDir, STATUS_HOOK fnStatusCallback, void * UserData) { RCODE rc = FERR_OK; FLMBYTE * pucLastCommittedLogHdr; HFDB hDb = HFDB_NULL; FDB * pDb; FLMBOOL bDbLocked = FALSE; FLMUINT uiDbVersion; // Make sure the destination database is closed if (RC_BAD( rc = FlmConfig( FLM_CLOSE_FILE, (void *)pszDestDbName, (void *)pszDestDataDir))) { goto Exit; } gv_FlmSysData.pFileHdlCache->closeUnusedFiles(); // Open the database so we can force a checkpoint. if (RC_BAD( rc = FlmDbOpen( pszSrcDbName, pszSrcDataDir, pszSrcRflDir, 0, NULL, &hDb))) { goto Exit; } pDb = (FDB *)hDb; // Need to lock the database, because we want to do a checkpoint // and then the copy immediately after without letting other // threads have the opportunity to get in and update the // database. if (RC_BAD( rc = FlmDbLock( hDb, FLM_LOCK_EXCLUSIVE, 0, FLM_NO_TIMEOUT))) { goto Exit; } bDbLocked = TRUE; // Force a checkpoint if (RC_BAD( rc = FlmDbCheckpoint( hDb, FLM_NO_TIMEOUT))) { goto Exit; } pucLastCommittedLogHdr = &pDb->pFile->ucLastCommittedLogHdr[ 0]; // Get the low and high RFL log file numbers from the log // header. uiDbVersion = pDb->pFile->FileHdr.uiVersionNum; // Once we get this far, we have exclusive access to the database // and we have forced a checkpoint. The database's contents are // guaranteed to be on disk at this point, and they will not // change. rc = flmCopyDb( uiDbVersion, pszSrcDbName, pszSrcDataDir, pszSrcRflDir, pszDestDbName, pszDestDataDir, pszDestRflDir, fnStatusCallback, UserData); Exit: // Unlock and close the database if (bDbLocked) { FlmDbUnlock( hDb); } if (hDb != HFDB_NULL) { (void)FlmDbClose( &hDb); (void)FlmConfig( FLM_CLOSE_FILE, (void *)pszSrcDbName, (void *)pszSrcDataDir); } return( rc); }
/******************************************************************** Desc: ? *********************************************************************/ FSTATIC FLMBOOL bldDoRebuild( void) { RCODE rc; FLMBOOL bOk = TRUE; char szErrMsg[ 100]; CREATE_OPTS createOpts; gv_ui64DatabaseSize = 0; gv_ui64BytesDone = 0; gv_uiDictRecsRecovered = 0; gv_iLastDoing = -1; gv_uiTotalRecs = 0; gv_uiRecsRecovered = 0; f_conSetBackFore( FLM_BLACK, FLM_LIGHTGRAY); f_conClearScreen( 0, 0); gv_bLoggingEnabled = FALSE; gv_uiLogBufferCount = 0; if( gv_szLogFileName[ 0]) { gv_pFileSystem->deleteFile( gv_szLogFileName); if (RC_OK( rc = gv_pFileSystem->createFile( gv_szLogFileName, FLM_IO_RDWR, &gv_pLogFile))) { gv_bLoggingEnabled = TRUE; } else { f_strcpy( szErrMsg, "Error creating log file: "); f_strcpy( &szErrMsg[ f_strlen( szErrMsg)], FlmErrorString( rc)); bldShowError( szErrMsg); bOk = FALSE; goto Exit; } } /* Configure FLAIM */ if (RC_BAD( rc = FlmConfig( FLM_CACHE_LIMIT, (void *)(gv_uiCacheSize * 1024), (void *)0))) { f_strcpy( szErrMsg, "Error setting cache size for FLAIM share: "); f_strcpy( &szErrMsg[ f_strlen( szErrMsg)], FlmErrorString( rc)); bldShowError( szErrMsg); bOk = FALSE; goto Exit; } f_conSetBackFore( FLM_BLACK, FLM_WHITE); if( gv_bLoggingEnabled) { bldLogString( NULL); bldLogString( NULL); bldLogString( NULL); bldLogString( "=========================================================================="); bldLogString( "REBUILD PARAMETERS:"); } f_conClearScreen( 0, PARAM_ROW); f_conStrOutXY( "REBUILD PARAMETERS:", LABEL_COLUMN, PARAM_ROW); bldOutLabel( LABEL_COLUMN + 2, SOURCE_ROW, "Source DB", gv_szSrcFileName, 0, TRUE); bldOutLabel( LABEL_COLUMN + 2, SOURCE_DATA_DIR_ROW, "Src. Data Dir", (gv_szSrcDataDir [0]) ? &gv_szSrcDataDir [0] : "<NONE>", 0, TRUE); bldOutLabel( LABEL_COLUMN + 2, DEST_ROW, "Destination DB", gv_szDestFileName, 0, TRUE); bldOutLabel( LABEL_COLUMN + 2, DEST_DATA_DIR_ROW, "Dest. Data Dir", (gv_szDestDataDir [0]) ? &gv_szDestDataDir [0] : "<NONE>", 0, TRUE); bldOutLabel( LABEL_COLUMN + 2, DEST_RFL_ROW, "Dest. RFL Dir", (gv_szDestRflDir [0]) ? &gv_szDestRflDir [0] : "<NONE>", 0, TRUE); bldOutLabel( LABEL_COLUMN + 2, DICT_ROW, "Dictionary File", (gv_szDictFileName [0]) ? &gv_szDictFileName [0] : "<NONE>", 0, TRUE); bldOutLabel( LABEL_COLUMN + 2, CACHE_ROW, "Cache (kb)", NULL, gv_uiCacheSize, TRUE); bldOutLabel( LABEL_COLUMN + 2, LOG_FILE_ROW, "Log File", (gv_szLogFileName [0]) ? &gv_szLogFileName [0] : "<NONE>", 0, TRUE); bldOutLabel( LABEL_COLUMN, DOING_ROW, "Current Action", "Startup ", 0L, FALSE); bldOutLabel( LABEL_COLUMN, DB_SIZE_ROW, "Database Size", NULL, (FLMUINT)gv_ui64DatabaseSize, FALSE); bldOutLabel( LABEL_COLUMN, BYTES_DONE_ROW, "Bytes Processed", NULL, (FLMUINT)gv_ui64BytesDone, FALSE); bldOutLabel( LABEL_COLUMN, TOTAL_REC_ROW, "Total Records", NULL, gv_uiTotalRecs, FALSE); bldOutLabel( LABEL_COLUMN, RECOV_ROW, "Records Recovered", NULL, gv_uiRecsRecovered, FALSE); bldOutLabel( LABEL_COLUMN, DICT_RECOV_ROW, "Dict Items Recov", NULL, gv_uiDictRecsRecovered, FALSE); if( gv_szDictFileName [0]) { gv_pszDictPath = &gv_szDictFileName [0]; } else { gv_pszDictPath = NULL; } /* Open the database ONLY to get the createOpts. Rebuild the exact prefix and other create options. */ rc = bldGetCreateOpts( gv_szSrcFileName, &createOpts); if ((!gv_bShutdown) && (RC_OK( rc))) { char * pszDestRflDir; pszDestRflDir = ((gv_szDestRflDir [0]) ? &gv_szDestRflDir [0] : NULL); rc = FlmDbRebuild( gv_szSrcFileName, gv_szSrcDataDir, gv_szDestFileName, gv_szDestDataDir, pszDestRflDir, gv_pszDictPath, &createOpts, &gv_uiTotalRecs, &gv_uiRecsRecovered, bldProgFunc, NULL); bldShowResults( "FlmDbRebuild", rc, gv_uiTotalRecs, gv_uiRecsRecovered, gv_uiDictRecsRecovered); } Exit: if( gv_bLoggingEnabled) { bldLogFlush(); gv_pLogFile->Release(); gv_pLogFile = NULL; } return( bOk); }