/**************************************************************************** Desc: Index a set of documents or until time runs out. ****************************************************************************/ RCODE F_Db::indexSetOfRows( FLMUINT uiIndexNum, FLMUINT64 ui64StartRowId, FLMUINT64 ui64EndRowId, IF_IxStatus * pIxStatus, IF_IxClient * pIxClient, SFLM_INDEX_STATUS * pIndexStatus, FLMBOOL * pbHitEnd, IF_Thread * pThread) { RCODE rc = NE_SFLM_OK; FLMUINT64 ui64RowId; FLMUINT64 ui64LastRowId = 0; F_INDEX * pIndex = NULL; F_TABLE * pTable; IF_LockObject * pDatabaseLockObj = m_pDatabase->m_pDatabaseLockObj; FLMBOOL bHitEnd = FALSE; FLMUINT uiCurrTime; FLMUINT uiLastStatusTime = 0; FLMUINT uiStartTime; FLMUINT uiMinTU; FLMUINT uiStatusIntervalTU; FLMUINT64 ui64RowsProcessed = 0; FLMBOOL bRelinquish = FALSE; FLMBYTE ucKey[ FLM_MAX_NUM_BUF_SIZE]; FLMUINT uiKeyLen; void * pvTmpPoolMark = m_tempPool.poolMark(); F_Btree * pbtree = NULL; FLMBOOL bNeg; FLMUINT uiBytesProcessed; F_Row * pRow = NULL; uiMinTU = FLM_MILLI_TO_TIMER_UNITS( 500); uiStatusIntervalTU = FLM_SECS_TO_TIMER_UNITS( 10); uiStartTime = FLM_GET_TIMER(); if (RC_BAD( rc = krefCntrlCheck())) { goto Exit; } pIndex = m_pDict->getIndex( uiIndexNum); flmAssert( pIndex); flmAssert( !(pIndex->uiFlags & IXD_SUSPENDED)); // Get a btree if (RC_BAD( rc = gv_SFlmSysData.pBtPool->btpReserveBtree( &pbtree))) { goto Exit; } pTable = m_pDict->getTable( pIndex->uiTableNum); flmAssert( pTable); if (RC_BAD( rc = pbtree->btOpen( this, &pTable->lfInfo, FALSE, TRUE))) { goto Exit; } uiKeyLen = sizeof( ucKey); if (RC_BAD( rc = flmNumber64ToStorage( ui64StartRowId, &uiKeyLen, ucKey, FALSE, TRUE))) { goto Exit; } if( RC_BAD( rc = pbtree->btLocateEntry( ucKey, sizeof( ucKey), &uiKeyLen, FLM_INCL))) { if (rc == NE_SFLM_EOF_HIT || rc == NE_SFLM_NOT_FOUND) { rc = NE_SFLM_OK; bHitEnd = TRUE; goto Commit_Keys; } goto Exit; } for (;;) { // See what row we're on if (RC_BAD( rc = flmCollation2Number( uiKeyLen, ucKey, &ui64RowId, &bNeg, &uiBytesProcessed))) { goto Exit; } if (ui64RowId > ui64EndRowId) { break; } if( RC_BAD( rc = gv_SFlmSysData.pRowCacheMgr->retrieveRow( this, pIndex->uiTableNum, ui64RowId, &pRow))) { goto Exit; } if (RC_BAD( rc = buildKeys( pIndex, pTable, pRow, TRUE, NULL))) { goto Exit; } // See if there is an indexing callback if (pIxClient) { if (RC_BAD( rc = pIxClient->doIndexing( this, uiIndexNum, pIndex->uiTableNum, pRow))) { goto Exit; } } ui64LastRowId = ui64RowId; ui64RowsProcessed++; if (pIndexStatus) { pIndexStatus->ui64RowsProcessed++; pIndexStatus->ui64LastRowIndexed = ui64LastRowId; } // Get the current time uiCurrTime = FLM_GET_TIMER(); // Break out if someone is waiting for an update transaction. if (pThread) { if (pThread->getShutdownFlag()) { bRelinquish = TRUE; break; } if (pDatabaseLockObj->getWaiterCount()) { // See if our minimum run time has elapsed if (FLM_ELAPSED_TIME( uiCurrTime, uiStartTime) >= uiMinTU) { if (ui64RowsProcessed < 50) { // If there are higher priority waiters in the lock queue, // we want to relinquish. if (pDatabaseLockObj->haveHigherPriorityWaiter( FLM_BACKGROUND_LOCK_PRIORITY)) { bRelinquish = TRUE; break; } } else { bRelinquish = TRUE; break; } } } else { // Even if no one has requested a lock for a long time, we // still want to periodically commit our transaction so // we won't lose more than uiMaxCPInterval timer units worth // of work if we crash. We will run until we exceed the checkpoint // interval and we see that someone (the checkpoint thread) is // waiting for the write lock. if (FLM_ELAPSED_TIME( uiCurrTime, uiStartTime) > gv_SFlmSysData.uiMaxCPInterval && m_pDatabase->m_pWriteLockObj->getWaiterCount()) { bRelinquish = TRUE; break; } } } if (FLM_ELAPSED_TIME( uiCurrTime, uiLastStatusTime) >= uiStatusIntervalTU) { uiLastStatusTime = uiCurrTime; if( pIxStatus) { if( RC_BAD( rc = pIxStatus->reportIndex( ui64LastRowId))) { goto Exit; } } // Send indexing completed event notification if( gv_SFlmSysData.EventHdrs[ SFLM_EVENT_UPDATES].pEventCBList) { flmDoEventCallback( SFLM_EVENT_UPDATES, SFLM_EVENT_INDEXING_PROGRESS, this, f_threadId(), 0, uiIndexNum, ui64LastRowId, NE_SFLM_OK); } // Log a progress message flmLogIndexingProgress( uiIndexNum, ui64LastRowId); } // Need to go to the next row. if( RC_BAD( rc = pbtree->btNextEntry( ucKey, sizeof( ucKey), &uiKeyLen))) { if (rc == NE_SFLM_EOF_HIT) { rc = NE_SFLM_OK; bHitEnd = TRUE; break; } goto Exit; } } Commit_Keys: if (RC_BAD( rc = keysCommit( TRUE))) { goto Exit; } // If at the end, change index state. if (bHitEnd) { if (RC_BAD( rc = setIxStateInfo( uiIndexNum, 0, 0))) { goto Exit; } // setIxStateInfo may have changed to a new dictionary, so pIxd is no // good after this point pIndex = NULL; } else if (ui64RowsProcessed) { if (RC_BAD( rc = setIxStateInfo( uiIndexNum, ui64LastRowId, IXD_OFFLINE))) { goto Exit; } // setIxStateInfo may have changed to a new dictionary, so pIndex is no // good after this point pIndex = NULL; } // Log the rows that were indexed, if any if (ui64LastRowId) { if (RC_BAD( rc = m_pDatabase->m_pRfl->logIndexSet( this, uiIndexNum, ui64StartRowId, ui64LastRowId))) { goto Exit; } } Exit: // We want to make one last call if we are in the foreground or if // we actually did some indexing. if (gv_SFlmSysData.EventHdrs[ SFLM_EVENT_UPDATES].pEventCBList) { flmDoEventCallback( SFLM_EVENT_UPDATES, SFLM_EVENT_INDEXING_PROGRESS, this, f_threadId(), 0, uiIndexNum, (FLMUINT64)(bHitEnd ? (FLMUINT64)0 : ui64LastRowId), NE_SFLM_OK); } flmLogIndexingProgress( uiIndexNum, (FLMUINT64)(bHitEnd ? (FLMUINT64)0 : ui64LastRowId)); if (pIxStatus) { (void) pIxStatus->reportIndex( ui64LastRowId); } if (pbHitEnd) { *pbHitEnd = bHitEnd; } krefCntrlFree(); m_tempPool.poolReset( pvTmpPoolMark); if (pbtree) { gv_SFlmSysData.pBtPool->btpReturnBtree( &pbtree); } if (pRow) { pRow->ReleaseRow(); } return( rc); }
void setUp() { buildDimensions(); buildElements(); buildKeys(); }