// buffer can stay in RAM of Flash
// ret -1 = error, ret 0 = disconnected
int32_t MTD_FLASHMEM Socket::write(void const *buffer, uint32_t length) {
  static uint32_t const MAXCHUNKSIZE = 128;

  if (!checkConnection())
    return -1;

  int32_t bytesSent = 0;
  // send in chunks of up to MAXCHUNKSIZE bytes
  uint8_t rambuf[min(length, MAXCHUNKSIZE)];
  uint8_t const *src = (uint8_t const *)buffer;
  while (bytesSent < length) {
    uint32_t bytesToSend = min(MAXCHUNKSIZE, length - bytesSent);
    f_memcpy(rambuf, src, bytesToSend);
    int32_t chunkBytesSent =
        m_remoteAddress.sin_len == 0
            ? lwip_send(m_socket, rambuf, bytesToSend, MSG_DONTWAIT)
            : lwip_sendto(m_socket, rambuf, bytesToSend, 0, (sockaddr *)&m_remoteAddress, sizeof(m_remoteAddress));
    int32_t lasterr = getLastError();
    if (lasterr == EAGAIN || lasterr == EWOULDBLOCK) {
      chunkBytesSent = 0;
    } else if (chunkBytesSent <= 0 || lasterr != 0) {
      // error
      bytesSent = -1;
      break;
    }
    bytesSent += chunkBytesSent;
    src += chunkBytesSent;
  }
  if (length > 0)
    m_connected = (bytesSent > 0);
  return bytesSent;
}
Example #2
0
/****************************************************************************
Desc:	All of the toAscii() functions convert values from their native
		formats to a string representation
****************************************************************************/
RCODE F_IniFile::toAscii( 
	char **		ppszParamValue,
	FLMBOOL 		bVal)
{
	RCODE		rc = NE_FLM_OK;
	
	if( RC_BAD( rc = m_pool.poolAlloc( 6, (void **)ppszParamValue)))
	{
		goto Exit;
	}
	
	if( bVal)
	{
		f_memcpy( *ppszParamValue, "TRUE ", 6);
	}
	else
	{
		f_memcpy( *ppszParamValue, "FALSE", 6);
	}
	
	m_bModified = TRUE;
	
Exit:

	return( rc);
}
Example #3
0
/****************************************************************************
Desc: Recover a database on startup.
****************************************************************************/
RCODE F_Database::doRecover(
	F_Db *					pDb,
	IF_RestoreClient *	pRestoreObj,
	IF_RestoreStatus *	pRestoreStatus)
{
	RCODE				rc = NE_XFLM_OK;
	XFLM_DB_HDR *	pLastCommittedDbHdr;

	// At this point, m_lastCommittedDbHdr contains the header
	// that was read from disk, which will be the state of the
	// header as of the last completed checkpoint.  Therefore,
	// we copy it into m_checkpointDbHdr.

	pLastCommittedDbHdr = &m_lastCommittedDbHdr;
	f_memcpy( &m_checkpointDbHdr, pLastCommittedDbHdr, sizeof( XFLM_DB_HDR));

	// Do a physical rollback on the database to restore the last
	// checkpoint.

	if (RC_BAD( rc = pDb->physRollback(
							(FLMUINT)pLastCommittedDbHdr->ui32RblEOF,
							(FLMUINT)pLastCommittedDbHdr->ui32RblFirstCPBlkAddr,
							TRUE,
							pLastCommittedDbHdr->ui64RflLastCPTransID)))
	{
		goto Exit;
	}
	pLastCommittedDbHdr->ui32RblFirstCPBlkAddr = 0;
	pLastCommittedDbHdr->ui32RblEOF = (FLMUINT32)m_uiBlockSize;
	if (RC_BAD( rc = writeDbHdr( pDb->m_pDbStats, pDb->m_pSFileHdl,
								pLastCommittedDbHdr,
								&m_checkpointDbHdr, TRUE)))
	{
		goto Exit;
	}

	// Set uiFirstLogCPBlkAddress to zero to indicate that no
	// physical blocks have been logged for the current checkpoint.
	// The above call to flmPhysRollback will have set the log header
	// to the same thing.

	m_uiFirstLogCPBlkAddress = 0;

	// Set the checkpointDbHdr to be the same as the log header

	f_memcpy( &m_checkpointDbHdr, pLastCommittedDbHdr, sizeof( XFLM_DB_HDR));

	// Open roll forward log and redo the transactions that
	// occurred since the last checkpoint, if any.

	if( RC_BAD( rc = m_pRfl->recover( pDb, pRestoreObj, pRestoreStatus)))
	{
		goto Exit;
	}

Exit:

	return( rc);
}
	char const* MTD_FLASHMEM ParameterReplacer::replaceTag(char const* curc)
	{
		char const* tagEnd;
		char const* tagStart = extractTagStr(curc, &tagEnd);
		if (getChar(tagStart) == '#')
		{
			// replace multiple parameters ('0param', '1param', ...)
			++tagStart;			
			uint32_t tagLen = tagEnd - tagStart;
			char tag[tagLen];
			f_memcpy(tag, tagStart, tagLen);
			tag[tagLen] = 0;
			for (uint32_t index = 0; ; ++index)
			{
				char const* fulltagname = f_printf(FSTR("%d%s"), index, tag);
				Params::Item* item = m_params->getItem(fulltagname);
				if (item)
					m_result.addChunks(&item->value); // push parameter content
				else
					break;
			}
		}
		else
		{
			// replace one parameter
			Params::Item* item = m_params->getItem(tagStart, tagEnd);
			if (item)				
				m_result.addChunks(&item->value); // push parameter content
		}
		return tagEnd + 2;	// bypass "}}"
	}
