/**************************************************************************** Desc: ****************************************************************************/ RCODE FLMAPI f_rwlockCreate( F_RWLOCK * phReadWriteLock) { RCODE rc = NE_FLM_OK; F_RWLOCK_IMP * pReadWriteLock = NULL; if( RC_BAD( rc = f_calloc( sizeof( F_RWLOCK_IMP), &pReadWriteLock))) { goto Exit; } pReadWriteLock->hMutex = F_MUTEX_NULL; if( RC_BAD( rc = f_mutexCreate( &pReadWriteLock->hMutex))) { goto Exit; } *phReadWriteLock = (F_RWLOCK)pReadWriteLock; pReadWriteLock = NULL; Exit: if( pReadWriteLock) { f_rwlockDestroy( (F_RWLOCK *)&pReadWriteLock); } return( rc); }
/**************************************************************************** Desc: Builds a character lookup table ****************************************************************************/ RCODE FLMAPI F_XML::setup( void) { RCODE rc = NE_FLM_OK; FLMUINT uiLoop; if( m_pCharTable) { f_free( &m_pCharTable); } if( RC_BAD( rc = f_calloc( sizeof( XMLCHAR) * 0xFFFF, &m_pCharTable))) { goto Exit; } for( uiLoop = 0; charTbl[uiLoop].ui16Flag; uiLoop++) { setCharFlag( charTbl[uiLoop].uLowChar, charTbl[uiLoop].uHighChar, charTbl[uiLoop].ui16Flag); } Exit: return( rc); }
/**************************************************************************** Public: FlmRecordSet::insert Desc: Insert a FlmRecord into the set. ****************************************************************************/ RCODE FlmRecordSet::insert( FlmRecord * pRecord) { RCODE rc = FERR_OK; FlmRecord ** ppTmpArray; // See if we need to reallocate the array. if (m_iTotalRecs == m_iRecArraySize) { if( RC_BAD( rc = f_calloc( sizeof( FlmRecord *) * (m_iRecArraySize + 10), &ppTmpArray))) { goto Exit; } if (m_iTotalRecs) { f_memcpy( ppTmpArray, m_ppRecArray, sizeof( FlmRecord *) * m_iTotalRecs); } m_ppRecArray = ppTmpArray; m_iRecArraySize += 10; } // Add the new entry into the array. m_ppRecArray [m_iTotalRecs] = pRecord; pRecord->AddRef(); m_iTotalRecs++; Exit: return( rc); }
/**************************************************************************** Desc: Add the index to the start list of background threads. ****************************************************************************/ RCODE flmAddToStartList( FDB * pDb, FLMUINT uiIndexNum) { RCODE rc = FERR_OK; F_BKGND_IX * pBackgroundIx; F_BKGND_IX * pNextBackgroundIx; // We'd better not be replaying the RFL flmAssert( !(pDb->uiFlags & FDB_REPLAYING_RFL)); // Look in the start list to make sure we don't already // have an entry for this index. We don't want to // start more than one thread per index. The background // indexing code is not structured to handle multiple build // threads on the same index. // NOTE: We don't want to remove any entries in the stop // list corresponding to this index. The reason for this // is the index may have been deleted, re-added, deleted, // modified, etc. several times during the transaction. // We want to make sure that an existing background indexing // thread is terminated and a new one is started. The stop // list is always processed first at transaction commit time. // Then new indexing threads (in the start list) are started. for( pBackgroundIx = pDb->pIxStartList; pBackgroundIx; pBackgroundIx = pNextBackgroundIx) { pNextBackgroundIx = pBackgroundIx->pNext; if( pBackgroundIx->indexStatus.uiIndexNum == uiIndexNum) { goto Exit; // Should return FERR_OK } } // Allocate and add the thread structure to the pDb thread list. if( RC_BAD( rc = f_calloc( (FLMUINT)( sizeof( F_BKGND_IX)), &pBackgroundIx))) { goto Exit; } pBackgroundIx->indexStatus.uiIndexNum = uiIndexNum; pBackgroundIx->pPrev = NULL; if( (pBackgroundIx->pNext = pDb->pIxStartList) != NULL) { pDb->pIxStartList->pPrev = pBackgroundIx; } pDb->pIxStartList = pBackgroundIx; Exit: return( rc); }
/**************************************************************************** Desc: Add a reference to an embedded user predicate. ****************************************************************************/ RCODE flmCurAddRefPredicate( QTINFO * pQTInfo, FlmUserPredicate * pPredicate ) { RCODE rc = FERR_OK; if (pQTInfo->uiNumPredicates == pQTInfo->uiMaxPredicates) { // Are we still in the embedded array? or have we // done an allocation? if (pQTInfo->uiMaxPredicates == MAX_USER_PREDICATES) { if (RC_BAD( rc = f_calloc( sizeof( FlmUserPredicate *) * (MAX_USER_PREDICATES * 2), &pQTInfo->ppPredicates))) { goto Exit; } // Copy all old pointers from embedded array. f_memcpy( pQTInfo->ppPredicates, &pQTInfo->Predicates [0], MAX_USER_PREDICATES * sizeof( FlmUserPredicate *)); } else { // Reallocate the structure. if (RC_BAD( rc = f_recalloc( sizeof( FlmUserPredicate *) * (pQTInfo->uiNumPredicates * 2), &pQTInfo->ppPredicates))) { goto Exit; } } pQTInfo->uiMaxPredicates *= 2; } pQTInfo->ppPredicates [pQTInfo->uiNumPredicates] = pPredicate; pPredicate->AddRef(); pQTInfo->uiNumPredicates++; Exit: return( rc); }
/**************************************************************************** Desc: Allocate structures and set entry size. ****************************************************************************/ RCODE F_BtreeNonLeaf::setup( FLMUINT uiEntrySize) { RCODE rc = NE_FLM_OK; if (RC_BAD( rc = f_calloc( DYNSSET_BLOCK_SIZE, &m_pucBlkBuf))) { goto Exit; } m_uiEntrySize = uiEntrySize; m_pvUserData = (void *) uiEntrySize; reset( ACCESS_BTREE_NON_LEAF); nextBlk( FBTREE_END); prevBlk( FBTREE_END); lemBlk( FBTREE_END); Exit: return( rc); }
/**************************************************************************** Desc: Allocate structures and set entry size. ****************************************************************************/ RCODE F_BtreeRoot::setup( FLMUINT uiEntrySize, char * pszFileName) { RCODE rc; if (RC_BAD( rc = f_calloc( DYNSSET_BLOCK_SIZE, &m_pucBlkBuf))) { goto Exit; } m_uiEntrySize = uiEntrySize; m_pvUserData = (void *) uiEntrySize; reset( ACCESS_BTREE_ROOT); m_pszFileName = pszFileName; nextBlk( FBTREE_END); prevBlk( FBTREE_END); lemBlk( FBTREE_END); Exit: return( rc); }
RCODE FLMAPI f_semCreate( F_SEM * phSem) { RCODE rc = NE_FLM_OK; sema_t * pSem = NULL; f_assert( phSem != NULL); f_assert( *phSem == F_SEM_NULL); if( RC_BAD( rc = f_calloc( sizeof( sema_t), &pSem))) { goto Exit; } if( (pSem->hWinSem = CreateSemaphore( (LPSECURITY_ATTRIBUTES)NULL, 0, 10000, NULL )) == NULL) { rc = RC_SET( NE_FLM_COULD_NOT_CREATE_SEMAPHORE); } *phSem = pSem; pSem = NULL; Exit: if( pSem) { if( pSem->hWinSem) { CloseHandle( pSem->hWinSem); } f_free( &pSem); } return( rc); }
/**************************************************************************** Desc: Set information in the index definition row. ****************************************************************************/ RCODE F_Db::setIxStateInfo( FLMUINT uiIndexNum, FLMUINT64 ui64LastRowIndexed, FLMUINT uiState) { RCODE rc = NE_SFLM_OK; IXD_FIXUP * pIxdFixup; F_INDEX * pIndex; FLMBOOL bMustAbortOnError = FALSE; F_Row * pRow = NULL; pIndex = m_pDict->getIndex( uiIndexNum); flmAssert( pIndex); // See if this index is in our fixup list. pIxdFixup = m_pIxdFixups; while (pIxdFixup && pIxdFixup->uiIndexNum != uiIndexNum) { pIxdFixup = pIxdFixup->pNext; } if (!pIxdFixup) { if (RC_BAD( rc = f_calloc( (FLMUINT)sizeof( IXD_FIXUP), &pIxdFixup))) { goto Exit; } pIxdFixup->pNext = m_pIxdFixups; m_pIxdFixups = pIxdFixup; pIxdFixup->uiIndexNum = uiIndexNum; pIxdFixup->ui64LastRowIndexed = pIndex->ui64LastRowIndexed; } bMustAbortOnError = TRUE; // Update the last row indexed, if it changed. if (pIxdFixup->ui64LastRowIndexed != ui64LastRowIndexed) { pIxdFixup->ui64LastRowIndexed = ui64LastRowIndexed; // First, retrieve the index definition row. if( RC_BAD( rc = gv_SFlmSysData.pRowCacheMgr->retrieveRow( this, SFLM_TBLNUM_INDEXES, pIndex->ui64DefRowId, &pRow))) { goto Exit; } if (ui64LastRowIndexed) { if (RC_BAD( rc = pRow->setUINT64( this, SFLM_COLNUM_INDEXES_LAST_ROW_INDEXED, ui64LastRowIndexed))) { goto Exit; } } else { pRow->setToNull( this, SFLM_COLNUM_INDEXES_LAST_ROW_INDEXED); } } // If IXD_SUSPENDED is set, then IXD_OFFLINE must also be set. // There are places in the code that only check for IXD_OFFLINE // that don't care if the index is also suspended. if (uiState & IXD_SUSPENDED) { uiState = IXD_SUSPENDED | IXD_OFFLINE; } else if (uiState & IXD_OFFLINE) { uiState = IXD_OFFLINE; } else { uiState = 0; } // See if we need to change state. if ((pIndex->uiFlags & (IXD_SUSPENDED | IXD_OFFLINE)) != uiState) { const char * pszStateStr; FLMUINT uiStateStrLen; if (uiState & IXD_SUSPENDED) { pszStateStr = SFLM_INDEX_SUSPENDED_STR; } else if (uiState & IXD_OFFLINE) { pszStateStr = SFLM_INDEX_OFFLINE_STR; } else { pszStateStr = SFLM_INDEX_ONLINE_STR; } // At this point we know we need to change the state. That means we need // to create a new dictionary, if we have not already done so. if (!(m_uiFlags & FDB_UPDATED_DICTIONARY)) { if (RC_BAD( rc = dictClone())) { goto Exit; } // Get a pointer to the new F_INDEX pIndex = m_pDict->getIndex( uiIndexNum); } // Retrieve the index definition row if it was not fetched above. if (!pRow) { if( RC_BAD( rc = gv_SFlmSysData.pRowCacheMgr->retrieveRow( this, SFLM_TBLNUM_INDEXES, pIndex->ui64DefRowId, &pRow))) { goto Exit; } } uiStateStrLen = f_strlen( pszStateStr); if (RC_BAD( rc = pRow->setUTF8( this, SFLM_COLNUM_INDEXES_INDEX_STATE, pszStateStr, uiStateStrLen, uiStateStrLen))) { goto Exit; } // Put the state into the F_INDEX. pIndex->uiFlags = (pIndex->uiFlags & (~(IXD_SUSPENDED | IXD_OFFLINE))) | uiState; } Exit: if (pRow) { pRow->ReleaseRow(); } if( RC_BAD( rc) && bMustAbortOnError) { setMustAbortTrans( rc); } return( rc); }
/**************************************************************************** Desc: Add the index to the stop list of background threads. ****************************************************************************/ RCODE flmAddToStopList( FDB * pDb, FLMUINT uiIndexNum) { RCODE rc = FERR_OK; F_BKGND_IX * pBackgroundIx; F_BKGND_IX * pNextBackgroundIx; // We'd better not be replaying the RFL flmAssert( !(pDb->uiFlags & FDB_REPLAYING_RFL)); // First look in the start list and remove any index matches. // This is need if you add an index and drop // it within the same transaction. for( pBackgroundIx = pDb->pIxStartList; pBackgroundIx; pBackgroundIx = pNextBackgroundIx) { pNextBackgroundIx = pBackgroundIx->pNext; if( pBackgroundIx->indexStatus.uiIndexNum == uiIndexNum) { if( pNextBackgroundIx) { pNextBackgroundIx->pPrev = pBackgroundIx->pPrev; } if( pBackgroundIx->pPrev) { pBackgroundIx->pPrev->pNext = pNextBackgroundIx; } else { pDb->pIxStartList = pNextBackgroundIx; } f_free( &pBackgroundIx); } } // See if we already have an entry in the stop list for the index. There // is no reason to have the index in the list more than once. for( pBackgroundIx = pDb->pIxStopList; pBackgroundIx; pBackgroundIx = pNextBackgroundIx) { pNextBackgroundIx = pBackgroundIx->pNext; if( pBackgroundIx->indexStatus.uiIndexNum == uiIndexNum) { goto Exit; // Should return FERR_OK } } // Allocate and add the thread structure to the pFile thread list. if( RC_BAD( rc = f_calloc( (FLMUINT)( sizeof( F_BKGND_IX)), &pBackgroundIx))) { goto Exit; } pBackgroundIx->indexStatus.uiIndexNum = uiIndexNum; pBackgroundIx->pPrev = NULL; if( (pBackgroundIx->pNext = pDb->pIxStopList) != NULL) { pDb->pIxStopList->pPrev = pBackgroundIx; } pDb->pIxStopList = pBackgroundIx; Exit: 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. ****************************************************************************/ RCODE flmStartIndexBuild( FDB * pDb, FLMUINT uiIndexNum) { RCODE rc = FERR_OK; FLMUINT uiGMT; IXD * pIxd; F_BKGND_IX * pBackgroundIx = NULL; char szThreadName[ F_PATH_MAX_SIZE]; char szBaseName[ F_FILENAME_SIZE]; f_timeGetSeconds( &uiGMT ); if( flmBackgroundIndexGet( pDb->pFile, uiIndexNum, FALSE) != NULL) { // There is already a background thread running on this index. flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } if( RC_BAD( rc = fdictGetIndex( pDb->pDict, pDb->pFile->bInLimitedMode, uiIndexNum, NULL, &pIxd, TRUE))) { goto Exit; } // Allocate the background thread and index status strucutures. if( RC_BAD( rc = f_calloc( (FLMUINT)sizeof( F_BKGND_IX), &pBackgroundIx))) { goto Exit; } pBackgroundIx->pFile = pDb->pFile; pBackgroundIx->indexStatus.bSuspended = FALSE; pBackgroundIx->indexStatus.uiIndexNum = uiIndexNum; pBackgroundIx->indexStatus.uiStartTime = uiGMT; pBackgroundIx->indexStatus.uiLastRecordIdIndexed = pIxd->uiLastDrnIndexed; pBackgroundIx->indexStatus.uiKeysProcessed = 0; pBackgroundIx->indexStatus.uiRecordsProcessed = 0; pBackgroundIx->indexStatus.uiTransactions = 0; pBackgroundIx->uiIndexingAction = FTHREAD_ACTION_INDEX_OFFLINE; pBackgroundIx->pPrev = NULL; pBackgroundIx->pNext = NULL; // Generate the thread name if (RC_BAD( rc = gv_FlmSysData.pFileSystem->pathReduce( pDb->pFile->pszDbPath, szThreadName, szBaseName))) { goto Exit; } f_sprintf( (char *)szThreadName, "BldIX %u (%s)", (unsigned)uiIndexNum, szBaseName); // Start the thread in the background indexing thread group. // The new thread will cleanup pBackgroundIx on termination. if( RC_BAD( rc = f_threadCreate( NULL, flmBackgroundIndexBuildThrd, szThreadName, gv_uiBackIxThrdGroup, uiIndexNum, (void *)pBackgroundIx, NULL, 24000))) { goto Exit; } Exit: if( RC_BAD( rc) && pBackgroundIx) { f_free( &pBackgroundIx); } return( rc); }
/*************************************************************************** Desc: This routine begins a thread that will do checkpoints for the passed in database. It gives the thread its own FLAIM session and its own handle to the database. *****************************************************************************/ RCODE F_Database::startCPThread( void) { RCODE rc = NE_XFLM_OK; CP_INFO * pCPInfo = NULL; char szThreadName[ F_PATH_MAX_SIZE]; char szBaseName[ 32]; F_SuperFileClient * pSFileClient = NULL; // Allocate a CP_INFO structure that will be passed into the // thread when it is created. if (RC_BAD( rc = f_calloc( (FLMUINT)(sizeof( CP_INFO)), &pCPInfo))) { goto Exit; } pCPInfo->pDatabase = this; // Create a "wait" semaphore if( RC_BAD( rc = f_semCreate( &pCPInfo->hWaitSem))) { goto Exit; } // Allocate a super file handle. if( (pCPInfo->pSFileHdl = f_new F_SuperFileHdl) == NULL) { rc = RC_SET( NE_XFLM_MEM); goto Exit; } if( (pSFileClient = f_new F_SuperFileClient) == NULL) { rc = RC_SET( NE_XFLM_MEM); goto Exit; } if( RC_BAD( rc = pSFileClient->setup( m_pszDbPath, m_pszDataDir, m_uiMaxFileSize))) { goto Exit; } // Set up the super file if( RC_BAD( rc = pCPInfo->pSFileHdl->setup( pSFileClient, gv_XFlmSysData.pFileHdlCache, gv_XFlmSysData.uiFileOpenFlags, gv_XFlmSysData.uiFileCreateFlags))) { goto Exit; } f_memset( &pCPInfo->Stats, 0, sizeof( XFLM_STATS)); pCPInfo->bStatsInitialized = TRUE; // Generate the thread name if (RC_BAD( rc = gv_XFlmSysData.pFileSystem->pathReduce( m_pszDbPath, szThreadName, szBaseName))) { goto Exit; } f_sprintf( (char *)szThreadName, "Checkpoint (%s)", (char *)szBaseName); // Start the checkpoint thread. if (RC_BAD( rc = gv_XFlmSysData.pThreadMgr->createThread( &m_pCPThrd, flmCPThread, szThreadName, gv_XFlmSysData.uiCheckpointThreadGroup, 0, pCPInfo, NULL, 32000))) { goto Exit; } m_pCPInfo = pCPInfo; pCPInfo = NULL; Exit: if( pCPInfo) { flmFreeCPInfo( &pCPInfo); } if( pSFileClient) { pSFileClient->Release(); } return( rc); }
/**************************************************************************** Desc: Copy a database's files, including roll-forward log files. *****************************************************************************/ FSTATIC RCODE flmCopyDb( FLMUINT uiDbVersion, 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; DB_COPY_INFO DbCopyInfo; F_SuperFileHdl * pSrcSFileHdl = NULL; F_SuperFileHdl * pDestSFileHdl = NULL; F_SuperFileClient * pSrcSFileClient = NULL; F_SuperFileClient * pDestSFileClient = NULL; FLMUINT uiFileNumber; FLMUINT uiHighFileNumber; FLMUINT uiHighLogFileNumber; FLMUINT64 ui64FileSize; FFILE * pFile = NULL; FLMBOOL bMutexLocked = FALSE; IF_FileHdl * pLockFileHdl = NULL; IF_FileHdl * pTmpFileHdl = NULL; IF_DirHdl * pDirHdl = NULL; FLMBOOL bFileLocked = FALSE; FLMBOOL bWriteLocked = FALSE; IF_LockObject * pWriteLockObj = NULL; IF_LockObject * pFileLockObj = NULL; COPIED_NAME * pCopiedList = NULL; FLMBOOL bUsedFFile = FALSE; FLMBYTE * pucInMemLogHdr = NULL; eLockType currLockType; FLMUINT uiLockThreadId; char * pszActualSrcRflPath = NULL; char * pszSrcPrefix = NULL; char * pszActualDestRflPath = NULL; char * pszDestPrefix = NULL; FLMBOOL bCreatedDestRflDir = FALSE; F_SEM hWaitSem = F_SEM_NULL; f_memset( &DbCopyInfo, 0, sizeof( DbCopyInfo)); // Should not do anything if the source and destination names // are the same. if (f_stricmp( pszSrcDbName, pszDestDbName) == 0) { goto Exit; } // Allocate a semaphore if( RC_BAD( rc = f_semCreate( &hWaitSem))) { goto Exit; } // Allocate memory for paths we don't want to push onto the stack. if (RC_BAD( rc = f_calloc( (F_PATH_MAX_SIZE + F_FILENAME_SIZE) * 2, &pszActualSrcRflPath))) { goto Exit; } pszSrcPrefix = &pszActualSrcRflPath[ F_PATH_MAX_SIZE]; pszActualDestRflPath = &pszSrcPrefix[ F_FILENAME_SIZE]; pszDestPrefix = &pszActualDestRflPath[ F_PATH_MAX_SIZE]; // Set up the super file object for the source database. // Must at least open the control file. if( (pSrcSFileClient = f_new F_SuperFileClient) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } if( RC_BAD( rc = pSrcSFileClient->setup( pszSrcDbName, pszSrcDataDir, uiDbVersion))) { goto Exit; } if( (pSrcSFileHdl = f_new F_SuperFileHdl) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } if( RC_BAD( rc = pSrcSFileHdl->setup( pSrcSFileClient, gv_FlmSysData.pFileHdlCache, gv_FlmSysData.uiFileOpenFlags, 0))) { goto Exit; } // Lock the destination database, if not already locked. // This is so we can overwrite it without necessarily // deleting it. May unlock and re-lock the global mutex. f_mutexLock( gv_FlmSysData.hShareMutex); bMutexLocked = TRUE; if (RC_BAD( rc = flmFindFile( pszDestDbName, pszDestDataDir, &pFile))) { goto Exit; } // If we didn't find an FFILE structure, get an // exclusive lock on the file. if (!pFile) { f_mutexUnlock( gv_FlmSysData.hShareMutex); bMutexLocked = FALSE; // Attempt to get an exclusive lock on the file. if (RC_BAD( rc = flmCreateLckFile( pszDestDbName, &pLockFileHdl))) { goto Exit; } } else { // The call to flmVerifyFileUse will wait if the file is in // the process of being opened by another thread. if (RC_BAD( rc = flmVerifyFileUse( gv_FlmSysData.hShareMutex, &pFile))) { goto Exit; } // Increment the use count on the FFILE so it will not // disappear while we are copying the file. if (++pFile->uiUseCount == 1) { flmUnlinkFileFromNUList( pFile); } bUsedFFile = TRUE; f_mutexUnlock( gv_FlmSysData.hShareMutex); bMutexLocked = FALSE; pucInMemLogHdr = &pFile->ucLastCommittedLogHdr [0]; // Lock the destination file object and transaction // object, if not already locked. pFile->pFileLockObj->getLockInfo( 0, &currLockType, &uiLockThreadId, NULL); if (currLockType != FLM_LOCK_EXCLUSIVE || uiLockThreadId != f_threadId()) { pFileLockObj = pFile->pFileLockObj; pFileLockObj->AddRef(); if (RC_BAD( rc = pFileLockObj->lock( hWaitSem, TRUE, FLM_NO_TIMEOUT, 0))) { goto Exit; } bFileLocked = TRUE; } // Lock the write object, if not already locked pFile->pWriteLockObj->getLockInfo( 0, &currLockType, &uiLockThreadId, NULL); if( currLockType != FLM_LOCK_EXCLUSIVE || uiLockThreadId != f_threadId()) { pWriteLockObj = pFile->pWriteLockObj; pWriteLockObj->AddRef(); // Only contention here is with the checkpoint thread - wait // forever until the checkpoint thread gives it up. if( RC_BAD( rc = pWriteLockObj->lock( hWaitSem, TRUE, FLM_NO_TIMEOUT, 0))) { goto Exit; } bWriteLocked = TRUE; } } // Set up the super file object for the destination database. if( (pDestSFileClient = f_new F_SuperFileClient) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } if( RC_BAD( rc = pDestSFileClient->setup( pszDestDbName, pszDestDataDir, uiDbVersion))) { goto Exit; } if( (pDestSFileHdl = f_new F_SuperFileHdl) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } if( RC_BAD( rc = pDestSFileHdl->setup( pDestSFileClient, gv_FlmSysData.pFileHdlCache, gv_FlmSysData.uiFileOpenFlags, gv_FlmSysData.uiFileCreateFlags))) { goto Exit; } // See how many files we have and calculate the total size. uiHighFileNumber = 0; for (;;) { if( RC_BAD( rc = pSrcSFileHdl->getFileSize( uiHighFileNumber, &ui64FileSize)) || !ui64FileSize) { if (rc == FERR_IO_PATH_NOT_FOUND || rc == FERR_IO_INVALID_PATH || !ui64FileSize) { // If the control file doesn't exist, we will return // path not found. if (!uiHighFileNumber) { goto Exit; } uiHighFileNumber--; rc = FERR_OK; break; } goto Exit; } DbCopyInfo.ui64BytesToCopy += ui64FileSize; if (uiHighFileNumber == MAX_DATA_BLOCK_FILE_NUMBER( uiDbVersion)) { break; } uiHighFileNumber++; } // See how many rollback log files we have, and calculate // their total size. uiHighLogFileNumber = FIRST_LOG_BLOCK_FILE_NUMBER( uiDbVersion); for (;;) { if ((RC_BAD( rc = pSrcSFileHdl->getFileSize( uiHighLogFileNumber, &ui64FileSize))) || !ui64FileSize) { if (rc == FERR_IO_PATH_NOT_FOUND || rc == FERR_IO_INVALID_PATH || !ui64FileSize) { if (uiHighLogFileNumber == FIRST_LOG_BLOCK_FILE_NUMBER( uiDbVersion)) { uiHighLogFileNumber = 0; } else { uiHighLogFileNumber--; } rc = FERR_OK; break; } goto Exit; } DbCopyInfo.ui64BytesToCopy += ui64FileSize; if (uiHighLogFileNumber == MAX_LOG_BLOCK_FILE_NUMBER( uiDbVersion)) { break; } uiHighLogFileNumber++; } // Get the sizes of the roll-forward log files if( uiDbVersion < FLM_FILE_FORMAT_VER_4_3) { // For pre-4.3 versions, only need to copy one RFL file. if (RC_BAD( rc = rflGetFileName( uiDbVersion, pszSrcDbName, pszSrcRflDir, 1, pszActualSrcRflPath))) { goto Exit; } if( RC_BAD( rc = gv_FlmSysData.pFileSystem->openFile( pszActualSrcRflPath, gv_FlmSysData.uiFileOpenFlags, &pTmpFileHdl))) { if (rc == FERR_IO_PATH_NOT_FOUND || rc == FERR_IO_INVALID_PATH) { rc = FERR_OK; } else { goto Exit; } } else { if (RC_BAD( rc = pTmpFileHdl->size( &ui64FileSize))) { goto Exit; } DbCopyInfo.ui64BytesToCopy += ui64FileSize; pTmpFileHdl->Release(); pTmpFileHdl = NULL; } } else { if( RC_BAD( rc = rflGetDirAndPrefix( uiDbVersion, pszSrcDbName, pszSrcRflDir, pszActualSrcRflPath, pszSrcPrefix))) { goto Exit; } if (RC_BAD( rc = gv_FlmSysData.pFileSystem->openDir( pszActualSrcRflPath, (char *)"*", &pDirHdl))) { goto Exit; } for (;;) { if( RC_BAD( rc = pDirHdl->next())) { if (rc == FERR_IO_NO_MORE_FILES) { rc = FERR_OK; break; } else { goto Exit; } } // If the current file is an RFL file, increment ui64BytesToCopy if( rflGetFileNum( uiDbVersion, pszSrcPrefix, pDirHdl->currentItemName(), &uiFileNumber)) { DbCopyInfo.ui64BytesToCopy += pDirHdl->currentItemSize(); } } pDirHdl->Release(); pDirHdl = NULL; } // Close all file handles in the source and destination pSrcSFileHdl->releaseFiles(); pDestSFileHdl->releaseFiles(); // Copy the database files. for (uiFileNumber = 0; uiFileNumber <= uiHighFileNumber; uiFileNumber++) { // Get the source file path and destination file path. if( RC_BAD( rc = pSrcSFileHdl->getFilePath( uiFileNumber, DbCopyInfo.szSrcFileName))) { goto Exit; } if( RC_BAD( rc = pDestSFileHdl->getFilePath( uiFileNumber, DbCopyInfo.szDestFileName))) { goto Exit; } // For the control file, don't copy first 2K - it will be set up // to show maintenance in progress. Then the first 2K will be copied // later. if (!uiFileNumber) { DbCopyInfo.bNewSrcFile = TRUE; if (RC_BAD( rc = flmCopyFile( gv_FlmSysData.pFileSystem, 2048, 0xFFFFFFFF, &DbCopyInfo, &pCopiedList, pucInMemLogHdr, TRUE, fnStatusCallback, UserData))) { goto Exit; } } else { DbCopyInfo.bNewSrcFile = TRUE; if (RC_BAD( rc = flmCopyFile( gv_FlmSysData.pFileSystem, 0, 0xFFFFFFFF, &DbCopyInfo, &pCopiedList, NULL, TRUE, fnStatusCallback, UserData))) { goto Exit; } } } // Copy the additional rollback log files, if any. for (uiFileNumber = FIRST_LOG_BLOCK_FILE_NUMBER( uiDbVersion); uiFileNumber <= uiHighLogFileNumber; uiFileNumber++) { // Get the source file path and destination file path. if (RC_BAD( rc = pSrcSFileHdl->getFilePath( uiFileNumber, DbCopyInfo.szSrcFileName))) { goto Exit; } if (RC_BAD( rc = pDestSFileHdl->getFilePath( uiFileNumber, DbCopyInfo.szDestFileName))) { goto Exit; } DbCopyInfo.bNewSrcFile = TRUE; if (RC_BAD( rc = flmCopyFile( gv_FlmSysData.pFileSystem, 0, 0xFFFFFFFF, &DbCopyInfo, &pCopiedList, NULL, TRUE, fnStatusCallback, UserData))) { goto Exit; } } // Copy the RFL files if( uiDbVersion < FLM_FILE_FORMAT_VER_4_3) { // Get the source file path and the destination file path. if (RC_BAD( rc = rflGetFileName( uiDbVersion, pszSrcDbName, pszSrcRflDir, 1, DbCopyInfo.szSrcFileName))) { goto Exit; } if (RC_BAD( rc = rflGetFileName( uiDbVersion, pszDestDbName, pszDestRflDir, 1, DbCopyInfo.szDestFileName))) { goto Exit; } DbCopyInfo.bNewSrcFile = TRUE; if (RC_BAD( rc = flmCopyFile( gv_FlmSysData.pFileSystem, 0, 0xFFFFFFFF, &DbCopyInfo, &pCopiedList, NULL, TRUE, fnStatusCallback, UserData))) { goto Exit; } } else { // Create the destination RFL directory, if needed. The purpose of this // code is two-fold: 1) We want to keep track of the fact that we tried // to create the destination RFL directory so we can try to remove it // if the copy fails; 2) If the destination RFL directory path specifies // a directory with existing files, we want to remove them. if( RC_BAD( rc = rflGetDirAndPrefix( uiDbVersion, pszDestDbName, pszDestRflDir, pszActualDestRflPath, pszDestPrefix))) { goto Exit; } if( RC_OK( gv_FlmSysData.pFileSystem->doesFileExist( pszActualDestRflPath))) { if( gv_FlmSysData.pFileSystem->isDir( pszActualDestRflPath)) { // Remove the existing directory and all files, etc. (void)gv_FlmSysData.pFileSystem->removeDir( pszActualDestRflPath, TRUE); } else { (void)gv_FlmSysData.pFileSystem->deleteFile( pszActualDestRflPath); } } // Try to create the destination RFL directory. This might fail if // another process was accessing the directory for some reason // (i.e., from a command prompt), when we tried to remove it above. // We really don't care if the call to CreateDir is sucessful, because // when we try to create the destination files (below), the FLAIM file // file system code will try to create any necessary directories. (void)gv_FlmSysData.pFileSystem->createDir( pszActualDestRflPath); bCreatedDestRflDir = TRUE; // Copy the RFL files. NOTE: We need to copy all of the RFL files // in the source RFL directory so that they will be available // when performing a database restore operation. if (RC_BAD( rc = gv_FlmSysData.pFileSystem->openDir( pszActualSrcRflPath, (char *)"*", &pDirHdl))) { goto Exit; } for (;;) { if( RC_BAD( rc = pDirHdl->next())) { if (rc == FERR_IO_NO_MORE_FILES) { rc = FERR_OK; break; } else { goto Exit; } } // If the current file is an RFL file, copy it to the destination if( rflGetFileNum( uiDbVersion, pszSrcPrefix, pDirHdl->currentItemName(), &uiFileNumber)) { // Get the source file path and the destination file path. if (RC_BAD( rc = rflGetFileName( uiDbVersion, pszSrcDbName, pszSrcRflDir, uiFileNumber, DbCopyInfo.szSrcFileName))) { goto Exit; } if (RC_BAD( rc = rflGetFileName( uiDbVersion, pszDestDbName, pszDestRflDir, uiFileNumber, DbCopyInfo.szDestFileName))) { goto Exit; } DbCopyInfo.bNewSrcFile = TRUE; if (RC_BAD( rc = flmCopyFile( gv_FlmSysData.pFileSystem, 0, 0xFFFFFFFF, &DbCopyInfo, &pCopiedList, NULL, TRUE, fnStatusCallback, UserData))) { goto Exit; } } } pDirHdl->Release(); pDirHdl = NULL; } // Do one final copy on the control file to copy just the first 2K if (RC_BAD( rc = pSrcSFileHdl->getFilePath( 0, DbCopyInfo.szSrcFileName))) { goto Exit; } if (RC_BAD( rc = pDestSFileHdl->getFilePath( 0, DbCopyInfo.szDestFileName))) { goto Exit; } DbCopyInfo.bNewSrcFile = FALSE; if (RC_BAD( rc = flmCopyFile( gv_FlmSysData.pFileSystem, 0, 2048, &DbCopyInfo, NULL, pucInMemLogHdr, FALSE, fnStatusCallback, UserData))) { goto Exit; } Exit: if (bUsedFFile) { if (!bMutexLocked) { f_mutexLock( gv_FlmSysData.hShareMutex); bMutexLocked = TRUE; } if (!(--pFile->uiUseCount)) { flmLinkFileToNUList( pFile); } } if (bMutexLocked) { f_mutexUnlock( gv_FlmSysData.hShareMutex); bMutexLocked = FALSE; } if (bWriteLocked) { if( RC_BAD( rc = pWriteLockObj->unlock())) { goto Exit; } bWriteLocked = FALSE; } if (bFileLocked) { RCODE rc3; if (RC_BAD( rc3 = pFileLockObj->unlock())) { if (RC_OK( rc)) rc = rc3; } bFileLocked = FALSE; } if (pWriteLockObj) { pWriteLockObj->Release(); pWriteLockObj = NULL; } if (pFileLockObj) { pFileLockObj->Release(); pFileLockObj = NULL; } if (pLockFileHdl) { pLockFileHdl->Release(); pLockFileHdl = NULL; } if( pTmpFileHdl) { pTmpFileHdl->Release(); } if( pDirHdl) { pDirHdl->Release(); } // Free all the names of files that were copied. // If the copy didn't finish, try to delete any files // that were copied. while (pCopiedList) { COPIED_NAME * pNext = pCopiedList->pNext; // If the overall copy failed, delete the copied file. if (RC_BAD( rc)) { (void)gv_FlmSysData.pFileSystem->deleteFile( pCopiedList->szPath); } f_free( &pCopiedList); pCopiedList = pNext; } if( RC_BAD( rc) && bCreatedDestRflDir) { (void)gv_FlmSysData.pFileSystem->removeDir( pszActualDestRflPath); } if( pszActualSrcRflPath) { f_free( &pszActualSrcRflPath); } if( hWaitSem != F_SEM_NULL) { f_semDestroy( &hWaitSem); } if( pSrcSFileHdl) { pSrcSFileHdl->Release(); } if( pSrcSFileClient) { pSrcSFileClient->Release(); } if( pDestSFileHdl) { pDestSFileHdl->Release(); } if( pDestSFileClient) { pDestSFileClient->Release(); } return( rc); }
int sys_calloc_hdlr(int n, int size) { return (int)f_calloc(MEM_USER, n, size); }