예제 #1
0
/****************************************************************************
Name:	update
Desc:
*****************************************************************************/
RCODE F_DynamicList::update(
	FLMUINT					uiKey,
	F_DLIST_DISP_HOOK 	pDisplayHook,
	void *					pvData,
	FLMUINT					uiDataLen)
{
	DLIST_NODE *	pTmp;
	RCODE				rc = NE_FLM_OK;

	if( (pTmp = getNode( uiKey)) == NULL)
	{
		rc = insert( uiKey, pDisplayHook, pvData, uiDataLen);
		goto Exit;
	}

	if( !pTmp->pvData || pTmp->uiDataLen != uiDataLen)
	{
		if( pTmp->pvData)
		{
			f_free( &pTmp->pvData);
			pTmp->uiDataLen = 0;
		}

		if( uiDataLen)
		{
			if( RC_BAD( rc = f_alloc( uiDataLen, &pTmp->pvData)))
			{
				goto Exit;
			}
		}
	}

	if( uiDataLen)
	{
		f_memcpy( pTmp->pvData, pvData, uiDataLen);
		pTmp->uiDataLen = uiDataLen;
	}

	m_bChanged = TRUE;

Exit:

	return( rc);
}
예제 #2
0
파일: zutil.c 프로젝트: dborca/mc
FBUF *
f_temp (void)
{
    int fd;
    FBUF *fs;

    fs = f_dopen(0);
    if (fs == NULL) {
	return NULL;
    }

    fd = mc_mkstemps((char **)&fs->name, "mcdiff", NULL);
    if (fd < 0) {
	f_free(fs);
	return NULL;
    }

    fs->fd = fd;
    fs->flags = FILE_FLAG_TEMP;
    return fs;
}
예제 #3
0
파일: malloc.c 프로젝트: brabo/frosted
void* f_realloc(int flags, void* ptr, size_t size)
{
    void * out;
    struct f_malloc_block * blk;

    /* size zero and valid ptr -> act as regular free() */
    if (!size && ptr)
        goto realloc_free;
    
    blk = (struct f_malloc_block *)(((uint8_t*)ptr) - sizeof(struct f_malloc_block));

    if (!ptr)
    {
        /* f ptr is not valid, act as regular malloc() */
        out = f_malloc(flags, size);
    }
    else if (blk->magic == 0xDECEA5ED)
    {
        /* copy over old block, if valid pointer */
        size_t new_size, copy_size;
        if (size > blk->size)
        {
            new_size = size;
            copy_size = blk->size;
        } else {
            new_size = blk->size;
            copy_size = size;
        }
        out = f_malloc(flags, size);

        copy_size = (size > blk->size) ? blk->size : size; // copy smallest of two
        memcpy(out, ptr, copy_size);
    }

realloc_free:
    f_free(ptr);
    return out;
}
예제 #4
0
파일: cdcacher.c 프로젝트: CivilPol/sdcboot
int GetValidDriver(){
    Window    wd;
    Field     fd;
    char      *devName="________";
    int       col=5, row=4, width=15, height=4;
    int       field_col=3, field_row=1;
    int       xkey; /* don't declare lastkey if using f_validate  */

    wd = w_open(col, row, width, height);
    w_umessage(wd,"CD DRIVER");
    w_lmessage(wd,"ESC to Quit");
    fd = f_create("", devName);
    f_validate(fd,ValidateDriverName,DISABLE);
    f_startclear(fd,ENABLE);
    f_return(fd,ENABLE);
    f_setbuffer(fd,cdDriver);
    xkey = f_process(wd, field_col, field_row, fd);
    f_getstring(fd,cdDriver);
    f_free(fd);
    w_close(wd);
    if (xkey == _ESC) return -1;
    else return 0;
}
예제 #5
0
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);
}
예제 #6
0
파일: cdcacher.c 프로젝트: CivilPol/sdcboot
int GetCacheName(){
    Window    wd;
    Field     fd;
    char      *fdData
          ="________________________________________________________________";
    int       col=5, row=4, width=68, height=3;
    int       field_col=1, field_row=1;
    int       xkey;

    wd = w_open(col, row, width, height);
    w_umessage(wd,"Cache File Name");
    w_lmessage(wd,"ESC to Quit");
    fd = f_create("", fdData);
    f_startclear(fd,ENABLE);
    f_return(fd,ENABLE);
    f_setbuffer(fd,CacheName);
    f_validate(fd,ValidateCacheName,DISABLE);
    xkey = f_process(wd, field_col, field_row, fd);
    f_getstring(fd,CacheName);
    f_free(fd);
    w_close(wd);
    if (xkey == _ESC) return -1;
    else return 0;
}
예제 #7
0
/****************************************************************************
Desc:		Renames all files of a database
****************************************************************************/
RCODE F_DbSystem::dbRename(
    const char *			pszDbName,
    // [IN] Database to be renamed.
    const char *			pszDataDir,
    // [IN] Directory for data files.
    const char *			pszRflDir,
    // [IN] RFL directory of database. NULL can be
    // passed to indicate that the log files are located
    // in the same directory as the other database files.
    const char *			pszNewDbName,
    // [IN] New name to be given to the database.  May be
    // the short name only, or include a directory.  If it
    // includes a directory, it must be the same directory
    // as the directory given in pszDbName.
    FLMBOOL					bOverwriteDestOk,
    // [IN] Ok to overwrite existing file with rename?
    IF_DbRenameStatus *	ifpStatus)
// [IN] Status callback function.
{
    RCODE					rc = NE_SFLM_OK;
    FLMUINT				uiFileNumber;
    DBRenameInfo *		pRenameList = NULL;
    FLMBOOL				bFileFound;
    char *				pszOldName = NULL;
    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_alloc( F_PATH_MAX_SIZE * 5, &pszOldName)))
    {
        goto Exit;
    }
    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_SFlmSysData.pFileSystem->pathReduce(
                         pszDbName, pszOldName, szOldBase)))
    {
        goto Exit;
    }
    if (RC_BAD( rc = gv_SFlmSysData.pFileSystem->pathReduce(
                         pszNewDbName, pszNewName, szNewBase)))
    {
        goto Exit;
    }

    // Directories must be the same.

    if (*pszNewName && f_stricmp( pszOldName, pszNewName) != 0)
    {
        rc = RC_SET( NE_SFLM_INVALID_PARM);
        goto Exit;
    }
    f_strcpy( pszNewName, pszOldName);
    if (RC_BAD( rc = gv_SFlmSysData.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_SFlmSysData.pFileSystem->pathAppend(
                             pszOldDataName, szOldBase)))
        {
            goto Exit;
        }
        if (RC_BAD( rc = gv_SFlmSysData.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 = checkDatabaseClosed( pszDbName, pszDataDir)))
    {
        goto Exit;
    }
    if (RC_BAD( rc = checkDatabaseClosed( pszFullNewName, pszDataDir)))
    {
        goto Exit;
    }

    // Start renaming files, beginning with the main DB file.

    if (RC_BAD( rc = flmRenameFile( pszDbName, pszFullNewName,
                                    bOverwriteDestOk, FALSE,
                                    &pRenameList, &bFileFound,
                                    ifpStatus)))
    {
        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,
                                    ifpStatus)))
    {
        goto Exit;
    }

    // Rename block (data) files.

    uiFileNumber = 1;
    for (;;)
    {
        F_SuperFileClient::bldSuperFileExtension( uiFileNumber, pszDataExtOld);
        F_SuperFileClient::bldSuperFileExtension( uiFileNumber, pszDataExtNew);

        if (RC_BAD( rc = flmRenameFile( pszOldDataName, pszNewDataName,
                                        bOverwriteDestOk, TRUE,
                                        &pRenameList, &bFileFound,
                                        ifpStatus)))
        {
            goto Exit;
        }
        if (!bFileFound)
        {
            break;
        }
        if (uiFileNumber == MAX_DATA_BLOCK_FILE_NUMBER)
        {
            break;
        }
        uiFileNumber++;
    }

    // Rename rollback log files.

    uiFileNumber = FIRST_LOG_BLOCK_FILE_NUMBER;
    for (;;)
    {
        F_SuperFileClient::bldSuperFileExtension( uiFileNumber, pszExtOld);
        F_SuperFileClient::bldSuperFileExtension( uiFileNumber, pszExtNew);

        if (RC_BAD( rc = flmRenameFile( pszOldName, pszNewName,
                                        bOverwriteDestOk, TRUE,
                                        &pRenameList, &bFileFound,
                                        ifpStatus)))
        {
            goto Exit;
        }
        if (!bFileFound)
        {
            break;
        }
        if (uiFileNumber == MAX_LOG_BLOCK_FILE_NUMBER)
        {
            break;
        }
        uiFileNumber++;
    }

    // Rename the RFL directory.

    if (RC_BAD( rc = rflGetDirAndPrefix( pszDbName, pszRflDir, pszOldName)))
    {
        goto Exit;
    }

    if (RC_BAD( rc = rflGetDirAndPrefix( pszFullNewName, pszRflDir,
                                         pszNewName)))
    {
        goto Exit;
    }

    if (RC_BAD( rc = flmRenameFile( pszOldName, pszNewName,
                                    bOverwriteDestOk, TRUE,
                                    &pRenameList, &bFileFound,
                                    ifpStatus)))
    {
        goto Exit;
    }

