// 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; }
/**************************************************************************** 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); }
/**************************************************************************** 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 "}}" }
/**************************************************************************** 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; } }
/**************************************************************************** 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); }
/*************************************************************************** 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); }
/**************************************************************************** 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; }
/**************************************************************************** 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); }
/**************************************************************************** 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(); }
FINLINE FLMINT FTKAPI outputStr( const char * pszStr, FLMUINT uiLen) { f_memcpy( m_pszDestBuffer, pszStr, uiLen); m_pszDestBuffer += uiLen; return( (FLMINT)uiLen); }
/**************************************************************************** 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); }
/**************************************************************************** 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)); }
/**************************************************************************** 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); }
/**************************************************************************** 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); }
/**************************************************************************** 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); }
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); }
// 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; }
/******************************************************************** 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); }
/**************************************************************************** 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); }
/**************************************************************************** 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); }
/**************************************************************************** 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); }
/**************************************************************************** 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); }
/**************************************************************************** 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); }
/**************************************************************************** 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); }