/****************************************************************************
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);
}
Beispiel #2
0
/****************************************************************************
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);
}
Beispiel #3
0
/****************************************************************************
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);
}
Beispiel #5
0
/****************************************************************************
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);
}	
Beispiel #12
0
/***************************************************************************
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);
}
Beispiel #13
0
/****************************************************************************
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);
}
Beispiel #14
0
int sys_calloc_hdlr(int n, int size)
{
    return (int)f_calloc(MEM_USER, n, size);
}