Exit:
    if (pszOldName)
    {
        f_free( &pszOldName);
    }

    // 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_SFlmSysData.pFileSystem->renameFile(
                pRenameFile->Info.szDstFileName, pRenameFile->Info.szSrcFileName);
        }
        f_free( &pRenameFile);
    }
    return( rc);
}
예제 #8
0
/***************************************************************************
Desc: This routine reads the header information for an existing
		flaim database and makes sure we have a valid database.
*****************************************************************************/
RCODE F_Database::readDbHdr(
	const char *			pszDbPath,
	XFLM_DB_STATS *		pDbStats,
	FLMBYTE *				pszPassword,
	FLMBOOL					bAllowLimited)
{
	RCODE						rc = NE_XFLM_OK;
	IF_FileHdl *			pFileHdl = NULL;

	if( RC_BAD( rc = gv_XFlmSysData.pFileSystem->openFile( pszDbPath, 
		gv_XFlmSysData.uiFileOpenFlags, &pFileHdl)))
	{
		goto Exit;
	}

	// Read and verify the database header.

	if (RC_BAD( rc = flmReadAndVerifyHdrInfo( pDbStats, pFileHdl,
									&m_lastCommittedDbHdr)))
	{
		goto Exit;
	}
	
	m_uiBlockSize = (FLMUINT)m_lastCommittedDbHdr.ui16BlockSize;
	m_uiDefaultLanguage = (FLMUINT)m_lastCommittedDbHdr.ui8DefaultLanguage;
	m_uiMaxFileSize = (FLMUINT)m_lastCommittedDbHdr.ui32MaxFileSize;
	m_uiSigBitsInBlkSize = calcSigBits( m_uiBlockSize);

	// Initialize the master database key from the database header
	
	m_bAllowLimitedMode = bAllowLimited;

	if (pszPassword && *pszPassword)
	{
		if (m_pszDbPasswd)
		{
			f_free( &m_pszDbPasswd);
		}

		if ( RC_BAD( rc = f_alloc( 
			(f_strlen( (const char *)pszPassword) + 1), &m_pszDbPasswd)))
		{
			goto Exit;
		}
		
		f_strcpy( (char *)m_pszDbPasswd, (const char *)pszPassword);
	}
	
	if( RC_BAD( rc = flmAllocCCS( &m_pWrappingKey)))
	{
		goto Exit;
	}

	if( RC_OK( rc = m_pWrappingKey->init( TRUE, FLM_NICI_AES)))
	{
		// If the key was encrypted in a password, then the pszPassword parameter better
		// be the key used to encrypt it.  If the key was not encrypted in a password,
		// then pszPassword parameter should be NULL.

		rc = m_pWrappingKey->setKeyFromStore(
								m_lastCommittedDbHdr.DbKey,
								pszPassword, NULL);
	}
	
	if( RC_BAD( rc))
	{
		if ((rc == NE_XFLM_ENCRYPTION_UNAVAILABLE) || bAllowLimited)
		{
			m_bInLimitedMode = TRUE;
			rc = NE_XFLM_OK;
		}
		else
		{
			goto Exit;
		}
	}

	// Note that we might still end up in limited mode if we can't verify all the keys
	// that are stored in the dictionary.

Exit:

	if( pFileHdl)
	{
		pFileHdl->Release();
	}

	return( rc);
}
예제 #9
0
/****************************************************************************
Desc:	Rename a database file and add to list of renamed files.
****************************************************************************/
FSTATIC RCODE flmRenameFile(
    const char *			pszSrcFileName,
    const char *			pszDstFileName,
    FLMBOOL					bOverwriteDestOk,
    FLMBOOL					bPathNotFoundOk,
    DBRenameInfo **		ppRenameList,
    FLMBOOL *				pbFileFound,
    IF_DbRenameStatus *	ifpStatus)
{
    RCODE				rc = NE_SFLM_OK;
    DBRenameInfo *	pRenameFile = NULL;

    *pbFileFound = FALSE;

    // Should not do anything if the source and destination names
    // are the same.

    if (f_stricmp( pszSrcFileName, pszDstFileName) == 0)
    {
        if (gv_SFlmSysData.pFileSystem->doesFileExist(
                    pszSrcFileName) == NE_SFLM_OK)
        {
            *pbFileFound = TRUE;
        }
        goto Exit;
    }

    if (RC_BAD( rc = f_alloc( sizeof( DBRenameInfo), &pRenameFile)))
    {
        goto Exit;
    }

    // If a destination file exists, and it is OK to overwrite
    // it, it must be deleted.

    if (bOverwriteDestOk)
    {
        if (gv_SFlmSysData.pFileSystem->isDir( pszDstFileName))
        {
            if (RC_BAD( rc = gv_SFlmSysData.pFileSystem->removeDir(
                                 pszDstFileName, TRUE)))
            {
                goto Exit;
            }
        }
        else
        {
            if (RC_BAD( rc = gv_SFlmSysData.pFileSystem->deleteFile(
                                 pszDstFileName)))
            {
                if (rc == NE_FLM_IO_PATH_NOT_FOUND || rc == NE_FLM_IO_INVALID_FILENAME)
                {
                    rc = NE_SFLM_OK;
                }
                else
                {
                    goto Exit;
                }
            }
        }
    }

    // If names are the same, no need to actually do the
    // rename.

    if (RC_BAD( rc = gv_SFlmSysData.pFileSystem->renameFile(
                         pszSrcFileName, pszDstFileName)))
    {
        if (rc == NE_FLM_IO_PATH_NOT_FOUND || rc == NE_FLM_IO_INVALID_FILENAME)
        {
            if (bPathNotFoundOk)
            {
                rc = NE_SFLM_OK;
            }
            else
            {
                goto Exit;
            }
        }
        else
        {
            goto Exit;
        }
    }
    else
    {
        *pbFileFound = TRUE;
        pRenameFile->pNext = *ppRenameList;
        *ppRenameList = pRenameFile;

        // Do user callback.  User could choose to stop the rename
        // from continuing.
        if (ifpStatus)
        {
            f_strcpy( pRenameFile->Info.szSrcFileName, pszSrcFileName);
            f_strcpy( pRenameFile->Info.szDstFileName, pszDstFileName);
            if (RC_BAD( rc = ifpStatus->dbRenameStatus(
                                 pRenameFile->Info.szSrcFileName,
                                 pRenameFile->Info.szDstFileName)))
            {
                goto Exit;
            }
        }

        // So it won't get deallocated at exit.

        pRenameFile = NULL;
    }
Exit:
    if (pRenameFile)
    {
        f_free( &pRenameFile);
    }
    return( rc);
}
예제 #10
0
/****************************************************************************
Desc:	Read the ini file and parse its contents
****************************************************************************/
RCODE FTKAPI F_IniFile::read(
	const char *		pszFileName)
{
	RCODE					rc = NE_FLM_OK;
	FLMBOOL				bMore = FALSE;
	FLMBOOL				bEOF = FALSE;
#define INITIAL_READ_BUF_SIZE	100
	FLMUINT				uiReadBufSize = 0;
	FLMUINT				uiBytesAvail = 0;
	FLMUINT				uiBytesInLine = 0;
	char *				pszReadBuf = NULL;
	FLMUINT				uiLineNum = 0;
	IF_FileSystem *	pFileSystem = f_getFileSysPtr();
	
	f_assert( m_bReady);
	f_assert( !m_pFileHdl);

	// Open the file

	if (RC_BAD( rc = f_alloc( f_strlen( pszFileName) + 1, &m_pszFileName)))
	{
		goto Exit;
	}

	f_strcpy( m_pszFileName, pszFileName);

	// It's not an error if the file doesn't exist.  If it does exist,
	// we'll read in its data.
	
	if( RC_BAD( pFileSystem->openFile( pszFileName, 
		FLM_IO_RDONLY, &m_pFileHdl)))
	{		
		goto Exit;
	}

	m_uiFileOffset = 0;

	// Read in and parse the file
	
	uiReadBufSize = INITIAL_READ_BUF_SIZE;
	if (RC_BAD( rc = f_alloc( uiReadBufSize, &pszReadBuf)))
	{
		goto Exit;
	}

	// Read in and parse each line in the file...
	while (!bEOF)
	{
		uiLineNum++;

		uiBytesAvail = uiReadBufSize;
		if( RC_BAD( rc = readLine( pszReadBuf, &uiBytesAvail, &bMore)) &&
			 rc != NE_FLM_IO_END_OF_FILE)
		{
			goto Exit;
		}
		
		if (rc == NE_FLM_IO_END_OF_FILE)
		{
			bEOF = TRUE;
		}
		
		// While there are more bytes in the line, re-alloc the buffer, and do
		// another read.
		
		uiBytesInLine = uiBytesAvail;
		while( bMore)
		{
			uiBytesAvail = uiReadBufSize;
			uiReadBufSize *= 2;

			if (RC_BAD( rc = f_realloc( uiReadBufSize, &pszReadBuf)))
			{
				goto Exit;
			}
			
			if (RC_BAD( rc = readLine( pszReadBuf+uiBytesAvail,
												&uiBytesAvail,	&bMore))	&&
				 (rc != NE_FLM_IO_END_OF_FILE) )
			{
				goto Exit;
			}
			
			if( rc == NE_FLM_IO_END_OF_FILE)
			{
				bEOF = TRUE;
			}
			uiBytesInLine += uiBytesAvail;
		}
		
		if ( (RC_OK( rc) || (rc == NE_FLM_IO_END_OF_FILE)) &&
				(uiBytesInLine > 0) )
		{
			// NumBytes will be 0 if the line was blank.  No need
			// to call parseBuffer in this case
			
			if (RC_BAD( rc = parseBuffer( pszReadBuf, uiBytesInLine)))
			{
				if (rc == NE_FLM_SYNTAX)
				{
					rc = NE_FLM_OK;
				}
				else
				{
					goto Exit;
				}
			}
		}
	}

Exit:

	// Close the file
	
	if( m_pFileHdl)
	{
		m_pFileHdl->closeFile();
		m_pFileHdl->Release();
		m_pFileHdl = NULL;
	}

	// Free the buffer
	
	if (pszReadBuf)
	{
		f_free( &pszReadBuf);
	}

	if (rc == NE_FLM_IO_END_OF_FILE)
	{
		rc = NE_FLM_OK;
	}

	return rc;
}
예제 #11
0
/****************************************************************************
Desc:	This destructor frees all of the structures associated with an
		F_Database object.
		Whoever called this routine has already determined that it is safe
		to do so.
Notes:	The global mutex is assumed to be locked when entering the
			routine.  It may be unlocked and re-locked before the routine
			exits, however.
****************************************************************************/
F_Database::~F_Database()
{
	F_NOTIFY_LIST_ITEM *	pCloseNotifies;
	F_Dict *    			pDict;
	F_Dict *					pTmpDict;

	// At this point, the use count better be zero

	flmAssert( !m_uiOpenIFDbCount);

	// Shut down all background threads before shutting down the CP thread.

	shutdownDatabaseThreads();

	if (m_pRfl)
	{
		m_pRfl->closeFile();
	}

	// Shouldn't have any pending input at this point

	flmAssert( !m_pPendingInput);

	// At this point, the use count better be zero

	flmAssert( !m_uiOpenIFDbCount);

	// Unlock the mutex

	f_mutexUnlock( gv_XFlmSysData.hShareMutex);

	// Shut down the checkpoint thread

	if( m_pCPThrd)
	{
		m_pCPThrd->stopThread();
		m_pCPThrd->Release();
		m_pCPThrd = NULL;
	}

	// Unlink all of the F_Dict objects that are connected to the
	// database.

	lockMutex();
	while (m_pDictList)
	{
		m_pDictList->unlinkFromDatabase();
	}
	unlockMutex();

	// Take the file out of its name hash bucket, if any.

	if (m_uiBucket != 0xFFFF)
	{
		f_mutexLock( gv_XFlmSysData.hShareMutex);
		if (m_pPrev)
		{
			m_pPrev->m_pNext = m_pNext;
		}
		else
		{
			gv_XFlmSysData.pDatabaseHashTbl[ m_uiBucket].pFirstInBucket = m_pNext;
		}

		if (m_pNext)
		{
			m_pNext->m_pPrev = m_pPrev;
		}
		m_uiBucket = 0xFFFF;
		
		// After this point, we should not need to keep the global mutex locked
		// because the F_Database is no longer visible to any thread to find in
		// the hash table.
	
		f_mutexUnlock( gv_XFlmSysData.hShareMutex);
	}
	
	// Shouldn't have any queries at this point.  But we will be nice in case
	// we do and will unlink the queries from the list

	flmAssert( !m_pFirstQuery);
	while (m_pFirstQuery)
	{
		F_Query *	pQuery = m_pFirstQuery;

		m_pFirstQuery = m_pFirstQuery->m_pNext;
		pQuery->m_pPrev = NULL;
		pQuery->m_pNext = NULL;
		pQuery->m_pDatabase = NULL;
	}

	// Free the RFL data, if any.

	if (m_pRfl)
	{
		m_pRfl->Release();
		m_pRfl = NULL;
	}

	flmAssert( m_pOpenNotifies == NULL);
	m_pOpenNotifies = NULL;

	// Save pCloseNotifies -- we will notify any waiters once the
	// F_Database has been freed.

	pCloseNotifies = m_pCloseNotifies;

	// Free any dictionary usage structures associated with the database.

	pDict = m_pDictList;
	while (pDict)
	{
		pTmpDict = pDict;
		pDict = pDict->getNext();
		pTmpDict->Release();
	}
	m_pDictList = NULL;

	// Free any shared cache associated with the database.
	// IMPORTANT NOTE:
	// Cannot have the global mutex locked when these are called because
	// these routines lock the block cache mutex and the node cache mutex.
	// If both the global mutex and the block or node cache mutexes are to be
	// locked, the rule is that the block or node cache mutex must be locked
	// before locking the global mutex.  This is because neededByReadTrans
	// will end up doing it in this order - when neededByReadTrans is called
	// either the block or node cache mutex is already locked, and it will
	// additionally lock the global mutex.  Since that order is already
	// required, we cannot have anyone else attempting to lock the mutexes
	// in a different order.
	
	freeBlockCache();
	freeNodeCache();
	
	// Release the lock objects.

	if (m_pWriteLockObj)
	{
		m_pWriteLockObj->Release();
		m_pWriteLockObj = NULL;
	}

	if (m_pDatabaseLockObj)
	{
		m_pDatabaseLockObj->Release();
		m_pDatabaseLockObj = NULL;
	}

	// Close and delete the lock file.

	if (m_pLockFileHdl)
	{
		(void)m_pLockFileHdl->closeFile();
		m_pLockFileHdl->Release();
		m_pLockFileHdl = NULL;
	}

	// Free the write buffer managers.

	if (m_pBufferMgr)
	{
		m_pBufferMgr->Release();
		m_pBufferMgr = NULL;
	}
	
	// Free the log header write buffer

	if (m_pDbHdrWriteBuf)
	{
		f_freeAlignedBuffer( (void **)&m_pDbHdrWriteBuf);
	}

	// Free the update buffer

	if (m_pucUpdBuffer)
	{
		f_free( &m_pucUpdBuffer);
		m_uiUpdBufferSize = 0;
	}
	
	m_krefPool.poolFree();

	if (m_ppBlocksDone)
	{
		f_free( &m_ppBlocksDone);
		m_uiBlocksDoneArraySize = 0;
	}

	// Notify waiters that the F_Database is gone

	while (pCloseNotifies)
	{
		F_SEM		hSem;

		*(pCloseNotifies->pRc) = NE_XFLM_OK;
		hSem = pCloseNotifies->hSem;
		pCloseNotifies = pCloseNotifies->pNext;
		f_semSignal( hSem);
	}

	f_free( &m_pszDbPath);
	
	// Encryption stuff
	
	if (m_pszDbPasswd)
	{
		f_free( &m_pszDbPasswd);
	}
	
	if (m_pWrappingKey)
	{
		m_pWrappingKey->Release();
		m_pWrappingKey = NULL;
	}
	
	flmAssert( !m_pFirstNode && !m_pLastNode && !m_pLastDirtyNode);
	
	if (m_hMutex != F_MUTEX_NULL)
	{
		f_mutexDestroy( &m_hMutex);
	}
	
	// Global mutex is still expected to be locked at this point
	
	f_mutexLock( gv_XFlmSysData.hShareMutex);
}
예제 #12
0
/****************************************************************************
Desc : Checks for physical corruption in a FLAIM database.
DNote: The routine verifies the database by first reading through
		 the database to count certain block types which are in linked lists.
		 It then verifies the linked lists.  It also verifies the B-TREEs
		 in the database.  The reason for the first pass is so that when we
		 verify the linked lists, we can keep ourselves from getting into
		 an infinite loop if there is a loop in the lists.
****************************************************************************/
RCODE F_DbCheck::dbCheck(
	const char *		pszDbFileName,
		// [IN] Full path and file name of the database which
		// is to be checked.  NULL can be passed as the value of
		// this parameter if pDb is non-NULL.
	const char *		pszDataDir,
		// [IN] Directory for data files.
	const char *		pszRflDir,
		// [IN] RFL directory.  NULL can be passed as the value of
		// this parameter to indicate that the log files are located
		// in the same directory as the database or if pDb is non-NULL.
	const char *		pszPassword,
		// [IN] Database password. Needed to open the database if the database
		// key has been wrapped in a password. NULL by default.
	FLMUINT				uiFlags,
		// [IN] Check flags.  Possible flags include:
		//
		//		XFLM_ONLINE. This flag instructs the check to repair any
		//		index corruptions it finds.  The database must have been
		//		opened in read/write mode in order for the check to
		//		successfully repair corruptions.  An update transaction
		//		will be started whenever a corruption is repaired.
		//
		//		XFLM_DO_LOGICAL_CHECK.  This flag instructs the check to
		//		perform a logical check of the databases's indexes
		//		in addition to the structural check.
		//
		//		XFLM_SKIP_DOM_LINK_CHECK.  This flag instructs the check to skip
		//		verifying the DOM links.  This check can take quite a long time
		//		to execute.
		//
		//		XFLM_ALLOW_LIMITED_MODE. This flag instructs the check to allow
		//		the database to be opened in limited mode if the database key is
		//		wrapped in a password and the password we pass is	incorrect 
		//		(or non-existent).
	IF_DbInfo **			ppDbInfo,
		// [IN] Pointer to a DB_INFO structure which is used to store
		// statistics collected during the database check.
	IF_DbCheckStatus *	pDbCheckStatus
		// [IN] Status interface.  Functions in this interface are called 
		// periodically to iform the calling application of the progress
		// being made.  This allows the application to monitor and/or display
		// the progress of the database check.  NULL may be passed as the
		// value of this parameter if the callback feature is not needed.
	)
{
	RCODE								rc = NE_XFLM_OK;
	FLMBYTE *						pBlk = NULL;
	FLMUINT							uiFileEnd;
	FLMUINT							uiBlockSize;
	FLMUINT							uiLoop;
	FLMUINT64						ui64TmpSize;
	FLMBOOL							bStartOver;
	FLMBOOL							bOkToCloseTrans = FALSE;
	FLMBOOL							bAllowLimitedMode =  ( uiFlags & XFLM_ALLOW_LIMITED_MODE)
																		? TRUE
																		: FALSE;

	if (RC_BAD( rc = gv_pXFlmDbSystem->dbOpen( pszDbFileName, pszDataDir,
		pszRflDir, pszPassword, bAllowLimitedMode, (IF_Db **)&m_pDb)))
	{
		goto Exit;
	}

	if ((m_pDbInfo = f_new F_DbInfo) == NULL)
	{
		rc = RC_SET( NE_XFLM_MEM);
		goto Exit;
	}
	if (ppDbInfo)
	{
		*ppDbInfo = m_pDbInfo;
		(*ppDbInfo)->AddRef();
	}

	m_pDbCheckStatus = pDbCheckStatus;
	m_LastStatusRc = NE_XFLM_OK;

	// Get the file size...

	if (uiFlags & XFLM_SKIP_DOM_LINK_CHECK)
	{
		m_bSkipDOMLinkCheck = TRUE;
	}

	// Initialize the information block and Progress structure.

	// Since we know that the check will start read transactions
	// during its processing, set the flag to indicate that the KRef table
	// should be cleaned up on exit if we are still in a read transaction.

	bOkToCloseTrans = TRUE;
	uiBlockSize = m_pDb->m_pDatabase->getBlockSize();

	// Allocate memory to use for reading through the data blocks.

	if( RC_BAD( rc = f_alloc( uiBlockSize, &pBlk)))
	{
		goto Exit;
	}

	if ((m_pBtPool = f_new F_BtPool) == NULL)
	{
		rc = RC_SET( NE_XFLM_MEM);
		goto Exit;
	}

	if (RC_BAD( rc = m_pBtPool->btpInit()))
	{
		goto Exit;
	}
	
	// Setup the result set database.
	
	if( RC_BAD( rc = FlmAllocRandomGenerator( &m_pRandGen)))
	{
		goto Exit;
	}

	m_pRandGen->setSeed( 9768);

	if (RC_BAD( rc = createAndOpenResultSetDb()))
	{
		goto Exit;
	}

Begin_Check:

	// Initialize all statistics in the DB_INFO structure.

	rc = NE_XFLM_OK;
	bStartOver = FALSE;

	m_pDbInfo->m_ui64FileSize = 0;
	m_pDbInfo->freeLogicalFiles();
	m_bPhysicalCorrupt = FALSE;
	m_bIndexCorrupt = FALSE;
	m_uiFlags = uiFlags;
	m_bStartedUpdateTrans = FALSE;
	f_memset( &m_pDbInfo->m_AvailBlocks, 0, sizeof( BLOCK_INFO));
	f_memset( &m_pDbInfo->m_LFHBlocks, 0, sizeof( BLOCK_INFO));

	f_memset( &m_Progress, 0, sizeof( XFLM_PROGRESS_CHECK_INFO));

	/* Get the dictionary information for the file. */

	if (RC_BAD( rc = getDictInfo()))
	{
		goto Exit;
	}

	m_Progress.ui64BytesExamined = 0;

	for (uiLoop = 1;
		  uiLoop <= MAX_DATA_BLOCK_FILE_NUMBER;
		  uiLoop++)
	{
		if (RC_BAD( m_pDb->m_pSFileHdl->getFileSize( uiLoop, &ui64TmpSize)))
		{
			break;
		}
		
		m_Progress.ui64FileSize += ui64TmpSize;
	}

	// See if we have a valid end of file

	uiFileEnd = m_pDb->m_uiLogicalEOF;
	if (FSGetFileOffset( uiFileEnd) % uiBlockSize != 0)
	{
		if (RC_BAD( rc = chkReportError( FLM_BAD_FILE_SIZE, XFLM_LOCALE_NONE,
			0, 0, 0xFF, (FLMUINT32)uiFileEnd, 0, 0, 0)))
		{
			goto Exit;
		}
	}
	else if (m_Progress.ui64FileSize <
					FSGetSizeInBytes( m_pDb->m_pDatabase-> getMaxFileSize(),
																		uiFileEnd))
	{
		m_Progress.ui64FileSize =
					FSGetSizeInBytes( m_pDb->m_pDatabase->getMaxFileSize(),
																uiFileEnd);
	}

	m_pDbInfo->m_ui64FileSize = m_Progress.ui64FileSize;

	// Verify the LFH blocks, B-Trees, and the AVAIL list.

	if( RC_BAD( rc = verifyLFHBlocks( &bStartOver)))
	{
		goto Exit;
	}
	if (bStartOver)
	{
		goto Begin_Check;
	}

	// Check the b-trees.
	
	if (RC_BAD( rc = verifyBTrees( &bStartOver)))
	{
		goto Exit;
	}
	if (bStartOver)
	{
		goto Begin_Check;
	}

	// Check the avail list.

	if (RC_BAD( rc = verifyAvailList( &bStartOver)))
	{
		goto Exit;
	}
	if (bStartOver)
	{
		goto Begin_Check;
	}

Exit:

	if ((m_bPhysicalCorrupt || m_bIndexCorrupt) &&
		 !gv_pXFlmDbSystem->errorIsFileCorrupt( rc))
	{
		rc = RC_SET( NE_XFLM_DATA_ERROR);
	}

	if (RC_OK( rc) && RC_BAD( m_LastStatusRc))
	{
		rc = m_LastStatusRc;
	}

	if (m_pDb)
	{
		// Close down the transaction, if one is going

		if( bOkToCloseTrans &&
			m_pDb->getTransType( ) == XFLM_READ_TRANS)
		{
			m_pDb->krefCntrlFree();
			m_pDb->transAbort();
		}
	}
	
	// Free memory, if allocated

	if (pBlk)
	{
		f_free( &pBlk);
	}

	// Close the FLAIM database we opened.

	if (m_pDb)
	{
		m_pDb->Release();
		m_pDb = NULL;
	}

	return( rc);
}
예제 #13
0
/********************************************************************
Desc: Edit a field
*********************************************************************/
FLMBOOL ViewEdit(
	FLMBOOL	bWriteEntireBlock
	)
{
	FLMUINT			uiBytesToWrite;
	FLMUINT			uiBytesWritten;
	FLMUINT			uiNum;
	FLMUINT64		ui64Num;
	FLMUINT32		ui32Num;
	FLMUINT16		ui16Num;
	char				szTempBuf[ 100];
	F_BLK_HDR *		pBlkHdr = NULL;
	RCODE				rc;
	FLMUINT			uiFileOffset;
	FLMUINT			uiFileNumber;
	FLMBOOL			bValEntered;
	FLMUINT			uiBytesRead;
	IF_FileHdl *	pFileHdl;
	FLMUINT32		ui32CRC;
	FLMUINT			uiBlockOffset;
	FLMUINT			uiBlkAddress = 0;
	FLMBYTE			ucSENValue[ 9];
	FLMBYTE *		pucSENBuffer = &ucSENValue[0];
	FLMUINT			uiSENLen = 0;

	if ((gv_pViewMenuCurrItem->uiModType & 0xF0) == MOD_DISABLED)
	{
		ViewShowError( "Cannot modify this value");
		return( FALSE);
	}
	uiFileOffset = gv_pViewMenuCurrItem->uiModFileOffset;
	uiFileNumber = gv_pViewMenuCurrItem->uiModFileNumber;

	switch (gv_pViewMenuCurrItem->uiModType & 0x0F)
	{
		case MOD_SEN5:
			// The SEN value is at most 5 bytes.
			ui64Num = 0;
			if (!ViewEditNum( &ui64Num,
						((gv_pViewMenuCurrItem->uiModType & 0xF0) == MOD_HEX), 5,
						~((FLMUINT64)0)))
			{
				return( FALSE);
			}

			// Need to know make a SEN out of this first.
			uiSENLen = f_encodeSEN( ui64Num, &pucSENBuffer);
			break;

		case MOD_SEN9:
			// The SEN value is at most 5 bytes.
			ui64Num = 0;
			if (!ViewEditNum( &ui64Num,
						((gv_pViewMenuCurrItem->uiModType & 0xF0) == MOD_HEX), 9,
						~((FLMUINT64)0)))
			{
				return( FALSE);
			}

			// Need to know make a SEN out of this first.
			uiSENLen = f_encodeSEN( ui64Num, &pucSENBuffer);
			break;

		case MOD_FLMUINT64:
			uiBytesToWrite = 8;
			if (!ViewEditNum( &ui64Num,
						((gv_pViewMenuCurrItem->uiModType & 0xF0) == MOD_HEX), 8,
						~((FLMUINT64)0)))
			{
				return( FALSE);
			}

			if (gv_pViewMenuCurrItem->uiModType & MOD_NATIVE)
			{
				f_memcpy( szTempBuf, &ui64Num, 8);
			}
			else
			{
				U642FBA( ui64Num, (FLMBYTE *)szTempBuf);
			}
			break;
		case MOD_FLMUINT32:
			uiBytesToWrite = 4;
			if (!ViewEditNum( &ui32Num,
						((gv_pViewMenuCurrItem->uiModType & 0xF0) == MOD_HEX), 4,
						(FLMUINT64)0xFFFFFFFF))
			{
				return( FALSE);
			}
			if (gv_pViewMenuCurrItem->uiModType & MOD_NATIVE)
			{
				f_memcpy( szTempBuf, &ui32Num, 4);
			}
			else
			{
				UD2FBA( ui32Num, (FLMBYTE *)szTempBuf);
			}
			break;
		case MOD_FLMUINT16:
			uiBytesToWrite = 2;
			if (!ViewEditNum( &ui16Num,
						((gv_pViewMenuCurrItem->uiModType & 0xF0) == MOD_HEX), 2,
						(FLMUINT64)0xFFFF))
			{
				return( FALSE);
			}
			if (gv_pViewMenuCurrItem->uiModType & MOD_NATIVE)
			{
				f_memcpy( szTempBuf, &ui16Num, 2);
			}
			else
			{
				UW2FBA( ui16Num, (FLMBYTE *)szTempBuf);
			}
			break;
		case MOD_FLMBYTE:
			uiBytesToWrite = 1;
			if (!ViewEditNum( &szTempBuf [0],
					((gv_pViewMenuCurrItem->uiModType & 0xF0) == MOD_HEX), 1,
					(FLMUINT64)0xFF))
			{
				return( FALSE);
			}
			break;
		case MOD_BINARY:
			uiBytesToWrite = gv_pViewMenuCurrItem->uiModBufLen;
			if (HAVE_HORIZ_CUR( gv_pViewMenuCurrItem))
			{
				uiFileOffset += gv_pViewMenuCurrItem->uiHorizCurPos;
				uiBytesToWrite -= gv_pViewMenuCurrItem->uiHorizCurPos;
			}
			if (!ViewEditBinary( NULL, (FLMBYTE *)szTempBuf,
							&uiBytesToWrite, &bValEntered) ||
				 !bValEntered)
			{
				return( FALSE);
			}
			break;
		case MOD_TEXT:
			if (!ViewEditText( "Enter Value: ", 
						szTempBuf, gv_pViewMenuCurrItem->uiModBufLen,
						&bValEntered) ||
				 !bValEntered)
			{
				return( FALSE);
			}
			uiBytesToWrite = gv_pViewMenuCurrItem->uiModBufLen;
			break;
		case MOD_LANGUAGE:
			if( !ViewEditLanguage( &uiNum))
			{
				return( FALSE);
			}
			szTempBuf[0] = (FLMBYTE)uiNum;
			uiBytesToWrite = 1;
			break;
		case MOD_CHILD_BLK:
			if( !ViewEditNum( &uiNum, TRUE, 4, (FLMUINT64)0xFFFFFFFF))
			{
				return( FALSE);
			}
			uiBytesToWrite = 4;
			UD2FBA( (FLMUINT32)uiNum, (FLMBYTE *)szTempBuf);
			break;
		case MOD_BITS:
			if (!ViewEditBits( (FLMBYTE *)&szTempBuf[ 0],
						((gv_pViewMenuCurrItem->uiModType & 0xF0) == MOD_HEX),
						(FLMBYTE)gv_pViewMenuCurrItem->uiModBufLen))
			{
				return( FALSE);
			}
			uiBytesToWrite = 1;
			break;
	}

	// Read in the block if necessary

	if (!bWriteEntireBlock)
	{
		pBlkHdr = (F_BLK_HDR *)(&szTempBuf [0]);
	}
	else
	{
		uiBlockOffset = (FLMUINT)(uiFileOffset %
						(FLMUINT)gv_ViewDbHdr.ui16BlockSize);
		uiBlkAddress = FSBlkAddress( uiFileNumber, 
											uiFileOffset - uiBlockOffset);
		uiFileOffset = uiFileOffset - uiBlockOffset;

		// Don't convert the block if the address is zero - means we
		// are updating the database header.

		if (!ViewBlkRead( uiBlkAddress, &pBlkHdr,
									!uiBlkAddress ? FALSE : TRUE,
									(FLMUINT)gv_ViewDbHdr.ui16BlockSize,
									NULL, NULL, &uiBytesRead, FALSE))
		{
			return( FALSE);
		}

		uiBytesToWrite = uiBytesRead;

		// Convert to native format

		if (!uiBlkAddress)
		{
			if (hdrIsNonNativeFormat( (XFLM_DB_HDR *)pBlkHdr))
			{
				convertDbHdr( (XFLM_DB_HDR *)pBlkHdr);
			}
		}
		else
		{
			if (blkIsNonNativeFormat( pBlkHdr))
			{
				convertBlk( (FLMUINT)gv_ViewDbHdr.ui16BlockSize, pBlkHdr);
			}
		}

		// Put the data in the appropriate place in the block

		if ((gv_pViewMenuCurrItem->uiModType & 0x0F) == MOD_BITS)
		{
			FLMBYTE		ucMask = (FLMBYTE)gv_pViewMenuCurrItem->uiModBufLen;
			FLMBYTE *	pucBuf = (FLMBYTE *)pBlkHdr;

			// Unset the bits, then OR in the new bits

			pucBuf [uiBlockOffset] &= (~(ucMask));
			pucBuf [uiBlockOffset] |= szTempBuf[ 0];
		}
		else if ((gv_pViewMenuCurrItem->uiModType & 0x0F) == MOD_SEN5 ||
					(gv_pViewMenuCurrItem->uiModType & 0x0F) == MOD_SEN9)
		{
			// Need to make sure the size of the original SEN is the same as the
			// new SEN.
			const FLMBYTE *	pucOrigSEN = (FLMBYTE *)pBlkHdr + uiBlockOffset;
			FLMBYTE				ucBuffer[9];
			FLMBYTE *			pucBuffer = &ucBuffer[0];
			FLMUINT64			ui64Value;
			FLMUINT				uiOrigSENLen;

			if (RC_BAD( rc = f_decodeSEN64( &pucOrigSEN,
													 (FLMBYTE *)pBlkHdr +
															gv_ViewDbHdr.ui16BlockSize,
													 &ui64Value)))
			{
				ViewShowRCError( "Decoding original SEN value", rc);
			}
			uiOrigSENLen = f_encodeSEN( ui64Value, &pucBuffer);

			if (uiOrigSENLen != uiSENLen)
			{
				ViewShowRCError( "SEN Length does not match original",
									  NE_XFLM_FAILURE);
			}
			else
			{
				f_memcpy( (FLMBYTE *)pBlkHdr + uiBlockOffset, ucSENValue,
							uiSENLen);
			}
		}
		else
		{
			f_memcpy( (FLMBYTE *)pBlkHdr + uiBlockOffset, szTempBuf,
							uiBytesToWrite);
		}

		// Calculate CRC

		if (!uiBlkAddress)
		{
			ui32CRC = calcDbHdrCRC( (XFLM_DB_HDR *)pBlkHdr);
			((XFLM_DB_HDR *)pBlkHdr)->ui32HdrCRC = ui32CRC;
			uiBytesToWrite = sizeof( XFLM_DB_HDR);
		}
		else
		{
			FLMUINT	uiBlkLen;
			uiBlkLen = gv_ViewDbHdr.ui16BlockSize;

#if 0
			if ((FLMUINT)pBlkHdr->ui16BlkBytesAvail >
					(FLMUINT)gv_ViewDbHdr.ui16BlockSize - blkHdrSize( pBlkHdr))
			{
				uiBlkLen = blkHdrSize( pBlkHdr);
			}
			else
			{
				uiBlkLen = (FLMUINT)(gv_ViewDbHdr.ui16BlockSize - 
											pBlkHdr->ui16BlkBytesAvail);
			}
#endif
			// Calculate and set the block CRC.

			ui32CRC = calcBlkCRC( pBlkHdr, uiBlkLen);
			pBlkHdr->ui32BlkCRC = ui32CRC;
		}
	}
	
	if (RC_BAD( rc = gv_pSFileHdl->getFileHdl( uiFileNumber, TRUE, &pFileHdl)))
	{
		ViewShowRCError( "getting file handle", rc);
	}

	// Write the data out to the file

	else if (RC_BAD( rc = pFileHdl->write( uiFileOffset, uiBytesToWrite,
							pBlkHdr, &uiBytesWritten)))
	{
		ViewShowRCError( "updating file", rc);
	}
	else if (RC_BAD( rc = pFileHdl->flush()))
	{
		ViewShowRCError( "flushing data to file", rc);
	}
	else if (bWriteEntireBlock && !uiBlkAddress)
	{
		f_memcpy( &gv_ViewDbHdr, pBlkHdr, sizeof( XFLM_DB_HDR));
	}

	// Free any memory used to read in the data block

	if (pBlkHdr && pBlkHdr != (F_BLK_HDR *)(&szTempBuf [0]))
	{
		f_free( &pBlkHdr);
	}
	return( TRUE);
}
예제 #14
0
/****************************************************************************
Desc:	Prints the web page for the SCacheHashTable
****************************************************************************/
RCODE F_SCacheHashTablePage::display(
	FLMUINT			uiNumParams,
	const char ** 	ppszParams)
{
	RCODE			rc = FERR_OK;
	FLMBOOL		bRefresh;
	FLMBOOL		bHighlight = TRUE;
  	FLMUINT		uiLoop;
	FLMUINT		uiHashTableSize;
	FLMUINT		uiUsedEntries = 0;
	char			szStart[10];
	char			szRefresh[] = "&Refresh";
	FLMUINT		uiStart;
	FLMUINT		uiNewStart;
	char *		pszTemp;
#define NUM_ENTRIES 20
	char *		pszHTLinks[NUM_ENTRIES];

	F_UNREFERENCED_PARM( uiNumParams);
	F_UNREFERENCED_PARM( ppszParams);

	// Check for the refresh parameter
	
	bRefresh = DetectParameter( uiNumParams, ppszParams, "Refresh");
	if (!bRefresh)
	{
		szRefresh[0]='\0';  // Effectively turns szRefresh into a null string
	}

	// Get the starting entry number...
	if (RC_BAD( rc = ExtractParameter( uiNumParams, ppszParams,
												  "Start", sizeof( szStart),
												  szStart)))
	{  
		flmAssert( 0);  
		goto Exit;
	}
	uiStart = f_atoud( szStart);

	// Allocate space for the hyperlink text
	for (uiLoop = 0; uiLoop < NUM_ENTRIES; uiLoop++)
	{
		if( RC_BAD( rc = f_alloc( 250, &pszHTLinks[ uiLoop])))
		{
			printErrorPage( rc, TRUE, (char *)"Failed to allocate temporary buffer");
			goto Exit;
		}

		pszHTLinks[uiLoop][0] = '\0';
	}

	if( RC_BAD( rc = f_alloc( 250, &pszTemp)))
	{
		printErrorPage( rc, TRUE, (char *)"Failed to allocate temporary buffer");
		goto Exit;
	}

	// Lock the database
	f_mutexLock( gv_FlmSysData.hShareMutex);

	// Get the number of entries in the hash table
	uiHashTableSize = gv_FlmSysData.SCacheMgr.uiHashTblSize;
	
	// May need to modify starting number if it's out of range...
	if ((uiStart + NUM_ENTRIES) >= uiHashTableSize)
	{
		uiStart = uiHashTableSize - NUM_ENTRIES;
	}


	// Loop through the entire table counting the number of entries in use
	// If the entry is one of the one's we're going to display, store the 
	// appropriate text in pszHTLinks
	for (uiLoop = 0; uiLoop < uiHashTableSize; uiLoop++)
	{
		if (gv_FlmSysData.SCacheMgr.ppHashTbl[uiLoop])
		{
			uiUsedEntries++;
		}

		if (	(uiLoop >= uiStart) &&
				(uiLoop < (uiStart + NUM_ENTRIES)) )
		{
			// This is one of the entries that we will display
			if (gv_FlmSysData.SCacheMgr.ppHashTbl[uiLoop])
			{
				flmBuildSCacheBlockString( pszHTLinks[uiLoop - uiStart], 
					gv_FlmSysData.SCacheMgr.ppHashTbl[uiLoop]);
			}

		}


	}

	// Unlock the database
	f_mutexUnlock( gv_FlmSysData.hShareMutex);

	// Begin rendering the page...
	stdHdr();

	printStyle();
	fnPrintf( m_pHRequest, HTML_DOCTYPE "<html>\n");

	// Determine if we are being requested to refresh this page or  not.

	if (bRefresh)
	{
		fnPrintf( m_pHRequest, 
			"<HEAD>"
			"<META http-equiv=\"refresh\" content=\"5; url=%s/SCacheHashTable?Start=%lu%s\">"
			"<TITLE>Database iMonitor - SCache Hash Table</TITLE>\n", m_pszURLString, uiStart, szRefresh);
	
	}
	else
	{
		fnPrintf( m_pHRequest, "<HEAD>\n");
	}


	// If we are not to refresh this page, then don't include the
	// refresh meta command
	if (!bRefresh)
	{
		f_sprintf( (char *)pszTemp,
			       "<A HREF=%s/SCacheHashTable?Start=%lu&Refresh>Start Auto-refresh (5 sec.)</A>",
					 m_pszURLString, uiStart);
	}
	else
	{
		f_sprintf( (char *)pszTemp,
			       "<A HREF=%s/SCacheHashTable?Start=%lu>Stop Auto-refresh</A>",
					 m_pszURLString, uiStart);
	}

	// Print out a formal header and the refresh option.
	printTableStart("SCache Hash Table", 4);

	printTableRowStart();
	printColumnHeading( "", JUSTIFY_LEFT, FLM_IMON_COLOR_PUTTY_1, 4, 1, FALSE);
	fnPrintf( m_pHRequest,
				 "<A HREF=%s/SCacheHashTable?Start=%lu%s>Refresh</A>, %s\n",
				 m_pszURLString, uiStart, szRefresh, pszTemp);
	printColumnHeadingClose();
	printTableRowEnd();
		
	printTableRowStart( (bHighlight = !bHighlight));
	fnPrintf( m_pHRequest, "<TD>Table Size: %lu </TD>\n", uiHashTableSize);
	printTableRowEnd();

	printTableRowStart( (bHighlight = !bHighlight));
	fnPrintf( m_pHRequest, "<TD>Entries Used: %lu (%lu%%) </TD>\n", uiUsedEntries,
				 ((uiUsedEntries * 100) / uiHashTableSize) );
	printTableRowEnd();
	
	// The rest of the table is going to be a single row with two columns:  
	// one for the list of hash buckets and the other for everything else

	printTableRowStart( FALSE);
	fnPrintf( m_pHRequest, " <TD>\n");
	// Print out the hash buckets
	for (uiLoop = 0; uiLoop < NUM_ENTRIES; uiLoop++)
	{
		if (pszHTLinks[uiLoop][0] != '\0')
		{
			fnPrintf( m_pHRequest, "<A HREF=%s%s>%lu</A> <br>\n",
						 pszHTLinks[uiLoop], szRefresh, uiStart+uiLoop);
		}
		else
		{
			fnPrintf( m_pHRequest, "%lu<br>\n", uiStart+uiLoop);
		}
	}

	fnPrintf( m_pHRequest, "</ul>\n</TD>\n<TD>\n");

	// Print out the other stuff...
	uiNewStart = (uiStart > 100)?(uiStart - 100):0;
	fnPrintf( m_pHRequest, "<A HREF=%s/SCacheHashTable?Start=%lu%s>Previous 100</A> <BR>\n",
					m_pszURLString, uiNewStart, szRefresh);
	uiNewStart = (uiStart > 10)?(uiStart - 10):0;
	fnPrintf( m_pHRequest, "<A HREF=%s/SCacheHashTable?Start=%lu%s>Previous 10</A> <BR>\n",
					m_pszURLString, uiNewStart, szRefresh);

	fnPrintf( m_pHRequest, "<BR>\n");
	uiNewStart = (uiStart + 10);
	if (uiNewStart >= (uiHashTableSize - NUM_ENTRIES))
	{
		uiNewStart = (uiHashTableSize - NUM_ENTRIES);
	}
	fnPrintf( m_pHRequest, "<A HREF=%s/SCacheHashTable?Start=%lu%s>Next 10</A> <BR>\n",
					m_pszURLString, uiNewStart, szRefresh);

	uiNewStart = (uiStart + 100);
	if (uiNewStart >= (uiHashTableSize - NUM_ENTRIES))
	{
		uiNewStart = (uiHashTableSize - NUM_ENTRIES);
	}
	fnPrintf( m_pHRequest, "<A HREF=%s/SCacheHashTable?Start=%lu%s>Next 100</A> <BR>\n"
				"<form type=\"submit\" method=\"get\" action=\"/coredb/SCacheHashTable\">\n"
				"<BR> Jump to specific bucket:<BR> \n"
				"<INPUT type=\"text\" size=\"10\" maxlength=\"10\" name=\"Start\"></INPUT> <BR>\n",
				m_pszURLString, uiNewStart, szRefresh);
	printButton( "Jump", BT_Submit);
	// We use a hidden field to pass the refresh parameter back the the server
	if (bRefresh)
	{
		fnPrintf( m_pHRequest, "<INPUT type=\"hidden\" name=\"Refresh\"></INPUT>\n");
	}
	fnPrintf( m_pHRequest, "</form>\n</TD>\n");

	printTableRowEnd();

	printTableEnd();
	printDocEnd();
	fnEmit();

Exit:
	// Free the space for the hyperlink text
	for (uiLoop = 0; uiLoop < NUM_ENTRIES; uiLoop++)
	{
		f_free( &pszHTLinks[uiLoop]);
	}

	f_free( &pszTemp);
	return( rc);

}
예제 #15
0
void main()
{
	setlocale(LC_ALL, "Russian");
	struct der *dr;
	dr = NULL;
	int flag = 0, sh, i;
	FILE *file;

	GG = (struct der **)calloc(M, sizeof(struct der *));

	while (1)
	{
		puts("Выбирите вид операции:");
		puts("	1 - Создать дерево");//
		puts("	2 - Загрузить дерево из файла");
		puts("	3 - Вывод содержимого дерева");//
		puts("	4 - Добавление элемента в дерево");//
		puts("	5 - Удаление элемента из дерева");//
		puts("	6 - Полное удалнение (очистка) дерева");//
		puts("	7 - Сорханить в файл");//
		puts("	8 - Удалить все до определенной даты");//
		puts("	9 - Выход");
		do
		{
			//fflush(stdin);
			__fpurge(stdin);
			if (!scanf("%d", &flag) || (flag < 1) || (flag > 9))
			{
				puts("Ошибка ввода. Введите заново");
			}
		} while (!flag || (flag < 1) || (flag > 9));

		switch (flag)
		{
		case 1: dr = sozd(dr); break;
		case 2: 
		{
			file = fopen("file.txt", "r");
			if (!file)
			{
				puts("Файл не найден");
				break;
			}
			fscanf(file, "%d", &GP);
			
			if (dr || GP == 0)
			{
				fclose(file);
				puts("Бинарное дерево уже создано");
				break;
			}
			dr = read(dr, file);
			sh = 1;
			while (sh != GP)
			{
				read_add(dr, file);
				sh++;
			}
			
			fclose(file);
			break;
		}
		case 3: see(dr); puts("Если пусто, то элементы дерева удалены, добавте."); break;
		case 4: add(dr); break;
		case 5: del(dr); break;
		case 6: f_free(dr); dr = NULL; break;
		case 7:
		{
			file = fopen("file.txt", "w");
			fprintf(file, "%d\r\n\r\n", GP);
			save(dr, file);
			fclose(file);
			break;
		}
		case 8: del_op(dr); break;
		case 9: f_free(dr); free(GG); return;
		}
	}
}
예제 #16
0
/****************************************************************************
Desc:	Prints the web page showing the binary data in an SCache block
****************************************************************************/
RCODE F_SCacheDataPage::display( 
	FLMUINT			uiNumParams,
	const char ** 	ppszParams)
{
	RCODE			rc = FERR_OK;

	FLMUINT		uiBlkAddress = 0;
	FLMUINT		uiLowTransID = 0;
	FLMUINT		uiHighTransID = 0;
	FFILE *		pFile = NULL;
	FLMBOOL		bFlaimLocked = FALSE;
	SCACHE		LocalSCacheBlock;
	char *		pucData = NULL;
	char *		pucDataLine;
	char			szData[97];
	char			szOneChar[7];
	FLMUINT		uiCurrentOffset = 0;
	FLMUINT		uiLoop = 0;
	
	f_mutexLock( gv_FlmSysData.hShareMutex);
	bFlaimLocked = TRUE;
	rc = locateSCacheBlock( uiNumParams, ppszParams, &LocalSCacheBlock,
									&uiBlkAddress, &uiLowTransID,	&uiHighTransID,
									&pFile);
	if (RC_BAD( rc))
	{
		if(rc == FERR_NOT_FOUND)
		{
			notFoundErr();
			rc = FERR_OK;
		}
		goto Exit;
	}
	else
	{
		// Store the data in a local variable...
		if( RC_BAD( rc = f_alloc( 
			LocalSCacheBlock.ui16BlkSize, &pucData)))
		{
			goto Exit;
		}

		f_memcpy( pucData, LocalSCacheBlock.pucBlk, LocalSCacheBlock.ui16BlkSize);
	}

	f_mutexUnlock( gv_FlmSysData.hShareMutex);
	bFlaimLocked = FALSE;

	// Start the HTML...
	
	stdHdr();
	fnPrintf( m_pHRequest, HTML_DOCTYPE 
				"<HTML> <BODY>\n<font face=arial><PRE>\n");

	while (uiCurrentOffset < LocalSCacheBlock.ui16BlkSize)
	{
		szData[0] = '\0';
		pucDataLine =  pucData + uiCurrentOffset;
		fnPrintf( m_pHRequest, "<font color=blue>0x%04X</font>    "
						"%02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X    ",
						uiCurrentOffset,
						pucDataLine[ 0], pucDataLine[ 1], pucDataLine[ 2], pucDataLine[ 3],
						pucDataLine[ 4], pucDataLine[ 5], pucDataLine[ 6], pucDataLine[ 7],
						pucDataLine[ 8], pucDataLine[ 9], pucDataLine[10], pucDataLine[11],
						pucDataLine[12], pucDataLine[13], pucDataLine[14], pucDataLine[15]);
	
		for (uiLoop = 0; uiLoop < 16; uiLoop++)
		{
			if (	(pucDataLine[uiLoop] >= 32) &&  // 32 is a space
					(pucDataLine[uiLoop] <= 126)  ) // 126 is a ~
			{
				f_sprintf( szOneChar, "&#%d;", pucDataLine[uiLoop]);
			}
			else
			{
				f_strcpy( szOneChar, "&#46;"); // 46 is a .
			}
			f_strcat(szData, szOneChar);

			// The reason for all the &#xxx; nonsence is because if we just put
			// the characters into a string, when the brower comes across a <
			// character, it will try to interpret what follows as an HTML
			// tag...
		}

		fnPrintf( m_pHRequest, "<font color=green>%s</font>\n", szData);
		
		uiCurrentOffset += 16;
	}

	fnPrintf( m_pHRequest, "</PRE></font>\n</BODY> </HTML>\n");
	fnEmit();

Exit:
	if (bFlaimLocked)
	{
		f_mutexUnlock( gv_FlmSysData.hShareMutex);
	}

	if (pucData)
	{
		f_free( &pucData);
	}

	return( rc);
}
예제 #17
0
/****************************************************************************
Desc:	Prints the web page for an SCACHEMGR struct
		(The URL for this page requires no parameters since there is only
		one SCACHE_MGR per copy of FLAIM.)
****************************************************************************/
RCODE F_SCacheMgrPage::display(
	FLMUINT			uiNumParams,
	const char ** 	ppszParams)
{
	RCODE			rc = FERR_OK;
	SCACHE_MGR	LocalSCacheMgr;
	FLMBOOL		bAutoRefresh;
#define NUM_CACHE_REQ_STRINGS			4
	char	*		pszSCacheRequestString[ NUM_CACHE_REQ_STRINGS];
	char			szOffsetTable[12][6];
	char			szAddressTable[2][20];
	FLMBOOL		bHighlight = FALSE;
	char *		pszTemp = NULL;
	FLMUINT		uiLoop;

	// Note: The SCacheBlock requests need the following params:
	// "BlockAddress", "File", "LowTransID" and "HighTransID"
	// ex:  <A href="SCacheBlock?BlockAddress=100?File=5?LowTransID=30?HighTransID=100"> pMRUCache </A>
	
	if( RC_BAD( rc = f_alloc( 200, &pszTemp)))
	{
		printErrorPage( rc, TRUE, (char *)"Failed to allocate temporary buffer");
		goto Exit;
	}

	// First thing that we need to do is grab a local copy of gv_FlmSysData.SCacheMgr,
	// and of the data for the three SCache blocks that it has pointers to...
	for (uiLoop = 0; uiLoop < NUM_CACHE_REQ_STRINGS; uiLoop++)
	{
		if( RC_BAD( rc = f_alloc( 150,
									&pszSCacheRequestString[ uiLoop])))
		{
			printErrorPage( rc, TRUE, (char *)"Failed to allocate temporary buffer");
			goto Exit;
		}
	}
	f_mutexLock( gv_FlmSysData.hShareMutex);
	f_memcpy (&LocalSCacheMgr, &gv_FlmSysData.SCacheMgr, sizeof (LocalSCacheMgr));
	flmBuildSCacheBlockString( pszSCacheRequestString[0], LocalSCacheMgr.pMRUCache);
	flmBuildSCacheBlockString( pszSCacheRequestString[1], LocalSCacheMgr.pLRUCache);
	flmBuildSCacheBlockString( pszSCacheRequestString[2], LocalSCacheMgr.pFirstFree);
	flmBuildSCacheBlockString( pszSCacheRequestString[3], LocalSCacheMgr.pLastFree);
	f_mutexUnlock( gv_FlmSysData.hShareMutex);

	bAutoRefresh = DetectParameter( uiNumParams, ppszParams, "Refresh");

	// Now - are we being asked to display the usage stats?  Or is this a regular page...
	if (DetectParameter( uiNumParams, ppszParams, "Usage"))
	{
		// There's a function to handle display the usage info (because both
		// RCacheMgr and SCacheMgr have usage stats).
		writeUsage( &LocalSCacheMgr.Usage, bAutoRefresh,
						"/SCacheMgr?Usage",
						"Usage Statistics for the SCache");
	}
	else // This is a regular SCacheMgr page...
	{
		// Determine if we are being requested to refresh this page or  not.

		stdHdr();

		fnPrintf( m_pHRequest, HTML_DOCTYPE "<HTML>\n");

		if (bAutoRefresh)
		{
			// Send back the page with a refresh command in the header

			fnPrintf( m_pHRequest, 
				"<HEAD>"
				"<META http-equiv=\"refresh\" content=\"5; url=%s/SCacheMgr?Refresh\">"
				"<TITLE>gv_FlmSysData.SCacheMgr</TITLE>\n", m_pszURLString);

			printStyle();
			popupFrame();  //Spits out a Javascript function that will open a new window..
	
			fnPrintf( m_pHRequest, "\n</HEAD>\n<body>\n");


			f_sprintf( (char *)pszTemp,
							"<A HREF=%s/SCacheMgr>Stop Auto-refresh</A>", m_pszURLString);
		}
		else  // bAutoRefresh == FALSE
		{
			// Send back a page without the refresh command
			fnPrintf( m_pHRequest, 
				"<HEAD>"
				"<TITLE>gv_FlmSysData.SCacheMgr</TITLE>\n");

			printStyle();
			popupFrame();  //Spits out a Javascript function that will open a new window..
	
			fnPrintf( m_pHRequest, "\n</HEAD>\n<body>\n");

			f_sprintf( (char *)pszTemp,
						"<A HREF=%s/SCacheMgr?Refresh>Start Auto-refresh (5 sec.)</A>",
						m_pszURLString);
		}

		// Write out the table headings
		printTableStart( "SCache Manager Structure", 4);

		printTableRowStart();
		printColumnHeading( "", JUSTIFY_LEFT, FLM_IMON_COLOR_PUTTY_1, 4, 1, FALSE);
		fnPrintf( m_pHRequest, "<A HREF=%s/SCacheMgr>Refresh</A>, %s\n", m_pszURLString, pszTemp);
		printColumnHeadingClose();
		printTableRowEnd();

		// Write out the table headings.
		printTableRowStart();
		printColumnHeading( "Byte Offset (hex)");
		printColumnHeading( "Field Name");
		printColumnHeading( "Field Type");
		printColumnHeading( "Value");
		printTableRowEnd();
	
		//Now - we have three rows in the table that may or may not have hyperlinks in them.  
		printTableRowStart( bHighlight = ~bHighlight);
		flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[0], "pMRUCache", &LocalSCacheMgr, &LocalSCacheMgr.pMRUCache);
		printTableRowStart( bHighlight = ~bHighlight);
		flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[1], "pLRUCache", &LocalSCacheMgr, &LocalSCacheMgr.pLRUCache);
		printTableRowStart( bHighlight = ~bHighlight);
		flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[2], "pFirstFree", &LocalSCacheMgr, &LocalSCacheMgr.pFirstFree);
		printTableRowStart( bHighlight = ~bHighlight);
		flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[3], "pLastFree", &LocalSCacheMgr, &LocalSCacheMgr.pLastFree);

		//Format the strings that are displayed in the Offset column on of the table
		printOffset(&LocalSCacheMgr, &LocalSCacheMgr.ppHashTbl, szOffsetTable[0]);
		printOffset(&LocalSCacheMgr, &LocalSCacheMgr.Usage, szOffsetTable[1]);
		printOffset(&LocalSCacheMgr, &LocalSCacheMgr.bAutoCalcMaxDirty, szOffsetTable[2]);
		printOffset(&LocalSCacheMgr, &LocalSCacheMgr.uiMaxDirtyCache, szOffsetTable[3]);
		printOffset(&LocalSCacheMgr, &LocalSCacheMgr.uiLowDirtyCache, szOffsetTable[4]);
		printOffset(&LocalSCacheMgr, &LocalSCacheMgr.uiTotalUses, szOffsetTable[5]);
		printOffset(&LocalSCacheMgr, &LocalSCacheMgr.uiBlocksUsed, szOffsetTable[6]);
		printOffset(&LocalSCacheMgr, &LocalSCacheMgr.uiPendingReads, szOffsetTable[7]);
		printOffset(&LocalSCacheMgr, &LocalSCacheMgr.uiIoWaits, szOffsetTable[8]);
		printOffset(&LocalSCacheMgr, &LocalSCacheMgr.uiHashTblSize, szOffsetTable[9]);
		printOffset(&LocalSCacheMgr, &LocalSCacheMgr.uiHashTblBits, szOffsetTable[10]);