Example #5
0
/****************************************************************************
Desc:	Returns the length of the base part of a database name.  If the
		name ends with a '.' or ".db", this will not be included in the
		returned length.
****************************************************************************/
void flmGetDbBasePath(
	char *			pszBaseDbName,
	const char *	pszDbName,
	FLMUINT *		puiBaseDbNameLen)
{
	FLMUINT			uiBaseLen = f_strlen( pszDbName);

	if( uiBaseLen <= 3 || 
		f_stricmp( &pszDbName[ uiBaseLen - 3], ".db") != 0)
	{
		if( pszDbName[ uiBaseLen - 1] == '.')
		{
			uiBaseLen--;
		}
	}
	else
	{
		uiBaseLen -= 3;
	}

	f_memcpy( pszBaseDbName, pszDbName, uiBaseLen);
	pszBaseDbName[ uiBaseLen] = 0;

	if( puiBaseDbNameLen)
	{
		*puiBaseDbNameLen = uiBaseLen;
	}
}
Example #6
0
/****************************************************************************
Desc:
****************************************************************************/
RCODE JNIBackupClient::WriteData(
	const void *	pvBuffer,
	FLMUINT			uiBytesToWrite)
{
	RCODE				rc = NE_XFLM_OK;
	JNIEnv *			pEnv;
	jclass			Cls;
	jmethodID		MId;
	jbyteArray		jBuff = NULL;
	void *			pvBuff;
	FLMBOOL			bMustDetach = FALSE;
	
	if (m_pJvm->GetEnv( (void **)&pEnv, JNI_VERSION_1_2) != JNI_OK)
	{
		if (m_pJvm->AttachCurrentThread( (void **)&pEnv, NULL) != 0)
		{
			rc = RC_SET( NE_XFLM_FAILURE);	
			goto Exit;
		}
		
		bMustDetach = TRUE;
	}
	
	Cls = pEnv->GetObjectClass( m_jClient);
	MId = pEnv->GetMethodID( Cls, "WriteData", "([B)I");
	
	flmAssert( MId);
	
	if ((jBuff = pEnv->NewByteArray( (jsize)uiBytesToWrite)) == NULL)
	{
		rc = RC_SET( NE_XFLM_MEM);
		goto Exit;
	}
	pvBuff = pEnv->GetPrimitiveArrayCritical(jBuff, NULL);
	f_memcpy(pvBuff, pvBuffer, uiBytesToWrite);
	pEnv->ReleasePrimitiveArrayCritical( jBuff, pvBuff, 0);
	
	if( RC_BAD( rc = (RCODE)pEnv->CallIntMethod( m_jClient, MId, jBuff)))
	{
		goto Exit;
	}
		
Exit:

	if (jBuff)
	{
		pEnv->DeleteLocalRef( jBuff);
	}

	if (bMustDetach)
	{
		if (m_pJvm->DetachCurrentThread() != 0)
		{
			flmAssert( 0);
			rc = RC_SET( NE_XFLM_FAILURE);
		}
	}

	return( rc);
}
Example #7
0
/***************************************************************************
Desc:	This routine opens a file and reads its dictionary into memory.
*****************************************************************************/
RCODE F_DbCheck::getDictInfo()
{
	RCODE	rc = NE_XFLM_OK;

	// Close down the transaction, if one is going.

	if (m_pDb->getTransType() != XFLM_UPDATE_TRANS)
	{
		if (m_pDb->getTransType() == XFLM_READ_TRANS)
		{
			(void)m_pDb->transAbort();
		}

		// Start a read transaction on the file to ensure we are connected
		// to the file's dictionary structures.

		if (RC_BAD( rc = m_pDb->transBegin( XFLM_READ_TRANS,
			FLM_NO_TIMEOUT, XFLM_DONT_POISON_CACHE, &m_pDbInfo->m_dbHdr)))
		{
			goto Exit;
		}
	}
	else
	{
		f_memcpy( &m_pDbInfo->m_dbHdr, m_pDb->m_pDatabase->getUncommittedDbHdr(),
					sizeof( XFLM_DB_HDR));
	}

Exit:
	return( rc);
}
Example #8
0
/****************************************************************************
Desc:
****************************************************************************/
XFLXPC void XFLAPI xflaim_Query_getOptInfo(
	XFLM_OPT_INFO *		pOptInfoArray,
	FLMUINT32				ui32InfoToGet,
	CS_XFLM_OPT_INFO *	pCSOptInfo)
{
	XFLM_OPT_INFO *	pOptInfo = &pOptInfoArray [ui32InfoToGet];

	pCSOptInfo->ui32OptType = (FLMUINT32)pOptInfo->eOptType;
	pCSOptInfo->ui32Cost = (FLMUINT32)pOptInfo->uiCost;
	pCSOptInfo->ui64NodeId = pOptInfo->ui64NodeId;
	pCSOptInfo->ui64EndNodeId = pOptInfo->ui64EndNodeId;
	f_memcpy( pCSOptInfo->szIxName, pOptInfo->szIxName, sizeof( pCSOptInfo->szIxName));
	pCSOptInfo->ui32IxNum = (FLMUINT32)pOptInfo->uiIxNum;
	pCSOptInfo->bMustVerifyPath = pOptInfo->bMustVerifyPath;
	pCSOptInfo->bDoNodeMatch = pOptInfo->bDoNodeMatch;
	pCSOptInfo->bCanCompareOnKey = pOptInfo->bCanCompareOnKey;
	pCSOptInfo->ui64KeysRead = pOptInfo->ui64KeysRead;
	pCSOptInfo->ui64KeyHadDupDoc = pOptInfo->ui64KeyHadDupDoc;
	pCSOptInfo->ui64KeysPassed = pOptInfo->ui64KeysPassed;
	pCSOptInfo->ui64NodesRead = pOptInfo->ui64NodesRead;
	pCSOptInfo->ui64NodesTested = pOptInfo->ui64NodesTested;
	pCSOptInfo->ui64NodesPassed = pOptInfo->ui64NodesPassed;
	pCSOptInfo->ui64DocsRead = pOptInfo->ui64DocsRead;
	pCSOptInfo->ui64DupDocsEliminated = pOptInfo->ui64DupDocsEliminated;
	pCSOptInfo->ui64NodesFailedValidation = pOptInfo->ui64NodesFailedValidation;
	pCSOptInfo->ui64DocsFailedValidation = pOptInfo->ui64DocsFailedValidation;
	pCSOptInfo->ui64DocsPassed = pOptInfo->ui64DocsPassed;
}
Example #9
0
/****************************************************************************
Public: 	FlmRecordSet::insert
Desc: 	Insert a FlmRecord into the set.
****************************************************************************/
RCODE FlmRecordSet::insert(
	FlmRecord *		pRecord)
{
	RCODE				rc = FERR_OK;
	FlmRecord **	ppTmpArray;

	// See if we need to reallocate the array.

	if (m_iTotalRecs == m_iRecArraySize)
	{
		if( RC_BAD( rc = f_calloc( 
						sizeof( FlmRecord *) * (m_iRecArraySize + 10),
						&ppTmpArray)))
		{
			goto Exit;
		}
		if (m_iTotalRecs)
		{
			f_memcpy( ppTmpArray, m_ppRecArray,
						sizeof( FlmRecord *) * m_iTotalRecs);
		}
		m_ppRecArray = ppTmpArray;
		m_iRecArraySize += 10;
	}

	// Add the new entry into the array.

	m_ppRecArray [m_iTotalRecs] = pRecord;
	pRecord->AddRef();
	m_iTotalRecs++;

Exit:
	return( rc);
}
/****************************************************************************
Desc:	Return the next entry in the result set.  If the result set
		is not positioned then the first entry will be returned.
****************************************************************************/
RCODE F_BtreeBlk::getNext(
    void *		pvEntryBuffer)
{
    RCODE			rc = NE_FLM_OK;
    FLMUINT		uiPos = m_uiPosition;

    // Position to the next/first entry.

    if (uiPos == DYNSSET_POSITION_NOT_SET)
    {
        uiPos = 0;
    }
    else
    {
        if (++uiPos > entryCount())
        {
            rc = RC_SET( NE_FLM_EOF_HIT);
            goto Exit;
        }
    }
    f_memcpy( pvEntryBuffer, ENTRY_POS(uiPos), m_uiEntrySize);
    m_uiPosition = uiPos;

Exit:

    return( rc);
}
Example #11
0
/****************************************************************************
Desc:	Returns database serial number
****************************************************************************/
void XFLAPI F_Db::getSerialNumber(
	char *	pucSerialNumber)
{
	m_pDatabase->lockMutex();
	f_memcpy( pucSerialNumber, m_pDatabase->m_lastCommittedDbHdr.ucDbSerialNum,
		XFLM_SERIAL_NUM_SIZE);
	m_pDatabase->unlockMutex();
}
Example #12
0
	FINLINE FLMINT FTKAPI outputStr(
		const char *	pszStr,
		FLMUINT			uiLen)
	{
		f_memcpy( m_pszDestBuffer, pszStr, uiLen);
		m_pszDestBuffer += uiLen;
		
		return( (FLMINT)uiLen);
	}