#ifdef FLM_DEBUG
		printOffset(&LocalSCacheMgr, &LocalSCacheMgr.bDebug, szOffsetTable[11]);
#endif


		printAddress( LocalSCacheMgr.ppHashTbl, szAddressTable[0]);
		printAddress( &LocalSCacheMgr.Usage, szAddressTable[1]);

		printTableRowStart( bHighlight = ~bHighlight);
		fnPrintf( m_pHRequest, TD_s
				"<td><A HREF=\"%s/SCacheHashTable?Start=0\">ppHashTbl</A></td>\n"
				"<td>SCACHE **</td>\n"
				"<td><A href=\"%s/SCacheHashTbl\">%s</A></td>\n",
				szOffsetTable[0], m_pszURLString, m_pszURLString, szAddressTable[0]);
		printTableRowEnd();

		printTableRowStart( bHighlight = ~bHighlight);
		fnPrintf( m_pHRequest, TD_s
			"<td><A href=\"javascript:openPopup('%s/SCacheMgr?Usage')\">Usage</A></td>\n"
			"<td>FLM_CACHE_USAGE</td>\n"
			"<td><A href=\"javascript:openPopup('%s/SCacheMgr?Usage')\">%s</A></td>\n",
			szOffsetTable[1], m_pszURLString, m_pszURLString, szAddressTable[1]);
		printTableRowEnd();

		// uiFreeCount
		printHTMLUint(
			(char *)"uiFreeCount",
			(char *)"FLMUINT",
			(void *)&LocalSCacheMgr,
			(void *)&LocalSCacheMgr.uiFreeCount,
			LocalSCacheMgr.uiFreeCount,
			(bHighlight = ~bHighlight));

		// uiFreeBytes
		printHTMLUint(
			(char *)"uiFreeBytes",
			(char *)"FLMUINT",
			(void *)&LocalSCacheMgr,
			(void *)&LocalSCacheMgr.uiFreeBytes,
			LocalSCacheMgr.uiFreeBytes,
			(bHighlight = ~bHighlight));

		// uiReplaceableCount
		printHTMLUint(
			(char *)"uiReplaceableCount",
			(char *)"FLMUINT",
			(void *)&LocalSCacheMgr,
			(void *)&LocalSCacheMgr.uiReplaceableCount,
			LocalSCacheMgr.uiReplaceableCount,
			(bHighlight = ~bHighlight));

		// uiReplaceableBytes
		printHTMLUint(
			(char *)"uiReplaceableBytes",
			(char *)"FLMUINT",
			(void *)&LocalSCacheMgr,
			(void *)&LocalSCacheMgr.uiReplaceableBytes,
			LocalSCacheMgr.uiReplaceableBytes,
			(bHighlight = ~bHighlight));

		printTableRowStart( bHighlight = ~bHighlight);
		fnPrintf( m_pHRequest, TD_s "<td>bAutoCalcMaxDirty</td>\n"
						"<td>FLMBOOL</td>\n" TD_i, szOffsetTable[2],
						LocalSCacheMgr.bAutoCalcMaxDirty);
		printTableRowEnd();

		printTableRowStart( bHighlight = ~bHighlight);
		fnPrintf( m_pHRequest, TD_s "<td>uiMaxDirtyCache</td>\n"
						"<td>FLMUINT</td>\n" TD_lu, szOffsetTable[3],
						LocalSCacheMgr.uiMaxDirtyCache);
		printTableRowEnd();

		printTableRowStart( bHighlight = ~bHighlight);
		fnPrintf( m_pHRequest, TD_s "<td>uiLowDirtyCache</td>\n"
						"<td>FLMUINT</td>\n" TD_lu, szOffsetTable[4],
						LocalSCacheMgr.uiLowDirtyCache);
		printTableRowEnd();

		printTableRowStart( bHighlight = ~bHighlight);
		fnPrintf( m_pHRequest, TD_s "<td>uiTotalUses</td>\n"
						"<td>FLMUINT</td>\n" TD_lu, szOffsetTable[5],
						LocalSCacheMgr.uiTotalUses);
		printTableRowEnd();

		printTableRowStart( bHighlight = ~bHighlight);
		fnPrintf( m_pHRequest, TD_s "<td>uiBlocksUsed</td> <td>FLMUINT</td>\n"
					TD_lu, szOffsetTable[6], LocalSCacheMgr.uiBlocksUsed);
		printTableRowEnd();

		printTableRowStart( bHighlight = ~bHighlight);
		fnPrintf( m_pHRequest, TD_s "<td>uiPendingReads</td>\n"
			"<td>FLMUINT</td>\n" TD_lu,  szOffsetTable[7],
			LocalSCacheMgr.uiPendingReads);
		printTableRowEnd();

		printTableRowStart( bHighlight = ~bHighlight);
		fnPrintf( m_pHRequest, TD_s "<td>uiIoWaits</td>\n <td>FLMUINT</td>\n" TD_lu,
						szOffsetTable[8], LocalSCacheMgr.uiIoWaits);
		printTableRowEnd();

		printTableRowStart( bHighlight = ~bHighlight);
		fnPrintf( m_pHRequest, TD_s "<td>uiHashTableSize</td>\n"
					"<td>FLMUINT</td>\n" TD_lu, szOffsetTable[9],
					LocalSCacheMgr.uiHashTblSize);
		printTableRowEnd();

		printTableRowStart( bHighlight = ~bHighlight);
		fnPrintf( m_pHRequest, TD_s "<td>uiHashTableBits</td>\n"
					"<td>FLMUINT</td>\n" TD_lu, szOffsetTable[10],
					LocalSCacheMgr.uiHashTblBits);
		printTableRowEnd();