Example #13
0
/****************************************************************************
Desc:	Make sure the vector array is allocated at least up to the element
		number that is passed in.
****************************************************************************/
RCODE F_DataVector::allocVectorArray(
	FLMUINT	uiElementNumber)
{
	RCODE	rc = NE_XFLM_OK;

	if (uiElementNumber >= m_uiNumElements)
	{

		// May need to allocate a new vector array

		if (uiElementNumber >= m_uiVectorArraySize)
		{
			FLMUINT					uiNewArraySize = uiElementNumber + 32;
			F_VECTOR_ELEMENT *	pNewVector;

			if (m_pVectorElements == &m_VectorArray [0])
			{
				if (RC_BAD( rc = f_alloc( uiNewArraySize * sizeof( F_VECTOR_ELEMENT),
											&pNewVector)))
				{
					goto Exit;
				}
				if (m_uiNumElements)
				{
					f_memcpy( pNewVector, m_pVectorElements,
						m_uiNumElements * sizeof( F_VECTOR_ELEMENT));
				}
			}
			else
			{
				pNewVector = m_pVectorElements;

				if (RC_BAD( rc = f_realloc( uiNewArraySize * sizeof( F_VECTOR_ELEMENT),
											&pNewVector)))
				{
					goto Exit;
				}

			}
			m_pVectorElements = pNewVector;
			m_uiVectorArraySize = uiNewArraySize;
		}

		// Initialized everything between the old last element and
		// the new element, including the new element, to zeroes.

		f_memset( &m_pVectorElements [m_uiNumElements], 0,
			sizeof( F_VECTOR_ELEMENT) *
			(uiElementNumber - m_uiNumElements + 1));

		m_uiNumElements = uiElementNumber + 1;
	}

Exit:

	return( rc);
}
Example #14
0
/****************************************************************************
Desc:
****************************************************************************/
FSTATIC void _flmDbgLogFlush( void)
{
	FLMUINT			uiBytesToWrite;
	FLMUINT			uiBytesWritten;
	char *			pszBufPtr = g_pszLogBuf;
	FLMUINT			uiTotalToWrite = g_uiLogBufOffset;
	RCODE				rc = NE_SFLM_OK;
	FLMUINT			uiBufferSize = DBG_LOG_BUFFER_SIZE + 1024;

	while( uiTotalToWrite)
	{
		if( uiTotalToWrite > 0xFE00)
		{
			uiBytesToWrite = 0xFE00;
		}
		else
		{
			uiBytesToWrite = uiTotalToWrite;
		}

		if( RC_BAD( rc = g_pLogFile->SectorWrite(
			g_uiLogFileOffset, uiBytesToWrite,
			pszBufPtr, uiBufferSize, NULL, &uiBytesWritten, FALSE)))
		{
			goto Exit;
		}

		flmAssert( uiBytesToWrite == uiBytesWritten);
		g_uiLogFileOffset += uiBytesWritten;
		pszBufPtr += uiBytesWritten;
		uiBufferSize -= uiBytesWritten;
		uiTotalToWrite -= uiBytesWritten;
	}

	if (g_uiLogBufOffset & 0x1FF)
	{
		if (g_uiLogBufOffset > 512)
		{
			f_memcpy( g_pszLogBuf,
				&g_pszLogBuf [g_uiLogBufOffset & 0xFFFFFE00],
					512);
			g_uiLogBufOffset &= 0x1FF;
		}
		g_uiLogFileOffset -= g_uiLogBufOffset;
	}
	else
	{
		g_uiLogBufOffset = 0;
	}

Exit:

	flmAssert( RC_OK( rc));
}
Example #15
0
/****************************************************************************
Desc: Add a reference to an embedded user predicate.
****************************************************************************/
RCODE flmCurAddRefPredicate(
	QTINFO *					pQTInfo,
	FlmUserPredicate *	pPredicate
	)
{
	RCODE		rc = FERR_OK;

	if (pQTInfo->uiNumPredicates == pQTInfo->uiMaxPredicates)
	{

		// Are we still in the embedded array? or have we
		// done an allocation?

		if (pQTInfo->uiMaxPredicates == MAX_USER_PREDICATES)
		{
			if (RC_BAD( rc = f_calloc(
										sizeof( FlmUserPredicate *) *
										(MAX_USER_PREDICATES * 2),
										&pQTInfo->ppPredicates)))
			{
				goto Exit;
			}

			// Copy all old pointers from embedded array.

			f_memcpy( pQTInfo->ppPredicates,
						 &pQTInfo->Predicates [0],
						 MAX_USER_PREDICATES * sizeof( FlmUserPredicate *));
		}
		else
		{

			// Reallocate the structure.

			if (RC_BAD( rc = f_recalloc(
										sizeof( FlmUserPredicate *) *
										(pQTInfo->uiNumPredicates * 2),
										&pQTInfo->ppPredicates)))
			{
				goto Exit;
			}
		}
		pQTInfo->uiMaxPredicates *= 2;
	}

	pQTInfo->ppPredicates [pQTInfo->uiNumPredicates] = pPredicate;
	pPredicate->AddRef();
	pQTInfo->uiNumPredicates++;
Exit:
	return( rc);
}
Example #16
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);
}
Example #17
0
/****************************************************************************
Desc:
****************************************************************************/
RCODE FTKAPI F_IOBuffer::addCallbackData(
	void *							pvData)
{
	RCODE			rc = NE_FLM_OK;
	
	if( m_uiCallbackDataCount >= m_uiMaxCallbackData)
	{
		if( m_ppCallbackData == m_callbackData)
		{
			void **	pNewTable;
			
			if( RC_BAD( rc = f_alloc( 
				(m_uiCallbackDataCount + 1) * sizeof( void *), &pNewTable)))
			{
				goto Exit;
			}
			
			f_memcpy( pNewTable, m_ppCallbackData, 
				m_uiMaxCallbackData * sizeof( void *));
			m_ppCallbackData = pNewTable;
		}
		else
		{
			if( RC_BAD( rc = f_realloc( 
				(m_uiCallbackDataCount + 1) * sizeof( void *), &m_ppCallbackData)))
			{
				goto Exit;
			}
		}
		
		m_uiMaxCallbackData = m_uiCallbackDataCount + 1;
	}
	
	m_ppCallbackData[ m_uiCallbackDataCount] = pvData;
	m_uiCallbackDataCount++;
	
Exit:

	return( rc);
}
/****************************************************************************
Desc:	Insert the entry into the buffer.
****************************************************************************/
RCODE F_BtreeBlk::insertEntry(
    void *		pvEntry,
    FLMUINT		uiChildAddr)
{
    RCODE			rc = NE_FLM_OK;
    FLMBYTE *	pucCurEntry;
    FLMUINT		uiShiftBytes;		// Always shift down

    if( entryCount() >= m_uiNumSlots)
    {
        rc = RC_SET( NE_FLM_FAILURE);
        goto Exit;
    }
    flmAssert( m_uiPosition != DYNSSET_POSITION_NOT_SET);
    pucCurEntry = ENTRY_POS( m_uiPosition);
    if ((uiShiftBytes = (entryCount() - m_uiPosition) *
                        (m_uiEntrySize + m_uiEntryOvhd)) != 0)
    {

        // Big hairy assert.  Finds coding bugs and corruptions.

        flmAssert( m_uiPosition * (m_uiEntrySize + m_uiEntryOvhd) +
                   uiShiftBytes < DYNSSET_BLOCK_SIZE - sizeof( FixedBlkHdr));

        f_memmove( pucCurEntry + m_uiEntrySize + m_uiEntryOvhd,
                   pucCurEntry, uiShiftBytes);
    }
    f_memcpy( pucCurEntry, pvEntry, m_uiEntrySize);
    if( m_uiEntryOvhd)
    {
        UD2FBA( (FLMUINT32)uiChildAddr, &pucCurEntry[m_uiEntrySize]);
    }
    entryCount( entryCount() + 1);
    m_uiPosition++;
    m_bDirty = TRUE;

Exit:

    return( rc);
}
/****************************************************************************
Desc:	Return the last entry in the result set.
****************************************************************************/
RCODE F_BtreeBlk::getLast(
    void *		pvEntryBuffer)
{
    RCODE			rc = NE_FLM_OK;
    FLMUINT		uiPos = entryCount();

    // Position to the next/first entry.

    if (uiPos == 0)
    {
        rc = RC_SET( NE_FLM_EOF_HIT);
        goto Exit;
    }

    uiPos--;
    f_memcpy( pvEntryBuffer, ENTRY_POS(uiPos), m_uiEntrySize);
    m_uiPosition = uiPos;

Exit:

    return( rc);
}
Example #20
0
RCODE FLMAPI f_mutexCreate(
	F_MUTEX *			phMutex)
{
	RCODE					rc = NE_FLM_OK;
	lwp_mutex_t			defaultMutex = DEFAULTMUTEX;

	f_assert( phMutex != NULL);

	// NOTE: Cannot call f_alloc because the memory initialization needs
	// to be able to set up mutexes.

	if ((*phMutex = (F_MUTEX)malloc( sizeof( lwp_mutex_t))) == F_MUTEX_NULL)
	{
		rc = RC_SET( NE_FLM_MEM);
		goto Exit;
	}
	
	f_memcpy( *phMutex, &defaultMutex, sizeof( lwp_mutex_t));

Exit:

	return( rc);
}
Example #21
0
 // buffer can stay in RAM of Flash
 // ret -1 = error, ret 0 = disconnected
 int32_t MTD_FLASHMEM Socket::write(void const* buffer, uint32_t length)
 {
     static uint32_t const MAXCHUNKSIZE = 128;
     
     int32_t bytesSent = 0;
     if (isStoredInFlash(buffer))
     {
         // copy from Flash, send in chunks of up to MAXCHUNKSIZE bytes
         uint8_t rambuf[min(length, MAXCHUNKSIZE)];
         uint8_t const* src = (uint8_t const*)buffer;
         while (bytesSent < length)
         {
             uint32_t bytesToSend = min(MAXCHUNKSIZE, length - bytesSent);
             f_memcpy(rambuf, src, bytesToSend);
             uint32_t chunkBytesSent = m_remoteAddress.sin_len == 0? lwip_send(m_socket, rambuf, bytesToSend, 0) :
                                                                     lwip_sendto(m_socket, rambuf, bytesToSend, 0, (sockaddr*)&m_remoteAddress, sizeof(m_remoteAddress));
             if (chunkBytesSent == 0)
             {
                 // error
                 bytesSent = 0;
                 break;
             }
             bytesSent += chunkBytesSent;
             src += chunkBytesSent;
         }
     }
     else
     {
         // just send as is
         bytesSent = m_remoteAddress.sin_len == 0? lwip_send(m_socket, buffer, length, 0) :
                                                   lwip_sendto(m_socket, buffer, length, 0, (sockaddr*)&m_remoteAddress, sizeof(m_remoteAddress));
     }
     if (length > 0)
         m_connected = (bytesSent > 0);
     return bytesSent;
 }