#ifdef FLM_DEBUG
		printTableRowStart( bHighlight = ~bHighlight);
		fnPrintf( m_pHRequest, TD_s "<td>bDebug</td>\n" "<td>FLMBOOL</td>\n"
					TD_i, szOffsetTable[11], LocalSCacheMgr.bDebug);
		printTableRowEnd();
#endif

		printTableEnd();
		
		fnPrintf( m_pHRequest, "</BODY></HTML>\n");

		fnEmit();

	}

Exit:

	if (pszTemp)
	{
		f_free( &pszTemp);
	}

	for (uiLoop = 0; uiLoop < NUM_CACHE_REQ_STRINGS; uiLoop++)
	{
		if( pszSCacheRequestString[uiLoop])
		{
			f_free( &pszSCacheRequestString[uiLoop]);
		}
	}

	return( rc);
}
예제 #18
0
/****************************************************************************
Desc:	Prints the web page for an SCACHE struct
****************************************************************************/
RCODE F_SCacheBlockPage::display(
	FLMUINT			uiNumParams,
	const char ** 	ppszParams)
{
	RCODE				rc = FERR_OK;
	FLMUINT			uiBlkAddress = 0;
	FLMUINT			uiLowTransID = 0;
	FLMUINT			uiHighTransID = 0;
	FFILE *			pFile;
	FLMBOOL			bHighlight = FALSE;
	char *			pszTemp = NULL;
	char *			pszTemp1 = NULL;
	FLMUINT			uiLoop = 0;
	char				szOffsetTable[10][6];
	char				szAddressTable[4][20];
	SCACHE			LocalSCacheBlock;
	FLMUINT			uiPFileBucket = 0;
	char *			pszSCacheRequestString[8] = {0, 0, 0, 0, 0, 0, 0, 0};
	char *			pszSCacheDataRequest = NULL;
	char *			pszSCacheAutoRequest = NULL; 
	char *			pszSCacheUseListRequest = NULL;
	char *			pszSCacheNotifyListRequest = NULL;
	char *			pszFFileRequest = NULL;
	char *			pszFlagNames = NULL;

	if( RC_BAD( rc = f_alloc( 200, &pszTemp)))
	{
		printErrorPage( rc, TRUE, (char *)"Failed to allocate temporary buffer");
		goto Exit;
	}

	if( RC_BAD( rc = f_alloc( 200, &pszTemp1)))
	{
		printErrorPage( rc, TRUE, (char *)"Failed to allocate temporary buffer");
		goto Exit;
	}

	// Allocate memory for all those string pointers we declared above...
	for (uiLoop = 0; uiLoop < 8; uiLoop++)
	{
		if( RC_BAD( rc = f_alloc( 150, &pszSCacheRequestString[ uiLoop])))
		{
			goto Exit;
		}
	}
		
	if( RC_BAD( rc = f_alloc( 150, &pszSCacheDataRequest)))
	{
		goto Exit;
	}

	if( RC_BAD( rc = f_alloc( 150, &pszSCacheAutoRequest)))
	{
		goto Exit;
	}

	if( RC_BAD( rc = f_alloc( 150, &pszSCacheUseListRequest)))
	{
		goto Exit;
	}

	if( RC_BAD( rc = f_alloc( 150, &pszSCacheNotifyListRequest)))
	{
		goto Exit;
	}

	if( RC_BAD( rc = f_alloc( 100, &pszFFileRequest)))
	{
		goto Exit;
	}

	if( RC_BAD( rc = f_alloc( 100, &pszFlagNames)))
	{
		goto Exit;
	}

	f_mutexLock( gv_FlmSysData.hShareMutex);

	rc = locateSCacheBlock( uiNumParams, ppszParams, &LocalSCacheBlock,
									&uiBlkAddress, &uiLowTransID,	&uiHighTransID,
									&pFile);

	if (RC_OK(rc) && LocalSCacheBlock.pFile)
	{
		uiPFileBucket = LocalSCacheBlock.pFile->uiBucket;
	}

	
	if (RC_OK( rc))
	{
		// Build the proper strings to request various other SCache blocks
		flmBuildSCacheBlockString( pszSCacheRequestString[0], LocalSCacheBlock.pPrevInFile);
		flmBuildSCacheBlockString( pszSCacheRequestString[1], LocalSCacheBlock.pNextInFile);
		flmBuildSCacheBlockString( pszSCacheRequestString[2], LocalSCacheBlock.pPrevInGlobalList);
		flmBuildSCacheBlockString( pszSCacheRequestString[3], LocalSCacheBlock.pNextInGlobalList);
		flmBuildSCacheBlockString( pszSCacheRequestString[4], LocalSCacheBlock.pPrevInHashBucket);
		flmBuildSCacheBlockString( pszSCacheRequestString[5], LocalSCacheBlock.pNextInHashBucket);
		flmBuildSCacheBlockString( pszSCacheRequestString[6], LocalSCacheBlock.pPrevInVersionList);
		flmBuildSCacheBlockString( pszSCacheRequestString[7], LocalSCacheBlock.pNextInVersionList);

		// Build the proper string to request the current Page
		flmBuildSCacheBlockString( pszSCacheAutoRequest, &LocalSCacheBlock);
	}

	f_mutexUnlock( gv_FlmSysData.hShareMutex);

	if (RC_BAD( rc))
	{
		if (rc == FERR_NOT_FOUND)
		{
			
			// The block wasn't there, print an error message and exit
			notFoundErr();
			rc = FERR_OK;
		}
		else if (rc == FERR_MEM)
		{
			// Parameters were too long to store in the space provided.
			// Probably means that the URL was malformed...
			malformedUrlErr();
			rc = FERR_OK;
		}
		goto Exit;
	}
	
	//Build the proper string to request this block's data...
	printAddress( pFile, szAddressTable[0]);
	f_sprintf( (char *)pszSCacheDataRequest,
		"%s/SCacheData?BlockAddress=%lu&File=%s&LowTransID=%lu&HighTransID=%lu",
		m_pszURLString, LocalSCacheBlock.uiBlkAddress, szAddressTable[0],
		uiLowTransID, uiHighTransID);
	
#ifdef FLM_DEBUG
	//Build the proper string to request this block's use list
	if( LocalSCacheBlock.pUseList)
	{
		f_sprintf( (char *)pszSCacheUseListRequest,
			"%s/SCacheUseList?BlockAddress=%lu&File=%s&LowTransID=%lu&HighTransID=%lu",
			m_pszURLString, LocalSCacheBlock.uiBlkAddress, szAddressTable[0],
			uiLowTransID, uiHighTransID);
	}
	else
	{
		pszSCacheUseListRequest[0] = '\0';
	}
#endif

	//Build the proper string to request the notify list data...
	if (LocalSCacheBlock.pNotifyList)
	{
		f_sprintf( (char *)pszSCacheNotifyListRequest,
			"%s/SCacheNotifyList?BlockAddress=%lu&File=%s&LowTransID=%lu&HighTransID=%lu",
			m_pszURLString, LocalSCacheBlock.uiBlkAddress, szAddressTable[0],
			uiLowTransID, uiHighTransID);
	}
	else
	{
		pszSCacheNotifyListRequest[0] = '\0';
	}

	//Build the proper string to request the FFile
	printAddress( LocalSCacheBlock.pFile, szAddressTable[0]);
	f_sprintf( (char *)pszFFileRequest, "%s/FFile?From=SCacheBlock&Bucket=%lu&Address=%s",
				 m_pszURLString, uiPFileBucket, szAddressTable[0]);
					

	// Build a string with the names of all the flags that have been set...
	pszFlagNames[0]='\0';
	if (LocalSCacheBlock.ui16Flags & CA_DIRTY)
	{
		f_strcat( pszFlagNames, "<BR> CA_DIRTY");
	}
	if (LocalSCacheBlock.ui16Flags & CA_READ_PENDING)
	{
		f_strcat( pszFlagNames, "<BR> CA_READ_PENDING");
	}
	if (LocalSCacheBlock.ui16Flags & CA_WRITE_TO_LOG)
	{
		f_strcat( pszFlagNames, "<BR> CA_WRITE_TO_LOG");
	}
	if (LocalSCacheBlock.ui16Flags & CA_LOG_FOR_CP)
	{
		f_strcat( pszFlagNames, "<BR> CA_LOG_FOR_CP");
	}
	if (LocalSCacheBlock.ui16Flags & CA_WAS_DIRTY)
	{
		f_strcat( pszFlagNames, "<BR> CA_WAS_DIRTY");
	}
	if (LocalSCacheBlock.ui16Flags & CA_WRITE_PENDING)
	{
		f_strcat( pszFlagNames, "<BR> CA_WRITE_PENDING");
	}
	if (LocalSCacheBlock.ui16Flags & CA_IN_WRITE_PENDING_LIST)
	{
		f_strcat( pszFlagNames, "<BR> CA_IN_WRITE_PENDING_LIST");
	}


	// OK - Start outputting HTML...
	stdHdr();

	fnPrintf( m_pHRequest, HTML_DOCTYPE "<html>\n");
		
	// Determine if we are being requested to refresh this page or  not.
	if (DetectParameter( uiNumParams, ppszParams, "Refresh"))
	{
		// Send back the page with a refresh command in the header
		fnPrintf( m_pHRequest, 
			"<HEAD>\n"
			"<META http-equiv=\"refresh\" content=\"5; url=\"%s\">"
			"<TITLE>SCache Block</TITLE>\n", pszSCacheAutoRequest);
		printStyle();
		popupFrame();  //Spits out a Javascript function that will open a new window..
		fnPrintf( m_pHRequest, "</HEAD>\n<body>\n");
		
		f_sprintf( (char*)pszTemp,
					"<A HREF=\"%s\">Stop Auto-refresh</A>", pszSCacheAutoRequest);
	}
	else
	{
		// Send back a page without the refresh command
		
		fnPrintf( m_pHRequest, "<HEAD>\n");
		printStyle();
		popupFrame();  //Spits out a Javascript function that will open a new window..
		fnPrintf( m_pHRequest, "</HEAD>\n<body>\n");
		
		f_sprintf( (char *)pszTemp,
					"<A HREF=\"%s?Refresh\">Start Auto-refresh (5 sec.)</A>", pszSCacheAutoRequest);
	}

	// Write out the table headings
	printTableStart( "SCache Block Structure", 4, 100);

	printTableRowStart();
	printColumnHeading( "", JUSTIFY_LEFT, FLM_IMON_COLOR_PUTTY_1, 4, 1, FALSE);
	fnPrintf( m_pHRequest, "<A HREF=\"%s\">Refresh</A>, %s\n",
				 pszSCacheAutoRequest, pszTemp);
	printColumnHeadingClose();
	printTableRowEnd();

	// Write out the table headings.
	printTableRowStart();
	printColumnHeading( "Byte Offset (hex)");
	printColumnHeading( "Field Name");
	printColumnHeading( "Field Type");
	printColumnHeading( "Value");
	printTableRowEnd();

	// Print the two rows for pPrevInFile and pNextInFile
	printTableRowStart( bHighlight = ~bHighlight);
	flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[0], "pPrevInFile", &LocalSCacheBlock, &LocalSCacheBlock.pPrevInFile);
	printTableRowStart( bHighlight = ~bHighlight);
	flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[1], "pNextInFile", &LocalSCacheBlock, &LocalSCacheBlock.pNextInFile);


	// Format the strings that are displayed in the Offset and Address
	// columns of the table
	printOffset( &LocalSCacheBlock, &LocalSCacheBlock.pucBlk, szOffsetTable[0]);
	printOffset( &LocalSCacheBlock, &LocalSCacheBlock.pFile, szOffsetTable[1]);
	printOffset( &LocalSCacheBlock, &LocalSCacheBlock.uiBlkAddress, szOffsetTable[2]);
	printOffset( &LocalSCacheBlock, &LocalSCacheBlock.pNotifyList, szOffsetTable[3]);
	printOffset( &LocalSCacheBlock, &LocalSCacheBlock.uiHighTransID, szOffsetTable[4]);
	printOffset( &LocalSCacheBlock, &LocalSCacheBlock.uiUseCount, szOffsetTable[5]);
	printOffset( &LocalSCacheBlock, &LocalSCacheBlock.ui16Flags, szOffsetTable[6]);
	printOffset( &LocalSCacheBlock, &LocalSCacheBlock.ui16BlkSize, szOffsetTable[7]);
#ifdef FLM_DEBUG
	printOffset( &LocalSCacheBlock, &LocalSCacheBlock.uiChecksum, szOffsetTable[8]);
	printOffset( &LocalSCacheBlock, &LocalSCacheBlock.pUseList, szOffsetTable[9]);
#endif

	printAddress( LocalSCacheBlock.pucBlk, szAddressTable[0]);
	printAddress( LocalSCacheBlock.pFile, szAddressTable[1]);
	printAddress( LocalSCacheBlock.pNotifyList, szAddressTable[2]);
#ifdef FLM_DEBUG
	printAddress( LocalSCacheBlock.pUseList, szAddressTable[3]);
#endif


	printTableRowStart( bHighlight = ~bHighlight);
	fnPrintf( m_pHRequest, TD_s "<td><A HREF=\"javascript:openPopup('%s')\">pucBlk</A></td>\n"
				"<td>FLMBYTE *</td>\n<td><A HREF=\"javascript:openPopup('%s')\">%s</A></td>\n",
				szOffsetTable[0],	pszSCacheDataRequest, pszSCacheDataRequest, szAddressTable[0] );
	printTableRowEnd();

	printTableRowStart( bHighlight = ~bHighlight);
	fnPrintf( m_pHRequest, TD_s "<td><A href=%s>pFile</A></td>\n"
				"<td>FFILE *</td>\n<td><A HREF=%s>%s</a></td>\n",
				szOffsetTable[1], pszFFileRequest, pszFFileRequest, szAddressTable[1]);
	printTableRowEnd();

	printTableRowStart( bHighlight = ~bHighlight);
	fnPrintf( m_pHRequest, TD_s "<td>uiBlkAddress</td>\n<td>FLMUINT</td>\n"
				"<td>0x%lX</td>\n", szOffsetTable[2], LocalSCacheBlock.uiBlkAddress);
	printTableRowEnd();

	//Print the rows for the remaining SCache * fields
	printTableRowStart( bHighlight = ~bHighlight);
	flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[2], "pPrevInGlobalList", &LocalSCacheBlock, &LocalSCacheBlock.pPrevInGlobalList);		
	printTableRowStart( bHighlight = ~bHighlight);
	flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[3], "pNextInGlobalList", &LocalSCacheBlock, &LocalSCacheBlock.pNextInGlobalList);
	printTableRowStart( bHighlight = ~bHighlight);
	flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[4], "pPrevInHashBucket", &LocalSCacheBlock, &LocalSCacheBlock.pPrevInHashBucket);		
	printTableRowStart( bHighlight = ~bHighlight);
	flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[5], "pNextInHashBucket", &LocalSCacheBlock, &LocalSCacheBlock.pNextInHashBucket);
	printTableRowStart( bHighlight = ~bHighlight);
	flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[6], "pPrevInVersionList", &LocalSCacheBlock, &LocalSCacheBlock.pPrevInVersionList);		
	printTableRowStart( bHighlight = ~bHighlight);
	flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[7], "pNextInVersionList", &LocalSCacheBlock, &LocalSCacheBlock.pNextInVersionList);

	//Notify list line
	printTableRowStart( bHighlight = ~bHighlight);
	if (LocalSCacheBlock.pNotifyList)
	{
		fnPrintf( m_pHRequest,
			TD_s
			" <td> <A HREF=\"javascript:openPopup('%s')\"> pNotifyList </A> </td>	<td>FNOTIFY *</td> "
			"<td> <A HREF=\"javascript:openPopup('%s')\"> %s </A> </td>",
			szOffsetTable[3], pszSCacheNotifyListRequest,
			pszSCacheNotifyListRequest, szAddressTable[2]);
	}
	else
	{
		fnPrintf( m_pHRequest,
			TD_s " <td> pNotifyList </td>	<td>FNOTIFY *</td> "
			"<td> 0x0 </td>", szOffsetTable[3]);
	}
	printTableRowEnd();


	printTableRowStart( bHighlight = ~bHighlight);
	fnPrintf( m_pHRequest, TD_s "<td>uiHighTransID</td>\n"
				"<td>FLMUINT</td>\n" TD_8x, szOffsetTable[4],
				LocalSCacheBlock.uiHighTransID);
	printTableRowEnd();

	printTableRowStart( bHighlight = ~bHighlight);
	fnPrintf( m_pHRequest, TD_s "<td>uiUseCount</td>\n<td>FLMUINT</td>\n"
				 TD_lu,  szOffsetTable[5], LocalSCacheBlock.uiUseCount);
	printTableRowEnd();

	printTableRowStart( bHighlight = ~bHighlight);
	fnPrintf( m_pHRequest, TD_s "<td>ui16Flags</td>\n<td>FLMUINT16</td>\n"
					"<td>0x%04X %s</td>\n", szOffsetTable[6],
					LocalSCacheBlock.ui16Flags, pszFlagNames);
	printTableRowEnd();

	printTableRowStart( bHighlight = ~bHighlight);
	fnPrintf( m_pHRequest, TD_s "<td>ui16BlkSize</td>\n<td>FLMUINT16</td>\n" TD_i,
					szOffsetTable[7], LocalSCacheBlock.ui16BlkSize);
	printTableRowEnd();

#ifdef FLM_DEBUG
	printTableRowStart( bHighlight = ~bHighlight);
	fnPrintf( m_pHRequest, TD_s "<td>uiChecksum</td>\n"
					"<td>FLMUINT</td>\n" TD_8x,
					szOffsetTable[8], LocalSCacheBlock.uiChecksum);
	printTableRowEnd();
#endif


#ifdef FLM_DEBUG
		//Last line - the use list...
		printTableRowStart( bHighlight = ~bHighlight);
		if (LocalSCacheBlock.pUseList)
		{
			fnPrintf( m_pHRequest,
				TD_s " <td> <A href=\"javascript:openPopup('%s')> pUseList </A> </td>	<td> SCACHE_USE_p </td>		<td> <A href=\"javascript:openPopup('%s')> %s </A></td>",
				szOffsetTable[9], pszSCacheUseListRequest, pszSCacheUseListRequest, szAddressTable[3]);
		}
		else
		{
			fnPrintf( m_pHRequest,
				TD_s " <td> pUseList </td>	<td> SCACHE_USE_p </td>	<td> 0x0 </td>",
				szOffsetTable[9]);
		}
		printTableRowEnd();

#endif

	fnPrintf( m_pHRequest, TABLE_END "</BODY></HTML>\n");
	fnEmit();