Example #22
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);
}
Example #23
0
/****************************************************************************
Desc : Return the status of the index.
****************************************************************************/
FLMEXP RCODE FLMAPI FlmIndexStatus(
	HFDB					hDb,
	FLMUINT				uiIndexNum,
	FINDEX_STATUS *	pIndexStatus)
{
	RCODE					rc = FERR_OK;
	FLMBOOL				bStartedAutoTrans = FALSE;
	FLMUINT 				uiLastDrnIndexed;
	FDB *					pDb = (FDB *)hDb;
	F_BKGND_IX *		pBackgroundIx;
	FLMBOOL				bSuspended;
	FLMBOOL				bMutexLocked = FALSE;

	flmAssert( pIndexStatus != NULL);

	if( IsInCSMode( hDb))
	{
		fdbInitCS( pDb);
		rc = flmIndexStatusCS( pDb, uiIndexNum, pIndexStatus);
		goto Exit;
	}

	if( RC_BAD( rc = fdbInit( (FDB *)hDb, FLM_READ_TRANS,
							FDB_TRANS_GOING_OK, 0, &bStartedAutoTrans)))
	{
		goto Exit;
	}

	f_mutexLock( gv_FlmSysData.hShareMutex);
	bMutexLocked = TRUE;

	pBackgroundIx = flmBackgroundIndexGet( pDb->pFile, uiIndexNum, TRUE);
	if( pBackgroundIx)
	{
		f_memcpy( pIndexStatus, &pBackgroundIx->indexStatus, 
			sizeof( FINDEX_STATUS));
		f_mutexUnlock( gv_FlmSysData.hShareMutex);
		bMutexLocked = FALSE;
		flmAssert( pIndexStatus->uiIndexNum == uiIndexNum);
	}
	else
	{
		IXD *		pIxd;
		FLMBOOL	bTrackerIxSuspended;

		if( RC_BAD( rc = fdictGetIndex( 
			pDb->pDict, pDb->pFile->bInLimitedMode,
			uiIndexNum,NULL, &pIxd, TRUE)))
		{
			goto Exit;
		}

		bSuspended = (pIxd->uiFlags & IXD_SUSPENDED)
												? TRUE
												: FALSE;

		f_mutexUnlock( gv_FlmSysData.hShareMutex);
		bMutexLocked = FALSE;

		// Get the index state from the tracker

		if( RC_BAD( rc = flmGetIxTrackerInfo( pDb, uiIndexNum, 
			NULL, &uiLastDrnIndexed, NULL, &bTrackerIxSuspended)))
		{
			if( rc == FERR_NOT_FOUND)
			{
				rc = RC_SET( FERR_BAD_IX);
			}
			goto Exit;
		}

		// Sanity check

#ifdef FLM_DEBUG
		if( pDb->pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_51 &&
			bSuspended != bTrackerIxSuspended)
		{
			flmAssert( 0);
		}
#endif

		// Populate the index status structure.

		f_memset( pIndexStatus, 0, sizeof( FINDEX_STATUS));
		pIndexStatus->uiIndexNum = uiIndexNum;
		pIndexStatus->uiLastRecordIdIndexed = uiLastDrnIndexed;
		pIndexStatus->bSuspended = bSuspended;
	}

Exit:

	if( bMutexLocked)
	{
		f_mutexUnlock( gv_FlmSysData.hShareMutex);
	}

	if( bStartedAutoTrans)
	{
		rc = flmEndAutoTrans( pDb, rc);
	}
	flmExit( FLM_INDEX_STATUS, pDb, rc);
	return( rc);
}
Example #24
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);
}
Example #25
0
/****************************************************************************
Desc:	Compose a key buffer from the vector's components.
****************************************************************************/
RCODE F_DataVector::outputKey(
	IXD *				pIxd,
	FLMUINT			uiMatchFlags,
	FLMBYTE *		pucKeyBuf,
	FLMUINT			uiKeyBufSize,
	FLMUINT *		puiKeyLen,
	FLMUINT			uiSearchKeyFlag)
{
	RCODE						rc = NE_XFLM_OK;
	ICD *						pIcd;
	FLMBYTE *				pucToKey;
	FLMBYTE *				pucKeyLenPos;
	FLMUINT					uiToKeyLen;
	FLMUINT					uiKeyLen;
	FLMUINT					uiKeyComponent;
	FLMUINT					uiDataComponent;
	FLMUINT					uiContextComponent;
	FLMBOOL					bDataTruncated;
	FLMUINT					uiDataType;
	FLMUINT					uiLanguage;
	F_VECTOR_ELEMENT *	pVector = NULL;
	FLMBYTE					ucIDBuf [256];
	FLMUINT					uiIDLen = 0;
	FLMUINT64				ui64Id;
	FLMUINT					uiMaxKeySize;
	FLMUINT					uiDataLen;
	const FLMBYTE *		pucDataPtr;
	FLMBYTE					ucTmpSen [FLM_MAX_NUM_BUF_SIZE];
	FLMBYTE *				pucTmpSen;
	FLMUINT					uiSenLen;
	FLMUINT					uiIDMatchFlags = uiMatchFlags & (XFLM_MATCH_IDS | XFLM_MATCH_DOC_ID);
	IF_BufferIStream *	pBufferStream = NULL;

	if (uiIDMatchFlags)
	{
		pucToKey = &ucIDBuf [0];
		uiIDLen = 0;
		
		// Put document ID into buffer.  If there is room for at least nine
		// bytes, we can encode the ID right into the buffer safely.  Otherwise,
		// we have to use a temporary buffer and see if there is room.
		
		if (sizeof( ucIDBuf) - uiIDLen >= 9)
		{
			uiIDLen += f_encodeSEN( m_ui64DocumentID, &pucToKey);
		}
		else
		{
			pucTmpSen = &ucTmpSen [0];
			uiSenLen = f_encodeSEN( m_ui64DocumentID, &pucTmpSen);
			if (uiSenLen + uiIDLen > sizeof( ucIDBuf))
			{
				rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
				goto Exit;
			}
			f_memcpy( pucToKey, ucTmpSen, uiSenLen);
			uiIDLen += uiSenLen;
			pucToKey += uiSenLen;
		}

		if (uiIDMatchFlags & XFLM_MATCH_IDS)
		{
			// Append the Key component NODE IDs to the key
	
			for (uiKeyComponent = 0;
				  uiKeyComponent < pIxd->uiNumKeyComponents;
				  uiKeyComponent++)
			{
				ui64Id = getID( uiKeyComponent);

				// Put node ID into buffer.  If there is room for at least nine
				// bytes, we can encode the ID right into the buffer safely.  Otherwise,
				// we have to use a temporary buffer and see if there is room.
				
				if (sizeof( ucIDBuf) - uiIDLen >= 9)
				{
					uiIDLen += f_encodeSEN( ui64Id, &pucToKey);
				}
				else
				{
					pucTmpSen = &ucTmpSen [0];
					uiSenLen = f_encodeSEN( ui64Id, &pucTmpSen);
					if (uiSenLen + uiIDLen > sizeof( ucIDBuf))
					{
						rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
						goto Exit;
					}
					f_memcpy( pucToKey, ucTmpSen, uiSenLen);
					uiIDLen += uiSenLen;
					pucToKey += uiSenLen;
				}
			}
	
			// Append the Data NODE IDs to the key
	
			for (uiDataComponent = 0;
				  uiDataComponent < pIxd->uiNumDataComponents;
				  uiDataComponent++)
			{
				ui64Id = getID( uiDataComponent +
													pIxd->uiNumKeyComponents);

				// Put node ID into buffer.  If there is room for at least nine
				// bytes, we can encode the ID right into the buffer safely.  Otherwise,
				// we have to use a temporary buffer and see if there is room.
				
				if (sizeof( ucIDBuf) - uiIDLen >= 9)
				{
					uiIDLen += f_encodeSEN( ui64Id, &pucToKey);
				}
				else
				{
					pucTmpSen = &ucTmpSen [0];
					uiSenLen = f_encodeSEN( ui64Id, &pucTmpSen);
					if (uiSenLen + uiIDLen > sizeof( ucIDBuf))
					{
						rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
						goto Exit;
					}
					f_memcpy( pucToKey, ucTmpSen, uiSenLen);
					uiIDLen += uiSenLen;
					pucToKey += uiSenLen;
				}
			}
	
			// Append the Context NODE IDs to the key
	
			for (uiContextComponent = 0;
				  uiContextComponent < pIxd->uiNumContextComponents;
				  uiContextComponent++)
			{
				ui64Id = getID( uiContextComponent +
													pIxd->uiNumKeyComponents +
													pIxd->uiNumDataComponents);

				// Put node ID into buffer.  If there is room for at least nine
				// bytes, we can encode the ID right into the buffer safely.  Otherwise,
				// we have to use a temporary buffer and see if there is room.
				
				if (sizeof( ucIDBuf) - uiIDLen >= 9)
				{
					uiIDLen += f_encodeSEN( ui64Id, &pucToKey);
				}
				else
				{
					pucTmpSen = &ucTmpSen [0];
					uiSenLen = f_encodeSEN( ui64Id, &pucTmpSen);
					if (uiSenLen + uiIDLen > sizeof( ucIDBuf))
					{
						rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
						goto Exit;
					}
					f_memcpy( pucToKey, ucTmpSen, uiSenLen);
					uiIDLen += uiSenLen;
					pucToKey += uiSenLen;
				}
			}
		}
		
		if (uiIDLen >= uiKeyBufSize)
		{
			rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
			goto Exit;
		}
	}

	// Output the key components

	uiMaxKeySize = uiKeyBufSize - uiIDLen;
	uiLanguage = pIxd->uiLanguage;
	uiKeyLen = 0;
	pucToKey = pucKeyBuf;
	pIcd = pIxd->pFirstKey;
	for (uiKeyComponent = 0;;pIcd = pIcd->pNextKeyComponent, uiKeyComponent++)
	{
		pucKeyLenPos = pucToKey;
		pucToKey += 2;
		uiKeyLen += 2;
		
		uiDataType = icdGetDataType( pIcd);

		// Find matching node in the tree - if not found skip and continue.

		if ((pVector = getVector( uiKeyComponent, VECT_SLOT_HAS_DATA)) == NULL)
		{
			UW2FBA( 0, pucKeyLenPos);
		}
		else
		{
			uiToKeyLen = 0;
			bDataTruncated = FALSE;

			// Take the dictionary number and make it the key

			if (pIcd->uiFlags & ICD_PRESENCE)
			{
				FLMUINT	uiNum;

				// Component better be a number - and better match the
				// tag number of the ICD

				if (RC_BAD( rc = getUINT( uiKeyComponent, &uiNum)))
				{
					goto Exit;
				}
				
				flmAssert( uiNum == pIcd->uiDictNum || pIcd->uiDictNum == ELM_ROOT_TAG);

        		// Output the tag number

				if (uiKeyLen + 4 > uiMaxKeySize)
				{
					rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
					goto Exit;
				}
				
				f_UINT32ToBigEndian( (FLMUINT32)uiNum, pucToKey);
				uiToKeyLen = 4;
			}
			else if (pIcd->uiFlags & ICD_METAPHONE)
			{
				FLMUINT					uiMeta;
				FLMBYTE					ucStorageBuf[ FLM_MAX_NUM_BUF_SIZE];
				FLMUINT					uiStorageLen;

				if (uiDataType != XFLM_TEXT_TYPE)
				{
					rc = RC_SET_AND_ASSERT( NE_XFLM_SYNTAX);
					goto Exit;
				}
				
				if (pVector->uiDataType == XFLM_TEXT_TYPE)
				{
					if (RC_BAD( rc = getUTF8Ptr( uiKeyComponent,
											&pucDataPtr, &uiDataLen)))
					{
						goto Exit;
					}
					
					if( !pBufferStream)
					{
						if( RC_BAD( rc = FlmAllocBufferIStream( &pBufferStream)))
						{
							goto Exit;
						}
					}
	
					if (RC_BAD( rc = pBufferStream->openStream( 
						(const char *)pucDataPtr, uiDataLen)))
					{
						goto Exit;
					}
	
					if (RC_BAD( rc = f_getNextMetaphone( pBufferStream, &uiMeta)))
					{
						if( rc == NE_XFLM_EOF_HIT)
						{
							rc = RC_SET( NE_XFLM_SYNTAX);
						}
						goto Exit;
					}
	
					pBufferStream->closeStream();
				}
				else if (pVector->uiDataType == XFLM_NUMBER_TYPE)
				{
					if( RC_BAD( rc = getUINT( uiKeyComponent, &uiMeta)))
					{
						goto Exit;
					}
				}
				else
				{
					rc = RC_SET_AND_ASSERT( NE_XFLM_SYNTAX);
					goto Exit;
				}

				if ( uiMeta)
				{
					uiStorageLen = FLM_MAX_NUM_BUF_SIZE;
					if( RC_BAD( rc = flmNumber64ToStorage( uiMeta,
						&uiStorageLen, ucStorageBuf, FALSE, FALSE)))
					{
						goto Exit;
					}

					if( !pBufferStream)
					{
						if( RC_BAD( rc = FlmAllocBufferIStream( &pBufferStream)))
						{
							goto Exit;
						}
					}
					
					if (RC_BAD( rc = pBufferStream->openStream( 
						(const char *)ucStorageBuf, uiStorageLen)))
					{
						goto Exit;
					}

        			// Output the metaphone key piece

					uiToKeyLen = uiMaxKeySize - uiKeyLen;
					if( RC_BAD( rc = KYCollateValue( pucToKey, &uiToKeyLen,
						pBufferStream, XFLM_NUMBER_TYPE,
						pIcd->uiFlags, pIcd->uiCompareRules, pIcd->uiLimit,
						NULL, NULL, uiLanguage,
						FALSE, FALSE, &bDataTruncated, NULL)))
					{
						goto Exit;
					}
					
					pBufferStream->closeStream();
				}
			}
			else
			{
				if (uiDataType == XFLM_TEXT_TYPE)
				{
					if (RC_BAD( rc = getUTF8Ptr( uiKeyComponent,
											&pucDataPtr, &uiDataLen)))
					{
						goto Exit;
					}
				}
				else
				{
					pucDataPtr = (FLMBYTE *)getDataPtr( pVector);
					uiDataLen = pVector->uiDataLength;
				}
				
				if (uiDataLen)
				{
					if( !pBufferStream)
					{
						if( RC_BAD( rc = FlmAllocBufferIStream( &pBufferStream)))
						{
							goto Exit;
						}
					}
					
					if (RC_BAD( rc = pBufferStream->openStream( 
						(const char *)pucDataPtr, uiDataLen)))
					{
						goto Exit;
					}

					uiToKeyLen = uiMaxKeySize - uiKeyLen;
					if( RC_BAD( rc = KYCollateValue( pucToKey, &uiToKeyLen,
						pBufferStream, uiDataType,
						pIcd->uiFlags, pIcd->uiCompareRules, pIcd->uiLimit,
						NULL, NULL, uiLanguage,
						(FLMBOOL) ((pIcd->uiFlags & ICD_SUBSTRING)
								? (isLeftTruncated( pVector)
									? FALSE : TRUE)
								: FALSE),
						isRightTruncated( pVector),
						&bDataTruncated, NULL)))
					{
						goto Exit;
					}
					
					pBufferStream->closeStream();					
				}
			}

			if (uiToKeyLen)
			{

				//	Increment total key length

				pucToKey += uiToKeyLen;
				uiKeyLen += uiToKeyLen;
			}
			if (!bDataTruncated)
			{
				UW2FBA( (FLMUINT16)(uiToKeyLen | uiSearchKeyFlag),
									pucKeyLenPos);
			}
			else
			{
				UW2FBA( (FLMUINT16)(uiToKeyLen | TRUNCATED_FLAG |
									uiSearchKeyFlag), pucKeyLenPos); 
			}
		}

		// Check if done.

		if (!pIcd->pNextKeyComponent)
		{
   	 	break;
		}
	}
	
	// Output the node IDs, if requested.

	if (uiIDMatchFlags)
	{

		// There will always be room at this point for the
		// IDs - because it was subtracted out above.

		f_memcpy( pucToKey, ucIDBuf, uiIDLen);
	}
	*puiKeyLen = uiKeyLen + uiIDLen;

Exit:

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

	return( rc);
}
Example #26
0
/****************************************************************************
Desc:	Compose a data buffer from the vector's components.
****************************************************************************/
RCODE F_DataVector::outputData(
	IXD *			pIxd,
	FLMBYTE *	pucDataBuf,
	FLMUINT		uiDataBufSize,
	FLMUINT *	puiDataLen)
{
	RCODE						rc = NE_XFLM_OK;
	ICD *						pIcd = pIxd->pFirstData;
	FLMUINT					uiDataComponent = 0;
	F_VECTOR_ELEMENT *	pVector;
	FLMBYTE *				pucData;
	FLMUINT					uiDataLength;
	FLMUINT					uiTotalLength = 0;
	FLMBYTE					ucTmpSen [32];
	FLMBYTE *				pucTmpSen = &ucTmpSen [0];
	FLMUINT					uiSENLen;
	FLMUINT					uiLastDataLen = 0;

	while (pIcd)
	{
		if ((pVector = getVector( uiDataComponent + pIxd->uiNumKeyComponents,
											VECT_SLOT_HAS_DATA)) != NULL)
		{

			// Cannot do data conversions right now.

			flmAssert( pVector->uiDataType == icdGetDataType( pIcd));
			uiDataLength = pVector->uiDataLength;
			pucData = (FLMBYTE *)getDataPtr( pVector);
		}
		else
		{
			uiDataLength = 0;
			pucData = NULL;
		}

		// Output the length of the data as a SEN value

		uiSENLen = f_encodeSEN( uiDataLength, &pucTmpSen);
		if (uiTotalLength + uiSENLen > uiDataBufSize)
		{
			rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
			goto Exit;
		}
		f_memcpy( pucDataBuf, ucTmpSen, uiSENLen);
		pucDataBuf += uiSENLen;
		uiTotalLength += uiSENLen;

		// Output the data

		if (uiDataLength)
		{
			if (uiTotalLength + uiDataLength > uiDataBufSize)
			{
				rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
				goto Exit;
			}
			f_memcpy( pucDataBuf, pucData, uiDataLength);
			pucDataBuf += uiDataLength;
			uiTotalLength += uiDataLength;
			uiLastDataLen = uiTotalLength;
		}
		pIcd = pIcd->pNextDataComponent;
		uiDataComponent++;
	}

Exit:

	// Even if rc == NE_XFLM_CONV_DEST_OVERFLOW, return a length

	*puiDataLen = uiLastDataLen;

	return( rc);
}
Example #27
0
/****************************************************************************
Desc:	Store a data value into its vector element.
****************************************************************************/
RCODE F_DataVector::storeValue(
	FLMINT				uiElementNumber,
	FLMUINT				uiDataType,
	const FLMBYTE *	pucData,
	FLMUINT				uiDataLen,
	FLMBYTE **			ppucDataPtr)
{
	RCODE						rc = NE_XFLM_OK;
	F_VECTOR_ELEMENT *	pVector;
	FLMBYTE *				pucDataPtr;
	FLMUINT					uiTemp;

	// Find or allocate space for the vector

	if (RC_BAD( rc = allocVectorArray( uiElementNumber)))
	{
		goto Exit;
	}

	pVector = &m_pVectorElements [uiElementNumber];

	// Will the data fit inside uiDataOffset?

	if (uiDataLen <= sizeof( FLMUINT))
	{
		pucDataPtr = (FLMBYTE *)&pVector->uiDataOffset;
	}
	else if (uiDataLen <= pVector->uiDataLength)
	{

		// New data will fit in original space.  Simply reuse it.

		pucDataPtr = m_pucDataBuf + pVector->uiDataOffset;
	}
	else
	{

		// New data will not fit in originally allocated space.
		// Must allocate new space.

		// Always align the new allocation so that if it gets
		// reused later for binary data it will be properly aligned.

		if ((m_uiDataBufOffset & FLM_ALLOC_ALIGN) != 0)
		{
			uiTemp = (FLM_ALLOC_ALIGN + 1) - (m_uiDataBufOffset & FLM_ALLOC_ALIGN);
			m_uiDataBufOffset += uiTemp;
		}

		if (uiDataLen + m_uiDataBufOffset > m_uiDataBufLength)
		{
			// Re-allocate the data buffer.

			if( m_pucDataBuf == m_ucIntDataBuf)
			{
				if (RC_BAD( rc = f_alloc(
								m_uiDataBufOffset + uiDataLen + 512,
								&m_pucDataBuf)))
				{
					goto Exit;
				}

				f_memcpy( m_pucDataBuf, m_ucIntDataBuf, m_uiDataBufOffset);
			}
			else
			{
				if (RC_BAD( rc = f_realloc(
								m_uiDataBufOffset + uiDataLen + 512,
								&m_pucDataBuf)))
				{
					goto Exit;
				}
			}

			m_uiDataBufLength = m_uiDataBufOffset + uiDataLen + 512;
		}
		pucDataPtr = m_pucDataBuf + m_uiDataBufOffset;
		pVector->uiDataOffset = m_uiDataBufOffset;
		m_uiDataBufOffset += uiDataLen;
	}

	// Store the data - may be zero length.

	if( pucData)
	{
		if( uiDataLen > 1)
		{
			f_memcpy( pucDataPtr, pucData, uiDataLen);
		}
		else if( uiDataLen)
		{
			*pucDataPtr = *pucData;
		}
	}

	pVector->uiFlags |= VECT_SLOT_HAS_DATA;
	pVector->uiDataLength = uiDataLen;
	pVector->uiDataType = uiDataType;

	if( ppucDataPtr)
	{
		*ppucDataPtr = pucDataPtr;
	}

Exit:

	return( rc);
}
Example #28
0
/****************************************************************************
Desc:	Populate a vector's components from the key part of an index key.
****************************************************************************/
RCODE F_DataVector::inputKey(
	IXD *					pIxd,
	const FLMBYTE *	pucKey,
	FLMUINT				uiKeyLen)
{
	RCODE					rc = NE_XFLM_OK;
	const FLMBYTE *	pucKeyEnd = pucKey + uiKeyLen;
	FLMBYTE				ucDataBuf [XFLM_MAX_KEY_SIZE];
	FLMUINT				uiDataLen;
	ICD *					pIcd;
	FLMUINT				uiLanguage = pIxd->uiLanguage;
	FLMUINT				uiComponentLen;
	FLMUINT				uiDataType;
	FLMBOOL				bDataRightTruncated;
	FLMBOOL				bFirstSubstring;
	FLMBOOL				bIsText;
	FLMUINT				uiComponent;
	FLMUINT64			ui64Id;
	FLMUINT				uiDictNumber;

	flmAssert( uiKeyLen);

	// Loop for each compound piece of key

	uiComponent = 0;
	pIcd = pIxd->pFirstKey;
	while (pIcd)
	{
		if (uiKeyLen < 2)
		{
			rc = RC_SET_AND_ASSERT( NE_XFLM_BTREE_ERROR);
			goto Exit;
		}
		
		uiComponentLen = getKeyComponentLength( pucKey);
		bDataRightTruncated = isKeyComponentTruncated( pucKey);
		uiKeyLen -= 2;
		pucKey += 2;
		
		if (uiComponentLen > uiKeyLen)
		{
			rc = RC_SET_AND_ASSERT( NE_XFLM_BTREE_ERROR);
			goto Exit;
		}
		
		bFirstSubstring = FALSE;
		bIsText = (icdGetDataType( pIcd) == XFLM_TEXT_TYPE &&
					  !(pIcd->uiFlags & (ICD_PRESENCE | ICD_METAPHONE)))
					 ? TRUE
					 : FALSE;

		uiDataType = icdGetDataType( pIcd);
		uiDictNumber = pIcd->uiDictNum;
		if (uiComponentLen)
		{
			if (pIcd->uiFlags & ICD_PRESENCE)
			{
				FLMUINT	uiNum;
				
				if (uiComponentLen != 4 || bDataRightTruncated)
				{
					rc = RC_SET_AND_ASSERT( NE_XFLM_BTREE_ERROR);
					goto Exit;
				}
				
				uiNum = (FLMUINT)f_bigEndianToUINT32( pucKey);
	
				// What is stored in the key better match the dictionary
				// number of the ICD.
	
				if (pIcd->uiDictNum != ELM_ROOT_TAG)
				{
					if (uiNum != uiDictNumber)
					{
						rc = RC_SET_AND_ASSERT( NE_XFLM_BTREE_ERROR);
						goto Exit;
					}
				}
				else
				{
					uiDictNumber = uiNum;
				}
				if (RC_BAD( rc = setUINT( uiComponent, uiNum)))
				{
					goto Exit;
				}
			}
			else if (pIcd->uiFlags & ICD_METAPHONE)
			{
				uiDataLen = sizeof( ucDataBuf);
	
				if ( uiComponentLen)
				{
					if( RC_BAD( rc = flmCollationNum2StorageNum( pucKey,
						uiComponentLen, ucDataBuf, &uiDataLen)))
					{
						goto Exit;
					}
				}
				else
				{
					uiDataLen = 0;
				}
	
				if (bDataRightTruncated)
				{
					rc = RC_SET_AND_ASSERT( NE_XFLM_BTREE_ERROR);
					goto Exit;
				}
	
				// Allocate and copy value into the component.  NOTE:
				// storeValue handles zero length data.
	
				if (RC_BAD( rc = storeValue( uiComponent, XFLM_NUMBER_TYPE, 
														ucDataBuf, uiDataLen)))
				{
					goto Exit;
				}
			}
			else
			{
	
				// Grab only the Nth section of key if compound key
	
				switch (uiDataType)
				{
					case XFLM_TEXT_TYPE:
					{
						FLMBOOL bTmpTruncated = FALSE;
	
						if (uiComponentLen)
						{
							uiDataLen = sizeof( ucDataBuf);
							if (RC_BAD( rc = flmColText2StorageText( pucKey,
								uiComponentLen,
								ucDataBuf, &uiDataLen, uiLanguage,
								&bTmpTruncated, &bFirstSubstring)))
							{
								goto Exit;
							}
							
							if (bTmpTruncated != bDataRightTruncated)
							{
								rc = RC_SET_AND_ASSERT( NE_XFLM_BTREE_ERROR);
								goto Exit;
							}
						}
						else
						{
							uiDataLen = 0;
						}
						break;
					}
	
					case XFLM_NUMBER_TYPE:
					{
						if (uiComponentLen)
						{
							uiDataLen = sizeof( ucDataBuf);
							if( RC_BAD( rc = flmCollationNum2StorageNum( pucKey,
								uiComponentLen, ucDataBuf, &uiDataLen)))
							{
								goto Exit;
							}
						}
						else
						{
							uiDataLen = 0;
						}
						
						if (bDataRightTruncated)
						{
							rc = RC_SET_AND_ASSERT( NE_XFLM_BTREE_ERROR);
							goto Exit;
						}
						break;
					}
	
					case XFLM_BINARY_TYPE:
					{
						uiDataLen = uiComponentLen;
						if (uiComponentLen > sizeof( ucDataBuf))
						{
							rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
							goto Exit;
						}
						if (uiComponentLen)
						{
							f_memcpy( ucDataBuf, pucKey, uiComponentLen);
						}
						break;
					}
	
					default:
						rc = RC_SET( NE_XFLM_DATA_ERROR);
						goto Exit;
				}
	
				// Allocate and copy value into the component.  NOTE:
				// storeValue handles zero length data.
	
				if (RC_BAD( rc = storeValue( uiComponent, uiDataType, ucDataBuf,
											uiDataLen)))
				{
					goto Exit;
				}
	
				// Set first sub-string and truncated flags.
	
				if ((pIcd->uiFlags & ICD_SUBSTRING) && !bFirstSubstring)
				{
					setLeftTruncated( uiComponent);
				}
				if (bDataRightTruncated)
				{
					setRightTruncated( uiComponent);
				}
			}
		}
		else
		{
			if ((pIcd->uiFlags & ICD_PRESENCE) && uiDictNumber == ELM_ROOT_TAG)
			{
				uiDictNumber = 0;
			}
		}

		// Store the name ID

		if (RC_BAD( rc = setNameId( uiComponent, uiDictNumber,
								(FLMBOOL)((pIcd->uiFlags & ICD_IS_ATTRIBUTE)
											 ? TRUE
											 : FALSE), FALSE)))
		{
			goto Exit;
		}

		// Position to the end of this component

		flmAssert( uiKeyLen >= uiComponentLen);
		pucKey += uiComponentLen;
		uiKeyLen -= uiComponentLen;
		uiComponent++;

		pIcd = pIcd->pNextKeyComponent;
	}
	
	// See if we have a document ID.
	
	if (RC_BAD( rc = f_decodeSEN64( &pucKey, pucKeyEnd, &m_ui64DocumentID)))
	{
		goto Exit;
	}
	
	// Get the node IDs for the key components, if any

	pIcd = pIxd->pFirstKey;
	uiComponent = 0;
	while (pIcd)
	{
		
		// Extract the component node ID

		if (RC_BAD( rc = f_decodeSEN64( &pucKey, pucKeyEnd, &ui64Id)))
		{
			goto Exit;
		}
		
		// No need to store if it is zero
		
		if (ui64Id)
		{
			if (RC_BAD( rc = setID( uiComponent, ui64Id)))
			{
				goto Exit;
			}
		}
		uiComponent++;
		pIcd = pIcd->pNextKeyComponent;
	}

	// Get the node IDs for the data components, if any

	pIcd = pIxd->pFirstData;
	while (pIcd)
	{

		// Extract the component node ID

		if (RC_BAD( rc = f_decodeSEN64( &pucKey, pucKeyEnd, &ui64Id)))
		{
			goto Exit;
		}
		
		// No need to store if it is zero
		
		if (ui64Id)
		{
			if (RC_BAD( rc = setID( uiComponent, ui64Id)))
			{
				goto Exit;
			}
		}
		
		// Store the name ID

		if (RC_BAD( rc = setNameId( uiComponent, pIcd->uiDictNum,
											(FLMBOOL)((pIcd->uiFlags & ICD_IS_ATTRIBUTE)
												 ? TRUE
												 : FALSE), TRUE)))
		{
			goto Exit;
		}
		uiComponent++;
		pIcd = pIcd->pNextDataComponent;
	}

	// Get the node IDs for the context components, if any

	pIcd = pIxd->pFirstContext;
	while (pIcd)
	{

		// Extract the component node ID

		if (RC_BAD( rc = f_decodeSEN64( &pucKey, pucKeyEnd, &ui64Id)))
		{
			goto Exit;
		}
		
		// No need to store if it is zero
		
		if (ui64Id)
		{
			if (RC_BAD( rc = setID( uiComponent, ui64Id)))
			{
				goto Exit;
			}
		}
		
		// Store the name ID

		if (RC_BAD( rc = setNameId( uiComponent, pIcd->uiDictNum,
											(FLMBOOL)((pIcd->uiFlags & ICD_IS_ATTRIBUTE)
												 ? TRUE
												 : FALSE), TRUE)))
		{
			goto Exit;
		}
		uiComponent++;
		pIcd = pIcd->pNextKeyComponent;
	}

Exit:

	return( rc);
}
/****************************************************************************
Desc:	Move first half of entries into new block.  Reset previous block
		to point to new block.  Add new last entry in new block to parent.
		Fixup prev/next linkages.
****************************************************************************/
RCODE F_BtreeBlk::split(
    F_BtreeRoot *	pRoot,
    FLMBYTE *		pucCurEntry,		// (in) Contains entry to insert
    FLMUINT			uiCurBlkAddr,		// (in) Blk addr if non-leaf
    FLMBYTE *		pucParentEntry,	// (out) Entry to insert into parent.
    FLMUINT *		puiNewBlkAddr)		// (out) New blk addr to insert into parent.
{
    RCODE				rc = NE_FLM_OK;
    F_BtreeBlk *		pPrevBlk;
    F_BtreeBlk *		pNewBlk = NULL;
    FLMBYTE *		pucEntry = NULL;
    FLMBYTE *		pucMidEntry;
    FLMBYTE *		pucChildAddr;
    FLMUINT			uiChildAddr;
    FLMUINT			uiPrevBlkAddr;
    FLMUINT			uiMid;
    FLMUINT			uiPos;
    FLMUINT			uiMoveBytes;
    FLMBOOL			bInserted = FALSE;

    // Allocate a new block for the split.

    if (RC_BAD( rc = pRoot->newBlk( &pNewBlk, blkType() )))
    {
        goto Exit;
    }
    pNewBlk->AddRef();				// Pin the block - may get flushed out.


    // the last half into the new block, but that would force the parent
    // entry to be changed.  This may take a little longer, but it is much
    // more easier to code.

    // Call search entry once just to setup for insert.

    (void) pNewBlk->searchEntry( ENTRY_POS( 0));

    // get the count and move more then half into the new block.

    uiMid = (entryCount() + 5) >> 1;
    uiChildAddr = FBTREE_END;

    for (uiPos = 0; uiPos < uiMid; uiPos++)
    {
        pucEntry = ENTRY_POS( uiPos);
        if (blkType() != ACCESS_BTREE_LEAF)
        {
            pucChildAddr = pucEntry + m_uiEntrySize;
            uiChildAddr = (FLMUINT)FB2UD(pucChildAddr);
        }

        // m_uiPosition automatically gets incremented.

        if (RC_BAD( rc = pNewBlk->insertEntry( pucEntry, uiChildAddr)))
        {
            RC_UNEXPECTED_ASSERT( rc);
            goto Exit;
        }
    }

    if (m_uiPosition < uiMid)
    {

        // Insert this entry now

        bInserted = TRUE;
        (void) pNewBlk->searchEntry( pucCurEntry);
        if (RC_BAD( rc = pNewBlk->insertEntry( pucCurEntry, uiCurBlkAddr)))
        {
            goto Exit;
        }
    }

    // Let caller insert into parent entry.  This rids us of recursion.

    f_memcpy( pucParentEntry, pucEntry, m_uiEntrySize);

    // Move the rest down

    pucEntry = ENTRY_POS( 0);
    pucMidEntry = ENTRY_POS( uiMid);

    entryCount( entryCount() - uiMid);
    uiMoveBytes = entryCount() * (m_uiEntrySize + m_uiEntryOvhd);
    flmAssert( uiMoveBytes < DYNSSET_BLOCK_SIZE - sizeof( FixedBlkHdr));
    f_memmove( pucEntry, pucMidEntry, uiMoveBytes);

    if( !bInserted)
    {

        // m_uiPosition -= uiMid;

        (void) searchEntry( pucCurEntry);
        if (RC_BAD( rc = insertEntry( pucCurEntry, uiCurBlkAddr)))
        {
            goto Exit;
        }
    }

    // VISIT: Could position stack to point to current element to insert.

    // Fixup the prev/next block linkages.

    if (prevBlk() != FBTREE_END)
    {
        if (RC_BAD( rc = pRoot->readBlk( prevBlk(), blkType(), &pPrevBlk )))
        {
            goto Exit;
        }

        pPrevBlk->nextBlk( pNewBlk->blkAddr());
        uiPrevBlkAddr = pPrevBlk->blkAddr();
    }
    else
    {
        uiPrevBlkAddr = FBTREE_END;
    }
    pNewBlk->prevBlk( uiPrevBlkAddr);
    pNewBlk->nextBlk( blkAddr());
    prevBlk( pNewBlk->blkAddr());

    *puiNewBlkAddr = pNewBlk->blkAddr();

Exit:

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

    return( rc);
}
/****************************************************************************
Desc:	Insert the entry into the btree - should be positioned
****************************************************************************/
RCODE F_BtreeRoot::insert(
    void *			pvEntry)
{
    RCODE				rc = NE_FLM_OK;
    FLMUINT			uiCurLevel;
    FLMBYTE			ucEntryBuf[FBTREE_MAX_LEVELS][DYNSSET_MAX_FIXED_ENTRY_SIZE];
    FLMUINT			uiNewBlkAddr;

    if (RC_OK( rc = m_BTStack[0]->insert( pvEntry)))
    {
        goto Exit;
    }

    // Failed to input at the left level.  Do block split(s).
    // This is an iterative and NOT a recursive split algorithm.
    // The debugging, and cases to test should be lots easier this way.

    f_memcpy( ucEntryBuf[0], pvEntry, m_uiEntrySize);
    uiCurLevel = 0;
    uiNewBlkAddr = FBTREE_END;
    for(;;)
    {

        // Split while adding the element.

        if (RC_BAD( rc = (m_BTStack[uiCurLevel])->split(
                             this,
                             ucEntryBuf[ uiCurLevel],
                             uiNewBlkAddr,
                             ucEntryBuf[ uiCurLevel+1],
                             &uiNewBlkAddr)))
        {
            goto Exit;
        }

        uiCurLevel++;
        flmAssert( uiCurLevel < m_uiLevels);

        if (RC_OK( rc = m_BTStack[uiCurLevel]->insertEntry(
                            ucEntryBuf[uiCurLevel], uiNewBlkAddr)))
        {
            goto Exit;
        }

        // Only returns NE_FLM_OK or FAILURE.

        // Root split?

        if (uiCurLevel + 1 == m_uiLevels)
        {
            flmAssert( m_uiLevels + 1 <= FBTREE_MAX_LEVELS);
            if (m_uiLevels + 1 > FBTREE_MAX_LEVELS)
            {
                rc = RC_SET( NE_FLM_BTREE_FULL);
                goto Exit;
            }

            // Need to split the root block.
            rc = ((F_BtreeRoot *)m_BTStack[uiCurLevel])->split(
                     ucEntryBuf[uiCurLevel], uiNewBlkAddr );
            break;
        }
    }

Exit:

    if (RC_OK(rc))
    {
        m_uiTotalEntries++;
    }
    return( rc);
}