Exit:

	// Even though uiLoop2 is not in the same scope as uiLoop, VC6 still
	// complains if this is called uiLoop....
	for (FLMUINT uiLoop2 = 0; uiLoop2 < 8; uiLoop2++)
	{
		if (pszSCacheRequestString[uiLoop2])
		{
			f_free( &pszSCacheRequestString[uiLoop2]);
		}
	}

	if (pszSCacheDataRequest)
	{
		f_free( &pszSCacheDataRequest);
	}

	if (pszSCacheAutoRequest)
	{
		f_free( &pszSCacheAutoRequest);
	}

	if (pszSCacheUseListRequest)
	{
		f_free( &pszSCacheUseListRequest);
	}

	if (pszSCacheNotifyListRequest)
	{
		f_free( &pszSCacheNotifyListRequest);
	}
	
	if( pszFFileRequest)
	{
		f_free( &pszFFileRequest);
	}

	if( pszFlagNames)
	{
		f_free( &pszFlagNames);
	}

	if (pszTemp)
	{
		f_free( &pszTemp);
	}

	if (pszTemp1)
	{
		f_free( &pszTemp1);
	}

	return( rc);
}
예제 #19
0
파일: flmimon.cpp 프로젝트: ajumi2/libflaim
/****************************************************************************
Desc:	This is the function that the HTTP server calls when it wants to
			display one of our pages
****************************************************************************/
int flmHttpCallback(
	HRequest *			pHRequest,
	void *				//pvUserData
	)
{
	RCODE							rc = FERR_OK;
	F_WebPage *					pPage = NULL;
	char *						pszPath = NULL;
	char *						pszQuery = NULL;
	char *						pszTemp = NULL;
	const char *				pszConstTemp = NULL;
#define MAX_PARAMS 10
	const char *				pszParams[ MAX_PARAMS];
	FLMUINT						uiNumParams;

	// If we get a NULL for the pHRequest object, then we are shutting down...

	if (pHRequest == NULL)
	{
		// Remove the globals that enable the secure pages...
		gv_FlmSysData.HttpConfigParms.fnSetGblValue( 
				FLM_SECURE_PASSWORD, "", 0);
		gv_FlmSysData.HttpConfigParms.fnSetGblValue(
				FLM_SECURE_EXPIRATION, "", 0);

		// Delete the web page factory object
		if (gv_pWPFact)
		{
			gv_pWPFact->Release( NULL);
		}
		gv_pWPFact = NULL;
		goto Exit;
	}

	// Increment the use count (helps ensure that the function pointers
	// that display() references don't go away while display() still needs
	// them.

	f_mutexLock( gv_FlmSysData.HttpConfigParms.hMutex);
	gv_FlmSysData.HttpConfigParms.uiUseCount++;
	f_mutexUnlock( gv_FlmSysData.HttpConfigParms.hMutex);

	// Must not access any HRequest function pointers prior to incrementing the
	// use count.

	if( !gv_FlmSysData.HttpConfigParms.fnReqPath)
	{
		flmAssert( 0);
		rc = RC_SET( FERR_FAILURE);
		goto Exit;
	}

	// If the web page factory does not exist yet, then we need to create it.
	if (!gv_pWPFact)
	{
		f_mutexLock( gv_FlmSysData.HttpConfigParms.hMutex);
		// In the time it took us to get the lock, some other thread might
		// have come along and created the factory already...
		if (!gv_pWPFact)
		{
			if ((gv_pWPFact = f_new F_WebPageFactory) == NULL)
			{
				rc = RC_SET( FERR_MEM);
				f_mutexUnlock( gv_FlmSysData.HttpConfigParms.hMutex);
				goto Exit;
			}
		}
		f_mutexUnlock( gv_FlmSysData.HttpConfigParms.hMutex);
	}
	
	pszConstTemp = gv_FlmSysData.HttpConfigParms.fnReqPath( pHRequest);
	flmAssert( pszConstTemp);

	if( RC_BAD( rc = f_alloc( 
		f_strlen( pszConstTemp) + 1, &pszPath)))
	{
		goto Exit;
	}

	f_strcpy( pszPath, pszConstTemp);
	
	pszConstTemp = gv_FlmSysData.HttpConfigParms.fnReqQuery( pHRequest);
	if( pszConstTemp)
	{
		if( RC_BAD( rc = f_alloc( f_strlen( pszConstTemp) + 1, &pszQuery)))
		{
			goto Exit;
		}

		f_strcpy( pszQuery, pszConstTemp);
		pszConstTemp = pszQuery;
	}
	else  // This URL had no query string...
	{
		// If pszQuery is NULL, it causes problems further down, so we'll
		// make it a pointer to a null string...

		if( RC_BAD( rc = f_alloc( 1, &pszQuery)))
		{
			goto Exit;
		}
		pszQuery[0] = '\0';				
	}

	// Strip off pszURLString (and the next '/', if there is one) from the request and store 
	// what's left as pszParams[0].
	// (ie: /coredb/FlmSysData --> FlmSysData)

	// Note: The reason we're checking for the URL string first is because if
	// we're using our own http stack, then this callback is called for every
	// http request and we don't want to crash if we've got a short URI.
	// When we're running under DS, we're guarenteed that the URLString will
	// be part of the URI.

	if( f_strlen( pszPath) >= gv_FlmSysData.HttpConfigParms.uiURLStringLen)
	{
		pszConstTemp = pszPath + gv_FlmSysData.HttpConfigParms.uiURLStringLen;
		if( *pszConstTemp == '/')
		{
			pszConstTemp++;
		}
	}
	else
	{
		pszConstTemp = pszPath;
	}

	pszParams[0] = pszConstTemp;
	uiNumParams = 1;


	// Parse parameters in the query string 
	// Note that it's technically incorrect to have more than one ? in a
	// URL, but we didn't know that when we first started creating some of 
	// these pages and as a result, some queries are in the form of:
	// ?name1=value1?name2=value2?name3=value3...  (which is improper) and
	// some have the form:
	// ?name1=value1&name2=value2&name3=value3... (which is correct).
	
	pszTemp = pszQuery;
	
	while( *pszTemp != 0)
	{
		flmAssert( uiNumParams < MAX_PARAMS);
		pszParams[ uiNumParams] = pszTemp;
		uiNumParams++;
		
		pszTemp = tokenizer( pszTemp, '?', '&');
		
		if (*pszTemp)
		{
			*pszTemp = '\0';
			pszTemp++;
		}
	}

	// Tell the factory to create the page
	
	if (RC_BAD( rc = gv_pWPFact->create( pszParams[0], &pPage, pHRequest)))
	{
		goto Exit;
	}
	
	
	pPage->setMembers( pHRequest);

	// display the page
	if( RC_BAD( rc = pPage->display (uiNumParams, &pszParams[0])))
	{
		goto Exit;
	}

Exit:

	// Decrement the use count

	if( pHRequest)
	{
		f_mutexLock( gv_FlmSysData.HttpConfigParms.hMutex);
		if( gv_FlmSysData.HttpConfigParms.uiUseCount > 0)
		{
			gv_FlmSysData.HttpConfigParms.uiUseCount--;
		}
		else
		{
			flmAssert( 0);
		}
		f_mutexUnlock( gv_FlmSysData.HttpConfigParms.hMutex);
	}
	
	if (pPage)
	{
		gv_pWPFact->Release( &pPage);
	}

	if (pszPath)
	{
		f_free( &pszPath);
	}

	if (pszQuery)
	{
		f_free( &pszQuery);
	}

	return (int)rc;
}
예제 #20
0
/********************************************************************
Desc: This routine follows all of the blocks in a chain, verifying
		that they are properly linked.  It also verifies each block's
		header.
*********************************************************************/
RCODE F_DbCheck::verifyBlkChain(
	BLOCK_INFO *	pBlkInfo,
	FLMUINT			uiLocale,
	FLMUINT			uiFirstBlkAddr,
	FLMUINT			uiBlkType,
	FLMBOOL *		pbStartOverRV
	)
{
	RCODE					rc = NE_XFLM_OK;
	FLMINT32				i32VerifyCode = 0;
	F_CachedBlock *	pSCache = NULL;
	F_BLK_HDR *			pBlkHdr = NULL;
	FLMUINT				uiPrevBlkAddress;
	FLMUINT				uiBlkCount = 0;
	STATE_INFO			StateInfo;
	FLMBOOL				bStateInitialized = FALSE;
	FLMUINT64			ui64SaveBytesExamined;
	FLMUINT				uiBlockSize = m_pDb->m_pDatabase->getBlockSize();
	FLMUINT				uiMaxBlocks = (FLMUINT)(FSGetSizeInBytes(
										m_pDb->m_pDatabase->getMaxFileSize(),
											m_pDb->m_uiLogicalEOF) /
											(FLMUINT64)uiBlockSize);

	uiPrevBlkAddress = 0;

	/* There must be at least ONE block if it is the LFH chain. */

	if ((uiBlkType == BT_LFH_BLK) && (uiFirstBlkAddr == 0))
	{
		i32VerifyCode = FLM_BAD_LFH_LIST_PTR;
		(void)chkReportError( i32VerifyCode,
									 (FLMUINT32)uiLocale,
									 0,
									 0,
									 0xFF,
									 0,
									 0,
									 0,
									 0);
		goto Exit;
	}

	/* Read through all of the blocks, verifying them as we go. */

Restart_Chain:
	uiBlkCount = 0;
	flmInitReadState( &StateInfo,
							&bStateInitialized,
							(FLMUINT)m_pDb->m_pDatabase->
											m_lastCommittedDbHdr.ui32DbVersion,
							m_pDb,
							NULL,
							(FLMUINT)((uiBlkType == BT_FREE)
											? (FLMUINT)0xFF
											: (FLMUINT)0),
							uiBlkType,
							NULL);
	
	ui64SaveBytesExamined = m_Progress.ui64BytesExamined;
	StateInfo.ui32BlkAddress = (FLMUINT32)uiFirstBlkAddr;

	while ((StateInfo.ui32BlkAddress != 0) && (uiBlkCount < uiMaxBlocks))
	{
		StateInfo.pBlkHdr = NULL;
		if( RC_BAD( rc = blkRead( StateInfo.ui32BlkAddress, &pBlkHdr,
			&pSCache, &i32VerifyCode)))
		{
			if (rc == NE_XFLM_OLD_VIEW)
			{
				FLMUINT	uiSaveDictSeq = m_pDb->m_pDict->getDictSeq();

				if (RC_BAD( rc = getDictInfo()))
					goto Exit;

				// If the dictionary ID changed, start over.

				if (m_pDb->m_pDict->getDictSeq() != uiSaveDictSeq)
				{
					*pbStartOverRV = TRUE;
					goto Exit;
				}

				m_Progress.ui64BytesExamined = ui64SaveBytesExamined;
				goto Restart_Chain;
			}
			pBlkInfo->i32ErrCode = i32VerifyCode;
			pBlkInfo->uiNumErrors++;
			rc = chkReportError( i32VerifyCode,
										(FLMUINT32)uiLocale,
										0,
										0,
										0xFF,
										StateInfo.ui32BlkAddress,
										0,
										0,
										0);
		}
		StateInfo.pBlkHdr = pBlkHdr;
		uiBlkCount++;
		m_Progress.ui64BytesExamined += (FLMUINT64)uiBlockSize;
		if (RC_BAD( rc = chkCallProgFunc()))
		{
			goto Exit;
		}

		f_yieldCPU();

		if ((i32VerifyCode = flmVerifyBlockHeader( &StateInfo,
															  pBlkInfo,
															  uiBlockSize,
															  0xFFFFFFFF,
															  uiPrevBlkAddress,
															  TRUE)) != 0)
		{
			pBlkInfo->i32ErrCode = i32VerifyCode;
			pBlkInfo->uiNumErrors++;
			chkReportError( i32VerifyCode,
								 (FLMUINT32)uiLocale,
								 0,
								 0,
								 0xFF,
								 StateInfo.ui32BlkAddress,
								 0,
								 0,
								 0);
			goto Exit;
		}
		uiPrevBlkAddress = StateInfo.ui32BlkAddress;
		StateInfo.ui32BlkAddress = pBlkHdr->ui32NextBlkInChain;
	}
	if (StateInfo.ui32BlkAddress != 0 && RC_OK( m_LastStatusRc))
	{
		switch (uiBlkType)
		{
			case BT_LFH_BLK:
				i32VerifyCode = FLM_BAD_LFH_LIST_END;
				break;
			case BT_FREE:
				i32VerifyCode = FLM_BAD_AVAIL_LIST_END;
				break;
		}
		pBlkInfo->i32ErrCode = i32VerifyCode;
		pBlkInfo->uiNumErrors++;
		chkReportError( i32VerifyCode,
							 (FLMUINT32)uiLocale,
							 0,
							 0,
							 0xFF,
							 (FLMUINT32)uiPrevBlkAddress,
							 0,
							 0,
							 0);
		goto Exit;
	}

Exit:

	if( pSCache)
	{
		ScaReleaseCache( pSCache, FALSE);
	}
	else if( pBlkHdr)
	{
		f_free( &pBlkHdr);
	}

	if (RC_OK(rc) && (i32VerifyCode != 0))
	{
		rc = RC_SET( NE_XFLM_DATA_ERROR);
	}

	return( rc);
}
예제 #21
0
/****************************************************************************
Desc:	This routine aborts an active transaction for a particular
		database.  If the database is open via a server, a message is
		sent to the server to abort the transaction.  Otherwise, the
		transaction is rolled back locally.
****************************************************************************/
RCODE F_Db::abortTrans(
	FLMBOOL			bOkToLogAbort)
{
	RCODE					rc = NE_XFLM_OK;
	eDbTransType		eSaveTransType;
	XFLM_DB_HDR *		pLastCommittedDbHdr;
	XFLM_DB_HDR *		pUncommittedDbHdr;
	FLMBOOL				bDumpedCache = FALSE;
	FLMBOOL				bKeepAbortedTrans;
	FLMUINT64			ui64TransId;
	F_Rfl *				pRfl = m_pDatabase->m_pRfl;
	RCODE					tmpRc;

	// Should never be calling on a temporary database.

	flmAssert( !m_pDatabase->m_bTempDb);

	// Get transaction type

	if (m_eTransType == XFLM_NO_TRANS)
	{
		goto Exit;	// Will return SUCCESS.
	}

	// No recovery required if it is a read transaction.

	if (m_eTransType == XFLM_READ_TRANS)
	{
		if (m_bKrefSetup)
		{
			// krefCntrlFree could be called w/o checking bKrefSetup because
			// it checks the flag, but it is more optimal to check the
			// flag before making the call because most of the time it will
			// be false.

			krefCntrlFree();
		}

		goto Unlink_From_Trans;
	}

#ifdef FLM_DBG_LOG
	flmDbgLogUpdate( m_pDatabase, m_ui64CurrTransID,
			0, 0, NE_XFLM_OK, "TAbrt");
#endif

	// Disable DB header writes

	pRfl->clearDbHdrs();

	// End any pending input operations

	m_pDatabase->endPendingInput();

	// Clear the document list

	m_pDatabase->m_DocumentList.clearNodes();

	// If the transaction had no update operations, restore it
	// to its pre-transaction state - make it appear that no
	// transaction ever happened.

	pLastCommittedDbHdr = &m_pDatabase->m_lastCommittedDbHdr;
	pUncommittedDbHdr = &m_pDatabase->m_uncommittedDbHdr;
	ui64TransId = m_ui64CurrTransID;

	// Free up all keys associated with this database.  This is done even
	// if we didn't have any update operations because the KREF may
	// have been initialized by key generation operations performed
	// by cursors, etc.

	krefCntrlFree();

	if (m_bHadUpdOper)
	{

		// Dump any start and stop indexing stubs that should be aborted.

		indexingAfterAbort();

		// Log the abort record to the rfl file, or throw away the logged
		// records altogether, depending on the LOG_KEEP_ABORTED_TRANS_IN_RFL
		// flag.  If the RFL volume is bad, we will not attempt to keep this
		// transaction in the RFL.

		if (!pRfl->seeIfRflVolumeOk())
		{
			bKeepAbortedTrans = FALSE;
		}
		else
		{
			bKeepAbortedTrans =
				(pUncommittedDbHdr->ui8RflKeepAbortedTrans)
				? TRUE
				: FALSE;
		}
	}
	else
	{
		bKeepAbortedTrans = FALSE;
	}

	// Log an abort transaction record to the roll-forward log or
	// throw away the entire transaction, depending on the
	// bKeepAbortedTrans flag.

	// If the transaction is being "dumped" because of a failed commit,
	// don't log anything to the RFL.

	if (bOkToLogAbort)
	{
#ifdef FLM_DEBUG
		if( pRfl->isLoggingEnabled())
		{
			flmAssert( m_ui64CurrTransID == pRfl->getCurrTransID());
		}
#endif

		if (RC_BAD( rc = pRfl->logEndTransaction(
			this, RFL_TRNS_ABORT_PACKET, !bKeepAbortedTrans)))
		{
			goto Exit1;
		}
	}
#ifdef FLM_DEBUG
	else
	{
		// If bOkToLogAbort is FALSE, this always means that either a
		// commit failed while trying to log an end transaction packet or a
		// commit packet was logged and the transaction commit subsequently
		// failed for some other reason.  In either case, the RFL should be
		// in a good state, with its current transaction ID reset to 0.  If
		// not, either bOkToLogAbort is being used incorrectly by the caller
		// or there is a bug in the RFL logic.

		flmAssert( pRfl->getCurrTransID() == 0);
	}
#endif

	// If there were no operations in the transaction, restore
	// everything as if the transaction never happened.

	// Even empty transactions can have modified nodes to clean up
	// so we need to call this no matter what.

	m_pDatabase->freeModifiedNodes( this, m_ui64CurrTransID - 1);

	if (!m_bHadUpdOper)
	{

		// Pretend we dumped cache - shouldn't be any to worry about at
		// this point.

		bDumpedCache = TRUE;
		goto Exit1;
	}

	// Dump ALL modified cache blocks associated with the DB.
	// NOTE: This needs to be done BEFORE the call to flmGetDbHdrInfo
	// below, because that call will change pDb->m_ui64CurrTransID,
	// and that value is used by freeModifiedNodes.

	m_pDatabase->freeModifiedBlocks( m_ui64CurrTransID);
	bDumpedCache = TRUE;

	// Reset the Db header from the last committed DB header in pFile.

	getDbHdrInfo( pLastCommittedDbHdr);
	if (RC_BAD( rc = physRollback( (FLMUINT)pUncommittedDbHdr->ui32RblEOF,
				 m_pDatabase->m_uiFirstLogBlkAddress, FALSE, 0)))
	{
		goto Exit1;
	}

	m_pDatabase->lockMutex();

	// Put the new transaction ID into the log header even though
	// we are not committing.  We want to keep the transaction IDs
	// incrementing even though we aborted.

	pLastCommittedDbHdr->ui64CurrTransID = ui64TransId;

	// Preserve where we are at in the roll-forward log.  Even though
	// the transaction aborted, we may have kept it in the RFL instead of
	// throw it away.

	pLastCommittedDbHdr->ui32RflCurrFileNum =
		pUncommittedDbHdr->ui32RflCurrFileNum;
	pLastCommittedDbHdr->ui32RflLastTransOffset =
		pUncommittedDbHdr->ui32RflLastTransOffset;
	f_memcpy( pLastCommittedDbHdr->ucLastTransRflSerialNum,
				 pUncommittedDbHdr->ucLastTransRflSerialNum,
				 XFLM_SERIAL_NUM_SIZE);
	f_memcpy( pLastCommittedDbHdr->ucNextRflSerialNum,
				 pUncommittedDbHdr->ucNextRflSerialNum,
				 XFLM_SERIAL_NUM_SIZE);

	// The following items tell us where we are at in the roll-back log.
	// During a transaction we may log blocks for the checkpoint or for
	// read transactions.  So, even though we are aborting this transaction,
	// there may be other things in the roll-back log that we don't want
	// to lose.  These items should not be reset until we do a checkpoint,
	// which is when we know it is safe to throw away the entire roll-back log.

	pLastCommittedDbHdr->ui32RblEOF =
		pUncommittedDbHdr->ui32RblEOF;
	pLastCommittedDbHdr->ui32RblFirstCPBlkAddr =
		pUncommittedDbHdr->ui32RblFirstCPBlkAddr;

	m_pDatabase->unlockMutex();

	pRfl->commitDbHdrs( pLastCommittedDbHdr,
							&m_pDatabase->m_checkpointDbHdr);

Exit1:

	// Dump cache, if not done above.

	if (!bDumpedCache)
	{
		m_pDatabase->freeModifiedBlocks( m_ui64CurrTransID);
		m_pDatabase->freeModifiedNodes( this, m_ui64CurrTransID - 1);
		bDumpedCache = TRUE;
	}

	// Throw away IXD_FIXUPs

	if (m_pIxdFixups)
	{
		IXD_FIXUP *	pIxdFixup;
		IXD_FIXUP *	pDeleteIxdFixup;

		pIxdFixup = m_pIxdFixups;
		while (pIxdFixup)
		{
			pDeleteIxdFixup = pIxdFixup;
			pIxdFixup = pIxdFixup->pNext;
			f_free( &pDeleteIxdFixup);
		}
		m_pIxdFixups = NULL;
	}

	if (m_eTransType == XFLM_UPDATE_TRANS &&
		 gv_XFlmSysData.EventHdrs[ XFLM_EVENT_UPDATES].pEventCBList)
	{
		flmTransEventCallback( XFLM_EVENT_ABORT_TRANS, this, rc,
						ui64TransId);
	}

Unlink_From_Trans:

	eSaveTransType = m_eTransType;

	if (m_uiFlags & FDB_HAS_WRITE_LOCK)
	{
		if (RC_BAD( tmpRc = pRfl->completeTransWrites( this, FALSE, FALSE)))
		{
			if (RC_OK( rc))
			{
				rc = tmpRc;
			}
		}
	}

	if (eSaveTransType == XFLM_UPDATE_TRANS)
	{

		// Before unlocking, restore collection information.

		if (m_uiFlags & FDB_UPDATED_DICTIONARY)
		{
			m_pDatabase->lockMutex();
			flmAssert( m_pDict);
			unlinkFromDict();
			if (m_pDatabase->m_pDictList)
			{

				// Link the F_Db to the right F_Dict object so it will
				// fixup the correct F_COLLECTION structures.

				linkToDict( m_pDatabase->m_pDictList);
			}
			m_pDatabase->unlockMutex();
		}

		if (m_pDict)
		{
			F_COLLECTION *	pCollection;
			FLMUINT			uiLfNum;
#ifdef FLM_DEBUG
			IXD *				pIxd;
			FLMUINT			uiRootBlk;
#endif

			// Only need to do collections.  Nothing from the LFH of
			// an index is stored in memory except for the root block
			// address, and whenever that is changed, we get a new
			// dictionary.  Since the new dictionary will be discarded
			// in that case, there is nothing to restore for an index.

			uiLfNum = 0;
			while ((pCollection = m_pDict->getNextCollection(
											uiLfNum, TRUE)) != NULL)
			{
#ifdef FLM_DEBUG
				uiRootBlk = pCollection->lfInfo.uiRootBlk;
#endif
				if (RC_BAD( tmpRc = m_pDatabase->lFileRead( this,
							&pCollection->lfInfo, pCollection)))
				{
					if (RC_OK( rc))
					{
						rc = tmpRc;
					}
				}
#ifdef FLM_DEBUG
				else
				{
					// Make sure root block did not change - should not
					// have because root block changes are done by creating
					// a new dictionary, and we have already discarded
					// any new dictionary.  Hence, root block address should
					// be the same in memory as it is no disk.

					flmAssert( uiRootBlk == pCollection->lfInfo.uiRootBlk);
				}
#endif
				uiLfNum = pCollection->lfInfo.uiLfNum;
			}

			// Do indexes in debug mode to make sure uiRootBlk is correct

#ifdef FLM_DEBUG
			uiLfNum = 0;
			while ((pIxd = m_pDict->getNextIndex( uiLfNum, TRUE)) != NULL)
			{
				uiRootBlk = pIxd->lfInfo.uiRootBlk;
				if (RC_BAD( tmpRc = m_pDatabase->lFileRead( this,
							&pIxd->lfInfo, NULL)))
				{
					if (RC_OK( rc))
					{
						rc = tmpRc;
					}
				}
				else
				{
					// Make sure root block did not change - should not
					// have because root block changes are done by creating
					// a new dictionary, and we have already discarded
					// any new dictionary.  Hence, root block address should
					// be the same in memory as it is no disk.

					flmAssert( uiRootBlk == pIxd->lfInfo.uiRootBlk);
				}
				uiLfNum = pIxd->lfInfo.uiLfNum;
			}
#endif
		}
	}

	// Unlink the database from the transaction list.

	unlinkFromTransList( FALSE);

	if (m_pDbStats)
	{
		FLMUINT64	ui64ElapMilli = 0;

		flmAddElapTime( &m_TransStartTime, &ui64ElapMilli);
		m_pDbStats->bHaveStats = TRUE;
		if (eSaveTransType == XFLM_READ_TRANS)
		{
			m_pDbStats->ReadTransStats.AbortedTrans.ui64Count++;
			m_pDbStats->ReadTransStats.AbortedTrans.ui64ElapMilli +=
					ui64ElapMilli;
		}
		else
		{
			m_pDbStats->UpdateTransStats.AbortedTrans.ui64Count++;
			m_pDbStats->UpdateTransStats.AbortedTrans.ui64ElapMilli +=
					ui64ElapMilli;
		}
	}

	if (m_pStats)
	{
		(void)flmStatUpdate( &m_Stats);
	}

Exit:

	m_AbortRc = NE_XFLM_OK;
	return( rc);
}
예제 #22
0
/****************************************************************************
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);
}
예제 #23
0
/****************************************************************************
Desc:
****************************************************************************/
RCODE SortKeyTestImpl::createOrModifyIndex( 
	FLMUINT			uiIndex,
	FLMBOOL			bComp1SortDescending,
	FLMBOOL			bComp1CaseSensitive,
	FLMBOOL			bComp1SortMissingHigh,
	FLMBOOL			bComp2SortDescending,
	FLMBOOL			bComp2SortMissingHigh)
{
	RCODE				rc = NE_XFLM_OK;
	char				szCompareRules1[100];
	char				szCompareRules2[100];
	char				szName[100];
	char *			pszIndex = NULL;
	IF_DOMNode *	pNode = NULL;
	const char *	pszIndexFormat = 		
		"<xflaim:Index "
			"xmlns:xflaim=\"http://www.novell.com/XMLDatabase/Schema\" "
			"xflaim:name=\"%s_IX\" "
			"xflaim:DictNumber=\"%u\">"
			"<xflaim:ElementComponent "
				"xflaim:CompareRules=\"%s\" "
				"xflaim:targetNameSpace=\"\" "
				"xflaim:DictNumber=\"%u\" "
				"xflaim:IndexOn=\"value\" "
				"xflaim:Required=\"1\" " // have to make this required so it will match the sort key ixd
				"xflaim:KeyComponent=\"1\" />"
			"<xflaim:ElementComponent "
				"xflaim:CompareRules=\"%s\" "
				"xflaim:targetNameSpace=\"\" "
				"xflaim:DictNumber=\"%u\" "
				"xflaim:IndexOn=\"value\" "
				"xflaim:Required=\"1\" " // have to make this required so it will match the sort key ixd
				"xflaim:KeyComponent=\"2\"/>"
		"</xflaim:Index>";

	szCompareRules1[0] = '\0';
	szCompareRules2[0] = '\0';

	if( bComp1SortDescending)
	{
		f_strcpy( szCompareRules1, XFLM_DESCENDING_OPTION_STR);
	}

	if ( !bComp1CaseSensitive)
	{
		f_strcat( szCompareRules1, " "XFLM_CASE_INSENSITIVE_OPTION_STR);
	}

	if ( bComp1SortMissingHigh)
	{
		f_strcat( szCompareRules1, " "XFLM_MISSING_HIGH_OPTION_STR);
	}

	if ( bComp2SortDescending)
	{
		f_strcpy( szCompareRules2, XFLM_DESCENDING_OPTION_STR);
	}

	if ( bComp2SortMissingHigh)
	{
		f_strcat( szCompareRules2, " "XFLM_MISSING_HIGH_OPTION_STR);
	}

	f_sprintf( szName, "(%s/%s)", szCompareRules1, szCompareRules2); 

	if ( RC_BAD( rc = f_alloc( f_strlen( pszIndexFormat) + 
		(f_strlen( szCompareRules1) + f_strlen(szCompareRules2)) * 2 +
		16, &pszIndex)))
	{
		MAKE_FLM_ERROR_STRING( "f_alloc failed", m_szDetails, rc);
		goto Exit;
	}

	f_sprintf( pszIndex, pszIndexFormat, szName, uiIndex, 
		szCompareRules1, FIRST_NAME_ID, szCompareRules2, LAST_NAME_ID); 

	// remove the index if it already exists

	if ( RC_OK( rc = m_pDb->getDictionaryDef( ELM_INDEX_TAG, uiIndex, &pNode)))
	{
		if ( RC_BAD( rc = pNode->deleteNode( m_pDb)))
		{
			MAKE_FLM_ERROR_STRING( "deleteNode failed.", m_szDetails, rc);
			goto Exit;
		}
	}

	if ( RC_BAD( rc = importBuffer( pszIndex, XFLM_DICT_COLLECTION)))
	{
		goto Exit;
	}

Exit:

	if ( pNode)
	{
		pNode->Release();
	}

	if ( pszIndex)
	{
		f_free( &pszIndex);
	}

	return( rc);
}
예제 #24
0
/**************************************************************************
Desc:		Get the Flaim collating string and convert back to a text string
Ret:		Length of new wpStr
Notes:	Allocates the area for the word string buffer if will be over 256.
***************************************************************************/
RCODE flmColText2StorageText(
	const FLMBYTE *	pucColStr,				// Points to the collated string
	FLMUINT				uiColStrLen,			// Length of the collated string
	FLMBYTE *			pucStorageBuf,			// Output string to build - TEXT string
	FLMUINT *			puiStorageLen,			// In: Size of buffer, Out: Bytes used
	FLMUINT	   		uiLang,
	FLMBOOL *			pbDataTruncated,		// Sets to TRUE if data had been truncated
	FLMBOOL *			pbFirstSubstring)		// Sets to TRUE if first substring
{
#define LOCAL_CHARS		150
	FLMBYTE		ucWPStr[ LOCAL_CHARS * 2 + LOCAL_CHARS / 5 ];	// Sample + 20%
	FLMBYTE *  	pucWPPtr = NULL;
	FLMBYTE *	pucAllocatedWSPtr = NULL;
	FLMUINT		uiWPStrLen;
	FLMBYTE *	pucStoragePtr;
	FLMUINT		uiUnconvChars;
	FLMUINT		uiTmp;
	FLMUINT		uiMaxStorageBytes = *puiStorageLen;
	FLMUINT		uiMaxWPBytes;
	FLMUINT		uiStorageOffset;
	FLMBYTE		ucTmpSen[ 5];
	FLMBYTE *	pucTmpSen = &ucTmpSen[ 0];
	RCODE			rc = NE_FLM_OK;

	if( uiColStrLen > LOCAL_CHARS)
	{
		// If it won't fit, allocate a new buffer

		if( RC_BAD( rc = f_alloc( SFLM_MAX_KEY_SIZE * 2, &pucWPPtr)))
		{
			goto Exit;
		}

		pucAllocatedWSPtr = pucWPPtr;
		uiMaxWPBytes = uiWPStrLen = SFLM_MAX_KEY_SIZE * 2;
	}
	else
	{
		pucWPPtr = &ucWPStr[ 0];
		uiMaxWPBytes = uiWPStrLen = sizeof( ucWPStr);
	}

 	if( (uiLang >= FLM_FIRST_DBCS_LANG) &&
 		 (uiLang <= FLM_LAST_DBCS_LANG))
 	{
		if( RC_BAD( rc = f_asiaColStr2WPStr( pucColStr, uiColStrLen,
			pucWPPtr, &uiWPStrLen, &uiUnconvChars,
			pbDataTruncated, pbFirstSubstring)))
		{
			goto Exit;
		}
	}
	else
	{
		if( RC_BAD( rc = f_colStr2WPStr( pucColStr, uiColStrLen,
			pucWPPtr, &uiWPStrLen, uiLang, &uiUnconvChars,
			pbDataTruncated, pbFirstSubstring)))
		{
			goto Exit;
		}
	}

	// Copy word string to the storage string area

	uiWPStrLen >>= 1;	// Convert # of bytes to # of words
	pucStoragePtr = pucStorageBuf;
	uiStorageOffset = 0;

	// Encode the number of characters as a SEN.  If pucEncPtr is
	// NULL, the caller is only interested in the length of the encoded
	// string, so a temporary buffer is used to call f_encodeSEN.

	uiTmp = f_encodeSEN( uiWPStrLen - uiUnconvChars, &pucTmpSen);
	if( (uiStorageOffset + uiTmp) >= uiMaxStorageBytes)
	{
		rc = RC_SET( NE_FLM_CONV_DEST_OVERFLOW);
		goto Exit;
	}
	f_memcpy( pucStoragePtr, &ucTmpSen[ 0], uiTmp);
	uiStorageOffset += uiTmp;

	// Encode each of the WP characters into UTF-8

	while( uiWPStrLen--)
	{
		FLMBYTE			ucChar;
		FLMBYTE			ucCharSet;
		FLMUNICODE		uChar;

		// Put the character in a local variable for speed

		ucChar = *pucWPPtr++;
		ucCharSet = *pucWPPtr++;

		if( ucCharSet == 0xFF && ucChar == 0xFF)
		{
			uChar = (((FLMUNICODE)*(pucWPPtr + 1)) << 8) | *pucWPPtr;
			pucWPPtr += 2;
			uiWPStrLen--; // Skip past 4 bytes for UNICODE
		}
		else
		{
			if( RC_BAD( rc = f_wpToUnicode(
				(((FLMUINT16)ucCharSet) << 8) + ucChar, &uChar)))
			{
				goto Exit;
			}
		}

		uiTmp = uiMaxStorageBytes - uiStorageOffset;
		if( RC_BAD( rc = f_uni2UTF8( uChar,
			&pucStorageBuf[ uiStorageOffset], &uiTmp)))
		{
			goto Exit;
		}
		uiStorageOffset += uiTmp;
	}

	if( uiStorageOffset >= uiMaxStorageBytes)
	{
		rc = RC_SET( NE_FLM_CONV_DEST_OVERFLOW);
		goto Exit;
	}

	// Tack on a trailing NULL byte

	pucStorageBuf[ uiStorageOffset++] = 0;

	// Return the length of the storage buffer

	*puiStorageLen = uiStorageOffset;

Exit:

	if( pucAllocatedWSPtr)
	{
		f_free( &pucAllocatedWSPtr);
	}

	return( rc);
}
예제 #25
0
/****************************************************************************
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);
}	
예제 #26
0
/****************************************************************************
 Desc:	This function handle the details of extracting the parameters
			needed to interpret the request and then generating the response
			HTML page
 ****************************************************************************/
RCODE F_FFilePage::display(
	FLMUINT			uiNumParams,
	const char ** 	ppszParams)
{
	RCODE				rc = FERR_OK;
#define GENERIC_SIZE_B 20
	char				szFrom[ GENERIC_SIZE_B];
	char				szBucket[ 4];
	FLMUINT			uiBucket;
	FFILE				localFFile;
	FFILE *			pFile;
	FLMBOOL			bRefresh;
	void *			pvAddress;
	char				szAddress[GENERIC_SIZE_B];
	char				szLink[GENERIC_SIZE_B];
	FLMBOOL			bFlmLocked = FALSE;
	DATASTRUCT		DataStruct;
	FLMBYTE *		pszTemp = NULL;
	FLMBYTE *		pszTemp1 = NULL;

	if( RC_BAD( rc = f_alloc( 150, &pszTemp)))
	{
		printErrorPage( rc, TRUE, (char *)"Failed to allocate temporary buffer");
		goto Exit;
	}

	if( RC_BAD( rc = f_alloc( 150, &pszTemp1)))
	{
		printErrorPage( rc, TRUE, (char *)"Failed to allocate temporary buffer");
		goto Exit;
	}

	// Initialize a few variables first...
	szFrom[0] = '\0';
	szBucket[0] = '\0';

	pFile = NULL;

	
	// Get the "From" parameter.  We use this to determine everything else.
	if (RC_BAD( rc = ExtractParameter( uiNumParams,
												  ppszParams,
												  "From",
												  sizeof( szFrom),
												  szFrom)))
	{
		goto Exit;
	}
	
	f_mutexLock( gv_FlmSysData.hShareMutex);
	bFlmLocked = TRUE;


	if (!f_stricmp( szFrom, "FileHashTbl"))
	{

		//  Get the hash bucket index
		if (RC_BAD( rc = ExtractParameter( uiNumParams, 
													 ppszParams, 
													 "Bucket", 
													 sizeof( szBucket),
													 szBucket)))
		{
			goto Exit;
		}

		uiBucket = f_atoud( szBucket);
		pFile = (FFILE *)gv_FlmSysData.pFileHashTbl[uiBucket].pFirstInBucket;
	}
	else if ( (f_stricmp( szFrom, "SCacheBlock") == 0) || 
				 (f_stricmp( szFrom, "RCache") == 0) ||
				 (f_stricmp( szFrom, "FDB") == 0))
	{
		// Get the FFile address and the Hash Bucket
		if (RC_BAD( rc = ExtractParameter( uiNumParams,
													  ppszParams,
													  "Bucket",
													  sizeof( szBucket),
													  szBucket)))
		{
			goto Exit;
		}
		
		uiBucket = f_atoud( szBucket);
		if (RC_BAD( rc = ExtractParameter( uiNumParams,
													  ppszParams,
													  "Address",
													  sizeof( szAddress),
													  szAddress)))
		{
			goto Exit;
		}
		
		pvAddress = (void *)f_atoud( szAddress);

		pFile = (FFILE *)gv_FlmSysData.pFileHashTbl[uiBucket].pFirstInBucket;

		while (pFile && (void *)pFile != pvAddress)
		{
			pFile = pFile->pNext;
		}
		
	}
	else if (f_stricmp( szFrom, "FlmSysData") == 0)
	{
		// Get the Link and the FFile address
		if (RC_BAD( rc = ExtractParameter( uiNumParams,
													  ppszParams,
													  "Link",
													  sizeof( szLink),
													  szLink)))
		{
			goto Exit;
		}

		if (RC_BAD( rc = ExtractParameter( uiNumParams,
													  ppszParams,
													  "Address",
													  sizeof( szAddress),
													  szAddress)))
		{
			goto Exit;
		}
		
		pvAddress = (void *)f_atoud( szAddress);

		if (f_stricmp( szLink, "pMrnuFile") == 0)
		{
			pFile = gv_FlmSysData.pMrnuFile;
			
			// Now let's make sure we are looking at the right FFile...
			while (pFile && (void *)pFile != pvAddress)
			{
				pFile = pFile->pNextNUFile;
			}
		}
		else if (f_stricmp( szLink, "pLrnuFile") == 0)
		{
			pFile = gv_FlmSysData.pLrnuFile;

			// Now let's make sure we are looking at the right FFile...
			while (pFile && (void *)pFile != pvAddress)
			{
				pFile = pFile->pPrevNUFile;
			}
		}

	}
	else if (f_stricmp( szFrom, "FFile") == 0)
	{
		// We need to get the Link, Bucket & Address

		if (RC_BAD(rc = ExtractParameter( uiNumParams,
													 ppszParams,
													 "Link",
													 sizeof( szLink),
													 szLink)))
		{
			goto Exit;
		}

		if (RC_BAD(rc = ExtractParameter( uiNumParams,
													 ppszParams,
													 "Address",
													 sizeof( szAddress),
													 szAddress)))
		{
			goto Exit;
		}
		
		pvAddress = (void *)f_atoud( szAddress);

		if (RC_BAD(rc = ExtractParameter( uiNumParams,
													 ppszParams,
													 "Bucket",
													 sizeof( szBucket),
													 szBucket)))
		{
			goto Exit;
		}

		uiBucket = f_atoud( szBucket);

		// First, let's get a reference to an FFile from the specified bucket

		if (gv_FlmSysData.pFileHashTbl[uiBucket].pFirstInBucket)
		{
			pFile = (FFILE *)gv_FlmSysData.pFileHashTbl[uiBucket].pFirstInBucket;
		}

		// Now let's make sure we are looking at the right FFile...
		while (pFile && (void *)pFile != pvAddress)
		{
			pFile = pFile->pNext;
		}


		// Now what link are we supposed to follow?
		if (f_stricmp( szLink, "pNext") == 0)
		{
			pFile = pFile->pNext;
		}
		else if (f_stricmp( szLink, "pPrev") == 0)
		{
			pFile = pFile->pPrev;
		}
		else if (f_stricmp( szLink, "pNextNUFile") == 0)
		{
			pFile = pFile->pNextNUFile;
		}
		else if (f_stricmp( szLink, "pPrevNUFile") == 0)
		{
			pFile = pFile->pPrevNUFile;
		}

	}

	// Gather additional data if present. Initialize the structure before
	// using it.
	f_memset( &DataStruct, 0, sizeof(DataStruct));

	if (pFile)
	{
		f_memcpy( &localFFile, pFile, sizeof(localFFile));

		if (pFile->pSCacheList)
		{
			DataStruct.SCacheBlkAddress = pFile->pSCacheList->uiBlkAddress;
			DataStruct.SCacheLowTransID = scaGetLowTransID( pFile->pSCacheList),
			DataStruct.SCacheHighTransID = pFile->pSCacheList->uiHighTransID;
		}
		if (pFile->pPendingWriteList)
		{
			DataStruct.PendingWriteBlkAddress = pFile->pPendingWriteList->uiBlkAddress;
			DataStruct.PendingWriteLowTransID = scaGetLowTransID( pFile->pPendingWriteList),
			DataStruct.PendingWriteHighTransID = pFile->pPendingWriteList->uiHighTransID;
		}
		if (pFile->pLastDirtyBlk)
		{
			DataStruct.LastDirtyBlkAddress = pFile->pLastDirtyBlk->uiBlkAddress;
			DataStruct.LastDirtyLowTransID = scaGetLowTransID( pFile->pLastDirtyBlk),
			DataStruct.LastDirtyHighTransID = pFile->pLastDirtyBlk->uiHighTransID;
		}
		
		if (pFile->pFirstRecord)
		{
			DataStruct.FirstRecordContainer = pFile->pFirstRecord->uiContainer;
			DataStruct.FirstRecordDrn = pFile->pFirstRecord->uiDrn;
			DataStruct.FirstRecordLowTransId = pFile->pFirstRecord->uiLowTransId;
		}

		if (pFile->pLastRecord)
		{
			DataStruct.LastRecordContainer = pFile->pLastRecord->uiContainer;
			DataStruct.LastRecordDrn = pFile->pLastRecord->uiDrn;
			DataStruct.LastRecordLowTransId = pFile->pLastRecord->uiLowTransId;
		}
	}
	

	f_mutexUnlock( gv_FlmSysData.hShareMutex);
	bFlmLocked = FALSE;

	stdHdr();

	fnPrintf( m_pHRequest, HTML_DOCTYPE);
	fnPrintf( m_pHRequest,  "<html>\n");


	// Determine if we are being requested to refresh this page or  not.
	if ((bRefresh = DetectParameter( uiNumParams,
											   ppszParams,
											   "Refresh")) == TRUE)
	{
		// Send back the page with a refresh command in the header
		f_sprintf( (char *)pszTemp, "%s/FFile?Refresh&From=%s&Bucket=%s",
					m_pszURLString,
					szFrom, szBucket);

		fnPrintf( m_pHRequest, 
			"<HEAD>"
			"<META http-equiv=\"refresh\" content=\"5; url=%s\">"
			"<TITLE>FFile Structure</TITLE>\n", pszTemp);
	}
	else
	{
		fnPrintf( m_pHRequest, "<HEAD><TITLE>FFile Structure</TITLE>\n");
	}
	printStyle();
	fnPrintf( m_pHRequest, "</HEAD>\n");

	fnPrintf( m_pHRequest,  "<body>\n");

	// If we are not to refresh this page, then don't include the
	// refresh meta command
	if (!bRefresh)
	{
		f_sprintf( (char *)pszTemp,
					"<A HREF=%s/FFile?Refresh&From=%s&Bucket=%s>Start Auto-refresh (5 sec.)</A>",
					m_pszURLString, szFrom, szBucket);
	}
	else
	{
		f_sprintf( (char *)pszTemp,
               "<A HREF=%s/FFile?From=%s&Bucket=%s>Stop Auto-refresh</A>",
					m_pszURLString, szFrom, szBucket);
	}
	// Prepare the refresh link.
	f_sprintf( (char *)pszTemp1,
            "<A HREF=%s/FFile?From=%s&Bucket=%s>Refresh</A>",
				m_pszURLString, szFrom, szBucket);



	// Show the table headings and the refresh option.

	if (pFile)
	{
		// Write out the table headings
		printTableStart( "FFile Structure", 4, 100);

		printTableRowStart();
		printColumnHeading( "", JUSTIFY_LEFT, FLM_IMON_COLOR_PUTTY_1, 4, 1, FALSE);
		fnPrintf( m_pHRequest, "%s, ", pszTemp1);
		fnPrintf( m_pHRequest, "%s\n", pszTemp);
		printColumnHeadingClose();
		printTableRowEnd();

		// Write out the table headings.
		printTableRowStart();
		printColumnHeading( "Byte Offset (hex)");
		printColumnHeading( "Field Name");
		printColumnHeading( "Field Type");
		printColumnHeading( "Value");
		printTableRowEnd();

		write_data( (pFile ? &localFFile: NULL), (void *)pFile, &DataStruct);

	}
	else
	{
		// Write out an error page...
		fnPrintf( m_pHRequest, 
			"<P>Unable to find the FFile structure that you requested."
			"  This is probably because the state of the cache changed between "
			"the time that you displayed the previous page and the time that you "
			"clicked on the link that brought you here.\n"
			"<P>Click on your browser's \"Back\" button, then click \"Reload\" "
			"and then try the link again.\n");
	}


	fnPrintf( m_pHRequest,  "</body></html>\n");

	fnEmit();

Exit:

	if (bFlmLocked)
	{
		f_mutexUnlock( gv_FlmSysData.hShareMutex);
		bFlmLocked = FALSE;
	}

	if (pszTemp)
	{
		f_free( &pszTemp);
	}

	if (pszTemp1)
	{
		f_free( &pszTemp1);
	}

	return( rc);


}
예제 #27
0
/****************************************************************************
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);
}
예제 #28
0
/*******************************************************************************
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);
}
예제 #29
0
파일: ftrans.cpp 프로젝트: ajumi2/libflaim
/****************************************************************************
Desc:	This routine commits an active transaction for a particular
		database.  If the database is open via a server, a message is
		sent to the server to commit the transaction.  Otherwise, the
		transaction is committed locally.
****************************************************************************/
RCODE flmCommitDbTrans(
	FDB *				pDb,
	FLMUINT			uiNewLogicalEOF,
	FLMBOOL			bForceCheckpoint,
	FLMBOOL *		pbEmpty)
{
	RCODE	  			rc = FERR_OK;
	FLMBYTE *		pucUncommittedLogHdr;
	FFILE *			pFile = pDb->pFile;
	FLMUINT			uiCPFileNum = 0;
	FLMUINT			uiCPOffset = 0;
	FLMUINT			uiTransId = 0;
	FLMBOOL			bTransEndLogged;
	FLMBOOL			bForceCloseOnError = FALSE;
	FLMBOOL			bOkToLogAbort = TRUE;
	DB_STATS *		pDbStats = pDb->pDbStats;
	FLMUINT			uiTransType;
	FLMBOOL			bInvisibleTrans = FALSE;
	FLMBOOL			bIndexAfterCommit = FALSE;

	pDb->uiFlags |= FDB_COMMITTING_TRANS;

	// See if we even have a transaction going.

	if ((uiTransType = pDb->uiTransType) == FLM_NO_TRANS)
	{
		goto Exit;	// Will return FERR_OK.
	}

	// See if we have a transaction going which should be aborted.

	if (flmCheckBadTrans( pDb))
	{
		rc = RC_SET( FERR_ABORT_TRANS);
		goto Exit;
	}

	// If we are in a read transaction we can skip most of the stuff
	// below because no updates would have occurred.  This will help
	// improve performance.

	if (uiTransType == FLM_READ_TRANS)
	{

		if( pDb->KrefCntrl.bKrefSetup)
		{
			// KrefCntrlFree could be called w/o checking bKrefSetup because
			// it checks the flag, but it is more optimal to check the
			// flag before making the call because most of the time it will
			// be false.

			KrefCntrlFree( pDb);
		}
		goto Exit1;
	}

	// At this point, we know we have an update transaction.

	pFile->pRfl->clearLogHdrs();

#ifdef FLM_DBG_LOG
	flmDbgLogUpdate( pFile->uiFFileId, pDb->LogHdr.uiCurrTransID,
			0, 0, FERR_OK, "TCmit");
#endif
	uiTransId = pDb->LogHdr.uiCurrTransID;

	// If the transaction had no update operations, restore it
	// to its pre-transaction state - make it appear that no
	// transaction ever happened.

	if (!pDb->bHadUpdOper)
	{
		bOkToLogAbort = FALSE;
		rc = pFile->pRfl->logEndTransaction( RFL_TRNS_COMMIT_PACKET, TRUE);

		// Even though we didn't have any update operations, there may have
		// been operations during the transaction (i.e., query operations)
		// that initialized the KREF in order to generate keys.

		KrefCntrlFree( pDb);

		// Restore everything as if the transaction never happened.

		f_mutexLock( gv_FlmSysData.hShareMutex);
		pFile->uiUpdateTransID = 0;
		f_mutexUnlock( gv_FlmSysData.hShareMutex);
		if (pbEmpty)
		{
			*pbEmpty = TRUE;
		}
		goto Exit1;
	}

	// Log commit record to roll-forward log

	bOkToLogAbort = FALSE;
	if (RC_BAD( rc = pFile->pRfl->logEndTransaction(
								RFL_TRNS_COMMIT_PACKET, FALSE, &bTransEndLogged)))
	{
		goto Exit1;
	}
	bForceCloseOnError = TRUE;

	// Commit any keys in the KREF buffers.

	if (RC_BAD( rc = KYKeysCommit( pDb, TRUE)))
	{
		flmLogError( rc, "calling KYKeysCommit from flmCommitDbTrans");
		goto Exit1;
	}

	if (RC_BAD( rc = FSCommitIxCounts( pDb)))
	{
		flmLogError( rc, "calling FSCommitIxCounts from flmCommitDbTrans");
		goto Exit1;
	}

	// Reinitialize the log header.  If the local dictionary was updated
	// during the transaction, increment the local dictionary ID so that
	// other concurrent users will know that it has been modified and
	// that they need to re-read it into memory.

	// If we are in recovery mode, see if we need to force
	// a checkpoint with what we have so far.  We force a
	// checkpoint on one of two conditions:
	
	// 1. If it appears that we have a buildup of dirty cache
	//		blocks.  We force a checkpoint on this condition
	//		because it will be more efficient than replacing
	//		cache blocks one at a time.
	//		We check for this condition by looking to see if
	//		our LRU block is not used and it is dirty.  That is
	//		a pretty good indicator that we have a buildup
	//		of dirty cache blocks.
	// 2.	We are at the end of the roll-forward log.  We
	//		want to force a checkpoint here to complete the
	//		recovery phase.

	if ( pDb->uiFlags & FDB_REPLAYING_RFL)
	{
		// If we are in the middle of upgrading, and are forcing
		// a checkpoint, use the file number and offset that were
		// set in the FDB.

		if ((pDb->uiFlags & FDB_UPGRADING) && bForceCheckpoint)
		{
			uiCPFileNum = pDb->uiUpgradeCPFileNum;
			uiCPOffset = pDb->uiUpgradeCPOffset;
		}
		else
		{
			SCACHE *		pTmpSCache;
			F_Rfl *		pRfl = pFile->pRfl;

			f_mutexLock( gv_FlmSysData.hShareMutex);
			pTmpSCache = gv_FlmSysData.SCacheMgr.pLRUCache;

			// Test for buildup of dirty cache blocks.

			if( (pTmpSCache && !pTmpSCache->uiUseCount &&
				  (pTmpSCache->ui16Flags & 
						(CA_DIRTY | CA_LOG_FOR_CP | CA_WRITE_TO_LOG))) ||
				pRfl->atEndOfLog() || bForceCheckpoint)
			{
				bForceCheckpoint = TRUE;
				uiCPFileNum = pRfl->getCurrFileNum();
				uiCPOffset = pRfl->getCurrReadOffset();
			}
			
			f_mutexUnlock( gv_FlmSysData.hShareMutex);
		}
	}

	// Move information collected in the pDb->LogHdr into the
	// uncommitted log header.  Other things that need to be
	// set have already been set in the uncommitted log header
	// at various places in the code.

	// Mutex does not have to be locked while we do this because
	// the update transaction is the only one that ever accesses
	// the uncommitted log header buffer.

	pucUncommittedLogHdr = &pFile->ucUncommittedLogHdr [0];

	// Set the new logical EOF if passed in.

	if( uiNewLogicalEOF)
	{
		pDb->LogHdr.uiLogicalEOF = uiNewLogicalEOF;
	}
	
	UD2FBA( (FLMUINT32)pDb->LogHdr.uiLogicalEOF,
		&pucUncommittedLogHdr [LOG_LOGICAL_EOF]);

	// Increment the commit counter.

	flmIncrUint( &pucUncommittedLogHdr [LOG_COMMIT_COUNT], 1);

	// Set the last committed transaction ID

	if( (bTransEndLogged || (pDb->uiFlags & FDB_REPLAYING_COMMIT)) &&
		pDb->pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_31)
	{
		UD2FBA( (FLMUINT32)uiTransId, 
			&pucUncommittedLogHdr [LOG_LAST_RFL_COMMIT_ID]);
	}

	// Write the header

	pFile->pRfl->commitLogHdrs( pucUncommittedLogHdr,
							pFile->ucCheckpointLogHdr);

	// Commit any record cache.

	flmRcaCommitTrans( pDb);

	// Push the IXD_FIXUP values back into the IXD

	if (pDb->pIxdFixups)
	{
		IXD_FIXUP *	pIxdFixup;
		IXD_FIXUP *	pDeleteIxdFixup;
		IXD *			pIxd;

		pIxdFixup = pDb->pIxdFixups;
		while (pIxdFixup)
		{
			if( RC_BAD( fdictGetIndex(
				pDb->pDict, pDb->pFile->bInLimitedMode,
				pIxdFixup->uiIndexNum, NULL, &pIxd, TRUE)))
			{
				flmAssert( 0);
				pIxd = NULL;
			}

			if( pIxd)
			{
				pIxd->uiLastContainerIndexed = pIxdFixup->uiLastContainerIndexed;
				pIxd->uiLastDrnIndexed = pIxdFixup->uiLastDrnIndexed;
			}
			pDeleteIxdFixup = pIxdFixup;
			pIxdFixup = pIxdFixup->pNext;
			f_free( &pDeleteIxdFixup);
		}
		pDb->pIxdFixups = NULL;
	}

	// Set the update transaction ID back to zero only 
	// AFTER we know the transaction has safely committed.

	f_mutexLock( gv_FlmSysData.hShareMutex);
	f_memcpy( pFile->ucLastCommittedLogHdr, pucUncommittedLogHdr,
					LOG_HEADER_SIZE);
	pFile->uiUpdateTransID = 0;
	ScaReleaseLogBlocks( pFile);
	if (pDb->uiFlags & FDB_UPDATED_DICTIONARY)
	{
		// Link the new local dictionary to its file.
		// Since the new local dictionary will be linked at the head
		// of the list of FDICT structures, see if the FDICT currently
		// at the head of the list is unused and can be unlinked.

		if ((pFile->pDictList) && (!pFile->pDictList->uiUseCount))
		{
			flmUnlinkDict( pFile->pDictList);
		}
		flmLinkDictToFile( pFile, pDb->pDict);
	}

	f_mutexUnlock( gv_FlmSysData.hShareMutex);

Exit1:

	// If the local dictionary was updated during this transaction,
	// link the new local dictionary structures to their file - or free
	// them if there was an error.

	if (pDb->uiFlags & FDB_UPDATED_DICTIONARY)
	{
		if( RC_BAD( rc) && pDb->pDict)
		{
			// Unlink the FDB from the FDICT. - Shouldn't have
			// to lock semaphore, because the DICT is NOT linked
			// to the FFILE.

			flmAssert( pDb->pDict->pFile == NULL);
			flmUnlinkFdbFromDict( pDb);
		}
	}

	if (RC_BAD( rc))
	{

		// Since we failed to commit, do an abort.  We are purposely not
		// checking the return code from flmAbortDbTrans because we already
		// have an error return code.  If we attempted to log the transaction
		// to the RFL and failed, we don't want to try to log an abort packet.
		// The RFL code has already reset the log back to the starting point 
		// of the transaction, thereby discarding all operations.

		pDb->uiFlags &= ~FDB_COMMITTING_TRANS;
		(void)flmAbortDbTrans( pDb, bOkToLogAbort);
		uiTransType = FLM_NO_TRANS;

		// Do we need to force all handles to close?

		if( bForceCloseOnError)
		{

			// Since the commit packet has already been logged to the RFL,
			// we must have failed when trying to write the log header.  The
			// database is in a bad state and must be closed.

			// Set the "must close" flag on all FDBs linked to the FFILE
			// and set the FFILE's "must close" flag.  This will cause any
			// subsequent operations on the database to fail until all
			// handles have been closed.

			flmSetMustCloseFlags( pFile, rc, FALSE);
		}
	}
	else
	{
		bInvisibleTrans = (pDb->uiFlags & FDB_INVISIBLE_TRANS) ? TRUE : FALSE;
		if (uiTransType == FLM_UPDATE_TRANS)
		{
			if (gv_FlmSysData.UpdateEvents.pEventCBList)
			{
				flmTransEventCallback( F_EVENT_COMMIT_TRANS, (HFDB)pDb, rc,
							uiTransId);
			}

			// Do the BLOB and indexing work before we unlock the db.

			FBListAfterCommit( pDb);
			
			if (pDb->pIxStopList || pDb->pIxStartList)
			{
				
				// Must not call flmIndexingAfterCommit until after
				// completeTransWrites.  Otherwise, there is a potential
				// deadlock condition where flmIndexingAfterCommit is
				// waiting on an indexing thread to quit, but that
				// thread is waiting to be signaled by this thread that
				// writes are completed.  However, flmIndexingAfterCommit
				// also must only be called while the database is still
				// locked.  If we were to leave the database locked for
				// every call to completeTransWrites, however, we would
				// lose the group commit capability.  Hence, we opt to
				// only lose it when there are actual indexing operations
				// to start or stop - which should be very few transactions.
				// That is what the bIndexAfterCommit flag is for.
				
				bIndexAfterCommit = TRUE;
			}
		}
	}

	// Unlock the database, if the update transaction is still going.
	// NOTE: We check uiTransType because it may have been reset
	// to FLM_NO_TRANS up above if flmAbortDbTrans was called.

	if (uiTransType == FLM_UPDATE_TRANS)
	{
		if (RC_BAD( rc))
		{

			// SHOULD NEVER HAPPEN - because it would have been taken
			// care of above - flmAbortDbTrans would have been called and
			// uiTransType would no longer be FLM_UPDATE_TRANS.

			flmAssert( 0);
			(void)pFile->pRfl->completeTransWrites( pDb, FALSE, TRUE);
		}
		else if( !bForceCheckpoint)
		{
			if( bIndexAfterCommit)
			{
				rc = pFile->pRfl->completeTransWrites( pDb, TRUE, FALSE);
				flmIndexingAfterCommit( pDb);
				flmUnlinkDbFromTrans( pDb, TRUE);
			}
			else
			{
				rc = pFile->pRfl->completeTransWrites( pDb, TRUE, TRUE);
			}
		}
		else
		{

			// Do checkpoint, if forcing.  Before doing the checkpoint
			// we have to make sure the roll-forward log writes
			// complete.  We don't want to unlock the DB while the
			// writes are happening in this case - thus, the FALSE
			// parameter to completeTransWrites.

			if (RC_OK( rc = pFile->pRfl->completeTransWrites( pDb, TRUE, FALSE)))
			{
				bForceCloseOnError = FALSE;
				rc = ScaDoCheckpoint( pDbStats, pDb->pSFileHdl, pFile,
						(pDb->uiFlags & FDB_DO_TRUNCATE) ? TRUE : FALSE,
						TRUE, CP_TIME_INTERVAL_REASON,
						uiCPFileNum, uiCPOffset);
			}
			
			if (bIndexAfterCommit)
			{
				flmIndexingAfterCommit( pDb);
			}
			
			flmUnlinkDbFromTrans( pDb, TRUE);
		}

		if (RC_BAD( rc) && bForceCloseOnError)
		{

			// Since the commit packet has already been logged to the RFL,
			// we must have failed when trying to write the log header.  The
			// database is in a bad state and must be closed.

			// Set the "must close" flag on all FDBs linked to the FFILE
			// and set the FFILE's "must close" flag.  This will cause any
			// subsequent operations on the database to fail until all
			// handles have been closed.

			flmSetMustCloseFlags( pFile, rc, FALSE);
		}
	}
	else
	{

		// Unlink the database from the transaction
		// structure as well as from the FDICT structure.

		flmUnlinkDbFromTrans( pDb, FALSE);
	}

	if (pDbStats && uiTransType != FLM_NO_TRANS)
	{
		FLMUINT64	ui64ElapMilli = 0;

		flmAddElapTime( &pDb->TransStartTime, &ui64ElapMilli);
		pDbStats->bHaveStats = TRUE;
		if (uiTransType == FLM_READ_TRANS)
		{
			pDbStats->ReadTransStats.CommittedTrans.ui64Count++;
			pDbStats->ReadTransStats.CommittedTrans.ui64ElapMilli +=
					ui64ElapMilli;
			if (bInvisibleTrans)
			{
				pDbStats->ReadTransStats.InvisibleTrans.ui64Count++;
				pDbStats->ReadTransStats.InvisibleTrans.ui64ElapMilli +=
					ui64ElapMilli;
			}
		}
		else
		{
			pDbStats->UpdateTransStats.CommittedTrans.ui64Count++;
			pDbStats->UpdateTransStats.CommittedTrans.ui64ElapMilli +=
					ui64ElapMilli;
		}
	}

	// Update stats

	if (pDb->pStats)
	{
		(void)flmStatUpdate( &gv_FlmSysData.Stats, &pDb->Stats);
	}

Exit:

	pDb->uiFlags &= ~FDB_COMMITTING_TRANS;
	return( rc);
}
예제 #30
0
파일: ftrans.cpp 프로젝트: ajumi2/libflaim
/****************************************************************************
Desc:	This routine aborts an active transaction for a particular
		database.  If the database is open via a server, a message is
		sent to the server to abort the transaction.  Otherwise, the
		transaction is rolled back locally.
****************************************************************************/
RCODE flmAbortDbTrans(
	FDB *				pDb,
	FLMBOOL			bOkToLogAbort)
{
	RCODE				rc = FERR_OK;
	FFILE *			pFile = pDb->pFile;
	FLMUINT			uiTransType;
	FLMBYTE *		pucLastCommittedLogHdr;
	FLMBYTE *		pucUncommittedLogHdr;
	FLMBOOL			bDumpedCache = FALSE;
	DB_STATS *		pDbStats = pDb->pDbStats;
	FLMBOOL			bKeepAbortedTrans;
	FLMUINT			uiTransId;
	FLMBOOL			bInvisibleTrans;

	// Get transaction type

	if ((uiTransType = pDb->uiTransType) == FLM_NO_TRANS)
	{
		goto Exit;
	}

	// No recovery required if it is a read transaction.

	if (uiTransType == FLM_READ_TRANS)
	{

		if( pDb->KrefCntrl.bKrefSetup)
		{
			// KrefCntrlFree could be called w/o checking bKrefSetup because
			// it checks the flag, but it is more optimal to check the
			// flag before making the call because most of the time it will
			// be false.

			KrefCntrlFree( pDb);
		}

		goto Unlink_From_Trans;
	}

#ifdef FLM_DBG_LOG
	flmDbgLogUpdate( pFile->uiFFileId, pDb->LogHdr.uiCurrTransID,
			0, 0, FERR_OK, "TAbrt");
#endif

	pFile->pRfl->clearLogHdrs();

	// If the transaction had no update operations, restore it
	// to its pre-transaction state - make it appear that no
	// transaction ever happened.

	pucLastCommittedLogHdr = &pFile->ucLastCommittedLogHdr [0];
	pucUncommittedLogHdr = &pFile->ucUncommittedLogHdr [0];
	uiTransId = pDb->LogHdr.uiCurrTransID;

	// Free up all keys associated with this database.  This is done even
	// if we didn't have any update operations because the KREF may
	// have been initialized by key generation operations performed
	// by cursors, etc.

	KrefCntrlFree( pDb);

	// Free any index counts we may have allocated.

	FSFreeIxCounts( pDb);
	
	if (pDb->bHadUpdOper)
	{
		// Dump any BLOB structures that should be aborted.

		FBListAfterAbort( pDb);

		// Dump any start and stop indexing stubs that should be aborted.

		flmIndexingAfterAbort( pDb);

		// Log the abort record to the rfl file, or throw away the logged
		// records altogether, depending on the LOG_KEEP_ABORTED_TRANS_IN_RFL
		// flag.  If the RFL volume is bad, we will not attempt to keep this
		// transaction in the RFL.

		if (!pFile->pRfl->seeIfRflVolumeOk())
		{
			bKeepAbortedTrans = FALSE;
		}
		else
		{
			bKeepAbortedTrans =
				(pucUncommittedLogHdr [LOG_KEEP_ABORTED_TRANS_IN_RFL])
				? TRUE
				: FALSE;
		}
	}
	else
	{
		bKeepAbortedTrans = FALSE;
	}

	// Log an abort transaction record to the roll-forward log or
	// throw away the entire transaction, depending on the
	// bKeepAbortedTrans flag.

	// If the transaction is being "dumped" because of a failed commit,
	// don't log anything to the RFL.

	if( bOkToLogAbort)
	{
		flmAssert( pDb->LogHdr.uiCurrTransID == pFile->pRfl->getCurrTransID());
		if (RC_BAD( rc = pFile->pRfl->logEndTransaction(
									RFL_TRNS_ABORT_PACKET, !bKeepAbortedTrans)))
		{
			goto Exit1;
		}
	}
#ifdef FLM_DEBUG
	else
	{
		// If bOkToLogAbort is FALSE, this always means that either a
		// commit failed while trying to log an end transaction packet or a
		// commit packet was logged and the transaction commit subsequently
		// failed for some other reason.  In either case, the RFL should be
		// in a good state, with its current transaction ID reset to 0.  If
		// not, either bOkToLogAbort is being used incorrectly by the caller
		// or there is a bug in the RFL logic.

		flmAssert( pFile->pRfl->getCurrTransID() == 0);
	}
#endif

	// If there were no operations in the transaction, restore
	// everything as if the transaction never happened.

	if (!pDb->bHadUpdOper)
	{
		f_mutexLock( gv_FlmSysData.hShareMutex);
		pFile->uiUpdateTransID = 0;
		f_mutexUnlock( gv_FlmSysData.hShareMutex);

		// Pretend we dumped cache - shouldn't be any to worry about at
		// this point.

		bDumpedCache = TRUE;
		goto Exit1;
	}

	// Dump ALL modified cache blocks associated with the DB.
	// NOTE: This needs to be done BEFORE the call to flmGetLogHdrInfo
	// below, because that call will change pDb->LogHdr.uiCurrTransID,
	// and that value is used by flmRcaAbortTrans.

	ScaFreeModifiedBlocks( pDb);
	flmRcaAbortTrans( pDb);
	bDumpedCache = TRUE;

	// Reset the LogHdr from the last committed log header in pFile.

	flmGetLogHdrInfo( pucLastCommittedLogHdr, &pDb->LogHdr);
	if (RC_BAD( rc = flmPhysRollback( pDb,
				 (FLMUINT)FB2UD( &pucUncommittedLogHdr [LOG_ROLLBACK_EOF]),
				 pFile->uiFirstLogBlkAddress, FALSE, 0)))
	{
		goto Exit1;
	}

	f_mutexLock( gv_FlmSysData.hShareMutex);

	// Put the new transaction ID into the log header even though
	// we are not committing.  We want to keep the transaction IDs
	// incrementing even though we aborted.

	UD2FBA( (FLMUINT32)uiTransId,
			&pucLastCommittedLogHdr [LOG_CURR_TRANS_ID]);

	// Preserve where we are at in the roll-forward log.  Even though
	// the transaction aborted, we may have kept it in the RFL instead of
	// throw it away.

	f_memcpy( &pucLastCommittedLogHdr [LOG_RFL_FILE_NUM],
				 &pucUncommittedLogHdr [LOG_RFL_FILE_NUM], 4);
	f_memcpy( &pucLastCommittedLogHdr [LOG_RFL_LAST_TRANS_OFFSET],
				 &pucUncommittedLogHdr [LOG_RFL_LAST_TRANS_OFFSET], 4);
	f_memcpy( &pucLastCommittedLogHdr [LOG_LAST_TRANS_RFL_SERIAL_NUM],
				 &pucUncommittedLogHdr [LOG_LAST_TRANS_RFL_SERIAL_NUM],
				 F_SERIAL_NUM_SIZE);
	f_memcpy( &pucLastCommittedLogHdr [LOG_RFL_NEXT_SERIAL_NUM],
				 &pucUncommittedLogHdr [LOG_RFL_NEXT_SERIAL_NUM],
				 F_SERIAL_NUM_SIZE);

	// The following items tell us where we are at in the roll-back log.
	// During a transaction we may log blocks for the checkpoint or for
	// read transactions.  So, even though we are aborting this transaction,
	// there may be other things in the roll-back log that we don't want
	// to lose.  These items should not be reset until we do a checkpoint,
	// which is when we know it is safe to throw away the entire roll-back log.

	f_memcpy( &pucLastCommittedLogHdr [LOG_ROLLBACK_EOF],
				 &pucUncommittedLogHdr [LOG_ROLLBACK_EOF], 4);
	f_memcpy( &pucLastCommittedLogHdr [LOG_PL_FIRST_CP_BLOCK_ADDR],
				 &pucUncommittedLogHdr [LOG_PL_FIRST_CP_BLOCK_ADDR], 4);

	f_mutexUnlock( gv_FlmSysData.hShareMutex);

	pFile->pRfl->commitLogHdrs( pucLastCommittedLogHdr,
							pFile->ucCheckpointLogHdr);

Exit1:

	// Dump cache, if not done above.

	if (!bDumpedCache)
	{
		ScaFreeModifiedBlocks( pDb);
		flmRcaAbortTrans( pDb);
		bDumpedCache = TRUE;
	}

	// Throw away IXD_FIXUPs

	if (pDb->pIxdFixups)
	{
		IXD_FIXUP *	pIxdFixup;
		IXD_FIXUP *	pDeleteIxdFixup;

		pIxdFixup = pDb->pIxdFixups;
		while (pIxdFixup)
		{
			pDeleteIxdFixup = pIxdFixup;
			pIxdFixup = pIxdFixup->pNext;
			f_free( &pDeleteIxdFixup);
		}
		pDb->pIxdFixups = NULL;
	}

	if (uiTransType != FLM_READ_TRANS &&
		 gv_FlmSysData.UpdateEvents.pEventCBList)
	{
		flmTransEventCallback( F_EVENT_ABORT_TRANS, (HFDB)pDb, rc,
						uiTransId);
	}

Unlink_From_Trans:

	bInvisibleTrans = (pDb->uiFlags & FDB_INVISIBLE_TRANS) ? TRUE : FALSE;
	if (pDb->uiFlags & FDB_HAS_WRITE_LOCK)
	{
		RCODE	tmpRc;

		if (RC_BAD( tmpRc = pFile->pRfl->completeTransWrites( pDb, FALSE, FALSE)))
		{
			if (RC_OK( rc))
			{
				rc = tmpRc;
			}
		}
	}

	// Unlink the database from the transaction
	// structure as well as from the FLDICT structure.

	flmUnlinkDbFromTrans( pDb, FALSE);

	if (pDbStats)
	{
		FLMUINT64	ui64ElapMilli = 0;

		flmAddElapTime( &pDb->TransStartTime, &ui64ElapMilli);
		pDbStats->bHaveStats = TRUE;
		if (uiTransType == FLM_READ_TRANS)
		{
			pDbStats->ReadTransStats.AbortedTrans.ui64Count++;
			pDbStats->ReadTransStats.AbortedTrans.ui64ElapMilli +=
					ui64ElapMilli;
			if (bInvisibleTrans)
			{
				pDbStats->ReadTransStats.InvisibleTrans.ui64Count++;
				pDbStats->ReadTransStats.InvisibleTrans.ui64ElapMilli +=
					ui64ElapMilli;
			}
		}
		else
		{
			pDbStats->UpdateTransStats.AbortedTrans.ui64Count++;
			pDbStats->UpdateTransStats.AbortedTrans.ui64ElapMilli +=
					ui64ElapMilli;
		}
	}

	if (pDb->pStats)
	{
		(void)flmStatUpdate( &gv_FlmSysData.Stats, &pDb->Stats);
	}

Exit:

	return( rc);
}